68 define(
'TOKEN_END', 1);
69 define(
'TOKEN_NUMBER', 2);
70 define(
'TOKEN_IDENTIFIER', 3);
71 define(
'TOKEN_STRING', 4);
72 define(
'TOKEN_REGEXP', 5);
73 define(
'TOKEN_NEWLINE', 6);
74 define(
'TOKEN_CONDCOMMENT_START', 7);
75 define(
'TOKEN_CONDCOMMENT_END', 8);
77 define(
'JS_SCRIPT', 100);
78 define(
'JS_BLOCK', 101);
79 define(
'JS_LABEL', 102);
80 define(
'JS_FOR_IN', 103);
81 define(
'JS_CALL', 104);
82 define(
'JS_NEW_WITH_ARGS', 105);
83 define(
'JS_INDEX', 106);
84 define(
'JS_ARRAY_INIT', 107);
85 define(
'JS_OBJECT_INIT', 108);
86 define(
'JS_PROPERTY_INIT', 109);
87 define(
'JS_GETTER', 110);
88 define(
'JS_SETTER', 111);
89 define(
'JS_GROUP', 112);
90 define(
'JS_LIST', 113);
92 define(
'JS_MINIFIED', 999);
94 define(
'DECLARED_FORM', 0);
95 define(
'EXPRESSED_FORM', 1);
96 define(
'STATEMENT_FORM', 2);
99 define(
'OP_SEMICOLON',
';');
100 define(
'OP_COMMA',
',');
101 define(
'OP_HOOK',
'?');
102 define(
'OP_COLON',
':');
103 define(
'OP_OR',
'||');
104 define(
'OP_AND',
'&&');
105 define(
'OP_BITWISE_OR',
'|');
106 define(
'OP_BITWISE_XOR',
'^');
107 define(
'OP_BITWISE_AND',
'&');
108 define(
'OP_STRICT_EQ',
'===');
109 define(
'OP_EQ',
'==');
110 define(
'OP_ASSIGN',
'=');
111 define(
'OP_STRICT_NE',
'!==');
112 define(
'OP_NE',
'!=');
113 define(
'OP_LSH',
'<<');
114 define(
'OP_LE',
'<=');
115 define(
'OP_LT',
'<');
116 define(
'OP_URSH',
'>>>');
117 define(
'OP_RSH',
'>>');
118 define(
'OP_GE',
'>=');
119 define(
'OP_GT',
'>');
120 define(
'OP_INCREMENT',
'++');
121 define(
'OP_DECREMENT',
'--');
122 define(
'OP_PLUS',
'+');
123 define(
'OP_MINUS',
'-');
124 define(
'OP_MUL',
'*');
125 define(
'OP_DIV',
'/');
126 define(
'OP_MOD',
'%');
127 define(
'OP_NOT',
'!');
128 define(
'OP_BITWISE_NOT',
'~');
129 define(
'OP_DOT',
'.');
130 define(
'OP_LEFT_BRACKET',
'[');
131 define(
'OP_RIGHT_BRACKET',
']');
132 define(
'OP_LEFT_CURLY',
'{');
133 define(
'OP_RIGHT_CURLY',
'}');
134 define(
'OP_LEFT_PAREN',
'(');
135 define(
'OP_RIGHT_PAREN',
')');
136 define(
'OP_CONDCOMMENT_END',
'@*/');
138 define(
'OP_UNARY_PLUS',
'U+');
139 define(
'OP_UNARY_MINUS',
'U-');
142 define(
'KEYWORD_BREAK',
'break');
143 define(
'KEYWORD_CASE',
'case');
144 define(
'KEYWORD_CATCH',
'catch');
145 define(
'KEYWORD_CONST',
'const');
146 define(
'KEYWORD_CONTINUE',
'continue');
147 define(
'KEYWORD_DEBUGGER',
'debugger');
148 define(
'KEYWORD_DEFAULT',
'default');
149 define(
'KEYWORD_DELETE',
'delete');
150 define(
'KEYWORD_DO',
'do');
151 define(
'KEYWORD_ELSE',
'else');
152 define(
'KEYWORD_ENUM',
'enum');
153 define(
'KEYWORD_FALSE',
'false');
154 define(
'KEYWORD_FINALLY',
'finally');
155 define(
'KEYWORD_FOR',
'for');
156 define(
'KEYWORD_FUNCTION',
'function');
157 define(
'KEYWORD_IF',
'if');
158 define(
'KEYWORD_IN',
'in');
159 define(
'KEYWORD_INSTANCEOF',
'instanceof');
160 define(
'KEYWORD_NEW',
'new');
161 define(
'KEYWORD_NULL',
'null');
162 define(
'KEYWORD_RETURN',
'return');
163 define(
'KEYWORD_SWITCH',
'switch');
164 define(
'KEYWORD_THIS',
'this');
165 define(
'KEYWORD_THROW',
'throw');
166 define(
'KEYWORD_TRUE',
'true');
167 define(
'KEYWORD_TRY',
'try');
168 define(
'KEYWORD_TYPEOF',
'typeof');
169 define(
'KEYWORD_VAR',
'var');
170 define(
'KEYWORD_VOID',
'void');
171 define(
'KEYWORD_WHILE',
'while');
172 define(
'KEYWORD_WITH',
'with');
179 'break',
'case',
'catch',
'continue',
'default',
'delete',
'do',
180 'else',
'finally',
'for',
'function',
'if',
'in',
'instanceof',
181 'new',
'return',
'switch',
'this',
'throw',
'try',
'typeof',
'var',
182 'void',
'while',
'with',
184 'abstract',
'boolean',
'byte',
'char',
'class',
'const',
'debugger',
185 'double',
'enum',
'export',
'extends',
'final',
'float',
'goto',
186 'implements',
'import',
'int',
'interface',
'long',
'native',
187 'package',
'private',
'protected',
'public',
'short',
'static',
188 'super',
'synchronized',
'throws',
'transient',
'volatile',
191 'arguments',
'eval',
'true',
'false',
'Infinity',
'NaN',
'null',
'undefined'
199 public static function minify($js, $filename=
'')
207 return $instance->min($js, $filename);
210 private function min($js, $filename)
214 $n = $this->
parser->parse($js, $filename, 1);
219 echo
$e->getMessage() .
"\n";
237 $noBlockGrouping =
true;
241 $childs = $n->treeNodes;
243 for ($c = 0, $i = 0, $j =
count($childs); $i < $j; $i++)
245 $type = $childs[$i]->type;
261 $t =
',' . substr(
$t, 4);
277 if ($c > 1 && !$noBlockGrouping)
284 $s .=
'function' . ($n->name ?
' ' . $n->name :
'') .
'(';
288 $s .=
'){' . $this->
parseTree($n->body,
true) .
'}';
292 $s =
'if(' . $this->
parseTree($n->condition) .
')';
293 $thenPart = $this->
parseTree($n->thenPart);
294 $elsePart = $n->elsePart ? $this->
parseTree($n->elsePart) :
null;
303 if ($thenPart !=
';' && $thenPart[0] !=
'{')
304 $thenPart =
'{' . $thenPart .
'}';
306 $s .= $thenPart .
'else';
309 if ($elsePart[0] !=
'{')
321 $s =
'switch(' . $this->
parseTree($n->discriminant) .
'){';
323 for ($i = 0, $j =
count($cases); $i < $j; $i++)
331 $statement = $this->
parseTree($case->statements,
true);
344 $s =
'for(' . ($n->setup ? $this->
parseTree($n->setup) :
'')
345 .
';' . ($n->condition ? $this->parseTree($n->condition) :
'')
346 .
';' . ($n->update ? $this->parseTree($n->update) :
'') .
')';
356 $s =
'while(' . $this->
parseTree($n->condition) .
')';
376 $s =
'do{' . $this->
parseTree($n->body,
true) .
'}while(' . $this->
parseTree($n->condition) .
')';
381 $s = $n->value . ($n->label ?
' ' . $n->label :
'');
385 $s =
'try{' . $this->
parseTree($n->tryBlock,
true) .
'}';
386 $catchClauses = $n->catchClauses;
387 for ($i = 0, $j =
count($catchClauses); $i < $j; $i++)
389 $t = $catchClauses[$i];
390 $s .=
'catch(' .
$t->varName . (
$t->guard ?
' if ' . $this->
parseTree(
$t->guard) :
'') .
'){' . $this->
parseTree(
$t->block,
true) .
'}';
392 if ($n->finallyBlock)
393 $s .=
'finally{' . $this->
parseTree($n->finallyBlock,
true) .
'}';
418 $s = $n->value .
' ';
419 $childs = $n->treeNodes;
420 for ($i = 0, $j =
count($childs); $i < $j; $i++)
423 $s .= ($i ?
',' :
'') .
$t->name;
424 $u =
$t->initializer;
432 $left = $this->
parseTree($n->treeNodes[0]);
433 $right = $this->
parseTree($n->treeNodes[1]);
442 if ($this->
isWordChar($right[0]) || $right[0] ==
'\\')
450 $right = $this->
parseTree($n->treeNodes[0]);
454 if ($this->
isWordChar($right[0]) || $right[0] ==
'\\')
461 $s =
'void(' . $this->
parseTree($n->treeNodes[0]) .
')';
465 throw new Exception(
'NOT IMPLEMENTED: DEBUGGER');
471 $childs = $n->treeNodes;
472 for ($i = 0, $j =
count($childs); $i < $j; $i++)
477 if ($expression = $n->expression)
482 $s = $n->label .
':' . $this->
parseTree($n->statement);
486 $childs = $n->treeNodes;
487 for ($i = 0, $j =
count($childs); $i < $j; $i++)
488 $s .= ($i ?
',' :
'') . $this->
parseTree($childs[$i]);
510 $left = $this->
parseTree($n->treeNodes[0]);
511 $right = $this->
parseTree($n->treeNodes[1]);
513 switch ($n->treeNodes[1]->type)
521 $s = $left . $n->type .
' ' . $right;
526 if ($n->type ==
OP_PLUS && substr($left, -1) == $right[0])
528 $s = substr($left, 0, -1) . substr($right, 1);
534 $s = $left . $n->type . $right;
542 $s = $n->value . $this->
parseTree($n->treeNodes[0]);
548 $s = $this->
parseTree($n->treeNodes[0]) . $n->value;
550 $s = $n->value . $this->
parseTree($n->treeNodes[0]);
562 $this->isValidIdentifier(substr($n->treeNodes[1]->value, 1, -1))
564 $s .=
'.' . substr($n->treeNodes[1]->value, 1, -1);
566 $s .=
'[' . $this->
parseTree($n->treeNodes[1]) .
']';
570 $childs = $n->treeNodes;
571 for ($i = 0, $j =
count($childs); $i < $j; $i++)
572 $s .= ($i ?
',' :
'') . $this->
parseTree($childs[$i]);
586 $childs = $n->treeNodes;
587 for ($i = 0, $j =
count($childs); $i < $j; $i++)
589 $s .= ($i ?
',' :
'') . $this->
parseTree($childs[$i]);
596 $childs = $n->treeNodes;
597 for ($i = 0, $j =
count($childs); $i < $j; $i++)
606 $this->isValidIdentifier(substr(
$t->treeNodes[0]->value, 1, -1))
608 $s .= substr(
$t->treeNodes[0]->value, 1, -1);
610 $s .=
$t->treeNodes[0]->value;
617 $s .=
' ' .
$t->name .
'(';
629 if (preg_match(
'/^([1-9]+)(0{3,})$/',
$s, $m))
630 $s = $m[1] .
'e' . strlen($m[2]);
640 $n->treeNodes[0]->type,
652 $s =
'(' . $this->
parseTree($n->treeNodes[0]) .
')';
657 throw new Exception(
'UNKNOWN TOKEN TYPE: ' . $n->type);
665 return preg_match(
'/^[a-zA-Z_][a-zA-Z0-9_]*$/', $string) && !in_array($string, $this->reserved);
670 return $char ==
'_' || $char ==
'$' || ctype_alnum($char);
682 '=' => 2,
'?' => 2,
':' => 2,
689 '==' => 9,
'!=' => 9,
'===' => 9,
'!==' => 9,
690 '<' => 10,
'<=' => 10,
'>=' => 10,
'>' => 10,
'in' => 10,
'instanceof' => 10,
691 '<<' => 11,
'>>' => 11,
'>>>' => 11,
692 '+' => 12,
'-' => 12,
693 '*' => 13,
'/' => 13,
'%' => 13,
694 'delete' => 14,
'void' => 14,
'typeof' => 14,
695 '!' => 14,
'~' => 14,
'U+' => 14,
'U-' => 14,
696 '++' => 15,
'--' => 15,
712 '==' => 2,
'!=' => 2,
'===' => 2,
'!==' => 2,
713 '<' => 2,
'<=' => 2,
'>=' => 2,
'>' => 2,
'in' => 2,
'instanceof' => 2,
714 '<<' => 2,
'>>' => 2,
'>>>' => 2,
716 '*' => 2,
'/' => 2,
'%' => 2,
717 'delete' => 1,
'void' => 1,
'typeof' => 1,
718 '!' => 1,
'~' => 1,
'U+' => 1,
'U-' => 1,
719 '++' => 1,
'--' => 1,
736 $this->t->init(
$s,
$f, $l);
740 if (!$this->t->isDone())
741 throw $this->t->newSyntaxError(
'Syntax error');
750 $n->funDecls = $x->funDecls;
751 $n->varDecls = $x->varDecls;
756 $n->value = $this->minifier->parseTree($n);
759 $n->treeNodes =
null;
772 array_push($x->stmtStack, $n);
775 $n->addNode($this->Statement($x));
777 array_pop($x->stmtStack);
793 $tt = $this->t->get();
814 $n =
new JSNode($this->t);
816 array_push($x->stmtStack, $n);
819 array_pop($x->stmtStack);
823 $n =
new JSNode($this->t);
828 $n->defaultIndex = -1;
830 array_push($x->stmtStack, $n);
839 if ($n->defaultIndex >= 0)
840 throw $this->t->newSyntaxError(
'More than one switch default');
843 $n2 =
new JSNode($this->t);
845 $n->defaultIndex =
count($n->cases);
850 throw $this->t->newSyntaxError(
'Invalid switch case');
856 $n2->statements->addNode($this->
Statement($x));
858 array_push($n->cases, $n2);
861 array_pop($x->stmtStack);
865 $n =
new JSNode($this->t);
871 $x->inForLoopInit =
true;
881 $x->inForLoopInit =
false;
889 if (
count($n2->treeNodes) != 1)
891 throw $this->t->SyntaxError(
892 'Invalid for..in left-hand side',
899 $n->iterator = $n2->treeNodes[0];
912 $n->setup = $n2 ?:
null;
920 $n->body = $this->
nest($x, $n);
924 $n =
new JSNode($this->t);
927 $n->body = $this->
nest($x, $n);
931 $n =
new JSNode($this->t);
935 if (!$x->ecmaStrictMode)
947 $n =
new JSNode($this->t);
952 $n->label = $this->t->currentToken()->value;
963 throw $this->t->newSyntaxError(
'Label not found');
965 while ($ss[$i]->label != $label);
972 throw $this->t->newSyntaxError(
'Invalid ' . $tt);
979 $n =
new JSNode($this->t);
980 $n->tryBlock = $this->
Block($x);
981 $n->catchClauses =
array();
985 $n2 =
new JSNode($this->t);
991 if ($x->ecmaStrictMode)
992 throw $this->t->newSyntaxError(
'Illegal catch guard');
994 if (
count($n->catchClauses) && !end($n->catchClauses)->guard)
995 throw $this->t->newSyntaxError(
'Guarded catch after unguarded');
1005 $n2->block = $this->
Block($x);
1006 array_push($n->catchClauses, $n2);
1010 $n->finallyBlock = $this->Block($x);
1012 if (!
count($n->catchClauses) && !$n->finallyBlock)
1013 throw $this->t->newSyntaxError(
'Invalid try statement');
1018 throw $this->t->newSyntaxError($tt .
' without preceding try');
1021 $n =
new JSNode($this->t);
1026 if (!$x->inFunction)
1027 throw $this->t->newSyntaxError(
'Invalid return');
1029 $n =
new JSNode($this->t);
1030 $tt = $this->t->peekOnSameLine();
1038 $n =
new JSNode($this->t);
1040 $n->body = $this->
nest($x, $n);
1050 $n =
new JSNode($this->t);
1054 $n =
new JSNode($this->t);
1060 $n->expression =
null;
1066 $this->t->scanOperand =
false;
1067 $tt = $this->t->peek();
1068 $this->t->scanOperand =
true;
1071 $label = $this->t->currentToken()->value;
1072 $ss = $x->stmtStack;
1073 for ($i =
count($ss) - 1; $i >= 0; --$i)
1075 if ($ss[$i]->label == $label)
1076 throw $this->t->newSyntaxError(
'Duplicate label');
1082 $n->statement = $this->
nest($x, $n);
1091 $n->end = $n->expression->end;
1095 if ($this->t->lineno == $this->t->currentToken()->lineno)
1097 $tt = $this->t->peekOnSameLine();
1099 throw $this->t->newSyntaxError(
'Missing ; before statement');
1115 $f->name = $this->t->currentToken()->value;
1116 elseif ($requireName)
1117 throw $this->t->newSyntaxError(
'Missing function identifier');
1125 throw $this->t->newSyntaxError(
'Missing formal parameter');
1127 array_push(
$f->params, $this->t->currentToken()->value);
1139 $f->end = $this->t->currentToken()->end;
1141 $f->functionForm = $functionForm;
1143 array_push($x->funDecls,
$f);
1150 $n =
new JSNode($this->t);
1156 $n2 =
new JSNode($this->t);
1157 $n2->name = $n2->value;
1161 if ($this->t->currentToken()->assignOp)
1162 throw $this->t->newSyntaxError(
'Invalid variable initialization');
1170 array_push($x->varDecls, $n2);
1179 $operators =
array();
1180 $operands =
array();
1183 $bl = $x->bracketLevel;
1184 $cl = $x->curlyLevel;
1185 $pl = $x->parenLevel;
1186 $hl = $x->hookLevel;
1188 while (($tt = $this->t->get()) !=
TOKEN_END)
1191 $x->bracketLevel == $bl &&
1192 $x->curlyLevel == $cl &&
1193 $x->parenLevel == $pl &&
1194 $x->hookLevel == $hl
1209 if ($this->t->scanOperand)
1212 while ( !empty($operators) &&
1213 $this->opPrecedence[end($operators)->type] > $this->opPrecedence[$tt]
1215 $this->
reduce($operators, $operands);
1217 array_push($operators,
new JSNode($this->t));
1220 $this->t->scanOperand =
true;
1227 array_push($operands, $n);
1234 throw $this->t->newSyntaxError(
'Invalid label');
1238 if ($this->t->scanOperand)
1242 while ( !empty($operators) &&
1243 $this->opPrecedence[end($operators)->
type] > $this->opPrecedence[$tt]
1245 $this->
reduce($operators, $operands);
1247 array_push($operators,
new JSNode($this->t));
1248 end($operands)->assignOp = $this->t->currentToken()->assignOp;
1249 $this->t->scanOperand =
true;
1256 if ($x->inForLoopInit && !$x->hookLevel &&
1257 !$x->bracketLevel && !$x->curlyLevel &&
1265 if ($tt ==
OP_COMMA && $x->hookLevel &&
1266 !$x->bracketLevel && !$x->curlyLevel &&
1285 if ($this->t->scanOperand)
1288 while ( !empty($operators) &&
1289 $this->opPrecedence[end($operators)->
type] >= $this->opPrecedence[$tt]
1291 $this->
reduce($operators, $operands);
1295 $tt = $this->t->get();
1297 throw $this->t->newSyntaxError(
"Unexpected token; token identifier or keyword expected.");
1299 array_push($operands,
new JSNode($this->t,
OP_DOT, array_pop($operands),
new JSNode($this->t)));
1303 array_push($operators,
new JSNode($this->t));
1304 $this->t->scanOperand =
true;
1311 if (!$this->t->scanOperand)
1314 array_push($operators,
new JSNode($this->t));
1318 if ($this->t->scanOperand)
1320 array_push($operators,
new JSNode($this->t));
1325 $t = $this->t->tokens[($this->t->tokenIndex + $this->t->lookahead - 1) & 3];
1326 if (
$t &&
$t->lineno != $this->t->lineno)
1329 if (!empty($operators))
1332 while ($this->opPrecedence[end($operators)->type] > $this->opPrecedence[$tt])
1333 $this->
reduce($operators, $operands);
1336 $n =
new JSNode($this->t, $tt, array_pop($operands));
1338 array_push($operands, $n);
1343 if (!$this->t->scanOperand)
1347 $this->t->scanOperand =
false;
1352 if (!$this->t->scanOperand)
1355 array_push($operands,
new JSNode($this->t));
1356 $this->t->scanOperand =
false;
1361 if ($this->t->scanOperand)
1362 array_push($operators,
new JSNode($this->t));
1364 array_push($operands,
new JSNode($this->t));
1368 if ($this->t->scanOperand)
1388 array_push($operands, $n);
1389 $this->t->scanOperand =
false;
1395 $this->t->scanOperand =
true;
1401 if ($this->t->scanOperand || $x->bracketLevel == $bl)
1411 if (!$this->t->scanOperand)
1422 $tt = $this->t->get();
1423 $tv = $this->t->currentToken()->value;
1424 if (($tv ==
'get' || $tv ==
'set') && $this->t->peek() ==
TOKEN_IDENTIFIER)
1426 if ($x->ecmaStrictMode)
1427 throw $this->t->newSyntaxError(
'Illegal property accessor');
1443 $id =
new JSNode($this->t);
1447 if ($x->ecmaStrictMode)
1448 throw $this->t->newSyntaxError(
'Illegal trailing ,');
1452 throw $this->t->newSyntaxError(
'Invalid property name');
1465 array_push($operands, $n);
1466 $this->t->scanOperand =
false;
1471 if (!$this->t->scanOperand && $x->curlyLevel != $cl)
1472 throw new Exception(
'PANIC: right curly botch');
1476 if ($this->t->scanOperand)
1482 while ( !empty($operators) &&
1483 $this->opPrecedence[end($operators)->
type] > $this->opPrecedence[
KEYWORD_NEW]
1485 $this->
reduce($operators, $operands);
1490 $n = end($operators);
1491 $this->t->scanOperand =
true;
1496 array_pop($operators);
1497 $n->addNode(array_pop($operands));
1504 array_push($operands, $n);
1505 $this->t->scanOperand =
false;
1519 if ($this->t->scanOperand || $x->parenLevel == $pl)
1531 $n = end($operands);
1532 if ($n->treeNodes[1]->type !=
OP_COMMA)
1533 $n->treeNodes[1] =
new JSNode($this->t,
JS_LIST, $n->treeNodes[1]);
1535 $n->treeNodes[1]->type =
JS_LIST;
1549 if ($x->hookLevel != $hl)
1550 throw $this->t->newSyntaxError(
'Missing : in conditional expression');
1552 if ($x->parenLevel != $pl)
1553 throw $this->t->newSyntaxError(
'Missing ) in parenthetical');
1555 if ($x->bracketLevel != $bl)
1556 throw $this->t->newSyntaxError(
'Missing ] in index expression');
1558 if ($this->t->scanOperand)
1559 throw $this->t->newSyntaxError(
'Missing operand');
1562 $this->t->scanOperand =
true;
1565 while (
count($operators))
1566 $this->
reduce($operators, $operands);
1568 return array_pop($operands);
1581 private function nest($x, $node, $end =
false)
1583 array_push($x->stmtStack, $node);
1584 $n = $this->statement($x);
1585 array_pop($x->stmtStack);
1588 $this->t->mustMatch($end);
1593 private function reduce(&$operators, &$operands)
1595 $n = array_pop($operators);
1597 $arity = $this->opArity[$op];
1598 $c =
count($operands);
1604 $left = $operands[$c - 2];
1605 if ($left->type == $op)
1607 $right = array_pop($operands);
1608 $left->addNode($right);
1616 $a = array_splice($operands, $c - $arity);
1617 for ($i = 0; $i < $arity; $i++)
1618 $n->addNode($a[$i]);
1621 $te = $this->t->currentToken()->end;
1625 array_push($operands, $n);
1705 if ($token =
$t->currentToken())
1708 $this->
value = $token->value;
1709 $this->lineno = $token->lineno;
1710 $this->start = $token->start;
1711 $this->end = $token->end;
1716 $this->lineno =
$t->lineno;
1719 if (($numargs = func_num_args()) > 2)
1721 $args = func_get_args();
1722 for ($i = 2; $i < $numargs; $i++)
1735 if (isset($this->
$name))
1736 return $this->$name;
1745 if ($node->start < $this->start)
1746 $this->start = $node->start;
1747 if ($this->end < $node->end)
1748 $this->end = $node->end;
1751 $this->treeNodes[] = $node;
1771 'case',
'catch',
'const',
'continue',
1772 'debugger',
'default',
'delete',
'do',
1774 'false',
'finally',
'for',
'function',
1775 'if',
'in',
'instanceof',
1779 'this',
'throw',
'true',
'try',
'typeof',
1785 ';',
',',
'?',
':',
'||',
'&&',
'|',
'^',
1786 '&',
'===',
'==',
'=',
'!==',
'!=',
'<<',
'<=',
1787 '<',
'>>>',
'>>',
'>=',
'>',
'++',
'--',
'+',
1788 '-',
'*',
'/',
'%',
'!',
'~',
'.',
'[',
1789 ']',
'{',
'}',
'(',
')',
'@*/'
1792 private $assignOps =
array(
'|',
'^',
'&',
'<<',
'>>',
'>>>',
'+',
'-',
'*',
'/',
'%');
1797 $this->opRegExp =
'#^(' . implode(
'|', array_map(
'preg_quote', $this->opTypeNames)) .
')#';
1803 $this->filename =
$filename ?:
'[inline]';
1807 $this->tokens =
array();
1808 $this->tokenIndex = 0;
1809 $this->lookahead = 0;
1810 $this->scanNewlines =
false;
1811 $this->scanOperand =
true;
1817 return substr($this->
source, $this->cursor, $chunksize);
1819 return substr($this->
source, $this->cursor);
1829 return $this->
get() == $tt || $this->
unget();
1834 if (!$this->
match($tt))
1835 throw $this->
newSyntaxError(
'Unexpected token; token ' . $tt .
' expected');
1842 if ($this->lookahead)
1845 if ($this->scanNewlines && $next->lineno != $this->lineno)
1861 $this->scanNewlines =
true;
1862 $tt = $this->
peek();
1863 $this->scanNewlines =
false;
1870 if (!empty($this->tokens))
1874 public function get($chunksize = 1000)
1876 while($this->lookahead)
1879 $this->tokenIndex = ($this->tokenIndex + 1) & 3;
1882 return $token->type;
1885 $conditional_comment =
false;
1893 $re = $this->scanNewlines ?
'/^[ \r\t]+/' :
'/^\s+/';
1894 if (preg_match($re,
$input, $match))
1896 $spaces = $match[0];
1897 $spacelen = strlen($spaces);
1898 $this->cursor += $spacelen;
1899 if (!$this->scanNewlines)
1900 $this->lineno += substr_count($spaces,
"\n");
1902 if ($spacelen == $chunksize)
1911 if (!preg_match(
'/^\/(?:\*(@(?:cc_on|if|elif|else|end))?.*?\*\/|\/[^\n]*)/s',
$input, $match))
1922 if (!empty($match[1]))
1924 $match[0] =
'/*' . $match[1];
1925 $conditional_comment =
true;
1930 $this->cursor += strlen($match[0]);
1931 $this->lineno += substr_count($match[0],
"\n");
1940 elseif ($conditional_comment)
1950 if ((
$input[1] ==
'x' ||
$input[1] ==
'X') && preg_match(
'/^0x[0-9a-f]+/i',
$input, $match))
1957 case '1':
case '2':
case '3':
case '4':
case '5':
1958 case '6':
case '7':
case '8':
case '9':
1960 preg_match(
'/^\d+(?:\.\d*)?(?:[eE][-+]?\d+)?/',
$input, $match);
1965 if (preg_match(
'/^\'(?:[^\\\\\'\r\n]++|\\\\(?:.|\r?\n))*\'/',
$input, $match))
1972 return $this->
get(
null);
1979 if (preg_match(
'/^"(?:[^\\\\"\r\n]++|\\\\(?:.|\r?\n))*"/',
$input, $match))
1986 return $this->
get(
null);
1993 if ($this->scanOperand && preg_match(
'/^\/((?:\\\\.|\[(?:\\\\.|[^\]])*\]|[^\/])+)\/([gimy]*)/',
$input, $match))
2012 preg_match($this->opRegExp,
$input, $match);
2014 if (in_array($op, $this->assignOps) &&
$input[strlen($op)] ==
'=')
2022 if ($this->scanOperand)
2034 if (preg_match(
'/^\.\d+(?:[eE][-+]?\d+)?/',
$input, $match))
2059 if (substr(
$input, 0, 3) ==
'@*/')
2061 $match =
array(
'@*/');
2069 if ($this->scanNewlines)
2071 $match =
array(
"\n");
2082 if (!preg_match(
'/^[$\w]+(?=[\s\/\|\^\&<>\+\-\*%=!.;,\?:~\[\]\{\}\(\)@])/',
$input, $match))
2087 $identifierStartChars =
"\\p{L}\\p{Nl}" . # UnicodeLetter
2090 $identifierPartChars = $identifierStartChars .
2091 "\\p{Mn}\\p{Mc}" . # UnicodeCombiningMark
2092 "\\p{Nd}" . # UnicodeDigit
2093 "\\p{Pc}"; # UnicodeConnectorPunctuation
2094 $unicodeEscape =
"\\\\u[0-9A-F-a-f]{4}";
2095 $identifierRegex =
"/^" .
2096 "(?:[$identifierStartChars]|$unicodeEscape)" .
2097 "(?:[$identifierPartChars]|$unicodeEscape)*" .
2099 if (preg_match($identifierRegex,
$input, $match))
2101 if (strpos($match[0],
'\\') !==
false) {
2104 $decoded = preg_replace_callback(
'/\\\\u([0-9A-Fa-f]{4})/',
2105 array(__CLASS__,
'unicodeEscapeCallback'),
2110 if (!preg_match(
"/^[$identifierStartChars][$identifierPartChars]*$/u", $decoded)) {
2117 if (in_array($decoded, $this->keywords)) {
2131 $this->tokenIndex = ($this->tokenIndex + 1) & 3;
2133 if (!isset($this->tokens[$this->tokenIndex]))
2134 $this->tokens[$this->tokenIndex] =
new JSToken();
2140 $token->assignOp = $op;
2144 $token->value = $match[0];
2145 $this->cursor += strlen($match[0]);
2155 if (++$this->lookahead == 4)
2158 $this->tokenIndex = ($this->tokenIndex - 1) & 3;
2163 return new Exception(
'Parse error: ' . $m .
' in file \'' . $this->filename .
'\' on line
' . $this->lineno);
2166 public static function unicodeEscapeCallback($m)
2168 return html_entity_decode('&#x
' . $m[1]. ';
', ENT_QUOTES, 'UTF-8
');