protected void checkActivationName(String name, int token) { if (!insideFunction()) { return; } boolean activation = false; if ("arguments".equals(name) && // An arrow function not generate arguments. So it not need activation. ((FunctionNode)currentScriptOrFn).getFunctionType() != FunctionNode.ARROW_FUNCTION) { activation = true; } else if (compilerEnv.getActivationNames() != null && compilerEnv.getActivationNames().contains(name)) { activation = true; } else if ("length".equals(name)) { if (token == Token.GETPROP && compilerEnv.getLanguageVersion() == Context.VERSION_1_2) { // Use of "length" in 1.2 requires an activation object. activation = true; } } if (activation) { setRequiresActivation(); } }
PerFunctionVariables(FunctionNode fnNode) { savedCurrentScriptOrFn = Parser.this.currentScriptOrFn; Parser.this.currentScriptOrFn = fnNode; savedCurrentScope = Parser.this.currentScope; Parser.this.currentScope = fnNode; savedLabelSet = Parser.this.labelSet; Parser.this.labelSet = null; savedLoopSet = Parser.this.loopSet; Parser.this.loopSet = null; savedLoopAndSwitchSet = Parser.this.loopAndSwitchSet; Parser.this.loopAndSwitchSet = null; savedEndFlags = Parser.this.endFlags; Parser.this.endFlags = 0; savedInForInit = Parser.this.inForInit; Parser.this.inForInit = false; }
private void transformCompilationUnit(ScriptNode tree, boolean inStrictMode) { loops = new ObjArray(); loopEnds = new ObjArray(); // to save against upchecks if no finally blocks are used. hasFinally = false; // Flatten all only if we are not using scope objects for block scope boolean createScopeObjects = tree.getType() != Token.FUNCTION || ((FunctionNode)tree).requiresActivation(); tree.flattenSymbolTable(!createScopeObjects); //uncomment to print tree before transformation if (Token.printTrees) System.out.println(tree.toStringTree(tree)); transformCompilationUnit_r(tree, tree, tree, createScopeObjects, inStrictMode); }
/** * 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; }
private void generateFunctionICode() { itsInFunctionFlag = true; FunctionNode theFunction = (FunctionNode)scriptOrFn; itsData.itsFunctionType = theFunction.getFunctionType(); itsData.itsNeedsActivation = theFunction.requiresActivation(); if (theFunction.getFunctionName() != null) { itsData.itsName = theFunction.getName(); } if (theFunction.isGenerator()) { addIcode(Icode_GENERATOR); addUint16(theFunction.getBaseLineno() & 0xFFFF); } if (theFunction.isInStrictMode()) { itsData.isStrict = true; } generateICodeFromTree(theFunction.getLastChild()); }
private void generateNestedFunctions() { int functionCount = scriptOrFn.getFunctionCount(); if (functionCount == 0) return; InterpreterData[] array = new InterpreterData[functionCount]; for (int i = 0; i != functionCount; i++) { FunctionNode fn = scriptOrFn.getFunctionNode(i); CodeGenerator gen = new CodeGenerator(); gen.compilerEnv = compilerEnv; gen.scriptOrFn = fn; gen.itsData = new InterpreterData(itsData); gen.generateFunctionICode(); array[i] = gen.itsData; } itsData.itsNestedFunctions = array; }
private void transformCompilationUnit(ScriptNode tree) { loops = new ObjArray(); loopEnds = new ObjArray(); // to save against upchecks if no finally blocks are used. hasFinally = false; // Flatten all only if we are not using scope objects for block scope boolean createScopeObjects = tree.getType() != Token.FUNCTION || ((FunctionNode)tree).requiresActivation(); tree.flattenSymbolTable(!createScopeObjects); //uncomment to print tree before transformation if (Token.printTrees) System.out.println(tree.toStringTree(tree)); boolean inStrictMode = tree instanceof AstRoot && ((AstRoot)tree).isInStrictMode(); transformCompilationUnit_r(tree, tree, tree, createScopeObjects, inStrictMode); }
private void generateFunctionICode() { itsInFunctionFlag = true; FunctionNode theFunction = (FunctionNode)scriptOrFn; itsData.itsFunctionType = theFunction.getFunctionType(); itsData.itsNeedsActivation = theFunction.requiresActivation(); if (theFunction.getFunctionName() != null) { itsData.itsName = theFunction.getName(); } if (!theFunction.getIgnoreDynamicScope()) { if (compilerEnv.isUseDynamicScope()) { itsData.useDynamicScope = true; } } if (theFunction.isGenerator()) { addIcode(Icode_GENERATOR); addUint16(theFunction.getBaseLineno() & 0xFFFF); } generateICodeFromTree(theFunction.getLastChild()); }
/** * Checks every variable {@code v} in {@code source} is marked as a * number-variable iff {@code numbers} contains {@code v} */ protected void assertNumberVars(CharSequence source, String... numbers) { // wrap source in function ScriptNode tree = compile("function f(){" + source + "}"); FunctionNode fnode = tree.getFunctionNode(0); assertNotNull(fnode); OptFunctionNode opt = OptFunctionNode.get(fnode); assertNotNull(opt); assertSame(fnode, opt.fnode); for (int i = 0, c = fnode.getParamCount(); i < c; ++i) { assertTrue(opt.isParameter(i)); assertFalse(opt.isNumberVar(i)); } Set<String> set = new HashSet<String>(asList(numbers)); for (int i = fnode.getParamCount(), c = fnode.getParamAndVarCount(); i < c; ++i) { assertFalse(opt.isParameter(i)); String name = fnode.getParamOrVarName(i); String msg = format("{%s -> number? = %b}", name, opt.isNumberVar(i)); assertEquals(msg, set.contains(name), opt.isNumberVar(i)); } }
/** * Checks every variable {@code v} in {@code source} is marked as a * number-variable iff {@code numbers} contains {@code v} */ protected void assertNumberVars(CharSequence source, String... numbers) { // wrap source in function ScriptNode tree = compile("function f(o, fn){" + source + "}"); FunctionNode fnode = tree.getFunctionNode(0); assertNotNull(fnode); OptFunctionNode opt = OptFunctionNode.get(fnode); assertNotNull(opt); assertSame(fnode, opt.fnode); for (int i = 0, c = fnode.getParamCount(); i < c; ++i) { assertTrue(opt.isParameter(i)); assertFalse(opt.isNumberVar(i)); } Set<String> set = new HashSet<String>(asList(numbers)); for (int i = fnode.getParamCount(), c = fnode.getParamAndVarCount(); i < c; ++i) { assertFalse(opt.isParameter(i)); String name = fnode.getParamOrVarName(i); String msg = format("{%s -> number? = %b}", name, opt.isNumberVar(i)); assertEquals(msg, set.contains(name), opt.isNumberVar(i)); } }
/** * 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); }
@Override public boolean visit(AstNode node) { if (node instanceof PropertyGet){ PropertyGet pg = (PropertyGet)node; AstNode target = pg.getTarget(); String propName = pg.getProperty().getIdentifier(); if (target instanceof KeywordLiteral && ConstraintGenUtil.isThis(target)){ if (node.getParent() instanceof Assignment){ Assignment a = (Assignment)node.getParent(); if (a.getLeft() == node){ writtenProperties.add(propName); } else { readProperties.add(propName); } } else { readProperties.add(propName); } readProperties.removeAll(writtenProperties); // if something is read and written, it should only be in the written set } } else if (node instanceof FunctionNode) { // don't recurse into nested function body return false; } return true; }
/** * 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 return statements */ private void processReturnStatement(ReturnStatement rs) throws Error { FunctionNode fun = ConstraintGenUtil.findEnclosingFunction(rs); FunctionTerm.FunctionKind funType = ConstraintGenUtil.isConstructor(fun) ? FunctionTerm.FunctionKind.Constructor : (ConstraintGenUtil.isMethod(fun) ? FunctionTerm.FunctionKind.Method : FunctionTerm.FunctionKind.Function); ITypeTerm funTerm = findOrCreateFunctionTerm(fun, funType); ITypeTerm returnTerm = findOrCreateFunctionReturnTerm(funTerm, fun.getParamCount(), rs.getLineno(), null); AstNode exp = rs.getReturnValue(); if (exp != null){ ITypeTerm expTerm = processExpression(exp); addSubTypeConstraint(expTerm, returnTerm, rs.getLineno(), (solution) -> subtypeError("bad return value " + shortSrc(exp), solution.typeOfTerm(expTerm), solution.typeOfTerm(returnTerm), locationOf(rs))); } else { ITypeTerm voidTerm = findOrCreateTypeTerm(new VoidType(), rs.getLineno()); addTypeEqualityConstraint(voidTerm, returnTerm, rs.getLineno(), (solution) -> genericTypeError("missing return value", locationOf(rs)) .withNote("expected " + describeTypeOf(returnTerm, solution))); } }
private void generateFunctionICode() { itsInFunctionFlag = true; FunctionNode theFunction = (FunctionNode)scriptOrFn; itsData.itsFunctionType = theFunction.getFunctionType(); itsData.itsNeedsActivation = theFunction.requiresActivation(); if (theFunction.getFunctionName() != null) { itsData.itsName = theFunction.getName(); } if (theFunction.isGenerator()) { addIcode(Icode_GENERATOR); addUint16(theFunction.getBaseLineno() & 0xFFFF); } generateICodeFromTree(theFunction.getLastChild()); }