@SuppressWarnings("fallthrough") private LiteralNode<?> getStringLiteral() { final LiteralNode<?> literal = getLiteral(); final String str = (String)literal.getValue(); for (int i = 0; i < str.length(); i++) { final char ch = str.charAt(i); switch (ch) { default: if (ch > 0x001f) { break; } case '"': case '\\': throw error(AbstractParser.message("unexpected.token", str)); } } return literal; }
/** * Parse a property assignment from the token stream * @return the property assignment as a Node */ private PropertyNode propertyAssignment() { // Capture firstToken. final long propertyToken = token; LiteralNode<?> name = null; if (type == STRING) { name = getStringLiteral(); } else if (type == ESCSTRING) { name = getLiteral(); } if (name != null) { expect(COLON); final Expression value = jsonLiteral(); return new PropertyNode(propertyToken, value.getFinish(), name, value, null, null); } // Raise an error. throw error(AbstractParser.message("expected", "string", type.getNameOrType())); }
/** * Directive value or null if statement is not a directive. * * @param stmt Statement to be checked * @return Directive value if the given statement is a directive */ private String getDirective(final Node stmt) { if (stmt instanceof ExpressionStatement) { final Node expr = ((ExpressionStatement)stmt).getExpression(); if (expr instanceof LiteralNode) { final LiteralNode<?> lit = (LiteralNode<?>)expr; final long litToken = lit.getToken(); final TokenType tt = Token.descType(litToken); // A directive is either a string or an escape string if (tt == TokenType.STRING || tt == TokenType.ESCSTRING) { // Make sure that we don't unescape anything. Return as seen in source! return source.getString(lit.getStart(), Token.descLength(litToken)); } } } return null; }
private Node leaveTYPEOF(final UnaryNode unaryNode) { final Expression rhs = unaryNode.getExpression(); final List<Expression> args = new ArrayList<>(); if (rhs instanceof IdentNode && !isParamOrVar((IdentNode)rhs)) { args.add(compilerConstantIdentifier(SCOPE)); args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null } else { args.add(rhs); args.add((Expression)LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this' } final Node runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args).accept(this); end(unaryNode); return runtimeNode; }
@Override public Node leaveIfNode(final IfNode ifNode) { final Node test = ifNode.getTest(); if (test instanceof LiteralNode.PrimitiveLiteralNode) { final boolean isTrue = ((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue(); final Block executed = isTrue ? ifNode.getPass() : ifNode.getFail(); final Block dropped = isTrue ? ifNode.getFail() : ifNode.getPass(); final List<Statement> statements = new ArrayList<>(); if (executed != null) { statements.addAll(executed.getStatements()); // Get statements form executed branch } if (dropped != null) { extractVarNodes(dropped, statements); // Get var-nodes from non-executed branch } if (statements.isEmpty()) { return new EmptyNode(ifNode); } return BlockStatement.createReplacement(ifNode, ifNode.getFinish(), statements); } return ifNode; }
@Override protected LiteralNode<?> eval() { LiteralNode<?> result; result = reduceTwoLiterals(); if (result != null) { return result; } result = reduceOneLiteral(); if (result != null) { return result; } return null; }
@Override public boolean enterLiteralNode(final LiteralNode<?> literalNode) { final Object value = literalNode.getValue(); if (value instanceof Lexer.RegexToken) { curExpr = new RegExpLiteralTreeImpl(literalNode); } else if (literalNode.isArray()) { final List<Expression> exprNodes = literalNode.getElementExpressions(); final List<ExpressionTreeImpl> exprTrees = new ArrayList<>(exprNodes.size()); for (final Node node : exprNodes) { if (node == null) { exprTrees.add(null); } else { curExpr = null; node.accept(this); assert curExpr != null : "null for " + node; exprTrees.add(curExpr); } } curExpr = new ArrayLiteralTreeImpl(literalNode, exprTrees); } else { curExpr = new LiteralTreeImpl(literalNode); } return false; }
@Override public boolean enterLiteralNode(final LiteralNode<?> literalNode) { if (literalNode.isArray()) { if (((LiteralNode.ArrayLiteralNode)literalNode).hasSpread() && ((LiteralNode.ArrayLiteralNode)literalNode).hasTrailingComma()) { throw error("Rest element must be last", literalNode.getElementExpressions().get(literalNode.getElementExpressions().size() - 1).getToken()); } boolean restElement = false; for (final Expression element : literalNode.getElementExpressions()) { if (element != null) { if (restElement) { throw error("Unexpected element after rest element", element.getToken()); } if (element.isTokenType(SPREAD_ARRAY)) { restElement = true; final Expression lvalue = ((UnaryNode) element).getExpression(); verifySpreadElement(lvalue); } element.accept(this); } } return false; } else { return enterDefault(literalNode); } }
private Node leaveTYPEOF(final UnaryNode unaryNode) { final Expression rhs = unaryNode.getExpression(); final List<Expression> args = new ArrayList<>(); if (rhs instanceof IdentNode && !isParamOrVar((IdentNode)rhs)) { args.add(compilerConstantIdentifier(SCOPE)); args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName())); //null } else { args.add(rhs); args.add(LiteralNode.newInstance(unaryNode)); //null, do not reuse token of identifier rhs, it can be e.g. 'this' } final Node runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args); end(unaryNode); return runtimeNode; }
@Override public Node leaveIfNode(final IfNode ifNode) { final Node test = ifNode.getTest(); if (test instanceof LiteralNode.PrimitiveLiteralNode) { final boolean isTrue = ((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue(); final Block executed = isTrue ? ifNode.getPass() : ifNode.getFail(); final Block dropped = isTrue ? ifNode.getFail() : ifNode.getPass(); final List<Statement> statements = new ArrayList<>(); if (executed != null) { statements.addAll(executed.getStatements()); // Get statements form executed branch } if (dropped != null) { extractVarNodesFromDeadCode(dropped, statements); // Get var-nodes from non-executed branch } if (statements.isEmpty()) { return new EmptyNode(ifNode); } return BlockStatement.createReplacement(ifNode, ifNode.getFinish(), statements); } return ifNode; }
@Override public boolean enterObjectNode(final ObjectNode objectNode) { weight += OBJECT_WEIGHT; final List<PropertyNode> properties = objectNode.getElements(); final boolean isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD; for (final PropertyNode property : properties) { if (!LiteralNode.isConstant(property.getValue())) { weight += SETPROP_WEIGHT; property.getValue().accept(this); } else if (!isSpillObject) { // constants in spill object are set via preset spill array, // but fields objects need to set constants. weight += SETPROP_WEIGHT; } } return false; }
/** * Create a LiteralNode from the current token * * @return LiteralNode representing the current token * @throws ParserException if any literals fails to parse */ protected final LiteralNode<?> getLiteral() throws ParserException { // Capture LITERAL token. final long literalToken = token; // Create literal node. final Object value = getValue(); // Advance to have a correct finish next(); LiteralNode<?> node = null; if (value == null) { node = LiteralNode.newInstance(literalToken, finish); } else if (value instanceof Number) { node = LiteralNode.newInstance(literalToken, finish, (Number)value); } else if (value instanceof String) { node = LiteralNode.newInstance(literalToken, finish, (String)value); } else if (value instanceof LexerToken) { if (value instanceof RegexToken) { final RegexToken regex = (RegexToken)value; try { RegExpFactory.validate(regex.getExpression(), regex.getOptions()); } catch (final ParserException e) { throw error(e.getMessage()); } } node = LiteralNode.newInstance(literalToken, finish, (LexerToken)value); } else { assert false : "unknown type for LiteralNode: " + value.getClass(); } return node; }
private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) { if (earlyError) { throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); } final ArrayList<Expression> args = new ArrayList<>(); args.add(lhs); if (rhs == null) { args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish())); } else { args.add(rhs); } args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString())); return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); }
private static boolean isNumericArray(final Node[] values) { for (final Node node : values) { if (node instanceof LiteralNode && ((LiteralNode<?>)node).getValue() instanceof Number) { continue; } return false; } return true; }
/** * Load a key value in the proper form. * * @param key */ //TODO move this and break it apart MethodEmitter loadKey(final Object key) { if (key instanceof IdentNode) { method.visitLdcInsn(((IdentNode) key).getName()); } else if (key instanceof LiteralNode) { method.visitLdcInsn(((LiteralNode<?>)key).getString()); } else { method.visitLdcInsn(JSType.toString(key)); } pushType(Type.OBJECT); //STRING return this; }
@Override public Node leaveLiteralNode(final LiteralNode<?> node) { if (node instanceof ArrayLiteralNode) { final ArrayLiteralNode aln = (ArrayLiteralNode)node; if (aln.getUnits() == null) { return node; } final List<ArrayUnit> newArrayUnits = new ArrayList<>(); for (final ArrayUnit au : aln.getUnits()) { newArrayUnits.add(new ArrayUnit(getExistingReplacement(au), au.getLo(), au.getHi())); } return aln.setUnits(lc, newArrayUnits); } return node; }
@Override public Node leaveUnaryNode(final UnaryNode unaryNode) { final LiteralNode<?> literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval(); if (literalNode != null) { log.info("Unary constant folded ", unaryNode, " to ", literalNode); return literalNode; } return unaryNode; }
@Override public Node leaveBinaryNode(final BinaryNode binaryNode) { final LiteralNode<?> literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval(); if (literalNode != null) { log.info("Binary constant folded ", binaryNode, " to ", literalNode); return literalNode; } return binaryNode; }
@Override public Node leaveTernaryNode(final TernaryNode ternaryNode) { final Node test = ternaryNode.getTest(); if (test instanceof LiteralNode.PrimitiveLiteralNode) { return (((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression()).getExpression(); } return ternaryNode; }
private static boolean isUniqueIntegerLiteral(final Expression expr, final Set<Integer> alreadySeen) { if (expr instanceof LiteralNode) { final Object value = ((LiteralNode<?>)expr).getValue(); if (value instanceof Integer) { return alreadySeen.add((Integer)value); } } return false; }
private static String getConstantPropertyName(final Expression expression) { if (expression instanceof LiteralNode.PrimitiveLiteralNode) { final Object value = ((LiteralNode) expression).getValue(); if (value instanceof String && SAFE_PROPERTY_NAME.matcher((String) value).matches()) { return (String) value; } } return null; }