UNPKG

9.22 kBJavaScriptView Raw
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
32 Prism.languages.php = {
33 'delimiter': {
34 pattern: /\?>$|^<\?(?:php(?=\s)|=)?/i,
35 alias: 'important'
36 },
37 'comment': comment,
38 'variable': /\$+(?:\w+\b|(?=\{))/i,
39 'package': {
40 pattern: /(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
41 lookbehind: true,
42 inside: {
43 'punctuation': /\\/
44 }
45 },
46 'class-name-definition': {
47 pattern: /(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,
48 lookbehind: true,
49 alias: 'class-name'
50 },
51 'function-definition': {
52 pattern: /(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,
53 lookbehind: true,
54 alias: 'function'
55 },
56 'keyword': [
57 {
58 pattern: /(\(\s*)\b(?:bool|boolean|int|integer|float|string|object|array)\b(?=\s*\))/i,
59 alias: 'type-casting',
60 greedy: true,
61 lookbehind: true
62 },
63 {
64 pattern: /([(,?]\s*)\b(?:bool|int|float|string|object|array(?!\s*\()|mixed|self|static|callable|iterable|(?:null|false)(?=\s*\|))\b(?=\s*\$)/i,
65 alias: 'type-hint',
66 greedy: true,
67 lookbehind: true
68 },
69 {
70 pattern: /([(,?]\s*[\w|]\|\s*)(?:null|false)\b(?=\s*\$)/i,
71 alias: 'type-hint',
72 greedy: true,
73 lookbehind: true
74 },
75 {
76 pattern: /(\)\s*:\s*(?:\?\s*)?)\b(?:bool|int|float|string|object|void|array(?!\s*\()|mixed|self|static|callable|iterable|(?:null|false)(?=\s*\|))\b/i,
77 alias: 'return-type',
78 greedy: true,
79 lookbehind: true
80 },
81 {
82 pattern: /(\)\s*:\s*(?:\?\s*)?[\w|]\|\s*)(?:null|false)\b/i,
83 alias: 'return-type',
84 greedy: true,
85 lookbehind: true
86 },
87 {
88 pattern: /\b(?:bool|int|float|string|object|void|array(?!\s*\()|mixed|iterable|(?:null|false)(?=\s*\|))\b/i,
89 alias: 'type-declaration',
90 greedy: true
91 },
92 {
93 pattern: /(\|\s*)(?:null|false)\b/i,
94 alias: 'type-declaration',
95 greedy: true,
96 lookbehind: true
97 },
98 {
99 pattern: /\b(?:parent|self|static)(?=\s*::)/i,
100 alias: 'static-context',
101 greedy: true
102 },
103 {
104 // yield from
105 pattern: /(\byield\s+)from\b/i,
106 lookbehind: true
107 },
108 // `class` is always a keyword unlike other keywords
109 /\bclass\b/i,
110 {
111 // https://www.php.net/manual/en/reserved.keywords.php
112 //
113 // keywords cannot be preceded by "->"
114 // the complex lookbehind means `(?<!(?:->|::)\s*)`
115 pattern: /((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:__halt_compiler|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|namespace|match|new|or|parent|print|private|protected|public|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i,
116 lookbehind: true
117 }
118 ],
119 'argument-name': {
120 pattern: /([(,]\s+)\b[a-z_]\w*(?=\s*:(?!:))/i,
121 lookbehind: true
122 },
123 'class-name': [
124 {
125 pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,
126 greedy: true,
127 lookbehind: true
128 },
129 {
130 pattern: /(\|\s*)\b[a-z_]\w*(?!\\)\b/i,
131 greedy: true,
132 lookbehind: true
133 },
134 {
135 pattern: /\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,
136 greedy: true
137 },
138 {
139 pattern: /(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,
140 alias: 'class-name-fully-qualified',
141 greedy: true,
142 lookbehind: true,
143 inside: {
144 'punctuation': /\\/
145 }
146 },
147 {
148 pattern: /(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,
149 alias: 'class-name-fully-qualified',
150 greedy: true,
151 inside: {
152 'punctuation': /\\/
153 }
154 },
155 {
156 pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
157 alias: 'class-name-fully-qualified',
158 greedy: true,
159 lookbehind: true,
160 inside: {
161 'punctuation': /\\/
162 }
163 },
164 {
165 pattern: /\b[a-z_]\w*(?=\s*\$)/i,
166 alias: 'type-declaration',
167 greedy: true
168 },
169 {
170 pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,
171 alias: ['class-name-fully-qualified', 'type-declaration'],
172 greedy: true,
173 inside: {
174 'punctuation': /\\/
175 }
176 },
177 {
178 pattern: /\b[a-z_]\w*(?=\s*::)/i,
179 alias: 'static-context',
180 greedy: true
181 },
182 {
183 pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,
184 alias: ['class-name-fully-qualified', 'static-context'],
185 greedy: true,
186 inside: {
187 'punctuation': /\\/
188 }
189 },
190 {
191 pattern: /([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,
192 alias: 'type-hint',
193 greedy: true,
194 lookbehind: true
195 },
196 {
197 pattern: /([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,
198 alias: ['class-name-fully-qualified', 'type-hint'],
199 greedy: true,
200 lookbehind: true,
201 inside: {
202 'punctuation': /\\/
203 }
204 },
205 {
206 pattern: /(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,
207 alias: 'return-type',
208 greedy: true,
209 lookbehind: true
210 },
211 {
212 pattern: /(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,
213 alias: ['class-name-fully-qualified', 'return-type'],
214 greedy: true,
215 lookbehind: true,
216 inside: {
217 'punctuation': /\\/
218 }
219 }
220 ],
221 'constant': constant,
222 'function': {
223 pattern: /(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,
224 lookbehind: true,
225 inside: {
226 'punctuation': /\\/
227 }
228 },
229 'property': {
230 pattern: /(->\s*)\w+/,
231 lookbehind: true
232 },
233 'number': number,
234 'operator': operator,
235 'punctuation': punctuation
236 };
237
238 var string_interpolation = {
239 pattern: /\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,
240 lookbehind: true,
241 inside: Prism.languages.php
242 };
243
244 var string = [
245 {
246 pattern: /<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,
247 alias: 'nowdoc-string',
248 greedy: true,
249 inside: {
250 'delimiter': {
251 pattern: /^<<<'[^']+'|[a-z_]\w*;$/i,
252 alias: 'symbol',
253 inside: {
254 'punctuation': /^<<<'?|[';]$/
255 }
256 }
257 }
258 },
259 {
260 pattern: /<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,
261 alias: 'heredoc-string',
262 greedy: true,
263 inside: {
264 'delimiter': {
265 pattern: /^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,
266 alias: 'symbol',
267 inside: {
268 'punctuation': /^<<<"?|[";]$/
269 }
270 },
271 'interpolation': string_interpolation
272 }
273 },
274 {
275 pattern: /`(?:\\[\s\S]|[^\\`])*`/,
276 alias: 'backtick-quoted-string',
277 greedy: true
278 },
279 {
280 pattern: /'(?:\\[\s\S]|[^\\'])*'/,
281 alias: 'single-quoted-string',
282 greedy: true
283 },
284 {
285 pattern: /"(?:\\[\s\S]|[^\\"])*"/,
286 alias: 'double-quoted-string',
287 greedy: true,
288 inside: {
289 'interpolation': string_interpolation
290 }
291 }
292 ];
293
294 Prism.languages.insertBefore('php', 'variable', {
295 'string': string,
296 'attribute': {
297 pattern: /#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,
298 greedy: true,
299 inside: {
300 'attribute-content': {
301 pattern: /^(#\[)[\s\S]+(?=\]$)/,
302 lookbehind: true,
303 // inside can appear subset of php
304 inside: {
305 'comment': comment,
306 'string': string,
307 'attribute-class-name': [
308 {
309 pattern: /([^:]|^)\b[a-z_]\w*(?!\\)\b/i,
310 alias: 'class-name',
311 greedy: true,
312 lookbehind: true
313 },
314 {
315 pattern: /([^:]|^)(?:\\?\b[a-z_]\w*)+/i,
316 alias: [
317 'class-name',
318 'class-name-fully-qualified'
319 ],
320 greedy: true,
321 lookbehind: true,
322 inside: {
323 'punctuation': /\\/
324 }
325 }
326 ],
327 'constant': constant,
328 'number': number,
329 'operator': operator,
330 'punctuation': punctuation
331 }
332 },
333 'delimiter': {
334 pattern: /^#\[|\]$/,
335 alias: 'punctuation'
336 }
337 }
338 },
339 });
340
341 Prism.hooks.add('before-tokenize', function (env) {
342 if (!/<\?/.test(env.code)) {
343 return;
344 }
345
346 var phpPattern = /<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/gi;
347 Prism.languages['markup-templating'].buildPlaceholders(env, 'php', phpPattern);
348 });
349
350 Prism.hooks.add('after-tokenize', function (env) {
351 Prism.languages['markup-templating'].tokenizePlaceholders(env, 'php');
352 });
353
354}(Prism));