477 default: |
476 default: |
478 break; |
477 break; |
479 } |
478 } |
480 |
479 |
481 // Build up node. |
480 // Build up node. |
482 return new BinaryNode(source, op, lhs, rhs); |
481 return new BinaryNode(op, lhs, rhs); |
483 } |
482 } |
484 |
483 |
485 /** |
484 /** |
486 * Reduce increment/decrement to simpler operations. |
485 * Reduce increment/decrement to simpler operations. |
487 * @param firstToken First token. |
486 * @param firstToken First token. |
488 * @param tokenType Operation token (INCPREFIX/DEC.) |
487 * @param tokenType Operation token (INCPREFIX/DEC.) |
489 * @param expression Left hand side expression. |
488 * @param expression Left hand side expression. |
490 * @param isPostfix Prefix or postfix. |
489 * @param isPostfix Prefix or postfix. |
491 * @return Reduced expression. |
490 * @return Reduced expression. |
492 */ |
491 */ |
493 private Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) { |
492 private static Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) { |
494 if (isPostfix) { |
493 if (isPostfix) { |
495 return new UnaryNode(source, Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression); |
494 return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression); |
496 } |
495 } |
497 |
496 |
498 return new UnaryNode(source, firstToken, expression); |
497 return new UnaryNode(firstToken, expression); |
499 } |
498 } |
500 |
499 |
501 /** |
500 /** |
502 * ----------------------------------------------------------------------- |
501 * ----------------------------------------------------------------------- |
503 * |
502 * |
522 final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); |
521 final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); |
523 // Set up the script to append elements. |
522 // Set up the script to append elements. |
524 |
523 |
525 FunctionNode script = newFunctionNode( |
524 FunctionNode script = newFunctionNode( |
526 functionToken, |
525 functionToken, |
527 new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName), |
526 new IdentNode(functionToken, Token.descPosition(functionToken), scriptName), |
528 new ArrayList<IdentNode>(), |
527 new ArrayList<IdentNode>(), |
529 FunctionNode.Kind.SCRIPT); |
528 FunctionNode.Kind.SCRIPT); |
530 |
529 |
531 functionDeclarations = new ArrayList<>(); |
530 functionDeclarations = new ArrayList<>(); |
532 sourceElements(); |
531 sourceElements(); |
865 // Get initializer expression. Suppress IN if not statement. |
864 // Get initializer expression. Suppress IN if not statement. |
866 init = assignmentExpression(!isStatement); |
865 init = assignmentExpression(!isStatement); |
867 } |
866 } |
868 |
867 |
869 // Allocate var node. |
868 // Allocate var node. |
870 final VarNode var = new VarNode(source, varToken, finish, name, init); |
869 final VarNode var = new VarNode(varToken, finish, name, init); |
871 vars.add(var); |
870 vars.add(var); |
872 appendStatement(var); |
871 appendStatement(var); |
873 |
872 |
874 if (type != COMMARIGHT) { |
873 if (type != COMMARIGHT) { |
875 break; |
874 break; |
921 // Get expression and add as statement. |
920 // Get expression and add as statement. |
922 final Node expression = expression(); |
921 final Node expression = expression(); |
923 |
922 |
924 ExecuteNode executeNode = null; |
923 ExecuteNode executeNode = null; |
925 if (expression != null) { |
924 if (expression != null) { |
926 executeNode = new ExecuteNode(source, expressionToken, finish, expression); |
925 executeNode = new ExecuteNode(expressionToken, finish, expression); |
927 appendStatement(executeNode); |
926 appendStatement(executeNode); |
928 } else { |
927 } else { |
929 expect(null); |
928 expect(null); |
930 } |
929 } |
931 |
930 |
978 * |
977 * |
979 * Parse a FOR statement. |
978 * Parse a FOR statement. |
980 */ |
979 */ |
981 private void forStatement() { |
980 private void forStatement() { |
982 // Create FOR node, capturing FOR token. |
981 // Create FOR node, capturing FOR token. |
983 ForNode forNode = new ForNode(source, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR); |
982 ForNode forNode = new ForNode(token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR); |
984 |
983 |
985 |
984 |
986 // Set up new block for scope of vars. Captures first token. |
985 // Set up new block for scope of vars. Captures first token. |
987 Block outer = newBlock(); |
986 Block outer = newBlock(); |
988 lc.push(forNode); |
987 lc.push(forNode); |
1148 // Capture DO token. |
1147 // Capture DO token. |
1149 final long doToken = token; |
1148 final long doToken = token; |
1150 // DO tested in the caller. |
1149 // DO tested in the caller. |
1151 next(); |
1150 next(); |
1152 |
1151 |
1153 WhileNode doWhileNode = new WhileNode(source, doToken, Token.descPosition(doToken), true); |
1152 WhileNode doWhileNode = new WhileNode(doToken, Token.descPosition(doToken), true); |
1154 lc.push(doWhileNode); |
1153 lc.push(doWhileNode); |
1155 |
1154 |
1156 try { |
1155 try { |
1157 // Get DO body. |
1156 // Get DO body. |
1158 doWhileNode = doWhileNode.setBody(lc, getStatement()); |
1157 doWhileNode = doWhileNode.setBody(lc, getStatement()); |
1400 final long switchToken = token; |
1399 final long switchToken = token; |
1401 // SWITCH tested in caller. |
1400 // SWITCH tested in caller. |
1402 next(); |
1401 next(); |
1403 |
1402 |
1404 // Create and add switch statement. |
1403 // Create and add switch statement. |
1405 SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null); |
1404 SwitchNode switchNode = new SwitchNode(switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null); |
1406 lc.push(switchNode); |
1405 lc.push(switchNode); |
1407 |
1406 |
1408 try { |
1407 try { |
1409 expect(LPAREN); |
1408 expect(LPAREN); |
1410 switchNode = switchNode.setExpression(lc, expression()); |
1409 switchNode = switchNode.setExpression(lc, expression()); |
1482 |
1481 |
1483 if (lc.findLabel(ident.getName()) != null) { |
1482 if (lc.findLabel(ident.getName()) != null) { |
1484 throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); |
1483 throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); |
1485 } |
1484 } |
1486 |
1485 |
1487 LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null); |
1486 LabelNode labelNode = new LabelNode(labelToken, finish, ident, null); |
1488 try { |
1487 try { |
1489 lc.push(labelNode); |
1488 lc.push(labelNode); |
1490 labelNode = labelNode.setBody(lc, getStatement()); |
1489 labelNode = labelNode.setBody(lc, getStatement()); |
1491 labelNode.setFinish(finish); |
1490 labelNode.setFinish(finish); |
1492 appendStatement(labelNode); |
1491 appendStatement(labelNode); |
1586 |
1585 |
1587 Block catchBlock = newBlock(); |
1586 Block catchBlock = newBlock(); |
1588 try { |
1587 try { |
1589 // Get CATCH body. |
1588 // Get CATCH body. |
1590 final Block catchBody = getBlock(true); |
1589 final Block catchBody = getBlock(true); |
1591 final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody); |
1590 final CatchNode catchNode = new CatchNode(catchToken, finish, exception, ifExpression, catchBody); |
1592 appendStatement(catchNode); |
1591 appendStatement(catchNode); |
1593 } finally { |
1592 } finally { |
1594 catchBlock = restoreBlock(catchBlock); |
1593 catchBlock = restoreBlock(catchBlock); |
1595 catchBlocks.add(catchBlock); |
1594 catchBlocks.add(catchBlock); |
1596 } |
1595 } |
1612 // Need at least one catch or a finally. |
1611 // Need at least one catch or a finally. |
1613 if (catchBlocks.isEmpty() && finallyStatements == null) { |
1612 if (catchBlocks.isEmpty() && finallyStatements == null) { |
1614 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken); |
1613 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken); |
1615 } |
1614 } |
1616 |
1615 |
1617 final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements); |
1616 final TryNode tryNode = new TryNode(tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements); |
1618 // Add try. |
1617 // Add try. |
1619 assert lc.peek() == outer; |
1618 assert lc.peek() == outer; |
1620 appendStatement(tryNode); |
1619 appendStatement(tryNode); |
1621 |
1620 |
1622 tryNode.setFinish(finish); |
1621 tryNode.setFinish(finish); |
1691 return getLiteral(); |
1690 return getLiteral(); |
1692 case EXECSTRING: |
1691 case EXECSTRING: |
1693 return execString(primaryToken); |
1692 return execString(primaryToken); |
1694 case FALSE: |
1693 case FALSE: |
1695 next(); |
1694 next(); |
1696 return LiteralNode.newInstance(source, primaryToken, finish, false); |
1695 return LiteralNode.newInstance(primaryToken, finish, false); |
1697 case TRUE: |
1696 case TRUE: |
1698 next(); |
1697 next(); |
1699 return LiteralNode.newInstance(source, primaryToken, finish, true); |
1698 return LiteralNode.newInstance(primaryToken, finish, true); |
1700 case NULL: |
1699 case NULL: |
1701 next(); |
1700 next(); |
1702 return LiteralNode.newInstance(source, primaryToken, finish); |
1701 return LiteralNode.newInstance(primaryToken, finish); |
1703 case LBRACKET: |
1702 case LBRACKET: |
1704 return arrayLiteral(); |
1703 return arrayLiteral(); |
1705 case LBRACE: |
1704 case LBRACE: |
1706 return objectLiteral(); |
1705 return objectLiteral(); |
1707 case LPAREN: |
1706 case LPAREN: |
1734 * @param primaryToken Original string token. |
1733 * @param primaryToken Original string token. |
1735 * @return callNode to $EXEC. |
1734 * @return callNode to $EXEC. |
1736 */ |
1735 */ |
1737 Node execString(final long primaryToken) { |
1736 Node execString(final long primaryToken) { |
1738 // Synthesize an ident to call $EXEC. |
1737 // Synthesize an ident to call $EXEC. |
1739 final IdentNode execIdent = new IdentNode(source, primaryToken, finish, ScriptingFunctions.EXEC_NAME); |
1738 final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME); |
1740 // Skip over EXECSTRING. |
1739 // Skip over EXECSTRING. |
1741 next(); |
1740 next(); |
1742 // Set up argument list for call. |
1741 // Set up argument list for call. |
1743 final List<Node> arguments = new ArrayList<>(); |
1742 final List<Node> arguments = new ArrayList<>(); |
1744 // Skip beginning of edit string expression. |
1743 // Skip beginning of edit string expression. |
1924 if (value != null) { |
1923 if (value != null) { |
1925 if (prevValue == null) { |
1924 if (prevValue == null) { |
1926 map.put(key, newProperty = newProperty.setValue(value)); |
1925 map.put(key, newProperty = newProperty.setValue(value)); |
1927 } else { |
1926 } else { |
1928 final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT); |
1927 final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT); |
1929 map.put(key, newProperty = newProperty.setValue(new BinaryNode(source, propertyToken, prevValue, value))); |
1928 map.put(key, newProperty = newProperty.setValue(new BinaryNode(propertyToken, prevValue, value))); |
1930 } |
1929 } |
1931 |
1930 |
1932 map.put(key, newProperty = newProperty.setGetter(null).setSetter(null)); |
1931 map.put(key, newProperty = newProperty.setGetter(null).setSetter(null)); |
1933 } |
1932 } |
1934 |
1933 |
2011 |
2010 |
2012 switch (ident) { |
2011 switch (ident) { |
2013 case "get": |
2012 case "get": |
2014 final PropertyKey getIdent = propertyName(); |
2013 final PropertyKey getIdent = propertyName(); |
2015 final String getterName = getIdent.getPropertyName(); |
2014 final String getterName = getIdent.getPropertyName(); |
2016 final IdentNode getNameNode = new IdentNode(source, ((Node)getIdent).getToken(), finish, "get " + getterName); |
2015 final IdentNode getNameNode = new IdentNode(((Node)getIdent).getToken(), finish, "get " + getterName); |
2017 expect(LPAREN); |
2016 expect(LPAREN); |
2018 expect(RPAREN); |
2017 expect(RPAREN); |
2019 functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER); |
2018 functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER); |
2020 return new PropertyNode(source, propertyToken, finish, getIdent, null, functionNode, null); |
2019 return new PropertyNode(propertyToken, finish, getIdent, null, functionNode, null); |
2021 |
2020 |
2022 case "set": |
2021 case "set": |
2023 final PropertyKey setIdent = propertyName(); |
2022 final PropertyKey setIdent = propertyName(); |
2024 final String setterName = setIdent.getPropertyName(); |
2023 final String setterName = setIdent.getPropertyName(); |
2025 final IdentNode setNameNode = new IdentNode(source, ((Node)setIdent).getToken(), finish, "set " + setterName); |
2024 final IdentNode setNameNode = new IdentNode(((Node)setIdent).getToken(), finish, "set " + setterName); |
2026 expect(LPAREN); |
2025 expect(LPAREN); |
2027 final IdentNode argIdent = getIdent(); |
2026 final IdentNode argIdent = getIdent(); |
2028 verifyStrictIdent(argIdent, "setter argument"); |
2027 verifyStrictIdent(argIdent, "setter argument"); |
2029 expect(RPAREN); |
2028 expect(RPAREN); |
2030 List<IdentNode> parameters = new ArrayList<>(); |
2029 List<IdentNode> parameters = new ArrayList<>(); |
2031 parameters.add(argIdent); |
2030 parameters.add(argIdent); |
2032 functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER); |
2031 functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER); |
2033 return new PropertyNode(source, propertyToken, finish, setIdent, null, null, functionNode); |
2032 return new PropertyNode(propertyToken, finish, setIdent, null, null, functionNode); |
2034 |
2033 |
2035 default: |
2034 default: |
2036 break; |
2035 break; |
2037 } |
2036 } |
2038 } |
2037 } |
2039 |
2038 |
2040 propertyName = new IdentNode(source, propertyToken, finish, ident); |
2039 propertyName = new IdentNode(propertyToken, finish, ident); |
2041 } else { |
2040 } else { |
2042 propertyName = propertyName(); |
2041 propertyName = propertyName(); |
2043 } |
2042 } |
2044 |
2043 |
2045 expect(COLON); |
2044 expect(COLON); |
2046 |
2045 |
2047 return new PropertyNode(source, propertyToken, finish, propertyName, assignmentExpression(false), null, null); |
2046 return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null); |
2048 } |
2047 } |
2049 |
2048 |
2050 /** |
2049 /** |
2051 * LeftHandSideExpression : |
2050 * LeftHandSideExpression : |
2052 * NewExpression |
2051 * NewExpression |
2101 final Node rhs = expression(); |
2100 final Node rhs = expression(); |
2102 |
2101 |
2103 expect(RBRACKET); |
2102 expect(RBRACKET); |
2104 |
2103 |
2105 // Create indexing node. |
2104 // Create indexing node. |
2106 lhs = new IndexNode(source, callToken, finish, lhs, rhs); |
2105 lhs = new IndexNode(callToken, finish, lhs, rhs); |
2107 |
2106 |
2108 break; |
2107 break; |
2109 |
2108 |
2110 case PERIOD: |
2109 case PERIOD: |
2111 next(); |
2110 next(); |
2112 |
2111 |
2113 final IdentNode property = getIdentifierName(); |
2112 final IdentNode property = getIdentifierName(); |
2114 |
2113 |
2115 // Create property access node. |
2114 // Create property access node. |
2116 lhs = new AccessNode(source, callToken, finish, lhs, property); |
2115 lhs = new AccessNode(callToken, finish, lhs, property); |
2117 |
2116 |
2118 break; |
2117 break; |
2119 |
2118 |
2120 default: |
2119 default: |
2121 break loop; |
2120 break loop; |
2167 |
2166 |
2168 if (!env._no_syntax_extensions && type == LBRACE) { |
2167 if (!env._no_syntax_extensions && type == LBRACE) { |
2169 arguments.add(objectLiteral()); |
2168 arguments.add(objectLiteral()); |
2170 } |
2169 } |
2171 |
2170 |
2172 final CallNode callNode = new CallNode(source, constructor.getToken(), finish, constructor, arguments); |
2171 final CallNode callNode = new CallNode(constructor.getToken(), finish, constructor, arguments); |
2173 |
2172 |
2174 return new UnaryNode(source, newToken, callNode); |
2173 return new UnaryNode(newToken, callNode); |
2175 } |
2174 } |
2176 |
2175 |
2177 /** |
2176 /** |
2178 * MemberExpression : |
2177 * MemberExpression : |
2179 * PrimaryExpression |
2178 * PrimaryExpression |
2324 |
2323 |
2325 // name is null, generate anonymous name |
2324 // name is null, generate anonymous name |
2326 boolean isAnonymous = false; |
2325 boolean isAnonymous = false; |
2327 if (name == null) { |
2326 if (name == null) { |
2328 final String tmpName = "_L" + source.getLine(Token.descPosition(token)); |
2327 final String tmpName = "_L" + source.getLine(Token.descPosition(token)); |
2329 name = new IdentNode(source, functionToken, Token.descPosition(functionToken), tmpName); |
2328 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); |
2330 isAnonymous = true; |
2329 isAnonymous = true; |
2331 } |
2330 } |
2332 |
2331 |
2333 expect(LPAREN); |
2332 expect(LPAREN); |
2334 final List<IdentNode> parameters = formalParameterList(); |
2333 final List<IdentNode> parameters = formalParameterList(); |
2375 throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); |
2374 throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); |
2376 } |
2375 } |
2377 // rename in non-strict mode |
2376 // rename in non-strict mode |
2378 parameterName = functionNode.uniqueName(parameterName); |
2377 parameterName = functionNode.uniqueName(parameterName); |
2379 final long parameterToken = parameter.getToken(); |
2378 final long parameterToken = parameter.getToken(); |
2380 parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); |
2379 parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); |
2381 } |
2380 } |
2382 |
2381 |
2383 parametersSet.add(parameterName); |
2382 parametersSet.add(parameterName); |
2384 } |
2383 } |
2385 } else if (arity == 1) { |
2384 } else if (arity == 1) { |
2387 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); |
2386 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); |
2388 } |
2387 } |
2389 } |
2388 } |
2390 |
2389 |
2391 if (isStatement) { |
2390 if (isStatement) { |
2392 final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT); |
2391 final VarNode varNode = new VarNode(functionToken, finish, name, functionNode, VarNode.IS_STATEMENT); |
2393 if (topLevel) { |
2392 if (topLevel) { |
2394 functionDeclarations.add(lineNumber); |
2393 functionDeclarations.add(lineNumber); |
2395 functionDeclarations.add(varNode); |
2394 functionDeclarations.add(varNode); |
2396 } else { |
2395 } else { |
2397 appendStatement(lineNumber); |
2396 appendStatement(lineNumber); |
2467 // just expression as function body |
2466 // just expression as function body |
2468 final Node expr = expression(); |
2467 final Node expr = expression(); |
2469 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); |
2468 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); |
2470 // create a return statement - this creates code in itself and does not need to be |
2469 // create a return statement - this creates code in itself and does not need to be |
2471 // wrapped into an ExecuteNode |
2470 // wrapped into an ExecuteNode |
2472 final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr); |
2471 final ReturnNode returnNode = new ReturnNode(expr.getToken(), finish, expr); |
2473 appendStatement(returnNode); |
2472 appendStatement(returnNode); |
2474 lastToken = token; |
2473 lastToken = token; |
2475 functionNode.setFinish(Token.descPosition(token) + Token.descLength(token)); |
2474 functionNode.setFinish(Token.descPosition(token) + Token.descLength(token)); |
2476 |
2475 |
2477 } else { |
2476 } else { |
2509 } |
2508 } |
2510 prependStatement(decl); |
2509 prependStatement(decl); |
2511 } |
2510 } |
2512 } |
2511 } |
2513 |
2512 |
2514 private RuntimeNode referenceError(final Node lhs, final Node rhs) { |
2513 private static RuntimeNode referenceError(final Node lhs, final Node rhs) { |
2515 final ArrayList<Node> args = new ArrayList<>(); |
2514 final ArrayList<Node> args = new ArrayList<>(); |
2516 args.add(lhs); |
2515 args.add(lhs); |
2517 if (rhs == null) { |
2516 if (rhs == null) { |
2518 args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish())); |
2517 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish())); |
2519 } else { |
2518 } else { |
2520 args.add(rhs); |
2519 args.add(rhs); |
2521 } |
2520 } |
2522 args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString())); |
2521 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString())); |
2523 return new RuntimeNode(source, lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); |
2522 return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); |
2524 } |
2523 } |
2525 |
2524 |
2526 /* |
2525 /* |
2527 * parse LHS [a, b, ..., c]. |
2526 * parse LHS [a, b, ..., c]. |
2528 * |
2527 * |