use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement in project ceylon by eclipse.
the class CallableBuilder method unboundValueMemberReference.
/**
* Used for "static" value references. For example:
* <pre>
* value x = Integer.plus;
* value y = Foo.method;
* value z = Outer.Inner;
* </pre>
*/
public static CallableBuilder unboundValueMemberReference(CeylonTransformer gen, Tree.QualifiedMemberOrTypeExpression qmte, Type typeModel, final TypedDeclaration value, Type expectedType) {
CallBuilder callBuilder = CallBuilder.instance(gen);
Type qualifyingType = qmte.getTarget().getQualifyingType();
JCExpression target = gen.naming.makeUnquotedIdent(Unfix.$instance$);
target = gen.expressionGen().applyErasureAndBoxing(target, qmte.getPrimary().getTypeModel(), true, BoxingStrategy.BOXED, qualifyingType);
if (gen.expressionGen().isThrowableMessage(qmte)) {
callBuilder.invoke(gen.utilInvocation().throwableMessage());
callBuilder.argument(target);
} else if (gen.expressionGen().isThrowableSuppressed(qmte)) {
callBuilder.invoke(gen.utilInvocation().suppressedExceptions());
callBuilder.argument(target);
} else {
JCExpression memberName = gen.naming.makeQualifiedName(target, value, Naming.NA_GETTER | Naming.NA_MEMBER);
if (value instanceof FieldValue) {
callBuilder.fieldRead(memberName);
} else {
callBuilder.invoke(memberName);
}
}
JCExpression innerInvocation = callBuilder.build();
// use the return type since the value is actually applied
Type returnType = gen.getReturnTypeOfCallable(typeModel);
innerInvocation = gen.expressionGen().applyErasureAndBoxing(innerInvocation, returnType, // expression is a Callable
qmte.getTypeErased(), !CodegenUtil.isUnBoxed(value), BoxingStrategy.BOXED, returnType, 0);
ParameterList outerPl = new ParameterList();
Parameter instanceParameter = new Parameter();
instanceParameter.setName(Naming.name(Unfix.$instance$));
Value valueModel = new Value();
instanceParameter.setModel(valueModel);
Type accessType = gen.getParameterTypeOfCallable(typeModel, 0);
;
if (!value.isShared()) {
accessType = Decl.getPrivateAccessType(qmte);
}
valueModel.setName(instanceParameter.getName());
valueModel.setInitializerParameter(instanceParameter);
valueModel.setType(accessType);
valueModel.setUnboxed(false);
outerPl.getParameters().add(instanceParameter);
CallableBuilder outer = new CallableBuilder(gen, qmte, typeModel, outerPl);
outer.parameterTypes = outer.getParameterTypesFromParameterModels();
List<JCStatement> innerBody = List.<JCStatement>of(gen.make().Return(innerInvocation));
outer.useDefaultTransformation(innerBody);
outer.companionAccess = Decl.isPrivateAccessRequiringCompanion(qmte);
if (expectedType != null)
outer.checkForFunctionalInterface(expectedType);
return outer;
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement in project ceylon by eclipse.
the class CallableBuilder method unboundFunctionalMemberReference.
/**
* Used for "static" method or class references. For example:
* <pre>
* value x = Integer.plus;
* value y = Foo.method;
* value z = Outer.Inner;
* </pre>
*/
public static JCExpression unboundFunctionalMemberReference(CeylonTransformer gen, Tree.QualifiedMemberOrTypeExpression qmte, Type typeModel, final Functional methodClassOrCtor, Reference producedReference, Type expectedType) {
final ParameterList parameterList = methodClassOrCtor.getFirstParameterList();
Type type = typeModel;
JCExpression target;
boolean memberClassCtorRef = ModelUtil.getConstructor((Declaration) methodClassOrCtor) != null && !ModelUtil.getConstructedClass((Declaration) methodClassOrCtor).isToplevel() && qmte.getPrimary() instanceof Tree.QualifiedTypeExpression;
boolean hasOuter = !(Decl.isConstructor((Declaration) methodClassOrCtor) && gen.getNumParameterLists(typeModel) == 1);
if (!hasOuter) {
type = typeModel;
if (memberClassCtorRef) {
target = gen.naming.makeUnquotedIdent(Unfix.$instance$);
} else {
target = null;
}
} else {
type = gen.getReturnTypeOfCallable(type);
Type qualifyingType = qmte.getTarget().getQualifyingType();
target = gen.naming.makeUnquotedIdent(Unfix.$instance$);
target = gen.expressionGen().applyErasureAndBoxing(target, producedReference.getQualifyingType(), true, BoxingStrategy.BOXED, qualifyingType);
}
CallableBuilder inner = new CallableBuilder(gen, qmte, type, parameterList);
// FromParameterModels();
inner.parameterTypes = inner.getParameterTypesFromCallableModel();
if (hasOuter) {
inner.defaultValueCall = inner.new MemberReferenceDefaultValueCall(methodClassOrCtor);
}
CallBuilder callBuilder = CallBuilder.instance(gen);
Type accessType = gen.getParameterTypeOfCallable(typeModel, 0);
boolean needsCast = false;
if (Decl.isConstructor((Declaration) methodClassOrCtor)) {
Constructor ctor = ModelUtil.getConstructor((Declaration) methodClassOrCtor);
Class cls = ModelUtil.getConstructedClass(ctor);
if (Strategy.generateInstantiator(ctor)) {
needsCast = Strategy.isInstantiatorUntyped(ctor);
callBuilder.invoke(gen.naming.makeInstantiatorMethodName(target, cls));
} else if (Decl.isJavaArrayWith(ctor)) {
callBuilder.arrayWith(gen.getReturnTypeOfCallable(typeModel).getQualifyingType(), gen.makeJavaType(gen.getReturnTypeOfCallable(typeModel), JT_CLASS_NEW));
} else {
callBuilder.instantiate(gen.makeJavaType(gen.getReturnTypeOfCallable(typeModel), JT_CLASS_NEW));
if (!ctor.isShared()) {
accessType = Decl.getPrivateAccessType(qmte);
}
}
} else if (methodClassOrCtor instanceof Function && ((Function) methodClassOrCtor).isParameter()) {
callBuilder.invoke(gen.naming.makeQualifiedName(target, (Function) methodClassOrCtor, Naming.NA_MEMBER));
} else if (methodClassOrCtor instanceof Function) {
callBuilder.invoke(gen.naming.makeQualifiedName(target, (Function) methodClassOrCtor, Naming.NA_MEMBER));
if (!((TypedDeclaration) methodClassOrCtor).isShared()) {
accessType = Decl.getPrivateAccessType(qmte);
}
} else if (methodClassOrCtor instanceof Class) {
Class cls = (Class) methodClassOrCtor;
if (Strategy.generateInstantiator(cls)) {
callBuilder.invoke(gen.naming.makeInstantiatorMethodName(target, cls));
} else {
callBuilder.instantiate(new ExpressionAndType(target, null), gen.makeJavaType(cls.getType(), JT_CLASS_NEW | AbstractTransformer.JT_NON_QUALIFIED));
if (!cls.isShared()) {
accessType = Decl.getPrivateAccessType(qmte);
}
}
} else {
throw BugException.unhandledDeclarationCase((Declaration) methodClassOrCtor, qmte);
}
ListBuffer<ExpressionAndType> reified = new ListBuffer<ExpressionAndType>();
DirectInvocation.addReifiedArguments(gen, producedReference, reified);
for (ExpressionAndType reifiedArgument : reified) {
callBuilder.argument(reifiedArgument.expression);
}
if (Decl.isConstructor((Declaration) methodClassOrCtor) && !Decl.isDefaultConstructor(ModelUtil.getConstructor((Declaration) methodClassOrCtor)) && !Decl.isJavaArrayWith((Constructor) methodClassOrCtor)) {
// invoke the param class ctor
Constructor ctor = ModelUtil.getConstructor((Declaration) methodClassOrCtor);
callBuilder.argument(gen.naming.makeNamedConstructorName(ctor, false));
}
for (Parameter parameter : parameterList.getParameters()) {
callBuilder.argument(gen.naming.makeQuotedIdent(Naming.getAliasedParameterName(parameter)));
}
JCExpression innerInvocation = callBuilder.build();
if (needsCast) {
innerInvocation = gen.make().TypeCast(gen.makeJavaType(gen.getReturnTypeOfCallable(type)), innerInvocation);
}
// Need to worry about boxing for Function and FunctionalParameter
if (methodClassOrCtor instanceof TypedDeclaration && !Decl.isConstructor((Declaration) methodClassOrCtor)) {
// use the method return type since the function is actually applied
Type returnType = gen.getReturnTypeOfCallable(type);
innerInvocation = gen.expressionGen().applyErasureAndBoxing(innerInvocation, returnType, // expression is a Callable
CodegenUtil.hasTypeErased((TypedDeclaration) methodClassOrCtor), !CodegenUtil.isUnBoxed((TypedDeclaration) methodClassOrCtor), BoxingStrategy.BOXED, returnType, 0);
} else if (methodClassOrCtor instanceof Class && Strategy.isInstantiatorUntyped((Class) methodClassOrCtor)) {
// $new method declared to return Object, so needs typecast
innerInvocation = gen.make().TypeCast(gen.makeJavaType(((Class) methodClassOrCtor).getType()), innerInvocation);
}
List<JCStatement> innerBody = List.<JCStatement>of(gen.make().Return(innerInvocation));
inner.useDefaultTransformation(innerBody);
JCExpression callable = inner.build();
if (!hasOuter) {
if (memberClassCtorRef) {
;
JCVariableDecl def = gen.makeVar(Unfix.$instance$.toString(), gen.makeJavaType(((QualifiedMemberOrTypeExpression) qmte.getPrimary()).getPrimary().getTypeModel()), gen.expressionGen().transformQualifiedMemberPrimary(qmte));
return gen.make().LetExpr(def, callable);
}
return callable;
}
ParameterList outerPl = new ParameterList();
Parameter instanceParameter = new Parameter();
instanceParameter.setName(Naming.name(Unfix.$instance$));
Value valueModel = new Value();
instanceParameter.setModel(valueModel);
valueModel.setName(instanceParameter.getName());
valueModel.setInitializerParameter(instanceParameter);
valueModel.setType(accessType);
valueModel.setUnboxed(false);
outerPl.getParameters().add(instanceParameter);
CallableBuilder outer = new CallableBuilder(gen, qmte, typeModel, outerPl);
outer.parameterTypes = outer.getParameterTypesFromParameterModels();
List<JCStatement> outerBody = List.<JCStatement>of(gen.make().Return(callable));
outer.useDefaultTransformation(outerBody);
outer.companionAccess = Decl.isPrivateAccessRequiringCompanion(qmte);
if (expectedType != null)
outer.checkForFunctionalInterface(expectedType);
return outer.build();
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement in project ceylon by eclipse.
the class CallableBuilder method makeFunctionalInterfaceMethod.
public MethodDefinitionBuilder makeFunctionalInterfaceMethod() {
FunctionOrValue methodOrValue = (FunctionOrValue) functionalInterfaceMethod.getDeclaration();
MethodDefinitionBuilder callMethod = MethodDefinitionBuilder.method(gen, methodOrValue, 0);
callMethod.isOverride(true);
callMethod.modifiers(Flags.PUBLIC);
Type returnType = functionalInterfaceMethod.getType();
if (methodOrValue instanceof Value || !((Function) methodOrValue).isDeclaredVoid()) {
int flags = CodegenUtil.isUnBoxed(methodOrValue) ? 0 : JT_NO_PRIMITIVES;
callMethod.resultType(gen.makeJavaType(returnType, flags), null);
}
ListBuffer<JCExpression> args = new ListBuffer<>();
// this depends on how we're declared to Java
boolean turnedToRaw = gen.rawSupertype(functionalInterface, JT_EXTENDS | JT_CLASS_NEW);
boolean variadic = false;
if (methodOrValue instanceof Function) {
int index = 0;
java.util.List<Parameter> parameters = ((Function) methodOrValue).getFirstParameterList().getParameters();
for (int i = 0; i < parameters.size(); i++) {
Parameter param = parameters.get(i);
Parameter targetParam = paramLists.getParameters().get(i);
TypedReference typedParameter = functionalInterfaceMethod.getTypedParameter(param);
ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.systemParameter(gen, param.getName());
Type paramType = typedParameter.getType();
if (param.isSequenced()) {
paramType = gen.typeFact().getSequentialElementType(paramType);
variadic = true;
}
// This is very special-casey, but is required and I haven't found more subtle
if (turnedToRaw && gen.simplifyType(param.getType()).isTypeParameter()) {
paramType = gen.typeFact().getObjectType();
}
long flags = Flags.FINAL;
// that looks fishy, perhaps we need to call non-widening rules instead
JCExpression javaType = gen.makeJavaType(paramType, paramType.isRaw() ? AbstractTransformer.JT_RAW : 0);
if (param.isSequenced()) {
flags |= Flags.VARARGS;
javaType = gen.make().TypeArray(javaType);
}
pdb.type(new TransformedType(javaType));
pdb.modifiers(flags);
callMethod.parameter(pdb);
JCExpression arg;
if (param.isSequenced()) {
arg = gen.javaVariadicToSequential(paramType, param);
} else {
arg = gen.makeUnquotedIdent(param.getName());
Type argumentType = parameterTypes.get(index);
if (gen.isOptional(paramType) && argumentType.isSubtypeOf(gen.typeFact().getObjectType()) && !targetParam.getModel().hasUncheckedNullType()) {
arg = gen.utilInvocation().checkNull(arg);
}
Type simpleParamType = gen.simplifyType(paramType);
// make unboxed java strings pass for ceylon strings so we can box them
boolean unboxedString = gen.isJavaStringExactly(simpleParamType);
if (unboxedString)
simpleParamType = gen.typeFact().getStringType();
BoxingStrategy boxingStrategy = BoxingStrategy.BOXED;
// in rare cases we don't want boxes
if (unboxedString && gen.isJavaStringExactly(argumentType))
boxingStrategy = BoxingStrategy.UNBOXED;
arg = gen.expressionGen().applyErasureAndBoxing(arg, simpleParamType, !(CodegenUtil.isUnBoxed(param.getModel()) || unboxedString), boxingStrategy, argumentType);
}
args.append(arg);
index++;
}
} else {
// no-arg getter
}
String callMethodName;
if (variadic)
callMethodName = Naming.getCallableVariadicMethodName();
else
callMethodName = Naming.getCallableMethodName();
JCExpression call = gen.make().Apply(null, gen.makeUnquotedIdent(callMethodName), args.toList());
JCStatement body;
if (methodOrValue instanceof Function && ((Function) methodOrValue).isDeclaredVoid())
body = gen.make().Exec(call);
else {
Type callableReturnType = gen.getReturnTypeOfCallable(typeModel);
Type simpleReturnType = gen.simplifyType(returnType);
boolean unboxed = CodegenUtil.isUnBoxed(methodOrValue) || gen.isJavaStringExactly(simpleReturnType);
if (unboxed) {
call = gen.expressionGen().applyErasureAndBoxing(call, callableReturnType, true, BoxingStrategy.UNBOXED, returnType);
} else if (callableReturnType.isNull()) {
// if the callable returns null and the SAM does not, we need a cast
call = gen.expressionGen().applyErasureAndBoxing(call, callableReturnType, true, BoxingStrategy.INDIFFERENT, returnType);
}
body = gen.make().Return(call);
}
callMethod.body(body);
return callMethod;
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement in project ceylon by eclipse.
the class CallableBuilder method callableToFunctionalInterface.
public static JCExpression callableToFunctionalInterface(CeylonTransformer gen, final Tree.InvocationExpression node, ParameterList parameterList, Type expectedType, Type callableType, boolean useParameterTypesFromCallableModel, JCExpression primaryExpr) {
ListBuffer<JCStatement> letStmts = new ListBuffer<JCStatement>();
CallableBuilder cb = new CallableBuilder(gen, node, callableType, parameterList);
cb.parameterTypes = useParameterTypesFromCallableModel ? cb.getParameterTypesFromCallableModel() : cb.getParameterTypesFromParameterModels();
Naming.SyntheticName instanceFieldName;
boolean instanceFieldIsBoxed = true;
boolean prevCallableInv = gen.expressionGen().withinSyntheticClassBody(true);
try {
instanceFieldName = gen.naming.synthetic(Unfix.$instance$);
letStmts.add(gen.makeVar(Flags.FINAL, instanceFieldName, gen.makeJavaType(callableType), primaryExpr));
} finally {
gen.expressionGen().withinSyntheticClassBody(prevCallableInv);
}
CallableTransformation tx;
cb.defaultValueCall = new DefaultValueMethodTransformation() {
@Override
public JCExpression makeDefaultValueMethod(AbstractTransformer gen, Parameter defaultedParam, List<JCExpression> defaultMethodArgs) {
JCExpression fn = null;
return gen.make().Apply(null, fn, defaultMethodArgs);
}
};
if (cb.isVariadic) {
tx = cb.new VariadicCallableTransformation(cb.new CallMethodWithForwardedBody(instanceFieldName, instanceFieldIsBoxed, node, false, callableType));
} else {
tx = cb.new FixedArityCallableTransformation(cb.new CallMethodWithForwardedBody(instanceFieldName, instanceFieldIsBoxed, node, true, callableType), null);
}
cb.useTransformation(tx);
cb.checkForFunctionalInterface(expectedType);
return letStmts.isEmpty() ? cb.build() : gen.make().LetExpr(letStmts.toList(), cb.build());
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement in project ceylon by eclipse.
the class CeylonTransformer method transformAttributeGetter.
public JCExpression transformAttributeGetter(TypedDeclaration declarationModel, final JCExpression expression) {
final String attrName = declarationModel.getName();
final String attrClassName = Naming.getAttrClassName(declarationModel, 0);
JCBlock getterBlock = makeGetterBlock(expression);
// For everything else generate a getter/setter method
AttributeDefinitionBuilder builder = AttributeDefinitionBuilder.indirect(this, attrName, declarationModel, declarationModel.isToplevel()).getterBlock(getterBlock).immutable();
ClassDefinitionBuilder classBuilder = ClassDefinitionBuilder.klass(this, attrClassName, null, false);
List<JCTree> attr = builder.buildWithWrapperClass(classBuilder);
JCNewClass newExpr = makeNewClass(attrClassName, false, null);
JCExpression result = makeLetExpr(naming.temp(), List.<JCStatement>of((JCStatement) attr.get(0)), newExpr);
return result;
}
Aggregations