private void print(VariableDeclaration node) throws IOException { switch (node.getType()) { case Token.VAR: writer.append("var "); break; case Token.LET: writer.append("let "); break; case Token.CONST: writer.append("const "); break; default: break; } print(node.getVariables().get(0)); for (int i = 1; i < node.getVariables().size(); ++i) { writer.append(',').ws(); print(node.getVariables().get(i)); } if (node.isStatement()) { writer.append(';'); } }
private Node transformForInLoop(ForInLoop loop) { decompiler.addToken(Token.FOR); if (loop.isForEach()) decompiler.addName("each "); decompiler.addToken(Token.LP); loop.setType(Token.LOOP); pushScope(loop); try { int declType = -1; AstNode iter = loop.getIterator(); if (iter instanceof VariableDeclaration) { declType = ((VariableDeclaration)iter).getType(); } Node lhs = transform(iter); if (loop.isForOf()) { decompiler.addName("of "); } else { decompiler.addToken(Token.IN); } Node obj = transform(loop.getIteratedObject()); decompiler.addToken(Token.RP); decompiler.addEOL(Token.LC); Node body = transform(loop.getBody()); decompiler.addEOL(Token.RC); return createForIn(declType, loop, lhs, obj, body, loop.isForEach(), loop.isForOf()); } finally { popScope(); } }
private Node transformVariables(VariableDeclaration node) { decompiler.addToken(node.getType()); transformVariableInitializers(node); // Might be most robust to have parser record whether it was // a variable declaration statement, possibly as a node property. AstNode parent = node.getParent(); if (!(parent instanceof Loop) && !(parent instanceof LetNode)) { decompiler.addEOL(Token.SEMI); } return node; }
/** * generate constraints for a for-in loop */ private void processForInLoop(ForInLoop loop) { AstNode it = loop.getIterator(); AstNode obj = loop.getIteratedObject(); ITypeTerm objTerm = processExpression(obj); MapType mapType = new MapType(factory.freshTypeVar()); addSubTypeConstraint( objTerm, findOrCreateTypeTerm(mapType, loop.getLineno()), loop.getLineno(), (solution) -> typeEqualityError("for-in loop can only iterate over map objects; " + obj.toSource() + " is not a map", solution.typeOfTerm(objTerm), mapType, locationOf(obj))); if (it instanceof VariableDeclaration){ VariableDeclaration vd = (VariableDeclaration)it; for (VariableInitializer vi : vd.getVariables()){ AstNode target = vi.getTarget(); if (target instanceof Name){ ITypeTerm leftTerm = findOrCreateNameDeclarationTerm((Name)target); addSubTypeConstraint( leftTerm, findOrCreateTypeTerm(StringType.make(), loop.getLineno()), loop.getLineno(), (solution) -> typeEqualityError( "loop variable " + it.toSource() + " of for-in loop must have string type", solution.typeOfTerm(leftTerm), StringType.make(), locationOf(it))); } } } else { error("unhandled type of iterator in for-in loop: " + it.getClass().getName(), it); } }
@Override public boolean visit(AstNode node) { if (node==null) { return false; } int nodeType = node.getType(); switch (nodeType) { case Token.SCRIPT: // AstRoot curScopeTreeNode = root; return true; case Token.FUNCTION: FunctionNode fn = (FunctionNode)node; return visitFunction(fn); case Token.VAR: VariableDeclaration varDec = (VariableDeclaration)node; return visitVariableDeclaration(varDec); case Token.BLOCK: return true; case Token.EXPR_RESULT: ExpressionStatement exprStmt = (ExpressionStatement)node; return visitExpressionStatement(exprStmt); } return false; // Unhandled node type }
/** * Extract variable from node and add to code block */ private void processVariableNode(Node child, CodeBlock block, Set<Completion> set, String entered, int offset) { //check block can resolve variable or is pre-processing variables if(block.contains(dot) || isPreProcessing()) { VariableDeclaration varDec = (VariableDeclaration) child; List<VariableInitializer> vars = varDec.getVariables(); for (VariableInitializer var : vars) { extractVariableFromNode(var, block, offset); } } }
private Node transformVariableInitializers(VariableDeclaration node) { List<VariableInitializer> vars = node.getVariables(); int size = vars.size(), i = 0; for (VariableInitializer var : vars) { AstNode target = var.getTarget(); AstNode init = var.getInitializer(); Node left = null; if (var.isDestructuring()) { decompile(target); // decompile but don't transform left = target; } else { left = transform(target); } Node right = null; if (init != null) { decompiler.addToken(Token.ASSIGN); right = transform(init); } if (var.isDestructuring()) { if (right == null) { // TODO: should this ever happen? node.addChildToBack(left); } else { Node d = createDestructuringAssignment(node.getType(), left, right); node.addChildToBack(d); } } else { if (right != null) { left.addChildToBack(right); } node.addChildToBack(left); } if (i++ < size-1) { decompiler.addToken(Token.COMMA); } } return node; }
private AstNode let(boolean isStatement, int pos) throws IOException { LetNode pn = new LetNode(pos); pn.setLineno(ts.lineno); if (mustMatchToken(Token.LP, "msg.no.paren.after.let")) pn.setLp(ts.tokenBeg - pos); pushScope(pn); try { VariableDeclaration vars = variables(Token.LET, ts.tokenBeg, isStatement); pn.setVariables(vars); if (mustMatchToken(Token.RP, "msg.no.paren.let")) { pn.setRp(ts.tokenBeg - pos); } if (isStatement && peekToken() == Token.LC) { // let statement consumeToken(); int beg = ts.tokenBeg; // position stmt at LC AstNode stmt = statements(); mustMatchToken(Token.RC, "msg.no.curly.let"); stmt.setLength(ts.tokenEnd - beg); pn.setLength(ts.tokenEnd - pos); pn.setBody(stmt); pn.setType(Token.LET); } else { // let expression AstNode expr = expr(); pn.setLength(getNodeEnd(expr) - pos); pn.setBody(expr); if (isStatement) { // let expression in statement context ExpressionStatement es = new ExpressionStatement(pn, !insideFunction()); es.setLineno(pn.getLineno()); return es; } } } finally { popScope(); } return pn; }
/** * 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; }