/** * For a conditional expression e1 ? e2 : e3, create an ITerm representing the * type of the entire expression and equate that term to the ITerms representing * the type of e2 and e3. * * We do not require the test expression to be a boolean; we can handle the implicit * conversions for this case. */ private ITypeTerm processConditionalExpression(ConditionalExpression ce) { ITypeTerm condTerm = findOrCreateExpressionTerm(ce); // still process the test expression to generate any appropriate // nested constraints processExpression(ce.getTestExpression()); ITypeTerm trueTerm = processExpression(ce.getTrueExpression()); ITypeTerm falseTerm = processExpression(ce.getFalseExpression()); addSubTypeConstraint(trueTerm, condTerm, ce.getLineno(), (solution) -> subtypeError("conditional expression branches are incompatible", solution.typeOfTerm(trueTerm), solution.typeOfTerm(condTerm), locationOf(ce))); addSubTypeConstraint(falseTerm, condTerm, ce.getLineno(), (solution) -> subtypeError("conditional expression branches are incompatible", solution.typeOfTerm(falseTerm), solution.typeOfTerm(condTerm), locationOf(ce))); return condTerm; }
private Node transformCondExpr(ConditionalExpression node) { Node test = transform(node.getTestExpression()); decompiler.addToken(Token.HOOK); Node ifTrue = transform(node.getTrueExpression()); decompiler.addToken(Token.COLON); Node ifFalse = transform(node.getFalseExpression()); return createCondExpr(test, ifTrue, ifFalse); }
private AstNode condExpr() throws IOException { AstNode pn = orExpr(); if (matchToken(Token.HOOK)) { int line = ts.lineno; int qmarkPos = ts.tokenBeg, colonPos = -1; /* * Always accept the 'in' operator in the middle clause of a ternary, * where it's unambiguous, even if we might be parsing the init of a * for statement. */ boolean wasInForInit = inForInit; inForInit = false; AstNode ifTrue; try { ifTrue = assignExpr(); } finally { inForInit = wasInForInit; } if (mustMatchToken(Token.COLON, "msg.no.colon.cond")) colonPos = ts.tokenBeg; AstNode ifFalse = assignExpr(); int beg = pn.getPosition(), len = getNodeEnd(ifFalse) - beg; ConditionalExpression ce = new ConditionalExpression(beg, len); ce.setLineno(line); ce.setTestExpression(pn); ce.setTrueExpression(ifTrue); ce.setFalseExpression(ifFalse); ce.setQuestionMarkPosition(qmarkPos - beg); ce.setColonPosition(colonPos - beg); pn = ce; } return pn; }
private void print(ConditionalExpression node, int precedence) throws IOException { if (precedence < PRECEDENCE_COND) { writer.append('('); } print(node.getTestExpression(), PRECEDENCE_COND - 1); writer.ws().append('?').ws(); print(node.getTrueExpression(), PRECEDENCE_COND - 1); writer.ws().append(':').ws(); print(node.getFalseExpression(), PRECEDENCE_COND); if (precedence < PRECEDENCE_COND) { writer.append(')'); } }
/** * 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); } }