use of org.eclipse.ceylon.model.typechecker.model.Constructor in project ceylon by eclipse.
the class TypeUtils method resolveTypeParameter.
/**
* Finds the owner of the type parameter and outputs a reference to the corresponding type argument.
*/
static void resolveTypeParameter(final Node node, final TypeParameter tp, final GenerateJsVisitor gen, final boolean skipSelfDecl) {
Scope parent = ModelUtil.getRealScope(node.getScope());
int outers = 0;
while (parent != null && parent != tp.getContainer()) {
if (parent instanceof TypeDeclaration && !(parent instanceof Constructor || ((TypeDeclaration) parent).isAnonymous())) {
outers++;
}
parent = parent.getScope();
}
if (tp.getContainer() instanceof ClassOrInterface) {
if (parent == tp.getContainer()) {
if (!skipSelfDecl) {
TypeDeclaration ontoy = ModelUtil.getContainingClassOrInterface(node.getScope());
while (ontoy.isAnonymous()) ontoy = ModelUtil.getContainingClassOrInterface(ontoy.getScope());
gen.out(gen.getNames().self(ontoy));
if (ontoy == parent)
outers--;
for (int i = 0; i < outers; i++) {
gen.out(".outer$");
}
gen.out(".");
}
gen.out("$$targs$$.", gen.getNames().typeParameterName(tp));
} else {
// This can happen in expressions such as Singleton(n) when n is dynamic
gen.out("{/*NO PARENT*/t:", gen.getClAlias(), "Anything}");
}
} else if (tp.getContainer() instanceof TypeAlias) {
if (parent == tp.getContainer()) {
gen.out("'", gen.getNames().typeParameterName(tp), "'");
} else {
// This can happen in expressions such as Singleton(n) when n is dynamic
gen.out("{/*NO PARENT ALIAS*/t:", gen.getClAlias(), "Anything}");
}
} else {
// it has to be a method, right?
// We need to find the index of the parameter where the argument occurs
// ...and it could be null...
Type type = null;
for (Iterator<ParameterList> iter0 = ((Function) tp.getContainer()).getParameterLists().iterator(); type == null && iter0.hasNext(); ) {
for (Iterator<Parameter> iter1 = iter0.next().getParameters().iterator(); iter1.hasNext(); ) {
type = typeContainsTypeParameter(iter1.next().getType(), tp);
}
}
// A type argument of the argument's type, in which case we must get the reified generic from the argument
if (tp.getContainer() == parent) {
gen.out(gen.getNames().typeArgsParamName((Function) tp.getContainer()), ".", gen.getNames().typeParameterName(tp));
} else {
if (parent == null && node instanceof Tree.StaticMemberOrTypeExpression) {
if (tp.getContainer() == ((Tree.StaticMemberOrTypeExpression) node).getDeclaration()) {
type = ((Tree.StaticMemberOrTypeExpression) node).getTarget().getTypeArguments().get(tp);
typeNameOrList(node, type, gen, skipSelfDecl);
return;
}
}
gen.out("'", gen.getNames().typeParameterName(tp), "'");
// gen.out.spitOut("Passing reference to " + tp.getQualifiedNameString() + " as a string...");
// gen.out("/*Please report this to the ceylon-js team: METHOD TYPEPARM plist ",
// Integer.toString(plistCount), "#", tp.getName(), "*/'", type.getProducedTypeQualifiedName(),
// "' container " + tp.getContainer() + " at " + node);
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.Constructor in project ceylon by eclipse.
the class Singletons method defineObject.
/**
* Generate an object definition, that is, define an anonymous class and then a function
* to return a single instance of it.
* @param that The node with the definition (can be ObjectDefinition, ObjectExpression, ObjectArgument)
* @param d The Value declaration for the object
* @param sats The list of satisfied types of the anonymous class
* @param superType The supertype of the anonymous class
* @param superCall The invocation of the supertype (object bla extends Foo(x))
* @param body The object definition's body
* @param annots The annotations (in case of ObjectDefinition)
* @param gen The main visitor/generator.
*/
static void defineObject(final Node that, final Value d, final List<Type> sats, final Tree.SimpleType superType, final Tree.InvocationExpression superCall, final Tree.Body body, final Tree.AnnotationList annots, final GenerateJsVisitor gen, InitDeferrer initDeferrer) {
final boolean addToPrototype = gen.opts.isOptimize() && d != null && d.isClassOrInterfaceMember();
final boolean isObjExpr = that instanceof Tree.ObjectExpression;
final TypeDeclaration _td = isObjExpr ? ((Tree.ObjectExpression) that).getAnonymousClass() : d.getTypeDeclaration();
final Class c = (Class) (_td instanceof Constructor ? _td.getContainer() : _td);
final String className = gen.getNames().name(c);
final String objectName = gen.getNames().name(d);
final String selfName = gen.getNames().self(c);
final Value natd = d == null ? null : (Value) ModelUtil.getNativeDeclaration(d, Backend.JavaScript);
if (that instanceof Tree.Declaration) {
if (NativeUtil.isNativeHeader((Tree.Declaration) that) && natd != null) {
// It's a native header, remember it for later when we deal with its implementation
gen.saveNativeHeader((Tree.Declaration) that);
return;
}
if (!(NativeUtil.isForBackend((Tree.Declaration) that, Backend.JavaScript) || NativeUtil.isHeaderWithoutBackend((Tree.Declaration) that, Backend.JavaScript))) {
return;
}
}
final List<Tree.Statement> stmts;
if (d != null && NativeUtil.isForBackend(d, Backend.JavaScript)) {
Tree.Declaration nh = gen.getNativeHeader(d);
if (nh == null && NativeUtil.hasNativeMembers(c) && that instanceof Tree.Declaration) {
nh = (Tree.Declaration) that;
}
stmts = NativeUtil.mergeStatements(body, nh, Backend.JavaScript);
} else {
stmts = body.getStatements();
}
Map<TypeParameter, Type> targs = new HashMap<>();
if (sats != null) {
for (Type st : sats) {
Map<TypeParameter, Type> stargs = st.getTypeArguments();
if (stargs != null && !stargs.isEmpty()) {
targs.putAll(stargs);
}
}
}
gen.out(GenerateJsVisitor.function, className, targs.isEmpty() ? "()" : "($$targs$$)");
gen.beginBlock();
if (isObjExpr) {
gen.out("var ", selfName, "=new ", className, ".$$;");
final ClassOrInterface coi = ModelUtil.getContainingClassOrInterface(c.getContainer());
if (coi != null) {
gen.out(selfName, ".outer$=", gen.getNames().self(coi));
gen.endLine(true);
}
} else {
if (c.isMember() && !d.isStatic()) {
gen.initSelf(that);
}
gen.instantiateSelf(c);
gen.referenceOuter(c);
}
// TODO should we generate all this code for native headers?
// Really we should merge the body of the header with that of the impl
// It's the only way to make this shit work in lexical scope mode
final List<Declaration> superDecs = new ArrayList<>();
if (!gen.opts.isOptimize()) {
final SuperVisitor superv = new SuperVisitor(superDecs);
for (Tree.Statement st : stmts) {
st.visit(superv);
}
}
if (!targs.isEmpty()) {
gen.out(selfName, ".$$targs$$=$$targs$$");
gen.endLine(true);
}
TypeGenerator.callSupertypes(sats, superType, c, that, superDecs, superCall, superType == null ? null : ((Class) c.getExtendedType().getDeclaration()).getParameterList(), gen);
gen.visitStatements(stmts);
gen.out("return ", selfName, ";");
gen.endBlock();
gen.out(";", className, ".$crtmm$=");
TypeUtils.encodeForRuntime(that, c, gen);
gen.endLine(true);
TypeGenerator.initializeType(that, gen, initDeferrer);
final String objvar = (addToPrototype ? "this." : "") + gen.getNames().createTempVariable();
if (d != null && !addToPrototype) {
gen.out("var ", objvar);
// If it's a property, create the object here
if (AttributeGenerator.defineAsProperty(d)) {
gen.out("=", className, "(");
if (!targs.isEmpty()) {
TypeUtils.printTypeArguments(that, targs, gen, false, null);
}
gen.out(")");
}
gen.endLine(true);
}
if (d != null && AttributeGenerator.defineAsProperty(d)) {
gen.out(gen.getClAlias(), "atr$(");
gen.outerSelf(d);
gen.out(",'", objectName, "',function(){return ");
if (addToPrototype) {
gen.out("this.", gen.getNames().privateName(d));
} else {
gen.out(objvar);
}
gen.out(";},undefined,");
TypeUtils.encodeForRuntime(that, d, annots, gen);
gen.out(")");
gen.endLine(true);
} else if (d != null) {
final String objectGetterName = gen.getNames().getter(d, false);
gen.out(GenerateJsVisitor.function, objectGetterName, "()");
gen.beginBlock();
// Create the object lazily
final String oname = gen.getNames().objectName(c);
gen.out("if(", objvar, "===", gen.getClAlias(), "INIT$)");
gen.generateThrow(gen.getClAlias() + "InitializationError", "Cyclic initialization trying to read the value of '" + d.getName() + "' before it was set", that);
gen.endLine(true);
gen.out("if(", objvar, "===undefined){", objvar, "=", gen.getClAlias(), "INIT$;", objvar, "=$init$", oname);
if (!oname.endsWith("()")) {
gen.out("()");
}
gen.out("(");
if (!targs.isEmpty()) {
TypeUtils.printTypeArguments(that, targs, gen, false, null);
}
gen.out(");", objvar, ".$crtmm$=", objectGetterName, ".$crtmm$;}");
gen.endLine();
gen.out("return ", objvar, ";");
gen.endBlockNewLine();
if (addToPrototype || d.isShared()) {
gen.outerSelf(d);
gen.out(".", objectGetterName, "=", objectGetterName);
gen.endLine(true);
}
if (!d.isToplevel()) {
if (gen.outerSelf(d))
gen.out(".");
}
gen.out(objectGetterName, ".$crtmm$=");
TypeUtils.encodeForRuntime(that, d, annots, gen);
gen.endLine(true);
gen.out(gen.getNames().getter(c, true), "=", objectGetterName);
gen.endLine(true);
if (d.isToplevel()) {
final String objectGetterNameMM = gen.getNames().getter(d, true);
gen.out("ex$.", objectGetterNameMM, "=", objectGetterNameMM);
gen.endLine(true);
}
} else if (isObjExpr) {
gen.out("return ", className, "();");
}
}
use of org.eclipse.ceylon.model.typechecker.model.Constructor in project ceylon by eclipse.
the class TypeGenerator method typeFunctionName.
/**
* Returns the name of the type or its $init$ function if it's local.
*/
static String typeFunctionName(final Tree.StaticType type, final ClassOrInterface coi, final GenerateJsVisitor gen) {
TypeDeclaration d = type.getTypeModel().getDeclaration();
final boolean removeAlias = d == null || !d.isClassOrInterfaceMember() || d instanceof Interface;
if ((removeAlias && d.isAlias()) || d instanceof Constructor) {
Type extendedType = d.getExtendedType();
d = extendedType == null ? null : extendedType.getDeclaration();
}
Declaration cont = ModelUtil.getContainingDeclaration(d);
final boolean inProto = gen.opts.isOptimize() && cont instanceof TypeDeclaration;
final boolean imported = gen.isImported(type.getUnit().getPackage(), d);
String dname = gen.getNames().name(d);
if (d.isAlias()) {
TypeDeclaration d2 = d;
while (d2.isAlias()) {
d2 = d2.getExtendedType().getDeclaration();
}
dname = gen.getNames().name(d2);
}
final String initName = "$init$" + dname + "()";
if (!imported && !d.isClassOrInterfaceMember()) {
return initName;
}
if (inProto && coi.isMember() && !d.isAlias() && (coi.getContainer() == cont || ModelUtil.contains(d, coi))) {
// use its $init$ function
return initName;
}
String tfn;
// #628 If coi is anonymous and inside cont, qualify the path from cont instead
if (coi != null && coi.isAnonymous() && cont instanceof Scope && ModelUtil.contains((Scope) cont, coi)) {
tfn = gen.qualifiedPath(type, cont, inProto);
} else if (inProto && d.isClassOrInterfaceMember()) {
return pathToType(type, d, gen);
} else {
tfn = gen.qualifiedPath(type, d, inProto);
}
tfn = gen.memberAccessBase(type, d, false, tfn);
if (removeAlias && !imported) {
int idx = tfn.lastIndexOf('.');
if (idx > 0) {
tfn = tfn.substring(0, idx + 1) + initName;
} else {
tfn = initName;
}
}
return tfn;
}
use of org.eclipse.ceylon.model.typechecker.model.Constructor in project ceylon by eclipse.
the class JsonPackage method getTypeFromJson.
/**
* Looks up a type from model data, creating it if necessary. The returned type will have its
* type parameters substituted if needed.
*/
private Type getTypeFromJson(Map<String, Object> m, Declaration container, List<TypeParameter> typeParams) {
TypeDeclaration td = null;
if (m.get(KEY_METATYPE) instanceof TypeDeclaration) {
td = (TypeDeclaration) m.get(KEY_METATYPE);
if (td instanceof ClassOrInterface && td.getUnit().getPackage() instanceof JsonPackage) {
((JsonPackage) td.getUnit().getPackage()).load(td.getName(), typeParams);
}
}
final String tname = (String) m.get(KEY_NAME);
if ("$U".equals(tname)) {
m.put(KEY_METATYPE, unknown);
return unknown.getType();
}
if (td == null && m.containsKey("comp")) {
@SuppressWarnings("unchecked") final List<Map<String, Object>> tmaps = (List<Map<String, Object>>) m.get(KEY_TYPES);
final ArrayList<Type> types = new ArrayList<>(tmaps.size());
if ("u".equals(m.get("comp"))) {
UnionType ut = new UnionType(u2);
for (Map<String, Object> tmap : tmaps) {
types.add(getTypeFromJson(tmap, container, typeParams));
}
ut.setCaseTypes(types);
td = ut;
} else if ("i".equals(m.get("comp"))) {
IntersectionType it = new IntersectionType(u2);
for (Map<String, Object> tmap : tmaps) {
types.add(getTypeFromJson(tmap, container, typeParams));
}
it.setSatisfiedTypes(types);
td = it;
} else {
throw new IllegalArgumentException("Invalid composite type '" + m.get("comp") + "'");
}
} else if (td == null) {
final String pname = (String) m.get(KEY_PACKAGE);
if (pname == null) {
// It's a ref to a type parameter
final List<TypeParameter> containerTypeParameters;
if (container instanceof Constructor) {
containerTypeParameters = ((Generic) container.getContainer()).getTypeParameters();
} else if (container instanceof Generic) {
containerTypeParameters = container.getTypeParameters();
} else {
containerTypeParameters = null;
}
if (containerTypeParameters != null) {
for (TypeParameter typeParam : containerTypeParameters) {
if (typeParam.getName().equals(tname)) {
td = typeParam;
}
}
}
if (td == null && typeParams != null) {
for (TypeParameter typeParam : typeParams) {
if (typeParam.getName().equals(tname)) {
td = typeParam;
}
}
}
} else {
String mname = (String) m.get(KEY_MODULE);
if ("$".equals(mname)) {
mname = LANGUAGE_MODULE_NAME;
}
org.eclipse.ceylon.model.typechecker.model.Package rp;
if ("$".equals(pname) || LANGUAGE_MODULE_NAME.equals(pname)) {
// Language module package
rp = isLanguagePackage() ? this : getModule().getLanguageModule().getDirectPackage(LANGUAGE_MODULE_NAME);
} else if (mname == null) {
// local type
if (".".equals(pname)) {
rp = this;
if (container instanceof TypeDeclaration && tname.equals(container.getName())) {
td = (TypeDeclaration) container;
}
} else {
rp = getModule().getDirectPackage(pname);
}
} else {
rp = getModule().getPackage(pname);
}
if (rp == null) {
throw new CompilerErrorException("Package not found: " + pname);
}
if (rp != this && rp instanceof JsonPackage && !((JsonPackage) rp).loaded) {
((JsonPackage) rp).loadIfNecessary();
}
final boolean nested = tname.indexOf('.') > 0;
final String level1 = nested ? tname.substring(0, tname.indexOf('.')) : tname;
if (rp != null && !nested) {
Declaration d = rp.getDirectMember(tname, null, false);
if (d instanceof TypeDeclaration) {
td = (TypeDeclaration) d;
if (td.isTuple()) {
if (m.containsKey(KEY_TYPES)) {
@SuppressWarnings("unchecked") List<Map<String, Object>> elemaps = (List<Map<String, Object>>) m.get(KEY_TYPES);
ArrayList<Type> elems = new ArrayList<>(elemaps.size());
for (Map<String, Object> elem : elemaps) {
elems.add(getTypeFromJson(elem, container, typeParams));
}
Type tail = elems.get(elems.size() - 1);
if ((tail.isSequence() || tail.isSequential()) && !tail.isTuple() && !tail.isEmpty()) {
elems.remove(elems.size() - 1);
} else {
tail = null;
}
return u2.getTupleType(elems, tail, -1);
} else if (m.containsKey("count")) {
@SuppressWarnings("unchecked") Map<String, Object> elem = (Map<String, Object>) m.get(KEY_TYPE);
Type[] elems = new Type[(int) m.remove("count")];
Arrays.fill(elems, getTypeFromJson(elem, container, typeParams));
return u2.getTupleType(Arrays.asList(elems), null, -1);
}
}
} else if (d instanceof FunctionOrValue) {
td = ((FunctionOrValue) d).getTypeDeclaration();
}
}
if (td == null && rp instanceof JsonPackage) {
if (nested) {
td = ((JsonPackage) rp).loadNestedType(tname, typeParams);
} else {
td = (TypeDeclaration) ((JsonPackage) rp).load(tname, typeParams);
}
}
// Then look in the top-level declarations
if (nested && td == null) {
for (Declaration d : rp.getMembers()) {
if (d instanceof TypeDeclaration && level1.equals(d.getName())) {
td = (TypeDeclaration) d;
}
}
final String[] path = tname.split("\\.");
for (int i = 1; i < path.length; i++) {
td = (TypeDeclaration) td.getDirectMember(path[i], null, false);
}
}
}
}
// From 1.2.3 we stored type arguments in maps
final Type newType = loadTypeArguments(m, td, container, typeParams);
if (newType != null) {
return newType;
}
// This is the old pre 1.2.3 stuff
@SuppressWarnings("unchecked") final List<Map<String, Object>> modelParms = (List<Map<String, Object>>) m.get(KEY_TYPE_PARAMS);
if (td != null && modelParms != null) {
// Substitute type parameters
final HashMap<TypeParameter, Type> concretes = new HashMap<>();
HashMap<TypeParameter, SiteVariance> variances = null;
if (td.getTypeParameters().size() < modelParms.size()) {
if (td.getUnit().getPackage() == this) {
parseTypeParameters(modelParms, td, null);
}
}
final Iterator<TypeParameter> viter = td.getTypeParameters().iterator();
for (Map<String, Object> ptparm : modelParms) {
TypeParameter _cparm = viter.next();
if (ptparm.containsKey(KEY_PACKAGE) || ptparm.containsKey(KEY_TYPES)) {
// Substitute for proper type
final Type _pt = getTypeFromJson(ptparm, container, typeParams);
concretes.put(_cparm, _pt);
} else if (ptparm.containsKey(KEY_NAME) && typeParams != null) {
// Look for type parameter with same name
for (TypeParameter typeParam : typeParams) {
if (typeParam.getName().equals(ptparm.get(KEY_NAME))) {
concretes.put(_cparm, typeParam.getType());
}
}
}
Integer usv = (Integer) ptparm.get(KEY_US_VARIANCE);
if (usv != null) {
if (variances == null) {
variances = new HashMap<>();
}
variances.put(_cparm, SiteVariance.values()[usv]);
}
}
if (!concretes.isEmpty()) {
return td.getType().substitute(concretes, variances);
}
}
if (td == null) {
try {
throw new IllegalArgumentException(String.format("Couldn't find type %s::%s for %s in %s<%s> (FROM pkg %s)", m.get(KEY_PACKAGE), m.get(KEY_NAME), m.get(KEY_MODULE), m, typeParams, getNameAsString()));
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
}
return td.getType();
}
use of org.eclipse.ceylon.model.typechecker.model.Constructor in project ceylon by eclipse.
the class MetamodelGenerator method encodeAnnotations.
/**
* Encodes all annotations as a map which is then stored under the
* {@link #KEY_ANNOTATIONS} key in the specified map.
* If the map is null, only the bitset annotations are calculated and returned.
* @return The bitmask for the bitset annotations.
*/
public static int encodeAnnotations(List<Annotation> annotations, Object d, Map<String, Object> m) {
List<Map<String, List<String>>> anns = m == null ? null : new ArrayList<Map<String, List<String>>>(annotations.size());
int bits = 0;
for (Annotation a : annotations) {
String name = a.getName();
int idx = "native".equals(name) ? -1 : annotationBits.indexOf(name);
if (idx >= 0) {
bits |= (1 << idx);
} else if (anns != null) {
List<String> args = a.getPositionalArguments();
if (args == null) {
args = Collections.emptyList();
}
anns.add(Collections.singletonMap(name, args));
}
}
if (d instanceof Value && ((Value) d).isVariable()) {
// Sometimes the value is not annotated, it only has a defined Setter
bits |= (1 << annotationBits.indexOf("variable"));
} else if (d instanceof org.eclipse.ceylon.model.typechecker.model.Class && ((org.eclipse.ceylon.model.typechecker.model.Class) d).isAbstract()) {
bits |= (1 << annotationBits.indexOf("abstract"));
} else if (d instanceof Constructor && ((Constructor) d).isAbstract()) {
bits |= (1 << annotationBits.indexOf("abstract"));
}
if (bits > 0 && m != null) {
String key = d instanceof Module ? "$mod-pa" : d instanceof org.eclipse.ceylon.model.typechecker.model.Package ? "$pkg-pa" : KEY_PACKED_ANNS;
m.put(key, bits);
}
if (anns != null && m != null && !anns.isEmpty()) {
String key = d instanceof Module ? "$mod-anns" : d instanceof org.eclipse.ceylon.model.typechecker.model.Package ? "$pkg-anns" : KEY_ANNOTATIONS;
m.put(key, anns);
}
return bits;
}
Aggregations