private AstNode xmlInitializer() throws IOException { if (currentToken != Token.LT) codeBug(); int pos = ts.tokenBeg, tt = ts.getFirstXMLToken(); if (tt != Token.XML && tt != Token.XMLEND) { reportError("msg.syntax"); return makeErrorNode(); } XmlLiteral pn = new XmlLiteral(pos); pn.setLineno(ts.lineno); for (;;tt = ts.getNextXMLToken()) { switch (tt) { case Token.XML: pn.addFragment(new XmlString(ts.tokenBeg, ts.getString())); mustMatchToken(Token.LC, "msg.syntax"); int beg = ts.tokenBeg; AstNode expr = (peekToken() == Token.RC) ? new EmptyExpression(beg, ts.tokenEnd - beg) : expr(); mustMatchToken(Token.RC, "msg.syntax"); XmlExpression xexpr = new XmlExpression(beg, expr); xexpr.setIsXmlAttribute(ts.isXMLAttribute()); xexpr.setLength(ts.tokenEnd - beg); pn.addFragment(xexpr); break; case Token.XMLEND: pn.addFragment(new XmlString(ts.tokenBeg, ts.getString())); return pn; default: reportError("msg.syntax"); return makeErrorNode(); } } }
private AstNode parenExpr() throws IOException { boolean wasInForInit = inForInit; inForInit = false; try { Comment jsdocNode = getAndResetJsDoc(); int lineno = ts.lineno; int begin = ts.tokenBeg; AstNode e = (peekToken() == Token.RP ? new EmptyExpression(begin) : expr()); if (peekToken() == Token.FOR) { return generatorExpression(e, begin); } ParenthesizedExpression pn = new ParenthesizedExpression(e); if (jsdocNode == null) { jsdocNode = getAndResetJsDoc(); } if (jsdocNode != null) { pn.setJsDocNode(jsdocNode); } mustMatchToken(Token.RP, "msg.no.paren"); if (e.getType() == Token.EMPTY && peekToken() != Token.ARROW) { reportError("msg.syntax"); return makeErrorNode(); } pn.setLength(ts.tokenEnd - pn.getPosition()); pn.setLineno(lineno); return pn; } finally { inForInit = wasInForInit; } }
private Node transformXmlLiteral(XmlLiteral node) { // a literal like <foo>{bar}</foo> is rewritten as // new XML("<foo>" + bar + "</foo>"); Node pnXML = new Node(Token.NEW, node.getLineno()); List<XmlFragment> frags = node.getFragments(); XmlString first = (XmlString)frags.get(0); boolean anon = first.getXml().trim().startsWith("<>"); pnXML.addChildToBack(createName(anon ? "XMLList" : "XML")); Node pn = null; for (XmlFragment frag : frags) { if (frag instanceof XmlString) { String xml = ((XmlString)frag).getXml(); decompiler.addName(xml); if (pn == null) { pn = createString(xml); } else { pn = createBinary(Token.ADD, pn, createString(xml)); } } else { XmlExpression xexpr = (XmlExpression)frag; boolean isXmlAttr = xexpr.isXmlAttribute(); Node expr; decompiler.addToken(Token.LC); if (xexpr.getExpression() instanceof EmptyExpression) { expr = createString(""); } else { expr = transform(xexpr.getExpression()); } decompiler.addToken(Token.RC); if (isXmlAttr) { // Need to put the result in double quotes expr = createUnary(Token.ESCXMLATTR, expr); Node prepend = createBinary(Token.ADD, createString("\""), expr); expr = createBinary(Token.ADD, prepend, createString("\"")); } else { expr = createUnary(Token.ESCXMLTEXT, expr); } pn = createBinary(Token.ADD, pn, expr); } } pnXML.addChildToBack(pn); return pnXML; }
private AstNode arrowFunction(AstNode params) throws IOException { int baseLineno = ts.lineno; // line number where source starts int functionSourceStart = params != null ? params.getPosition() : -1; // start of "function" kwd FunctionNode fnNode = new FunctionNode(functionSourceStart); fnNode.setFunctionType(FunctionNode.ARROW_FUNCTION); fnNode.setJsDocNode(getAndResetJsDoc()); // Would prefer not to call createDestructuringAssignment until codegen, // but the symbol definitions have to happen now, before body is parsed. Map<String, Node> destructuring = new HashMap<String, Node>(); Set<String> paramNames = new HashSet<String>(); PerFunctionVariables savedVars = new PerFunctionVariables(fnNode); try { if (params instanceof ParenthesizedExpression) { fnNode.setParens(0, params.getLength()); AstNode p = ((ParenthesizedExpression)params).getExpression(); if (!(p instanceof EmptyExpression)) { arrowFunctionParams(fnNode, p, destructuring, paramNames); } } else { arrowFunctionParams(fnNode, params, destructuring, paramNames); } if (!destructuring.isEmpty()) { Node destructuringNode = new Node(Token.COMMA); // Add assignment helper for each destructuring parameter for (Map.Entry<String, Node> param: destructuring.entrySet()) { Node assign = createDestructuringAssignment(Token.VAR, param.getValue(), createName(param.getKey())); destructuringNode.addChildToBack(assign); } fnNode.putProp(Node.DESTRUCTURING_PARAMS, destructuringNode); } fnNode.setBody(parseFunctionBody(FunctionNode.ARROW_FUNCTION, fnNode)); fnNode.setEncodedSourceBounds(functionSourceStart, ts.tokenEnd); fnNode.setLength(ts.tokenEnd - functionSourceStart); } finally { savedVars.restore(); } if (fnNode.isGenerator()) { reportError("msg.arrowfunction.generator"); return makeErrorNode(); } fnNode.setSourceName(sourceURI); fnNode.setBaseLineno(baseLineno); fnNode.setEndLineno(ts.lineno); return fnNode; }
/** * May return an {@link ArrayLiteral} or {@link ArrayComprehension}. */ private AstNode arrayLiteral() throws IOException { if (currentToken != Token.LB) codeBug(); int pos = ts.tokenBeg, end = ts.tokenEnd; List<AstNode> elements = new ArrayList<AstNode>(); ArrayLiteral pn = new ArrayLiteral(pos); boolean after_lb_or_comma = true; int afterComma = -1; int skipCount = 0; for (;;) { int tt = peekToken(); if (tt == Token.COMMA) { consumeToken(); afterComma = ts.tokenEnd; if (!after_lb_or_comma) { after_lb_or_comma = true; } else { elements.add(new EmptyExpression(ts.tokenBeg, 1)); skipCount++; } } else if (tt == Token.RB) { consumeToken(); // for ([a,] in obj) is legal, but for ([a] in obj) is // not since we have both key and value supplied. The // trick is that [a,] and [a] are equivalent in other // array literal contexts. So we calculate a special // length value just for destructuring assignment. end = ts.tokenEnd; pn.setDestructuringLength(elements.size() + (after_lb_or_comma ? 1 : 0)); pn.setSkipCount(skipCount); if (afterComma != -1) warnTrailingComma(pos, elements, afterComma); break; } else if (tt == Token.FOR && !after_lb_or_comma && elements.size() == 1) { return arrayComprehension(elements.get(0), pos); } else if (tt == Token.EOF) { reportError("msg.no.bracket.arg"); break; } else { if (!after_lb_or_comma) { reportError("msg.no.bracket.arg"); } elements.add(assignExpr()); after_lb_or_comma = false; afterComma = -1; } } for (AstNode e : elements) { pn.addElement(e); } pn.setLength(end - pos); 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; }
/** * 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); } }
/** * handle empty expressions (used e.g. in for loops). */ private ITypeTerm processEmptyExpression(EmptyExpression n) { return findOrCreateExpressionTerm(n); }