UNPKG

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