private Node transformXmlRef(Node pn, XmlRef node, int memberTypeFlags) { if ((memberTypeFlags & Node.ATTRIBUTE_FLAG) != 0) decompiler.addToken(Token.XMLATTR); Name namespace = node.getNamespace(); String ns = namespace != null ? namespace.getIdentifier() : null; if (ns != null) { decompiler.addName(ns); decompiler.addToken(Token.COLONCOLON); } if (node instanceof XmlPropRef) { String name = ((XmlPropRef)node).getPropName().getIdentifier(); decompiler.addName(name); return createPropertyGet(pn, ns, name, memberTypeFlags); } else { decompiler.addToken(Token.LB); Node expr = transform(((XmlElemRef)node).getExpression()); decompiler.addToken(Token.RB); return createElementGet(pn, ns, expr, memberTypeFlags); } }
/** * Parse the [expr] portion of an xml element reference, e.g. * @[expr], @*::[expr], or ns::[expr]. */ private XmlElemRef xmlElemRef(int atPos, Name namespace, int colonPos) throws IOException { int lb = ts.tokenBeg, rb = -1, pos = atPos != -1 ? atPos : lb; AstNode expr = expr(); int end = getNodeEnd(expr); if (mustMatchToken(Token.RB, "msg.no.bracket.index")) { rb = ts.tokenBeg; end = ts.tokenEnd; } XmlElemRef ref = new XmlElemRef(pos, end - pos); ref.setNamespace(namespace); ref.setColonPos(colonPos); ref.setAtPos(atPos); ref.setExpression(expr); ref.setBrackets(lb, rb); return ref; }
/** * Gets a Java-compatible "informative" name for the the ScriptOrFnNode */ String cleanName(final ScriptNode n) { String result = ""; if (n instanceof FunctionNode) { Name name = ((FunctionNode) n).getFunctionName(); if (name == null) { result = "anonymous"; } else { result = name.getIdentifier(); } } else { result = "script"; } return result; }
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; }
/** * Find or create a term representing a FunctionNode (function definition). The * created FunctionTerm provides methods for accessing the terms corresponding to the * function's parameters and return type. The boolean flag isMethod indicates whether * the function is a method. */ public FunctionTerm findOrCreateFunctionTerm(FunctionNode fun, FunctionTerm.FunctionKind funType) { if (!functionTerms.containsKey(fun)){ FunctionTerm var = new FunctionTerm(fun, funType); var.setReturnVariable(this.findOrCreateFunctionReturnTerm(var, fun.getParamCount())); List<AstNode> params = fun.getParams(); List<NameDeclarationTerm> paramVars = new ArrayList<NameDeclarationTerm>(); for (int i=0; i < params.size(); i++){ AstNode param = params.get(i); if (param instanceof Name){ NameDeclarationTerm paramCV = this.findOrCreateNameDeclarationTerm((Name)param); paramVars.add(paramCV); } else { throw new Error("unimplemented case in findOrCreateFunctionVariable"); } } var.setParamVariables(paramVars); functionTerms.put(fun, var); } return functionTerms.get(fun); }
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; }
/** * For a function definition (FunctionNode), create constraints equating its * parameters to param(.) variables, and equate the type of the function name * to the type of the entire function definition. */ private void createFunctionNodeConstraints(FunctionNode node, ITypeTerm funTerm){ // if the function has a name, equate the types of the function node and the function name Name funName = node.getFunctionName(); if (funName != null){ ITypeTerm nameTerm = findOrCreateNameDeclarationTerm(funName); addSubTypeConstraint(funTerm, nameTerm, node.getLineno(), null); } // for a function f with params v1, v2, ... generate param(|f|,i) = |v_i| for (int i=0; i < node.getParamCount(); i++){ AstNode param = node.getParams().get(i); if (param instanceof Name){ Name name = (Name)param; ITypeTerm nameVar = findOrCreateNameDeclarationTerm(name); ITypeTerm paramVar = findOrCreateFunctionParamTerm(funTerm, i, node.getParamCount(), node.getLineno()); addTypeEqualityConstraint(paramVar, nameVar, param.getLineno(), null); } else { error("createFunctionNodeConstraints: unexpected parameter type", node); } } }
/** * generate constraints for assignments */ private void processAssignment(Assignment a) throws Error { AstNode left = a.getLeft(); AstNode right = a.getRight(); ITypeTerm expTerm = findOrCreateExpressionTerm(a); if (left instanceof Name){ processAssignToVariable(a, left, right, expTerm); } else if (left instanceof PropertyGet) { PropertyGet pg = (PropertyGet)left; if (pg.getProperty().getIdentifier().equals("prototype")){ processAssignToPrototype(a, left, right, expTerm); } else { processAssignToProperty(a, left, right, expTerm); } processExpression(pg.getTarget()); // TEST } else if (left instanceof ElementGet){ processIndexedAssignment(a, left, right, expTerm); } else { error("unsupported LHS type in Assignment: " + left.getClass().getName(), left); } }
/** * 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; }
/** * for an expression that consists of a simple reference to a variable, we create an ITerm * for that expression, find the unique representative for the referenced variable, and * generate a constraint that equates these. */ private ITypeTerm processVariableReference(Name name) { ITypeTerm expTerm = findOrCreateExpressionTerm(name); if (!ConstraintGenUtil.isGlobal(name)){ // no need for NameDeclarationTerm for global variables Name declaration = ConstraintGenUtil.findDecl(name); ITypeTerm nameTerm = findOrCreateNameDeclarationTerm(declaration); addTypeEqualityConstraint(expTerm, nameTerm, name.getLineno(), null); } else { String identifier = name.getIdentifier(); if (identifier.equals("undefined")){ addTypeEqualityConstraint(new TypeParamTerm(name), findOrCreateExpressionTerm(name), name.getLineno(), null); } else { ITypeTerm globalTerm = findOrCreateGlobalDeclarationTerm(name, jsEnv); addTypeEqualityConstraint(globalTerm, expTerm, name.getLineno(), null); createConstraintsForGlobalFunction(name); } } return expTerm; }
private String createLookupString(FunctionCall fn) { StringBuilder sb = new StringBuilder(); String name = ""; switch(fn.getTarget().getType()) { case Token.NAME : name = ((Name) fn.getTarget()).getIdentifier(); break; } sb.append(name); sb.append("("); Iterator<AstNode> i = fn.getArguments().iterator(); while (i.hasNext()) { i.next(); sb.append("p"); if(i.hasNext()) sb.append(","); } sb.append(")"); return sb.toString(); }
/** * Lookup the name of the node within the last JavaScript type. e.g var a = * 1; var b = a.MAX_VALUE; looks up MAX_VALUE within NumberLiteral a where a * is resolve before as a JavaScript Number; * * @param node * @param lastJavaScriptType * @return */ protected JavaScriptType lookupFromName(AstNode node, JavaScriptType lastJavaScriptType) { JavaScriptType javaScriptType = null; if (lastJavaScriptType != null) { String lookupText = null; switch (node.getType()) { case Token.NAME: lookupText = ((Name) node).getIdentifier(); break; } if (lookupText == null) { // just try the source lookupText = node.toSource(); } javaScriptType = lookupJavaScriptType(lastJavaScriptType, lookupText); } return javaScriptType; }
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()); } }
private BreakStatement breakStatement() throws IOException { if (currentToken != Token.BREAK) codeBug(); consumeToken(); int lineno = ts.lineno, pos = ts.tokenBeg, end = ts.tokenEnd; Name breakLabel = null; if (peekTokenOrEOL() == Token.NAME) { breakLabel = createNameNode(); end = getNodeEnd(breakLabel); } // matchJumpLabelName only matches if there is one LabeledStatement labels = matchJumpLabelName(); // always use first label as target Jump breakTarget = labels == null ? null : labels.getFirstLabel(); if (breakTarget == null && breakLabel == null) { if (loopAndSwitchSet == null || loopAndSwitchSet.size() == 0) { if (breakLabel == null) { reportError("msg.bad.break", pos, end - pos); } } else { breakTarget = loopAndSwitchSet.get(loopAndSwitchSet.size() - 1); } } BreakStatement pn = new BreakStatement(pos, end - pos); pn.setBreakLabel(breakLabel); // can be null if it's a bad break in error-recovery mode if (breakTarget != null) pn.setBreakTarget(breakTarget); pn.setLineno(lineno); return pn; }
private ContinueStatement continueStatement() throws IOException { if (currentToken != Token.CONTINUE) codeBug(); consumeToken(); int lineno = ts.lineno, pos = ts.tokenBeg, end = ts.tokenEnd; Name label = null; if (peekTokenOrEOL() == Token.NAME) { label = createNameNode(); end = getNodeEnd(label); } // matchJumpLabelName only matches if there is one LabeledStatement labels = matchJumpLabelName(); Loop target = null; if (labels == null && label == null) { if (loopSet == null || loopSet.size() == 0) { reportError("msg.continue.outside"); } else { target = loopSet.get(loopSet.size() - 1); } } else { if (labels == null || !(labels.getStatement() instanceof Loop)) { reportError("msg.continue.nonloop", pos, end - pos); } target = labels == null ? null : (Loop)labels.getStatement(); } ContinueStatement pn = new ContinueStatement(pos, end - pos); if (target != null) // can be null in error-recovery mode pn.setTarget(target); pn.setLabel(label); pn.setLineno(lineno); return pn; }
private ObjectProperty methodDefinition(int pos, AstNode propName, int entryKind) throws IOException { FunctionNode fn = function(FunctionNode.FUNCTION_EXPRESSION); // We've already parsed the function name, so fn should be anonymous. Name name = fn.getFunctionName(); if (name != null && name.length() != 0) { reportError("msg.bad.prop"); } ObjectProperty pn = new ObjectProperty(pos); switch (entryKind) { case GET_ENTRY: pn.setIsGetterMethod(); fn.setFunctionIsGetterMethod(); break; case SET_ENTRY: pn.setIsSetterMethod(); fn.setFunctionIsSetterMethod(); break; case METHOD_ENTRY: pn.setIsNormalMethod(); fn.setFunctionIsNormalMethod(); break; } int end = getNodeEnd(fn); pn.setLeft(propName); pn.setRight(fn); pn.setLength(end - pos); return pn; }
/** * Create a {@code Name} node using the token info from the * last scanned name. In some cases we need to either synthesize * a name node, or we lost the name token information by peeking. * If the {@code token} parameter is not {@link Token#NAME}, then * we use token info saved in instance vars. */ private Name createNameNode(boolean checkActivation, int token) { int beg = ts.tokenBeg; String s = ts.getString(); int lineno = ts.lineno; if (!"".equals(prevNameTokenString)) { beg = prevNameTokenStart; s = prevNameTokenString; lineno = prevNameTokenLineno; prevNameTokenStart = 0; prevNameTokenString = ""; prevNameTokenLineno = 0; } if (s == null) { if (compilerEnv.isIdeMode()) { s = ""; } else { codeBug(); } } Name name = new Name(beg, s); name.setLineno(lineno); if (checkActivation) { checkActivationName(s, token); } return name; }
private void checkCallRequiresActivation(AstNode pn) { if ((pn.getType() == Token.NAME && "eval".equals(((Name)pn).getIdentifier())) || (pn.getType() == Token.GETPROP && "eval".equals(((PropertyGet)pn).getProperty().getIdentifier()))) setRequiresActivation(); }
/** Can only be called when node has String context. */ public void setScope(Scope s) { if (s == null) Kit.codeBug(); if (!(this instanceof Name)) { throw Kit.codeBug(); } ((Name)this).setScope(s); }
/** * Find or create a term representing an expression consisting of a variable name */ public NameDeclarationTerm findOrCreateNameDeclarationTerm(final Name name){ Name name2 = ConstraintGenUtil.findDecl(name); if (name2 == null) { throw new Error("no declaration found for " + name.getIdentifier()); } if (!nameTerms.containsKey(name2)){ nameTerms.put(name2, new NameDeclarationTerm(name2)); } return nameTerms.get(name2); }
/** * Find or create a term representing the name, without first mapping the name to its * declaration */ public NameDeclarationTerm findOrCreateNameDeclTermNoLookup(final Name name) { if (!nameTerms.containsKey(name)){ nameTerms.put(name, new NameDeclarationTerm(name)); } return nameTerms.get(name); }
/** * Find or create a term representing an expression consisting of a global variable name */ public EnvironmentDeclarationTerm findOrCreateGlobalDeclarationTerm(final Name name, JSEnvironment env){ if (!globalVarTerms.containsKey(name)){ globalVarTerms.put(name, new EnvironmentDeclarationTerm(name, env)); } return globalVarTerms.get(name); }
/** * Finds the declaration of the called function. Assumes that the call's target * is a Name, which is passed as the second parameter. * */ static FunctionNode findFunDecl(FunctionCall fc, Name funName){ List<FunctionNode> funsFound = findFunDecl2(fc, new ArrayList<FunctionNode>()); for (int i=0; i < funsFound.size(); i++){ FunctionNode fun = funsFound.get(i); if (funName.getIdentifier().equals(fun.getName())){ return fun; } } return null; }
/** * Finds the declaration of the referenced Name. */ static Name findDecl(Name name){ List<Name> declsFound = findDecl2(name); for (int i=0; i < declsFound.size(); i++){ Name name2 = declsFound.get(i); if (name.getIdentifier().equals(name2.getIdentifier())){ return name2; } } return null; }
/** * 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; }