|
1 # -*- coding: utf-8 -*- |
|
2 """ |
|
3 pygments.lexers.make |
|
4 ~~~~~~~~~~~~~~~~~~~~ |
|
5 |
|
6 Lexers for Makefiles and similar. |
|
7 |
|
8 :copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS. |
|
9 :license: BSD, see LICENSE for details. |
|
10 """ |
|
11 |
|
12 import re |
|
13 |
|
14 from pygments.lexer import Lexer, RegexLexer, include, bygroups, \ |
|
15 do_insertions, using |
|
16 from pygments.token import Text, Comment, Operator, Keyword, Name, String, \ |
|
17 Punctuation |
|
18 from pygments.lexers.shell import BashLexer |
|
19 |
|
20 __all__ = ['MakefileLexer', 'BaseMakefileLexer', 'CMakeLexer'] |
|
21 |
|
22 |
|
23 class MakefileLexer(Lexer): |
|
24 """ |
|
25 Lexer for BSD and GNU make extensions (lenient enough to handle both in |
|
26 the same file even). |
|
27 |
|
28 *Rewritten in Pygments 0.10.* |
|
29 """ |
|
30 |
|
31 name = 'Makefile' |
|
32 aliases = ['make', 'makefile', 'mf', 'bsdmake'] |
|
33 filenames = ['*.mak', '*.mk', 'Makefile', 'makefile', 'Makefile.*', 'GNUmakefile'] |
|
34 mimetypes = ['text/x-makefile'] |
|
35 |
|
36 r_special = re.compile( |
|
37 r'^(?:' |
|
38 # BSD Make |
|
39 r'\.\s*(include|undef|error|warning|if|else|elif|endif|for|endfor)|' |
|
40 # GNU Make |
|
41 r'\s*(ifeq|ifneq|ifdef|ifndef|else|endif|-?include|define|endef|:|vpath)|' |
|
42 # GNU Automake |
|
43 r'\s*(if|else|endif))(?=\s)') |
|
44 r_comment = re.compile(r'^\s*@?#') |
|
45 |
|
46 def get_tokens_unprocessed(self, text): |
|
47 ins = [] |
|
48 lines = text.splitlines(True) |
|
49 done = '' |
|
50 lex = BaseMakefileLexer(**self.options) |
|
51 backslashflag = False |
|
52 for line in lines: |
|
53 if self.r_special.match(line) or backslashflag: |
|
54 ins.append((len(done), [(0, Comment.Preproc, line)])) |
|
55 backslashflag = line.strip().endswith('\\') |
|
56 elif self.r_comment.match(line): |
|
57 ins.append((len(done), [(0, Comment, line)])) |
|
58 else: |
|
59 done += line |
|
60 for item in do_insertions(ins, lex.get_tokens_unprocessed(done)): |
|
61 yield item |
|
62 |
|
63 def analyse_text(text): |
|
64 # Many makefiles have $(BIG_CAPS) style variables |
|
65 if re.search(r'\$\([A-Z_]+\)', text): |
|
66 return 0.1 |
|
67 |
|
68 |
|
69 class BaseMakefileLexer(RegexLexer): |
|
70 """ |
|
71 Lexer for simple Makefiles (no preprocessing). |
|
72 |
|
73 .. versionadded:: 0.10 |
|
74 """ |
|
75 |
|
76 name = 'Base Makefile' |
|
77 aliases = ['basemake'] |
|
78 filenames = [] |
|
79 mimetypes = [] |
|
80 |
|
81 tokens = { |
|
82 'root': [ |
|
83 # recipes (need to allow spaces because of expandtabs) |
|
84 (r'^(?:[\t ]+.*\n|\n)+', using(BashLexer)), |
|
85 # special variables |
|
86 (r'\$[<@$+%?|*]', Keyword), |
|
87 (r'\s+', Text), |
|
88 (r'#.*?\n', Comment), |
|
89 (r'(export)(\s+)(?=[\w${}\t -]+\n)', |
|
90 bygroups(Keyword, Text), 'export'), |
|
91 (r'export\s+', Keyword), |
|
92 # assignment |
|
93 (r'([\w${}().-]+)(\s*)([!?:+]?=)([ \t]*)((?:.*\\\n)+|.*\n)', |
|
94 bygroups(Name.Variable, Text, Operator, Text, using(BashLexer))), |
|
95 # strings |
|
96 (r'(?s)"(\\\\|\\.|[^"\\])*"', String.Double), |
|
97 (r"(?s)'(\\\\|\\.|[^'\\])*'", String.Single), |
|
98 # targets |
|
99 (r'([^\n:]+)(:+)([ \t]*)', bygroups(Name.Function, Operator, Text), |
|
100 'block-header'), |
|
101 # expansions |
|
102 (r'\$\(', Keyword, 'expansion'), |
|
103 ], |
|
104 'expansion': [ |
|
105 (r'[^$a-zA-Z_()]+', Text), |
|
106 (r'[a-zA-Z_]+', Name.Variable), |
|
107 (r'\$', Keyword), |
|
108 (r'\(', Keyword, '#push'), |
|
109 (r'\)', Keyword, '#pop'), |
|
110 ], |
|
111 'export': [ |
|
112 (r'[\w${}-]+', Name.Variable), |
|
113 (r'\n', Text, '#pop'), |
|
114 (r'\s+', Text), |
|
115 ], |
|
116 'block-header': [ |
|
117 (r'[,|]', Punctuation), |
|
118 (r'#.*?\n', Comment, '#pop'), |
|
119 (r'\\\n', Text), # line continuation |
|
120 (r'\$\(', Keyword, 'expansion'), |
|
121 (r'[a-zA-Z_]+', Name), |
|
122 (r'\n', Text, '#pop'), |
|
123 (r'.', Text), |
|
124 ], |
|
125 } |
|
126 |
|
127 |
|
128 class CMakeLexer(RegexLexer): |
|
129 """ |
|
130 Lexer for `CMake <http://cmake.org/Wiki/CMake>`_ files. |
|
131 |
|
132 .. versionadded:: 1.2 |
|
133 """ |
|
134 name = 'CMake' |
|
135 aliases = ['cmake'] |
|
136 filenames = ['*.cmake', 'CMakeLists.txt'] |
|
137 mimetypes = ['text/x-cmake'] |
|
138 |
|
139 tokens = { |
|
140 'root': [ |
|
141 # (r'(ADD_CUSTOM_COMMAND|ADD_CUSTOM_TARGET|ADD_DEFINITIONS|' |
|
142 # r'ADD_DEPENDENCIES|ADD_EXECUTABLE|ADD_LIBRARY|ADD_SUBDIRECTORY|' |
|
143 # r'ADD_TEST|AUX_SOURCE_DIRECTORY|BUILD_COMMAND|BUILD_NAME|' |
|
144 # r'CMAKE_MINIMUM_REQUIRED|CONFIGURE_FILE|CREATE_TEST_SOURCELIST|' |
|
145 # r'ELSE|ELSEIF|ENABLE_LANGUAGE|ENABLE_TESTING|ENDFOREACH|' |
|
146 # r'ENDFUNCTION|ENDIF|ENDMACRO|ENDWHILE|EXEC_PROGRAM|' |
|
147 # r'EXECUTE_PROCESS|EXPORT_LIBRARY_DEPENDENCIES|FILE|FIND_FILE|' |
|
148 # r'FIND_LIBRARY|FIND_PACKAGE|FIND_PATH|FIND_PROGRAM|FLTK_WRAP_UI|' |
|
149 # r'FOREACH|FUNCTION|GET_CMAKE_PROPERTY|GET_DIRECTORY_PROPERTY|' |
|
150 # r'GET_FILENAME_COMPONENT|GET_SOURCE_FILE_PROPERTY|' |
|
151 # r'GET_TARGET_PROPERTY|GET_TEST_PROPERTY|IF|INCLUDE|' |
|
152 # r'INCLUDE_DIRECTORIES|INCLUDE_EXTERNAL_MSPROJECT|' |
|
153 # r'INCLUDE_REGULAR_EXPRESSION|INSTALL|INSTALL_FILES|' |
|
154 # r'INSTALL_PROGRAMS|INSTALL_TARGETS|LINK_DIRECTORIES|' |
|
155 # r'LINK_LIBRARIES|LIST|LOAD_CACHE|LOAD_COMMAND|MACRO|' |
|
156 # r'MAKE_DIRECTORY|MARK_AS_ADVANCED|MATH|MESSAGE|OPTION|' |
|
157 # r'OUTPUT_REQUIRED_FILES|PROJECT|QT_WRAP_CPP|QT_WRAP_UI|REMOVE|' |
|
158 # r'REMOVE_DEFINITIONS|SEPARATE_ARGUMENTS|SET|' |
|
159 # r'SET_DIRECTORY_PROPERTIES|SET_SOURCE_FILES_PROPERTIES|' |
|
160 # r'SET_TARGET_PROPERTIES|SET_TESTS_PROPERTIES|SITE_NAME|' |
|
161 # r'SOURCE_GROUP|STRING|SUBDIR_DEPENDS|SUBDIRS|' |
|
162 # r'TARGET_LINK_LIBRARIES|TRY_COMPILE|TRY_RUN|UNSET|' |
|
163 # r'USE_MANGLED_MESA|UTILITY_SOURCE|VARIABLE_REQUIRES|' |
|
164 # r'VTK_MAKE_INSTANTIATOR|VTK_WRAP_JAVA|VTK_WRAP_PYTHON|' |
|
165 # r'VTK_WRAP_TCL|WHILE|WRITE_FILE|' |
|
166 # r'COUNTARGS)\b', Name.Builtin, 'args'), |
|
167 (r'\b(\w+)([ \t]*)(\()', bygroups(Name.Builtin, Text, |
|
168 Punctuation), 'args'), |
|
169 include('keywords'), |
|
170 include('ws') |
|
171 ], |
|
172 'args': [ |
|
173 (r'\(', Punctuation, '#push'), |
|
174 (r'\)', Punctuation, '#pop'), |
|
175 (r'(\$\{)(.+?)(\})', bygroups(Operator, Name.Variable, Operator)), |
|
176 (r'(\$ENV\{)(.+?)(\})', bygroups(Operator, Name.Variable, Operator)), |
|
177 (r'(\$<)(.+?)(>)', bygroups(Operator, Name.Variable, Operator)), |
|
178 (r'(?s)".*?"', String.Double), |
|
179 (r'\\\S+', String), |
|
180 (r'[^)$"# \t\n]+', String), |
|
181 (r'\n', Text), # explicitly legal |
|
182 include('keywords'), |
|
183 include('ws') |
|
184 ], |
|
185 'string': [ |
|
186 |
|
187 ], |
|
188 'keywords': [ |
|
189 (r'\b(WIN32|UNIX|APPLE|CYGWIN|BORLAND|MINGW|MSVC|MSVC_IDE|MSVC60|' |
|
190 r'MSVC70|MSVC71|MSVC80|MSVC90)\b', Keyword), |
|
191 ], |
|
192 'ws': [ |
|
193 (r'[ \t]+', Text), |
|
194 (r'#.*\n', Comment), |
|
195 ] |
|
196 } |
|
197 |
|
198 def analyse_text(text): |
|
199 exp = r'^ *CMAKE_MINIMUM_REQUIRED *\( *VERSION *\d(\.\d)* *( FATAL_ERROR)? *\) *$' |
|
200 if re.search(exp, text, flags=re.MULTILINE | re.IGNORECASE): |
|
201 return 0.8 |
|
202 return 0.0 |