Search in sources :

Example 1 with Expression

use of com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression in project ceylon-compiler by ceylon.

the class ExpressionTransformer method transformSpreadArgument.

private ExpressionAndType transformSpreadArgument(SimpleInvocation invocation, int numArguments, int argIndex, BoxingStrategy boxingStrategy, Type parameterType) {
    ExpressionAndType exprAndType;
    final Type iteratedType = typeFact().getIteratedType(parameterType);
    final JCExpression expr;
    final JCExpression type;
    // optimise "*javaArray.iterable" into "javaArray" for java variadic parameters, since we can pass them just along
    if (invocation.isJavaMethod() && numArguments == argIndex + 1 && !invocation.isArgumentComprehension(argIndex)) {
        Expression argumentExpression = invocation.getArgumentExpression(argIndex);
        Term argument = Decl.unwrapExpressionsUntilTerm(argumentExpression);
        if (argument instanceof Tree.QualifiedMemberExpression) {
            Tree.QualifiedMemberExpression qualifiedMemberArgument = (Tree.QualifiedMemberExpression) argument;
            if ("iterable".equals(qualifiedMemberArgument.getIdentifier().getText()) && isJavaArray(qualifiedMemberArgument.getPrimary().getTypeModel())) {
                // just pass the array as-is
                // we don't care at all about unboxing or casting since we can't be dealing with boxing
                // and we generate our own cast, at least for non-primitive arrays where it may be ambiguous,
                // we could avoid the cast for non-type-parameter and non-Object arrays, but that's more expensive
                // to check for
                JCExpression primary = transformExpression(qualifiedMemberArgument.getPrimary());
                type = makeJavaType(typeFact().getSequenceType(iteratedType).getType());
                if (isJavaObjectArray(qualifiedMemberArgument.getPrimary().getTypeModel())) {
                    expr = make().TypeCast(makeJavaType(qualifiedMemberArgument.getPrimary().getTypeModel()), primary);
                } else {
                    expr = primary;
                }
                return new ExpressionAndType(expr, type);
            }
        }
    }
    // invoking f(a, *b), where declared f(A a, B* b)
    // we can have several remaining arguments and the last one is spread
    List<JCExpression> x = List.<JCExpression>nil();
    for (int ii = argIndex; ii < numArguments; ii++) {
        JCExpression argExpr = invocation.getTransformedArgumentExpression(ii);
        // the last parameter is spread and must be put first
        if (ii < numArguments - 1) {
            x = x.append(argExpr);
        } else {
            // convert to a Sequential if required
            Type argType = invocation.getArgumentType(ii);
            if (!typeFact().isSequentialType(argType))
                argExpr = iterableToSequential(argExpr);
            x = x.prepend(argExpr);
        }
    }
    if (invocation.isJavaMethod()) {
        // collect all the initial arguments and wrap into a Java array
        // first arg is the spread part
        JCExpression last = x.head;
        // remove it from x
        x = x.tail;
        Type lastType = invocation.getArgumentType(numArguments - 1);
        // must translate it into a Util call
        expr = sequenceToJavaArray(invocation, last, parameterType, boxingStrategy, lastType, x);
    } else {
        JCExpression typeExpr = makeJavaType(iteratedType, JT_TYPE_ARGUMENT);
        JCExpression sequentialExpr = utilInvocation().sequentialInstance(typeExpr, makeReifiedTypeArgument(iteratedType), x.head, x.tail);
        if (invocation.isParameterVariadicPlus(argIndex)) {
            expr = utilInvocation().castSequentialToSequence(sequentialExpr, iteratedType);
        } else {
            expr = sequentialExpr;
        }
    }
    type = makeJavaType(typeFact().getSequenceType(iteratedType).getType());
    exprAndType = new ExpressionAndType(expr, type);
    return exprAndType;
}
Also used : Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) LetExpression(com.redhat.ceylon.compiler.typechecker.tree.Tree.LetExpression) Expression(com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) TreeUtil.unwrapExpressionUntilTerm(com.redhat.ceylon.compiler.typechecker.tree.TreeUtil.unwrapExpressionUntilTerm) Term(com.redhat.ceylon.compiler.typechecker.tree.Tree.Term)

Example 2 with Expression

use of com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression in project ceylon-compiler by ceylon.

the class StatementTransformer method transform.

