use of org.eclipse.ceylon.compiler.typechecker.tree.Tree.Term in project ceylon by eclipse.
the class ExpressionTransformer method getIntegerLiteralPower.
/**
* Returns the literal value of the power in the given power expression,
* or null if the power is not an integer literal (or negation of an
* integer literal)
* @throws ErroneousException
*/
static java.lang.Number getIntegerLiteralPower(Tree.PowerOp op) throws ErroneousException {
java.lang.Number power;
Tree.Term term = unwrapExpressionUntilTerm(op.getRightTerm());
if (term instanceof Tree.NaturalLiteral) {
power = literalValue((Tree.NaturalLiteral) term);
} else if (term instanceof Tree.NegativeOp && ((Tree.NegativeOp) term).getTerm() instanceof Tree.NaturalLiteral) {
power = literalValue((Tree.NegativeOp) term);
} else {
power = null;
}
return power;
}
use of org.eclipse.ceylon.compiler.typechecker.tree.Tree.Term in project ceylon by eclipse.
the class ExpressionTransformer method transform.
// Postfix operator
public JCExpression transform(Tree.PostfixOperatorExpression expr) {
OperatorTranslation operator = Operators.getOperator(expr.getClass());
if (operator == null) {
return makeErroneous(expr, "compiler bug " + expr.getNodeType() + " is not yet supported");
}
OptimisationStrategy optimisationStrategy = operator.getUnOpOptimisationStrategy(expr, expr.getTerm(), this);
boolean canOptimise = optimisationStrategy.useJavaOperator();
// only fully optimise if we don't have to access the getter/setter
if (canOptimise && CodegenUtil.isDirectAccessVariable(expr.getTerm())) {
JCExpression term = transformExpression(expr.getTerm(), BoxingStrategy.UNBOXED, expr.getTypeModel(), EXPR_WIDEN_PRIM);
return at(expr).Unary(operator.javacOperator, term);
}
Tree.Term term = unwrapExpressionUntilTerm(expr.getTerm());
Type returnType = term.getTypeModel();
List<JCVariableDecl> decls = List.nil();
List<JCStatement> stats = List.nil();
JCExpression result = null;
// we can optimise that case a bit sometimes
boolean boxResult = !canOptimise;
// (let $tmp = attr; attr = $tmp.getSuccessor(); $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(expr);
// Type $tmp = 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, returnType);
JCVariableDecl tmpVar = make().VarDef(make().Modifiers(0), varName, exprType, getter);
decls = decls.prepend(tmpVar);
// attr = $tmp.getSuccessor()
JCExpression successor;
if (canOptimise) {
// use +1/-1 if we can optimise a bit
successor = make().Binary(operator == OperatorTranslation.UNARY_POSTFIX_INCREMENT ? JCTree.Tag.PLUS : JCTree.Tag.MINUS, make().Ident(varName), makeInteger(1));
successor = unAutoPromote(successor, returnType, expr.getSmall());
} else {
successor = make().Apply(null, makeSelect(make().Ident(varName), operator.getCeylonMethodName()), List.<JCExpression>nil());
// make sure the result is boxed if necessary, the result of successor/predecessor is always boxed
successor = boxUnboxIfNecessary(successor, true, term.getTypeModel(), CodegenUtil.getBoxingStrategy(term));
}
JCExpression assignment = makeAssignment(expr, term, transformAssignmentLhs(expr, term), successor);
stats = stats.prepend(at(expr).Exec(assignment));
// $tmp
result = make().Ident(varName);
} else if (term instanceof Tree.QualifiedMemberExpression) {
// e.attr++
// (let $tmpE = e, $tmpV = $tmpE.attr; $tmpE.attr = $tmpV.getSuccessor(); $tmpV;)
Tree.QualifiedMemberExpression qualified = (Tree.QualifiedMemberExpression) term;
boolean isSuper = isSuperOrSuperOf(qualified.getPrimary());
boolean isPackage = isPackageQualified(qualified);
// transform the primary, this will get us a boxed primary
JCExpression e = transformQualifiedMemberPrimary(qualified);
at(expr);
// 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 = $tmpE.attr
JCExpression attrType = makeJavaType(returnType, boxResult ? JT_NO_PRIMITIVES : 0);
Name varVName = naming.tempName("opV");
JCExpression getter;
if (isSuper) {
getter = transformMemberExpression(qualified, transformSuper(qualified), null);
} else if (isPackage) {
getter = transformMemberExpression(qualified, null, null);
} else {
getter = transformMemberExpression(qualified, make().Ident(varEName), null);
}
// make sure we box the results if necessary
getter = applyErasureAndBoxing(getter, term, boxResult ? BoxingStrategy.BOXED : BoxingStrategy.UNBOXED, returnType);
JCVariableDecl tmpVVar = make().VarDef(make().Modifiers(0), varVName, attrType, getter);
decls = decls.prepend(tmpVVar);
if (!isSuper && !isPackage) {
// define all the variables
decls = decls.prepend(tmpEVar);
}
// $tmpE.attr = $tmpV.getSuccessor()
JCExpression successor;
if (canOptimise) {
// use +1/-1 if we can optimise a bit
successor = make().Binary(operator == OperatorTranslation.UNARY_POSTFIX_INCREMENT ? JCTree.Tag.PLUS : JCTree.Tag.MINUS, make().Ident(varVName), makeInteger(1));
successor = unAutoPromote(successor, returnType, expr.getSmall());
} else {
successor = make().Apply(null, makeSelect(make().Ident(varVName), operator.getCeylonMethodName()), List.<JCExpression>nil());
// make sure the result is boxed if necessary, the result of successor/predecessor is always boxed
successor = boxUnboxIfNecessary(successor, true, term.getTypeModel(), CodegenUtil.getBoxingStrategy(term));
}
JCExpression assignment = makeAssignment(expr, term, qualifyLhs(expr, term, isSuper ? transformSuper(qualified) : make().Ident(varEName)), successor);
stats = stats.prepend(at(expr).Exec(assignment));
// $tmpV
result = make().Ident(varVName);
} else {
return makeErroneous(term, "compiler bug: " + term.getNodeType() + " is not supported yet");
}
return make().LetExpr(decls, stats, result);
}
use of org.eclipse.ceylon.compiler.typechecker.tree.Tree.Term in project ceylon by eclipse.
the class ExpressionTransformer method transformExpression.
JCExpression transformExpression(final Tree.Term expr, BoxingStrategy boxingStrategy, Type expectedType, int flags) {
if (expr == null) {
return null;
}
at(expr);
if (inStatement && boxingStrategy != BoxingStrategy.INDIFFERENT) {
// We're not directly inside the ExpressionStatement anymore
inStatement = false;
}
// Cope with things like ((expr))
// FIXME: shouldn't that be in the visitor?
Tree.Term term = expr;
while (term instanceof Tree.Expression) {
term = ((Tree.Expression) term).getTerm();
}
JCExpression result;
if (term instanceof Tree.IfExpression) {
flags |= EXPR_IS_NOT_BASE_MEMBER;
}
CeylonVisitor v = gen().visitor;
final ListBuffer<JCTree> prevDefs = v.defs;
final boolean prevInInitializer = v.inInitializer;
final ClassDefinitionBuilder prevClassBuilder = v.classBuilder;
final Type prevExpectedType = this.expectedType;
final boolean prevCoerced = this.coerced;
try {
v.defs = new ListBuffer<JCTree>();
v.inInitializer = false;
v.classBuilder = gen().current();
this.expectedType = expectedType;
this.coerced = (flags & EXPR_IS_COERCED) != 0;
term.visit(v);
if (v.hasResult()) {
result = v.getSingleResult();
if (result == null) {
throw new BugException(term, "visitor yielded multiple results");
}
} else {
throw new BugException(term, "visitor didn't yield any result");
}
} catch (BugException e) {
result = e.makeErroneous(this, expr);
} finally {
v.classBuilder = prevClassBuilder;
v.inInitializer = prevInInitializer;
v.defs = prevDefs;
this.coerced = prevCoerced;
this.expectedType = prevExpectedType;
}
if ((flags & EXPR_TARGET_ACCEPTS_NULL) == 0 && expectedType != null && hasUncheckedNulls(expr) && expectedType.isSubtypeOf(typeFact().getObjectType()) && !knownNullSafe(term)) {
result = utilInvocation().checkNull(result);
flags |= EXPR_HAS_NULL_CHECK_FENCE;
}
result = applyErasureAndBoxing(result, expr, boxingStrategy, expectedType, flags);
return result;
}
use of org.eclipse.ceylon.compiler.typechecker.tree.Tree.Term in project ceylon by eclipse.
the class ExpressionTransformer method transformOverridableUnaryOperator.
private JCExpression transformOverridableUnaryOperator(Tree.UnaryOperatorExpression op, Type expectedType) {
at(op);
Tree.Term term = op.getTerm();
OperatorTranslation operator = Operators.getOperator(op.getClass());
if (operator == null) {
return makeErroneous(op, "compiler bug: " + op.getClass() + " is an unhandled operator class");
}
JCExpression ret;
if (operator.getUnOpOptimisationStrategy(op, op.getTerm(), this).useJavaOperator()) {
// optimisation for unboxed types
JCExpression expr = transformExpression(term, BoxingStrategy.UNBOXED, expectedType, EXPR_WIDEN_PRIM);
// unary + is essentially a NOOP
if (operator == OperatorTranslation.UNARY_POSITIVE)
return expr;
ret = make().Unary(operator.javacOperator, expr);
ret = unAutoPromote(ret, op.getTypeModel(), op.getSmall());
} else {
if (operator == OperatorTranslation.UNARY_POSITIVE) {
// is the self type of Invertible, so use the type of op
return transformExpression(term, BoxingStrategy.BOXED, op.getTypeModel());
}
ret = make().Apply(null, makeSelect(transformExpression(term, BoxingStrategy.BOXED, expectedType), Naming.getGetterName(operator.getCeylonMethodName())), List.<JCExpression>nil());
}
return ret;
}
use of org.eclipse.ceylon.compiler.typechecker.tree.Tree.Term in project ceylon by eclipse.
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)'");
}
if (!isSpanOf(range, typeFact().getCharacterType()) && !isSpanOf(range, typeFact().getIntegerType())) {
return optimizationFailed(stmt, Optimization.SpanOpIteration, "The RangeOp doesn't produce a Range<Integer>/Range<Character>");
}
return increment == null ? new SpanOpIterationOptimization(stmt, range, increment) : new SpanOpWithStepIterationOptimization(stmt, range, increment);
}
Aggregations