prism-php.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /**
  2. * Original by Aaron Harun: http://aahacreative.com/2012/07/31/php-syntax-highlighting-prism/
  3. * Modified by Miles Johnson: http://milesj.me
  4. * Rewritten by Tom Pavelec
  5. *
  6. * Supports PHP 5.3 - 8.0
  7. */
  8. (function (Prism) {
  9. var comment = /\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/;
  10. var constant = [
  11. {
  12. pattern: /\b(?:false|true)\b/i,
  13. alias: 'boolean'
  14. },
  15. {
  16. pattern: /(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,
  17. greedy: true,
  18. lookbehind: true,
  19. },
  20. {
  21. pattern: /(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,
  22. greedy: true,
  23. lookbehind: true,
  24. },
  25. /\b(?:null)\b/i,
  26. /\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/,
  27. ];
  28. var number = /\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i;
  29. var operator = /<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/;
  30. var punctuation = /[{}\[\](),:;]/;
  31. Prism.languages.php = {
  32. 'delimiter': {
  33. pattern: /\?>$|^<\?(?:php(?=\s)|=)?/i,
  34. alias: 'important'
  35. },
  36. 'comment': comment,
  37. 'variable': /\$+(?:\w+\b|(?=\{))/,
  38. 'package': {
  39. pattern: /(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
  40. lookbehind: true,
  41. inside: {
  42. 'punctuation': /\\/
  43. }
  44. },
  45. 'class-name-definition': {
  46. pattern: /(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,
  47. lookbehind: true,
  48. alias: 'class-name'
  49. },
  50. 'function-definition': {
  51. pattern: /(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,
  52. lookbehind: true,
  53. alias: 'function'
  54. },
  55. 'keyword': [
  56. {
  57. pattern: /(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,
  58. alias: 'type-casting',
  59. greedy: true,
  60. lookbehind: true
  61. },
  62. {
  63. pattern: /([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,
  64. alias: 'type-hint',
  65. greedy: true,
  66. lookbehind: true
  67. },
  68. {
  69. pattern: /(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i,
  70. alias: 'return-type',
  71. greedy: true,
  72. lookbehind: true
  73. },
  74. {
  75. pattern: /\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,
  76. alias: 'type-declaration',
  77. greedy: true
  78. },
  79. {
  80. pattern: /(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,
  81. alias: 'type-declaration',
  82. greedy: true,
  83. lookbehind: true
  84. },
  85. {
  86. pattern: /\b(?:parent|self|static)(?=\s*::)/i,
  87. alias: 'static-context',
  88. greedy: true
  89. },
  90. {
  91. // yield from
  92. pattern: /(\byield\s+)from\b/i,
  93. lookbehind: true
  94. },
  95. // `class` is always a keyword unlike other keywords
  96. /\bclass\b/i,
  97. {
  98. // https://www.php.net/manual/en/reserved.keywords.php
  99. //
  100. // keywords cannot be preceded by "->"
  101. // the complex lookbehind means `(?<!(?:->|::)\s*)`
  102. pattern: /((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,
  103. lookbehind: true
  104. }
  105. ],
  106. 'argument-name': {
  107. pattern: /([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i,
  108. lookbehind: true
  109. },
  110. 'class-name': [
  111. {
  112. pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,
  113. greedy: true,
  114. lookbehind: true
  115. },
  116. {
  117. pattern: /(\|\s*)\b[a-z_]\w*(?!\\)\b/i,
  118. greedy: true,
  119. lookbehind: true
  120. },
  121. {
  122. pattern: /\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,
  123. greedy: true
  124. },
  125. {
  126. pattern: /(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,
  127. alias: 'class-name-fully-qualified',
  128. greedy: true,
  129. lookbehind: true,
  130. inside: {
  131. 'punctuation': /\\/
  132. }
  133. },
  134. {
  135. pattern: /(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,
  136. alias: 'class-name-fully-qualified',
  137. greedy: true,
  138. inside: {
  139. 'punctuation': /\\/
  140. }
  141. },
  142. {
  143. pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
  144. alias: 'class-name-fully-qualified',
  145. greedy: true,
  146. lookbehind: true,
  147. inside: {
  148. 'punctuation': /\\/
  149. }
  150. },
  151. {
  152. pattern: /\b[a-z_]\w*(?=\s*\$)/i,
  153. alias: 'type-declaration',
  154. greedy: true
  155. },
  156. {
  157. pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,
  158. alias: ['class-name-fully-qualified', 'type-declaration'],
  159. greedy: true,
  160. inside: {
  161. 'punctuation': /\\/
  162. }
  163. },
  164. {
  165. pattern: /\b[a-z_]\w*(?=\s*::)/i,
  166. alias: 'static-context',
  167. greedy: true
  168. },
  169. {
  170. pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,
  171. alias: ['class-name-fully-qualified', 'static-context'],
  172. greedy: true,
  173. inside: {
  174. 'punctuation': /\\/
  175. }
  176. },
  177. {
  178. pattern: /([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,
  179. alias: 'type-hint',
  180. greedy: true,
  181. lookbehind: true
  182. },
  183. {
  184. pattern: /([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,
  185. alias: ['class-name-fully-qualified', 'type-hint'],
  186. greedy: true,
  187. lookbehind: true,
  188. inside: {
  189. 'punctuation': /\\/
  190. }
  191. },
  192. {
  193. pattern: /(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,
  194. alias: 'return-type',
  195. greedy: true,
  196. lookbehind: true
  197. },
  198. {
  199. pattern: /(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
  200. alias: ['class-name-fully-qualified', 'return-type'],
  201. greedy: true,
  202. lookbehind: true,
  203. inside: {
  204. 'punctuation': /\\/
  205. }
  206. }
  207. ],
  208. 'constant': constant,
  209. 'function': {
  210. pattern: /(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,
  211. lookbehind: true,
  212. inside: {
  213. 'punctuation': /\\/
  214. }
  215. },
  216. 'property': {
  217. pattern: /(->\s*)\w+/,
  218. lookbehind: true
  219. },
  220. 'number': number,
  221. 'operator': operator,
  222. 'punctuation': punctuation
  223. };
  224. var string_interpolation = {
  225. pattern: /\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,
  226. lookbehind: true,
  227. inside: Prism.languages.php
  228. };
  229. var string = [
  230. {
  231. pattern: /<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,
  232. alias: 'nowdoc-string',
  233. greedy: true,
  234. inside: {
  235. 'delimiter': {
  236. pattern: /^<<<'[^']+'|[a-z_]\w*;$/i,
  237. alias: 'symbol',
  238. inside: {
  239. 'punctuation': /^<<<'?|[';]$/
  240. }
  241. }
  242. }
  243. },
  244. {
  245. pattern: /<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,
  246. alias: 'heredoc-string',
  247. greedy: true,
  248. inside: {
  249. 'delimiter': {
  250. pattern: /^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,
  251. alias: 'symbol',
  252. inside: {
  253. 'punctuation': /^<<<"?|[";]$/
  254. }
  255. },
  256. 'interpolation': string_interpolation
  257. }
  258. },
  259. {
  260. pattern: /`(?:\\[\s\S]|[^\\`])*`/,
  261. alias: 'backtick-quoted-string',
  262. greedy: true
  263. },
  264. {
  265. pattern: /'(?:\\[\s\S]|[^\\'])*'/,
  266. alias: 'single-quoted-string',
  267. greedy: true
  268. },
  269. {
  270. pattern: /"(?:\\[\s\S]|[^\\"])*"/,
  271. alias: 'double-quoted-string',
  272. greedy: true,
  273. inside: {
  274. 'interpolation': string_interpolation
  275. }
  276. }
  277. ];
  278. Prism.languages.insertBefore('php', 'variable', {
  279. 'string': string,
  280. 'attribute': {
  281. pattern: /#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,
  282. greedy: true,
  283. inside: {
  284. 'attribute-content': {
  285. pattern: /^(#\[)[\s\S]+(?=\]$)/,
  286. lookbehind: true,
  287. // inside can appear subset of php
  288. inside: {
  289. 'comment': comment,
  290. 'string': string,
  291. 'attribute-class-name': [
  292. {
  293. pattern: /([^:]|^)\b[a-z_]\w*(?!\\)\b/i,
  294. alias: 'class-name',
  295. greedy: true,
  296. lookbehind: true
  297. },
  298. {
  299. pattern: /([^:]|^)(?:\\?\b[a-z_]\w*)+/i,
  300. alias: [
  301. 'class-name',
  302. 'class-name-fully-qualified'
  303. ],
  304. greedy: true,
  305. lookbehind: true,
  306. inside: {
  307. 'punctuation': /\\/
  308. }
  309. }
  310. ],
  311. 'constant': constant,
  312. 'number': number,
  313. 'operator': operator,
  314. 'punctuation': punctuation
  315. }
  316. },
  317. 'delimiter': {
  318. pattern: /^#\[|\]$/,
  319. alias: 'punctuation'
  320. }
  321. }
  322. },
  323. });
  324. Prism.hooks.add('before-tokenize', function (env) {
  325. if (!/<\?/.test(env.code)) {
  326. return;
  327. }
  328. var phpPattern = /<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g;
  329. Prism.languages['markup-templating'].buildPlaceholders(env, 'php', phpPattern);
  330. });
  331. Prism.hooks.add('after-tokenize', function (env) {
  332. Prism.languages['markup-templating'].tokenizePlaceholders(env, 'php');
  333. });
  334. }(Prism));