public JCStatement transform(Tree.TryCatchStatement t) {
    Tree.TryClause tryClause = t.getTryClause();
    at(tryClause);
    JCBlock tryBlock = transform(tryClause.getBlock());
    Tree.ResourceList resList = tryClause.getResourceList();
    if (resList != null) {
        ArrayList<Tree.Resource> resources = new ArrayList<Tree.Resource>(resList.getResources());
        Collections.reverse(resources);
        for (Tree.Resource res : resources) {
            List<JCStatement> stats = List.nil();
            Tree.Expression resExpr;
            String resVarName;
            if (res.getExpression() != null) {
                resExpr = res.getExpression();
                resVarName = naming.newTemp("try");
            } else if (res.getVariable() != null) {
                Tree.Variable var = res.getVariable();
                resExpr = var.getSpecifierExpression().getExpression();
                resVarName = var.getIdentifier().getText();
            } else {
                throw new BugException(res, "missing resource expression");
            }
            boolean isDestroyable = typeFact().getDestroyableType().isSupertypeOf(resExpr.getTypeModel());
            Type resVarType = resExpr.getTypeModel();
            Type resVarExpectedType = isDestroyable ? typeFact().getDestroyableType() : typeFact().getObtainableType();
            // CloseableType $var = resource-expression
            JCExpression expr = expressionGen().transformExpression(resExpr);
            JCExpression javaType = makeJavaType(resVarType);
            JCVariableDecl var = makeVar(FINAL, resVarName, javaType, expr);
            stats = stats.append(var);
            if (!isDestroyable) {
                JCExpression resVar0 = expressionGen().applyErasureAndBoxing(makeUnquotedIdent(resVarName), resVarType, true, BoxingStrategy.BOXED, resVarExpectedType);
                JCMethodInvocation openCall = make().Apply(null, makeQualIdent(resVar0, "obtain"), List.<JCExpression>nil());
                stats = stats.append(make().Exec(openCall));
            }
            // Exception $tpmex = null;
            String innerExTmpVarName = naming.newTemp("ex");
            JCExpression innerExType = makeJavaType(typeFact().getThrowableType(), JT_CATCH);
            JCVariableDecl innerExTmpVar = makeVar(innerExTmpVarName, innerExType, makeNull());
            stats = stats.append(innerExTmpVar);
            // $tmpex = ex;
            List<JCStatement> innerCatchStats = List.nil();
            Name innerCatchVarName = naming.tempName("ex");
            JCAssign exTmpAssign = make().Assign(makeUnquotedIdent(innerExTmpVarName), make().Ident(innerCatchVarName));
            innerCatchStats = innerCatchStats.append(make().Exec(exTmpAssign));
            // throw ex;
            JCThrow innerCatchThrow = make().Throw(make().Ident(innerCatchVarName));
            innerCatchStats = innerCatchStats.append(innerCatchThrow);
            JCBlock innerCatchBlock = make().Block(0, innerCatchStats);
            // $var.close() /// ((Closeable)$var).close()
            JCExpression exarg = makeUnquotedIdent(innerExTmpVarName);
            JCExpression resVar1 = expressionGen().applyErasureAndBoxing(makeUnquotedIdent(resVarName), resVarType, true, BoxingStrategy.BOXED, resVarExpectedType);
            JCMethodInvocation closeCall = make().Apply(null, makeQualIdent(resVar1, isDestroyable ? "destroy" : "release"), List.<JCExpression>of(exarg));
            JCBlock closeTryBlock = make().Block(0, List.<JCStatement>of(make().Exec(closeCall)));
            // try { $var.close() } catch (Exception closex) { $tmpex.addSuppressed(closex); }
            Name closeCatchVarName = naming.tempName("closex");
            JCExpression closeCatchExType = makeJavaType(typeFact().getThrowableType(), JT_CATCH);
            JCVariableDecl closeCatchVar = make().VarDef(make().Modifiers(Flags.FINAL), closeCatchVarName, closeCatchExType, null);
            JCExpression addarg = make().Ident(closeCatchVarName);
            JCMethodInvocation addSuppressedCall = make().Apply(null, makeQualIdent(makeUnquotedIdent(innerExTmpVarName), "addSuppressed"), List.<JCExpression>of(addarg));
            JCCatch closeCatch = make().Catch(closeCatchVar, make().Block(0, List.<JCStatement>of(make().Exec(addSuppressedCall))));
            JCTry closeTry = at(res).Try(closeTryBlock, List.<JCCatch>of(closeCatch), null);
            // $var.close() /// ((Closeable)$var).close()
            JCExpression exarg2 = makeUnquotedIdent(innerExTmpVarName);
            JCExpression resVar2 = expressionGen().applyErasureAndBoxing(makeUnquotedIdent(resVarName), resVarType, true, BoxingStrategy.BOXED, resVarExpectedType);
            JCMethodInvocation closeCall2 = make().Apply(null, makeQualIdent(resVar2, isDestroyable ? "destroy" : "release"), List.<JCExpression>of(exarg2));
            // if ($tmpex != null) { ... } else { ... }
            JCBinary closeCatchCond = make().Binary(JCTree.NE, makeUnquotedIdent(innerExTmpVarName), makeNull());
            JCIf closeCatchIf = make().If(closeCatchCond, closeTry, make().Exec(closeCall2));
            // try { .... } catch (Exception ex) { $tmpex=ex; throw ex; }
            // finally { try { $var.close() } catch (Exception closex) { } }
            JCExpression innerCatchExType = makeJavaType(typeFact().getThrowableType(), JT_CATCH);
            JCVariableDecl innerCatchVar = make().VarDef(make().Modifiers(Flags.FINAL), innerCatchVarName, innerCatchExType, null);
            JCCatch innerCatch = make().Catch(innerCatchVar, innerCatchBlock);
            JCBlock innerFinallyBlock = make().Block(0, List.<JCStatement>of(closeCatchIf));
            JCTry innerTry = at(res).Try(tryBlock, List.<JCCatch>of(innerCatch), innerFinallyBlock);
            stats = stats.append(innerTry);
            tryBlock = at(res).Block(0, stats);
        }
    }
    final List<JCCatch> catches;
    if (usePolymorphicCatches(t.getCatchClauses())) {
        catches = transformCatchesPolymorphic(t.getCatchClauses());
    } else {
        catches = transformCatchesIfElseIf(t.getCatchClauses());
    }
    final JCBlock finallyBlock;
    Tree.FinallyClause finallyClause = t.getFinallyClause();
    if (finallyClause != null) {
        at(finallyClause);
        finallyBlock = transform(finallyClause.getBlock());
    } else {
        finallyBlock = null;
    }
    if (!catches.isEmpty() || finallyBlock != null) {
        return at(t).Try(tryBlock, catches, finallyBlock);
    } else {
        return tryBlock;
    }
}
Also used : Variable(com.redhat.ceylon.compiler.typechecker.tree.Tree.Variable) JCAssign(com.sun.tools.javac.tree.JCTree.JCAssign) ArrayList(java.util.ArrayList) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement) SyntheticName(com.redhat.ceylon.compiler.java.codegen.Naming.SyntheticName) CName(com.redhat.ceylon.compiler.java.codegen.Naming.CName) Name(com.sun.tools.javac.util.Name) OptionName(com.sun.tools.javac.main.OptionName) JCIf(com.sun.tools.javac.tree.JCTree.JCIf) Expression(com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression) CustomTree(com.redhat.ceylon.compiler.typechecker.tree.CustomTree) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) JCThrow(com.sun.tools.javac.tree.JCTree.JCThrow) JCBlock(com.sun.tools.javac.tree.JCTree.JCBlock) JCBinary(com.sun.tools.javac.tree.JCTree.JCBinary) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) JCTry(com.sun.tools.javac.tree.JCTree.JCTry) JCMethodInvocation(com.sun.tools.javac.tree.JCTree.JCMethodInvocation) Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCCatch(com.sun.tools.javac.tree.JCTree.JCCatch)

Example 3 with Expression

use of com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression in project ceylon-compiler by ceylon.

the class StatementTransformer method transform.

/**
     * Transforms a Ceylon destructuring assignment to Java code.
     * @param stmt The Ceylon destructure
     * @return The Java tree
     */
List<JCVariableDecl> transform(Tree.Destructure stmt) {
    List<JCVariableDecl> result = List.nil();
    // Create temp var to hold result of expression
    Tree.Pattern pat = stmt.getPattern();
    Naming.SyntheticName tmpVarName = naming.synthetic(pat);
    Expression destExpr = stmt.getSpecifierExpression().getExpression();
    JCExpression typeExpr = makeJavaType(destExpr.getTypeModel());
    JCExpression expr = expressionGen().transformExpression(destExpr);
    at(stmt);
    JCVariableDecl tmpVar = makeVar(Flags.FINAL, tmpVarName, typeExpr, expr);
    result = result.append(tmpVar);
    // Now add the destructured variables
    List<JCVariableDecl> vars = VarDefBuilder.buildAll(transformPattern(pat, tmpVarName.makeIdent()));
    result = result.appendList(vars);
    return result;
}
Also used : JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) SpecifierOrInitializerExpression(com.redhat.ceylon.compiler.typechecker.tree.Tree.SpecifierOrInitializerExpression) Expression(com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression) CustomTree(com.redhat.ceylon.compiler.typechecker.tree.CustomTree) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) SyntheticName(com.redhat.ceylon.compiler.java.codegen.Naming.SyntheticName) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl)

Example 4 with Expression

use of com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression in project ceylon-compiler by ceylon.

the class StatementTransformer method makeThenBlock.

private JCBlock makeThenBlock(Cond cond, Node thenPart, Substitution subs, String tmpVar, Tree.Term outerExpression, Type expectedType) {
    List<JCStatement> blockStmts;
    if (thenPart instanceof Tree.Block)
        blockStmts = statementGen().transformBlock((Tree.Block) thenPart);
    else if (thenPart instanceof Tree.Expression) {
        blockStmts = evaluateAndAssign(tmpVar, (Tree.Expression) thenPart, outerExpression, expectedType);
    } else if (thenPart == null) {
        blockStmts = List.<JCStatement>nil();
    } else {
        blockStmts = List.<JCStatement>of(make().Exec(makeErroneous(thenPart, "Only block or expression allowed")));
    }
    if (subs != null) {
        // The variable holding the result for the code inside the code block
        blockStmts = blockStmts.prepend(at(cond.getCondition()).VarDef(make().Modifiers(FINAL), names().fromString(subs.substituted), cond.getVarTrans().makeTypeExpr(), cond.getVarTrans().makeResultExpr()));
    }
    JCBlock thenBlock = at(cond.getCondition()).Block(0, blockStmts);
    return thenBlock;
}
Also used : JCBlock(com.sun.tools.javac.tree.JCTree.JCBlock) Expression(com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression) JCBlock(com.sun.tools.javac.tree.JCTree.JCBlock) ControlBlock(com.redhat.ceylon.model.typechecker.model.ControlBlock) CustomTree(com.redhat.ceylon.compiler.typechecker.tree.CustomTree) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement)

Example 5 with Expression

use of com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression in project ceylon-compiler by ceylon.

the class StatementTransformer method spanOpIteration.

/**
     * Returns a {@link SpanOpIterationOptimization} if that optimization applies
     * to the given {@code for} statement, otherwise null.
     * @param stmt The for statement
     * @return a {@link SpanOpIterationOptimization} or null.
     */
