slcom/slangc/model/PackageModel.sauce

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;
}
}