make.py 7.6 KB

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