use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree in project ceylon by eclipse.
the class AbstractTransformer method makeLazyIterable.
/**
* Makes a lazy iterable literal, for a sequenced argument to a named invocation
* (<code>f{foo=""; expr1, expr2, *expr3}</code>) or
* for an iterable instantiation (<code>{expr1, expr2, *expr3}</code>)
*/
JCExpression makeLazyIterable(Tree.SequencedArgument sequencedArgument, Type seqElemType, Type absentType, int flags) {
java.util.List<PositionalArgument> list = sequencedArgument.getPositionalArguments();
int i = 0;
ListBuffer<JCStatement> returns = new ListBuffer<JCStatement>();
boolean spread = false;
boolean old = expressionGen().withinSyntheticClassBody(true);
try {
for (Tree.PositionalArgument arg : list) {
at(arg);
JCExpression jcExpression;
// last expression can be an Iterable<seqElemType>
if (arg instanceof Tree.SpreadArgument || arg instanceof Tree.Comprehension) {
// make sure we only have spread/comprehension as last
if (i != list.size() - 1) {
jcExpression = makeErroneous(arg, "compiler bug: spread or comprehension argument is not last in sequence literal");
} else {
spread = true;
jcExpression = transformSpreadOrComprehension(arg, seqElemType);
}
} else if (arg instanceof Tree.ListedArgument) {
Tree.Expression expr = ((Tree.ListedArgument) arg).getExpression();
// always boxed since we stuff them into a sequence
jcExpression = expressionGen().transformExpression(expr, BoxingStrategy.BOXED, seqElemType);
} else {
jcExpression = makeErroneous(arg, "compiler bug: " + arg.getNodeType() + " is not a supported sequenced argument");
}
at(arg);
// the last iterable goes first if spread
returns.add(make().Return(jcExpression));
i++;
}
at(sequencedArgument);
if (Strategy.preferLazySwitchingIterable(sequencedArgument.getPositionalArguments())) {
// use a LazySwitchingIterable
MethodDefinitionBuilder mdb = MethodDefinitionBuilder.systemMethod(this, Unfix.$evaluate$.toString());
mdb.isOverride(true);
mdb.modifiers(PROTECTED | FINAL);
mdb.resultType(new TransformedType(make().Type(syms().objectType)));
mdb.parameter(ParameterDefinitionBuilder.systemParameter(this, Unfix.$index$.toString()).type(new TransformedType(make().Type(syms().intType))));
JCSwitch swtch;
try (SavedPosition sp = noPosition()) {
ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
i = 0;
for (JCStatement e : returns) {
cases.add(make().Case(make().Literal(i++), List.<JCStatement>of(e)));
}
cases.add(make().Case(null, List.<JCStatement>of(make().Return(makeNull()))));
swtch = make().Switch(naming.makeUnquotedIdent(Unfix.$index$), cases.toList());
}
mdb.body(swtch);
return at(sequencedArgument).NewClass(null, // of(makeJavaType(seqElemType), makeJavaType(absentType)),
List.<JCExpression>nil(), make().TypeApply(make().QualIdent(syms.ceylonLazyIterableType.tsym), List.<JCExpression>of(makeJavaType(seqElemType, JT_TYPE_ARGUMENT), makeJavaType(absentType, JT_TYPE_ARGUMENT))), // td,
List.of(// td,
makeReifiedTypeArgument(seqElemType), // td
makeReifiedTypeArgument(absentType), // numMethods
make().Literal(list.size()), // spread),
make().Literal(spread)), make().AnonymousClassDef(make().Modifiers(FINAL), List.<JCTree>of(mdb.build())));
} else {
ListBuffer<JCTree> methods = new ListBuffer<JCTree>();
// generate a method for each expression in the iterable
MethodDefinitionBuilder mdb;
i = 0;
for (JCStatement expr : returns) {
mdb = MethodDefinitionBuilder.systemMethod(this, "$" + i);
i++;
mdb.modifiers(PRIVATE | FINAL);
mdb.resultType(new TransformedType(make().Type(syms().objectType)));
mdb.body(expr);
methods.add(mdb.build());
}
// the $evaluate method switches between them
mdb = MethodDefinitionBuilder.systemMethod(this, Unfix.$evaluate$.toString());
mdb.isOverride(true);
mdb.modifiers(PROTECTED | FINAL);
mdb.resultType(new TransformedType(make().Type(syms().objectType)));
mdb.parameter(ParameterDefinitionBuilder.systemParameter(this, Unfix.$index$.toString()).type(new TransformedType(make().Type(syms().intType))));
JCSwitch swtch;
try (SavedPosition sp = noPosition()) {
ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
for (i = 0; i < returns.size(); i++) {
cases.add(make().Case(make().Literal(i), List.<JCStatement>of(make().Return(make().Apply(null, naming.makeUnquotedIdent("$" + i), List.<JCExpression>nil())))));
}
cases.add(make().Case(null, List.<JCStatement>of(make().Return(makeNull()))));
swtch = make().Switch(naming.makeUnquotedIdent(Unfix.$index$), cases.toList());
}
mdb.body(swtch);
return at(sequencedArgument).NewClass(null, // of(makeJavaType(seqElemType), makeJavaType(absentType)),
List.<JCExpression>nil(), make().TypeApply(make().QualIdent(syms.ceylonLazyIterableType.tsym), List.<JCExpression>of(makeJavaType(seqElemType, JT_TYPE_ARGUMENT), makeJavaType(absentType, JT_TYPE_ARGUMENT))), // td,
List.of(// td,
makeReifiedTypeArgument(seqElemType), // td
makeReifiedTypeArgument(absentType), // numMethods
make().Literal(list.size()), // spread),
make().Literal(spread)), make().AnonymousClassDef(make().Modifiers(FINAL), methods.toList().prepend(mdb.build())));
}
} finally {
expressionGen().withinSyntheticClassBody(old);
}
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree in project ceylon by eclipse.
the class CallableBuilder method build.
public JCExpression build() {
// Generate a subclass of Callable
ListBuffer<JCTree> classBody = new ListBuffer<JCTree>();
gen.at(node);
if (parameterDefaultValueMethods != null) {
for (MethodDefinitionBuilder mdb : parameterDefaultValueMethods) {
classBody.append(mdb.build());
}
}
transformation.appendMethods(classBody);
gen.at(node);
JCClassDecl classDef = gen.make().AnonymousClassDef(gen.make().Modifiers(0, annotations != null ? annotations : List.<JCAnnotation>nil()), classBody.toList());
int variadicIndex = isVariadic ? numParams - 1 : -1;
Type callableType;
if (typeModel.isTypeConstructor()) {
callableType = typeModel.getDeclaration().getExtendedType();
} else {
callableType = typeModel;
}
JCNewClass callableInstance;
if (functionalInterface == null) {
callableInstance = gen.at(node).NewClass(null, null, gen.makeJavaType(callableType, JT_EXTENDS | JT_CLASS_NEW), List.<JCExpression>of(gen.makeReifiedTypeArgument(callableType.getTypeArgumentList().get(0)), gen.makeReifiedTypeArgument(callableType.getTypeArgumentList().get(1)), gen.make().Literal(callableType.asString(true)), gen.make().TypeCast(gen.syms().shortType, gen.makeInteger(variadicIndex))), classDef);
} else {
callableInstance = gen.make().NewClass(null, null, gen.makeJavaType(functionalInterface, JT_EXTENDS | JT_CLASS_NEW), List.<JCExpression>nil(), classDef);
}
JCExpression result;
if (typeModel.isTypeConstructor()) {
result = buildTypeConstructor(callableType, callableInstance);
} else {
result = callableInstance;
}
gen.at(null);
if (instanceSubstitution != null) {
instanceSubstitution.close();
}
return result;
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree in project ceylon by eclipse.
the class ClassTransformer method transformObject.
private List<JCTree> transformObject(Node def, Tree.Declaration annotated, Tree.SatisfiedTypes satisfiesTypes, Value model, Class klass, ClassDefinitionBuilder containingClassBuilder, boolean makeLocalInstance) {
naming.clearSubstitutions(klass);
String name = klass.getName();
String javaClassName = Naming.quoteClassName(name);
ClassDefinitionBuilder objectClassBuilder = ClassDefinitionBuilder.object(this, javaClassName, name, Decl.isLocal(klass)).forDefinition(klass);
if (Strategy.introduceJavaIoSerializable(klass, typeFact().getJavaIoSerializable())) {
objectClassBuilder.introduce(make().QualIdent(syms().serializableType.tsym));
if (def instanceof Tree.ObjectDefinition && klass.isMember() && (ModelUtil.isCaptured(klass) || model.isCaptured())) {
addWriteReplace(klass, objectClassBuilder);
}
}
makeReadResolve(def, objectClassBuilder, klass, model);
// Make sure top types satisfy reified type
addReifiedTypeInterface(objectClassBuilder, klass);
if (supportsReifiedAlias(klass))
objectClassBuilder.reifiedAlias(klass.getType());
CeylonVisitor visitor = gen().visitor;
final ListBuffer<JCTree> prevDefs = visitor.defs;
final boolean prevInInitializer = visitor.inInitializer;
final ClassDefinitionBuilder prevClassBuilder = visitor.classBuilder;
List<JCStatement> childDefs;
try {
visitor.defs = new ListBuffer<JCTree>();
visitor.inInitializer = true;
visitor.classBuilder = objectClassBuilder;
def.visitChildren(visitor);
childDefs = (List<JCStatement>) visitor.getResult().toList();
} finally {
visitor.classBuilder = prevClassBuilder;
visitor.inInitializer = prevInInitializer;
visitor.defs = prevDefs;
naming.closeScopedSubstitutions(def.getScope());
}
addMissingUnrefinedMembers(def, klass, objectClassBuilder);
satisfaction(satisfiesTypes, klass, objectClassBuilder);
serialization(klass, objectClassBuilder);
if (model != null && model.isToplevel() && def instanceof Tree.ObjectDefinition) {
// generate a field and getter
AttributeDefinitionBuilder builder = AttributeDefinitionBuilder.wrapped(this, model.getName(), model, true, null).userAnnotations(makeAtIgnore()).userAnnotationsSetter(makeAtIgnore()).immutable().initialValue(makeNewClass(naming.makeName(model, Naming.NA_FQ | Naming.NA_WRAPPER)), BoxingStrategy.BOXED).is(PUBLIC, klass.isShared()).is(STATIC, true);
if (annotated != null) {
builder.fieldAnnotations(expressionGen().transformAnnotations(OutputElement.FIELD, annotated));
builder.userAnnotations(expressionGen().transformAnnotations(OutputElement.GETTER, annotated));
}
objectClassBuilder.defs(builder.build());
}
if (annotated != null) {
objectClassBuilder.annotations(expressionGen().transformAnnotations(OutputElement.TYPE, annotated));
objectClassBuilder.getInitBuilder().userAnnotations(expressionGen().transformAnnotations(OutputElement.CONSTRUCTOR, annotated));
}
// make sure we set the container in case we move it out
addAtContainer(objectClassBuilder, klass);
objectClassBuilder.annotations(makeAtObject()).satisfies(klass.getSatisfiedTypes()).defs(childDefs);
objectClassBuilder.getInitBuilder().modifiers(PRIVATE);
objectClassBuilder.addGetTypeMethod(klass.getType());
if (model != null)
objectClassBuilder.modelAnnotations(model.getAnnotations()).modifiers(modifierTransformation().object(model));
at(def);
List<JCTree> result = objectClassBuilder.build();
if (makeLocalInstance && !model.isStatic()) {
if (model.isSelfCaptured()) {
// if it's captured we need to box it and define the var before the class, so it can access it
JCNewClass newInstance = makeNewClass(objectClassBuilder.getClassName(), false, null);
JCFieldAccess setter = naming.makeSelect(Naming.getLocalValueName(model), Naming.getSetterName(model));
JCStatement assign = make().Exec(make().Assign(setter, newInstance));
result = result.prepend(assign);
JCVariableDecl localDecl = makeVariableBoxDecl(null, model);
result = result.prepend(localDecl);
} else {
// not captured, we can define the var after the class
JCVariableDecl localDecl = makeLocalIdentityInstance(name, objectClassBuilder.getClassName(), false);
result = result.append(localDecl);
}
} else if (model != null && model.isClassOrInterfaceMember()) {
boolean generateGetter = ModelUtil.isCaptured(model);
JCExpression type = makeJavaType(klass.getType());
if (generateGetter) {
int modifiers = TRANSIENT | PRIVATE | (model.isStatic() ? STATIC : 0);
JCExpression initialValue = makeNull();
containingClassBuilder.field(modifiers, name, type, initialValue, false);
AttributeDefinitionBuilder getter = AttributeDefinitionBuilder.getter(this, name, model).modifiers(modifierTransformation().getterSetter(model, false));
if (def instanceof Tree.ObjectDefinition) {
getter.userAnnotations(expressionGen().transformAnnotations(OutputElement.GETTER, ((Tree.ObjectDefinition) def)));
}
ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
stmts.add(make().If(make().Binary(JCTree.Tag.EQ, naming.makeUnquotedIdent(Naming.quoteFieldName(name)), makeNull()), make().Exec(make().Assign(naming.makeUnquotedIdent(Naming.quoteFieldName(name)), makeNewClass(makeJavaType(klass.getType()), null))), null));
stmts.add(make().Return(naming.makeUnquotedIdent(Naming.quoteFieldName(name))));
getter.getterBlock(make().Block(0, stmts.toList()));
result = result.appendList(getter.build());
} else {
int modifiers = FINAL | (model.isStatic() ? STATIC : 0);
JCExpression initialValue = makeNewClass(makeJavaType(klass.getType()), null);
containingClassBuilder.field(modifiers, name, type, initialValue, true);
}
}
return result;
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree in project ceylon by eclipse.
the class ClassTransformer method transform.
public List<JCTree> transform(final Tree.ClassOrInterface def) {
final ClassOrInterface model = def.getDeclarationModel();
if (model.isToplevel() && isEe(model)) {
replaceModifierTransformation(new EeModifierTransformation());
}
// in that case
if (model.isAlias() && Decl.isAncestorLocal(model))
return List.nil();
naming.clearSubstitutions(model);
final String javaClassName;
String ceylonClassName = def.getIdentifier().getText();
if (def instanceof Tree.AnyInterface) {
javaClassName = naming.makeTypeDeclarationName(model, QUALIFIED).replaceFirst(".*\\.", "");
} else {
javaClassName = Naming.quoteClassName(ceylonClassName);
}
ClassDefinitionBuilder instantiatorImplCb;
ClassDefinitionBuilder instantiatorDeclCb;
if (model.isInterfaceMember()) {
instantiatorImplCb = gen().current().getCompanionBuilder((Interface) model.getContainer());
instantiatorDeclCb = gen().current();
} else {
instantiatorImplCb = gen().current();
instantiatorDeclCb = null;
}
ClassDefinitionBuilder classBuilder = ClassDefinitionBuilder.klass(this, javaClassName, ceylonClassName, Decl.isLocal(model)).forDefinition(model).hasDelegatingConstructors(CodegenUtil.hasDelegatingConstructors(def));
classBuilder.getInitBuilder().deprecated(model.isDeprecated());
// Very special case for Anything
if (model.isAnything()) {
classBuilder.extending(model.getType(), null);
}
if (def instanceof Tree.AnyClass) {
classBuilder.getInitBuilder().modifiers(modifierTransformation().constructor(model));
Tree.AnyClass classDef = (Tree.AnyClass) def;
Class cls = classDef.getDeclarationModel();
// Member classes need a instantiator method
boolean generateInstantiator = Strategy.generateInstantiator(cls);
if (!cls.hasConstructors()) {
classBuilder.getInitBuilder().userAnnotations(expressionGen().transformAnnotations(OutputElement.CONSTRUCTOR, def));
}
if (generateInstantiator && !cls.hasConstructors() && !cls.hasEnumerated()) {
if (!cls.isStatic()) {
classBuilder.getInitBuilder().modifiers(PROTECTED);
}
generateInstantiators(classBuilder, cls, null, instantiatorDeclCb, instantiatorImplCb, classDef, classDef.getParameterList());
}
classBuilder.annotations(expressionGen().transformAnnotations(OutputElement.TYPE, def));
if (def instanceof Tree.ClassDefinition) {
transformClass((Tree.ClassDefinition) def, cls, classBuilder, classDef.getParameterList(), generateInstantiator, instantiatorDeclCb, instantiatorImplCb);
} else {
// class alias
classBuilder.getInitBuilder().modifiers(PRIVATE);
transformClassAlias((Tree.ClassDeclaration) def, classBuilder);
}
addMissingUnrefinedMembers(def, cls, classBuilder);
}
if (def instanceof Tree.AnyInterface) {
classBuilder.annotations(expressionGen().transformAnnotations(OutputElement.TYPE, def));
if (def instanceof Tree.InterfaceDefinition) {
transformInterface(def, (Interface) model, classBuilder);
} else {
// interface alias
classBuilder.annotations(makeAtAlias(model.getExtendedType(), null));
classBuilder.isAlias(true);
}
classBuilder.isDynamic(model.isDynamic());
}
// make sure we set the container in case we move it out
addAtContainer(classBuilder, model);
transformTypeParameters(classBuilder, model);
// Transform the class/interface members
List<JCStatement> childDefs = visitClassOrInterfaceDefinition(def, classBuilder);
// everything else is synthetic
at(null);
TransformationPlan plan = errors().hasDeclarationError(def);
if (plan instanceof ThrowerCatchallConstructor) {
classBuilder.broken();
MethodDefinitionBuilder initBuilder = classBuilder.noInitConstructor().addConstructor(model.isDeprecated());
initBuilder.body(statementGen().makeThrowUnresolvedCompilationError(plan.getErrorMessage().getMessage()));
// Although we have the class pl which we could use we don't know
// that it won't collide with the default named constructor's pl
// which would cause a javac error about two constructors with the same sig
// so we generate a Object... here. There's still a risk of collision though
// when the default constructor has pl (ObjectArray).
ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.implicitParameter(this, "ignored");
pdb.modifiers(VARARGS);
pdb.type(new TransformedType(make().TypeArray(make().Type(syms().objectType))));
initBuilder.parameter(pdb);
} else if (plan instanceof PrivateConstructorOnly) {
classBuilder.broken();
MethodDefinitionBuilder initBuilder = classBuilder.noInitConstructor().addConstructor(model.isDeprecated());
initBuilder.body(statementGen().makeThrowUnresolvedCompilationError(plan.getErrorMessage().getMessage()));
initBuilder.modifiers(PRIVATE);
}
// If it's a Class without initializer parameters...
if (Strategy.generateMain(def)) {
// ... then add a main() method
classBuilder.method(makeMainForClass(model));
}
classBuilder.modelAnnotations(model.getAnnotations()).modifiers(modifierTransformation().classFlags(model)).satisfies(model.getSatisfiedTypes()).caseTypes(model.getCaseTypes(), model.getSelfType()).defs(childDefs);
// aliases and native headers don't need a $getType method
if (!model.isAlias()) {
// only classes get a $getType method
if (model instanceof Class)
classBuilder.addGetTypeMethod(model.getType());
if (supportsReifiedAlias(model))
classBuilder.reifiedAlias(model.getType());
}
// we can add things which depend on knowing all the fields
if (Strategy.generateJpaCtor(model) && plan instanceof Generate) {
buildJpaConstructor((Class) model, classBuilder);
}
if (model instanceof Class && !(model instanceof ClassAlias) && plan instanceof Generate) {
Class c = (Class) model;
if (Strategy.introduceJavaIoSerializable(c, typeFact().getJavaIoSerializable())) {
classBuilder.introduce(make().QualIdent(syms().serializableType.tsym));
if (Strategy.useSerializationProxy(c) && noValueConstructorErrors((Tree.ClassDefinition) def)) {
at(def);
addWriteReplace(c, classBuilder);
}
}
serialization(c, classBuilder);
}
// reset position before initializer constructor is generated.
at(def);
classBuilder.at(def);
List<JCTree> result;
if (Decl.isAnnotationClass(def.getDeclarationModel())) {
ListBuffer<JCTree> trees = new ListBuffer<JCTree>();
trees.addAll(transformAnnotationClass((Tree.AnyClass) def));
transformAnnotationClassConstructor((Tree.AnyClass) def, classBuilder);
// you only need that method if you satisfy Annotation which is erased to j.l.a.Annotation
if (model.inherits(typeFact().getAnnotationDeclaration()))
classBuilder.addAnnotationTypeMethod(model.getType());
trees.addAll(classBuilder.build());
result = trees.toList();
} else {
result = classBuilder.build();
}
if (model.isToplevel() && isEe(model)) {
replaceModifierTransformation(new ModifierTransformation());
}
return result;
}
use of org.eclipse.ceylon.langtools.tools.javac.tree.JCTree in project ceylon by eclipse.
the class ClassTransformer method makeNamedConstructor.
/**
* Makes a named constructor
* @param that
* @param classBuilder
* @param mods
* @param ctorName
* @param ctorBody
* @param declFlags
* @return
*/
public List<JCTree> makeNamedConstructor(Tree.Declaration that, Tree.ParameterList parameterList, Constructor ctor, ClassDefinitionBuilder classBuilder, boolean generateInstantiator, int mods, boolean atIgnoreCtor, String ctorName, List<JCStatement> ctorBody, DeclNameFlag... declFlags) {
ListBuffer<JCTree> result = new ListBuffer<JCTree>();
Class clz = (Class) ctor.getContainer();
at(that);
MethodDefinitionBuilder ctorDb = MethodDefinitionBuilder.constructor(this, ctor.isDeprecated());
ClassDefinitionBuilder decl = null;
ClassDefinitionBuilder impl = null;
if (generateInstantiator) {
if (clz.getContainer() instanceof Interface) {
decl = classBuilder.getContainingClassBuilder();
impl = classBuilder.getContainingClassBuilder().getCompanionBuilder((Interface) clz.getContainer());
} else {
decl = classBuilder.getContainingClassBuilder();
impl = classBuilder.getContainingClassBuilder();
}
generateInstantiators(classBuilder, clz, ctor, decl, impl, that, parameterList);
}
ctorDb.userAnnotations(expressionGen().transformAnnotations(OutputElement.CONSTRUCTOR, that));
if (atIgnoreCtor) {
ctorDb.modelAnnotations(makeAtIgnore());
} else if (!Decl.isDefaultConstructor(ctor)) {
ctorDb.modelAnnotations(makeAtName(ctor.getName()));
}
if (ModelUtil.isEnumeratedConstructor(ctor)) {
ctorDb.modelAnnotations(makeAtEnumerated());
}
ctorDb.modifiers(mods);
for (TypeParameter tp : Strategy.getEffectiveTypeParameters(clz)) {
ctorDb.reifiedTypeParameter(tp);
}
if (ctorName != null) {
// generate a constructor name class (and constant)
transformConstructorName(classBuilder, result, ctor, clz, mods, ctorName, declFlags);
// Add the name paramter
ctorDb.parameter(makeConstructorNameParameter(ctor, declFlags));
}
// Add the rest of the parameters (this worries about aliasing)
if (parameterList != null) {
transformClassOrCtorParameters(null, (Class) ctor.getContainer(), ctor, that, parameterList, contains(declFlags, DeclNameFlag.DELEGATION), classBuilder, ctorDb, generateInstantiator, decl, impl);
}
// Transformation of body has to happen after transformation of parameter so we know about parameter aliasing.
at(that);
ctorDb.block(make().Block(0, ctorBody));
result.add(ctorDb.build());
return result.toList();
}
Aggregations