/** * 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())); }
private void checkPropertyRedefinition(final PropertyNode property, final Expression value, final FunctionNode getter, final FunctionNode setter, final Expression prevValue, final FunctionNode prevGetter, final FunctionNode prevSetter) { // ECMA 11.1.5 strict mode restrictions if (isStrictMode && value != null && prevValue != null) { throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); } final boolean isPrevAccessor = prevGetter != null || prevSetter != null; final boolean isAccessor = getter != null || setter != null; // data property redefined as accessor property if (prevValue != null && isAccessor) { throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); } // accessor property redefined as data if (isPrevAccessor && value != null) { throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); } if (isAccessor && isPrevAccessor) { if (getter != null && prevGetter != null || setter != null && prevSetter != null) { throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); } } }
@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; }
@Override public boolean enterPropertyNode(final PropertyNode propertyNode) { if(propertyNode.getKeyName().equals(ScriptObject.PROTO_PROPERTY_NAME)) { tagNeverOptimistic(propertyNode.getValue()); } return super.enterPropertyNode(propertyNode); }
@Override public boolean enterPropertyNode(final PropertyNode propertyNode) { // Avoid falsely adding property keys to the control flow graph if(propertyNode.getValue() != null) { propertyNode.getValue().accept(this); } return false; }
@Override public boolean enterObjectNode(final ObjectNode objectNode) { final List<PropertyNode> propNodes = objectNode.getElements(); final List<? extends PropertyTree> propTrees = translateProperties(propNodes); curExpr = new ObjectLiteralTreeImpl(objectNode, propTrees); return false; }
private List<? extends PropertyTree> translateProperties(final List<PropertyNode> propNodes) { final List<PropertyTree> propTrees = new ArrayList<>(propNodes.size()); for (final PropertyNode propNode : propNodes) { propTrees.add(translateProperty(propNode)); } return propTrees; }
private PropertyTree translateProperty(final PropertyNode propNode) { return new PropertyTreeImpl(propNode, translateExpr(propNode.getKey()), translateExpr(propNode.getValue()), (FunctionExpressionTree) translateExpr(propNode.getGetter()), (FunctionExpressionTree) translateExpr(propNode.getSetter())); }
PropertyTreeImpl(final PropertyNode node, final ExpressionTree key, final ExpressionTree value, final FunctionExpressionTree getter, final FunctionExpressionTree setter) { super(node); this.key = key; this.value = value; this.getter = getter; this.setter = setter; this.isStatic = node.isStatic(); this.isComputed = node.isComputed(); }
@Override public boolean enterPropertyNode(final PropertyNode propertyNode) { if (propertyNode.getValue() != null) { propertyNode.getValue().accept(this); return false; } else { return enterDefault(propertyNode); } }
@Override public boolean enterPropertyNode(final PropertyNode propertyNode) { if(ScriptObject.PROTO_PROPERTY_NAME.equals(propertyNode.getKeyName())) { tagNeverOptimistic(propertyNode.getValue()); } return super.enterPropertyNode(propertyNode); }
@Override public boolean enterObjectNode(final ObjectNode objectNode) { for(final PropertyNode propertyNode: objectNode.getElements()) { // Avoid falsely adding property keys to the control flow graph final Expression value = propertyNode.getValue(); if (value != null) { visitExpression(value); } } return pushExpressionType(objectNode); }
@Override public boolean enterObjectNode(final ObjectNode objectNode) { final List<PropertyNode> propNodes = objectNode.getElements(); final List<PropertyTreeImpl> propTrees = new ArrayList<>(propNodes.size()); for (final PropertyNode propNode : propNodes) { propTrees.add(new PropertyTreeImpl(propNode, translateExpr(propNode.getKey()), translateExpr(propNode.getValue()), (FunctionExpressionTree) translateExpr(propNode.getGetter()), (FunctionExpressionTree) translateExpr(propNode.getSetter()))); } curExpr = new ObjectLiteralTreeImpl(objectNode, propTrees); return false; }
PropertyTreeImpl(final PropertyNode node, final ExpressionTree key, final ExpressionTree value, final FunctionExpressionTree getter, final FunctionExpressionTree setter) { super(node); this.key = key; this.value = value; this.getter = getter; this.setter = setter; }
/** * Parse an object literal from the token stream * @return the object literal as a Node */ private ObjectNode objectLiteral() { // Capture LBRACE token. final long objectToken = token; // LBRACE tested in caller. next(); // Prepare to accumulate elements. final List<PropertyNode> elements = new ArrayList<>(); // Create a block for the object literal. loop: while (true) { switch (type) { case RBRACE: next(); break loop; case COMMARIGHT: next(); // check for trailing comma - not allowed in JSON if (type == RBRACE) { throw error(AbstractParser.message("trailing.comma.in.json", type.getNameOrType())); } break; default: // Get and add the next property. final PropertyNode property = propertyAssignment(); elements.add(property); // Comma between property assigments is mandatory in JSON. if (type != RBRACE && type != COMMARIGHT) { throw error(AbstractParser.message("expected", ", or }", type.getNameOrType())); } break; } } // Construct new object literal. return new ObjectNode(objectToken, finish, elements); }
/** * PropertyAssignment : * PropertyName : AssignmentExpression * get PropertyName ( ) { FunctionBody } * set PropertyName ( PropertySetParameterList ) { FunctionBody } * * PropertySetParameterList : * Identifier * * PropertyName : * IdentifierName * StringLiteral * NumericLiteral * * See 11.1.5 * * Parse an object literal property. * @return Property or reference node. */ private PropertyNode propertyAssignment() { // Capture firstToken. final long propertyToken = token; final int functionLine = line; PropertyKey propertyName; if (type == IDENT) { // Get IDENT. final String ident = (String)expectValue(IDENT); if (type != COLON) { final long getSetToken = propertyToken; switch (ident) { case "get": final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine); return new PropertyNode(propertyToken, finish, getter.ident, null, getter.functionNode, null); case "set": final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine); return new PropertyNode(propertyToken, finish, setter.ident, null, null, setter.functionNode); default: break; } } propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); } else { propertyName = propertyName(); } expect(COLON); defaultNames.push(propertyName); try { return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null); } finally { defaultNames.pop(); } }
@Override public boolean enterPropertyNode(final PropertyNode propertyNode) { final Node key = propertyNode.getKey(); final Node value = propertyNode.getValue(); if (value != null) { objectStart(); location(propertyNode); property("key"); key.accept(this); comma(); property("value"); value.accept(this); comma(); property("kind", "init"); objectEnd(); } else { // getter final Node getter = propertyNode.getGetter(); if (getter != null) { objectStart(); location(propertyNode); property("key"); key.accept(this); comma(); property("value"); getter.accept(this); comma(); property("kind", "get"); objectEnd(); } // setter final Node setter = propertyNode.getSetter(); if (setter != null) { if (getter != null) { comma(); } objectStart(); location(propertyNode); property("key"); key.accept(this); comma(); property("value"); setter.accept(this); comma(); property("kind", "set"); objectEnd(); } } return false; }
@Override public Node leavePropertyNode(final PropertyNode propertyNode) { weight += LITERAL_WEIGHT; return propertyNode; }
@Override public boolean enterPropertyNode(final PropertyNode propertyNode) { assert false : "should not reach here!"; return false; }
private PropertyNode createDefaultClassConstructor(final int classLineNumber, final long classToken, final long lastToken, final IdentNode className, final boolean subclass) { final int ctorFinish = finish; final List<Statement> statements; final List<IdentNode> parameters; final long identToken = Token.recast(classToken, TokenType.IDENT); if (subclass) { final IdentNode superIdent = createIdentNode(identToken, ctorFinish, SUPER.getName()).setIsDirectSuper(); final IdentNode argsIdent = createIdentNode(identToken, ctorFinish, "args").setIsRestParameter(); final Expression spreadArgs = new UnaryNode(Token.recast(classToken, TokenType.SPREAD_ARGUMENT), argsIdent); final CallNode superCall = new CallNode(classLineNumber, classToken, ctorFinish, superIdent, Collections.singletonList(spreadArgs), false); statements = Collections.singletonList(new ExpressionStatement(classLineNumber, classToken, ctorFinish, superCall)); parameters = Collections.singletonList(argsIdent); } else { statements = Collections.emptyList(); parameters = Collections.emptyList(); } final Block body = new Block(classToken, ctorFinish, Block.IS_BODY, statements); final IdentNode ctorName = className != null ? className : createIdentNode(identToken, ctorFinish, CONSTRUCTOR_NAME); final ParserContextFunctionNode function = createParserContextFunctionNode(ctorName, classToken, FunctionNode.Kind.NORMAL, classLineNumber, parameters); function.setLastToken(lastToken); function.setFlag(FunctionNode.ES6_IS_METHOD); function.setFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR); if (subclass) { function.setFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR); function.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER); } if (className == null) { function.setFlag(FunctionNode.IS_ANONYMOUS); } final PropertyNode constructor = new PropertyNode(classToken, ctorFinish, ctorName, createFunctionNode( function, classToken, ctorName, parameters, FunctionNode.Kind.NORMAL, classLineNumber, body ), null, null, false, false); return constructor; }
@Override public boolean enterPropertyNode(final PropertyNode propertyNode) { // Property nodes are only accessible through object literals, and we handled that case above throw new AssertionError(); }