1: <?php
2: namespace Pharborist;
3:
4: use Pharborist\Constants\ClassMagicConstantNode;
5: use Pharborist\Constants\DirMagicConstantNode;
6: use Pharborist\Constants\FileMagicConstantNode;
7: use Pharborist\Constants\FunctionMagicConstantNode;
8: use Pharborist\Constants\LineMagicConstantNode;
9: use Pharborist\Constants\MethodMagicConstantNode;
10: use Pharborist\Constants\NamespaceMagicConstantNode;
11: use Pharborist\Constants\TraitMagicConstantNode;
12: use Pharborist\Types\FloatNode;
13: use Pharborist\Types\IntegerNode;
14: use Pharborist\Variables\VariableNode;
15:
16: 17: 18: 19: 20:
21: class Token {
22: 23: 24: 25: 26: 27: 28: 29: 30:
31: public static function parse($text) {
32: static $int_regex = <<<'EOF'
33: /^[+-]?(?:
34: 0
35: | [1-9][0-9]*
36: | 0[xX][0-9a-fA-F]+
37: | 0[0-7]+
38: | 0b[01]+
39: )$/x
40: EOF;
41: static $decimal_regex = <<<EOF
42: /^[+-]?(?:
43: [0-9]*\.[0-9]+ (?:[eE][+-]?[0-9]+)?
44: | [0-9]+\.[0-9]* (?:[eE][+-]?[0-9]+)?
45: | [0-9]+[eE][+-]?[0-9]+
46: )$/x
47: EOF;
48: static $var_regex = '/^\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/';
49: switch ($text) {
50: case 'abstract':
51: return static::_abstract();
52: case 'array':
53: return static::_array();
54: case 'as':
55: return static::_as();
56: case 'break':
57: return static::_break();
58: case 'callable':
59: return static::_callable();
60: case 'case':
61: return static::_case();
62: case 'catch':
63: return static::_catch();
64: case 'class':
65: return static::_class();
66: case 'clone':
67: return static::_clone();
68: case 'const':
69: return static::_const();
70: case 'continue':
71: return static::_continue();
72: case 'declare':
73: return static::_declare();
74: case 'default':
75: return static::_default();
76: case 'die':
77: return static::_die();
78: case 'do':
79: return static::_do();
80: case 'echo':
81: return static::_echo();
82: case 'else':
83: return static::_else();
84: case 'elseif':
85: return static::_elseIf();
86: case 'empty':
87: return static::_empty();
88: case 'enddeclare':
89: return static::_endDeclare();
90: case 'endfor':
91: return static::_endFor();
92: case 'endforeach':
93: return static::_endForeach();
94: case 'endif':
95: return static::_endIf();
96: case 'endswitch':
97: return static::_endSwitch();
98: case 'endwhile':
99: return static::_endWhile();
100: case 'eval':
101: return static::_eval();
102: case 'exit':
103: return static::_exit();
104: case 'extends':
105: return static::_extends();
106: case 'final':
107: return static::_final();
108: case 'finally':
109: return static::_finally();
110: case 'for':
111: return static::_for();
112: case 'foreach':
113: return static::_foreach();
114: case 'function':
115: return static::_function();
116: case 'global':
117: return static::_global();
118: case 'goto':
119: return static::_goto();
120: case 'if':
121: return static::_if();
122: case 'implements':
123: return static::_implements();
124: case 'include':
125: return static::_include();
126: case 'include_once':
127: return static::_includeOnce();
128: case 'instanceof':
129: return static::_instanceOf();
130: case 'insteadof':
131: return static::_insteadOf();
132: case 'interface':
133: return static::_interface();
134: case 'isset':
135: return static::_isset();
136: case 'list':
137: return static::_list();
138: case 'namespace':
139: return static::_namespace();
140: case 'new':
141: return static::_new();
142: case 'print':
143: return static::_print();
144: case 'private':
145: return static::_private();
146: case 'protected':
147: return static::_protected();
148: case 'public':
149: return static::_public();
150: case 'require':
151: return static::_require();
152: case 'require_once':
153: return static::_requireOnce();
154: case 'return':
155: return static::_return();
156: case 'static':
157: return static::_static();
158: case 'switch':
159: return static::_switch();
160: case 'throw':
161: return static::_throw();
162: case 'trait':
163: return static::_trait();
164: case 'try':
165: return static::_try();
166: case 'unset':
167: return static::_unset();
168: case 'use':
169: return static::_use();
170: case 'var':
171: return static::_var();
172: case 'while':
173: return static::_while();
174: case 'yield':
175: return static::_yield();
176: case 'and':
177: return static::logicalAnd();
178: case 'or':
179: return static::logicalOr();
180: case 'xor':
181: return static::logicalXor();
182: case '(array)':
183: return static::arrayCast();
184: case '(bool)':
185: case '(boolean)':
186: return static::booleanCast();
187: case '(real)':
188: case '(double)':
189: case '(float)':
190: return static::doubleCast();
191: case '(int)':
192: case '(integer)':
193: return static::integerCast();
194: case '(object)':
195: return static::objectCast();
196: case '(string)':
197: return static::stringCast();
198: case '(unset)':
199: return static::unsetCast();
200: case '__halt_compiler':
201: return static::haltCompiler();
202: case '__CLASS__':
203: return static::classConstant();
204: case '__DIR__':
205: return static::dirConstant();
206: case '__FILE__':
207: return static::fileConstant();
208: case '__FUNCTION__':
209: return static::functionConstant();
210: case '__LINE__':
211: return static::lineConstant();
212: case '__METHOD__':
213: return static::methodConstant();
214: case '__NAMESPACE__':
215: return static::namespaceConstant();
216: case '__TRAIT__':
217: return static::traitConstant();
218: case '...':
219: return static::splat();
220: case '=>':
221: return static::doubleArrow();
222: case '->':
223: return static::objectOperator();
224: case '::':
225: return static::doubleColon();
226: case '&=':
227: return static::bitwiseAndAssign();
228: case '|=':
229: return static::bitwiseOrAssign();
230: case '^=':
231: return static::bitwiseXorAssign();
232: case '*=':
233: return static::multiplyAssign();
234: case '/=':
235: return static::divideAssign();
236: case '%=':
237: return static::modulusAssign();
238: case '+=':
239: return static::addAssign();
240: case '-=':
241: return static::subtractAssign();
242: case '.=':
243: return static::concatAssign();
244: case '===':
245: return static::isIdentical();
246: case '==':
247: return static::isEqual();
248: case '!==':
249: return static::isNotIdentical();
250: case '!=':
251: return static::isNotEqual();
252: case '<=':
253: return static::isLessThanOrEqual();
254: case '>=':
255: return static::isGreaterThanOrEqual();
256: case '&&':
257: return static::booleanAnd();
258: case '||':
259: return static::booleanOr();
260: case '<<':
261: return static::bitwiseShiftLeft();
262: case '<<=':
263: return static::bitwiseShiftLeftAssign();
264: case '>>':
265: return static::bitwiseShiftRight();
266: case '>>=':
267: return static::bitwiseShiftRightAssign();
268: case '\\':
269: return static::namespaceSeparator();
270: case '--':
271: return static::decrement();
272: case '++':
273: return static::increment();
274: case '`':
275: case '~':
276: case '!':
277: case '@':
278: case '%':
279: case '^':
280: case '&':
281: case '*':
282: case '(':
283: case ')':
284: case '-':
285: case '+':
286: case '=':
287: case '{':
288: case '}':
289: case '[':
290: case ']':
291: case '|':
292: case ':':
293: case ';':
294: case "'":
295: case '"':
296: case '<':
297: case ',':
298: case '>':
299: case '.':
300: case '?':
301: case '/':
302: return new TokenNode($text, $text);
303: case ' ':
304: return static::space();
305: case '?>':
306: return static::closeTag();
307: default:
308: if (rtrim($text) === '<?php') {
309: return static::openTag();
310: }
311: elseif (preg_match($int_regex, $text)) {
312: return static::integer($text);
313: }
314: elseif (preg_match($decimal_regex, $text)) {
315: return static::decimalNumber($text);
316: }
317: elseif (preg_match($var_regex, $text)) {
318: return static::variable($text);
319: }
320:
321: throw new \InvalidArgumentException("Unable to parse '{$text}'");
322: }
323: }
324:
325: public static function _abstract() {
326: return new TokenNode(T_ABSTRACT, 'abstract');
327: }
328:
329: public static function add() {
330: return new TokenNode('+', '+');
331: }
332:
333: public static function addAssign() {
334: return new TokenNode(T_PLUS_EQUAL, '+=');
335: }
336:
337: public static function _array() {
338: return new TokenNode(T_ARRAY, 'array');
339: }
340:
341: public static function arrayCast() {
342: return new TokenNode(T_ARRAY_CAST, '(array)');
343: }
344:
345: public static function _as() {
346: return new TokenNode(T_AS, 'as');
347: }
348:
349: public static function assign() {
350: return new TokenNode('=', '=');
351: }
352:
353: public static function backtick() {
354: return new TokenNode('`', '`');
355: }
356:
357: public static function bitwiseAnd() {
358: return new TokenNode('&', '&');
359: }
360:
361: public static function bitwiseAndAssign() {
362: return new TokenNode(T_AND_EQUAL, '&=');
363: }
364:
365: public static function bitwiseNot() {
366: return new TokenNode('~', '~');
367: }
368:
369: public static function bitwiseOr() {
370: return new TokenNode('|', '|');
371: }
372:
373: public static function bitwiseOrAssign() {
374: return new TokenNode(T_OR_EQUAL, '|=');
375: }
376:
377: public static function bitwiseXor() {
378: return new TokenNode('^', '^');
379: }
380:
381: public static function bitwiseXorAssign() {
382: return new TokenNode(T_XOR_EQUAL, '^=');
383: }
384:
385: public static function bitwiseShiftLeft() {
386: return new TokenNode(T_SL, '<<');
387: }
388:
389: public static function bitwiseShiftLeftAssign() {
390: return new TokenNode(T_SL_EQUAL, '<<=');
391: }
392:
393: public static function bitwiseShiftRight() {
394: return new TokenNode(T_SR, '>>');
395: }
396:
397: public static function bitwiseShiftRightAssign() {
398: return new TokenNode(T_SR_EQUAL, '>>=');
399: }
400:
401: public static function booleanAnd() {
402: return new TokenNode(T_BOOLEAN_AND, '&&');
403: }
404:
405: public static function booleanOr() {
406: return new TokenNode(T_BOOLEAN_OR, '||');
407: }
408:
409: public static function booleanCast() {
410: return new TokenNode(T_BOOL_CAST, '(boolean)');
411: }
412:
413: public static function _break() {
414: return new TokenNode(T_BREAK, 'break');
415: }
416:
417: public static function _callable() {
418: return new TokenNode(T_CALLABLE, 'callable');
419: }
420:
421: public static function _case() {
422: return new TokenNode(T_CASE, 'case');
423: }
424:
425: public static function _catch() {
426: return new TokenNode(T_CATCH, 'catch');
427: }
428:
429: public static function _class() {
430: return new TokenNode(T_CLASS, 'class');
431: }
432:
433: public static function classConstant() {
434: return new ClassMagicConstantNode(T_CLASS_C, '__CLASS__');
435: }
436:
437: public static function _clone() {
438: return new TokenNode(T_CLONE, 'clone');
439: }
440:
441: public static function closeTag() {
442: return new TokenNode(T_CLOSE_TAG, '?>');
443: }
444:
445: public static function colon() {
446: return new TokenNode(':', ':');
447: }
448:
449: public static function comma() {
450: return new TokenNode(',', ',');
451: }
452:
453: public static function concat() {
454: return new TokenNode('.', '.');
455: }
456:
457: public static function concatAssign() {
458: return new TokenNode(T_CONCAT_EQUAL, '.=');
459: }
460:
461: public static function _const() {
462: return new TokenNode(T_CONST, 'const');
463: }
464:
465: public static function _continue() {
466: return new TokenNode(T_CONTINUE, 'continue');
467: }
468:
469: public static function curlyOpen() {
470: return new TokenNode(T_CURLY_OPEN, '{');
471: }
472:
473: public static function decrement() {
474: return new TokenNode(T_DEC, '--');
475: }
476:
477: public static function _declare() {
478: return new TokenNode(T_DECLARE, 'declare');
479: }
480:
481: public static function _default() {
482: return new TokenNode(T_DEFAULT, 'default');
483: }
484:
485: public static function dirConstant() {
486: return new DirMagicConstantNode(T_DIR, '__DIR__');
487: }
488:
489: public static function _die() {
490: return new TokenNode(T_EXIT, 'die');
491: }
492:
493: public static function divide() {
494: return new TokenNode('/', '/');
495: }
496:
497: public static function divideAssign() {
498: return new TokenNode(T_DIV_EQUAL, '/=');
499: }
500:
501: public static function decimalNumber($number) {
502: return new FloatNode(T_DNUMBER, $number);
503: }
504:
505: public static function _do() {
506: return new TokenNode(T_DO, 'do');
507: }
508:
509: public static function dollarOpenCurly() {
510: return new TokenNode(T_DOLLAR_OPEN_CURLY_BRACES, '${');
511: }
512:
513: public static function doubleArrow() {
514: return new TokenNode(T_DOUBLE_ARROW, '=>');
515: }
516:
517: public static function doubleCast() {
518: return new TokenNode(T_DOUBLE_CAST, '(double)');
519: }
520:
521: public static function doubleColon() {
522: return new TokenNode(T_DOUBLE_COLON, '::');
523: }
524:
525: public static function _echo() {
526: return new TokenNode(T_ECHO, 'echo');
527: }
528:
529: public static function _else() {
530: return new TokenNode(T_ELSE, 'else');
531: }
532:
533: public static function _elseIf() {
534: return new TokenNode(T_ELSEIF, 'elseif');
535: }
536:
537: public static function _empty() {
538: return new TokenNode(T_EMPTY, 'empty');
539: }
540:
541: public static function _endDeclare() {
542: return new TokenNode(T_ENDDECLARE, 'enddeclare');
543: }
544:
545: public static function _endFor() {
546: return new TokenNode(T_ENDFOR, 'endfor');
547: }
548:
549: public static function _endForeach() {
550: return new TokenNode(T_ENDFOREACH, 'endforeach');
551: }
552:
553: public static function _endIf() {
554: return new TokenNode(T_ENDIF, 'endif');
555: }
556:
557: public static function _endSwitch() {
558: return new TokenNode(T_ENDSWITCH, 'endswitch');
559: }
560:
561: public static function _endWhile() {
562: return new TokenNode(T_ENDWHILE, 'endwhile');
563: }
564:
565: public static function _eval() {
566: return new TokenNode(T_EVAL, 'eval');
567: }
568:
569: public static function _exit() {
570: return new TokenNode(T_EXIT, 'exit');
571: }
572:
573: public static function _extends() {
574: return new TokenNode(T_EXTENDS, 'extends');
575: }
576:
577: public static function fileConstant() {
578: return new FileMagicConstantNode(T_FILE, '__FILE__');
579: }
580:
581: public static function _final() {
582: return new TokenNode(T_FINAL, 'final');
583: }
584:
585: public static function _finally() {
586: return new TokenNode(T_FINALLY, 'finally');
587: }
588:
589: public static function _for() {
590: return new TokenNode(T_FOR, 'for');
591: }
592:
593: public static function _foreach() {
594: return new TokenNode(T_FOREACH, 'foreach');
595: }
596:
597: public static function _function() {
598: return new TokenNode(T_FUNCTION, 'function');
599: }
600:
601: public static function functionConstant() {
602: return new FunctionMagicConstantNode(T_FUNC_C, '__FUNCTION__');
603: }
604:
605: public static function _global() {
606: return new TokenNode(T_GLOBAL, 'global');
607: }
608:
609: public static function _goto() {
610: return new TokenNode(T_GOTO, 'goto');
611: }
612:
613: public static function haltCompiler() {
614: return new TokenNode(T_HALT_COMPILER, '__halt_compiler');
615: }
616:
617: public static function identifier($id) {
618: return new TokenNode(T_STRING, $id);
619: }
620:
621: public static function _if() {
622: return new TokenNode(T_IF, 'if');
623: }
624:
625: public static function _implements() {
626: return new TokenNode(T_IMPLEMENTS, 'implements');
627: }
628:
629: public static function increment() {
630: return new TokenNode(T_INC, '++');
631: }
632:
633: public static function _include() {
634: return new TokenNode(T_INCLUDE, 'include');
635: }
636:
637: public static function _includeOnce() {
638: return new TokenNode(T_INCLUDE_ONCE, 'include_once');
639: }
640:
641: public static function inlineHtml($html) {
642: return new TokenNode(T_INLINE_HTML, $html);
643: }
644:
645: public static function _instanceOf() {
646: return new TokenNode(T_INSTANCEOF, 'instanceof');
647: }
648:
649: public static function _insteadOf() {
650: return new TokenNode(T_INSTEADOF, 'insteadof');
651: }
652:
653: public static function integerCast() {
654: return new TokenNode(T_INT_CAST, '(integer)');
655: }
656:
657: public static function _interface() {
658: return new TokenNode(T_INTERFACE, 'interface');
659: }
660:
661: public static function _isset() {
662: return new TokenNode(T_ISSET, 'isset');
663: }
664:
665: public static function isEqual() {
666: return new TokenNode(T_IS_EQUAL, '==');
667: }
668:
669: public static function isGreaterThan() {
670: return new TokenNode('>', '>');
671: }
672:
673: public static function isGreaterThanOrEqual() {
674: return new TokenNode(T_IS_GREATER_OR_EQUAL, '>=');
675: }
676:
677: public static function isIdentical() {
678: return new TokenNode(T_IS_IDENTICAL, '===');
679: }
680:
681: public static function isNotEqual() {
682: return new TokenNode(T_IS_NOT_EQUAL, '!=');
683: }
684:
685: public static function isNotIdentical() {
686: return new TokenNode(T_IS_NOT_IDENTICAL, '!==');
687: }
688:
689: public static function isLessThan() {
690: return new TokenNode('<', '<');
691: }
692:
693: public static function isLessThanOrEqual() {
694: return new TokenNode(T_IS_SMALLER_OR_EQUAL, '<=');
695: }
696:
697: public static function lineConstant() {
698: return new LineMagicConstantNode(T_LINE, '__LINE__');
699: }
700:
701: public static function _list() {
702: return new TokenNode(T_LIST, 'list');
703: }
704:
705: public static function integer($number) {
706: return new IntegerNode(T_LNUMBER, $number);
707: }
708:
709: public static function logicalAnd() {
710: return new TokenNode(T_LOGICAL_AND, 'and');
711: }
712:
713: public static function logicalOr() {
714: return new TokenNode(T_LOGICAL_OR, 'or');
715: }
716:
717: public static function logicalXor() {
718: return new TokenNode(T_LOGICAL_XOR, 'xor');
719: }
720:
721: public static function methodConstant() {
722: return new MethodMagicConstantNode(T_METHOD_C, '__METHOD__');
723: }
724:
725: public static function modulus() {
726: return new TokenNode('%', '%');
727: }
728:
729: public static function modulusAssign() {
730: return new TokenNode(T_MOD_EQUAL, '%=');
731: }
732:
733: public static function multiply() {
734: return new TokenNode('*', '*');
735: }
736:
737: public static function multiplyAssign() {
738: return new TokenNode(T_MUL_EQUAL, '*=');
739: }
740:
741: public static function _namespace() {
742: return new TokenNode(T_NAMESPACE, 'namespace');
743: }
744:
745: public static function namespaceConstant() {
746: return new NamespaceMagicConstantNode(T_NS_C, '__NAMESPACE__');
747: }
748:
749: public static function namespaceSeparator() {
750: return new TokenNode(T_NS_SEPARATOR, '\\');
751: }
752:
753: public static function _new() {
754: return new TokenNode(T_NEW, 'new');
755: }
756:
757: public static function newline() {
758: return Token::whitespace("\n");
759: }
760:
761: public static function not() {
762: return new TokenNode('!', '!');
763: }
764:
765: public static function numString($index) {
766: return new TokenNode(T_NUM_STRING, $index);
767: }
768:
769: public static function objectCast() {
770: return new TokenNode(T_OBJECT_CAST, '(object)');
771: }
772:
773: public static function objectOperator() {
774: return new TokenNode(T_OBJECT_OPERATOR, '->');
775: }
776:
777: public static function openTag() {
778: return new TokenNode(T_OPEN_TAG, '<?php' . "\n");
779: }
780:
781: public static function openEchoTag() {
782: return new TokenNode(T_OPEN_TAG_WITH_ECHO, '<?=');
783: }
784:
785: public static function _print() {
786: return new TokenNode(T_PRINT, 'print');
787: }
788:
789: public static function _public() {
790: return new TokenNode(T_PUBLIC, 'public');
791: }
792:
793: public static function _protected() {
794: return new TokenNode(T_PROTECTED, 'protected');
795: }
796:
797: public static function _private() {
798: return new TokenNode(T_PRIVATE, 'private');
799: }
800:
801: public static function reference() {
802: return new TokenNode('&', '&');
803: }
804:
805: public static function _require() {
806: return new TokenNode(T_REQUIRE, 'require');
807: }
808:
809: public static function _requireOnce() {
810: return new TokenNode(T_REQUIRE_ONCE, 'require_once');
811: }
812:
813: public static function _return() {
814: return new TokenNode(T_RETURN, 'return');
815: }
816:
817: public static function semiColon() {
818: return new TokenNode(';', ';');
819: }
820:
821: public static function splat() {
822: return new TokenNode(T_ELLIPSIS, '...');
823: }
824:
825: public static function subtract() {
826: return new TokenNode('-', '-');
827: }
828:
829: public static function subtractAssign() {
830: return new TokenNode(T_MINUS_EQUAL, '-=');
831: }
832:
833: public static function space() {
834: return Token::whitespace(' ');
835: }
836:
837: public static function _static() {
838: return new TokenNode(T_STATIC, 'static');
839: }
840:
841: public static function stringCast() {
842: return new TokenNode(T_STRING_CAST, '(string)');
843: }
844:
845: public static function suppress() {
846: return new TokenNode('@', '@');
847: }
848:
849: public static function _switch() {
850: return new TokenNode(T_SWITCH, 'switch');
851: }
852:
853: public static function ternaryOperator() {
854: return new TokenNode('?', '?');
855: }
856:
857: public static function _throw() {
858: return new TokenNode(T_THROW, 'throw');
859: }
860:
861: public static function _trait() {
862: return new TokenNode(T_TRAIT, 'trait');
863: }
864:
865: public static function traitConstant() {
866: return new TraitMagicConstantNode(T_TRAIT_C, '__TRAIT__');
867: }
868:
869: public static function _try() {
870: return new TokenNode(T_TRY, 'try');
871: }
872:
873: public static function _unset() {
874: return new TokenNode(T_UNSET, 'unset');
875: }
876:
877: public static function unsetCast() {
878: return new TokenNode(T_UNSET_CAST, '(unset)');
879: }
880:
881: public static function _use() {
882: return new TokenNode(T_USE, 'use');
883: }
884:
885: public static function _var() {
886: return new TokenNode(T_VAR, 'var');
887: }
888:
889: public static function variable($var) {
890: return new VariableNode(T_VARIABLE, $var);
891: }
892:
893: public static function _while() {
894: return new TokenNode(T_WHILE, 'while');
895: }
896:
897: public static function whitespace($ws) {
898: return WhitespaceNode::create($ws);
899: }
900:
901: public static function _yield() {
902: return new TokenNode(T_YIELD, 'yield');
903: }
904:
905: public static function openBrace() {
906: return new TokenNode('{', '{');
907: }
908:
909: public static function closeBrace() {
910: return new TokenNode('}', '}');
911: }
912:
913: public static function openBracket() {
914: return new TokenNode('[', '[');
915: }
916:
917: public static function closeBracket() {
918: return new TokenNode(']', ']');
919: }
920:
921: public static function openParen() {
922: return new TokenNode('(', '(');
923: }
924:
925: public static function closeParen() {
926: return new TokenNode(')', ')');
927: }
928:
929: public static function startHeredoc($label) {
930: return new TokenNode(T_START_HEREDOC, "<<<{$label}\n");
931: }
932:
933: public static function endHeredoc($label) {
934: return new TokenNode(T_END_HEREDOC, $label);
935: }
936:
937: public static function startNowdoc($label) {
938: return new TokenNode(T_START_HEREDOC, "<<<'{$label}'\n");
939: }
940:
941: public static function endNowdoc($label) {
942: return static::endHeredoc($label);
943: }
944:
945: public static function doubleQuote() {
946: return new TokenNode('"', '"');
947: }
948: }
949: