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;
}
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;
}
}
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;
}
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;
}
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);
}
Aggregations