290 lines
9.6 KiB
Plaintext
290 lines
9.6 KiB
Plaintext
package slangc.model;
|
|
|
|
import slang.data.ComparisonOp;
|
|
import slang.data.List;
|
|
import slang.data.Map;
|
|
import slangc.api.Reporter;
|
|
import slangc.parser.Branch;
|
|
import slangc.parser.Node;
|
|
import slangc.parser.NodeType;
|
|
import slangc.parser.Token;
|
|
|
|
public class PackageModel {
|
|
private SystemModel system;
|
|
private String name;
|
|
private Map<String, TypeModel> types = new Map<String, TypeModel>();
|
|
private Map<String, SourceModel> sources = new Map<String, SourceModel>();
|
|
|
|
public PackageModel(SystemModel system, String name) {
|
|
this.system = system;
|
|
this.name = name;
|
|
if (name == null) {
|
|
throw new Error("Package name is null");
|
|
}
|
|
}
|
|
|
|
public SystemModel getSystem() {
|
|
return system;
|
|
}
|
|
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
|
|
public boolean hasType(String name) {
|
|
return types.hasKey(name);
|
|
}
|
|
|
|
public TypeModel getType(String name) {
|
|
if (hasType(name)) {
|
|
return types.get(name);
|
|
} else {
|
|
throw new Error("Internal error/TODO: Type '" + name + "' doesn't exist in package '" + getName() + "'");
|
|
}
|
|
}
|
|
|
|
public String[] getTypeNames() {
|
|
String[] result = new String[types.count()];
|
|
List<String> list = new List<String>();
|
|
list.appendList(types.keys());
|
|
list.sort(String.getDefaultComparisonOp());
|
|
return list.arrayCopy();
|
|
}
|
|
|
|
public boolean hasSource(String name) {
|
|
return sources.hasKey(name);
|
|
}
|
|
|
|
public SourceModel getSource(String name) {
|
|
if (hasSource(name)) {
|
|
return sources.get(name);
|
|
} else {
|
|
throw new Error("Internal error/TODO: Source '" + name + "' doesn't exist in package '" + getName() + "'");
|
|
}
|
|
}
|
|
|
|
public String[] getSourceNames() {
|
|
String[] result = new String[sources.count()];
|
|
List<String> list = new List<String>();
|
|
list.appendList(sources.keys());
|
|
list.sort(String.getDefaultComparisonOp());
|
|
return list.arrayCopy();
|
|
}
|
|
|
|
public int countErrors() {
|
|
int total = 0;
|
|
SourceModel[] srcs = sources.values().arrayCopy();
|
|
for(int i = 0; i < srcs.length; i++) {
|
|
total += srcs[i].countErrors();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
public int deleteErrors() {
|
|
int total = 0;
|
|
SourceModel[] srcs = sources.values().arrayCopy();
|
|
for(int i = 0; i < srcs.length; i++) {
|
|
total += srcs[i].deleteErrors();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
private void addInnerAndUntitledTypes(UserTypeModel model) {
|
|
recursiveAddInnerAndUntitledTypes(model, model.getParsed().getSubnode(model.getParsed().countSubnodes() - 2), null);
|
|
}
|
|
|
|
private void recursiveAddInnerAndUntitledTypes(UserTypeModel model, Node subnode, InnerTypeScope.SourceScope withinScope) {
|
|
if (subnode instanceof Branch) {
|
|
Branch b = (Branch) subnode;
|
|
if (b.getNodeType() == NodeType.CLASS_DECLARATION || b.getNodeType() == NodeType.INTERFACE_DECLARATION || b.getNodeType() == NodeType.ENUM_DECLARATION) {
|
|
Token name = (Token)((Branch)b.getSubnode(2)).getSubnode(0);
|
|
String shortname = name.getSnippet().getSource();
|
|
if (b.getNodeType() == NodeType.CLASS_DECLARATION || b.getNodeType() == NodeType.INTERFACE_DECLARATION) {
|
|
shortname += genericTemplateString(b.getSubnode(3));
|
|
}
|
|
TypeLevel tl = TypeLevel.INNER;
|
|
if (withinScope != null) {
|
|
shortname = shortname + "#" + model.nextUntitledNumber();
|
|
tl = TypeLevel.INNER_INNER;
|
|
}
|
|
String namestr = model.getOuterName() + ":" + shortname;
|
|
if (types.hasKey(namestr)) {
|
|
throw new Error("Internal error/TODO: Same type '" + namestr + "' (in package '" + getName() + "') defined twice");
|
|
}
|
|
UserTypeModel inner = new UserTypeModel(this, shortname, model.getSource(), b, tl, withinScope == null ? ((InnerTypeScope.SourceScope)model) : withinScope);
|
|
NodeData.of(b).setTypeDefinition(inner);
|
|
types.set(namestr, inner);
|
|
inner.setupTranslations();
|
|
addInnerAndUntitledTypes(inner);
|
|
} else if (b.getNodeType() == NodeType.NEW_CLASS_EXPRESSION) {
|
|
String shortname = "Untitled#" + model.nextUntitledNumber();
|
|
String namestr = model.getOuterName() + ":" + shortname;
|
|
if (types.hasKey(namestr)) {
|
|
throw new Error("Internal error/TODO: Same type '" + namestr + "' (in package '" + getName() + "') defined twice");
|
|
}
|
|
UserTypeModel inner = new UserTypeModel(this, shortname, model.getSource(), b, TypeLevel.UNTITLED, withinScope == null ? ((InnerTypeScope.SourceScope) model) : withinScope);
|
|
NodeData.of(b).setTypeDefinition(inner);
|
|
types.set(namestr, inner);
|
|
addInnerAndUntitledTypes(inner);
|
|
} else {
|
|
if (b.getNodeType() == NodeType.BLOCK_STATEMENT || b.getNodeType() == NodeType.SWITCH_MEMBERS) {
|
|
if (withinScope == null) {
|
|
withinScope = model.innerScopeForSource(b);
|
|
} else {
|
|
withinScope = withinScope.innerScopeForSource(b);
|
|
}
|
|
}
|
|
//System.err.println("Within method? " + withinScope);
|
|
for (int i = 0; i < b.countSubnodes(); i++) {
|
|
recursiveAddInnerAndUntitledTypes(model, b.getSubnode(i), withinScope);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void recursiveInitialiseNodeData(NodeData outer, Node subnode) {
|
|
assert(subnode.userdata == null);
|
|
NodeData d = new NodeData(outer, subnode, system);
|
|
subnode.userdata = d;
|
|
if (subnode instanceof Branch) {
|
|
Branch b = (Branch) subnode;
|
|
for (int i = 0; i < b.countSubnodes(); i++) {
|
|
recursiveInitialiseNodeData(d, b.getSubnode(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
public SyntheticTypeModel addSyntheticType(SyntheticTypeModel m) {
|
|
if (types.hasKey(m.getOuterName())) {
|
|
throw new Error("Internal error/TODO: Synthetic type '" + m.fullName() + "' collides with the name of an existing type");
|
|
}
|
|
types.set(m.getOuterName(), m);
|
|
return m;
|
|
}
|
|
|
|
public UserTypeModel addInstantiatedType(UserTypeModel m) {
|
|
if (types.hasKey(m.getOuterName())) {
|
|
throw new Error("Internal error/TODO: Instantiated type '" + m.fullName() + "' collides with the name of an existing type");
|
|
}
|
|
types.set(m.getOuterName(), m);
|
|
return m;
|
|
}
|
|
|
|
public SourceModel addSource(String filename, Branch parsed, boolean included) {
|
|
if (sources.hasKey(filename)) {
|
|
throw new Error("Internal error/TODO: Same file '" + filename + "' included twice");
|
|
}
|
|
|
|
recursiveInitialiseNodeData(null, parsed);
|
|
|
|
SourceModel s = new SourceModel(this, filename, parsed, included);
|
|
|
|
Branch u = s.getTypesBranch();
|
|
int count = u.countSubnodes();
|
|
for (int i = 0; i < count; i++) {
|
|
if (u.getSubnode(i).getNodeType() == NodeType.SEMICOLON) {
|
|
continue; // Skip this
|
|
}
|
|
//System.err.println("Adding a " + u.getSubnode(i).getNodeType());
|
|
Token name;
|
|
if (u.getSubnode(i).getNodeType() == NodeType.ATTRIBUTE_DECLARATION) {
|
|
name = (Token)((Branch)((Branch)u.getSubnode(i)).getSubnode(3)).getSubnode(0);
|
|
} else {
|
|
name = (Token)((Branch)((Branch)u.getSubnode(i)).getSubnode(2)).getSubnode(0);
|
|
}
|
|
String namestr = name.getSnippet().getSource();
|
|
if (u.getSubnode(i).getNodeType() == NodeType.CLASS_DECLARATION || u.getSubnode(i).getNodeType() == NodeType.INTERFACE_DECLARATION) {
|
|
String genstr = genericTemplateString(((Branch)((Branch)u.getSubnode(i)).getSubnode(3)));
|
|
namestr += genstr;
|
|
}
|
|
if (types.hasKey(namestr)) {
|
|
throw new Error("Internal error/TODO: Same type '" + namestr + "' (in package '" + getName() + "') defined twice");
|
|
}
|
|
UserTypeModel model = new UserTypeModel(this, namestr, s, (Branch)u.getSubnode(i), TypeLevel.OUTER, null);
|
|
NodeData.of(u.getSubnode(i)).setTypeDefinition(model);
|
|
types.set(namestr, model);
|
|
model.setupTranslations();
|
|
addInnerAndUntitledTypes(model);
|
|
/*
|
|
Branch b = (Branch)((Branch)u.getSubnode(i)).getSubnode(2);
|
|
System.out.println("Got a '" + b.getNodeType() + "'");
|
|
int count2 = b.countSubnodes();
|
|
for (int i2 = 0; i2 < count2; i2++) {
|
|
Node b2 = b.getSubnode(i2);
|
|
System.out.println("> Got a '" + b2.getNodeType() + "': " + b2);//(b2 instanceof Token ? ((Token)b2).));
|
|
}*/
|
|
}
|
|
|
|
sources.set(filename, s);
|
|
return s;
|
|
}
|
|
|
|
public static int templateArgumentCount(Node templatepart) {
|
|
if (templatepart.getNodeType() == NodeType.NO_GENERIC_DECLARATIONS) {
|
|
return 0;
|
|
} else {
|
|
Branch argpart = (Branch) ((Branch)templatepart).getSubnode(1);
|
|
int count = 0;
|
|
for (int i = 0; i < argpart.countSubnodes(); i++) {
|
|
if (argpart.getSubnode(i).getNodeType() != NodeType.COMMA) {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
}
|
|
|
|
public static String genericTemplateString(Node templatepart) {
|
|
int c = templateArgumentCount(templatepart);
|
|
if (c == 0) {
|
|
return "";
|
|
} else {
|
|
String result = "";
|
|
for (int i = 0; i < c; i++) {
|
|
if (i != 0) {
|
|
result += ",";
|
|
}
|
|
result += "?";
|
|
}
|
|
return "<" + result + ">";
|
|
}
|
|
}
|
|
|
|
public int expand() {
|
|
int total = 0;
|
|
TypeModel[] typs = types.values().arrayCopy();
|
|
for(int i = 0; i < typs.length; i++) {
|
|
total += typs[i].expand();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
public void dump(Reporter reporter, String indent, String incr) {
|
|
reporter.note("DUMP", indent + "> Package '" + getName() + "'");
|
|
String[] typs = getTypeNames();
|
|
for (int i = 0; i < typs.length; i++) {
|
|
getType(typs[i]).dump(reporter, indent + incr, incr);
|
|
}
|
|
}
|
|
|
|
public int resolveTypes() {
|
|
int total = 0;
|
|
TypeModel[] typs = types.values().arrayCopy();
|
|
for(int i = 0; i < typs.length; i++) {
|
|
total += typs[i].resolveTypes();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
public int resolveExpressions(boolean includingReferences) {
|
|
int total = 0;
|
|
TypeModel[] typs = types.values().arrayCopy();
|
|
for(int i = 0; i < typs.length; i++) {
|
|
if (includingReferences || !typs[i].isReferenceOnly()) {
|
|
total += typs[i].resolveExpressions();
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
}
|