use of com.sun.tools.javac.tree.JCTree.JCStatement in project ceylon-compiler by ceylon.
the class ClassDefinitionBuilder method addRefineReifiedTypeParametersMethod.
public ClassDefinitionBuilder addRefineReifiedTypeParametersMethod(java.util.List<TypeParameter> typeParameterList) {
MethodDefinitionBuilder method = MethodDefinitionBuilder.systemMethod(gen, gen.naming.getRefineTypeParametersMethodName());
method.modifiers(PUBLIC);
method.ignoreModelAnnotations();
List<JCStatement> body = List.nil();
for (TypeParameter tp : typeParameterList) {
String descriptorName = gen.naming.getTypeArgumentDescriptorName(tp);
method.parameter(makeReifiedParameter(descriptorName));
body = body.prepend(gen.makeReifiedTypeParameterAssignment(tp));
}
method.body(body);
defs(method.build());
return this;
}
use of com.sun.tools.javac.tree.JCTree.JCStatement in project ceylon-compiler by ceylon.
the class ExpressionTransformer method transformSpreadOperator.
private JCExpression transformSpreadOperator(final Tree.QualifiedMemberOrTypeExpression expr, TermTransformer transformer) {
at(expr);
boolean spreadMethodReferenceOuter = !expr.equals(this.spreading) && !isWithinInvocation() && isCeylonCallableSubtype(expr.getTypeModel());
boolean spreadMethodReferenceInner = expr.equals(this.spreading) && isWithinInvocation();
Tree.QualifiedMemberOrTypeExpression oldSpreading = spreading;
if (spreadMethodReferenceOuter) {
spreading = expr;
}
try {
Naming.SyntheticName varBaseName = naming.alias("spread");
ListBuffer<JCStatement> letStmts = ListBuffer.<JCStatement>lb();
final Naming.SyntheticName srcIterableName;
if (spreadMethodReferenceInner) {
// use the var we initialized in the outer
srcIterableName = this.memberPrimary;
} else {
srcIterableName = varBaseName.suffixedBy(Suffix.$iterable$);
}
if (spreadMethodReferenceOuter) {
// if we're in the outer, note then name of the var for use in the inner.
this.memberPrimary = srcIterableName;
}
Naming.SyntheticName srcIteratorName = varBaseName.suffixedBy(Suffix.$iterator$);
Type srcElementType = expr.getTarget().getQualifyingType();
JCExpression srcIterableTypeExpr = makeJavaType(typeFact().getIterableType(srcElementType), JT_NO_PRIMITIVES);
JCExpression srcIterableExpr;
boolean isSuperOrSuperOf = false;
if (spreadMethodReferenceInner) {
srcIterableExpr = srcIterableName.makeIdent();
} else {
boolean isSuper = isSuper(expr.getPrimary());
isSuperOrSuperOf = isSuper || isSuperOf(expr.getPrimary());
if (isSuperOrSuperOf) {
// so we just refer to it later
if (isSuper) {
Declaration member = expr.getPrimary().getTypeModel().getDeclaration().getMember("iterator", null, false);
srcIterableExpr = transformSuper(expr, (TypeDeclaration) member.getContainer());
} else
srcIterableExpr = transformSuperOf(expr, expr.getPrimary(), "iterator");
} else {
srcIterableExpr = transformExpression(expr.getPrimary(), BoxingStrategy.BOXED, typeFact().getIterableType(srcElementType));
}
}
// do not capture the iterable for super invocations: see above
if (!spreadMethodReferenceInner && !isSuperOrSuperOf) {
JCVariableDecl srcIterable = null;
srcIterable = makeVar(Flags.FINAL, srcIterableName, srcIterableTypeExpr, srcIterableExpr);
letStmts.prepend(srcIterable);
}
Type resultElementType = expr.getTarget().getType();
Type resultAbsentType = typeFact().getIteratedAbsentType(expr.getPrimary().getTypeModel());
// private Iterator<srcElementType> iterator = srcIterableName.iterator();
JCVariableDecl srcIterator = makeVar(Flags.FINAL, srcIteratorName, makeJavaType(typeFact().getIteratorType(srcElementType)), make().Apply(null, // for super we do not capture it because we can't and it's constant anyways
naming.makeQualIdent(isSuperOrSuperOf ? srcIterableExpr : srcIterableName.makeIdent(), "iterator"), List.<JCExpression>nil()));
Naming.SyntheticName iteratorResultName = varBaseName.suffixedBy(Suffix.$element$);
/* public Object next() {
* Object result;
* if (!((result = iterator.next()) instanceof Finished)) {
* result = transformedMember(result);
* }
* return result;
*/
/* Any arguments in the member of the spread would get re-evaluated on each iteration
* so we need to shift them to the scope of the Let to ensure they're evaluated once.
*/
boolean aliasArguments = (transformer instanceof InvocationTermTransformer) && ((InvocationTermTransformer) transformer).invocation.getNode() instanceof Tree.InvocationExpression && ((Tree.InvocationExpression) ((InvocationTermTransformer) transformer).invocation.getNode()).getPositionalArgumentList() != null;
if (aliasArguments) {
((InvocationTermTransformer) transformer).callBuilder.argumentHandling(CallBuilder.CB_ALIAS_ARGS, varBaseName);
}
JCNewClass iterableClass;
boolean prevSyntheticClassBody = expressionGen().withinSyntheticClassBody(true);
try {
JCExpression transformedElement = applyErasureAndBoxing(iteratorResultName.makeIdent(), typeFact().getAnythingType(), CodegenUtil.hasTypeErased(expr.getPrimary()), true, BoxingStrategy.BOXED, srcElementType, 0);
transformedElement = transformMemberExpression(expr, transformedElement, transformer);
// be handled by the previous recursion
if (spreadMethodReferenceOuter) {
return make().LetExpr(letStmts.toList(), transformedElement);
}
transformedElement = applyErasureAndBoxing(transformedElement, resultElementType, // not necessarily of the applied member
expr.getTarget().getDeclaration() instanceof TypedDeclaration ? CodegenUtil.hasTypeErased((TypedDeclaration) expr.getTarget().getDeclaration()) : false, !CodegenUtil.isUnBoxed(expr), BoxingStrategy.BOXED, resultElementType, 0);
MethodDefinitionBuilder nextMdb = MethodDefinitionBuilder.systemMethod(this, "next");
nextMdb.isOverride(true);
nextMdb.annotationFlags(Annotations.IGNORE);
nextMdb.modifiers(Flags.PUBLIC | Flags.FINAL);
nextMdb.resultType(null, make().Type(syms().objectType));
nextMdb.body(List.of(makeVar(iteratorResultName, make().Type(syms().objectType), null), make().If(make().Unary(JCTree.NOT, make().TypeTest(make().Assign(iteratorResultName.makeIdent(), make().Apply(null, naming.makeQualIdent(srcIteratorName.makeIdent(), "next"), List.<JCExpression>nil())), make().Type(syms().ceylonFinishedType))), make().Block(0, List.<JCStatement>of(make().Exec(make().Assign(iteratorResultName.makeIdent(), transformedElement)))), null), make().Return(iteratorResultName.makeIdent())));
JCMethodDecl nextMethod = nextMdb.build();
// new AbstractIterator()
JCNewClass iteratorClass = make().NewClass(null, null, make().TypeApply(make().QualIdent(syms().ceylonAbstractIteratorType.tsym), List.of(makeJavaType(resultElementType, JT_TYPE_ARGUMENT))), List.of(makeReifiedTypeArgument(resultElementType)), make().AnonymousClassDef(make().Modifiers(0), List.of(srcIterator, nextMethod)));
MethodDefinitionBuilder iteratorMdb = MethodDefinitionBuilder.systemMethod(this, "iterator");
iteratorMdb.isOverride(true);
iteratorMdb.annotationFlags(Annotations.IGNORE);
iteratorMdb.modifiers(Flags.PUBLIC | Flags.FINAL);
iteratorMdb.resultType(null, makeJavaType(typeFact().getIteratorType(resultElementType)));
iteratorMdb.body(make().Return(iteratorClass));
// new AbstractIterable()
iterableClass = make().NewClass(null, null, make().TypeApply(make().QualIdent(syms().ceylonAbstractIterableType.tsym), List.of(makeJavaType(resultElementType, JT_TYPE_ARGUMENT), makeJavaType(resultAbsentType, JT_TYPE_ARGUMENT))), List.of(makeReifiedTypeArgument(resultElementType), makeReifiedTypeArgument(resultAbsentType)), make().AnonymousClassDef(make().Modifiers(0), List.<JCTree>of(iteratorMdb.build())));
} finally {
expressionGen().withinSyntheticClassBody(prevSyntheticClassBody);
}
if (aliasArguments) {
letStmts = letStmts.appendList(((InvocationTermTransformer) transformer).callBuilder.getStatements());
}
JCMethodInvocation result = make().Apply(null, naming.makeQualIdent(iterableClass, "sequence"), List.<JCExpression>nil());
JCExpression spread = letStmts.isEmpty() ? result : make().LetExpr(letStmts.toList(), result);
// Do we *statically* know the result must be a Sequence
final boolean primaryIsSequence = typeFact().isNonemptyIterableType(expr.getPrimary().getTypeModel());
Type returnElementType = expr.getTarget().getType();
if (primaryIsSequence) {
int flags = EXPR_DOWN_CAST;
spread = applyErasureAndBoxing(spread, typeFact().getSequentialType(returnElementType), false, true, BoxingStrategy.BOXED, primaryIsSequence ? typeFact().getSequenceType(returnElementType) : typeFact().getSequentialType(returnElementType), flags);
}
return spread;
} finally {
spreading = oldSpreading;
}
}
use of com.sun.tools.javac.tree.JCTree.JCStatement in project ceylon-compiler by ceylon.
the class ExpressionTransformer method transformAssignAndReturnOperation.
private JCExpression transformAssignAndReturnOperation(Node operator, Tree.Term term, boolean boxResult, Type valueType, Type returnType, AssignAndReturnOperationFactory factory) {
List<JCVariableDecl> decls = List.nil();
List<JCStatement> stats = List.nil();
JCExpression result = null;
// (let $tmp = OP(attr); attr = $tmp; $tmp)
if (term instanceof Tree.BaseMemberExpression || // special case for java statics Foo.attr where Foo does not need to be evaluated
(term instanceof Tree.QualifiedMemberExpression && ((Tree.QualifiedMemberExpression) term).getStaticMethodReference())) {
JCExpression getter;
if (term instanceof Tree.BaseMemberExpression)
getter = transform((Tree.BaseMemberExpression) term, null);
else
getter = transformMemberExpression((Tree.QualifiedMemberExpression) term, null, null);
at(operator);
// Type $tmp = OP(attr);
JCExpression exprType = makeJavaType(returnType, boxResult ? JT_NO_PRIMITIVES : 0);
Name varName = naming.tempName("op");
// make sure we box the results if necessary
getter = applyErasureAndBoxing(getter, term, boxResult ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, valueType);
JCExpression newValue = factory.getNewValue(getter);
// no need to box/unbox here since newValue and $tmpV share the same boxing type
JCVariableDecl tmpVar = make().VarDef(make().Modifiers(0), varName, exprType, newValue);
decls = decls.prepend(tmpVar);
// attr = $tmp
// make sure the result is unboxed if necessary, $tmp may be boxed
JCExpression value = make().Ident(varName);
BoxingStrategy boxingStrategy = CodegenUtil.getBoxingStrategy(term);
value = applyErasureAndBoxing(value, returnType, boxResult, boxingStrategy, valueType);
JCExpression assignment = transformAssignment(operator, term, value);
stats = stats.prepend(at(operator).Exec(assignment));
// $tmp
// return, with the box type we asked for
result = make().Ident(varName);
} else if (term instanceof Tree.QualifiedMemberExpression) {
// e.attr
// (let $tmpE = e, $tmpV = OP($tmpE.attr); $tmpE.attr = $tmpV; $tmpV;)
Tree.QualifiedMemberExpression qualified = (Tree.QualifiedMemberExpression) term;
boolean isSuper = isSuperOrSuperOf(qualified.getPrimary());
// transform the primary, this will get us a boxed primary
JCExpression e = transformQualifiedMemberPrimary(qualified);
at(operator);
// Type $tmpE = e
JCExpression exprType = makeJavaType(qualified.getTarget().getQualifyingType(), JT_NO_PRIMITIVES);
Name varEName = naming.tempName("opE");
JCVariableDecl tmpEVar = make().VarDef(make().Modifiers(0), varEName, exprType, e);
// Type $tmpV = OP($tmpE.attr)
JCExpression attrType = makeJavaType(returnType, boxResult ? JT_NO_PRIMITIVES : 0);
Name varVName = naming.tempName("opV");
JCExpression getter = transformMemberExpression(qualified, isSuper ? transformSuper(qualified) : make().Ident(varEName), null);
// make sure we box the results if necessary
getter = applyErasureAndBoxing(getter, term, boxResult ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, valueType);
JCExpression newValue = factory.getNewValue(getter);
// no need to box/unbox here since newValue and $tmpV share the same boxing type
JCVariableDecl tmpVVar = make().VarDef(make().Modifiers(0), varVName, attrType, newValue);
// define all the variables
decls = decls.prepend(tmpVVar);
if (!isSuper) {
decls = decls.prepend(tmpEVar);
}
// $tmpE.attr = $tmpV
// make sure $tmpV is unboxed if necessary
JCExpression value = make().Ident(varVName);
BoxingStrategy boxingStrategy = CodegenUtil.getBoxingStrategy(term);
value = applyErasureAndBoxing(value, returnType, boxResult, boxingStrategy, valueType);
JCExpression assignment = transformAssignment(operator, term, isSuper ? transformSuper(qualified) : make().Ident(varEName), value);
stats = stats.prepend(at(operator).Exec(assignment));
// $tmpV
// return, with the box type we asked for
result = make().Ident(varVName);
} else {
return makeErroneous(operator, "compiler bug: " + term.getNodeType() + " is not a supported assign and return operator");
}
return make().LetExpr(decls, stats, result);
}
use of com.sun.tools.javac.tree.JCTree.JCStatement in project ceylon-compiler by ceylon.
the class ExpressionTransformer method transformIf.
// this one trusts the expected type
private JCExpression transformIf(Tree.IfExpression op, Type expectedType) {
String tmpVar = naming.newTemp("ifResult");
Tree.Expression thenPart = op.getIfClause().getExpression();
Tree.Expression elsePart = op.getElseClause() != null ? op.getElseClause().getExpression() : null;
Tree.Variable elseVar = op.getElseClause() != null ? op.getElseClause().getVariable() : null;
java.util.List<Tree.Condition> conditions = op.getIfClause().getConditionList().getConditions();
List<JCStatement> statements = statementGen().transformIf(conditions, thenPart, elseVar, elsePart, tmpVar, op, expectedType);
at(op);
// use the op model for the variable, not expected type, because expected type may be optional, where op
// says not optional (even in case of java interop which may return null), so we allow null values in j.l.String (unboxed)
// because the caller will insert the null check if the expected type is optional
JCExpression vartype = makeJavaType(op.getTypeModel(), CodegenUtil.getBoxingStrategy(op) == BoxingStrategy.UNBOXED ? 0 : JT_NO_PRIMITIVES);
return make().LetExpr(make().VarDef(make().Modifiers(0), names().fromString(tmpVar), vartype, null), statements, makeUnquotedIdent(tmpVar));
}
use of com.sun.tools.javac.tree.JCTree.JCStatement in project ceylon-compiler by ceylon.
the class ExpressionTransformer method transform.
public JCExpression transform(Tree.WithinOp op) {
Tree.Term middleTerm = op.getTerm();
Tree.Bound lowerBound = op.getLowerBound();
OperatorTranslation lowerOp = Operators.getOperator(lowerBound instanceof Tree.OpenBound ? Tree.SmallerOp.class : Tree.SmallAsOp.class);
Tree.Term lowerTerm = lowerBound.getTerm();
Tree.Bound upperBound = op.getUpperBound();
OperatorTranslation upperOp = Operators.getOperator(upperBound instanceof Tree.OpenBound ? Tree.SmallerOp.class : Tree.SmallAsOp.class);
Tree.Term upperTerm = upperBound.getTerm();
Type middleType = getComparableType(middleTerm);
Type lowerType = getComparableType(lowerTerm);
Type upperType = getComparableType(upperTerm);
// If any of the terms is optimizable, then use optimized
OptimisationStrategy opt;
boolean optimizeLower = lowerOp.isTermOptimisable(lowerTerm, lowerType, this) == OptimisationStrategy.OPTIMISE || lowerOp.isTermOptimisable(middleTerm, middleType, this) == OptimisationStrategy.OPTIMISE;
boolean optimizeUpper = upperOp.isTermOptimisable(middleTerm, middleType, this) == OptimisationStrategy.OPTIMISE || upperOp.isTermOptimisable(upperTerm, upperType, this) == OptimisationStrategy.OPTIMISE;
if ((lowerType.isExactly(middleType) && middleType.isExactly(upperType) && (optimizeLower || // if all same type and any optimizable
optimizeUpper)) || (// otherwise onle if all optimizable
optimizeLower && optimizeUpper)) {
opt = OptimisationStrategy.OPTIMISE;
} else {
opt = OptimisationStrategy.NONE;
}
SyntheticName middleName = naming.alias("middle");
List<JCStatement> vars = List.<JCStatement>of(makeVar(middleName, makeJavaType(middleType, opt.getBoxingStrategy() == BoxingStrategy.UNBOXED ? 0 : JT_NO_PRIMITIVES), transformExpression(middleTerm, opt.getBoxingStrategy(), middleType)));
JCExpression lower = transformBound(middleName, middleType, lowerType, lowerOp, opt, middleTerm, lowerBound, false);
JCExpression upper = transformBound(middleName, middleType, upperType, upperOp, opt, middleTerm, upperBound, true);
at(op);
OperatorTranslation andOp = Operators.getOperator(Tree.AndOp.class);
OptimisationStrategy optimisationStrategy = OptimisationStrategy.OPTIMISE;
return make().LetExpr(vars, transformOverridableBinaryOperator(andOp, optimisationStrategy, lower, upper, null, null, op.getTypeModel()));
}
Aggregations