}
/** Looks up a type from model data, creating it if necessary. The returned type will have its
* type parameters substituted if needed. */
private ProducedType getTypeFromJson(Map<String, Object> m, Declaration container, List<TypeParameter> typeParams) {
TypeDeclaration td = null;
if (m.get(MetamodelGenerator.KEY_METATYPE) instanceof TypeDeclaration) {
td = (TypeDeclaration)m.get(MetamodelGenerator.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(MetamodelGenerator.KEY_NAME);
if ("$U".equals(tname)) {
m.put(MetamodelGenerator.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(MetamodelGenerator.KEY_TYPES);
final ArrayList<ProducedType> types = new ArrayList<ProducedType>(tmaps.size());
if ("u".equals(m.get("comp"))) {
UnionType ut = new UnionType(u2);
for (Map<String, Object> tmap : tmaps) {
Util.addToUnion(types, 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) {
Util.addToIntersection(types, getTypeFromJson(tmap, container, typeParams), u2);
}
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(MetamodelGenerator.KEY_PACKAGE);
if (pname == null) {
//It's a ref to a type parameter
final List<TypeParameter> containerTypeParameters = container instanceof Generic ?
((Generic)container).getTypeParameters() : null;
if (containerTypeParameters != null) {
for (TypeParameter typeParam : containerTypeParameters) {
if (typeParam.getName().equals(tname)) {
td = typeParam;
}
}
}
if (td == null) {
for (TypeParameter typeParam : typeParams) {
if (typeParam.getName().equals(tname)) {
td = typeParam;
}
}
}
} else {
String mname = (String)m.get(MetamodelGenerator.KEY_MODULE);
if ("$".equals(mname)) {
mname = Module.LANGUAGE_MODULE_NAME;
}
com.redhat.ceylon.compiler.typechecker.model.Package rp;
if ("$".equals(pname)) {
//Language module package
rp = Module.LANGUAGE_MODULE_NAME.equals(getNameAsString())? this :
getModule().getLanguageModule().getDirectPackage(Module.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).loadDeclarations();
}
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;
} else if (d instanceof MethodOrValue) {
td = ((MethodOrValue)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);
}
}
}
}
@SuppressWarnings("unchecked")
final List<Map<String,Object>> modelParms = (List<Map<String,Object>>)m.get(MetamodelGenerator.KEY_TYPE_PARAMS);
if (td != null && modelParms != null) {
//Substitute type parameters
final HashMap<TypeParameter, ProducedType> concretes = new HashMap<TypeParameter, ProducedType>();
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(MetamodelGenerator.KEY_PACKAGE) || ptparm.containsKey(MetamodelGenerator.KEY_TYPES)) {
//Substitute for proper type
final ProducedType _pt = getTypeFromJson(ptparm, container, typeParams);
if (ptparm.containsKey(MetamodelGenerator.KEY_US_VARIANCE)) {
if (variances == null) {
variances = new HashMap<>();
}
variances.put(_cparm, SiteVariance.values()[(int)ptparm.get(MetamodelGenerator.KEY_US_VARIANCE)]);
}
concretes.put(_cparm, _pt);
} else if (ptparm.containsKey(MetamodelGenerator.KEY_NAME)) {
//Look for type parameter with same name
for (TypeParameter typeParam : typeParams) {
if (typeParam.getName().equals(ptparm.get(MetamodelGenerator.KEY_NAME))) {
concretes.put(_cparm, typeParam.getType());
}
}
}
}
if (!concretes.isEmpty()) {
ProducedType rval = td.getType().substitute(concretes);
if (variances != null) {
rval.setVarianceOverrides(variances);
}
return rval;
}
}
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(MetamodelGenerator.KEY_PACKAGE), m.get(MetamodelGenerator.KEY_NAME),
m.get(MetamodelGenerator.KEY_MODULE), m, typeParams, getNameAsString()));
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
}
return td.getType();
}