python.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. Language: Python
  3. Description: Python is an interpreted, object-oriented, high-level programming language with dynamic semantics.
  4. Website: https://www.python.org
  5. Category: common
  6. */
  7. function python(hljs) {
  8. const RESERVED_WORDS = [
  9. 'and',
  10. 'as',
  11. 'assert',
  12. 'async',
  13. 'await',
  14. 'break',
  15. 'class',
  16. 'continue',
  17. 'def',
  18. 'del',
  19. 'elif',
  20. 'else',
  21. 'except',
  22. 'finally',
  23. 'for',
  24. '',
  25. 'from',
  26. 'global',
  27. 'if',
  28. 'import',
  29. 'in',
  30. 'is',
  31. 'lambda',
  32. 'nonlocal|10',
  33. 'not',
  34. 'or',
  35. 'pass',
  36. 'raise',
  37. 'return',
  38. 'try',
  39. 'while',
  40. 'with',
  41. 'yield',
  42. ];
  43. const BUILT_INS = [
  44. '__import__',
  45. 'abs',
  46. 'all',
  47. 'any',
  48. 'ascii',
  49. 'bin',
  50. 'bool',
  51. 'breakpoint',
  52. 'bytearray',
  53. 'bytes',
  54. 'callable',
  55. 'chr',
  56. 'classmethod',
  57. 'compile',
  58. 'complex',
  59. 'delattr',
  60. 'dict',
  61. 'dir',
  62. 'divmod',
  63. 'enumerate',
  64. 'eval',
  65. 'exec',
  66. 'filter',
  67. 'float',
  68. 'format',
  69. 'frozenset',
  70. 'getattr',
  71. 'globals',
  72. 'hasattr',
  73. 'hash',
  74. 'help',
  75. 'hex',
  76. 'id',
  77. 'input',
  78. 'int',
  79. 'isinstance',
  80. 'issubclass',
  81. 'iter',
  82. 'len',
  83. 'list',
  84. 'locals',
  85. 'map',
  86. 'max',
  87. 'memoryview',
  88. 'min',
  89. 'next',
  90. 'object',
  91. 'oct',
  92. 'open',
  93. 'ord',
  94. 'pow',
  95. 'print',
  96. 'property',
  97. 'range',
  98. 'repr',
  99. 'reversed',
  100. 'round',
  101. 'set',
  102. 'setattr',
  103. 'slice',
  104. 'sorted',
  105. 'staticmethod',
  106. 'str',
  107. 'sum',
  108. 'super',
  109. 'tuple',
  110. 'type',
  111. 'vars',
  112. 'zip',
  113. ];
  114. const LITERALS = [
  115. '__debug__',
  116. 'Ellipsis',
  117. 'False',
  118. 'None',
  119. 'NotImplemented',
  120. 'True',
  121. ];
  122. const KEYWORDS = {
  123. keyword: RESERVED_WORDS.join(' '),
  124. built_in: BUILT_INS.join(' '),
  125. literal: LITERALS.join(' ')
  126. };
  127. const PROMPT = {
  128. className: 'meta', begin: /^(>>>|\.\.\.) /
  129. };
  130. const SUBST = {
  131. className: 'subst',
  132. begin: /\{/, end: /\}/,
  133. keywords: KEYWORDS,
  134. illegal: /#/
  135. };
  136. const LITERAL_BRACKET = {
  137. begin: /\{\{/,
  138. relevance: 0
  139. };
  140. const STRING = {
  141. className: 'string',
  142. contains: [hljs.BACKSLASH_ESCAPE],
  143. variants: [
  144. {
  145. begin: /([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/, end: /'''/,
  146. contains: [hljs.BACKSLASH_ESCAPE, PROMPT],
  147. relevance: 10
  148. },
  149. {
  150. begin: /([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/, end: /"""/,
  151. contains: [hljs.BACKSLASH_ESCAPE, PROMPT],
  152. relevance: 10
  153. },
  154. {
  155. begin: /([fF][rR]|[rR][fF]|[fF])'''/, end: /'''/,
  156. contains: [hljs.BACKSLASH_ESCAPE, PROMPT, LITERAL_BRACKET, SUBST]
  157. },
  158. {
  159. begin: /([fF][rR]|[rR][fF]|[fF])"""/, end: /"""/,
  160. contains: [hljs.BACKSLASH_ESCAPE, PROMPT, LITERAL_BRACKET, SUBST]
  161. },
  162. {
  163. begin: /([uU]|[rR])'/, end: /'/,
  164. relevance: 10
  165. },
  166. {
  167. begin: /([uU]|[rR])"/, end: /"/,
  168. relevance: 10
  169. },
  170. {
  171. begin: /([bB]|[bB][rR]|[rR][bB])'/, end: /'/
  172. },
  173. {
  174. begin: /([bB]|[bB][rR]|[rR][bB])"/, end: /"/
  175. },
  176. {
  177. begin: /([fF][rR]|[rR][fF]|[fF])'/, end: /'/,
  178. contains: [hljs.BACKSLASH_ESCAPE, LITERAL_BRACKET, SUBST]
  179. },
  180. {
  181. begin: /([fF][rR]|[rR][fF]|[fF])"/, end: /"/,
  182. contains: [hljs.BACKSLASH_ESCAPE, LITERAL_BRACKET, SUBST]
  183. },
  184. hljs.APOS_STRING_MODE,
  185. hljs.QUOTE_STRING_MODE
  186. ]
  187. };
  188. // https://docs.python.org/3.9/reference/lexical_analysis.html#numeric-literals
  189. const digitpart = '[0-9](_?[0-9])*';
  190. const pointfloat = `(\\b(${digitpart}))?\\.(${digitpart})|\\b(${digitpart})\\.`;
  191. const NUMBER = {
  192. className: 'number', relevance: 0,
  193. variants: [
  194. // exponentfloat, pointfloat
  195. // https://docs.python.org/3.9/reference/lexical_analysis.html#floating-point-literals
  196. // optionally imaginary
  197. // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals
  198. // Note: no leading \b because floats can start with a decimal point
  199. // and we don't want to mishandle e.g. `fn(.5)`,
  200. // no trailing \b for pointfloat because it can end with a decimal point
  201. // and we don't want to mishandle e.g. `0..hex()`; this should be safe
  202. // because both MUST contain a decimal point and so cannot be confused with
  203. // the interior part of an identifier
  204. { begin: `(\\b(${digitpart})|(${pointfloat}))[eE][+-]?(${digitpart})[jJ]?\\b` },
  205. { begin: `(${pointfloat})[jJ]?` },
  206. // decinteger, bininteger, octinteger, hexinteger
  207. // https://docs.python.org/3.9/reference/lexical_analysis.html#integer-literals
  208. // optionally "long" in Python 2
  209. // https://docs.python.org/2.7/reference/lexical_analysis.html#integer-and-long-integer-literals
  210. // decinteger is optionally imaginary
  211. // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals
  212. { begin: '\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?\\b' },
  213. { begin: '\\b0[bB](_?[01])+[lL]?\\b' },
  214. { begin: '\\b0[oO](_?[0-7])+[lL]?\\b' },
  215. { begin: '\\b0[xX](_?[0-9a-fA-F])+[lL]?\\b' },
  216. // imagnumber (digitpart-based)
  217. // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals
  218. { begin: `\\b(${digitpart})[jJ]\\b` },
  219. ]
  220. };
  221. const PARAMS = {
  222. className: 'params',
  223. variants: [
  224. // Exclude params at functions without params
  225. {begin: /\(\s*\)/, skip: true, className: null },
  226. {
  227. begin: /\(/, end: /\)/, excludeBegin: true, excludeEnd: true,
  228. keywords: KEYWORDS,
  229. contains: ['self', PROMPT, NUMBER, STRING, hljs.HASH_COMMENT_MODE],
  230. },
  231. ],
  232. };
  233. SUBST.contains = [STRING, NUMBER, PROMPT];
  234. return {
  235. name: 'Python',
  236. aliases: ['py', 'gyp', 'ipython'],
  237. keywords: KEYWORDS,
  238. illegal: /(<\/|->|\?)|=>/,
  239. contains: [
  240. PROMPT,
  241. NUMBER,
  242. // eat "if" prior to string so that it won't accidentally be
  243. // labeled as an f-string as in:
  244. { begin: /\bself\b/, }, // very common convention
  245. { beginKeywords: "if", relevance: 0 },
  246. STRING,
  247. hljs.HASH_COMMENT_MODE,
  248. {
  249. variants: [
  250. {className: 'function', beginKeywords: 'def'},
  251. {className: 'class', beginKeywords: 'class'}
  252. ],
  253. end: /:/,
  254. illegal: /[${=;\n,]/,
  255. contains: [
  256. hljs.UNDERSCORE_TITLE_MODE,
  257. PARAMS,
  258. {
  259. begin: /->/, endsWithParent: true,
  260. keywords: 'None'
  261. }
  262. ]
  263. },
  264. {
  265. className: 'meta',
  266. begin: /^[\t ]*@/, end: /(?=#)|$/,
  267. contains: [NUMBER, PARAMS, STRING]
  268. },
  269. {
  270. begin: /\b(print|exec)\(/ // don’t highlight keywords-turned-functions in Python 3
  271. }
  272. ]
  273. };
  274. }
  275. module.exports = python;