Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.redhat.ceylon.compiler.js.loader.MetamodelGenerator Maven / Gradle / Ivy
package com.redhat.ceylon.compiler.js.loader;
import static com.redhat.ceylon.model.typechecker.model.Module.LANGUAGE_MODULE_NAME;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.redhat.ceylon.common.Backend;
import com.redhat.ceylon.common.Versions;
import com.redhat.ceylon.compiler.js.util.TypeUtils;
import com.redhat.ceylon.model.typechecker.model.Annotation;
import com.redhat.ceylon.model.typechecker.model.ClassAlias;
import com.redhat.ceylon.model.typechecker.model.Constructor;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.DeclarationKind;
import com.redhat.ceylon.model.typechecker.model.Function;
import com.redhat.ceylon.model.typechecker.model.FunctionOrValue;
import com.redhat.ceylon.model.typechecker.model.Interface;
import com.redhat.ceylon.model.typechecker.model.ModelUtil;
import com.redhat.ceylon.model.typechecker.model.Module;
import com.redhat.ceylon.model.typechecker.model.ModuleImport;
import com.redhat.ceylon.model.typechecker.model.Parameter;
import com.redhat.ceylon.model.typechecker.model.ParameterList;
import com.redhat.ceylon.model.typechecker.model.SiteVariance;
import com.redhat.ceylon.model.typechecker.model.Type;
import com.redhat.ceylon.model.typechecker.model.TypeAlias;
import com.redhat.ceylon.model.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.model.typechecker.model.TypeParameter;
import com.redhat.ceylon.model.typechecker.model.Value;
/** Generates the metamodel for all objects in a module.
* This is used by the MetamodelVisitor.
*
* @author Enrique Zamudio
*/
public class MetamodelGenerator {
public static final String KEY_CLASSES = "$c";
public static final String KEY_INTERFACES = "$i";
public static final String KEY_OBJECTS = "$o";
public static final String KEY_METHODS = "$m";
public static final String KEY_ATTRIBUTES = "$at";
public static final String KEY_ANNOTATIONS = "an";
public static final String KEY_PACKED_ANNS = "pa";
public static final String KEY_TYPE = "$t";
public static final String KEY_RETURN_TYPE = "$rt";
public static final String KEY_TYPES = "l";
public static final String KEY_TYPE_PARAMS = "tp";
public static final String KEY_TYPE_ARGS = "ta";
public static final String KEY_METATYPE = "mt";
public static final String KEY_MODULE = "md";
public static final String KEY_NAME = "nm";
public static final String KEY_PACKAGE = "pk";
public static final String KEY_PARAMS = "ps";
public static final String KEY_SELF_TYPE = "st";
public static final String KEY_SATISFIES = "sts";
public static final String KEY_DS_VARIANCE = "dv"; //declaration-site variance
public static final String KEY_US_VARIANCE = "uv"; //use-site variance
public static final String KEY_CONSTRUCTOR = "co";
public static final String KEY_CONSTRUCTORS = "$cn";
public static final String KEY_FLAGS = "$ff";
public static final String KEY_DEFAULT = "def";
public static final String KEY_DYNAMIC = "dyn";
// backend specific keys
public static final String KEY_JS_TSENUM = "$tsenum"; // case constructor is a TypeScript enum
public static final String METATYPE_CLASS = "c";
public static final String METATYPE_INTERFACE = "i";
public static final String METATYPE_ALIAS = "als";
public static final String METATYPE_OBJECT = "o";
public static final String METATYPE_METHOD = "m";
public static final String METATYPE_ATTRIBUTE = "a";
public static final String METATYPE_GETTER = "g";
public static final String METATYPE_SETTER = "s";
public static final String METATYPE_TYPE_PARAMETER = "tp";
public static final String METATYPE_PARAMETER = "prm";
//DO NOT REARRANGE, only append
public static final List annotationBits = Arrays.asList("shared", "actual", "formal", "default",
"sealed", "final", "native", "late", "abstract", "annotation",
"variable", "serializable", "static");
private final Map model = new HashMap<>();
private static final Map unknownTypeMap = new HashMap<>();
private static final Map nothingTypeMap = new HashMap<>();
private final Module module;
public MetamodelGenerator(Module module) {
this.module = module;
model.put("$mod-name", module.getNameAsString());
model.put("$mod-version", module.getVersion());
model.put("$mod-bin", Versions.JS_BINARY_MAJOR_VERSION+"."+Versions.JS_BINARY_MINOR_VERSION);
if (module.isNative()) {
List backends = new ArrayList<>(1);
for(Backend backend : module.getNativeBackends()) {
backends.add(backend.nativeAnnotation);
}
model.put("$mod-nat", backends);
}
encodeAnnotations(module.getAnnotations(), module, model);
if (!module.getImports().isEmpty()) {
ArrayList imps = new ArrayList<>(module.getImports().size());
for (ModuleImport mi : module.getImports()) {
if (!ModelUtil.isForBackend(mi.getNativeBackends(), Backend.JavaScript)) {
continue;
}
if (mi.getModule().getVersion() == null) { //#416
continue;
}
String impath = String.format("%s/%s", mi.getModule().getNameAsString(), mi.getModule().getVersion());
if (mi.getNamespace() != null) {
impath = mi.getNamespace() + ":" + impath;
}
if (mi.isOptional() || mi.isExport() || mi.isNative()) {
Map optimp = new HashMap<>(3);
optimp.put("path",impath);
if (mi.isOptional()) {
optimp.put("opt", 1);
}
if (mi.isExport()) {
optimp.put("exp", 1);
}
if (mi.isNative()) {
List backends = new ArrayList<>(1);
for(Backend backend : mi.getNativeBackends())
backends.add(backend.nativeAnnotation);
optimp.put("nat", backends);
}
imps.add(optimp);
} else {
imps.add(impath);
}
}
model.put("$mod-deps", imps);
}
if (unknownTypeMap.isEmpty()) {
unknownTypeMap.put(KEY_NAME, "$U");
}
if (nothingTypeMap.isEmpty()) {
nothingTypeMap.put(KEY_NAME, "Nothing");
nothingTypeMap.put(KEY_PACKAGE, "$");
}
}
/** Returns the in-memory model as a collection of maps.
* The top-level map represents the module. */
public Map getModel() {
return Collections.unmodifiableMap(model);
}
@SuppressWarnings("unchecked")
private Map findParent(Declaration d) {
Map pkgmap = getPackageMap(d.getUnit().getPackage());
if (d.isToplevel()) {
return pkgmap;
}
List names = TypeUtils.generateModelPath(ModelUtil.getContainingDeclaration(d));
names.remove(0); //we don't need the package key
if (names.isEmpty()) {
return pkgmap;
}
Map last = pkgmap;
for (String name : names) {
if (last == null) {
break;
}
Map sub = (Map)last.get(name);
if (sub == null && name.charAt(0)=='$') {
sub = new HashMap<>();
last.put(name, sub);
}
last = sub;
}
return last;
}
private Map tupleTypeMap(Type tt, Declaration from) {
final Map m = new HashMap<>();
m.put(KEY_NAME, "Tuple");
m.put(KEY_PACKAGE, "$");
List targs = tt.getTypeArgumentList(); //Element, First, Rest
if (from.getUnit().isHomogeneousTuple(tt)) {
int min = from.getUnit().getHomogeneousTupleLength(tt);
m.put(KEY_TYPE, typeMap(targs.get(1), from));
m.put("count", min);
} else {
encodeTypes(from.getUnit().getTupleElementTypes(tt), m, KEY_TYPES, from);
}
return m;
}
/** Create a map for the specified Type.
* Includes name, package, module and type parameters, unless it's a union or intersection
* type, in which case it contains a "comp" key with an "i" or "u" and a key "types" with
* the list of types that compose it. */
private Map typeMap(Type pt, Declaration from) {
if (ModelUtil.isTypeUnknown(pt)) {
return unknownTypeMap;
} else if (pt.isNothing()) {
return nothingTypeMap;
}
Map m = new HashMap<>();
if (pt.isUnion() || pt.isIntersection()) {
List subtipos = pt.isUnion() ? pt.getCaseTypes() : pt.getSatisfiedTypes();
List> subs = new ArrayList<>(subtipos.size());
for (Type sub : subtipos) {
subs.add(typeMap(sub, from));
}
m.put("comp", pt.isUnion() ? "u" : "i");
m.put(KEY_TYPES, subs);
return m;
} else if (pt.isTuple() && !pt.involvesTypeParameters()) {
return tupleTypeMap(pt, from);
}
TypeDeclaration d = pt.getDeclaration();
if (d.isToplevel() || pt.isTypeParameter()) {
m.put(KEY_NAME, d.getName());
} else {
String qn = d.getQualifiedNameString();
int p0 = qn.indexOf("::");
if (p0>=0) {
qn = qn.substring(p0+2);
}
p0 = qn.indexOf('.');
if (p0 >= 0) {
StringBuilder nestedName = new StringBuilder(TypeUtils.modelName(d));
Declaration pd = ModelUtil.getContainingDeclaration(d);
while (pd != null) {
nestedName.insert(0, '.');
nestedName.insert(0, TypeUtils.modelName(pd));
pd = ModelUtil.getContainingDeclaration(pd);
}
qn = nestedName.toString();
}
m.put(KEY_NAME, qn);
}
if (d.getDeclarationKind()==DeclarationKind.TYPE_PARAMETER) {
//For types that reference type parameters, we're done
return m;
}
com.redhat.ceylon.model.typechecker.model.Package pkg = d.getUnit().getPackage();
if (pkg == null || pkg.equals(from.getUnit().getPackage())) {
addPackage(m, ".");
} else {
addPackage(m, pkg.getNameAsString());
}
if (pkg != null && !pkg.getModule().equals(module)) {
final Module mod = pkg.getModule();
m.put(KEY_MODULE, mod.isLanguageModule()?"$":mod.getNameAsString());
}
putTypeArguments(m, pt, from);
return m;
}
/** Returns a map with the same info as {@link #typeParameterMap(Type)} but with
* an additional key {@value #KEY_DS_VARIANCE} if it's covariant ("out") or contravariant ("in"). */
private Map typeParameterMap(TypeParameter tp, Declaration from) {
Map map = new HashMap<>();
map.put(MetamodelGenerator.KEY_NAME, tp.getName());
if (tp.isCovariant()) {
map.put(KEY_DS_VARIANCE, "out");
} else if (tp.isContravariant()) {
map.put(KEY_DS_VARIANCE, "in");
}
if (tp.getSelfType() != null) {
map.put(KEY_SELF_TYPE, tp.getSelfType().getDeclaration().getName());
}
if (tp.getSatisfiedTypes() != null && !tp.getSatisfiedTypes().isEmpty()) {
encodeTypes(tp.getSatisfiedTypes(), map, KEY_SATISFIES, from);
}
if (tp.getCaseTypes() != null && !tp.getCaseTypes().isEmpty()) {
encodeTypes(tp.getCaseTypes(), map, "of", from);
}
if (tp.getDefaultTypeArgument() != null) {
map.put(KEY_DEFAULT, typeMap(tp.getDefaultTypeArgument(), from));
}
return map;
}
private void putTypeArguments(Map container, Type pt, Declaration from) {
int tparmSize = 0;
Type t = pt;
while (t != null) {
tparmSize += t.getTypeArgumentList() == null ? 0 : t.getTypeArgumentList().size();
t = t.getQualifyingType();
}
if (tparmSize > 0) {
final Map> targs = new HashMap<>(tparmSize);
t = pt;
while (t != null) {
final Map usv = t.getVarianceOverrides();
if (t.getTypeArgumentList() != null && !t.getTypeArgumentList().isEmpty()) {
for (Map.Entry targ : t.getTypeArguments().entrySet()) {
final Map tpmap = typeMap(targ.getValue(), from);
final SiteVariance variance = usv.get(targ.getKey());
if (variance != null) {
tpmap.put(MetamodelGenerator.KEY_US_VARIANCE, variance.ordinal());
}
targs.put(partiallyQualifiedName(targ.getKey().getDeclaration()) + "." + targ.getKey().getName(), tpmap);
}
}
t = t.getQualifyingType();
}
container.put(KEY_TYPE_ARGS, targs);
}
}
public static String partiallyQualifiedName(Declaration d) {
String qname = d.getQualifiedNameString();
int idx = qname.indexOf("::");
if (idx >= 0) {
qname = qname.substring(idx+2);
}
return qname;
}
/** Create a list of maps from the list of type parameters.
* @see #typeParameterMap(TypeParameter) */
private List> typeParameters(List tpl, Declaration from) {
if (tpl != null && !tpl.isEmpty()) {
List> l = new ArrayList<>(tpl.size());
for (TypeParameter tp : tpl) {
l.add(typeParameterMap(tp, from));
}
return l;
}
return null;
}
/** Create a list of maps for the parameter list. Each map will be a parameter, including
* name, type, default value (if any), and whether it's sequenced. */
private List> parameterListMap(ParameterList plist, Declaration from) {
if (plist == null) {
//Possibly an anonymous class for an anonymous object
return null;
}
List parms = plist.getParameters();
if (parms.size() > 0) {
List> p = new ArrayList<>(parms.size());
for (Parameter parm : parms) {
Map pm = new HashMap<>();
pm.put(KEY_NAME, parm.getName());
pm.put(KEY_METATYPE, METATYPE_PARAMETER);
if (parm.isSequenced()) {
pm.put("seq", 1);
}
if (parm.isDefaulted()) {
pm.put(KEY_DEFAULT, 1);
}
if (parm.isAtLeastOne()) {
pm.put("$min1", 1);
}
final FunctionOrValue parmtype = parm.getModel();
if (parmtype != null && parmtype.getDeclarationKind()==DeclarationKind.TYPE_PARAMETER) {
pm.put(KEY_TYPE, parmtype.getName());
} else {
pm.put(KEY_TYPE, typeMap(parm.getType(), from));
}
if (parm.isHidden()) {
pm.put("$hdn", 1);
}
if (parmtype instanceof Function) {
pm.put("$pt", "f");
List>> _paramLists = new ArrayList<>(
((Function)parmtype).getParameterLists().size());
for (ParameterList subplist : ((Function)parmtype).getParameterLists()) {
List> params = parameterListMap(subplist, from);
if (params == null) {
params = Collections.emptyList();
}
_paramLists.add(params);
}
if (_paramLists.size() > 1 || !_paramLists.get(0).isEmpty()) {
pm.put(KEY_PARAMS, _paramLists);
}
}
//TODO do these guys need anything else?
/*if (parm.getDefaultArgument() != null) {
//This could be compiled to JS...
pm.put(ANN_DEFAULT, parm.getDefaultArgument().getSpecifierExpression().getExpression().getTerm().getText());
}*/
encodeAnnotations(parm.getModel().getAnnotations(), parm.getModel(), pm);
p.add(pm);
}
return p;
}
return null;
}
@SuppressWarnings("unchecked")
public Map encodeMethod(Function d) {
final Map m = new HashMap<>();
m.put(KEY_METATYPE, METATYPE_METHOD);
m.put(KEY_NAME, d.getName());
if (d.isDynamic()) {
m.put(KEY_DYNAMIC, 1);
}
List> tpl = typeParameters(d.getTypeParameters(), d);
if (tpl != null) {
m.put(KEY_TYPE_PARAMS, tpl);
}
m.put(KEY_TYPE, typeMap(d.getType(), d));
List>> paramLists = new ArrayList<>(d.getParameterLists().size());
for (ParameterList plist : d.getParameterLists()) {
List> params = parameterListMap(plist, d);
if (params == null) {
params = Collections.emptyList();
}
paramLists.add(params);
}
if (paramLists.size() > 1 || !paramLists.get(0).isEmpty()) {
m.put(KEY_PARAMS, paramLists);
}
int ff = 0;
if (d.isDeclaredVoid()) {
ff |= 1;
}
if (d.isDeferred()) {
ff |= 2;
}
if (ff > 0) {
m.put(KEY_FLAGS, ff);
}
//Annotations
encodeAnnotations(d.getAnnotations(), d, m);
Map parent= findParent(d);
if (parent != null) {
if (parent != getPackageMap(d.getUnit().getPackage())) {
if (!parent.containsKey(KEY_METHODS)) {
parent.put(KEY_METHODS, new HashMap<>());
}
parent = (Map)parent.get(KEY_METHODS);
}
if (parent != null) {
parent.put(TypeUtils.modelName(d), m);
}
}
return m;
}
@SuppressWarnings("unchecked")
public Map encodeClass(com.redhat.ceylon.model.typechecker.model.Class d) {
final Map m = new HashMap<>();
m.put(KEY_METATYPE, METATYPE_CLASS);
m.put(KEY_NAME, TypeUtils.modelName(d));
//Type parameters
List> tpl = typeParameters(d.getTypeParameters(), d);
if (tpl != null) {
m.put(KEY_TYPE_PARAMS, tpl);
}
//self type
if (d.getSelfType() != null) {
m.put(KEY_SELF_TYPE, d.getSelfType().getDeclaration().getName());
}
//Extends
if (d.getExtendedType() != null) {
m.put("super", typeMap(d.getExtendedType(), d));
}
//Satisfies
encodeTypes(d.getSatisfiedTypes(), m, KEY_SATISFIES, d);
//Initializer parameters
final List> inits = parameterListMap(d.getParameterList(), d);
if (inits != null && !inits.isEmpty()) {
m.put(KEY_PARAMS, inits);
}
//Case types
encodeTypes(d.getCaseTypes(), m, "of", d);
//Annotations
encodeAnnotations(d.getAnnotations(), d, m);
if (d.isAnonymous()) {
m.put("$anon", 1);
}
if (d.isAlias()) {
m.put("$alias", 1);
TypeDeclaration constructor = ((ClassAlias)d).getConstructor();
if (constructor instanceof Constructor) {
m.put(KEY_CONSTRUCTOR, ((Constructor)constructor).getName());
}
// else, it's the default "constructor", and will be the (Class) d.getExtendedType().getDeclaration()
}
Map parent = findParent(d);
if (parent != null) {
if (parent != getPackageMap(d.getUnit().getPackage())) {
if (!parent.containsKey(KEY_CLASSES)) {
parent.put(KEY_CLASSES, new HashMap<>());
}
parent = (Map)parent.get(KEY_CLASSES);
}
parent.put(TypeUtils.modelName(d), m);
}
return m;
}
public Map encodeConstructor(final Constructor d) {
//First of all, find the class this thing belongs to
Map c = findParent(d);
final String mname = TypeUtils.modelName(d);
if (c == null) {
System.out.println("WTF no parent for Constructor " + d);
return null;
}
Map m = new HashMap<>();
if (d.getName() != null) {
m.put(KEY_NAME, mname);
}
final ParameterList plist = d.getFirstParameterList();
if (plist != null) {
m.put(KEY_PARAMS, plist.getParameters().isEmpty() ? Collections.EMPTY_LIST : parameterListMap(plist, d));
}
encodeAnnotations(d.getAnnotations(), d, m);
if (c.get(KEY_CONSTRUCTORS) == null) {
c.put(KEY_CONSTRUCTORS, new HashMap<>());
}
@SuppressWarnings("unchecked")
Map consmap = (Map)c.get(KEY_CONSTRUCTORS);
consmap.put(d.getName() == null ? "$def" : mname, m);
return null;
}
@SuppressWarnings("unchecked")
public Map encodeInterface(Interface d) {
final Map m = new HashMap<>();
m.put(KEY_METATYPE, METATYPE_INTERFACE);
m.put(KEY_NAME, d.getName());
//Type parameters
List> tpl = typeParameters(d.getTypeParameters(), d);
if (tpl != null) {
m.put(KEY_TYPE_PARAMS, tpl);
}
//self type
if (d.getSelfType() != null) {
m.put(KEY_SELF_TYPE, d.getSelfType().getDeclaration().getName());
}
if (d.isDynamic()) {
m.put(KEY_DYNAMIC, 1);
}
//satisfies
encodeTypes(d.getSatisfiedTypes(), m, KEY_SATISFIES, d);
//Case types
encodeTypes(d.getCaseTypes(), m, "of", d);
//Annotations
encodeAnnotations(d.getAnnotations(), d, m);
if (d.isAlias()) {
m.put("$alias", typeMap(d.getExtendedType(), d));
}
Map parent = findParent(d);
if (parent != null) {
if (!d.isToplevel() || d.isMember()) {
if (!parent.containsKey(KEY_INTERFACES)) {
parent.put(KEY_INTERFACES, new HashMap<>());
}
parent = (Map)parent.get(KEY_INTERFACES);
}
parent.put(TypeUtils.modelName(d), m);
}
return m;
}
@SuppressWarnings("unchecked")
public void encodeObject(Value d) {
Map parent = findParent(d);
if (!d.isToplevel() && parent != null) {
if (!parent.containsKey(KEY_OBJECTS)) {
parent.put(KEY_OBJECTS, new HashMap<>());
}
parent = (Map)parent.get(KEY_OBJECTS);
}
Map m = new HashMap<>();
m.put(KEY_METATYPE, METATYPE_OBJECT);
m.put(KEY_NAME, d.getName());
//Extends
m.put("super", typeMap(d.getTypeDeclaration().getExtendedType(), d));
//Satisfies
encodeTypes(d.getTypeDeclaration().getSatisfiedTypes(), m, KEY_SATISFIES, d);
//Certain annotations
encodeAnnotations(d.getAnnotations(), d, m);
if (parent != null) {
parent.put(TypeUtils.modelName(d.getTypeDeclaration()), m);
}
}
@SuppressWarnings("unchecked")
public Map encodeAttributeOrGetter(FunctionOrValue d) {
Map m = new HashMap<>();
Map parent;
final String mname = TypeUtils.modelName(d);
if (d.isToplevel() || d.isMember() || containsTypes(d)) {
parent = findParent(d);
if (parent == null) {
return null;
}
if (parent != getPackageMap(d.getUnit().getPackage())) {
final String _k = KEY_ATTRIBUTES;
if (!parent.containsKey(_k)) {
parent.put(_k, new HashMap<>());
}
parent = (Map)parent.get(_k);
}
if (parent.containsKey(mname)) {
//merge existing
m = (Map)parent.get(mname);
}
} else {
//Ignore attributes inside control blocks, methods, etc.
return null;
}
m.put(KEY_NAME, d.getName());
m.put(KEY_METATYPE, (d instanceof Value && d.isTransient()) ? METATYPE_GETTER : METATYPE_ATTRIBUTE);
m.put(KEY_TYPE, typeMap(d.getType(), d));
if (d.isDynamic()) {
m.put(KEY_DYNAMIC, 1);
}
parent.put(mname, m);
encodeAnnotations(d.getAnnotations(), d, m);
if (d instanceof Value && ((Value) d).getSetter() != null) {
Map smap = (Map)m.get("$set");
if (smap==null) {
smap = new HashMap<>();
m.put("$set", smap);
smap.put(KEY_METATYPE, METATYPE_SETTER);
encodeAnnotations(((Value)d).getSetter().getAnnotations(), ((Value)d).getSetter(), smap);
}
}
return m;
}
@SuppressWarnings("unchecked")
public Map encodeTypeAlias(TypeAlias d) {
Map parent;
if (d.isToplevel() || d.isMember()) {
parent = findParent(d);
if (parent == null) {
return null;
}
if (!d.isToplevel()) {
if (!parent.containsKey(KEY_ATTRIBUTES)) {
parent.put(KEY_ATTRIBUTES, new HashMap<>());
}
parent = (Map)parent.get(KEY_ATTRIBUTES);
}
} else {
//Ignore attributes inside control blocks, methods, etc.
return null;
}
Map m = new HashMap<>();
m.put(KEY_METATYPE, METATYPE_ALIAS);
m.put(KEY_NAME, d.getName());
List> tpl = typeParameters(d.getTypeParameters(), d);
if (tpl != null) {
m.put(KEY_TYPE_PARAMS, tpl);
}
if (d.getSelfType() != null) {
m.put(KEY_SELF_TYPE, d.getSelfType().getDeclaration().getName());
}
m.put("$alias", typeMap(d.getExtendedType(), d));
encodeTypes(d.getCaseTypes(), m, "of", d);
encodeTypes(d.getSatisfiedTypes(), m, KEY_SATISFIES, d);
encodeAnnotations(d.getAnnotations(), d, m);
parent.put(TypeUtils.modelName(d), m);
return m;
}
/** Encodes the list of types and puts them under the specified key in the map. */
private void encodeTypes(List types, Map m, String key, Declaration from) {
if (types == null || types.isEmpty()) return;
List> sats = new ArrayList<>(types.size());
for (Type st : types) {
sats.add(typeMap(st, from));
}
m.put(key, sats);
}
/** 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 annotations, Object d, Map m) {
List>> anns = m == null ? null : new ArrayList>>(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 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 com.redhat.ceylon.model.typechecker.model.Class
&& ((com.redhat.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 com.redhat.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 com.redhat.ceylon.model.typechecker.model.Package ? "$pkg-anns" : KEY_ANNOTATIONS;
m.put(key, anns);
}
return bits;
}
private void addPackage(final Map map, final String pkgName) {
if (pkgName.equals(LANGUAGE_MODULE_NAME)) {
map.put(KEY_PACKAGE, "$");
} else {
map.put(KEY_PACKAGE, pkgName);
}
}
public boolean containsTypes(Declaration d) {
for (Declaration m : d.getMembers()) {
if (m instanceof Value && ((Value)m).getTypeDeclaration().isAnonymous())return true;
if (m instanceof TypeDeclaration || containsTypes(m)) {
return true;
}
}
return false;
}
public Map getPackageMap(com.redhat.ceylon.model.typechecker.model.Package p) {
@SuppressWarnings("unchecked")
Map pkgmap = (Map)model.get(p.getNameAsString());
if (pkgmap == null) {
pkgmap = new HashMap<>();
encodeAnnotations(p.getAnnotations(), p, pkgmap);
model.put(p.getNameAsString(), pkgmap);
}
return pkgmap;
}
}