private ForStatementTransformation spanOpIteration(Tree.ForStatement stmt) {
    if (isOptimizationDisabled(stmt, Optimization.SpanOpIteration)) {
        return optimizationFailed(stmt, Optimization.SpanOpIteration, "optimization explicitly disabled by @disableOptimization");
    }
    Tree.ForIterator iterator = stmt.getForClause().getForIterator();
    if (!(iterator instanceof Tree.ValueIterator)) {
        return optimizationFailed(stmt, Optimization.SpanOpIteration, "optimization applies only to ValueIterators");
    }
    Tree.ValueIterator vi = (Tree.ValueIterator) iterator;
    Tree.SpecifierExpression specifier = vi.getSpecifierExpression();
    Tree.Term term = specifier.getExpression().getTerm();
    final Tree.Term increment;
    final Tree.RangeOp range;
    if (term instanceof Tree.RangeOp) {
        // So it's a for (i in (lhs..rhs)) { ... }
        increment = null;
        range = (Tree.RangeOp) term;
    } else if (term instanceof Tree.InvocationExpression) {
        Tree.InvocationExpression inv = (Tree.InvocationExpression) term;
        if (inv.getPrimary() instanceof Tree.QualifiedMemberExpression) {
            Tree.QualifiedMemberExpression prim = (Tree.QualifiedMemberExpression) inv.getPrimary();
            if ("by".equals(prim.getIdentifier().getText()) && prim.getPrimary() instanceof Tree.Expression && (((Tree.Expression) (prim.getPrimary())).getTerm() instanceof Tree.RangeOp)) {
                // So it's a for (i in (lhs..rhs).by(increment)) { ... }
                range = (Tree.RangeOp) ((Tree.Expression) (prim.getPrimary())).getTerm();
                if (inv.getPositionalArgumentList() != null) {
                    Tree.PositionalArgument a = inv.getPositionalArgumentList().getPositionalArguments().get(0);
                    if (a instanceof Tree.ListedArgument)
                        increment = ((Tree.ListedArgument) a).getExpression().getTerm();
                    else
                        return optimizationFailed(stmt, Optimization.SpanOpIteration, "Unable to determine expression for argument to by(): appears spread or comprehension");
                } else if (inv.getNamedArgumentList() != null) {
                    Tree.SpecifiedArgument sarg = null;
                    for (Tree.NamedArgument arg : inv.getNamedArgumentList().getNamedArguments()) {
                        if ("step".equals(arg.getIdentifier().getText())) {
                            if (arg instanceof Tree.SpecifiedArgument) {
                                sarg = ((Tree.SpecifiedArgument) arg);
                                break;
                            }
                        // TODO In theory we could support Tree.AttributeArgument too
                        }
                    }
                    if (sarg != null) {
                        increment = sarg.getSpecifierExpression().getExpression().getTerm();
                    } else {
                        return optimizationFailed(stmt, Optimization.SpanOpIteration, "Unable to determine expression for argument to by{}");
                    }
                } else {
                    return optimizationFailed(stmt, Optimization.SpanOpIteration, "Unable to get arguments to by()");
                }
            } else {
                return optimizationFailed(stmt, Optimization.SpanOpIteration, "Only applies to Iterables of the form 'lhs..rhs' or '(lhs..rhs).by(step)'");
            }
        } else {
            return optimizationFailed(stmt, Optimization.SpanOpIteration, "Only applies to Iterables of the form 'lhs..rhs' or '(lhs..rhs).by(step)'");
        }
    } else {
        return optimizationFailed(stmt, Optimization.SpanOpIteration, "Only applies to Iterables of the form 'lhs..rhs' or '(lhs..rhs).by(step)'");
    }
    com.sun.tools.javac.code.Type type;
    Type integerType = typeFact().getIntegerType();
    Type characterType = typeFact().getCharacterType();
    if (isSpanOf(range, integerType)) {
        type = syms().longType;
    } else if (isSpanOf(range, characterType)) {
        type = syms().intType;
    } else {
        return optimizationFailed(stmt, Optimization.SpanOpIteration, "The RangeOp doesn't produce a Range<Integer>/Range<Character>");
    }
    return increment == null ? new SpanOpIterationOptimization(stmt, range, increment, type) : new SpanOpWithStepIterationOptimization(stmt, range, increment, type);
}
Also used : Expression(com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression) CustomTree(com.redhat.ceylon.compiler.typechecker.tree.CustomTree) JCTree(com.sun.tools.javac.tree.JCTree) Tree(com.redhat.ceylon.compiler.typechecker.tree.Tree) RangeOp(com.redhat.ceylon.compiler.typechecker.tree.Tree.RangeOp) Term(com.redhat.ceylon.compiler.typechecker.tree.Tree.Term) Type(com.redhat.ceylon.model.typechecker.model.Type) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) SpecifierOrInitializerExpression(com.redhat.ceylon.compiler.typechecker.tree.Tree.SpecifierOrInitializerExpression) Expression(com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression) RangeOp(com.redhat.ceylon.compiler.typechecker.tree.Tree.RangeOp)

Aggregations

Expression (com.redhat.ceylon.compiler.typechecker.tree.Tree.Expression)15 Tree (com.redhat.ceylon.compiler.typechecker.tree.Tree)14 JCTree (com.sun.tools.javac.tree.JCTree)10 CustomTree (com.redhat.ceylon.compiler.typechecker.tree.CustomTree)8 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)8 Type (com.redhat.ceylon.model.typechecker.model.Type)6 SpecifierOrInitializerExpression (com.redhat.ceylon.compiler.typechecker.tree.Tree.SpecifierOrInitializerExpression)5 Term (com.redhat.ceylon.compiler.typechecker.tree.Tree.Term)5 JCStatement (com.sun.tools.javac.tree.JCTree.JCStatement)4 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)4 JCBlock (com.sun.tools.javac.tree.JCTree.JCBlock)3 ArrayList (java.util.ArrayList)3 BoxingStrategy (com.redhat.ceylon.compiler.java.codegen.AbstractTransformer.BoxingStrategy)2 SyntheticName (com.redhat.ceylon.compiler.java.codegen.Naming.SyntheticName)2 LetExpression (com.redhat.ceylon.compiler.typechecker.tree.Tree.LetExpression)2 Variable (com.redhat.ceylon.compiler.typechecker.tree.Tree.Variable)2 CName (com.redhat.ceylon.compiler.java.codegen.Naming.CName)1 Substitution (com.redhat.ceylon.compiler.java.codegen.Naming.Substitution)1 SourceDeclarationVisitor (com.redhat.ceylon.compiler.java.loader.SourceDeclarationVisitor)1 PhasedUnit (com.redhat.ceylon.compiler.typechecker.context.PhasedUnit)1