void decompileObjectLiteral(ObjectLiteral node) { decompiler.addToken(Token.LC); List<ObjectProperty> props = node.getElements(); int size = props.size(); for (int i = 0; i < size; i++) { ObjectProperty prop = props.get(i); boolean destructuringShorthand = Boolean.TRUE.equals(prop.getProp(Node.DESTRUCTURING_SHORTHAND)); decompile(prop.getLeft()); if (!destructuringShorthand) { decompiler.addToken(Token.COLON); decompile(prop.getRight()); } if (i < size - 1) { decompiler.addToken(Token.COMMA); } } decompiler.addToken(Token.RC); }
public List<String> getPropertyNames(){ List<String> propNames = new ArrayList<String>(); ObjectLiteral ol = (ObjectLiteral)this.getNode(); for (ObjectProperty op : ol.getElements()){ AstNode left = op.getLeft(); if (left instanceof Name){ propNames.add(((Name)left).getIdentifier()); } else if (left instanceof StringLiteral){ String identifier = ConstraintGenUtil.removeQuotes(((StringLiteral)left).toSource()); propNames.add(identifier); } else { System.err.println(left.getClass().getName() + " " + left.toSource()); throw new Error("unsupported case in getPropertyNames()"); } } return propNames; }
public static List<String> getPropertyNames(ObjectLiteral ol){ List<String> propNames = new ArrayList<String>(); for (ObjectProperty op : ol.getElements()){ AstNode left = op.getLeft(); if (left instanceof Name){ propNames.add(((Name)left).getIdentifier()); } else if (left instanceof StringLiteral){ String identifier = ConstraintGenUtil.removeQuotes(((StringLiteral)left).toSource()); propNames.add(identifier); } else { System.err.println(left.getClass().getName() + " " + left.toSource()); throw new Error("unsupported case in getPropertyNames()"); } } return propNames; }
/** * Create constraints for an object literal. */ private ITypeTerm processObjectLiteralForObject(ObjectLiteral n) { ITypeTerm expTerm = findOrCreateObjectLiteralTerm(n); ObjectLiteral o = (ObjectLiteral)n; for (ObjectProperty prop : o.getElements()){ AstNode left = prop.getLeft(); AstNode right = prop.getRight(); if (left instanceof Name){ String identifier = ((Name)left).getIdentifier(); // for object literal o = { name_1 : exp_1, ..., name_k : exp_k } generate // a constraint |exp_i| <: prop(|o|, name_i) ITypeTerm propTerm = findOrCreatePropertyAccessTerm(expTerm, identifier, null); ITypeTerm valTerm = processExpression(right); processCopy(right, valTerm, propTerm, n.getLineno(), null); } } return expTerm; }
/** * Create constraints for a map literal. */ private ITypeTerm processObjectLiteralForMap(ObjectLiteral o) { ITypeTerm expTerm = findOrCreateMapLiteralTerm(o); for (ObjectProperty prop : o.getElements()){ AstNode left = prop.getLeft(); AstNode right = prop.getRight(); if (left instanceof StringLiteral){ // for map literal o = { name_1 : exp_1, ..., name_k : exp_k } generate // a constraint |exp_i| <: MapElem(|o|) ITypeTerm mapAccessTerm = findOrCreateIndexedTerm(expTerm, o.getLineno()); ITypeTerm valTerm = processExpression(right); processCopy(right, valTerm, mapAccessTerm, o.getLineno(), (solution) -> genericTypeError("map does not have a homogenous value type", locationOf(prop)) .withNote("map value type is " + describeTypeOf(mapAccessTerm, solution)) .withNote("key " + left.toSource() + " has type " + describeTypeOf(valTerm, solution))); } } return expTerm; }
private void visitPrototypeMembers(ObjectLiteral objLiteral, String clazz) { List<ObjectProperty> properties = objLiteral.getElements(); for (ObjectProperty property : properties) { AstNode propertyKey = property.getLeft(); JavaScriptTreeNode tn = createTreeNode(propertyKey); String memberName = RhinoUtil.getPropertyName(propertyKey); AstNode propertyValue = property.getRight(); visitPrototypeMember(tn, clazz, memberName, propertyValue); } }
void decompile(AstNode node) { switch (node.getType()) { case Token.ARRAYLIT: decompileArrayLiteral((ArrayLiteral)node); break; case Token.OBJECTLIT: decompileObjectLiteral((ObjectLiteral)node); break; case Token.STRING: decompiler.addString(((StringLiteral)node).getValue()); break; case Token.NAME: decompiler.addName(((Name)node).getIdentifier()); break; case Token.NUMBER: decompiler.addNumber(((NumberLiteral)node).getNumber()); break; case Token.GETPROP: decompilePropertyGet((PropertyGet)node); break; case Token.EMPTY: break; case Token.GETELEM: decompileElementGet((ElementGet) node); break; case Token.THIS: decompiler.addToken(node.getType()); break; default: Kit.codeBug("unexpected token: " + Token.typeToName(node.getType())); } }
private void arrowFunctionParams(FunctionNode fnNode, AstNode params, Map<String, Node> destructuring, Set<String> paramNames) { if (params instanceof ArrayLiteral || params instanceof ObjectLiteral) { markDestructuring(params); fnNode.addParam(params); String pname = currentScriptOrFn.getNextTempName(); defineSymbol(Token.LP, pname, false); destructuring.put(pname, params); } else if (params instanceof InfixExpression && params.getType() == Token.COMMA) { arrowFunctionParams(fnNode, ((InfixExpression)params).getLeft(), destructuring, paramNames); arrowFunctionParams(fnNode, ((InfixExpression)params).getRight(), destructuring, paramNames); } else if (params instanceof Name) { fnNode.addParam(params); String paramName = ((Name)params).getIdentifier(); defineSymbol(Token.LP, paramName); if (this.inUseStrictDirective) { if ("eval".equals(paramName) || "arguments".equals(paramName)) { reportError("msg.bad.id.strict", paramName); } if (paramNames.contains(paramName)) addError("msg.dup.param.strict", paramName); paramNames.add(paramName); } } else { reportError("msg.no.parm", params.getPosition(), params.getLength()); fnNode.addParam(makeErrorNode()); } }
public ObjectLiteralTerm(ObjectLiteral n){ super(n); ObjectType oType = new ObjectType(this.getPropertyNames().stream() .map((s) -> new Property(s, new AnyType(), false)) .collect(Collectors.toList())); this.type = oType; }
/** * Find or create a term representing the type of an object literal */ public ITypeTerm findOrCreateObjectLiteralTerm(ObjectLiteral n) { if (!objectLiteralTerms.containsKey(n)){ objectLiteralTerms.put(n, new ObjectLiteralTerm(n)); } return objectLiteralTerms.get(n); }
/** * Find or create a term representing the type of a map literal */ public ITypeTerm findOrCreateMapLiteralTerm(ObjectLiteral n) { if (!mapLiteralTerms.containsKey(n)){ mapLiteralTerms.put(n, new MapLiteralTerm(n)); } return mapLiteralTerms.get(n); }
/** * Tests if an object literal is an object by checking that all * properties are unquoted. */ static boolean isObject(ObjectLiteral o){ boolean result = (o.getElements().size() > 0); for (ObjectProperty prop : o.getElements()){ AstNode left = prop.getLeft(); result = result && (left instanceof Name); } return result; }
/** * Tests if an object literal is a map by checking that * all properties are quoted. * In JavaScript, both double quotes and single quotes are * supported but for now we assume double quotes are used. * * Empty object literals are assumed to be maps. */ static boolean isMap(ObjectLiteral o){ boolean result = true; for (ObjectProperty prop : o.getElements()){ AstNode left = prop.getLeft(); result = result && (left instanceof StringLiteral); } return result; }
/** * is right a valid expression to assign into the prototype field of a * constructor? currently we allow object literals, constructor calls, and * expressions of the form B.prototype * * @param right * @return */ private boolean validRHSForAssignToPrototype(AstNode right) { if (right instanceof ObjectLiteral || right instanceof NewExpression) { return true; } if (right instanceof PropertyGet) { PropertyGet pg = (PropertyGet) right; if (pg.getProperty().getIdentifier().equals("prototype")) { return true; } } return false; }
/** * generate constraints for object literals. */ private ITypeTerm processObjectLiteral(ObjectLiteral n) { if (ConstraintGenUtil.isObject(n)){ return processObjectLiteralForObject(n); } else if (ConstraintGenUtil.isMap(n)){ return processObjectLiteralForMap(n); } else { return expError("inconsistent use of quotes in object literal: " + n.toSource(), n); } }
private void visitMethodOrEnum(final String name, final String jsDoc, final AstNode astNode) { if (jsDoc == null) { //TODO sometimes values are recognized as enums even if they are not. LOG.error("Comment in node {} for file {} is empty.", name, fileName); return; } final JsElement element = parser.parse(fileName, jsDoc); if (element == null || element.isPrivate()) { return; // ignore private stuff... } if (element.isEnum()) { final JsFile jsFile = parseClassOrInterfaceName(name, false, element); files.put(name, jsFile); if (astNode instanceof ObjectLiteral) { final ObjectLiteral ol = (ObjectLiteral) astNode; for (final ObjectProperty op : ol.getElements()) { final Name left = (Name) op.getLeft(); jsFile.addEnumValue(left.toSource(), left.getJsDoc()); } } } else if (isMethod(name, element)) { //method assigned as method variable. final JsMethod method = addMethod(name, element, false); if (method == null) { LOG.warn("Should this be abstract: {} in file:{}", name, fileName); } else { method.setAbstract(true); } } else if (element.isConst() || element.isDefine()){ consts.put(name, element); } else { LOG.warn("We missed something: {}: {} in file:{}", name, element, fileName); } }
private void print(ObjectLiteral node) throws IOException { writer.append('{').ws(); if (node.getElements() != null && !node.getElements().isEmpty()) { print(node.getElements().get(0)); for (int i = 1; i < node.getElements().size(); ++i) { writer.append(',').ws(); print(node.getElements().get(i)); } } writer.ws().append('}'); }
private Node transformObjectLiteral(ObjectLiteral node) { if (node.isDestructuring()) { return node; } // createObjectLiteral rewrites its argument as object // creation plus object property entries, so later compiler // stages don't need to know about object literals. decompiler.addToken(Token.LC); List<ObjectProperty> elems = node.getElements(); Node object = new Node(Token.OBJECTLIT); Object[] properties; if (elems.isEmpty()) { properties = ScriptRuntime.emptyArgs; } else { int size = elems.size(), i = 0; properties = new Object[size]; for (ObjectProperty prop : elems) { if (prop.isGetterMethod()) { decompiler.addToken(Token.GET); } else if (prop.isSetterMethod()) { decompiler.addToken(Token.SET); } else if (prop.isNormalMethod()) { decompiler.addToken(Token.METHOD); } properties[i++] = getPropKey(prop.getLeft()); // OBJECTLIT is used as ':' in object literal for // decompilation to solve spacing ambiguity. if (!(prop.isMethod())) { decompiler.addToken(Token.OBJECTLIT); } Node right = transform(prop.getRight()); if (prop.isGetterMethod()) { right = createUnary(Token.GET, right); } else if (prop.isSetterMethod()) { right = createUnary(Token.SET, right); } else if (prop.isNormalMethod()) { right = createUnary(Token.METHOD, right); } object.addChildToBack(right); if (i < size) { decompiler.addToken(Token.COMMA); } } } decompiler.addToken(Token.RC); object.putProp(Node.OBJECT_IDS_PROP, properties); return object; }
/** * Parse a new-expression, or if next token isn't {@link Token#NEW}, * a primary expression. * @param allowCallSyntax passed down to {@link #memberExprTail} */ private AstNode memberExpr(boolean allowCallSyntax) throws IOException { int tt = peekToken(), lineno = ts.lineno; AstNode pn; if (tt != Token.NEW) { pn = primaryExpr(); } else { consumeToken(); int pos = ts.tokenBeg; NewExpression nx = new NewExpression(pos); AstNode target = memberExpr(false); int end = getNodeEnd(target); nx.setTarget(target); int lp = -1; if (matchToken(Token.LP)) { lp = ts.tokenBeg; List<AstNode> args = argumentList(); if (args != null && args.size() > ARGC_LIMIT) reportError("msg.too.many.constructor.args"); int rp = ts.tokenBeg; end = ts.tokenEnd; if (args != null) nx.setArguments(args); nx.setParens(lp - pos, rp - pos); } // Experimental syntax: allow an object literal to follow a new // expression, which will mean a kind of anonymous class built with // the JavaAdapter. the object literal will be passed as an // additional argument to the constructor. if (matchToken(Token.LC)) { ObjectLiteral initializer = objectLiteral(); end = getNodeEnd(initializer); nx.setInitializer(initializer); } nx.setLength(end - pos); pn = nx; } pn.setLineno(lineno); AstNode tail = memberExprTail(allowCallSyntax, pn); return tail; }
Node destructuringAssignmentHelper(int variableType, Node left, Node right, String tempName) { Scope result = createScopeNode(Token.LETEXPR, left.getLineno()); result.addChildToFront(new Node(Token.LET, createName(Token.NAME, tempName, right))); try { pushScope(result); defineSymbol(Token.LET, tempName, true); } finally { popScope(); } Node comma = new Node(Token.COMMA); result.addChildToBack(comma); List<String> destructuringNames = new ArrayList<String>(); boolean empty = true; switch (left.getType()) { case Token.ARRAYLIT: empty = destructuringArray((ArrayLiteral)left, variableType, tempName, comma, destructuringNames); break; case Token.OBJECTLIT: empty = destructuringObject((ObjectLiteral)left, variableType, tempName, comma, destructuringNames); break; case Token.GETPROP: case Token.GETELEM: switch (variableType) { case Token.CONST: case Token.LET: case Token.VAR: reportError("msg.bad.assign.left"); } comma.addChildToBack(simpleAssignment(left, createName(tempName))); break; default: reportError("msg.bad.assign.left"); } if (empty) { // Don't want a COMMA node with no children. Just add a zero. comma.addChildToBack(createNumber(0)); } result.putProp(Node.DESTRUCTURING_NAMES, destructuringNames); return result; }
public MapLiteralTerm(ObjectLiteral n){ super(n); this.type = new MapType(new AnyType()); }
public static boolean isMethodAssignedInObjectLiteral(FunctionNode n){ return (n.getParent() instanceof ObjectProperty && n.getParent().getParent() instanceof ObjectLiteral); }
/** * This method generates constraints for all relevant AstNodes. It delegates its work to various * processXXX() methods that handle AstNodes of type XXX. */ @Override public boolean visit(AstNode node) { if (node instanceof VariableInitializer){ processVariableInitializer(node); } else if (node instanceof ReturnStatement){ processReturnStatement((ReturnStatement)node); } else if (node instanceof ExpressionStatement){ processExpressionStatement((ExpressionStatement)node); } else if (node instanceof ForLoop){ processForLoop((ForLoop)node); } else if (node instanceof ForInLoop){ processForInLoop((ForInLoop)node); }else if (node instanceof WhileLoop){ processWhileLoop((WhileLoop)node); } else if (node instanceof DoLoop){ processDoLoop((DoLoop)node); } else if (node instanceof NewExpression){ processNewExpression((NewExpression)node); } else if (node instanceof FunctionCall){ processFunctionCall((FunctionCall)node); } else if (node instanceof ElementGet){ processElementGet((ElementGet)node); } else if (node instanceof FunctionNode){ processFunctionNode((FunctionNode)node); } else if (node instanceof IfStatement){ processIfStatement((IfStatement)node); } else if (node instanceof KeywordLiteral){ processKeywordLiteral((KeywordLiteral)node); } else if (node instanceof SwitchStatement){ processSwitchStatement((SwitchStatement)node); } else if (node instanceof SwitchCase){ processSwitchCase((SwitchCase)node); } else if ((node instanceof AstRoot) || //AstRoot: no constraints need to be generated (node instanceof BreakStatement) || //BreakStatement: no constraints need to be generated (node instanceof VariableDeclaration) || //VariableDeclaration: we generate constraints for its constituent VariableInitializer nodes (node instanceof Name) || //Name: generate constraints for complex expressions that refer to names (node instanceof NumberLiteral) || //NumberLiteral: generate constraints for complex expressions that refer to names (node instanceof StringLiteral) || //StringLiteral: generate constraints for complex expressions that refer to names (node instanceof Assignment) || // Assignment is a special case of InfixExpression (node instanceof ArrayLiteral) || (node instanceof UnaryExpression) || (node instanceof InfixExpression) || (node instanceof ConditionalExpression) || (node instanceof ParenthesizedExpression) || (node instanceof EmptyExpression) || (node instanceof ObjectLiteral) || (node instanceof EmptyStatement) || (node instanceof ContinueStatement) || (node instanceof Scope) || (node instanceof Block)){ // // occurs in programs with for loops -- nothing to be done here? /* nothing */ } else { error("unsupported node " + node.toSource().trim() + " of type: " + node.getClass().getName(), node); } return true; }
/** * Creates constraints for the subtree rooted at a designated expression node, * and returns a constraint variable corresponding to the root of the tree. */ private ITypeTerm processExpression(AstNode n){ ITypeTerm cached = theMap.get(n); if (cached != null) return cached; if (n instanceof Name){ return processVariableReference((Name)n); } else if (n instanceof NumberLiteral){ return processNumericConstant((NumberLiteral)n); } else if (n instanceof StringLiteral){ return processStringLiteral((StringLiteral)n); } else if (ConstraintGenUtil.isBooleanConstant(n)){ return processBooleanConstant(n); } else if (n instanceof UnaryExpression){ return processUnaryExpression((UnaryExpression)n); } else if (n instanceof InfixExpression){ return processInfixExpression((InfixExpression)n); } else if (n instanceof FunctionCall){ return processFunctionCallExpression((FunctionCall)n); } else if (n instanceof ArrayLiteral){ return processArrayLiteral((ArrayLiteral)n); } else if (n instanceof ElementGet){ return processElementGet((ElementGet)n); } else if (n instanceof ParenthesizedExpression) { return processParenthesizedExpression((ParenthesizedExpression)n); } else if (n instanceof ConditionalExpression) { return processConditionalExpression((ConditionalExpression)n); } else if (n instanceof ObjectLiteral) { return processObjectLiteral((ObjectLiteral)n); } else if (n instanceof KeywordLiteral){ return processKeywordLiteral((KeywordLiteral)n); } else if (n instanceof FunctionNode){ return processFunctionNode((FunctionNode)n); } else if (n instanceof EmptyExpression){ return processEmptyExpression((EmptyExpression)n); } else { System.err.println(n.toSource()); return expError("unimplemented case in findOrCreateExpressionVariable: " + n.getClass().getName(), n); } }
private ITypeTerm findOrCreateObjectLiteralTerm(ObjectLiteral lit){ ITypeTerm t = factory.findOrCreateObjectLiteralTerm(lit); generator.addTermLineNumber(t, lit.getLineno()); return t; }
private ITypeTerm findOrCreateMapLiteralTerm(ObjectLiteral lit){ ITypeTerm t = factory.findOrCreateMapLiteralTerm(lit); generator.addTermLineNumber(t, lit.getLineno()); return t; }
@Override public boolean visit(AstNode node) { boolean continueProcessing = true; // We only need to check Object Literals if (node instanceof ObjectLiteral) { List<ObjectProperty> kvProps = null; List<ObjectProperty> props = ((ObjectLiteral) node).getElements(); if (props != null) { // Walk through nodes to check if this is a root bundle with // key/value pairs embedded. for (int i = 0; i < props.size(); i++) { Node left = props.get(i).getLeft(); String name = null; if (left instanceof StringLiteral) { name = ((StringLiteral) left).getValue(); } else if (left instanceof Name) { name = ((Name) left).getIdentifier(); } else { continue; } Node right = props.get(i).getRight(); if (name.equalsIgnoreCase("root")) { // This AMD i18n bundle with "root" object // (key/value pairs) embedded. // For example, // // define({ // "root": { // "msg.hello": "Hello", // "msg.byte": "Bye" // }, // "fr": true, // "de": true // }); // right = removeParenthes(right); if (right instanceof ObjectLiteral) { kvProps = ((ObjectLiteral) right).getElements(); break; } } } } if (kvProps == null) { // This bundle contains key/value pairs in the root Object // directly. // For example, // // define({ // "msg.hello": "Hello", // "msg.byte": "Bye" // }); // kvProps = props; } // Put key/value pairs to elements for (ObjectProperty kv : kvProps) { Node propKey = kv.getLeft(); String key = null; if (propKey instanceof Name) { key = ((Name) propKey).getIdentifier(); } else if (propKey instanceof StringLiteral) { key = ((StringLiteral) propKey).getValue(); } if (key == null) { continue; } Node propVal = kv.getRight(); String val = concatStringNodes(propVal); if (val == null) { continue; } elements.put(key, val); } continueProcessing = false; } return continueProcessing; }
/** * It is assumed that <code>descriptorObjectLit</code> has been * identified as an object literal containing property descriptors. Any * property descriptors found as properties of that literal are parsed * and tree nodes are created for them. * * @param descriptorObjLit The object literal containing property * descriptors (for example, the object parameter to * <code>Object.create()</code>). * @param clazz The class that the properties belong to. */ private void visitPropertyDescriptors(ObjectLiteral descriptorObjLit, String clazz) { List<ObjectProperty> descriptors = descriptorObjLit.getElements(); for (ObjectProperty prop : descriptors) { AstNode propertyKey = prop.getLeft(); AstNode propertyValue = prop.getRight(); // Should always be true, as this should be a property descriptor if (propertyValue instanceof ObjectLiteral) { JavaScriptTreeNode tn = createTreeNode(propertyKey); String memberName = RhinoUtil.getPropertyName(propertyKey); visitPropertyDescriptor(tn, clazz, memberName, (ObjectLiteral)propertyValue); } } }