Initial commit of main compiler sources (or should I say ... SAUCES!)
This commit is contained in:
BIN
slangc/.DS_Store
vendored
Normal file
BIN
slangc/.DS_Store
vendored
Normal file
Binary file not shown.
1646
slangc/api/BytecodeHeap.sauce
Normal file
1646
slangc/api/BytecodeHeap.sauce
Normal file
File diff suppressed because it is too large
Load Diff
1023
slangc/api/BytecodeInstructionWriter.sauce
Normal file
1023
slangc/api/BytecodeInstructionWriter.sauce
Normal file
File diff suppressed because it is too large
Load Diff
29
slangc/api/BytecodeOutput.sauce
Normal file
29
slangc/api/BytecodeOutput.sauce
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
public abstract class BytecodeOutput {
|
||||||
|
protected int count = 0;
|
||||||
|
public abstract void endOfFile();
|
||||||
|
public abstract void processByte(byte b);
|
||||||
|
|
||||||
|
public final void write8(byte b) {
|
||||||
|
processByte(b);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write16(short w) {
|
||||||
|
write8((byte)w);
|
||||||
|
write8((byte)(w >> 8));
|
||||||
|
}
|
||||||
|
public void write32(int w) {
|
||||||
|
write16((short)w);
|
||||||
|
write16((short)(w >> 16));
|
||||||
|
}
|
||||||
|
public void write64(long w) {
|
||||||
|
write32((int)w);
|
||||||
|
write32((int)(w >> 32));
|
||||||
|
}
|
||||||
|
}
|
339
slangc/api/BytecodeTarget.sauce
Normal file
339
slangc/api/BytecodeTarget.sauce
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
import slang.data.List;
|
||||||
|
import slang.data.Map;
|
||||||
|
import slangc.api.BytecodeHeap;
|
||||||
|
import slangc.bytecode.MethodSignature;
|
||||||
|
import slangc.bytecode.TypeSignature;
|
||||||
|
import slangc.model.FieldModel;
|
||||||
|
import slangc.model.Flags;
|
||||||
|
import slangc.model.MethodModel;
|
||||||
|
import slangc.model.ParameterModel;
|
||||||
|
import slangc.model.UserTypeModel;
|
||||||
|
import slangc.model.statements.BlockStatement;
|
||||||
|
import slangc.model.BuiltinTypeModel;
|
||||||
|
|
||||||
|
public class BytecodeTarget extends CompilerTarget {
|
||||||
|
final BytecodeHeap heap;
|
||||||
|
final BytecodeOutput output;
|
||||||
|
private final List<ReprocessType> types = new List<ReprocessType>();
|
||||||
|
|
||||||
|
private final Map<TypeSignature,BytecodeInstructionWriter.StackType> cachedStackTypes = new Map<TypeSignature,BytecodeInstructionWriter.StackType>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public BytecodeInstructionWriter.StackType stackType(TypeSignature type) {
|
||||||
|
if (!cachedStackTypes.hasKey(type)) {
|
||||||
|
BytecodeInstructionWriter.StackType t = calculateStackType(type);
|
||||||
|
cachedStackTypes.set(type, t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
return cachedStackTypes.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytecodeInstructionWriter.StackType calculateStackType(TypeSignature type) {
|
||||||
|
if (type.mappableEquals(TypeSignature.VOID)) {
|
||||||
|
return BytecodeInstructionWriter.StackType.VOID;
|
||||||
|
} /*else if (type.mappableEquals(getSystem().getDefaultBooleanType().getTypeSignature())) {
|
||||||
|
return BytecodeInstructionWriter.StackType.BIT;
|
||||||
|
} else if (type.mappableEquals(getSystem().getDefaultFloat32Type().getTypeSignature())) {
|
||||||
|
return BytecodeInstructionWriter.StackType.FLOAT32;
|
||||||
|
} else if (type.mappableEquals(getSystem().getDefaultFloat64Type().getTypeSignature())) {
|
||||||
|
return BytecodeInstructionWriter.StackType.FLOAT64;
|
||||||
|
} else if (type.mappableEquals(getSystem().getDefaultInt64Type().getTypeSignature())) {
|
||||||
|
return BytecodeInstructionWriter.StackType.INT64;
|
||||||
|
} else if (getSystem().matchesTypeOption(TypeOption.Kind.DUCK, type)) {
|
||||||
|
return BytecodeInstructionWriter.StackType.DUCK;
|
||||||
|
}*/ else if (getSystem().getType(type) instanceof BuiltinTypeModel) {
|
||||||
|
for (int i = 0; i < BytecodeInstructionWriter.StackType.lookupCount(BytecodeInstructionWriter.StackType.class); i++) {
|
||||||
|
if (getSystem().matchesTypeOption((TypeOption.Kind)TypeOption.Kind.lookup(TypeOption.Kind.class, i), type)) {
|
||||||
|
return (BytecodeInstructionWriter.StackType)BytecodeInstructionWriter.StackType.lookup(BytecodeInstructionWriter.StackType.class, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BytecodeInstructionWriter.StackType.INT32;
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < BytecodeInstructionWriter.StackType.lookupCount(BytecodeInstructionWriter.StackType.class); i++) {
|
||||||
|
if (getSystem().matchesTypeOption((TypeOption.Kind)TypeOption.Kind.lookup(TypeOption.Kind.class, i), type)) {
|
||||||
|
return (BytecodeInstructionWriter.StackType)BytecodeInstructionWriter.StackType.lookup(BytecodeInstructionWriter.StackType.class, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BytecodeInstructionWriter.StackType.OBJECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ReprocessType {
|
||||||
|
UserTypeModel type;
|
||||||
|
boolean addToMainList;
|
||||||
|
|
||||||
|
ReprocessType(UserTypeModel type, boolean addToMainList) {
|
||||||
|
this.type = type;
|
||||||
|
this.addToMainList = addToMainList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytecodeTarget(BytecodeOutput output, BytecodeHeap heap) {
|
||||||
|
this.output = output;
|
||||||
|
this.heap = heap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytecodeTarget(BytecodeOutput output) {
|
||||||
|
this(output, new BytecodeHeap(1000000000, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateFieldInitialisers(UserTypeModel t, BytecodeInstructionWriter w, boolean isStaticInit) {
|
||||||
|
for (int i = 0; i < t.countFieldMembers(); i++) {
|
||||||
|
FieldModel f = t.getFieldMember(i);
|
||||||
|
if (isStaticInit && f.isEnumField()) {
|
||||||
|
w.genNewObject(t.getDefaultInstanceConstructor().getMethodSignature());
|
||||||
|
w.genStore(f.getFieldSignature());
|
||||||
|
} else if (f.hasInitialiser() && f.isStatic() == isStaticInit) {
|
||||||
|
TypeSignature storing = f.getInitialisationExpression().generate(w);
|
||||||
|
if (!storing.mappableEquals(f.getStorageType().getTypeSignature())) {
|
||||||
|
w.genConvert(storing, f.getStorageType().getTypeSignature());
|
||||||
|
storing = f.getStorageType().getTypeSignature();
|
||||||
|
}
|
||||||
|
if (!f.isStatic()) {
|
||||||
|
w.genThis();
|
||||||
|
}
|
||||||
|
w.genStore(f.getFieldSignature());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visitField(BytecodeHeap.ObjectLike typ, FieldModel m) {
|
||||||
|
BytecodeHeap.ObjectLike member = heap.newField(typ, m.getFlags(), m.getFieldSignature());
|
||||||
|
for (int i = 0; i < m.getAttributes().countTranslations(); i++) {
|
||||||
|
heap.addMemberTranslation(member, m.getAttributes().getTranslation(i).language, m.getAttributes().getTranslation(i).name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visitMethod(BytecodeHeap.ObjectLike typ, MethodModel m) {
|
||||||
|
BytecodeHeap.ObjectLike member = heap.newMethod(typ, m.getFlags(), m.getMethodSignature(), m.countLocals());
|
||||||
|
for (int i = 0; i < m.getAttributes().countTranslations(); i++) {
|
||||||
|
heap.addMemberTranslation(member, m.getAttributes().getTranslation(i).language, m.getAttributes().getTranslation(i).name);
|
||||||
|
}
|
||||||
|
if (m.hasBody() || m.isConstructor()) {
|
||||||
|
BytecodeInstructionWriter w = new BytecodeInstructionWriter(this, m.getOwner(), member);
|
||||||
|
w.pushSource(m.getSource());
|
||||||
|
boolean initAfterFirstStatement = false;
|
||||||
|
if (m.isStaticInitialisation()) {
|
||||||
|
generateFieldInitialisers((UserTypeModel)m.getOwner(), w, true);
|
||||||
|
} else if (m.isConstructor()) {
|
||||||
|
if (m.checkExplicitBaseConstructorCall(true)) {
|
||||||
|
// This will have "approved" the constructor call location,
|
||||||
|
// But we need to check if it was actually a super(...) call
|
||||||
|
// (and not a call to another this(...) constructor)
|
||||||
|
// before we go around re-initialising any already-initialised fields!
|
||||||
|
if (m.checkExplicitBaseConstructorCall(false)) {
|
||||||
|
initAfterFirstStatement = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m.hasBody()) {
|
||||||
|
w.genDefaultSuperConstructorCall();
|
||||||
|
} else {
|
||||||
|
// This handles synthetic constructors
|
||||||
|
// These naturally pass all arguments to the super-constructor
|
||||||
|
for (int i = 0; i < m.countParameters(); i++) {
|
||||||
|
ParameterModel p = m.getParameter(i);
|
||||||
|
w.genLoadLocalOrParam(p.getStorageType().getTypeSignature(), p.getIndex());
|
||||||
|
}
|
||||||
|
w.genNestedConstructorCall(m.getPrototype().getMethodSignature());
|
||||||
|
}
|
||||||
|
generateFieldInitialisers((UserTypeModel)m.getOwner(), w, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m.countExceptions() > 0) {
|
||||||
|
BytecodeHeap.ObjectLike o = getHeap().newObjectLike(BytecodeHeap.StandardClass.SIMPLEARRAY, m.countExceptions());
|
||||||
|
for (int i = 0; i < m.countExceptions(); i++) {
|
||||||
|
o.setElement(i, getHeap().getTypeSignature(m.getException(i).getTypeSignature()));
|
||||||
|
}
|
||||||
|
member.setElement(BytecodeHeap.MethodFields.THROWS.value, o);
|
||||||
|
}
|
||||||
|
if (m.hasBody()) {
|
||||||
|
/* Manually loop through statements to ensure fields are initialised if needed. */
|
||||||
|
if (m.getBody() instanceof BlockStatement) {
|
||||||
|
BlockStatement block = (BlockStatement) m.getBody();
|
||||||
|
w.pushSource(block.getSource());
|
||||||
|
if (block.countInnerStatements() == 0 && initAfterFirstStatement) {
|
||||||
|
generateFieldInitialisers((UserTypeModel)m.getOwner(), w, false);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < block.countInnerStatements(); i++) {
|
||||||
|
block.getInnerStatement(i).generate(w);
|
||||||
|
if (i == 0 && initAfterFirstStatement) {
|
||||||
|
generateFieldInitialisers((UserTypeModel)m.getOwner(), w, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.popSource();
|
||||||
|
} else {
|
||||||
|
m.getBody().generate(w);
|
||||||
|
if (initAfterFirstStatement) {
|
||||||
|
generateFieldInitialisers((UserTypeModel)m.getOwner(), w, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.genEnd();
|
||||||
|
w.popSource(m.getSource());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateImplicitStaticInit(UserTypeModel m, BytecodeHeap.ObjectLike typ) {
|
||||||
|
int flags = Flags.MASK_METHOD | Flags.MASK_CONSTRUCTOR | Flags.MASK_STATIC | Flags.MASK_SYNTHETIC;
|
||||||
|
BytecodeHeap.ObjectLike member = heap.newMethod(typ, flags, new MethodSignature(m.getTypeSignature(), MethodSignature.Kind.STATIC_INIT, TypeSignature.VOID, "static-init", new TypeSignature[0]), 0);
|
||||||
|
BytecodeInstructionWriter w = new BytecodeInstructionWriter(this, m, member);
|
||||||
|
w.pushSource(m.getParsed());
|
||||||
|
generateFieldInitialisers(m, w, true);
|
||||||
|
w.genEnd();
|
||||||
|
w.popSource(m.getParsed());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitProvidesOrDepends(ProvidesOrDepends x) {
|
||||||
|
if (x.provides) {
|
||||||
|
heap.newProvides(x.name, x.version);
|
||||||
|
} else {
|
||||||
|
heap.newDepends(x.name, x.version, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMeta(boolean important, String key, String value) {
|
||||||
|
heap.newMetadata(important, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitTypeOption(TypeOption o) {
|
||||||
|
heap.registerRuntimeType(o.kind.value, o.kind.value, o.getTypeSignature(), o.formatopt, o.isBuiltin, o.isNumber, o.isFloat, o.isSigned, o.nbits);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDataFile(DataFile dataFile) {
|
||||||
|
heap.newFile(dataFile.packagename, dataFile.innername, dataFile.data, dataFile.typeinfo, dataFile.debugname);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitType(UserTypeModel m, boolean addToMainList) {
|
||||||
|
types.append(new ReprocessType(m, addToMainList));
|
||||||
|
dryRun(m, addToMainList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean firstDryRun = true;
|
||||||
|
private void dryRun(UserTypeModel m, boolean addToMainList) {
|
||||||
|
if (firstDryRun) {
|
||||||
|
for (int i = 0; i <= 1024; i++) {
|
||||||
|
//heap.getConstInt32(""+i);
|
||||||
|
}
|
||||||
|
firstDryRun = false;
|
||||||
|
}
|
||||||
|
heap.getTypeSignature(m.getTypeSignature());
|
||||||
|
|
||||||
|
for (int i = 0; i < m.countFieldMembers(); i++) {
|
||||||
|
FieldModel f = m.getFieldMember(i);
|
||||||
|
heap.getFieldSignature(f.getFieldSignature());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m.countMethodMembers(); i++) {
|
||||||
|
MethodModel mt = m.getMethodMember(i);
|
||||||
|
if (!mt.isStaticInitialisation()) {
|
||||||
|
//Log.line("For " + mt.toString() + "[" + mt.getMethodSignature().toString() + "] got " + heap.getMethodSignature(mt.getMethodSignature()).debugString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processType(UserTypeModel m, boolean addToMainList) {
|
||||||
|
BytecodeHeap.ObjectLike typ = heap.newType(m.getFlags(), m.getTypeSignature());
|
||||||
|
if (m.getBaseClass() != null) {
|
||||||
|
typ.setElement(2, heap.getTypeSignature(m.getBaseClass().getTypeSignature()));
|
||||||
|
}
|
||||||
|
if (m.countInterfaces() > 0) {
|
||||||
|
BytecodeHeap.ObjectLike ifcs = heap.newObjectLike(BytecodeHeap.StandardClass.SIMPLEARRAY, m.countInterfaces());
|
||||||
|
typ.setElement(3, ifcs);
|
||||||
|
for (int i = 0; i < m.countInterfaces(); i++) {
|
||||||
|
ifcs.setElement(i, heap.getTypeSignature(m.getInterface(i).getTypeSignature()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m.getSource() != null) {
|
||||||
|
typ.setElement(BytecodeHeap.TypeFields.FILENAME.value, heap.getConstString(m.getSource().getFilename()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m.countFieldMembers(); i++) {
|
||||||
|
FieldModel f = m.getFieldMember(i);
|
||||||
|
visitField(typ, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean explicitStaticInit = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < m.countMethodMembers(); i++) {
|
||||||
|
MethodModel mt = m.getMethodMember(i);
|
||||||
|
if (mt.isStaticInitialisation()) {
|
||||||
|
explicitStaticInit = true;
|
||||||
|
}
|
||||||
|
visitMethod(typ, mt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!explicitStaticInit) {
|
||||||
|
generateImplicitStaticInit(m, typ);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addToMainList) {
|
||||||
|
getHeap().getEntrypointsArray().appendElement(typ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
for (int i = 0; i < types.count(); i++) {
|
||||||
|
Log.line("Reprocessing type #" + i);
|
||||||
|
ReprocessType t = types.get(i);
|
||||||
|
Log.line("Reprocessing type " + t.type.toString());
|
||||||
|
processType(t.type, t.addToMainList);
|
||||||
|
}
|
||||||
|
Log.line("FINISHING: " + quickReport());
|
||||||
|
Log.line("in BytecodeTaget...");
|
||||||
|
if (output != null) {
|
||||||
|
heap.writeAll(output, "#!/usr/bin/env testvm", 3, 256, 1, 1);
|
||||||
|
output.endOfFile();
|
||||||
|
} else {
|
||||||
|
Log.line("NO OUTPUT??");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String strbytes(int size) {
|
||||||
|
int orig = size;
|
||||||
|
String result = "";
|
||||||
|
|
||||||
|
if (size > 1024*1024) {
|
||||||
|
result += (size/(1024*1024)) + " MB";
|
||||||
|
size %= (1024*1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > 1024) {
|
||||||
|
if (!result.equals("")) {
|
||||||
|
result += " ";
|
||||||
|
}
|
||||||
|
result += (size/1024) + " KB";
|
||||||
|
size %= 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size != 0 || result.equals("")) {
|
||||||
|
if (!result.equals("")) {
|
||||||
|
result += " ";
|
||||||
|
}
|
||||||
|
result += size + " bytes";
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result += " (" + /*String.format("%.4f",*/ (orig / (1024.0*1024.0)) + "MB)";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String quickReport() {
|
||||||
|
return "Object table " + strbytes(heap.objectTableSize(3)) + " (" + (heap.highestUsedRecordIndex() + 1) + " entries), index size " + strbytes(heap.objectTableIndexSize(3, 256)) + ", data section " + strbytes(heap.dataSize(1)) + ": total file size " + strbytes(heap.fileSize(3, 256, 1, 1)) /*heap.objectTableSize(3) + heap.objectTableIndexSize(3, 256) + heap.dataSize(1))*/;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytecodeHeap getHeap() {
|
||||||
|
return heap;
|
||||||
|
}
|
||||||
|
}
|
13
slangc/api/CacheManager.sauce
Normal file
13
slangc/api/CacheManager.sauce
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
import slang.streams.SyncInput;
|
||||||
|
import slang.streams.SyncOutput;
|
||||||
|
|
||||||
|
public class CacheManager {
|
||||||
|
public SyncInput<byte> getInput(String cacheName) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public SyncOutput<byte> getOutput(String cacheName) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
34
slangc/api/CompilerPackage.sauce
Normal file
34
slangc/api/CompilerPackage.sauce
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
import slangc.codegraph.DynamicPackage;
|
||||||
|
|
||||||
|
public class CompilerPackage extends DynamicPackage {
|
||||||
|
private Unit[] units = new Unit[0];
|
||||||
|
|
||||||
|
public CompilerPackage() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompilerSet getEnclosingContainer() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return (CompilerSet) super.getEnclosingContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countUnits() {
|
||||||
|
return units.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addUnit(Unit u) {
|
||||||
|
if (u.getPackageName().equals(getSimpleName())) {
|
||||||
|
Unit[] nunits = new Unit[units.length + 1];
|
||||||
|
for (int i = 0; i < units.length; i++) {
|
||||||
|
nunits[i] = units[i];
|
||||||
|
}
|
||||||
|
nunits[nunits.length - 1] = u;
|
||||||
|
units = nunits;
|
||||||
|
} else {
|
||||||
|
throw new Error("Package name mismatch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
slangc/api/CompilerSet.sauce
Normal file
43
slangc/api/CompilerSet.sauce
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
import slangc.codegraph.DynamicSet;
|
||||||
|
|
||||||
|
public class CompilerSet extends DynamicSet {
|
||||||
|
|
||||||
|
public CompilerSet() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompilerWorld getEnclosingContainer() {
|
||||||
|
return (CompilerWorld) super.getEnclosingContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompilerPackage getNamedElement(int index) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return (CompilerPackage) super.getNamedElement(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompilerPackage findPackageOrNull(String name) {
|
||||||
|
for (int i = 0; i < countNamedElements(); i++) {
|
||||||
|
CompilerPackage p = getNamedElement(i);
|
||||||
|
if (p.getSimpleName().equals(name)) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompilerPackage findPackageOrCreate(String name) {
|
||||||
|
CompilerPackage result = findPackageOrNull(name);
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
result = new CompilerPackage();
|
||||||
|
result.setSimpleName(name);
|
||||||
|
appendNamedElement(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
34
slangc/api/CompilerTarget.sauce
Normal file
34
slangc/api/CompilerTarget.sauce
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
import slangc.model.SystemModel;
|
||||||
|
import slangc.model.UserTypeModel;
|
||||||
|
|
||||||
|
public abstract class CompilerTarget {
|
||||||
|
private SystemModel system;
|
||||||
|
|
||||||
|
public CompilerTarget() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void visitType(UserTypeModel m, boolean addToMainList);
|
||||||
|
|
||||||
|
public abstract void finish();
|
||||||
|
|
||||||
|
public abstract String quickReport();
|
||||||
|
|
||||||
|
public SystemModel getSystem() {
|
||||||
|
return system;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSystem(SystemModel system) {
|
||||||
|
this.system = system;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void visitDataFile(DataFile dataFile);
|
||||||
|
|
||||||
|
public abstract void visitProvidesOrDepends(ProvidesOrDepends x);
|
||||||
|
|
||||||
|
public abstract void visitMeta(boolean important, String key, String value);
|
||||||
|
|
||||||
|
public abstract void visitTypeOption(TypeOption o);
|
||||||
|
}
|
766
slangc/api/CompilerWorld.sauce
Normal file
766
slangc/api/CompilerWorld.sauce
Normal file
@ -0,0 +1,766 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
import slangc.codegraph.DynamicSet;
|
||||||
|
import slangc.codegraph.DynamicWorld;
|
||||||
|
import slangc.model.BuiltinTypeBehaviour;
|
||||||
|
import slangc.model.PackageModel;
|
||||||
|
import slangc.model.SystemModel;
|
||||||
|
import slangc.model.TypeModel;
|
||||||
|
import slangc.model.MethodModel;
|
||||||
|
import slangc.model.UserTypeModel;
|
||||||
|
import slangc.parser.Language;
|
||||||
|
import slangc.parser.Source;
|
||||||
|
|
||||||
|
public class CompilerWorld extends DynamicWorld {
|
||||||
|
private Reporter reporter = null;
|
||||||
|
private Unit[] includedSources = new Unit[0];
|
||||||
|
private Unit[] referencedSources = new Unit[0];
|
||||||
|
private DynamicSet referencedSet;
|
||||||
|
private DynamicSet includedSet;
|
||||||
|
private Language language = new Language();
|
||||||
|
private CompilerTarget target = null;
|
||||||
|
private String[] sourceExtensions = new String[0];
|
||||||
|
private String[] dataExtensions = new String[0];
|
||||||
|
private String[] ignoreExtensions = new String[0];
|
||||||
|
private DataFile[] dataFiles = new DataFile[0];
|
||||||
|
private ProvidesOrDepends[] providesDepends = new ProvidesOrDepends[0];
|
||||||
|
private String[] globalImports = new String[0];
|
||||||
|
private MetaOrAlias[] aliasTypes = new MetaOrAlias[0];
|
||||||
|
private MetaOrAlias[] aliasPackages = new MetaOrAlias[0];
|
||||||
|
private MetaOrAlias[] importantMeta = new MetaOrAlias[0];
|
||||||
|
private MetaOrAlias[] otherMeta = new MetaOrAlias[0];
|
||||||
|
private TypeOption[] typeOptions = new TypeOption[0];
|
||||||
|
private String[] mainTypes = new String[0];
|
||||||
|
private CacheManager cacheManager = new CacheManager();
|
||||||
|
|
||||||
|
public CompilerWorld() {
|
||||||
|
referencedSet = new DynamicSet();
|
||||||
|
referencedSet.setSimpleName("<referenced>");
|
||||||
|
appendNamedElement(referencedSet);
|
||||||
|
includedSet = new DynamicSet();
|
||||||
|
includedSet.setSimpleName("<included>");
|
||||||
|
appendNamedElement(includedSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheManager getCacheManager() {
|
||||||
|
return cacheManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCacheManager(CacheManager m) {
|
||||||
|
cacheManager = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int errorVerbosity = 5;
|
||||||
|
|
||||||
|
public void setErrorVerbosity(int i) {
|
||||||
|
errorVerbosity = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] arrayLengthNames = null;
|
||||||
|
|
||||||
|
public void addArrayLengthName(String n) {
|
||||||
|
// NOTE: Adding any names will clear the default "length" definition!
|
||||||
|
if (arrayLengthNames == null) {
|
||||||
|
arrayLengthNames = new String[]{n};
|
||||||
|
} else {
|
||||||
|
String[] narr = new String[arrayLengthNames.length + 1];
|
||||||
|
for (int i = 0; i < arrayLengthNames.length; i++) {
|
||||||
|
narr[i] = arrayLengthNames[i];
|
||||||
|
}
|
||||||
|
narr[narr.length-1] = n;
|
||||||
|
arrayLengthNames = narr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(CompilerTarget t) {
|
||||||
|
this.target = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompilerTarget getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] addPatternArray(String[] arr, String ext) {
|
||||||
|
for (int i = 0; i < arr.length; i++) {
|
||||||
|
if (arr[i].equals(ext)) {
|
||||||
|
return arr; // No need to add.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String[] r = new String[arr.length + 1];
|
||||||
|
for (int i = 0; i < r.length; i++) {
|
||||||
|
if (i < arr.length) {
|
||||||
|
r[i] = arr[i];
|
||||||
|
} else {
|
||||||
|
r[i] = ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSourcePattern(String ext) {
|
||||||
|
sourceExtensions = addPatternArray(sourceExtensions, ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDataPattern(String ext) {
|
||||||
|
dataExtensions = addPatternArray(dataExtensions, ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addIgnorePattern(String ext) {
|
||||||
|
ignoreExtensions = addPatternArray(ignoreExtensions, ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchesPatternArray(String[] exts, String name) {
|
||||||
|
for (int i = 0; i < exts.length; i++) {
|
||||||
|
if (exts[i].startsWith("*")) {
|
||||||
|
//System.err.println("Testing '" + name + "' against extension '" + exts[i].sub(1) + "'");
|
||||||
|
if (name.endsWith(exts[i].sub(1))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//System.err.println("Testing '" + name + "' against '" + exts[i] + "'");
|
||||||
|
if (name.equals(exts[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesSourcePattern(String filename) {
|
||||||
|
return matchesPatternArray(sourceExtensions, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesDataPattern(String filename) {
|
||||||
|
return matchesPatternArray(dataExtensions, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesIgnorePattern(String filename) {
|
||||||
|
return matchesPatternArray(ignoreExtensions, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addGlobalImport(String x) {
|
||||||
|
String[] newarr = new String[globalImports.length + 1];
|
||||||
|
for (int i = 0; i < newarr.length; i++) {
|
||||||
|
if (i < globalImports.length) {
|
||||||
|
newarr[i] = globalImports[i];
|
||||||
|
} else {
|
||||||
|
newarr[i] = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
globalImports = newarr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addProvidesOrdepends(ProvidesOrDepends x) {
|
||||||
|
ProvidesOrDepends[] newarr = new ProvidesOrDepends[providesDepends.length + 1];
|
||||||
|
for (int i = 0; i < newarr.length; i++) {
|
||||||
|
if (i < providesDepends.length) {
|
||||||
|
newarr[i] = providesDepends[i];
|
||||||
|
} else {
|
||||||
|
newarr[i] = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
providesDepends = newarr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addProvidesVersion(String name, String version) {
|
||||||
|
addProvidesOrdepends(new ProvidesOrDepends(true, name, version));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDependsVersion(String name, String version) {
|
||||||
|
addProvidesOrdepends(new ProvidesOrDepends(false, name, version));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTypeOption(TypeOption o) {
|
||||||
|
TypeOption[] r = new TypeOption[typeOptions.length + 1];
|
||||||
|
for (int i = 0; i < r.length; i++) {
|
||||||
|
if (i < typeOptions.length) {
|
||||||
|
r[i] = typeOptions[i];
|
||||||
|
} else {
|
||||||
|
r[i] = o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typeOptions = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSpecialType(TypeOption.Kind kind, String typename, String formatOptions) {
|
||||||
|
addTypeOption(new TypeOption(kind, typename, formatOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addBuiltinType(TypeOption.Kind kind, String typename, String formatOptions, boolean isDuck, boolean isNumber, boolean isFloat, boolean isSigned, int nbits) {
|
||||||
|
addTypeOption(new TypeOption(kind, typename, formatOptions, true, isDuck, isNumber, isFloat, isSigned, nbits));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addBuiltinType(TypeOption.Kind kind, String typename, String formatOptions) {
|
||||||
|
switch (kind) {
|
||||||
|
case TypeOption.Kind.BIT:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, false, false, false, 1);
|
||||||
|
break;
|
||||||
|
case TypeOption.Kind.INT8:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, true, false, true, 8);
|
||||||
|
break;
|
||||||
|
case TypeOption.Kind.INT16:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, true, false, true, 16);
|
||||||
|
break;
|
||||||
|
case TypeOption.Kind.INT32:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, true, false, true, 32);
|
||||||
|
break;
|
||||||
|
case TypeOption.Kind.INT64:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, true, false, true, 64);
|
||||||
|
break;
|
||||||
|
case TypeOption.Kind.UINT8:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, true, false, false, 8);
|
||||||
|
break;
|
||||||
|
case TypeOption.Kind.UINT16:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, true, false, false, 16);
|
||||||
|
break;
|
||||||
|
case TypeOption.Kind.UINT32:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, true, false, false, 32);
|
||||||
|
break;
|
||||||
|
case TypeOption.Kind.UINT64:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, true, false, false, 64);
|
||||||
|
break;
|
||||||
|
case TypeOption.Kind.FLOAT32:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, true, true, true, 32);
|
||||||
|
break;
|
||||||
|
case TypeOption.Kind.FLOAT64:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, true, true, true, 64);
|
||||||
|
break;
|
||||||
|
case TypeOption.Kind.DUCK:
|
||||||
|
addBuiltinType(kind, typename, formatOptions, false, true, true, true, 64);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("No default behaviour for " + kind + " as a builtin type, must provide specific behaviour information");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* system.addBuiltinType("fencom.stdlib", "bit", new BuiltinTypeBehaviour());
|
||||||
|
|
||||||
|
system.addBuiltinType("fencom.stdlib", "int8", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 8));
|
||||||
|
system.addBuiltinType("fencom.stdlib", "int16", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 16));
|
||||||
|
system.addBuiltinType("fencom.stdlib", "int32", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 32));
|
||||||
|
system.addBuiltinType("fencom.stdlib", "int64", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 64));
|
||||||
|
|
||||||
|
system.addBuiltinType("fencom.stdlib", "uint8", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 8));
|
||||||
|
system.addBuiltinType("fencom.stdlib", "uint16", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 16));
|
||||||
|
system.addBuiltinType("fencom.stdlib", "uint32", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 32));
|
||||||
|
system.addBuiltinType("fencom.stdlib", "uint64", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 64));
|
||||||
|
|
||||||
|
system.addBuiltinType("fencom.stdlib", "float32", new BuiltinTypeBehaviour.NumberBehaviour(true, true, 32));
|
||||||
|
system.addBuiltinType("fencom.stdlib", "float64", new BuiltinTypeBehaviour.NumberBehaviour(true, true, 64));
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private MetaOrAlias[] addMetaOrAliasArray(MetaOrAlias[] arr, MetaOrAlias ext) {
|
||||||
|
MetaOrAlias[] r = new MetaOrAlias[arr.length + 1];
|
||||||
|
for (int i = 0; i < r.length; i++) {
|
||||||
|
if (i < arr.length) {
|
||||||
|
r[i] = arr[i];
|
||||||
|
} else {
|
||||||
|
r[i] = ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMeta(boolean important, String key, String value) {
|
||||||
|
if (important) {
|
||||||
|
importantMeta = addMetaOrAliasArray(importantMeta, new MetaOrAlias(key, value));
|
||||||
|
} else {
|
||||||
|
otherMeta = addMetaOrAliasArray(otherMeta, new MetaOrAlias(key, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAliasType(String aliasName, String targetName) {
|
||||||
|
aliasTypes = addMetaOrAliasArray(aliasTypes, new MetaOrAlias(aliasName, targetName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAliasPackage(String aliasName, String targetName) {
|
||||||
|
aliasPackages = addMetaOrAliasArray(aliasPackages, new MetaOrAlias(aliasName, targetName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMainType(String typeName) {
|
||||||
|
String[] newarr = new String[mainTypes.length + 1];
|
||||||
|
for (int i = 0; i < newarr.length; i++) {
|
||||||
|
if (i < mainTypes.length) {
|
||||||
|
newarr[i] = mainTypes[i];
|
||||||
|
} else {
|
||||||
|
newarr[i] = typeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mainTypes = newarr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDataFile(String packagename, String innername, byte[] data, String typeinfo, String debugname) {
|
||||||
|
DataFile[] newarr = new DataFile[dataFiles.length + 1];
|
||||||
|
for (int i = 0; i < newarr.length; i++) {
|
||||||
|
if (i < dataFiles.length) {
|
||||||
|
newarr[i] = dataFiles[i];
|
||||||
|
} else {
|
||||||
|
newarr[i] = new DataFile(packagename, innername, data, typeinfo, debugname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataFiles = newarr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSource(Source source, boolean referenceOnly) {
|
||||||
|
if (referenceOnly) {
|
||||||
|
Unit[] nsources = new Unit[referencedSources.length + 1];
|
||||||
|
for (int i = 0; i < referencedSources.length; i++) {
|
||||||
|
nsources[i] = referencedSources[i];
|
||||||
|
}
|
||||||
|
nsources[nsources.length - 1] = new Unit(this, source);
|
||||||
|
referencedSources = nsources;
|
||||||
|
} else {
|
||||||
|
Unit[] nsources = new Unit[includedSources.length + 1];
|
||||||
|
for (int i = 0; i < includedSources.length; i++) {
|
||||||
|
nsources[i] = includedSources[i];
|
||||||
|
}
|
||||||
|
nsources[nsources.length - 1] = new Unit(this, source);
|
||||||
|
includedSources = nsources;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompilerSet getNamedElement(int index) {
|
||||||
|
return (CompilerSet) super.getNamedElement(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Reporter getReporter() {
|
||||||
|
if (reporter == null) {
|
||||||
|
reporter = new NullReporter();
|
||||||
|
}
|
||||||
|
return reporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReporter(Reporter reporter) {
|
||||||
|
this.reporter = reporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String pkgname(String fullname) {
|
||||||
|
int l = fullname.searchLast(".");
|
||||||
|
if (l < 0) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return fullname.sub(0, l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String typname(String fullname) {
|
||||||
|
int l = fullname.searchLast(".");
|
||||||
|
if (l < 0) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return fullname.sub(l + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builds the sources, returning true if completed or false otherwise (errors will be reported to the reporter).
|
||||||
|
*
|
||||||
|
* @return true if completed successfully, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean build() {
|
||||||
|
int i; // Reused for many small top-level loops.
|
||||||
|
/*
|
||||||
|
getReporter().note("STAGE", "Scanning referenced sources");
|
||||||
|
for (i = 0; i < referencedSources.length; i++) {
|
||||||
|
getReporter().note("STAGE-PART", referencedSources[i].getFilename());
|
||||||
|
referencedSources[i].scan();
|
||||||
|
}
|
||||||
|
getReporter().note("STAGE", "Scanning included sources");
|
||||||
|
for (i = 0; i < includedSources.length; i++) {
|
||||||
|
getReporter().note("STAGE-PART", includedSources[i].getFilename());
|
||||||
|
includedSources[i].scan();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
getReporter().note("STAGE", "Parsing referenced sources");
|
||||||
|
for (i = 0; i < referencedSources.length; i++) {
|
||||||
|
getReporter().note("STAGE-PART", referencedSources[i].getFilename());
|
||||||
|
referencedSources[i].parse();
|
||||||
|
try {
|
||||||
|
getReporter().note("CACHE", "Using cache filename " + referencedSources[i].getCacheName() + " for " + referencedSources[i].getFilename());
|
||||||
|
if (referencedSources[i].updateCache()) {
|
||||||
|
getReporter().note("CACHE", "Updated cache");
|
||||||
|
} else {
|
||||||
|
getReporter().note("CACHE", "Skipped updating cache");
|
||||||
|
}
|
||||||
|
} catch (Error e) {
|
||||||
|
getReporter().note("CACHE", "Cache failed for " + referencedSources[i].getFilename());
|
||||||
|
e.log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getReporter().note("STAGE", "Parsing included sources");
|
||||||
|
for (i = 0; i < includedSources.length; i++) {
|
||||||
|
getReporter().note("STAGE-PART", includedSources[i].getFilename());
|
||||||
|
includedSources[i].parse();
|
||||||
|
try {
|
||||||
|
getReporter().note("CACHE", "Using cache filename " + includedSources[i].getCacheName() + " for " + includedSources[i].getFilename());
|
||||||
|
if (includedSources[i].updateCache()) {
|
||||||
|
getReporter().note("CACHE", "Updated cache");
|
||||||
|
} else {
|
||||||
|
getReporter().note("CACHE", "Skipped updating cache");
|
||||||
|
}
|
||||||
|
} catch (Error e) {
|
||||||
|
getReporter().note("CACHE", "Cache failed for " + includedSources[i].getFilename());
|
||||||
|
e.log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getReporter().note("STAGE", "Checking referenced sources");
|
||||||
|
int totalerrors = 0;
|
||||||
|
for (i = 0; i < referencedSources.length; i++) {
|
||||||
|
int e = referencedSources[i].checkErrors(errorVerbosity);
|
||||||
|
if (e != 0) {
|
||||||
|
getReporter().note("ERRORS", "Found " + e + " errors in '" + referencedSources[i].getFilename() + "'");
|
||||||
|
}
|
||||||
|
totalerrors += e;
|
||||||
|
}
|
||||||
|
getReporter().note("STAGE", "Checking included sources");
|
||||||
|
int ngood = 0;
|
||||||
|
int nbad = 0;
|
||||||
|
for (i = 0; i < includedSources.length; i++) {
|
||||||
|
int e = includedSources[i].checkErrors(errorVerbosity);
|
||||||
|
if (e != 0) {
|
||||||
|
nbad++;
|
||||||
|
getReporter().note("ERRORS", "Found " + e + " errors in '" + includedSources[i].getFilename() + "'");
|
||||||
|
} else {
|
||||||
|
ngood++;
|
||||||
|
}
|
||||||
|
totalerrors += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ratiogood = ((double) ngood) / ((double) ngood + nbad);
|
||||||
|
int percentgood = (int) (ratiogood * 100);
|
||||||
|
|
||||||
|
getReporter().note("SUMMARY", "" + ngood + " good files and " + nbad + " bad files (" + percentgood + "% good)");
|
||||||
|
|
||||||
|
if (totalerrors != 0) {
|
||||||
|
getReporter().note("TERMINATED", "Scanning/parsing/checking of sources resulted in " + totalerrors + " errors");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemModel system = new SystemModel();
|
||||||
|
|
||||||
|
getReporter().note("STAGE", "Configuring runtime types");
|
||||||
|
|
||||||
|
String core = "kebab0.core";
|
||||||
|
|
||||||
|
system.addBuiltinType(core, "bit", new BuiltinTypeBehaviour());
|
||||||
|
|
||||||
|
system.addBuiltinType(core, "duck", new BuiltinTypeBehaviour.DuckBehaviour());
|
||||||
|
|
||||||
|
system.addBuiltinType(core, "int8", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 8));
|
||||||
|
system.addBuiltinType(core, "int16", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 16));
|
||||||
|
system.addBuiltinType(core, "int32", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 32));
|
||||||
|
system.addBuiltinType(core, "int64", new BuiltinTypeBehaviour.NumberBehaviour(false, true, 64));
|
||||||
|
|
||||||
|
system.addBuiltinType(core, "uint8", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 8));
|
||||||
|
system.addBuiltinType(core, "uint16", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 16));
|
||||||
|
system.addBuiltinType(core, "uint32", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 32));
|
||||||
|
system.addBuiltinType(core, "uint64", new BuiltinTypeBehaviour.NumberBehaviour(false, false, 64));
|
||||||
|
|
||||||
|
system.addBuiltinType(core, "float32", new BuiltinTypeBehaviour.NumberBehaviour(true, true, 32));
|
||||||
|
system.addBuiltinType(core, "float64", new BuiltinTypeBehaviour.NumberBehaviour(true, true, 64));
|
||||||
|
|
||||||
|
system.addBuiltinType(core, "pointer", new BuiltinTypeBehaviour());
|
||||||
|
//system.addBuiltinType(core, "word", new BuiltinTypeBehaviour());
|
||||||
|
|
||||||
|
/*for (i = 0; i < typeOptions.length; i++) {
|
||||||
|
TypeOption o = typeOptions[i];
|
||||||
|
if (o.isBuiltin) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
system.setTypeOptions(typeOptions);
|
||||||
|
|
||||||
|
/* The built-in types should be quite specific. For general-purpose use, aliases comparable to
|
||||||
|
* standard C/D/Java/C# types are provided. These just point to the underlying built-in types.
|
||||||
|
*/
|
||||||
|
system.addAliasType(core, "boolean", core, "bit");
|
||||||
|
system.addAliasType(core, "byte", core, "int8");
|
||||||
|
system.addAliasType(core, "short", core, "int16");
|
||||||
|
system.addAliasType(core, "char", core, "uint16");
|
||||||
|
system.addAliasType(core, "int", core, "int32");
|
||||||
|
system.addAliasType(core, "long", core, "int64");
|
||||||
|
system.addAliasType(core, "float", core, "float32");
|
||||||
|
system.addAliasType(core, "double", core, "float64");
|
||||||
|
|
||||||
|
for (i = 0; i < aliasTypes.length; i++) {
|
||||||
|
MetaOrAlias a = aliasTypes[i];
|
||||||
|
system.addAliasType(pkgname(a.key), typname(a.key), pkgname(a.value), typname(a.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < aliasPackages.length; i++) {
|
||||||
|
MetaOrAlias a = aliasPackages[i];
|
||||||
|
system.addAliasPackage(a.key, a.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
system.addGlobalImport("fencom.stdlib");
|
||||||
|
system.addGlobalImport("java.lang");
|
||||||
|
*/
|
||||||
|
for (i = 0; i < globalImports.length; i++) {
|
||||||
|
if (globalImports[i].endsWith("*")) {
|
||||||
|
system.addGlobalImport(pkgname(globalImports[i]));
|
||||||
|
} else {
|
||||||
|
system.addGlobalImport(pkgname(globalImports[i]), typname(globalImports[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arrayLengthNames != null) {
|
||||||
|
getReporter().note("STAGE", "Overriding some magical options");
|
||||||
|
system.setArrayLengthNames(arrayLengthNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
getReporter().note("STAGE", "Adding referenced sources");
|
||||||
|
for (i = 0; i < referencedSources.length; i++) {
|
||||||
|
system.addUnit(referencedSources[i], false);
|
||||||
|
}
|
||||||
|
getReporter().note("STAGE", "Adding included sources");
|
||||||
|
for (i = 0; i < includedSources.length; i++) {
|
||||||
|
system.addUnit(includedSources[i], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
getReporter().note("STAGE", "Checking for initial errors");
|
||||||
|
if (system.countErrors() != 0) {
|
||||||
|
getReporter().note("TERMINATED", "Unpacking into internal model resulted in " + system.countErrors() + " errors");
|
||||||
|
}
|
||||||
|
|
||||||
|
//system.dump(getReporter());
|
||||||
|
|
||||||
|
int expandStage = 1;
|
||||||
|
boolean keepExpanding = true;
|
||||||
|
while (keepExpanding) {
|
||||||
|
getReporter().note("STAGE", "Expanding internal model (phase " + expandStage + ")");
|
||||||
|
int nexpanded = system.expand();
|
||||||
|
getReporter().note("NOTE", "Expanded " + nexpanded + " items");
|
||||||
|
//system.dump(getReporter());
|
||||||
|
if (system.countErrors() != 0) {
|
||||||
|
keepExpanding = false;
|
||||||
|
getReporter().note("TERMINATED", "Expanding internal model resulted in " + system.countErrors() + " errors");
|
||||||
|
//return false;
|
||||||
|
}
|
||||||
|
if (nexpanded == 0) {
|
||||||
|
keepExpanding = false;
|
||||||
|
}
|
||||||
|
expandStage++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resolveStage = 1;
|
||||||
|
boolean keepResolving = true;
|
||||||
|
int maxErrorRetries = 100;
|
||||||
|
int errorRetries = 0;
|
||||||
|
int maxNoExpandRetries = 100;
|
||||||
|
while (keepResolving) {
|
||||||
|
getReporter().note("STAGE", "Resolving types (phase " + resolveStage + ")");
|
||||||
|
int nexpanded = system.resolveTypes();
|
||||||
|
getReporter().note("NOTE", "Resolved " + nexpanded + " items");
|
||||||
|
//system.dump(getReporter());
|
||||||
|
if (system.countErrors() != 0) {
|
||||||
|
//if (errorRetries > maxErrorRetries) {
|
||||||
|
keepResolving = false;
|
||||||
|
getReporter().note("TERMINATED", "Resolving types resulted in " + system.countErrors() + " errors");
|
||||||
|
//return false;
|
||||||
|
/*} else {
|
||||||
|
getReporter().note("RETRYING", "Failed to resolve some types, I wiil retry assuming further expansion is necessary to find them");
|
||||||
|
system.deleteErrors();
|
||||||
|
errorRetries++;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
if (nexpanded == 0) {
|
||||||
|
getReporter().note("NOT-RETRYING", "Maximum number of internal no-expand retries exceded");
|
||||||
|
keepResolving = false;
|
||||||
|
}
|
||||||
|
resolveStage++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int tmp = 0; tmp < 10; tmp++) {
|
||||||
|
getReporter().note("NOTE", "Extra check stage " + tmp);
|
||||||
|
if (system.resolveTypes() != 0) {
|
||||||
|
getReporter().note("WARNING", "Extra expansion is necessary???");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//system.dump(getReporter());
|
||||||
|
|
||||||
|
if (checkErrors() != 0) {
|
||||||
|
getReporter().note("FAILED-IN", "Seems to have failed in the type-expansion stage");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveStage = 1;
|
||||||
|
keepResolving = true;
|
||||||
|
while (keepResolving) {
|
||||||
|
getReporter().note("STAGE", "Resolving expressions (phase " + resolveStage + ")");
|
||||||
|
int nexpanded = system.resolveExpressions(false); // NOTE: The parameter controls whether or not references are checked too
|
||||||
|
getReporter().note("NOTE", "Resolved " + nexpanded + " items");
|
||||||
|
//system.dump(getReporter());
|
||||||
|
if (system.countErrors() != 0) {
|
||||||
|
keepResolving = false;
|
||||||
|
getReporter().note("TERMINATED", "Resolving expressions resulted in " + system.countErrors() + " errors");
|
||||||
|
//return false;
|
||||||
|
}
|
||||||
|
if (nexpanded == 0) {
|
||||||
|
keepResolving = false;
|
||||||
|
}
|
||||||
|
resolveStage++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkErrors() != 0) {
|
||||||
|
getReporter().note("FAILED-IN", "Seems to have failed in the expression-reslolving stage");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This isn't finished yet (disabled for now in favour of a cleaner/slower expression resolution stage)
|
||||||
|
CTarget.transpile(system, "foo.h", new LineOutput() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void line(String line) {
|
||||||
|
System.err.println("HDR> " + line);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endOfFile() {
|
||||||
|
System.err.println("HDR END");
|
||||||
|
}
|
||||||
|
}, new LineOutput() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void line(String line) {
|
||||||
|
System.err.println("SRC> " + line);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endOfFile() {
|
||||||
|
System.err.println("SRC END");
|
||||||
|
}
|
||||||
|
});*/
|
||||||
|
|
||||||
|
if (getTarget() == null) {
|
||||||
|
getReporter().note("ABORTED", "No target to write to");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
getTarget().setSystem(system);
|
||||||
|
int total = 0;
|
||||||
|
String[] pkgs = system.getPackageNames();
|
||||||
|
for (i = 0; i < providesDepends.length; i++) {
|
||||||
|
ProvidesOrDepends x = providesDepends[i];
|
||||||
|
getReporter().note("REGISTERING", (x.provides ? "provides" : "depends") + " name '" + x.name + "' version '" + x.version + "'");
|
||||||
|
getTarget().visitProvidesOrDepends(x);
|
||||||
|
}
|
||||||
|
int mainTypesFound = 0;
|
||||||
|
for (i = 0; i < pkgs.length; i++) {
|
||||||
|
PackageModel p = system.getPackage(pkgs[i]);
|
||||||
|
String[] typs = p.getTypeNames();
|
||||||
|
for (int j = 0; j < typs.length; j++) {
|
||||||
|
TypeModel m = p.getType(typs[j]);
|
||||||
|
MethodModel[] constrs = m.getInstanceConstructors();
|
||||||
|
//for (int x = 0; x < constrs.length; x++) {
|
||||||
|
// Log.line("Type " + m.fullName() + "[" + typs[j] + "] has constr #" + x + ": " + constrs[x].toString());
|
||||||
|
//}
|
||||||
|
if (m instanceof UserTypeModel && m.existsAtRuntime() && !m.isReferenceOnly()) {
|
||||||
|
String name = m.fullName();
|
||||||
|
boolean isMain = false;
|
||||||
|
getReporter().note("COMPILING", "#" + total + ": " + name);
|
||||||
|
for (int x = 0; x < mainTypes.length; x++) {
|
||||||
|
if (name.equals(mainTypes[x])) {
|
||||||
|
mainTypesFound++;
|
||||||
|
isMain = true;
|
||||||
|
getReporter().note("NOTE", "Adding " + name + " to main list");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getTarget().visitType((UserTypeModel) m, isMain);
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mainTypesFound != mainTypes.length) {
|
||||||
|
getReporter().note("WARNING", "Couldn't find main types (expecting " + mainTypes.length + " found " + mainTypesFound);
|
||||||
|
}
|
||||||
|
for (i = 0; i < dataFiles.length; i++) {
|
||||||
|
getReporter().note("INSERTING", "#" + total + ": " + dataFiles[i].packagename + "." + dataFiles[i].innername);
|
||||||
|
getTarget().visitDataFile(dataFiles[i]);
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
for (i = 0; i < importantMeta.length; i++) {
|
||||||
|
getTarget().visitMeta(true, importantMeta[i].key, importantMeta[i].value);
|
||||||
|
}
|
||||||
|
for (i = 0; i < otherMeta.length; i++) {
|
||||||
|
getTarget().visitMeta(false, otherMeta[i].key, otherMeta[i].value);
|
||||||
|
}
|
||||||
|
for (i = 0; i < typeOptions.length; i++) {
|
||||||
|
getTarget().visitTypeOption(typeOptions[i]);
|
||||||
|
}
|
||||||
|
if (total > 0) {
|
||||||
|
if (checkErrors() != 0) {
|
||||||
|
getReporter().note("FINISHING", "Producing (WITH ERRORS) a total of " + total + " type-level objects: " + getTarget().quickReport());
|
||||||
|
getTarget().finish();
|
||||||
|
getReporter().note("PARTIAL-SUCCESS", "Target has been produced (WITH ERRORS).");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
getReporter().note("FINISHING", "Producing a total of " + total + " toplevels: " + getTarget().quickReport());
|
||||||
|
Log.line("In CompilerWorld");
|
||||||
|
getTarget().finish();
|
||||||
|
getReporter().note("SUCCESS", "Target has been produced.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getReporter().note("ABORTED", "Producing empty target.");
|
||||||
|
getTarget().finish();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int checkErrors() {
|
||||||
|
|
||||||
|
getReporter().note("CHECK", "Checking referenced sources for errors");
|
||||||
|
int terrors = 0;
|
||||||
|
for (int i = 0; i < referencedSources.length; i++) {
|
||||||
|
int e = referencedSources[i].checkErrors(errorVerbosity);
|
||||||
|
if (e != 0) {
|
||||||
|
getReporter().note("ERRORS", "Found " + e + " errors in '" + referencedSources[i].getFilename() + "'");
|
||||||
|
}
|
||||||
|
terrors += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (terrors != 0) {
|
||||||
|
getReporter().note("FAILED", "Checking of referenced sources resulted in " + terrors + " errors");
|
||||||
|
return terrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
getReporter().note("CHECK", "Checking included sources for errors");
|
||||||
|
for (int i = 0; i < includedSources.length; i++) {
|
||||||
|
int e = includedSources[i].checkErrors(errorVerbosity);
|
||||||
|
if (e != 0) {
|
||||||
|
getReporter().note("ERRORS", "Found " + e + " errors in '" + includedSources[i].getFilename() + "'");
|
||||||
|
}
|
||||||
|
terrors += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some random syntax tests were inserted here just to see how they behave
|
||||||
|
// on the plaform which shall not be named:
|
||||||
|
//String[] foo = {"foo","bar"};
|
||||||
|
//Object[] bar = foo;
|
||||||
|
//int[] x = {1,2,3};
|
||||||
|
//long[] y = x;
|
||||||
|
// Some weird behaviour I found in some random code (binary operators on booleans):
|
||||||
|
//int wtf1 = 0, wtf2 = 0, wtf3 = 0, wtf4 = 0;
|
||||||
|
//getReporter().note("TEST", "" + (wtf1 < wtf2-1 & (wtf1 != wtf3-1 | wtf4 == 0)));
|
||||||
|
|
||||||
|
if (terrors != 0) {
|
||||||
|
getReporter().note("FAILED", "Checking of included sources resulted in " + terrors + " errors");
|
||||||
|
return terrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return terrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Language getLanguage() {
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLanguage(Language l) {
|
||||||
|
language = l;
|
||||||
|
}
|
||||||
|
}
|
17
slangc/api/DataFile.sauce
Normal file
17
slangc/api/DataFile.sauce
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
public class DataFile {
|
||||||
|
String packagename;
|
||||||
|
String innername;
|
||||||
|
byte[] data;
|
||||||
|
String typeinfo;
|
||||||
|
String debugname;
|
||||||
|
public DataFile(String packagename, String innername, byte[] data, String typeinfo, String debugname) {
|
||||||
|
this.packagename = packagename;
|
||||||
|
this.innername = innername;
|
||||||
|
this.data = data;
|
||||||
|
this.typeinfo = typeinfo;
|
||||||
|
this.debugname = debugname;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
slangc/api/MetaOrAlias.sauce
Normal file
12
slangc/api/MetaOrAlias.sauce
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
public class MetaOrAlias {
|
||||||
|
public final String key;
|
||||||
|
public final String value;
|
||||||
|
|
||||||
|
public MetaOrAlias(String key, String value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
34
slangc/api/NullReporter.sauce
Normal file
34
slangc/api/NullReporter.sauce
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
public class NullReporter implements Reporter {
|
||||||
|
|
||||||
|
public NullReporter() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadingSource(String filename, boolean included) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadingFile(String filename, boolean included) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadingReferencedSet(String filename) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finishedLoading(int referencedSources, int referencedFiles, int referencedSets, int includedSources,
|
||||||
|
int includedFiles) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void note(String topic, String text) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
17
slangc/api/ProvidesOrDepends.sauce
Normal file
17
slangc/api/ProvidesOrDepends.sauce
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
public class ProvidesOrDepends {
|
||||||
|
public final boolean provides;
|
||||||
|
public final String name;
|
||||||
|
public final String version;
|
||||||
|
|
||||||
|
public ProvidesOrDepends(boolean provides, String name, String version) {
|
||||||
|
super();
|
||||||
|
this.provides = provides;
|
||||||
|
this.name = name;
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
10
slangc/api/Reporter.sauce
Normal file
10
slangc/api/Reporter.sauce
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
public interface Reporter {
|
||||||
|
public void note(String topic, String text);
|
||||||
|
public void loadingSource(String filename, boolean included);
|
||||||
|
public void loadingFile(String filename, boolean included);
|
||||||
|
public void loadingReferencedSet(String filename);
|
||||||
|
public void finishedLoading(int referencedSources, int referencedFiles, int referencedSets, int includedSources, int includedFiles);
|
||||||
|
|
||||||
|
}
|
93
slangc/api/TypeOption.sauce
Normal file
93
slangc/api/TypeOption.sauce
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
import slangc.bytecode.TypeSignature;
|
||||||
|
|
||||||
|
public class TypeOption {
|
||||||
|
/** Note the first 16 must match up to BytecodeInstructionWriter.StackType. */
|
||||||
|
public static enum Kind {
|
||||||
|
/* #0-#3 are used for special types (these are not valid in all scenarios). */
|
||||||
|
UNINITIALISED,
|
||||||
|
INVALID,
|
||||||
|
DUCK,
|
||||||
|
VOID,
|
||||||
|
/* #4 is the object type. */
|
||||||
|
OBJECT,
|
||||||
|
/* #5-#7 are the basic non-integer primitives. */
|
||||||
|
BIT,
|
||||||
|
FLOAT32,
|
||||||
|
FLOAT64,
|
||||||
|
|
||||||
|
/* #8-#15 are the basic integer primitives. */
|
||||||
|
INT8,
|
||||||
|
INT16,
|
||||||
|
INT32,
|
||||||
|
INT64,
|
||||||
|
UINT8,
|
||||||
|
UINT16,
|
||||||
|
UINT32,
|
||||||
|
UINT64,
|
||||||
|
|
||||||
|
/* #16-#31 are the other standard runtime types. */
|
||||||
|
MAGIC,
|
||||||
|
TYPE,
|
||||||
|
STRING,
|
||||||
|
ENUMBASE,
|
||||||
|
ARRAYBASE,
|
||||||
|
INSTANCECONSTRUCTOR,
|
||||||
|
STATICCONSTRUCTOR,
|
||||||
|
INSTANCEFIELD,
|
||||||
|
INSTANCEMETHOD,
|
||||||
|
STATICFIELD,
|
||||||
|
STATICMETHOD,
|
||||||
|
INTERFACEMETHOD,
|
||||||
|
BYTECODEFILE,
|
||||||
|
LOADER,
|
||||||
|
THREAD,
|
||||||
|
DEVICEHANDLE
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Kind kind;
|
||||||
|
public final String typeName;
|
||||||
|
public final String formatopt;
|
||||||
|
|
||||||
|
public final boolean isBuiltin;
|
||||||
|
public final boolean isDuck;
|
||||||
|
public final boolean isNumber;
|
||||||
|
public final boolean isFloat;
|
||||||
|
public final boolean isSigned;
|
||||||
|
public final int nbits;
|
||||||
|
|
||||||
|
public TypeSignature getTypeSignature() {
|
||||||
|
if (kind == Kind.VOID) {
|
||||||
|
return TypeSignature.VOID;
|
||||||
|
} else {
|
||||||
|
return new TypeSignature(CompilerWorld.pkgname(typeName), CompilerWorld.typname(typeName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeOption(Kind kind, String value, String formatopt) {
|
||||||
|
super();
|
||||||
|
this.kind = kind;
|
||||||
|
this.typeName = value;
|
||||||
|
this.formatopt = formatopt;
|
||||||
|
this.isBuiltin = false;
|
||||||
|
this.isDuck = false;
|
||||||
|
this.isNumber = false;
|
||||||
|
this.isFloat = false;
|
||||||
|
this.isSigned = false;
|
||||||
|
this.nbits = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeOption(Kind kind, String value, String formatopt, boolean isBuiltin, boolean isDuck, boolean isNumber, boolean isFloat, boolean isSigned, int nbits) {
|
||||||
|
this.kind = kind;
|
||||||
|
this.typeName = value;
|
||||||
|
this.formatopt = formatopt;
|
||||||
|
this.isBuiltin = isBuiltin;
|
||||||
|
this.isDuck = isDuck;
|
||||||
|
this.isNumber = isNumber;
|
||||||
|
this.isFloat = isFloat;
|
||||||
|
this.isSigned = isSigned;
|
||||||
|
this.nbits = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
245
slangc/api/Unit.sauce
Normal file
245
slangc/api/Unit.sauce
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
package slangc.api;
|
||||||
|
|
||||||
|
import slang.data.Mappable;
|
||||||
|
import slang.streams.SyncOutput;
|
||||||
|
import slang.streams.SyncInput;
|
||||||
|
|
||||||
|
import slangc.parser.Annotation;
|
||||||
|
import slangc.parser.AnnotationType;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.LocationAnnotation;
|
||||||
|
import slangc.parser.ErrorAnnotation;
|
||||||
|
import slangc.parser.NoteAnnotation;
|
||||||
|
import slangc.parser.LocationType;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.Parse;
|
||||||
|
import slangc.parser.Scan;
|
||||||
|
import slangc.parser.Source;
|
||||||
|
import slangc.parser.Token;
|
||||||
|
import slangc.parser.WarningType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds all of the information for a unit (sourceFile file) and abstracts away the semantics of scanning/parsing/checking them.
|
||||||
|
* @author Zak
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Unit {
|
||||||
|
private CompilerWorld world;
|
||||||
|
private Source source;
|
||||||
|
private Scan scan = null;
|
||||||
|
private Branch parse = null;
|
||||||
|
|
||||||
|
public Unit(CompilerWorld world, Source source) {
|
||||||
|
this.world = world;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompilerWorld getWorld() {
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Source getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilename() {
|
||||||
|
return getSource().getFilename();
|
||||||
|
}
|
||||||
|
|
||||||
|
int hashCache = -1;
|
||||||
|
public int getCacheHash() {
|
||||||
|
if (hashCache < 0) {
|
||||||
|
hashCache = Mappable.nonNegativeHashOf(getSource().getString(0, getSource().getIndexLength()));
|
||||||
|
}
|
||||||
|
return hashCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean updateCache() {
|
||||||
|
try {
|
||||||
|
Branch b = parse();
|
||||||
|
// TODO: Check if needs updating here
|
||||||
|
SyncOutput<byte> o = world.getCacheManager().getOutput(getCacheName());
|
||||||
|
if (o == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
b.dumpBinary(o);
|
||||||
|
o.close();
|
||||||
|
return true;
|
||||||
|
} catch (duck d) {
|
||||||
|
Log.line("WARNING: Updating cache failed with error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCacheName() {
|
||||||
|
return "." + getCacheHash() + "." + getSource().getIndexLength() + ".cache";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPackageName() {
|
||||||
|
Branch pkg = (Branch) parse().getSubnode(0);
|
||||||
|
if (pkg == null) {
|
||||||
|
return "defpkg"; //throw new Error("Invalid package format");
|
||||||
|
}
|
||||||
|
pkg = (Branch) pkg.getSubnode(1);
|
||||||
|
if (pkg == null) {
|
||||||
|
throw new Error("Invalid package format");
|
||||||
|
}
|
||||||
|
String name = "";
|
||||||
|
for (int i = 0; i < pkg.countSubnodes(); i++) {
|
||||||
|
Branch sub = (Branch) pkg.getSubnode(i);
|
||||||
|
if (sub == null) {
|
||||||
|
throw new Error("Invalid package format");
|
||||||
|
}
|
||||||
|
Token token = (Token) sub.getSubnode(0);
|
||||||
|
if (token == null) {
|
||||||
|
throw new Error("Invalid package format");
|
||||||
|
}
|
||||||
|
name += token.getSnippet().getSource();
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Scan scan() {
|
||||||
|
if (scan == null) {
|
||||||
|
scan = new Scan(world.getLanguage(), source);
|
||||||
|
//scan.scanPedantic();
|
||||||
|
scan.scanQuick();
|
||||||
|
}
|
||||||
|
|
||||||
|
return scan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Branch loadCache(SyncInput<byte> inp) {
|
||||||
|
scan = new Scan(world.getLanguage(), source);
|
||||||
|
parse = (Branch) Node.loadBinary(scan, inp);
|
||||||
|
inp.close();
|
||||||
|
_wasCached = true;
|
||||||
|
return parse;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean _wasCached = false;
|
||||||
|
|
||||||
|
public boolean wasCached() {
|
||||||
|
return _wasCached;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Branch parse() {
|
||||||
|
if (parse == null) {
|
||||||
|
SyncInput<byte> cacheIn = world.getCacheManager().getInput(getCacheName());
|
||||||
|
if (cacheIn != null) {
|
||||||
|
//Log.line("Loading from cache...");
|
||||||
|
return loadCache(cacheIn);
|
||||||
|
}
|
||||||
|
//Log.line("Not cached...");
|
||||||
|
Scan s = scan();
|
||||||
|
Parse p = new Parse();
|
||||||
|
parse = (Branch) p.parseUnit(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Token checkRecursively(Branch b, Token p) {
|
||||||
|
if (!Node.mightHaveErrors && !Node.mightHaveWarnings) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
if (p != null && b.countAnnotations(AnnotationType.LOCATION) == 0) {
|
||||||
|
b.annotate(new LocationAnnotation(LocationType.AFTER, p));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < b.countSubnodes(); i++) {
|
||||||
|
Node n = b.getSubnode(i);
|
||||||
|
if (n instanceof Token) {
|
||||||
|
p = (Token) n;
|
||||||
|
p.annotate(new LocationAnnotation(LocationType.AROUND, p));
|
||||||
|
} else if (n == null) {
|
||||||
|
b.annotate(WarningType.INTERNAL_WARNING, "Had a null member");
|
||||||
|
} else {
|
||||||
|
p = checkRecursively((Branch) n, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p != null && b.countAnnotations(AnnotationType.LOCATION) == 0) {
|
||||||
|
b.annotate(new LocationAnnotation(LocationType.AROUND, p));
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int checkErrors(int verbosity) {
|
||||||
|
int nerrors = 0;
|
||||||
|
|
||||||
|
Branch p = parse();
|
||||||
|
|
||||||
|
checkRecursively(p, null);
|
||||||
|
|
||||||
|
//getWorld().getReporter().note("CHECKING", getFilename());
|
||||||
|
|
||||||
|
//getWorld().getReporter().note("CHECKING", "File '" + getFilename() + "' reports package as '" + getPackageName() + "'");
|
||||||
|
|
||||||
|
nerrors += p.countErrorsRecursively();
|
||||||
|
|
||||||
|
if (nerrors != 0) {
|
||||||
|
getWorld().getReporter().note("ERRORS", "Found " + nerrors + " errors in '" + getFilename() + "', dumping AST:");
|
||||||
|
dump(getWorld().getReporter(), parse(), verbosity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nerrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void dump(Reporter out, Node n, int verbosity) {
|
||||||
|
dump(out, n, "", verbosity < 5 ? "" : " ", verbosity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void dump(Reporter out, Node n, String curindent, String subindent, int verbosity) {
|
||||||
|
if (n instanceof Branch) {
|
||||||
|
dumpBranch(out, (Branch) n, curindent, subindent, verbosity);
|
||||||
|
} else if (n instanceof Token) {
|
||||||
|
dumpToken(out, (Token) n, curindent, subindent, verbosity);
|
||||||
|
} else if (n instanceof Annotation) {
|
||||||
|
dumpAnnotation(out, (Annotation) n, curindent, subindent, verbosity);
|
||||||
|
} else if (n == null) {
|
||||||
|
out.note("DUMP", curindent + "-! UH-OH !- null");
|
||||||
|
} else {
|
||||||
|
out.note("DUMP", curindent + "-! TO-DO !- code to dump " + n.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void dumpAnnotations(Reporter out, Node n, String curindent, String subindent, int verbosity) {
|
||||||
|
for (int i = 0; i < n.countAnnotations(); i++) {
|
||||||
|
dump(out, n.getAnnotation(i), curindent + subindent, subindent, verbosity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void dumpBranch(Reporter out, Branch b, String curindent, String subindent, int verbosity) {
|
||||||
|
if (verbosity < 10 && b.countErrorsRecursively() == 0) {
|
||||||
|
if (verbosity > 2) out.note("DUMP", curindent + "-> " + b.getNodeType().name() + " (...)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (verbosity >= 5 || b.countErrorsHere() > 0) {
|
||||||
|
if (verbosity > 2) out.note("DUMP", curindent + "-> " + b.getNodeType());
|
||||||
|
dumpAnnotations(out, b, curindent, subindent, verbosity);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < b.countSubnodes(); i++) {
|
||||||
|
dump(out, b.getSubnode(i), curindent + subindent, subindent, verbosity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void dumpToken(Reporter out, Token t, String curindent, String subindent, int verbosity) {
|
||||||
|
if (verbosity >= 5) {
|
||||||
|
out.note("DUMP", curindent + "-. " + t);
|
||||||
|
dumpAnnotations(out, t, curindent, subindent, verbosity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void dumpAnnotation(Reporter out, Annotation a, String curindent, String subindent, int verbosity) {
|
||||||
|
if (a instanceof ErrorAnnotation) {
|
||||||
|
out.note("DUMP", curindent + "-! " + ((ErrorAnnotation) a).getErrorType().name());
|
||||||
|
} else if (a instanceof NoteAnnotation) {
|
||||||
|
out.note("DUMP", curindent + "-+ " + ((NoteAnnotation) a).getText());
|
||||||
|
} else if (a instanceof LocationAnnotation) {
|
||||||
|
out.note("DUMP", curindent + "-- " + ((LocationAnnotation) a).niceString());
|
||||||
|
} else {
|
||||||
|
out.note("DUMP", curindent + "-+ " + a.toString());
|
||||||
|
}
|
||||||
|
dumpAnnotations(out, a, curindent, subindent, verbosity);
|
||||||
|
}
|
||||||
|
}
|
30
slangc/bytecode/BytecodeObject.sauce
Normal file
30
slangc/bytecode/BytecodeObject.sauce
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
import slangc.api.BytecodeOutput;
|
||||||
|
|
||||||
|
public abstract class BytecodeObject {
|
||||||
|
|
||||||
|
public static enum Type {
|
||||||
|
NULL,
|
||||||
|
BOOLEAN,
|
||||||
|
INT32,
|
||||||
|
INT64,
|
||||||
|
FLOAT,
|
||||||
|
DOUBLE,
|
||||||
|
STRING,
|
||||||
|
TYPESIG,
|
||||||
|
TYPE,
|
||||||
|
METHODSIG,
|
||||||
|
METHOD,
|
||||||
|
FIELDSIG,
|
||||||
|
FIELD
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytecodeObject() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int sizeOfArrayPart();
|
||||||
|
|
||||||
|
public abstract void writeArrayPart(BytecodeOutput output);
|
||||||
|
}
|
36
slangc/bytecode/FieldSignature.sauce
Normal file
36
slangc/bytecode/FieldSignature.sauce
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
import slang.data.Mappable;
|
||||||
|
|
||||||
|
public final class FieldSignature implements Mappable {
|
||||||
|
public final TypeSignature owner;
|
||||||
|
public final boolean isStatic;
|
||||||
|
public final TypeSignature storageType;
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
public FieldSignature(TypeSignature owner, boolean isStatic, TypeSignature storageType, String name) {
|
||||||
|
super();
|
||||||
|
this.owner = owner;
|
||||||
|
this.isStatic = isStatic;
|
||||||
|
this.storageType = storageType;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return owner.toString() + (isStatic ? "##" : "#") + name + ":" + storageType.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int mappableHash() {
|
||||||
|
return Mappable.hashOf(toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mappableEquals(Mappable obj) {
|
||||||
|
if (obj instanceof FieldSignature) {
|
||||||
|
return this.toString().equals(((FieldSignature)obj).toString());
|
||||||
|
} else {
|
||||||
|
return false; //super.equals(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
slangc/bytecode/Instruction.sauce
Normal file
12
slangc/bytecode/Instruction.sauce
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
public class Instruction {
|
||||||
|
|
||||||
|
public Instruction() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public short encodeFirstOp(MajorOpcode major, MinorOpcode minor, StackType type, int extraops) {
|
||||||
|
return 0; //TODO
|
||||||
|
}
|
||||||
|
}
|
10
slangc/bytecode/MajorOpcode.sauce
Normal file
10
slangc/bytecode/MajorOpcode.sauce
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
public enum MajorOpcode {
|
||||||
|
INVALID_ZERO,
|
||||||
|
LOADSTORE,
|
||||||
|
CALL,
|
||||||
|
NEW_ARRAY,
|
||||||
|
CONVERT,
|
||||||
|
ALU
|
||||||
|
}
|
60
slangc/bytecode/MethodSignature.sauce
Normal file
60
slangc/bytecode/MethodSignature.sauce
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
import slang.data.Mappable;
|
||||||
|
|
||||||
|
public final class MethodSignature implements Mappable {
|
||||||
|
public static enum Kind {
|
||||||
|
STATIC_INIT,
|
||||||
|
CONSTRUCTOR,
|
||||||
|
STATIC_METHOD,
|
||||||
|
INSTANCE_METHOD,
|
||||||
|
INTERFACE_METHOD
|
||||||
|
}
|
||||||
|
public final TypeSignature owner;
|
||||||
|
public final Kind kind;
|
||||||
|
public final TypeSignature returnType;
|
||||||
|
public final String name;
|
||||||
|
public final TypeSignature[] argumentTypes;
|
||||||
|
|
||||||
|
public MethodSignature(TypeSignature owner, Kind kind, TypeSignature returnType, String name,
|
||||||
|
TypeSignature[] argumentTypes) {
|
||||||
|
super();
|
||||||
|
this.owner = owner;
|
||||||
|
this.kind = kind;
|
||||||
|
this.returnType = returnType;
|
||||||
|
this.name = name;
|
||||||
|
this.argumentTypes = argumentTypes;
|
||||||
|
cachedHash = Mappable.hashOf(toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStatic() {
|
||||||
|
switch (kind) {
|
||||||
|
case Kind.STATIC_INIT:
|
||||||
|
case Kind.STATIC_METHOD:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return owner.toString() + (isStatic() ? "##" : "#") + name + "(" + TypeSignature.arrayToString(argumentTypes) + ")" + ":" + (returnType == null ? "void" : returnType.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
int cachedHash = 0;
|
||||||
|
@Override
|
||||||
|
public int mappableHash() {
|
||||||
|
return cachedHash; //Mappable.hashOf(toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mappableEquals(Mappable obj) {
|
||||||
|
if (obj instanceof MethodSignature) {
|
||||||
|
MethodSignature mso = (MethodSignature)obj;
|
||||||
|
return mso.name == this.name && this.toString().equals(mso.toString());
|
||||||
|
} else {
|
||||||
|
return false; //super.equals(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
slangc/bytecode/MinorOpcode.sauce
Normal file
50
slangc/bytecode/MinorOpcode.sauce
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
public interface MinorOpcode {
|
||||||
|
public static enum CALL implements MinorOpcode {
|
||||||
|
STATIC,
|
||||||
|
INSTANCE,
|
||||||
|
NEW
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum LOADSTORE implements MinorOpcode {
|
||||||
|
LOAD_CONSTANT,
|
||||||
|
RESERVED,
|
||||||
|
LOAD_LOCAL,
|
||||||
|
STORE_LOCAL,
|
||||||
|
LOAD_INSTANCE,
|
||||||
|
STORE_INSTANCE,
|
||||||
|
LOAD_ARRAY,
|
||||||
|
STORE_ARRAY,
|
||||||
|
LOAD_STATIC,
|
||||||
|
STORE_STATIC,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum CONVERT implements MinorOpcode {
|
||||||
|
TO_INT8,
|
||||||
|
TO_INT16,
|
||||||
|
TO_INT32,
|
||||||
|
TO_INT64,
|
||||||
|
TO_UINT8,
|
||||||
|
TO_UINT16,
|
||||||
|
TO_UINT32,
|
||||||
|
TO_UINT64,
|
||||||
|
TO_FLOAT32,
|
||||||
|
TO_FLOAT64,
|
||||||
|
TO_STRING,
|
||||||
|
TO_OBJECT,
|
||||||
|
TO_DUCK
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum ALU implements MinorOpcode {
|
||||||
|
ADD,
|
||||||
|
SUB,
|
||||||
|
SHL,
|
||||||
|
SHRX,
|
||||||
|
SHRZ,
|
||||||
|
MUL,
|
||||||
|
DIV,
|
||||||
|
MOD,
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
171
slangc/bytecode/StackMachineAdapter.sauce
Normal file
171
slangc/bytecode/StackMachineAdapter.sauce
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
public class StackMachineAdapter implements StackMachineVisitor {
|
||||||
|
protected final StackMachineVisitor target;
|
||||||
|
protected final ReferenceFactory referenceFactory;
|
||||||
|
|
||||||
|
public StackMachineAdapter(StackMachineVisitor target, ReferenceFactory referenceFactory) {
|
||||||
|
this.target = target;
|
||||||
|
this.referenceFactory = referenceFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.FieldReference getFieldReference(StackMachineVisitor.TypeReference owner, boolean isStatic, StackMachineVisitor.TypeReference type, String name) {
|
||||||
|
return referenceFactory.getFieldReference(this, owner, isStatic, type, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.MethodReference getMethodReference(StackMachineVisitor.TypeReference owner, boolean isStatic, StackMachineVisitor.TypeReference returnType,
|
||||||
|
String name, StackMachineVisitor.TypeReference[] argumentTypes) {
|
||||||
|
return referenceFactory.getMethodReference(this, owner, isStatic, returnType, name, argumentTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.TypeReference voidTypeReference() {
|
||||||
|
return referenceFactory.voidTypeReference(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.TypeReference getTypeReference(String packageName, String typeName) {
|
||||||
|
return referenceFactory.getTypeReference(this, packageName, typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public void finish() {
|
||||||
|
target.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reference construction is separated out since it may be handled very differently in different scenarios.
|
||||||
|
* See DefaultReferenceFactory for a simple "pass-through" implementation. Other adapters may want to keep a
|
||||||
|
* description of the references instead and then reconstruct references as they're used, or may want to pass
|
||||||
|
* some of them through but also need to cache some information.
|
||||||
|
*/
|
||||||
|
public static interface ReferenceFactory {
|
||||||
|
public StackMachineVisitor.FieldReference toTarget(StackMachineVisitor.FieldReference localReference);
|
||||||
|
public StackMachineVisitor.MethodReference toTarget(StackMachineVisitor.MethodReference localReference);
|
||||||
|
public StackMachineVisitor.TypeReference toTarget(StackMachineVisitor.TypeReference localReference);
|
||||||
|
public StackMachineVisitor.TypeReference[] toTarget(StackMachineVisitor.TypeReference[] localReferences);
|
||||||
|
|
||||||
|
public StackMachineVisitor.FieldReference getFieldReference(StackMachineAdapter adapter, StackMachineVisitor.TypeReference owner, boolean isStatic, StackMachineVisitor.TypeReference type, String name);
|
||||||
|
|
||||||
|
public StackMachineVisitor.MethodReference getMethodReference(StackMachineAdapter adapter, StackMachineVisitor.TypeReference owner, boolean isStatic, StackMachineVisitor.TypeReference returnType,
|
||||||
|
String name, StackMachineVisitor.TypeReference[] argumentTypes);
|
||||||
|
|
||||||
|
public StackMachineVisitor.TypeReference voidTypeReference(StackMachineVisitor.StackMachineAdapter adapter);
|
||||||
|
|
||||||
|
public StackMachineVisitor.TypeReference getTypeReference(StackMachineVisitor.StackMachineAdapter adapter, String packageName, String typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DefaultReferenceFactory implements ReferenceFactory {
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.FieldReference toTarget(StackMachineVisitor.FieldReference localReference) {
|
||||||
|
return localReference;
|
||||||
|
}
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.MethodReference toTarget(StackMachineVisitor.MethodReference localReference) {
|
||||||
|
return localReference;
|
||||||
|
}
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.TypeReference toTarget(StackMachineVisitor.TypeReference localReference) {
|
||||||
|
return localReference;
|
||||||
|
}
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.TypeReference[] toTarget(StackMachineVisitor.TypeReference[] localReferences) {
|
||||||
|
return localReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.FieldReference getFieldReference(StackMachineAdapter adapter, StackMachineVisitor.TypeReference owner, boolean isStatic,
|
||||||
|
StackMachineVisitor.TypeReference type, String name) {
|
||||||
|
return adapter.target.getFieldReference(owner, isStatic, type, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.MethodReference getMethodReference(StackMachineAdapter adapter, StackMachineVisitor.TypeReference owner, boolean isStatic,
|
||||||
|
StackMachineVisitor.TypeReference returnType, String name, StackMachineVisitor.TypeReference[] argumentTypes) {
|
||||||
|
return adapter.target.getMethodReference(owner, isStatic, returnType, name, argumentTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.TypeReference voidTypeReference(StackMachineAdapter adapter) {
|
||||||
|
return adapter.target.voidTypeReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.TypeReference getTypeReference(StackMachineAdapter adapter, String packageName, String typeName) {
|
||||||
|
return adapter.target.getTypeReference(packageName, typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SystemAdapter extends StackMachineAdapter implements SystemVisitor {
|
||||||
|
|
||||||
|
public SystemAdapter(StackMachineVisitor target, ReferenceFactory referenceFactory) {
|
||||||
|
super(target, referenceFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.TypeVisitor beginType(StackMachineVisitor.TypeReference reference) {
|
||||||
|
((StackMachineVisitor.SystemVisitor)target).beginType(reference);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AdapterWithAttributes extends StackMachineAdapter implements StackMachineVisitor.VisitorWithAttributes {
|
||||||
|
|
||||||
|
public AdapterWithAttributes(StackMachineVisitor.VisitorWithAttributes target, ReferenceFactory referenceFactory) {
|
||||||
|
super(target, referenceFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public void setProtectionType(StackMachineVisitor.ProtectionType t) {
|
||||||
|
((StackMachineVisitor.VisitorWithAttributes)target).setProtectionType(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TypeAdapter extends AdapterWithAttributes implements StackMachineVisitor.TypeVisitor {
|
||||||
|
|
||||||
|
public TypeAdapter(StackMachineVisitor.TypeVisitor target, ReferenceFactory referenceFactory) {
|
||||||
|
super(target, referenceFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public void setSourceFile(String filename) {
|
||||||
|
((StackMachineVisitor.TypeVisitor)target).setSourceFile(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public void setBaseType(StackMachineVisitor.TypeReference reference) {
|
||||||
|
((StackMachineVisitor.TypeVisitor)target).setBaseType(referenceFactory.toTarget(reference));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public void setInterfaceTypes(StackMachineVisitor.TypeReference[] interfaces) {
|
||||||
|
((StackMachineVisitor.TypeVisitor)target).setInterfaceTypes(referenceFactory.toTarget(interfaces));
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public void setOuterType(StackMachineVisitor.TypeReference reference) {
|
||||||
|
((StackMachineVisitor.TypeVisitor)target).setOuterType(referenceFactory.toTarget(reference));
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.FieldVisitor beginField(StackMachineVisitor.FieldReference reference) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StackMachineVisitor.MethodVisitor beginMethod(StackMachineVisitor.MethodReference reference) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
67
slangc/bytecode/StackMachineVisitor.sauce
Normal file
67
slangc/bytecode/StackMachineVisitor.sauce
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
public interface StackMachineVisitor {
|
||||||
|
public enum ProtectionType {
|
||||||
|
PRIVATE,
|
||||||
|
PROTECTED,
|
||||||
|
DEFAULT,
|
||||||
|
PUBLIC
|
||||||
|
}
|
||||||
|
public interface VisitorWithAttributes extends StackMachineVisitor {
|
||||||
|
void setProtectionType(ProtectionType t);
|
||||||
|
}
|
||||||
|
public interface SystemVisitor extends StackMachineVisitor {
|
||||||
|
TypeVisitor beginType(TypeReference reference);
|
||||||
|
}
|
||||||
|
public interface TypeVisitor extends VisitorWithAttributes {
|
||||||
|
void setSourceFile(String filename);
|
||||||
|
void setBaseType(TypeReference reference);
|
||||||
|
void setInterfaceTypes(TypeReference[] interfaces);
|
||||||
|
void setOuterType(TypeReference reference);
|
||||||
|
FieldVisitor beginField(FieldReference reference);
|
||||||
|
MethodVisitor beginMethod(MethodReference reference);
|
||||||
|
}
|
||||||
|
public interface FieldVisitor extends VisitorWithAttributes {
|
||||||
|
|
||||||
|
}
|
||||||
|
public interface MethodVisitor extends VisitorWithAttributes {
|
||||||
|
InstructionTarget beginInstructions();
|
||||||
|
}
|
||||||
|
public interface InstructionTarget extends StackMachineVisitor {
|
||||||
|
public void setSourceLine(int lineNumber);
|
||||||
|
public void labelHere(LabelReference reference);
|
||||||
|
public LabelReference newLabel(String debugName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Reference {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TypeReference extends Reference {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface FieldReference extends Reference {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MethodReference extends Reference {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface LocalReference extends Reference {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface LabelReference extends Reference {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldReference getFieldReference(TypeReference owner, boolean isStatic, TypeReference type, String name);
|
||||||
|
public MethodReference getMethodReference(TypeReference owner, boolean isStatic, TypeReference returnType, String name, TypeReference[] argumentTypes);
|
||||||
|
|
||||||
|
public TypeReference voidTypeReference();
|
||||||
|
public TypeReference getTypeReference(String packageName, String typeName);
|
||||||
|
|
||||||
|
void finish();
|
||||||
|
}
|
16
slangc/bytecode/StackType.sauce
Normal file
16
slangc/bytecode/StackType.sauce
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This denotes the type of a typeName on the stack (a typeName which instructions work with).
|
||||||
|
* @author Zak
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum StackType {
|
||||||
|
DUCK,
|
||||||
|
OBJECT,
|
||||||
|
INT32,
|
||||||
|
INT64,
|
||||||
|
FLOAT32,
|
||||||
|
FLOAT64,
|
||||||
|
BOOLEAN
|
||||||
|
}
|
5
slangc/bytecode/SystemVisitor.sauce
Normal file
5
slangc/bytecode/SystemVisitor.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
public interface SystemVisitor extends Visitor {
|
||||||
|
TypeVisitor visitType(TypeSignature signature);
|
||||||
|
}
|
53
slangc/bytecode/TypeSignature.sauce
Normal file
53
slangc/bytecode/TypeSignature.sauce
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
import slang.data.Mappable;
|
||||||
|
|
||||||
|
public final class TypeSignature implements Mappable {
|
||||||
|
public final String packageName;
|
||||||
|
public final String typeName;
|
||||||
|
|
||||||
|
public static final TypeSignature VOID = new TypeSignature("kebab0.core", "void"); // TODO: Make translatable
|
||||||
|
|
||||||
|
public TypeSignature(String packageName, String typeName) {
|
||||||
|
/*if (packageName == null) {
|
||||||
|
throw new Error("Can't create type signature with null package");
|
||||||
|
}*/
|
||||||
|
if (typeName == null) {
|
||||||
|
throw new Error("Can't create type signature with null type");
|
||||||
|
}
|
||||||
|
this.packageName = packageName;
|
||||||
|
this.typeName = typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return packageName + "." + typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String arrayToString(TypeSignature[] types) {
|
||||||
|
String result = "";
|
||||||
|
|
||||||
|
for (int i = 0; i < types.length; i++) {
|
||||||
|
if (i != 0) {
|
||||||
|
result += ",";
|
||||||
|
}
|
||||||
|
result += types[i].toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int mappableHash() {
|
||||||
|
return Mappable.hashOf(toString());//toString().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mappableEquals(Mappable obj) {
|
||||||
|
if (obj instanceof TypeSignature) {
|
||||||
|
return this.toString().equals(((TypeSignature)obj).toString());
|
||||||
|
} else {
|
||||||
|
return false; //super.equals(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
slangc/bytecode/TypeVisitor.sauce
Normal file
6
slangc/bytecode/TypeVisitor.sauce
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
public interface TypeVisitor extends Visitor {
|
||||||
|
//FieldVisitor visitField(FieldSignature signature);
|
||||||
|
//MethodVisitor visitMethod(MethodSignature signature);
|
||||||
|
}
|
5
slangc/bytecode/Visitor.sauce
Normal file
5
slangc/bytecode/Visitor.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.bytecode;
|
||||||
|
|
||||||
|
public interface Visitor {
|
||||||
|
void finish();
|
||||||
|
}
|
5
slangc/codegraph/AbstractClassDefinition.sauce
Normal file
5
slangc/codegraph/AbstractClassDefinition.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractClassDefinition extends AbstractTypeDefinition {
|
||||||
|
public AbstractLink getSuperClass();
|
||||||
|
}
|
5
slangc/codegraph/AbstractConstructor.sauce
Normal file
5
slangc/codegraph/AbstractConstructor.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractConstructor extends AbstractInvokable {
|
||||||
|
|
||||||
|
}
|
9
slangc/codegraph/AbstractContainer.sauce
Normal file
9
slangc/codegraph/AbstractContainer.sauce
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractContainer extends AbstractNamedElement {
|
||||||
|
public int countNamedElements();
|
||||||
|
|
||||||
|
public AbstractNamedElement getNamedElement(int index);
|
||||||
|
|
||||||
|
public ContainerType getContainerType();
|
||||||
|
}
|
5
slangc/codegraph/AbstractEnumDefinition.sauce
Normal file
5
slangc/codegraph/AbstractEnumDefinition.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractEnumDefinition extends AbstractInterfaceDefinition {
|
||||||
|
|
||||||
|
}
|
5
slangc/codegraph/AbstractField.sauce
Normal file
5
slangc/codegraph/AbstractField.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractField extends AbstractNamedElement {
|
||||||
|
|
||||||
|
}
|
5
slangc/codegraph/AbstractInterfaceDefinition.sauce
Normal file
5
slangc/codegraph/AbstractInterfaceDefinition.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractInterfaceDefinition {
|
||||||
|
|
||||||
|
}
|
5
slangc/codegraph/AbstractInvokable.sauce
Normal file
5
slangc/codegraph/AbstractInvokable.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractInvokable extends AbstractMember {
|
||||||
|
|
||||||
|
}
|
7
slangc/codegraph/AbstractLink.sauce
Normal file
7
slangc/codegraph/AbstractLink.sauce
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractLink {
|
||||||
|
boolean isResolved();
|
||||||
|
String getTargetName();
|
||||||
|
AbstractNamedElement getTarget();
|
||||||
|
}
|
7
slangc/codegraph/AbstractMember.sauce
Normal file
7
slangc/codegraph/AbstractMember.sauce
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractMember extends AbstractNamedElement {
|
||||||
|
public MemberType getMemberType();
|
||||||
|
|
||||||
|
public boolean isStatic();
|
||||||
|
}
|
5
slangc/codegraph/AbstractMethod.sauce
Normal file
5
slangc/codegraph/AbstractMethod.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractMethod extends AbstractInvokable {
|
||||||
|
|
||||||
|
}
|
15
slangc/codegraph/AbstractNamedElement.sauce
Normal file
15
slangc/codegraph/AbstractNamedElement.sauce
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractNamedElement {
|
||||||
|
|
||||||
|
public AbstractContainer getEnclosingContainer();
|
||||||
|
public String getSimpleName();
|
||||||
|
public String getFullName();
|
||||||
|
|
||||||
|
public AbstractTypeDefinition getType();
|
||||||
|
public AbstractPackage getPackage();
|
||||||
|
public AbstractSet getSet();
|
||||||
|
public AbstractWorld getWorld();
|
||||||
|
|
||||||
|
public Object getCompilerObject();
|
||||||
|
}
|
5
slangc/codegraph/AbstractPackage.sauce
Normal file
5
slangc/codegraph/AbstractPackage.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractPackage extends AbstractContainer {
|
||||||
|
|
||||||
|
}
|
11
slangc/codegraph/AbstractSet.sauce
Normal file
11
slangc/codegraph/AbstractSet.sauce
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a set of packages (either an already-compiled set, or a set of sourceFile packages being compiled or analysed).
|
||||||
|
*
|
||||||
|
* @author Zak
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface AbstractSet extends AbstractContainer {
|
||||||
|
|
||||||
|
}
|
5
slangc/codegraph/AbstractTagDefinition.sauce
Normal file
5
slangc/codegraph/AbstractTagDefinition.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractTagDefinition extends AbstractTypeDefinition {
|
||||||
|
|
||||||
|
}
|
10
slangc/codegraph/AbstractTypeDefinition.sauce
Normal file
10
slangc/codegraph/AbstractTypeDefinition.sauce
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractTypeDefinition extends AbstractContainer {
|
||||||
|
|
||||||
|
public TypeType getTypeType();
|
||||||
|
|
||||||
|
public int countInheritedInterfaces();
|
||||||
|
|
||||||
|
public AbstractLink getInheritedInterface(int index);
|
||||||
|
}
|
5
slangc/codegraph/AbstractWorld.sauce
Normal file
5
slangc/codegraph/AbstractWorld.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public interface AbstractWorld extends AbstractContainer {
|
||||||
|
|
||||||
|
}
|
8
slangc/codegraph/ContainerType.sauce
Normal file
8
slangc/codegraph/ContainerType.sauce
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public enum ContainerType {
|
||||||
|
WORLD,
|
||||||
|
SET,
|
||||||
|
PACKAGE,
|
||||||
|
TYPE
|
||||||
|
}
|
21
slangc/codegraph/DynamicClassDefinition.sauce
Normal file
21
slangc/codegraph/DynamicClassDefinition.sauce
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public class DynamicClassDefinition extends DynamicType implements AbstractClassDefinition {
|
||||||
|
private DynamicLink superClass = null;
|
||||||
|
|
||||||
|
public DynamicClassDefinition() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeType getTypeType() {
|
||||||
|
return TypeType.CLASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DynamicLink getSuperClass() {
|
||||||
|
return superClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuperClass(DynamicLink superClass) {
|
||||||
|
this.superClass = superClass;
|
||||||
|
}
|
||||||
|
}
|
9
slangc/codegraph/DynamicConstructor.sauce
Normal file
9
slangc/codegraph/DynamicConstructor.sauce
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public class DynamicConstructor extends DynamicInvokable implements AbstractConstructor {
|
||||||
|
|
||||||
|
public DynamicConstructor() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
slangc/codegraph/DynamicContainer.sauce
Normal file
31
slangc/codegraph/DynamicContainer.sauce
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public abstract class DynamicContainer extends DynamicNamedElement implements AbstractContainer {
|
||||||
|
private DynamicNamedElement[] elements = new DynamicNamedElement[0];
|
||||||
|
|
||||||
|
public DynamicContainer() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countNamedElements() {
|
||||||
|
return elements.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DynamicNamedElement getNamedElement(int index) {
|
||||||
|
if (index < 0 || index > elements.length) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return elements[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendNamedElement(DynamicNamedElement e) {
|
||||||
|
DynamicNamedElement[] nelem = new DynamicNamedElement[elements.length + 1];
|
||||||
|
for (int i = 0; i < elements.length; i++) {
|
||||||
|
nelem[i] = elements[i];
|
||||||
|
}
|
||||||
|
nelem[nelem.length - 1] = e;
|
||||||
|
elements = nelem;
|
||||||
|
e.setEnclosingContainer(this);
|
||||||
|
}
|
||||||
|
}
|
13
slangc/codegraph/DynamicEnumDefinition.sauce
Normal file
13
slangc/codegraph/DynamicEnumDefinition.sauce
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public class DynamicEnumDefinition extends DynamicInterfaceDefinition implements AbstractEnumDefinition {
|
||||||
|
|
||||||
|
public DynamicEnumDefinition() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeType getTypeType() {
|
||||||
|
return TypeType.ENUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
9
slangc/codegraph/DynamicField.sauce
Normal file
9
slangc/codegraph/DynamicField.sauce
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public class DynamicField extends DynamicNamedElement implements AbstractField {
|
||||||
|
|
||||||
|
public DynamicField() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
slangc/codegraph/DynamicInterfaceDefinition.sauce
Normal file
13
slangc/codegraph/DynamicInterfaceDefinition.sauce
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public class DynamicInterfaceDefinition extends DynamicType implements AbstractInterfaceDefinition {
|
||||||
|
|
||||||
|
public DynamicInterfaceDefinition() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeType getTypeType() {
|
||||||
|
return TypeType.INTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
19
slangc/codegraph/DynamicInvokable.sauce
Normal file
19
slangc/codegraph/DynamicInvokable.sauce
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public abstract class DynamicInvokable extends DynamicNamedElement implements AbstractInvokable {
|
||||||
|
|
||||||
|
public DynamicInvokable() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemberType getMemberType() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStatic() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
slangc/codegraph/DynamicLink.sauce
Normal file
10
slangc/codegraph/DynamicLink.sauce
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public abstract class DynamicLink implements AbstractLink {
|
||||||
|
|
||||||
|
public DynamicLink() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
10
slangc/codegraph/DynamicMethod.sauce
Normal file
10
slangc/codegraph/DynamicMethod.sauce
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public class DynamicMethod extends DynamicInvokable implements AbstractMethod {
|
||||||
|
|
||||||
|
public DynamicMethod() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
87
slangc/codegraph/DynamicNamedElement.sauce
Normal file
87
slangc/codegraph/DynamicNamedElement.sauce
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public class DynamicNamedElement implements AbstractNamedElement {
|
||||||
|
private AbstractContainer container = null;
|
||||||
|
private String name = "";
|
||||||
|
private Object compilerObject = null;
|
||||||
|
|
||||||
|
public void setEnclosingContainer(AbstractContainer container) {
|
||||||
|
if (this.container != null) {
|
||||||
|
throw new Error("Container is already set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractContainer getEnclosingContainer() {
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSimpleName(String name) {
|
||||||
|
if (!this.name.equals("")) {
|
||||||
|
throw new Error("SimpleName is already set.");
|
||||||
|
}
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSimpleName() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFullName() {
|
||||||
|
if (container != null && container != getSet()) {
|
||||||
|
return container.getFullName() + "." + getSimpleName();
|
||||||
|
} else {
|
||||||
|
return getSimpleName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractTypeDefinition getType() {
|
||||||
|
if (this instanceof AbstractTypeDefinition) {
|
||||||
|
return (AbstractTypeDefinition) this;
|
||||||
|
} else if (container != null) {
|
||||||
|
return container.getType();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractPackage getPackage() {
|
||||||
|
if (this instanceof AbstractPackage) {
|
||||||
|
return (AbstractPackage) this;
|
||||||
|
} else if (container != null) {
|
||||||
|
return container.getPackage();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractSet getSet() {
|
||||||
|
if (this instanceof AbstractSet) {
|
||||||
|
return (AbstractSet) this;
|
||||||
|
} else if (container != null) {
|
||||||
|
return container.getSet();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractWorld getWorld() {
|
||||||
|
if (this instanceof AbstractWorld) {
|
||||||
|
return (AbstractWorld) this;
|
||||||
|
} else if (container != null) {
|
||||||
|
return container.getWorld();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getCompilerObject() {
|
||||||
|
return compilerObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompilerObject(Object compilerObject) {
|
||||||
|
this.compilerObject = compilerObject;
|
||||||
|
}
|
||||||
|
}
|
12
slangc/codegraph/DynamicPackage.sauce
Normal file
12
slangc/codegraph/DynamicPackage.sauce
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public class DynamicPackage extends DynamicContainer implements AbstractPackage {
|
||||||
|
|
||||||
|
public DynamicPackage() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContainerType getContainerType() {
|
||||||
|
return ContainerType.PACKAGE;
|
||||||
|
}
|
||||||
|
}
|
12
slangc/codegraph/DynamicSet.sauce
Normal file
12
slangc/codegraph/DynamicSet.sauce
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public class DynamicSet extends DynamicContainer implements AbstractSet {
|
||||||
|
|
||||||
|
public DynamicSet() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContainerType getContainerType() {
|
||||||
|
return ContainerType.SET;
|
||||||
|
}
|
||||||
|
}
|
13
slangc/codegraph/DynamicTagDefinition.sauce
Normal file
13
slangc/codegraph/DynamicTagDefinition.sauce
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public class DynamicTagDefinition extends DynamicInterfaceDefinition implements AbstractTagDefinition {
|
||||||
|
|
||||||
|
public DynamicTagDefinition() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeType getTypeType() {
|
||||||
|
return TypeType.TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
slangc/codegraph/DynamicType.sauce
Normal file
35
slangc/codegraph/DynamicType.sauce
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public abstract class DynamicType extends DynamicContainer implements AbstractTypeDefinition {
|
||||||
|
private DynamicLink[] interfaces = new DynamicLink[0];
|
||||||
|
|
||||||
|
public DynamicType() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContainerType getContainerType() {
|
||||||
|
return ContainerType.TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int countInheritedInterfaces() {
|
||||||
|
return interfaces.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DynamicLink getInheritedInterface(int index) {
|
||||||
|
if (index < 0 || index > interfaces.length) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return interfaces[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendInheritedInterface(DynamicLink iface) {
|
||||||
|
DynamicLink[] nifcs = new DynamicLink[interfaces.length + 1];
|
||||||
|
for (int i = 0; i < interfaces.length; i++) {
|
||||||
|
nifcs[i] = interfaces[i];
|
||||||
|
}
|
||||||
|
nifcs[nifcs.length - 1] = iface;
|
||||||
|
interfaces = nifcs;
|
||||||
|
}
|
||||||
|
}
|
13
slangc/codegraph/DynamicWorld.sauce
Normal file
13
slangc/codegraph/DynamicWorld.sauce
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public class DynamicWorld extends DynamicContainer implements AbstractWorld {
|
||||||
|
|
||||||
|
public DynamicWorld() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContainerType getContainerType() {
|
||||||
|
return ContainerType.WORLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
slangc/codegraph/MemberType.sauce
Normal file
8
slangc/codegraph/MemberType.sauce
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public enum MemberType {
|
||||||
|
FIELD,
|
||||||
|
METHOD,
|
||||||
|
CONSTRUCTOR,
|
||||||
|
TYPE
|
||||||
|
}
|
9
slangc/codegraph/TypeType.sauce
Normal file
9
slangc/codegraph/TypeType.sauce
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package slangc.codegraph;
|
||||||
|
|
||||||
|
public enum TypeType {
|
||||||
|
UNINITIALISED,
|
||||||
|
CLASS,
|
||||||
|
INTERFACE,
|
||||||
|
ENUM,
|
||||||
|
TAG
|
||||||
|
}
|
66
slangc/model/AbstractMemberSet.sauce
Normal file
66
slangc/model/AbstractMemberSet.sauce
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slang.data.List;
|
||||||
|
|
||||||
|
public abstract class AbstractMemberSet {
|
||||||
|
TypeModel owner;
|
||||||
|
MemberCategory category;
|
||||||
|
private List<MemberModel> array = new List<MemberModel>();
|
||||||
|
|
||||||
|
public AbstractMemberSet(TypeModel owner, MemberCategory category) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.category = category;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public TypeModel getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemberCategory getCategory() {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMember(MemberModel field) {
|
||||||
|
if (field.getCategory() != getCategory()) {
|
||||||
|
throw new Error("Tried to add member in category " + field.getCategory() + " in set of different category " + getCategory());
|
||||||
|
}
|
||||||
|
array.append(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countMembers() {
|
||||||
|
return array.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countMembersNamed(String name) {
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < array.count(); i++) {
|
||||||
|
if (array.get(i).matchesName(null, name)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasMemberNamed(String name) {
|
||||||
|
return countMembersNamed(name) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemberModel getMember(int i) {
|
||||||
|
return array.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemberModel getMemberNamed(String name, int i) {
|
||||||
|
int count = 0;
|
||||||
|
for (int x = 0; x < array.count(); x++) {
|
||||||
|
if (array.get(x).matchesName(null, name)) {
|
||||||
|
if (count == i) {
|
||||||
|
return array.get(x);
|
||||||
|
} else {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error("Tried to get definition #" + i + " of members named '" + name + "' but only " + countMembersNamed(name) + " such definitions exist");
|
||||||
|
}
|
||||||
|
}
|
65
slangc/model/AliasTypeModel.sauce
Normal file
65
slangc/model/AliasTypeModel.sauce
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.api.Reporter;
|
||||||
|
|
||||||
|
public class AliasTypeModel extends SyntheticTypeModel {
|
||||||
|
private PackageModel targetPackage;
|
||||||
|
private String targetName;
|
||||||
|
private TypeModel target;
|
||||||
|
|
||||||
|
public AliasTypeModel(PackageModel packageModel, String name, TypeLevel level, TypeModel owner, PackageModel targetPackage, String targetname) {
|
||||||
|
super(packageModel, name, level, owner);
|
||||||
|
this.targetPackage = targetPackage;
|
||||||
|
this.targetName = targetname;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeType getTypeType() {
|
||||||
|
return TypeType.ALIAS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageModel getTargetPackage() {
|
||||||
|
return targetPackage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTargetName() {
|
||||||
|
return targetName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int expand() {
|
||||||
|
if (existsAtRuntime() && target == null) {
|
||||||
|
target = targetPackage.getType(targetName);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int resolveTypes() {
|
||||||
|
//System.out.println("TODO: resolveTypes in " + this.getClass().getName());
|
||||||
|
return expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dump(Reporter reporter, String indent, String incr) {
|
||||||
|
super.dump(reporter, indent, incr);
|
||||||
|
reporter.note("DUMP", indent + incr + "[points to " + target + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeModel simplify() {
|
||||||
|
expand();
|
||||||
|
if (target != null) {
|
||||||
|
return target.simplify();
|
||||||
|
} else {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isObjectType() {
|
||||||
|
return target.isObjectType();
|
||||||
|
}
|
||||||
|
}
|
90
slangc/model/ArrayTypeModel.sauce
Normal file
90
slangc/model/ArrayTypeModel.sauce
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.api.Reporter;
|
||||||
|
|
||||||
|
public class ArrayTypeModel extends SyntheticTypeModel {
|
||||||
|
private TypeModel target;
|
||||||
|
|
||||||
|
public ArrayTypeModel(TypeModel target) {
|
||||||
|
super(target.getPackage(), "[]", TypeLevel.ARRAY, target);
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeType getTypeType() {
|
||||||
|
return TypeType.ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int expand() {
|
||||||
|
/*
|
||||||
|
if (existsAtRuntime() && target == null) {
|
||||||
|
target = targetPackage.getType(targetName);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}*/
|
||||||
|
/*if (target == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return target.expand();
|
||||||
|
}*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int resolveTypes() {
|
||||||
|
//System.out.println("TODO: resolveTypes in " + this.getClass().getName());
|
||||||
|
return expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dump(Reporter reporter, String indent, String incr) {
|
||||||
|
super.dump(reporter, indent, incr);
|
||||||
|
reporter.note("DUMP", indent + incr + "[element type " + target + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeModel simplify() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getElementType() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isObjectType() {
|
||||||
|
// Arrays are generally treated as objects
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean inherits(TypeModel otherType) {
|
||||||
|
if (otherType == getPackage().getSystem().getDefaultBaseType()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodModel[] getMethods(String name, boolean includeBase) {
|
||||||
|
if (includeBase) {
|
||||||
|
return getPackage().getSystem().getDefaultBaseType().getMethods(name, includeBase);
|
||||||
|
} else {
|
||||||
|
return new MethodModel[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAssignableFrom(TypeModel otherType) {
|
||||||
|
if (super.isAssignableFrom(otherType)) {
|
||||||
|
return true;
|
||||||
|
} else if (target.isObjectType() && otherType instanceof ArrayTypeModel) {
|
||||||
|
return target.isAssignableFrom(((ArrayTypeModel) otherType).target);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
slangc/model/AttributeModel.sauce
Normal file
9
slangc/model/AttributeModel.sauce
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public abstract class AttributeModel {
|
||||||
|
|
||||||
|
public AttributeModel() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
5
slangc/model/AttributeOwner.sauce
Normal file
5
slangc/model/AttributeOwner.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public interface AttributeOwner {
|
||||||
|
AttributeSet getAttributes();
|
||||||
|
}
|
272
slangc/model/AttributeSet.sauce
Normal file
272
slangc/model/AttributeSet.sauce
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slang.data.List;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.ErrorType;
|
||||||
|
import slangc.parser.Language;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.NodeType;
|
||||||
|
import slangc.parser.Token;
|
||||||
|
|
||||||
|
public class AttributeSet {
|
||||||
|
private AttributeOwner owner;
|
||||||
|
private Branch source;
|
||||||
|
private boolean isStatic = false;
|
||||||
|
private boolean isPublic = false;
|
||||||
|
private boolean isPrivate = false;
|
||||||
|
private boolean isProtected = false;
|
||||||
|
private boolean isAbstract = false;
|
||||||
|
private boolean isFinal = false;
|
||||||
|
private boolean isNative = false;
|
||||||
|
private boolean isTransient = false;
|
||||||
|
private boolean isSynchronized = false;
|
||||||
|
private boolean isVolatile = false;
|
||||||
|
private List<Translation> translations = new List<AttributeSet.Translation>();
|
||||||
|
|
||||||
|
public static class Translation {
|
||||||
|
public final String language;
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
public Translation(String language, String name) {
|
||||||
|
this.language = language;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(String[] enabledLanguages, String name) {
|
||||||
|
return matchesEnabledLanguages(enabledLanguages) && matchesName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesEnabledLanguages(String[] enabledLanguages) {
|
||||||
|
if (enabledLanguages == null) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < enabledLanguages.length; i++) {
|
||||||
|
if (enabledLanguages[i].equals(language)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesName(String n) {
|
||||||
|
return n.equals(this.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countTranslations() {
|
||||||
|
return translations.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Translation getTranslation(int i) {
|
||||||
|
return translations.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFlags() {
|
||||||
|
int f = 0;
|
||||||
|
|
||||||
|
if (isPublic()) {
|
||||||
|
f |= Flags.MASK_PUBLIC;
|
||||||
|
} else if (isPrivate()) {
|
||||||
|
f |= Flags.MASK_PRIVATE;
|
||||||
|
} else if (isProtected()) {
|
||||||
|
f |= Flags.MASK_PROTECTED;
|
||||||
|
} else {
|
||||||
|
f |= Flags.MASK_PACKAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStatic()) {
|
||||||
|
f |= Flags.MASK_STATIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAbstract()) {
|
||||||
|
f |= Flags.MASK_PUBLIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFinal()) {
|
||||||
|
f |= Flags.MASK_FINAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNative()) {
|
||||||
|
f |= Flags.MASK_NATIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPublic()) {
|
||||||
|
f |= Flags.MASK_TRANSIENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPublic()) {
|
||||||
|
f |= Flags.MASK_VOLATILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttributeSet(AttributeOwner owner, Branch source) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.source = source;
|
||||||
|
|
||||||
|
if (source != null) {
|
||||||
|
for (int i = 0; i < source.countSubnodes(); i++) {
|
||||||
|
Node n = source.getSubnode(i);
|
||||||
|
if (n.getNodeType() == NodeType.SIMPLE_MODIFIER) {
|
||||||
|
applySimpleModifier((Token)((Branch)n).getSubnode(0));
|
||||||
|
} else if (n.getNodeType() == NodeType.NAME_TAGGED_MODIFIER) {
|
||||||
|
Node langName = ((Branch)n).getSubnode(1);
|
||||||
|
Node itemName = ((Branch)n).getSubnode(3);
|
||||||
|
Token lt = ((Token)((Branch) langName).getSubnode(0));
|
||||||
|
Token it = ((Token)((Branch) itemName).getSubnode(0));
|
||||||
|
applyTranslation(lt.getSnippet().getSource(), it.getSnippet().getSource());
|
||||||
|
} else if (n.getNodeType() == NodeType.SIMPLE_MODIFIER) {
|
||||||
|
Node itemName = ((Branch)n).getSubnode(1);
|
||||||
|
Token it = ((Token)((Branch) itemName).getSubnode(0));
|
||||||
|
applyTranslation("", it.getSnippet().getSource());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyTranslation(String language, String name) {
|
||||||
|
this.translations.append(new Translation(language, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesTranslation(String[] enabledLanguages, String name) {
|
||||||
|
for (int i = 0; i < translations.count(); i++) {
|
||||||
|
Translation t = translations.get(i);
|
||||||
|
if (t.matches(enabledLanguages, name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applySimpleModifier(Token name) {
|
||||||
|
String src = name.getSnippet().getSource();
|
||||||
|
if (name.getOwner().getLanguage().matches(Language.Key.PUBLIC, src)) {
|
||||||
|
if (isPublic) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier is already set");
|
||||||
|
} else if (isPrivate || isProtected) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier conflicts with another modifier");
|
||||||
|
}
|
||||||
|
isPublic = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (name.getOwner().getLanguage().matches(Language.Key.STATIC, src)) { //src.equals("static")) {
|
||||||
|
if (isStatic) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier is already set");
|
||||||
|
}/* else if (isAbstract) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier conflicts with another modifier");
|
||||||
|
}*/
|
||||||
|
isStatic = true;
|
||||||
|
} else if (name.getOwner().getLanguage().matches(Language.Key.ABSTRACT, src)) { //src.equals("abstract")) {
|
||||||
|
if (isAbstract) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier is already set");
|
||||||
|
} else if (isFinal || isNative) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier conflicts with another modifier");
|
||||||
|
}
|
||||||
|
isAbstract = true;
|
||||||
|
} else if (name.getOwner().getLanguage().matches(Language.Key.FINAL, src)) { //src.equals("final")) {
|
||||||
|
if (isFinal) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier is already set");
|
||||||
|
} else if (isAbstract) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier conflicts with another modifier");
|
||||||
|
}
|
||||||
|
isFinal = true;
|
||||||
|
} else if (name.getOwner().getLanguage().matches(Language.Key.NATIVE, src)) { //src.equals("native")) {
|
||||||
|
if (isNative) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier is already set");
|
||||||
|
}/* else if (isStatic || isAbstract) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier conflicts with another modifier");
|
||||||
|
}*/
|
||||||
|
isNative = true;
|
||||||
|
} else if (name.getOwner().getLanguage().matches(Language.Key.PUBLIC, src)) { //src.equals("public")) {
|
||||||
|
// default setting left
|
||||||
|
} else if (name.getOwner().getLanguage().matches(Language.Key.PRIVATE, src)) { //src.equals("private")) {
|
||||||
|
if (isPrivate) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier is already set");
|
||||||
|
} else if (isPublic || isProtected) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier conflicts with another modifier");
|
||||||
|
}
|
||||||
|
isPrivate = true;
|
||||||
|
} else if (name.getOwner().getLanguage().matches(Language.Key.PROTECTED, src)) {//src.equals("protected")) {
|
||||||
|
if (isProtected) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier is already set");
|
||||||
|
} else if (isPublic || isPrivate) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier conflicts with another modifier");
|
||||||
|
}
|
||||||
|
isProtected = true;
|
||||||
|
} else if (name.getOwner().getLanguage().matches(Language.Key.TRANSIENT, src)) { //src.equals("transient")) {
|
||||||
|
if (isTransient) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier is already set");
|
||||||
|
}/* else if (isPublic) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier conflicts with another modifier");
|
||||||
|
}*/
|
||||||
|
isTransient = true;
|
||||||
|
} else if (name.getOwner().getLanguage().matches(Language.Key.SYNCHRONISED, src)) { //src.equals("synchronized")) {
|
||||||
|
if (isSynchronized) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier is already set");
|
||||||
|
}/* else if (isPublic) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier conflicts with another modifier");
|
||||||
|
}*/
|
||||||
|
isSynchronized = true;
|
||||||
|
} else if (name.getOwner().getLanguage().matches(Language.Key.VOLATILE, src)) { //src.equals("volatile")) {
|
||||||
|
if (isVolatile) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier is already set");
|
||||||
|
}/* else if (isPublic) {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "This modifier conflicts with another modifier");
|
||||||
|
}*/
|
||||||
|
isVolatile = true;
|
||||||
|
} else {
|
||||||
|
name.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised modifier");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttributeOwner getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Branch getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStatic() {
|
||||||
|
return isStatic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAbstract() {
|
||||||
|
return isAbstract;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinal() {
|
||||||
|
return isFinal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNative() {
|
||||||
|
return isNative;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrivate() {
|
||||||
|
return isPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPublic() {
|
||||||
|
return isPublic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isProtected() {
|
||||||
|
return isProtected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTransient() {
|
||||||
|
return isTransient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSynchronized() {
|
||||||
|
return isSynchronized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVolatile() {
|
||||||
|
return isVolatile;
|
||||||
|
}
|
||||||
|
}
|
66
slangc/model/BuiltinTypeBehaviour.sauce
Normal file
66
slangc/model/BuiltinTypeBehaviour.sauce
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public class BuiltinTypeBehaviour {
|
||||||
|
|
||||||
|
public boolean isAssignableFrom(TypeModel otherType) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** If it waddles like a duck and quacks like a duck then it's a duck. */
|
||||||
|
public static class DuckBehaviour extends BuiltinTypeBehaviour {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAssignableFrom(TypeModel otherType) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NumberBehaviour extends BuiltinTypeBehaviour {
|
||||||
|
private boolean isFloat;
|
||||||
|
private boolean isSigned;
|
||||||
|
private int numberOfBits;
|
||||||
|
public NumberBehaviour(boolean isFloat, boolean isSigned, int numberOfBits) {
|
||||||
|
super();
|
||||||
|
this.isFloat = isFloat;
|
||||||
|
this.isSigned = isSigned;
|
||||||
|
this.numberOfBits = numberOfBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAssignableFrom(TypeModel otherType) {
|
||||||
|
if (otherType instanceof BuiltinTypeModel) {
|
||||||
|
BuiltinTypeModel otherBuiltin = (BuiltinTypeModel) otherType;
|
||||||
|
BuiltinTypeBehaviour otherBehaviour = otherBuiltin.getBuiltinTypeBehaviour();
|
||||||
|
if (otherBehaviour instanceof NumberBehaviour) {
|
||||||
|
return isAssignableFrom((NumberBehaviour)otherBehaviour);
|
||||||
|
} else if (otherBehaviour instanceof DuckBehaviour) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAssignableFrom(NumberBehaviour otherBehaviour) {
|
||||||
|
// Handle floats first
|
||||||
|
if (this.isFloat && !otherBehaviour.isFloat) {
|
||||||
|
return true;
|
||||||
|
} else if (!this.isFloat && otherBehaviour.isFloat) {
|
||||||
|
return false;
|
||||||
|
} else if (this.isFloat && otherBehaviour.isFloat) {
|
||||||
|
return this.numberOfBits >= otherBehaviour.numberOfBits;
|
||||||
|
}
|
||||||
|
// Otherwise we know it's an integer
|
||||||
|
if (this.numberOfBits == otherBehaviour.numberOfBits && this.isSigned == otherBehaviour.isSigned) {
|
||||||
|
return true;
|
||||||
|
} else if (this.numberOfBits > otherBehaviour.numberOfBits) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
slangc/model/BuiltinTypeModel.sauce
Normal file
45
slangc/model/BuiltinTypeModel.sauce
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public class BuiltinTypeModel extends SyntheticTypeModel {
|
||||||
|
|
||||||
|
private final BuiltinTypeBehaviour builtinTypeBehaviour;
|
||||||
|
|
||||||
|
public BuiltinTypeModel(PackageModel packageModel, String name, TypeLevel level, TypeModel owner, BuiltinTypeBehaviour builtinTypeBehaviour) {
|
||||||
|
super(packageModel, name, level, owner);
|
||||||
|
this.builtinTypeBehaviour = builtinTypeBehaviour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BuiltinTypeBehaviour getBuiltinTypeBehaviour() {
|
||||||
|
return builtinTypeBehaviour;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeType getTypeType() {
|
||||||
|
return TypeType.BUILTIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int expand() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int resolveTypes() {
|
||||||
|
//System.out.println("TODO: resolveTypes in " + this.getClass().getName());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isObjectType() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAssignableFrom(TypeModel otherType) {
|
||||||
|
if (super.isAssignableFrom(otherType)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return getBuiltinTypeBehaviour().isAssignableFrom(otherType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
89
slangc/model/ClauseModel.sauce
Normal file
89
slangc/model/ClauseModel.sauce
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.api.Reporter;
|
||||||
|
import slangc.model.clauses.*;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.NodeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A "clause" is basically used for any substatement/subexpression which can't be interpreted
|
||||||
|
* as a statement or expression by itself.
|
||||||
|
*
|
||||||
|
* <p/>There are still some subexpressions which may work more like a clause (not producing a normal
|
||||||
|
* expression result but only helping to resolve an outer expression), but in ambiguous cases these
|
||||||
|
* are treated as normal expressions rather than clauses
|
||||||
|
* (particularly subreferences like "x.y", which could refer to a field "y" within a local variable
|
||||||
|
* "x", or to a class "y" within package "x", or to a package "x.y" from which the class "x.y.Z" can
|
||||||
|
* be resolved in an outer subreference - but since this might just be a simple expression referring
|
||||||
|
* to a field it's stored in an ExpressionModel instead).
|
||||||
|
*
|
||||||
|
* @author Zak
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class ClauseModel {
|
||||||
|
private StatementOwner owner;
|
||||||
|
private Node source;
|
||||||
|
|
||||||
|
public ClauseModel(StatementOwner owner, Node source) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatementOwner getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClauseModel construct(StatementOwner owner, Node source) {
|
||||||
|
switch (source.getNodeType()) {
|
||||||
|
case NodeType.NO_ELSE_CLAUSE:
|
||||||
|
case NodeType.NO_FINALLY_CLAUSE:
|
||||||
|
return null;
|
||||||
|
case NodeType.CATCH_CLAUSE:
|
||||||
|
return new CatchClause(owner, (Branch)source);
|
||||||
|
case NodeType.FINALLY_CLAUSE:
|
||||||
|
return new FinallyClause(owner, (Branch)source);
|
||||||
|
case NodeType.ELSE_CLAUSE:
|
||||||
|
return new ElseClause(owner, (Branch)source);
|
||||||
|
case NodeType.ARRAY_EXPRESSIONS:
|
||||||
|
case NodeType.EXPRESSIONS:
|
||||||
|
return new Expressions((ExpressionOwner)owner, (Branch)source);
|
||||||
|
case NodeType.ARGUMENTS:
|
||||||
|
return new Arguments((ExpressionOwner)owner, (Branch)source);
|
||||||
|
case NodeType.SIMPLE_ARGUMENT_DECLARATION:
|
||||||
|
case NodeType.FOR_VARIABLES:
|
||||||
|
return new Variables(owner, (Branch) source);
|
||||||
|
case NodeType.SWITCH_MEMBERS:
|
||||||
|
return new SwitchMembers(owner, (Branch) source);
|
||||||
|
default:
|
||||||
|
Log.line("Unrecognised clause is type " + source.getNodeType());
|
||||||
|
return new UnrecognisedClause(owner, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClauseModel[] constructMultiple(StatementOwner owner, Branch source) {
|
||||||
|
ClauseModel[] result = new ClauseModel[source.countSubnodes()];
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
result[i] = construct(owner, source.getSubnode(i));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump(Reporter reporter, String indent, String incr) {
|
||||||
|
reporter.note("DUMP", indent + incr + "TODO: dump " + Type.of(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Named lookupSimpleName(String name) {
|
||||||
|
return getOwner().lookupSimpleName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel[] lookupSimpleMethod(String name) {
|
||||||
|
return getOwner().lookupSimpleMethod(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int resolveExpressions();
|
||||||
|
}
|
42
slangc/model/CombinedImportModel.sauce
Normal file
42
slangc/model/CombinedImportModel.sauce
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public class CombinedImportModel extends ImportModel {
|
||||||
|
private ImportModel[] models;
|
||||||
|
|
||||||
|
public CombinedImportModel(SystemModel system, boolean synthetic, ImportModel[] innerModels) {
|
||||||
|
super(system, synthetic);
|
||||||
|
models = innerModels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countInnerModels() {
|
||||||
|
return models.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImportModel getInnerModel(int index) {
|
||||||
|
return models[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeModel lookupExact(String name) {
|
||||||
|
for (int i = 0; i < models.length; i++) {
|
||||||
|
//System.out.println("Checking '" + name + "' against " + models[i]);
|
||||||
|
TypeModel x = models[i].lookupExact(name);
|
||||||
|
if (x != null) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeModel lookupLoose(String name) {
|
||||||
|
for (int i = 0; i < models.length; i++) {
|
||||||
|
//System.out.println("Checking '" + name + "' against " + models[i]);
|
||||||
|
TypeModel x = models[i].lookupLoose(name);
|
||||||
|
if (x != null) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
313
slangc/model/ExpressionModel.sauce
Normal file
313
slangc/model/ExpressionModel.sauce
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.api.BytecodeInstructionWriter;
|
||||||
|
import slangc.api.Reporter;
|
||||||
|
import slangc.bytecode.TypeSignature;
|
||||||
|
import slangc.model.clauses.Arguments;
|
||||||
|
import slangc.model.expressions.*;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.ErrorType;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.NodeType;
|
||||||
|
import slangc.parser.NoteAnnotation;
|
||||||
|
|
||||||
|
public abstract class ExpressionModel extends StatementOrExpression implements ExpressionOwner {
|
||||||
|
ExpressionOwner owner;
|
||||||
|
Node source;
|
||||||
|
ExpressionResult resolvedResult;
|
||||||
|
|
||||||
|
public ExpressionModel(ExpressionOwner owner, Node source) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpressionOwner getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ExpressionModel construct(ExpressionOwner owner, Node source) {
|
||||||
|
switch (source.getNodeType()) {
|
||||||
|
case NodeType.BRACED_EXPRESSION:
|
||||||
|
return construct(owner, ((Branch) source).getSubnode(1));
|
||||||
|
case NodeType.INTEGER_LITERAL_EXPRESSION:
|
||||||
|
case NodeType.CHAR_LITERAL_EXPRESSION:
|
||||||
|
case NodeType.BOOLEAN_LITERAL_EXPRESSION:
|
||||||
|
case NodeType.STRING_LITERAL_EXPRESSION:
|
||||||
|
case NodeType.FLOAT_LITERAL_EXPRESSION:
|
||||||
|
case NodeType.NULL_LITERAL_EXPRESSION:
|
||||||
|
return new LiteralExpression(owner, source);
|
||||||
|
case NodeType.ADDITIVE_EXPRESSION:
|
||||||
|
case NodeType.MULTIPLICATIVE_EXPRESSION:
|
||||||
|
case NodeType.COMPARISON_EXPRESSION:
|
||||||
|
case NodeType.LOGICAL_EXPRESSION:
|
||||||
|
case NodeType.SHIFT_EXPRESSION:
|
||||||
|
case NodeType.EQUALITY_EXPRESSION:
|
||||||
|
case NodeType.BITWISE_AND_EXPRESSION:
|
||||||
|
case NodeType.BITWISE_XOR_EXPRESSION:
|
||||||
|
case NodeType.BITWISE_OR_EXPRESSION:
|
||||||
|
case NodeType.LOGICAL_AND_EXPRESSION:
|
||||||
|
case NodeType.LOGICAL_OR_EXPRESSION:
|
||||||
|
return new BinaryExpression(owner, source);
|
||||||
|
case NodeType.CONDITIONAL_EXPRESSION:
|
||||||
|
return new ConditionalExpression(owner, source);
|
||||||
|
case NodeType.REFERENCE_EXPRESSION:
|
||||||
|
return new ReferenceExpression(owner, source);
|
||||||
|
case NodeType.GENERIC_REFERENCE_EXPRESSION:
|
||||||
|
return new GenericReferenceExpression(owner, source);
|
||||||
|
case NodeType.THIS_EXPRESSION:
|
||||||
|
return new ThisExpression(owner, source);
|
||||||
|
case NodeType.SUBREFERENCE_EXPRESSION:
|
||||||
|
if (((Branch)source).getSubnode(0).getNodeType() == NodeType.SUPER) {
|
||||||
|
return new SuperReferenceExpression(owner, source);
|
||||||
|
} else {
|
||||||
|
return new SubreferenceExpression(owner, source);
|
||||||
|
}
|
||||||
|
case NodeType.ASSIGNMENT_EXPRESSION:
|
||||||
|
return new AssignmentExpression(owner, source);
|
||||||
|
case NodeType.UNARY_EXPRESSION:
|
||||||
|
return new UnaryExpression(owner, source);
|
||||||
|
case NodeType.COUNT_EXPRESSION:
|
||||||
|
return new CountExpression(owner, source);
|
||||||
|
case NodeType.CAST_EXPRESSION:
|
||||||
|
return new CastExpression(owner, source);
|
||||||
|
case NodeType.INSTANCEOF_EXPRESSION:
|
||||||
|
return new InstanceofExpression(owner, source);
|
||||||
|
case NodeType.TYPE_EXPRESSION:
|
||||||
|
return new TypeExpression(owner, source);
|
||||||
|
case NodeType.OUTER_THIS_EXPRESSION:
|
||||||
|
return new OuterThisExpression(owner, source);
|
||||||
|
case NodeType.NEW_OBJECT_EXPRESSION:
|
||||||
|
return new NewObjectExpression(owner, source);
|
||||||
|
case NodeType.NEW_CLASS_EXPRESSION:
|
||||||
|
return new NewClassExpression(owner, source);
|
||||||
|
case NodeType.NEW_CLEARED_ARRAY_EXPRESSION:
|
||||||
|
return new NewClearedArrayExpression(owner, source);
|
||||||
|
case NodeType.NEW_INITIALISED_ARRAY_EXPRESSION:
|
||||||
|
return new NewInitialisedArrayExpression(owner, source);
|
||||||
|
case NodeType.SUPER_CONSTRUCTOR_CALL_EXPRESSION:
|
||||||
|
return new SuperConstructorCallExpression(owner, source);
|
||||||
|
case NodeType.THIS_CONSTRUCTOR_CALL_EXPRESSION:
|
||||||
|
return new ThisConstructorCallExpression(owner, source);
|
||||||
|
case NodeType.NORMAL_METHOD_CALL_EXPRESSION:
|
||||||
|
return new NormalMethodCallExpression(owner, source);
|
||||||
|
case NodeType.AUTOMATIC_METHOD_CALL_EXPRESSION:
|
||||||
|
return new AutomaticMethodCallExpression(owner, source);
|
||||||
|
case NodeType.SUPER_METHOD_CALL_EXPRESSION:
|
||||||
|
return new SuperMethodCallExpression(owner, source);
|
||||||
|
case NodeType.THIS_METHOD_CALL_EXPRESSION:
|
||||||
|
return new ThisMethodCallExpression(owner, source);
|
||||||
|
case NodeType.ARRAY_INDEX_EXPRESSION:
|
||||||
|
return new ArrayIndexExpression(owner, source);
|
||||||
|
case NodeType.ARRAY_INITIALISER:
|
||||||
|
return new ArrayInitialiserExpression(owner, source);
|
||||||
|
default:
|
||||||
|
return new UnrecognisedExpression(owner, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump(Reporter reporter, String indent, String incr) {
|
||||||
|
reporter.note("DUMP", indent + incr + "TODO: dump " + Type.of(this));
|
||||||
|
dumpResolved(reporter, indent + incr, incr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dumpResolved(Reporter reporter, String indent, String incr) {
|
||||||
|
if (isResolved()) {
|
||||||
|
if (hasTargetMethod()) {
|
||||||
|
reporter.note("DUMP", indent + incr + "Target method is " + getTargetMethod());
|
||||||
|
}
|
||||||
|
reporter.note("DUMP", indent + incr + "Result is " + getResult());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InnerTypeScope getTypeScope() {
|
||||||
|
// TODO: Better interface support
|
||||||
|
if (getOwner() instanceof ExpressionModel) {
|
||||||
|
return ((ExpressionModel)getOwner()).getTypeScope();
|
||||||
|
}
|
||||||
|
return getOwner().getTypeScope();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel resolveType(Node subnode) {
|
||||||
|
// TODO: Better interface support
|
||||||
|
if (getOwner() instanceof ExpressionModel) {
|
||||||
|
return ((ExpressionModel)getOwner()).resolveType(subnode);
|
||||||
|
}
|
||||||
|
return getOwner().resolveType(subnode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemberModel getMethodOrField() {
|
||||||
|
// TODO: Better interface support
|
||||||
|
if (getOwner() instanceof ExpressionModel) {
|
||||||
|
return ((ExpressionModel)getOwner()).getMethodOrField();
|
||||||
|
}
|
||||||
|
return getOwner().getMethodOrField();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Named lookupSimpleName(String name) {
|
||||||
|
// TODO: Better interface support
|
||||||
|
if (getOwner() instanceof ExpressionModel) {
|
||||||
|
return ((ExpressionModel)getOwner()).lookupSimpleName(name);
|
||||||
|
}
|
||||||
|
return getOwner().lookupSimpleName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel[] lookupSimpleMethod(String name) {
|
||||||
|
// TODO: Better interface support
|
||||||
|
if (getOwner() instanceof ExpressionModel) {
|
||||||
|
return ((ExpressionModel)getOwner()).lookupSimpleMethod(name);
|
||||||
|
}
|
||||||
|
return getOwner().lookupSimpleMethod(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used as a default for getSubexpressions() to avoid creating empty arrays.
|
||||||
|
*/
|
||||||
|
public static final ExpressionModel[] NO_SUBEXPRESSIONS = new ExpressionModel[0];
|
||||||
|
|
||||||
|
public abstract ExpressionModel[] getSubexpressions();
|
||||||
|
|
||||||
|
protected int resolveSubexpressions() {
|
||||||
|
int nresolved = 0;
|
||||||
|
ExpressionModel[] exprs = getSubexpressions();
|
||||||
|
for (int i = 0; i < exprs.length; i++) {
|
||||||
|
nresolved += exprs[i].resolveExpressions();
|
||||||
|
}
|
||||||
|
return nresolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int resolveExpressions() {
|
||||||
|
if (isResolved()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int nresolved = resolveSubexpressions();
|
||||||
|
/** If subexpressions resulted in an error, return early to avoid making concentric nonsense errors. */
|
||||||
|
if (getSource().countErrorsRecursively() > 0) {
|
||||||
|
return nresolved;
|
||||||
|
}
|
||||||
|
resolvedResult = resolveResult();
|
||||||
|
if (resolvedResult == null) {
|
||||||
|
/* For consistency, failed resolutions logically resolve to an invalid result. */
|
||||||
|
resolvedResult = ExpressionResult.INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolvedResult.getKind() == ExpressionResult.Kind.INVALID) {
|
||||||
|
if (getSource() == null) {
|
||||||
|
throw new Error("Internal error: Failed to resolve synthetic expression " + this);
|
||||||
|
}
|
||||||
|
if (getSource() != null && getSource().countErrorsRecursively() == 0) {
|
||||||
|
getSource().annotate(ErrorType.INTERNAL_ERROR, "Compiler failed to derive any result information in " + Type.of(this));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nresolved++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nresolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should only usually be called once by resolveExpressions(). Before the first call,
|
||||||
|
* any subexpressions are resolved recursively. After the first call,
|
||||||
|
* the expression result is stored by ExpressionModel and accessible from getResult().
|
||||||
|
*
|
||||||
|
* @return Either an ExpressionResult instance holding the resolved information
|
||||||
|
* about the expression's result, or null (which will be taken as an invalid result).
|
||||||
|
*/
|
||||||
|
//protected abstract ExpressionResult resolveResult();
|
||||||
|
protected ExpressionResult resolveResult() {return null;}
|
||||||
|
|
||||||
|
public boolean isResolved() {
|
||||||
|
return resolvedResult != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpressionResult getResult() {
|
||||||
|
if (!isResolved()) {
|
||||||
|
throw new Error("Attempting to get result of unresolved expression!");
|
||||||
|
}
|
||||||
|
return resolvedResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SystemModel getSystem() {
|
||||||
|
return getOwner().getMethodOrField().getOwner().getPackage().getSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasTargetMethod() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel getTargetMethod() {
|
||||||
|
throw new Error("Can't get target method of a " + Type.of(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to select the best applicable method from a list of available options, using
|
||||||
|
* the static methods of MethodModel to sort through them. The reason for doing the final
|
||||||
|
* selection here is so that we can report errors in the right place and in a consistent way.
|
||||||
|
*
|
||||||
|
* <p/>
|
||||||
|
* If a single "best" method is found, it is returned. Otherwise (if zero methods match or
|
||||||
|
* if multiple match and we can't select a best one from them) an error is reported and
|
||||||
|
* null is returned.
|
||||||
|
*
|
||||||
|
* @param availableMethods
|
||||||
|
* @param arguments
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public MethodModel bestTargetMethod(MethodModel[] availableMethods, Arguments arguments) {
|
||||||
|
MethodModel[] bestChoices = //MethodModel.findApplicableMethods(availableMethods, arguments);
|
||||||
|
MethodModel.bestApplicableMethods(availableMethods, arguments, false);
|
||||||
|
|
||||||
|
/* If we can't find a relevant method without varargs, only then try varargs. */
|
||||||
|
if (bestChoices.length != 1) {
|
||||||
|
MethodModel[] newChoices = MethodModel.bestApplicableMethods(availableMethods, arguments, true);
|
||||||
|
if (newChoices.length == 1) {
|
||||||
|
return newChoices[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestChoices.length == 1) {
|
||||||
|
return bestChoices[0];
|
||||||
|
} else if (bestChoices.length > 1) {
|
||||||
|
getSource().annotate(ErrorType.INTERNAL_ERROR, "Ambiguous method invocation");
|
||||||
|
for (int i = 0; i < bestChoices.length; i++) {
|
||||||
|
getSource().annotate(new NoteAnnotation("Could be referring to " + bestChoices[i]));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} else { // No choices
|
||||||
|
getSource().annotate(ErrorType.INTERNAL_ERROR, "No matching method for " + arguments.resultString());
|
||||||
|
if (availableMethods.length == 0) {
|
||||||
|
getSource().annotate(new NoteAnnotation("There appear to be no such methods to select from"));
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < availableMethods.length; i++) {
|
||||||
|
getSource().annotate(new NoteAnnotation("Failed to match " + availableMethods[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract TypeSignature innerGenerate(BytecodeInstructionWriter w);
|
||||||
|
|
||||||
|
public final TypeSignature generate(BytecodeInstructionWriter w) {
|
||||||
|
w.pushSource(getSource());
|
||||||
|
TypeSignature result = innerGenerate(w);
|
||||||
|
w.popSource();
|
||||||
|
if (result == null) {
|
||||||
|
result = TypeSignature.VOID;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateStore(BytecodeInstructionWriter w, TypeSignature storing) {
|
||||||
|
w.genError("TODO: generateStore for " + Type.of(this));
|
||||||
|
}
|
||||||
|
}
|
5
slangc/model/ExpressionOwner.sauce
Normal file
5
slangc/model/ExpressionOwner.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public interface ExpressionOwner extends StatementOwner {
|
||||||
|
public TypeModel getExpectedResult(ExpressionModel e);
|
||||||
|
}
|
226
slangc/model/ExpressionResult.sauce
Normal file
226
slangc/model/ExpressionResult.sauce
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstraction over the result of an expression, which might be a typeName known
|
||||||
|
* at compile time but more generally just holds knowledge of the resulting type
|
||||||
|
* of an expression. There may also be some edge cases where the type can't be
|
||||||
|
* determined until later (but may not be an error).
|
||||||
|
*
|
||||||
|
* @author Zak
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class ExpressionResult {
|
||||||
|
public static enum Kind {
|
||||||
|
INVALID, /// Failed for some reason
|
||||||
|
VOID, /// This expression is actually invoking a void method (or similar) and has no result
|
||||||
|
NULL, /// This is a null expression, so can be assigned to any normal object but otherwise has no type
|
||||||
|
// Not yet implemented: DUCK, /// This could be anything
|
||||||
|
TYPED_VALUE, /// We have some idea of it's type but not of it's typeName
|
||||||
|
POINTS_TO_TYPE, /// This isn't really an expression as such, just a subexpression pointing to a type
|
||||||
|
START_OF_NAME, /// This isn't really an expression as such, just a subexpression pointing to a package name
|
||||||
|
POINTS_TO_STORAGE_SLOT, /// This points to a storage slot, so it has a typeName type and may also be assignable
|
||||||
|
CONSTANT // We know the exact typeName of the result
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StartOfName extends ExpressionResult {
|
||||||
|
String name;
|
||||||
|
public StartOfName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Kind getKind() {
|
||||||
|
return Kind.START_OF_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNameSoFar() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PointsToType extends ExpressionResult {
|
||||||
|
private TypeModel type;
|
||||||
|
public PointsToType(TypeModel type) {
|
||||||
|
this.type = type;
|
||||||
|
if (type == null) {
|
||||||
|
throw new Error("Type cannot be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Kind getKind() {
|
||||||
|
return Kind.POINTS_TO_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getType() {
|
||||||
|
return type.simplify();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(" + getType() + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TypedValue extends ExpressionResult {
|
||||||
|
TypeModel type;
|
||||||
|
public TypedValue(TypeModel type) {
|
||||||
|
this.type = type.simplify();
|
||||||
|
if (this.type == null) {
|
||||||
|
throw new Error("Type cannot be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Kind getKind() {
|
||||||
|
return Kind.TYPED_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean resolvesToValueOrNull() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeModel getValueType() {
|
||||||
|
return type.simplify();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(" + getValueType() + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PointsToStorageSlot extends ExpressionResult {
|
||||||
|
private ArrayTypeModel arrayType;
|
||||||
|
private StorageSlot slot;
|
||||||
|
public PointsToStorageSlot(ArrayTypeModel arrayType) {
|
||||||
|
this.arrayType = arrayType;
|
||||||
|
}
|
||||||
|
public PointsToStorageSlot(StorageSlot slot) {
|
||||||
|
this.slot = slot;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Kind getKind() {
|
||||||
|
return Kind.POINTS_TO_STORAGE_SLOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean resolvesToValueOrNull() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayTypeModel getArrayType() {
|
||||||
|
return arrayType;
|
||||||
|
}
|
||||||
|
public StorageSlot getSlot() {
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeModel getValueType() {
|
||||||
|
if (arrayType != null) {
|
||||||
|
if (arrayType.getElementType() == null) {
|
||||||
|
throw new Error("Type cannot be null");
|
||||||
|
}
|
||||||
|
return arrayType.getElementType();
|
||||||
|
}
|
||||||
|
if (slot.getStorageType() == null) {
|
||||||
|
throw new Error("Type cannot be null");
|
||||||
|
}
|
||||||
|
return slot.getStorageType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + "(" + getValueType() + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SimpleExpressionResult extends ExpressionResult {
|
||||||
|
private final Kind kind;
|
||||||
|
|
||||||
|
SimpleExpressionResult(Kind kind) {
|
||||||
|
this.kind = kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Kind getKind() {
|
||||||
|
return kind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final ExpressionResult INVALID = new SimpleExpressionResult(Kind.INVALID);
|
||||||
|
|
||||||
|
public static final ExpressionResult VOID = new SimpleExpressionResult(Kind.VOID);
|
||||||
|
|
||||||
|
public static final ExpressionResult NULL = new NullExpressionResult();
|
||||||
|
|
||||||
|
private static class NullExpressionResult extends ExpressionResult {
|
||||||
|
@Override
|
||||||
|
public Kind getKind() {
|
||||||
|
return Kind.NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean resolvesToValueOrNull() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean resolvesToNull() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeModel getValueTypeWithNullType(TypeModel nullType) {
|
||||||
|
return nullType;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Not yet implemented
|
||||||
|
public static final ExpressionResult DUCK = new SimpleExpressionResult(Kind.DUCK);
|
||||||
|
/*/
|
||||||
|
|
||||||
|
//TypeModel typeOrNull;
|
||||||
|
//Named pointedTo;
|
||||||
|
//String constantValue;
|
||||||
|
|
||||||
|
public ExpressionResult() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Kind getKind();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "" + getKind();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean resolvesToNull() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean resolvesToValueOrNull() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean resolvesToValue() {
|
||||||
|
return resolvesToValueOrNull() && !resolvesToNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getValueType() {
|
||||||
|
throw new Error("Can't get typeName type from a " + getKind());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getValueTypeWithNullType(TypeModel nullType) {
|
||||||
|
return getValueType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ExpressionResult fromMethodResult(MethodModel targetMethod) {
|
||||||
|
if (targetMethod == null) {
|
||||||
|
return ExpressionResult.INVALID;
|
||||||
|
} else if (!targetMethod.hasReturnType()) {
|
||||||
|
return ExpressionResult.VOID;
|
||||||
|
} else {
|
||||||
|
return new ExpressionResult.TypedValue(targetMethod.getReturnType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
204
slangc/model/FieldModel.sauce
Normal file
204
slangc/model/FieldModel.sauce
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.api.Reporter;
|
||||||
|
import slangc.bytecode.FieldSignature;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.ErrorType;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.NodeType;
|
||||||
|
|
||||||
|
public class FieldModel extends MemberModel implements ExpressionOwner, StorageSlot {
|
||||||
|
private Branch slotSource;
|
||||||
|
private TypeModel baseStorageType;
|
||||||
|
private ExpressionModel initialisation;
|
||||||
|
private LocalStorageModel upvalueReference;
|
||||||
|
private boolean isEnum = false;
|
||||||
|
|
||||||
|
public FieldModel(UserTypeModel owner, String name, Branch source, Branch slotSource) {
|
||||||
|
super(owner, name, source);
|
||||||
|
this.slotSource = slotSource;
|
||||||
|
baseStorageType = owner.resolveTypeReference(source.getSubnode(1));
|
||||||
|
//if (baseStorageType == null) {
|
||||||
|
// sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Can't find storage type for field");
|
||||||
|
//}
|
||||||
|
if (hasInitialiser()) {
|
||||||
|
initialisation = ExpressionModel.construct(this, slotSource.getSubnode(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldModel(UserTypeModel owner, String name, Branch source) {
|
||||||
|
super(owner, name, source);
|
||||||
|
isEnum = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldModel(UserTypeModel owner, String name, LocalStorageModel upvalueReference) {
|
||||||
|
super(owner, name, null);
|
||||||
|
this.upvalueReference = upvalueReference;
|
||||||
|
baseStorageType = upvalueReference.getStorageType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getNameNode() {
|
||||||
|
return slotSource.getSubnode(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
if (isEnum) {
|
||||||
|
return super.getName();
|
||||||
|
}
|
||||||
|
if (upvalueReference != null) {
|
||||||
|
return upvalueReference.getName();
|
||||||
|
}
|
||||||
|
return UserTypeModel.plainName(getNameNode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countAdditionalIndices() {
|
||||||
|
if (isUpvalue()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Node n = getNameNode();
|
||||||
|
int i = 0;
|
||||||
|
while (n.getNodeType() == NodeType.INDEXED_NAME) {
|
||||||
|
n = ((Branch) n).getSubnode(0);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getStorageType() {
|
||||||
|
if (isEnum) {
|
||||||
|
return getOwner();
|
||||||
|
}
|
||||||
|
TypeModel effectiveType = baseStorageType;
|
||||||
|
if (effectiveType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < countAdditionalIndices(); i++) {
|
||||||
|
effectiveType = effectiveType.getOrCreateArrayInstance();
|
||||||
|
}
|
||||||
|
return effectiveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemberCategory getCategory() {
|
||||||
|
return MemberCategory.FIELD;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Branch getSlotSource() {
|
||||||
|
return slotSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasInitialiser() {
|
||||||
|
if (isEnum) {
|
||||||
|
return false; // Kind of does have an initialiser but is treated specially.
|
||||||
|
}
|
||||||
|
if (isUpvalue()) {
|
||||||
|
return false; // Kind of does have an initialiser but is treated specially.
|
||||||
|
}
|
||||||
|
return getSlotSource().getNodeType() == NodeType.INITIALISED_SLOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//public TypeModel getStorageType() {
|
||||||
|
// return baseStorageType;
|
||||||
|
//}
|
||||||
|
|
||||||
|
public ExpressionModel getInitialisationExpression() {
|
||||||
|
return initialisation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dump(Reporter reporter, String indent, String incr) {
|
||||||
|
super.dump(reporter, indent, incr);
|
||||||
|
if (baseStorageType != null) {
|
||||||
|
reporter.note("DUMP", indent + incr + "> Storage type is " + baseStorageType);
|
||||||
|
} else {
|
||||||
|
reporter.note("DUMP", "[no storage type information]");
|
||||||
|
}
|
||||||
|
if (hasInitialiser()) {
|
||||||
|
reporter.note("DUMP", indent + incr + "> Initialised with expression:");
|
||||||
|
initialisation.dump(reporter, indent + incr + incr, incr);
|
||||||
|
} else {
|
||||||
|
reporter.note("DUMP", indent + incr + "[this field is not initialised]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||||
|
return getStorageType();
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public InnerTypeScope getTypeScope() {
|
||||||
|
return getOwner();
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public TypeModel resolveType(Node typeReference) {
|
||||||
|
return ((UserTypeModel)getOwner()).resolveTypeReference(typeReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public MemberModel getMethodOrField() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StorageSlot.Kind getSlotKind() {
|
||||||
|
if (isStatic()) {
|
||||||
|
return StorageSlot.Kind.STATIC_FIELD;
|
||||||
|
} else {
|
||||||
|
return StorageSlot.Kind.INSTANCE_FIELD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public Named lookupSimpleName(String name) {
|
||||||
|
return getOwner().lookupSimpleName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public MethodModel[] lookupSimpleMethod(String name) {
|
||||||
|
return getOwner().lookupSimpleMethod(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int resolveExpressions() {
|
||||||
|
if (hasInitialiser()) {
|
||||||
|
return getInitialisationExpression().resolveExpressions();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStatic() {
|
||||||
|
if (isEnum) { // Enum fields are always static
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Interface fields are assumed to be static
|
||||||
|
if (getOwner().getTypeType() == TypeType.INTERFACE || getOwner().getTypeType() == TypeType.INTERFACE_TEMPLATE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.isStatic();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnumField() {
|
||||||
|
return isEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUpvalue() {
|
||||||
|
return upvalueReference != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalStorageModel getUpvalueReference() {
|
||||||
|
return upvalueReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFlags() {
|
||||||
|
return super.getFlags() | (isUpvalue() ? (Flags.MASK_UPVALUE | Flags.MASK_SYNTHETIC | Flags.MASK_FINAL) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldSignature getFieldSignature() {
|
||||||
|
return new FieldSignature(getOwner().getTypeSignature(), isStatic(), getStorageType().getTypeSignature(), getName());
|
||||||
|
}
|
||||||
|
}
|
15
slangc/model/FieldSet.sauce
Normal file
15
slangc/model/FieldSet.sauce
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public class FieldSet extends AbstractMemberSet {
|
||||||
|
public FieldSet(TypeModel owner, MemberCategory category) {
|
||||||
|
super(owner,category);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldModel getMember(int i) {
|
||||||
|
return (FieldModel) super.getMember(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldModel getMemberNamed(String name, int i) {
|
||||||
|
return (FieldModel) super.getMemberNamed(name, i);
|
||||||
|
}
|
||||||
|
}
|
26
slangc/model/Flags.sauce
Normal file
26
slangc/model/Flags.sauce
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public final class Flags {
|
||||||
|
public static final int MASK_PUBLIC = (1<<0);
|
||||||
|
public static final int MASK_PACKAGE = (0<<0);
|
||||||
|
public static final int MASK_PROTECTED = (2<<0);
|
||||||
|
public static final int MASK_PRIVATE = (3<<0);
|
||||||
|
|
||||||
|
public static final int MASK_FIELD = (0<<2);
|
||||||
|
public static final int MASK_METHOD = (1<<2);
|
||||||
|
public static final int MASK_CLASS = (2<<2);
|
||||||
|
public static final int MASK_INTERFACE = (3<<2);
|
||||||
|
public static final int MASK_ENUM = (4<<2);
|
||||||
|
|
||||||
|
public static final int MASK_STATIC = (1<<5);
|
||||||
|
public static final int MASK_FINAL = (1<<6);
|
||||||
|
public static final int MASK_CONSTRUCTOR= (1<<7);
|
||||||
|
public static final int MASK_ABSTRACT = (1<<8);
|
||||||
|
public static final int MASK_INNER = (1<<9);
|
||||||
|
public static final int MASK_SYNTHETIC = (1<<10);
|
||||||
|
public static final int MASK_NATIVE = (1<<11);
|
||||||
|
public static final int MASK_TRANSIENT = (1<<12);
|
||||||
|
public static final int MASK_VOLATILE = (1<<13);
|
||||||
|
public static final int MASK_UPVALUE = (1<<14);
|
||||||
|
public static final int MASK_MAIN = (1<<15);
|
||||||
|
}
|
32
slangc/model/ImportModel.sauce
Normal file
32
slangc/model/ImportModel.sauce
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public abstract class ImportModel {
|
||||||
|
private SystemModel system;
|
||||||
|
private boolean synthetic;
|
||||||
|
|
||||||
|
public ImportModel(SystemModel system, boolean synthetic) {
|
||||||
|
this.system = system;
|
||||||
|
this.synthetic = synthetic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SystemModel getSystem() {
|
||||||
|
return system;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSynthetic() {
|
||||||
|
return synthetic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract TypeModel lookupExact(String name);
|
||||||
|
public abstract TypeModel lookupLoose(String name);
|
||||||
|
|
||||||
|
public final TypeModel lookup(String name) {
|
||||||
|
TypeModel t = lookupExact(name);
|
||||||
|
|
||||||
|
if (t == null) {
|
||||||
|
return lookupLoose(name);
|
||||||
|
} else {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
slangc/model/InnerTypeModel.sauce
Normal file
28
slangc/model/InnerTypeModel.sauce
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
|
||||||
|
public class InnerTypeModel extends MemberModel {
|
||||||
|
private TypeModel definedType;
|
||||||
|
|
||||||
|
public InnerTypeModel(TypeModel owner, String name, Branch source, TypeModel definedType) {
|
||||||
|
super(owner, name, source);
|
||||||
|
this.definedType = definedType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemberCategory getCategory() {
|
||||||
|
return MemberCategory.INNER_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getDefinedType() {
|
||||||
|
return definedType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int resolveExpressions() {
|
||||||
|
// Resolution of expressions within inner types happens from the top-level
|
||||||
|
// (it probably can safely be repeated here but there's no need to).
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
351
slangc/model/InnerTypeScope.sauce
Normal file
351
slangc/model/InnerTypeScope.sauce
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slang.data.Map;
|
||||||
|
import slang.data.List;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.ErrorType;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.NodeType;
|
||||||
|
import slangc.parser.Token;
|
||||||
|
|
||||||
|
public class InnerTypeScope {
|
||||||
|
public static class SourceScope extends InnerTypeScope {
|
||||||
|
public final Branch source;
|
||||||
|
SourceScope(InnerTypeScope owner, Branch source) {
|
||||||
|
super(owner);
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<String, TypeModel> innerTypes = new Map<String, TypeModel>();
|
||||||
|
InnerTypeScope owner;
|
||||||
|
protected Map<Branch, SourceScope> sourceScopes = null;
|
||||||
|
|
||||||
|
InnerTypeScope(InnerTypeScope owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceScope innerScopeForSource(Branch b) {
|
||||||
|
if (sourceScopes == null) {
|
||||||
|
sourceScopes = new Map<Branch, SourceScope>();
|
||||||
|
}
|
||||||
|
if (!sourceScopes.hasKey(b)) {
|
||||||
|
sourceScopes.set(b, new SourceScope(this, b));
|
||||||
|
}
|
||||||
|
return sourceScopes.get(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasInnerScopeForSource(Branch b) {
|
||||||
|
return sourceScopes != null && sourceScopes.hasKey(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceScope getInnerScopeForSource(Branch b) {
|
||||||
|
//System.err.println("Looking up inner scope for " + b + " in " + this);
|
||||||
|
if (hasInnerScopeForSource(b)) {
|
||||||
|
//System.err.println("Found");
|
||||||
|
return sourceScopes.get(b);
|
||||||
|
} else {
|
||||||
|
//System.err.println("Not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOuterName() {
|
||||||
|
return owner.getOuterName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean dirtyHackRecursing = false;
|
||||||
|
public TypeModel resolveTypeName(String name) {
|
||||||
|
//System.err.println("Looking up '" + name + "' in " + this);
|
||||||
|
/*if (this instanceof UserTypeModel) {
|
||||||
|
if (!dirtyHackRecursing) {
|
||||||
|
System.err.println("RESORTING TO DIRTY HACK");
|
||||||
|
dirtyHackRecursing = true;
|
||||||
|
UserTypeModel dirtyHack = (UserTypeModel) this;
|
||||||
|
dirtyHack.resolveTypes();
|
||||||
|
dirtyHack.resolveTypes();
|
||||||
|
dirtyHack.resolveTypes();
|
||||||
|
dirtyHack.resolveTypes();
|
||||||
|
dirtyHack.resolveTypes();
|
||||||
|
dirtyHackRecursing = false;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
if (innerTypes.hasKey(name)) {
|
||||||
|
//System.err.println("Got it!");
|
||||||
|
return innerTypes.get(name);
|
||||||
|
} else if (owner != null) {
|
||||||
|
return owner.resolveTypeName(name);
|
||||||
|
} else {
|
||||||
|
// TODO: Handle super-types here?
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String plainName(Node nameNode) {
|
||||||
|
if (nameNode.getNodeType() == NodeType.NAME) {
|
||||||
|
Token t = (Token) ((Branch)nameNode).getSubnode(0);
|
||||||
|
return t.getSnippet().getSource();
|
||||||
|
} else if (nameNode.getNodeType() == NodeType.INDEXED_NAME) {
|
||||||
|
//throw new Error("TODO");
|
||||||
|
return plainName(((Branch) nameNode).getSubnode(0));
|
||||||
|
} else if (nameNode.getNodeType() == NodeType.TYPE || nameNode.getNodeType() == NodeType.TYPE_REFERENCE) {
|
||||||
|
//System.err.println("TODO: Add array information to associated type!");
|
||||||
|
|
||||||
|
return plainName(((Branch) nameNode).getSubnode(0));
|
||||||
|
} else if (nameNode instanceof Token) {
|
||||||
|
return ((Token)nameNode).getSnippet().getSource();
|
||||||
|
} else {
|
||||||
|
throw new Error("Internal error/TODO: Not a plain name: " + nameNode.getNodeType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InnerTypeScope getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageModel getPackage() {
|
||||||
|
return owner.getPackage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getNearestType() {
|
||||||
|
if (this instanceof TypeModel) {
|
||||||
|
return (TypeModel) this;
|
||||||
|
} else {
|
||||||
|
return owner.getNearestType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public TypeModel resolveTypeReference(Node subnode) {
|
||||||
|
try {
|
||||||
|
String n = plainName(subnode);
|
||||||
|
TypeModel t = resolveTypeName(n);
|
||||||
|
if (t == null) {
|
||||||
|
return getOwner().resolveTypeReference(subnode);
|
||||||
|
} else {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
} catch (Error e) {
|
||||||
|
System.err.println(e);
|
||||||
|
return getOwner().resolveTypeReference(subnode);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public TypeModel[] resolveClassReferences(Node typeRefs) {
|
||||||
|
if (typeRefs.getNodeType() == NodeType.CLASS_IMPLEMENTS || typeRefs.getNodeType() == NodeType.INTERFACE_BASES) {
|
||||||
|
return resolveClassReferences(((Branch)typeRefs).getSubnode(1));
|
||||||
|
} else if (typeRefs.getNodeType() == NodeType.TYPE_REFERENCES) {
|
||||||
|
Branch b = (Branch) typeRefs;
|
||||||
|
List<TypeModel> results = new List<TypeModel>();
|
||||||
|
for (int i = 0; i < b.countSubnodes(); i++) {
|
||||||
|
//System.out.println("SUBREFS GOT A " + b.getSubnode(i).getNodeType());
|
||||||
|
if (b.getSubnode(i).getNodeType() != NodeType.COMMA) {
|
||||||
|
results.append(resolveTypeReference(b.getSubnode(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results.arrayCopy();
|
||||||
|
} else {
|
||||||
|
throw new Error("Internal error/TODO: Unrecognised type references container " + typeRefs.getNodeType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemplateArgument parseOneTemplateArgument(Node targ) {
|
||||||
|
if (targ.getNodeType() != NodeType.GENERIC_VALUE && targ.getNodeType() != NodeType.TYPE) {
|
||||||
|
throw new Error("Internal error/TODO: Not a generic typeName: " + targ.getNodeType());
|
||||||
|
}
|
||||||
|
TypeModel type = resolveTypeReference(((Branch)targ).getSubnode(0));
|
||||||
|
if (type == null) {
|
||||||
|
targ.annotate(ErrorType.INTERNAL_ERROR, "Couldn't resolve this template argument");
|
||||||
|
}
|
||||||
|
return new TypeTemplateArgument(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemplateArguments parseTemplateArguments(Node targs) {
|
||||||
|
if (targs.getNodeType() == NodeType.GENERIC_ARGUMENTS) {
|
||||||
|
return parseTemplateArguments(((Branch)targs).getSubnode(1));
|
||||||
|
} else if (targs.getNodeType() == NodeType.GENERIC_EXPRESSIONS) {
|
||||||
|
Branch b = (Branch) targs;
|
||||||
|
List<TemplateArgument> list = new List<TemplateArgument>();
|
||||||
|
for (int i = 0; i < b.countSubnodes(); i++) {
|
||||||
|
if (b.getSubnode(i).getNodeType() != NodeType.COMMA) {
|
||||||
|
TemplateArgument ta = parseOneTemplateArgument(b.getSubnode(i));
|
||||||
|
if (ta == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
list.append(ta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new TemplateArguments(list.arrayCopy());
|
||||||
|
} else {
|
||||||
|
throw new Error("Internal error/TODO: Not a generic sizeExpression node: " + targs.getNodeType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel resolveTypeReference(Node typeReference) {
|
||||||
|
return resolveTypeReference(typeReference, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel resolveTypeReference(Node typeReference, boolean simplify) {
|
||||||
|
TypeModel result = innerResolveTypeReference(typeReference);
|
||||||
|
if (simplify && (result != null)) {
|
||||||
|
result = result.simplify();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel innerResolveGlobal(String globalName) {
|
||||||
|
if (!globalName.search(".")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String pkg = globalName.sub(0, globalName.searchLast("."));
|
||||||
|
String typ = globalName.sub(globalName.searchLast(".") + 1);
|
||||||
|
if (!getPackage().getSystem().hasPackage(pkg)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PackageModel p = getPackage().getSystem().getPackage(pkg);
|
||||||
|
if (!p.hasType(typ)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return p.getType(typ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel innerResolveTypeReference(Node typeReference) {
|
||||||
|
if (typeReference.getNodeType() == NodeType.TYPE_REFERENCE) {
|
||||||
|
InnerTypeScope outer = this;
|
||||||
|
TypeModel result = null;
|
||||||
|
String unresolved = "";
|
||||||
|
if (((Branch)typeReference).countSubnodes() < 1) {
|
||||||
|
throw new Error("wtf? Empty name?");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < ((Branch)typeReference).countSubnodes(); i++) {
|
||||||
|
Node node = ((Branch)typeReference).getSubnode(i);
|
||||||
|
if (node.getNodeType() == NodeType.DOT) {
|
||||||
|
unresolved += ".";
|
||||||
|
} else {
|
||||||
|
String n;
|
||||||
|
boolean isGenericInstance = false;
|
||||||
|
TemplateArguments targs = null;
|
||||||
|
if (node.getNodeType() == NodeType.GENERIC_NAME) {
|
||||||
|
n = plainName(((Branch)node).getSubnode(0));
|
||||||
|
targs = parseTemplateArguments(((Branch)node).getSubnode(1));
|
||||||
|
isGenericInstance = true;
|
||||||
|
|
||||||
|
n += targs.genericString();
|
||||||
|
} else {
|
||||||
|
n = plainName(node);
|
||||||
|
}
|
||||||
|
unresolved += n;
|
||||||
|
|
||||||
|
//System.err.println("I be working with '" + unresolved + "'");
|
||||||
|
|
||||||
|
TypeModel tmp = null;
|
||||||
|
if (outer != null) {
|
||||||
|
//System.err.println("I be resolving outer");
|
||||||
|
tmp = outer.resolveTypeName(n);
|
||||||
|
}
|
||||||
|
if (tmp == null) {
|
||||||
|
//System.err.println("I be resolving inner");
|
||||||
|
tmp = innerResolveGlobal(unresolved);
|
||||||
|
}
|
||||||
|
if (tmp == null) {
|
||||||
|
//System.err.println("I still null");
|
||||||
|
outer = null;
|
||||||
|
result = null;
|
||||||
|
//throw new Error("Can't find type '" + n + "' within " + outer.fullName());
|
||||||
|
//node.annotate(ErrorType.INTERNAL_ERROR, "Can't find type '" + n + "' within " + outer.fullName());
|
||||||
|
//return null;
|
||||||
|
} else if (isGenericInstance) {
|
||||||
|
//System.err.println("I is generic???");
|
||||||
|
if (targs == null) {
|
||||||
|
node.annotate(ErrorType.INTERNAL_ERROR, "Failed to decode template sizeExpression");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TypeModel inst = tmp.getOrCreateTemplateInstance(targs);
|
||||||
|
if (inst == null) {
|
||||||
|
node.annotate(ErrorType.INTERNAL_ERROR, "Unable to instantiate " + tmp.fullName() + " with sizeExpression " + targs);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
outer = inst;
|
||||||
|
result = inst;
|
||||||
|
} else {
|
||||||
|
//System.err.println("I is done? " + tmp);
|
||||||
|
tmp = tmp.simplify();
|
||||||
|
//System.err.println("I is simplified? " + tmp);
|
||||||
|
outer = tmp;
|
||||||
|
result = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result == null) {
|
||||||
|
if (this == getNearestType()) {
|
||||||
|
//throw new Error("???" + unresolved);
|
||||||
|
typeReference.annotate(ErrorType.INTERNAL_ERROR, "Unable to resolve " + unresolved);
|
||||||
|
} else {
|
||||||
|
getOwner().innerResolveTypeReference(typeReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
//return resolveTypeReference(((Branch)typeReference).getSubnode(0));
|
||||||
|
} else if (typeReference.getNodeType() == NodeType.NAME) {
|
||||||
|
Token t = (Token) ((Branch)typeReference).getSubnode(0);
|
||||||
|
String n = t.getSnippet().getSource();
|
||||||
|
TypeModel result = resolveTypeName(n);
|
||||||
|
if (result == null) {
|
||||||
|
throw new Error("Failed to lookup name '" + n + "'");
|
||||||
|
//t.annotate(ErrorType.INTERNAL_ERROR, "Failed to lookup name '" + n + "'");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} else if (typeReference.getNodeType() == NodeType.TOKEN) {
|
||||||
|
Token t = (Token) typeReference;
|
||||||
|
String n = t.getSnippet().getSource();
|
||||||
|
TypeModel result = resolveTypeName(n);
|
||||||
|
if (result == null) {
|
||||||
|
throw new Error("Failed to lookup name '" + n + "'");
|
||||||
|
//t.annotate(ErrorType.INTERNAL_ERROR, "Failed to lookup name '" + n + "'");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} else if (typeReference.getNodeType() == NodeType.TYPE) {
|
||||||
|
return resolveTypeReference(((Branch)typeReference).getSubnode(0));
|
||||||
|
} else if (typeReference.getNodeType() == NodeType.ARRAY_TYPE) {
|
||||||
|
TypeModel b = resolveTypeReference(((Branch)typeReference).getSubnode(0));
|
||||||
|
if (b == null) {
|
||||||
|
return null; // Should have already warned if base type not found
|
||||||
|
}
|
||||||
|
return b.getOrCreateArrayInstance();
|
||||||
|
} else {
|
||||||
|
throw new Error("Unrecognised type reference node: " + typeReference.getNodeType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasInnerType(String name) {
|
||||||
|
return innerTypes.hasKey(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getInnerType(String name) {
|
||||||
|
if (hasInnerType(name)) {
|
||||||
|
return innerTypes.get(name);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasInnerTypeForSource(Branch source) {
|
||||||
|
return getInnerTypeForSource(source) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getInnerTypeForSource(Branch source) {
|
||||||
|
List<TypeModel> inners = new List<TypeModel>();
|
||||||
|
inners.appendList(innerTypes.values());
|
||||||
|
for (int i = 0; i < inners.count(); i++) {
|
||||||
|
if (inners.get(i) instanceof UserTypeModel) {
|
||||||
|
UserTypeModel t = (UserTypeModel) inners.get(i);
|
||||||
|
if (t.parsed == source) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
15
slangc/model/InnerTypeSet.sauce
Normal file
15
slangc/model/InnerTypeSet.sauce
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public class InnerTypeSet extends AbstractMemberSet {
|
||||||
|
public InnerTypeSet(TypeModel owner, MemberCategory category) {
|
||||||
|
super(owner,category);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InnerTypeModel getMember(int i) {
|
||||||
|
return (InnerTypeModel) super.getMember(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InnerTypeModel getMemberNamed(String name, int i) {
|
||||||
|
return (InnerTypeModel) super.getMemberNamed(name, i);
|
||||||
|
}
|
||||||
|
}
|
73
slangc/model/LocalStorageModel.sauce
Normal file
73
slangc/model/LocalStorageModel.sauce
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.api.Reporter;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.ErrorType;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.NodeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the base type used both for method parameters and (other/temporary) local variables.
|
||||||
|
* These are typically accessed the same way at runtime (offset from the stack base of the
|
||||||
|
* invoked method), so the same rules usually apply and they can usually be handled the same way.
|
||||||
|
*
|
||||||
|
* @author Zak
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class LocalStorageModel implements StorageSlot {
|
||||||
|
MethodModel owner;
|
||||||
|
int index;
|
||||||
|
Branch source;
|
||||||
|
private TypeModel baseStorageType;
|
||||||
|
|
||||||
|
public LocalStorageModel(MethodModel owner, int index, Branch source, TypeModel assignedType) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.index = index;
|
||||||
|
this.source = source;
|
||||||
|
|
||||||
|
if (assignedType == null) {
|
||||||
|
if (source.getSubnode(1) == null) {
|
||||||
|
source.annotate(ErrorType.MISSING_PART, "Can't find type information!");
|
||||||
|
} else {
|
||||||
|
//baseStorageType = ((UserTypeModel)owner.getOwner()).resolveTypeReference(sourceFile.getSubnode(1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
baseStorageType = assignedType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Node getNameNode();
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return UserTypeModel.plainName(getNameNode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countAdditionalIndices() {
|
||||||
|
Node n = getNameNode();
|
||||||
|
int i = 0;
|
||||||
|
while (n.getNodeType() == NodeType.INDEXED_NAME) {
|
||||||
|
n = ((Branch) n).getSubnode(0);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getStorageType() {
|
||||||
|
TypeModel effectiveType = baseStorageType;
|
||||||
|
if (effectiveType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < countAdditionalIndices(); i++) {
|
||||||
|
effectiveType = effectiveType.getOrCreateArrayInstance();
|
||||||
|
}
|
||||||
|
return effectiveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump(Reporter reporter, String indent, String incr) {
|
||||||
|
reporter.note("DUMP", indent + "> '" + getName() + "', storage type " + getStorageType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
83
slangc/model/LocalVariableSlot.sauce
Normal file
83
slangc/model/LocalVariableSlot.sauce
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.NodeType;
|
||||||
|
|
||||||
|
public class LocalVariableSlot extends LocalStorageModel implements StorageSlot, ExpressionOwner {
|
||||||
|
private final StatementOwner owner;
|
||||||
|
private ExpressionModel initialiser;
|
||||||
|
|
||||||
|
public LocalVariableSlot(StatementOwner owner, Branch source, TypeModel type) {
|
||||||
|
super((MethodModel)owner.getMethodOrField(), ((MethodModel)owner.getMethodOrField()).countLocals(), source, type);
|
||||||
|
this.owner = owner;
|
||||||
|
if (source.getNodeType() == NodeType.INITIALISED_SLOT) {
|
||||||
|
initialiser = ExpressionModel.construct(this, source.getSubnode(source.countSubnodes() - 1));
|
||||||
|
}
|
||||||
|
if (owner == null) {
|
||||||
|
throw new Error("Internal error...");
|
||||||
|
}
|
||||||
|
((MethodModel)owner.getMethodOrField()).localAdded(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node getNameNode() {
|
||||||
|
return source.getSubnode(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StorageSlot.Kind getSlotKind() {
|
||||||
|
return StorageSlot.Kind.LOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatementOwner getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int resolveExpressions() {
|
||||||
|
if (initialiser != null) {
|
||||||
|
return initialiser.resolveExpressions();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public InnerTypeScope getTypeScope() {
|
||||||
|
return owner.getTypeScope();
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public TypeModel resolveType(Node subnode) {
|
||||||
|
if (owner == null) throw new Error("This shouldn't be null");
|
||||||
|
return owner.resolveType(subnode);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public MemberModel getMethodOrField() {
|
||||||
|
return owner.getMethodOrField();
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public Named lookupSimpleName(String name) {
|
||||||
|
return owner.lookupSimpleName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public MethodModel[] lookupSimpleMethod(String name) {
|
||||||
|
return owner.lookupSimpleMethod(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||||
|
return getStorageType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasInitialiser() {
|
||||||
|
return initialiser != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpressionModel getInitialiser() {
|
||||||
|
return initialiser;
|
||||||
|
}
|
||||||
|
}
|
7
slangc/model/MemberCategory.sauce
Normal file
7
slangc/model/MemberCategory.sauce
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public enum MemberCategory {
|
||||||
|
INNER_TYPE,
|
||||||
|
FIELD,
|
||||||
|
METHOD
|
||||||
|
}
|
94
slangc/model/MemberModel.sauce
Normal file
94
slangc/model/MemberModel.sauce
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.api.Reporter;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
|
||||||
|
public abstract class MemberModel implements AttributeOwner {
|
||||||
|
private TypeModel owner;
|
||||||
|
private String name;
|
||||||
|
private Branch source;
|
||||||
|
private AttributeSet attributes;
|
||||||
|
|
||||||
|
MemberModel(TypeModel owner, String name, Branch source) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.name = name;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesName(String[] enabledLanguages, String name) {
|
||||||
|
if (getName().equals(name)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return getAttributes().matchesTranslation(enabledLanguages, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Branch getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract MemberCategory getCategory();
|
||||||
|
|
||||||
|
public AttributeSet getAttributes() {
|
||||||
|
if (attributes == null) {
|
||||||
|
if (source == null) {
|
||||||
|
attributes = new AttributeSet(this, null);
|
||||||
|
} else {
|
||||||
|
attributes = new AttributeSet(this, (Branch) source.getSubnode(0)); // TODO: Consider how this may impact inner classes (attributes will be decoded here and also with the type, may need to combine both sets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFlags() {
|
||||||
|
switch (getCategory()) {
|
||||||
|
case MemberCategory.FIELD:
|
||||||
|
return getAttributes().getFlags() | Flags.MASK_FIELD;
|
||||||
|
case MemberCategory.METHOD:
|
||||||
|
return getAttributes().getFlags() | Flags.MASK_METHOD;
|
||||||
|
case MemberCategory.INNER_TYPE:
|
||||||
|
return getAttributes().getFlags() | Flags.MASK_INNER;
|
||||||
|
default:
|
||||||
|
throw new Error("Internal error: Bad member category " + getCategory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setAttributes(AttributeSet attributes) {
|
||||||
|
this.attributes = attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int resolveTypes() {
|
||||||
|
if (attributes == null) {
|
||||||
|
getAttributes();
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump(Reporter reporter, String indent, String incr) {
|
||||||
|
reporter.note("DUMP", indent + getCategory() + " '" + getName() + "'" + (isStatic() ? " [static]" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStatic() {
|
||||||
|
return getAttributes().isStatic();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrivate() {
|
||||||
|
return getAttributes().isPrivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSynthetic() {
|
||||||
|
return source == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int resolveExpressions();
|
||||||
|
}
|
646
slangc/model/MethodModel.sauce
Normal file
646
slangc/model/MethodModel.sauce
Normal file
@ -0,0 +1,646 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slang.data.List;
|
||||||
|
import slangc.api.Reporter;
|
||||||
|
import slangc.bytecode.MethodSignature;
|
||||||
|
import slangc.bytecode.TypeSignature;
|
||||||
|
import slangc.model.clauses.Arguments;
|
||||||
|
import slangc.model.expressions.SuperConstructorCallExpression;
|
||||||
|
import slangc.model.expressions.ThisConstructorCallExpression;
|
||||||
|
import slangc.model.statements.BlockStatement;
|
||||||
|
import slangc.model.statements.ExpressionStatement;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.ErrorType;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.NodeType;
|
||||||
|
|
||||||
|
public class MethodModel extends MemberModel implements StatementOwner {
|
||||||
|
BlockStatement body = null;
|
||||||
|
ParameterSet parameters = null;
|
||||||
|
TypeModel returnType = null;
|
||||||
|
TypeModel[] exceptions = null;
|
||||||
|
List<LocalStorageModel> locals = null;
|
||||||
|
MethodModel prototype = null;
|
||||||
|
|
||||||
|
/** Constructor for synthetic methods which copy an existing method signature. */
|
||||||
|
public MethodModel(TypeModel owner, String name, MethodModel copySignatureFrom) {
|
||||||
|
super(owner, name, null);
|
||||||
|
// TODO: It might be worth making a deep copy of the parameters so they're actually usable by synthetic code
|
||||||
|
parameters = copySignatureFrom.parameters;
|
||||||
|
returnType = copySignatureFrom.returnType;
|
||||||
|
exceptions = copySignatureFrom.exceptions;
|
||||||
|
setAttributes(copySignatureFrom.getAttributes());
|
||||||
|
this.prototype = copySignatureFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel(TypeModel owner, String name, Branch source) {
|
||||||
|
super(owner, name, source);
|
||||||
|
|
||||||
|
parameters = new ParameterSet(this);
|
||||||
|
|
||||||
|
if (!isStaticInitialisation()) {
|
||||||
|
Branch p = source.getNodeType() == NodeType.METHOD_DECLARATION ?
|
||||||
|
(Branch) source.getSubnode(source.countSubnodes() - 4)
|
||||||
|
: (Branch) source.getSubnode(source.countSubnodes() - 3);
|
||||||
|
Branch l = (Branch) p.getSubnode(1);
|
||||||
|
int goodparams = 0;
|
||||||
|
for (int i = 0; i < l.countSubnodes(); i++) {
|
||||||
|
Node n = l.getSubnode(i);
|
||||||
|
if (n.getNodeType() != NodeType.COMMA) {
|
||||||
|
goodparams++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < l.countSubnodes(); i++) {
|
||||||
|
/* Parameters are indexed in bytecode by their stack position (relative to
|
||||||
|
* the method call frame info), which gives the last parameter index -1,
|
||||||
|
* the second-last index -2 and so on (since the last parameter will be
|
||||||
|
* pushed just before the method call frame starts).
|
||||||
|
*/
|
||||||
|
int negindex = (0 - goodparams) + parameters.countParameters();
|
||||||
|
Node n = l.getSubnode(i);
|
||||||
|
if (n.getNodeType() != NodeType.COMMA) {
|
||||||
|
parameters.addParameter(new ParameterModel(this, negindex /*parameters.countParameters()*/, (Branch) n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exceptions = unpackExceptions(((Branch)(source.getSubnode(source.countSubnodes() - 2))));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isConstructor()) {
|
||||||
|
//Log.line("Owner is " + owner.fullName());
|
||||||
|
returnType = owner;
|
||||||
|
} else if (isStaticInitialisation()) {
|
||||||
|
returnType = null; // TODO: Better "void" handling
|
||||||
|
} else {
|
||||||
|
Branch t = (Branch) source.getSubnode(2);
|
||||||
|
if (t.getNodeType() == NodeType.NO_RETURN_TYPE) {
|
||||||
|
returnType = null; // TODO: Better "void" handling
|
||||||
|
} else {
|
||||||
|
returnType = ((UserTypeModel)owner).resolveTypeReference(t.getSubnode(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasBody()) {
|
||||||
|
body = new BlockStatement(this, (Branch) ((Branch)(source.getSubnode(source.countSubnodes() - 1))).getSubnode(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeModel[] unpackExceptions(Branch b) {
|
||||||
|
if (b.getNodeType() == NodeType.NO_THROWS) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
Branch list = (Branch)b.getSubnode(0);
|
||||||
|
if (list.countSubnodes() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < list.countSubnodes(); i++) {
|
||||||
|
if (list.getSubnode(i).getNodeType() != NodeType.COMMA) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeModel[] result = new TypeModel[count];
|
||||||
|
count = 0;
|
||||||
|
for (int i = 0; i < list.countSubnodes(); i++) {
|
||||||
|
if (list.getSubnode(i).getNodeType() != NodeType.COMMA) {
|
||||||
|
result[count] = getOwner().resolveTypeReference(list.getSubnode(i));
|
||||||
|
if (result[count] == null) {
|
||||||
|
list.getSubnode(i).annotate(ErrorType.INTERNAL_ERROR, "Failed to resolve type reference");
|
||||||
|
//throw new Error("TODO BAD");
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countExceptions() {
|
||||||
|
if (exceptions == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return exceptions.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getException(int i) {
|
||||||
|
return exceptions[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemberCategory getCategory() {
|
||||||
|
return MemberCategory.METHOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConstructor() {
|
||||||
|
return getName().equals("this");/*return getSource().getNodeType() == NodeType.CONSTRUCTOR_DECLARATION;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParameterSet getParameters() {
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this is an instance constructor, checks if it's body begins with a call to another/super constructor and
|
||||||
|
* marks that constructor's location as approved.
|
||||||
|
* @return true if this is an instance constructor starting with an explicit (and now marked "approved")
|
||||||
|
* call to another/super constructor, otherwise false.
|
||||||
|
*/
|
||||||
|
public boolean checkExplicitBaseConstructorCall(boolean includingThisConstructorCall) {
|
||||||
|
if (isConstructor() && hasBody()) {
|
||||||
|
if (getBody() instanceof BlockStatement) {
|
||||||
|
BlockStatement b = (BlockStatement) getBody();
|
||||||
|
if (b.countInnerStatements() > 0) {
|
||||||
|
StatementModel first = b.getInnerStatement(0);
|
||||||
|
if (first instanceof ExpressionStatement) {
|
||||||
|
ExpressionModel expr = ((ExpressionStatement)first).getExpression();
|
||||||
|
if (expr instanceof ThisConstructorCallExpression) {
|
||||||
|
((ThisConstructorCallExpression)expr).setApprovedLocation(true);
|
||||||
|
if (includingThisConstructorCall) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (expr instanceof SuperConstructorCallExpression) {
|
||||||
|
((SuperConstructorCallExpression)expr).setApprovedLocation(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStaticInitialisation() {
|
||||||
|
return getSource() != null && getSource().getNodeType() == NodeType.STATIC_CONSTRUCTOR_DECLARATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasBody() {
|
||||||
|
if (body != null) {
|
||||||
|
return true;
|
||||||
|
} else if (isSynthetic()) {
|
||||||
|
return body != null;
|
||||||
|
} else {
|
||||||
|
return getSource().getSubnode(getSource().countSubnodes() - 1).getNodeType() == NodeType.METHOD_BODY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockStatement getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasReturnType() {
|
||||||
|
return returnType != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getReturnType() {
|
||||||
|
return returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dump(Reporter reporter, String indent, String incr) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
super.dump(reporter, indent, incr);
|
||||||
|
|
||||||
|
if (hasReturnType()) {
|
||||||
|
reporter.note("DUMP", indent + incr + "> Return type is " + getReturnType());
|
||||||
|
} else {
|
||||||
|
reporter.note("DUMP", indent + incr + "[no/void return type]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.countParameters() == 0) {
|
||||||
|
reporter.note("DUMP", indent + incr + "[no parameters]");
|
||||||
|
} else {
|
||||||
|
reporter.note("DUMP", indent + incr + "> " + parameters.countParameters() + " parameters:");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < parameters.countParameters(); i++) {
|
||||||
|
parameters.getParameter(i).dump(reporter, indent + incr + incr, incr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasBody()) {
|
||||||
|
reporter.note("DUMP", indent + incr + "> Method body: ...");
|
||||||
|
//body.dump(reporter, indent + incr + incr, incr);
|
||||||
|
} else {
|
||||||
|
reporter.note("DUMP", indent + incr + "[no method body]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStatic() {
|
||||||
|
return super.isStatic() /*|| isConstructor()*/ || isStaticInitialisation();
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public TypeModel resolveType(Node typeReference) {
|
||||||
|
return ((UserTypeModel)getOwner()).resolveTypeReference(typeReference);
|
||||||
|
}
|
||||||
|
//@Override
|
||||||
|
public MethodModel getMethodOrField() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public InnerTypeScope getTypeScope() {
|
||||||
|
return getOwner();
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public Named lookupSimpleName(String name) {
|
||||||
|
if (parameters != null && parameters.hasParameter(name)) {
|
||||||
|
return parameters.getParameter(name);
|
||||||
|
}
|
||||||
|
return getOwner().lookupSimpleName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel[] lookupSimpleMethod(String name) {
|
||||||
|
return getOwner().lookupSimpleMethod(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String signatureString() {
|
||||||
|
String result = getName();
|
||||||
|
result += "(";
|
||||||
|
|
||||||
|
if (parameters != null) {
|
||||||
|
for (int i = 0; i < parameters.countParameters(); i++) {
|
||||||
|
if (i != 0) {
|
||||||
|
result += ",";
|
||||||
|
}
|
||||||
|
ParameterModel m = parameters.getParameter(i);
|
||||||
|
result += m.getStorageType().fullName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result += ")";
|
||||||
|
|
||||||
|
if (returnType != null) {
|
||||||
|
result += ":" + returnType.fullName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getOwner().toString() + "." + signatureString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean overrides(MethodModel other) {
|
||||||
|
//System.err.println("Checking if " + this + " overrides " + other + "...");
|
||||||
|
// Perform obvious checks first - if names don't match we don't override
|
||||||
|
if (!getName().equals(other.getName())) {
|
||||||
|
//System.err.println("Doesn't override - names don't match");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// If other type isn't an ancestor of this type we don't override
|
||||||
|
if (!getOwner().inherits(other.getOwner())) {
|
||||||
|
//System.err.println("Doesn't override - doesn't fit hierarchy");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// In the special case of constructors, they will be considered to logically override any inherited constructors
|
||||||
|
if (isConstructor()) {
|
||||||
|
//System.err.println("Does kind-of override - is constructor");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// If names/types can lead to a potential override, we need to check parameters/return types
|
||||||
|
if (!canOverrideParameters(other.parameters)) {
|
||||||
|
//System.err.println("Doesn't override - parameters don't match");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!canOverrideReturn(other.returnType)) {
|
||||||
|
//System.err.println("Doesn't override - return types are incompatible");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//System.err.println("Signatures match so it does override");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canOverrideParameters(ParameterSet other) {
|
||||||
|
if (parameters.countParameters() != other.countParameters()) {
|
||||||
|
//System.err.println("Patemeter counts don't match");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < parameters.countParameters(); i++) {
|
||||||
|
ParameterModel thisp = parameters.getParameter(i);
|
||||||
|
ParameterModel otherp = other.getParameter(i);
|
||||||
|
if (thisp.getStorageType() != otherp.getStorageType()) {
|
||||||
|
//System.err.println("Storage types " + thisp.getStorageType() + " and " + otherp.getStorageType() + " don't match");
|
||||||
|
return false;
|
||||||
|
/*if (!(thisp.getStorageType() instanceof UserTypeModel) || !(otherp.getStorageType() instanceof UserTypeModel)) {
|
||||||
|
return false;
|
||||||
|
}*/
|
||||||
|
/*if (!thisp.getStorageType().isAssignableFrom(otherp.getStorageType())) {
|
||||||
|
return false;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If nothing mismatched we can override
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canOverrideReturn(TypeModel otherReturnType) {
|
||||||
|
if (returnType == otherReturnType) {
|
||||||
|
return true;
|
||||||
|
} else if (returnType != null && otherReturnType != null) {
|
||||||
|
return otherReturnType.isAssignableFrom(returnType);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int resolveExpressions() {
|
||||||
|
if (hasBody()) {
|
||||||
|
return getBody().resolveExpressions();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isApplicableToArguments(Arguments arguments, boolean allowVarargs) {
|
||||||
|
ExpressionModel[] exprs = arguments.getSubexpressions();
|
||||||
|
if ((!allowVarargs || !parameters.isVarargs()) && exprs.length != parameters.countParameters()) {
|
||||||
|
return false;
|
||||||
|
} else if (allowVarargs && parameters.isVarargs() && exprs.length < parameters.countNonVarargParameters()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < exprs.length; i++) {
|
||||||
|
ExpressionResult r = exprs[i].getResult();
|
||||||
|
if (r.resolvesToValueOrNull()) {
|
||||||
|
if (r.getKind() == ExpressionResult.Kind.NULL) {
|
||||||
|
if (!parameters.getParameterType(i, allowVarargs).isObjectType()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!parameters.getParameterType(i, allowVarargs).isAssignableFrom(r.getValueType())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If nothing was a mismatch, it should be good to go! */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLeftAssignableFromRight(ParameterSet left, ParameterSet right, boolean allowVarargs) {
|
||||||
|
if (left.countParameters() != right.countParameters()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < left.countParameters(); i++) {
|
||||||
|
if (!left.getParameterType(i, allowVarargs).isAssignableFrom(right.getParameterType(i, allowVarargs))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareApplicabilityOfArguments(MethodModel other, Arguments arguments, boolean allowVarargs) {
|
||||||
|
if (isLeftAssignableFromRight(this.parameters, other.parameters, allowVarargs)) {
|
||||||
|
return -1;
|
||||||
|
} else if (isLeftAssignableFromRight(other.parameters, this.parameters, allowVarargs)) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compareApplicabilityOfArguments(MethodModel[] lhs, MethodModel[] rhs, Arguments arguments, boolean allowVarargs) {
|
||||||
|
if (lhs.length == 0 && rhs.length > 0) {
|
||||||
|
return 1;
|
||||||
|
} else if (rhs.length == 0 && lhs.length > 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < lhs.length; i++) {
|
||||||
|
for (int j = 0; i < rhs.length; j++) {
|
||||||
|
int comp = lhs[i].compareApplicabilityOfArguments(rhs[j], arguments, allowVarargs);
|
||||||
|
if (comp != 0) {
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodModel[] addArrays(MethodModel[] a, MethodModel[] b) {
|
||||||
|
MethodModel[] c = new MethodModel[a.length + b.length];
|
||||||
|
for (int i = 0; i < c.length; i++) {
|
||||||
|
c[i] = i < a.length ? a[i] : b[i - a.length];
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodModel[] arrayWithout(MethodModel[] a, MethodModel b) {
|
||||||
|
MethodModel[] c = new MethodModel[0];
|
||||||
|
for (int i = 0; i < a.length; i++) {
|
||||||
|
if (a[i] != b) {
|
||||||
|
c = addArrays(c, new MethodModel[] {a[i]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean arrayContains(MethodModel[] a, MethodModel b) {
|
||||||
|
for (int i = 0; i < a.length; i++) {
|
||||||
|
if (a[i] == b) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new array of MethodModel instances where any duplicate entries or those
|
||||||
|
* made irrelevant by others in the list which override them are removed.
|
||||||
|
*
|
||||||
|
* <p/>
|
||||||
|
* This shouldn't normally be used directly, but is used internally by findApplicableMethods/bestApplicableMethod.
|
||||||
|
* @param availableMethods
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static MethodModel[] findRelevantMethods(MethodModel[] availableMethods, boolean checkOverrides) {
|
||||||
|
MethodModel[] result = new MethodModel[0];
|
||||||
|
|
||||||
|
for (int i = 0; i < availableMethods.length; i++) {
|
||||||
|
MethodModel thisMethod = availableMethods[i];
|
||||||
|
boolean willAdd = true;
|
||||||
|
for (int j = 0; j < availableMethods.length; j++) {
|
||||||
|
if (checkOverrides && i != j) {
|
||||||
|
MethodModel otherMethod = availableMethods[j];
|
||||||
|
if (otherMethod.overrides(thisMethod)) {
|
||||||
|
//System.err.println("Method " + thisMethod + " is overridden by " + otherMethod + " so will be ignored");
|
||||||
|
willAdd = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Avoid adding any already-existing results so this method can also remove duplicates
|
||||||
|
if (willAdd && !arrayContains(result, availableMethods[i])) {
|
||||||
|
//System.err.println("Method " + thisMethod + " will be considered");
|
||||||
|
result = addArrays(result, new MethodModel[] {availableMethods[i]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Narrows down a list of available methods/constructors (i.e. which have been looked up by name) to
|
||||||
|
* those which are applicable to the given arguments. This also avoids adding any methods which are
|
||||||
|
* overridden by a method already on the list.
|
||||||
|
*
|
||||||
|
* <p/>
|
||||||
|
* This shouldn't normally be used directly, instead bestApplicableMethods should be used to get a
|
||||||
|
* reduced list.
|
||||||
|
*
|
||||||
|
* @param availableMethods
|
||||||
|
* @param arguments
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static MethodModel[] findApplicableMethods(MethodModel[] availableMethods, Arguments arguments, boolean allowVarargs) {
|
||||||
|
// Begin by removing any duplicate methods
|
||||||
|
// (note, overridden methods should already be excluded UNLESS they also occur in scope
|
||||||
|
// actually, that probably never happens anyway. Doesn't seem to be an issue?)
|
||||||
|
availableMethods = findRelevantMethods(availableMethods, false);
|
||||||
|
|
||||||
|
MethodModel[] result = new MethodModel[0];
|
||||||
|
|
||||||
|
for (int i = 0; i < availableMethods.length; i++) {
|
||||||
|
//System.err.println("Checking if " + availableMethods[i] + " matches " + arguments);
|
||||||
|
if (availableMethods[i].isApplicableToArguments(arguments, allowVarargs)) {
|
||||||
|
//System.err.println("Match.");
|
||||||
|
result = addArrays(result, new MethodModel[] {availableMethods[i]});
|
||||||
|
//System.err.println("Result length: " + result.length);
|
||||||
|
} else {
|
||||||
|
//System.err.println("No match.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of the "most applicable" methods (based on the arguments) from an array of
|
||||||
|
* available choices.
|
||||||
|
*
|
||||||
|
* <p/>
|
||||||
|
* This method first calls findApplicableMethods to limit to those which are applicable.
|
||||||
|
* If no methods are applicable, an empty array is returned. If more than one are applicable, then
|
||||||
|
* this method will try to select the "most applicable" from those, ideally returning exactly
|
||||||
|
* one method but including any ambiguous ones if necessary.
|
||||||
|
*
|
||||||
|
* @param availableMethods
|
||||||
|
* @param arguments
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static MethodModel[] bestApplicableMethods(MethodModel[] availableMethods, Arguments arguments, boolean allowVarargs) {
|
||||||
|
MethodModel[] applicable = findApplicableMethods(availableMethods, arguments, allowVarargs);
|
||||||
|
/* If there's only one applicable method (or none) then we don't have to do any more work to
|
||||||
|
* choose between them.
|
||||||
|
*/
|
||||||
|
if (applicable.length < 2) {
|
||||||
|
return applicable;
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodModel[] mostApplicable = new MethodModel[0];
|
||||||
|
|
||||||
|
for (int i = 0; i < applicable.length; i++) {
|
||||||
|
if (mostApplicable.length == 0) {
|
||||||
|
mostApplicable = new MethodModel[] {applicable[i]};
|
||||||
|
} else {
|
||||||
|
MethodModel[] newMostApplicable = new MethodModel[0];
|
||||||
|
for (int j = 0; j < mostApplicable.length; j++) {
|
||||||
|
int comp = applicable[i].compareApplicabilityOfArguments(mostApplicable[j], arguments, allowVarargs);
|
||||||
|
if (comp < 0) {
|
||||||
|
newMostApplicable = addArrays(newMostApplicable, new MethodModel[] {mostApplicable[j]});
|
||||||
|
} else if (comp > 0) {
|
||||||
|
newMostApplicable = addArrays(newMostApplicable, new MethodModel[] {applicable[i]});
|
||||||
|
} else {
|
||||||
|
newMostApplicable = addArrays(newMostApplicable, new MethodModel[] {mostApplicable[j], applicable[i]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mostApplicable = newMostApplicable;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
MethodModel[] newArray = new MethodModel[] {applicable[i]};
|
||||||
|
int slangc = compareApplicabilityOfArguments(mostApplicable, newArray, arguments);
|
||||||
|
if (slangc < 0) {
|
||||||
|
mostApplicable = newArray;
|
||||||
|
} else if (slangc > 0) {
|
||||||
|
// the existing ones are more applicable, no further action is required
|
||||||
|
} else {
|
||||||
|
// they are equally applicable, so we add the two lists together
|
||||||
|
mostApplicable = addArrays(mostApplicable, newArray);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return mostApplicable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodSignature getMethodSignature() {
|
||||||
|
TypeSignature[] argsigs = new TypeSignature[parameters.countParameters()];
|
||||||
|
for (int i = 0; i < argsigs.length; i++) {
|
||||||
|
argsigs[i] = parameters.getParameter(i).getStorageType().getTypeSignature();
|
||||||
|
}
|
||||||
|
MethodSignature.Kind kind;
|
||||||
|
if (isStaticInitialisation()) {
|
||||||
|
kind = MethodSignature.Kind.STATIC_INIT;
|
||||||
|
} else if (isConstructor()) {
|
||||||
|
kind = MethodSignature.Kind.CONSTRUCTOR;
|
||||||
|
} else if (getOwner().getTypeType() == TypeType.INTERFACE || getOwner().getTypeType() == TypeType.INTERFACE_TEMPLATE) {
|
||||||
|
kind = isStatic() ? MethodSignature.Kind.STATIC_METHOD : MethodSignature.Kind.INTERFACE_METHOD;
|
||||||
|
} else {
|
||||||
|
kind = isStatic() ? MethodSignature.Kind.STATIC_METHOD : MethodSignature.Kind.INSTANCE_METHOD;
|
||||||
|
}
|
||||||
|
return new MethodSignature(getOwner().getTypeSignature(), kind, returnType == null ? TypeSignature.VOID : returnType.getTypeSignature(), getName(), argsigs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countParameters() {
|
||||||
|
return parameters.countParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParameterModel getParameter(int indexFromLeft) {
|
||||||
|
return parameters.getParameter(indexFromLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<LocalStorageModel> getLocals() {
|
||||||
|
if (locals == null) {
|
||||||
|
locals = new List<LocalStorageModel>();
|
||||||
|
for (int i = 0; i < countParameters(); i++) {
|
||||||
|
locals.append(parameters.getParameter(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return locals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countLocals() {
|
||||||
|
return getLocals().count();
|
||||||
|
}
|
||||||
|
|
||||||
|
void localAdded(LocalVariableSlot l) {
|
||||||
|
getLocals().append(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFlags() {
|
||||||
|
int f = super.getFlags();
|
||||||
|
|
||||||
|
if (isConstructor() || isStaticInitialisation()) {
|
||||||
|
f |= Flags.MASK_CONSTRUCTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSynthetic()) {
|
||||||
|
f |= Flags.MASK_SYNTHETIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel getPrototype() {
|
||||||
|
return prototype;
|
||||||
|
}
|
||||||
|
}
|
15
slangc/model/MethodSet.sauce
Normal file
15
slangc/model/MethodSet.sauce
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public class MethodSet extends AbstractMemberSet {
|
||||||
|
public MethodSet(TypeModel owner, MemberCategory category) {
|
||||||
|
super(owner,category);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel getMember(int i) {
|
||||||
|
return (MethodModel) super.getMember(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel getMemberNamed(String name, int i) {
|
||||||
|
return (MethodModel) super.getMemberNamed(name, i);
|
||||||
|
}
|
||||||
|
}
|
5
slangc/model/Named.sauce
Normal file
5
slangc/model/Named.sauce
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public interface Named {
|
||||||
|
public String getName();
|
||||||
|
}
|
45
slangc/model/NodeData.sauce
Normal file
45
slangc/model/NodeData.sauce
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.parser.Node;
|
||||||
|
|
||||||
|
public class NodeData {
|
||||||
|
private SystemModel system;
|
||||||
|
private NodeData outer;
|
||||||
|
private Node node;
|
||||||
|
|
||||||
|
private UserTypeModel typeDefinition = null;
|
||||||
|
|
||||||
|
NodeData(NodeData outer, Node node, SystemModel system) {
|
||||||
|
this.outer = outer;
|
||||||
|
this.node = node;
|
||||||
|
this.system = system;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getNode() {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeData getOuter() {
|
||||||
|
return outer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTypeDefinition() {
|
||||||
|
return typeDefinition != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserTypeModel getTypeDefinition() {
|
||||||
|
return typeDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTypeDefinition(UserTypeModel typeDefinition) {
|
||||||
|
this.typeDefinition = typeDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NodeData of(Node n) {
|
||||||
|
return (NodeData)n.userdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SystemModel getSystem() {
|
||||||
|
return system;
|
||||||
|
}
|
||||||
|
}
|
34
slangc/model/PackageImportModel.sauce
Normal file
34
slangc/model/PackageImportModel.sauce
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public class PackageImportModel extends ImportModel {
|
||||||
|
private String packageName;
|
||||||
|
|
||||||
|
public PackageImportModel(SystemModel system, boolean synthetic, String packageName) {
|
||||||
|
super(system, synthetic);
|
||||||
|
this.packageName = packageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPackageName() {
|
||||||
|
return packageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeModel lookupExact(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeModel lookupLoose(String name) {
|
||||||
|
if (getSystem().hasPackage(getPackageName())) {
|
||||||
|
if (getSystem().getPackage(getPackageName()).hasType(name)) {
|
||||||
|
return getSystem().getPackage(getPackageName()).getType(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "PackageImportModel(\"" + packageName + "\")";
|
||||||
|
}
|
||||||
|
}
|
289
slangc/model/PackageModel.sauce
Normal file
289
slangc/model/PackageModel.sauce
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
44
slangc/model/ParameterModel.sauce
Normal file
44
slangc/model/ParameterModel.sauce
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.api.Reporter;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.NodeType;
|
||||||
|
|
||||||
|
public class ParameterModel extends LocalStorageModel {
|
||||||
|
|
||||||
|
public ParameterModel(MethodModel owner, int index, Branch source) {
|
||||||
|
super(owner, index, (Branch) source/*.getSubnode(2)*/, owner.resolveType(source.getSubnode(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVariableArguments() {
|
||||||
|
return source.getNodeType() == NodeType.VARIABLE_ARGUMENT_DECLARATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump(Reporter reporter, String indent, String incr) {
|
||||||
|
reporter.note("DUMP", indent + "> '" + getName() + "', storage type " + getStorageType() + (isVariableArguments() ? " [varargs]" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeModel getStorageType() {
|
||||||
|
if (isVariableArguments()) {
|
||||||
|
return super.getStorageType().getOrCreateArrayInstance();
|
||||||
|
} else {
|
||||||
|
return super.getStorageType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node getNameNode() {
|
||||||
|
if (isVariableArguments()) {
|
||||||
|
return source.getSubnode(3);
|
||||||
|
} else {
|
||||||
|
return source.getSubnode(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public StorageSlot.Kind getSlotKind() {
|
||||||
|
return StorageSlot.Kind.ARGUMENT;
|
||||||
|
}
|
||||||
|
}
|
78
slangc/model/ParameterSet.sauce
Normal file
78
slangc/model/ParameterSet.sauce
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slang.data.List;
|
||||||
|
|
||||||
|
public class ParameterSet {
|
||||||
|
private MethodModel owner;
|
||||||
|
private List<ParameterModel> parameters = new List<ParameterModel>();
|
||||||
|
|
||||||
|
public ParameterSet(MethodModel owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countParameters() {
|
||||||
|
return parameters.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countNonVarargParameters() {
|
||||||
|
if (isVarargs()) {
|
||||||
|
return parameters.count() - 1;
|
||||||
|
} else {
|
||||||
|
return parameters.count();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParameterModel getVarargsParameter() {
|
||||||
|
if (isVarargs()) {
|
||||||
|
return parameters.get(parameters.count() - 1);
|
||||||
|
} else {
|
||||||
|
throw new Error("There is no varargs parameter here!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getVarargsElementType() {
|
||||||
|
return ((ArrayTypeModel) getVarargsParameter().getStorageType()).getElementType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVarargs() {
|
||||||
|
return parameters.count() > 0 && parameters.get(parameters.count() - 1).isVariableArguments();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeModel getParameterType(int i, boolean unpackVarargs) {
|
||||||
|
if (unpackVarargs && isVarargs() && i >= countNonVarargParameters()) {
|
||||||
|
return getVarargsElementType();
|
||||||
|
} else {
|
||||||
|
return parameters.get(i).getStorageType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParameterModel getParameter(int i) {
|
||||||
|
return parameters.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addParameter(ParameterModel p) {
|
||||||
|
parameters.append(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasParameter(String name) {
|
||||||
|
for (int i = 0; i < parameters.count(); i++) {
|
||||||
|
if (parameters.get(i).getName().equals(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParameterModel getParameter(String name) {
|
||||||
|
for (int i = 0; i < parameters.count(); i++) {
|
||||||
|
if (parameters.get(i).getName().equals(name)) {
|
||||||
|
return parameters.get(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
124
slangc/model/SourceModel.sauce
Normal file
124
slangc/model/SourceModel.sauce
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slang.data.List;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.NodeType;
|
||||||
|
import slangc.parser.Token;
|
||||||
|
|
||||||
|
public class SourceModel {
|
||||||
|
private PackageModel pkg;
|
||||||
|
private String filename;
|
||||||
|
private Branch parsed;
|
||||||
|
private boolean included;
|
||||||
|
private CombinedImportModel imports = null;
|
||||||
|
|
||||||
|
public SourceModel(PackageModel packageModel, String filename, Branch parsed, boolean included) {
|
||||||
|
this.pkg = packageModel;
|
||||||
|
this.filename = filename;
|
||||||
|
this.parsed = parsed;
|
||||||
|
this.included = included;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageModel getPackage() {
|
||||||
|
return pkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Branch getParsed() {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Branch getImportsBranch() {
|
||||||
|
return (Branch) parsed.getSubnode(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Branch getTypesBranch() {
|
||||||
|
return (Branch) parsed.getSubnode(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImportModel parseImport(Branch b) {
|
||||||
|
Node pkgOrTyp = b.getSubnode(1);
|
||||||
|
if (pkgOrTyp instanceof Branch && pkgOrTyp.getNodeType() == NodeType.IMPORTED_PACKAGE) {
|
||||||
|
return parseImportedPackage((Branch) pkgOrTyp);
|
||||||
|
} else if (pkgOrTyp instanceof Branch && pkgOrTyp.getNodeType() == NodeType.IMPORTED_TYPE) {
|
||||||
|
return parseImportedType((Branch) pkgOrTyp);
|
||||||
|
} else {
|
||||||
|
throw new Error("INTERNAL ERROR/TODO: Bad import declaration in parse tree");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String nameStr(Node n) {
|
||||||
|
if (n instanceof Branch && ((Branch) n).countSubnodes() == 1 /*n.getNodeType() == NodeType.NAME*/) {
|
||||||
|
return nameStr(((Branch)n).getSubnode(0));
|
||||||
|
} else if (n instanceof Token) {
|
||||||
|
return ((Token)n).getSnippet().getSource();
|
||||||
|
} else {
|
||||||
|
throw new Error("INTERNAL ERROR/TODO: Name string for " + n.getNodeType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImportModel parseImportedType(Branch b) {
|
||||||
|
String typnam = nameStr(b.getSubnode(b.countSubnodes() - 1));
|
||||||
|
String pkgnam = "";
|
||||||
|
for (int i = 0; i < b.countSubnodes() - 2; i++) {
|
||||||
|
pkgnam += nameStr(b.getSubnode(i));
|
||||||
|
}
|
||||||
|
//System.err.println("IMPORTING " + pkgnam + " . " + typnam);
|
||||||
|
return new TypeImportModel(pkg.getSystem(), b, pkgnam, typnam);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImportModel parseImportedPackage(Branch b) {
|
||||||
|
Branch pkgpart = (Branch) b.getSubnode(0);
|
||||||
|
String pkgnam = "";
|
||||||
|
for (int i = 0; i < pkgpart.countSubnodes(); i++) {
|
||||||
|
pkgnam += nameStr(pkgpart.getSubnode(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
//System.err.println("IMPORTING " + pkgnam + " (.*)");
|
||||||
|
return new PackageImportModel(pkg.getSystem(), false, pkgnam);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CombinedImportModel parseImports(boolean includeGlobals) {
|
||||||
|
List<ImportModel> models = new List<ImportModel>();
|
||||||
|
if (includeGlobals) {
|
||||||
|
models.append(getPackage().getSystem().getGlobalImports());
|
||||||
|
}
|
||||||
|
|
||||||
|
Branch b = getImportsBranch();
|
||||||
|
for (int i = 0; i < b.countSubnodes(); i++) {
|
||||||
|
Node n = b.getSubnode(i);
|
||||||
|
if (n instanceof Branch && n.getNodeType() == NodeType.IMPORT_DECLARATION) {
|
||||||
|
models.append(parseImport((Branch) n));
|
||||||
|
} else {
|
||||||
|
throw new Error("INTERNAL ERROR/TODO: Bad import declaration in parse tree");
|
||||||
|
}
|
||||||
|
//System.out.println("> GOT IMPORT " + b.getSubnode(i).getNodeType());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportModel[] modelsArray = models.arrayCopy();
|
||||||
|
return new CombinedImportModel(getPackage().getSystem(), false, modelsArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CombinedImportModel getImports() {
|
||||||
|
if (imports == null) {
|
||||||
|
imports = parseImports(true);
|
||||||
|
}
|
||||||
|
return imports;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countErrors() {
|
||||||
|
return parsed.countErrorsRecursively();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteErrors() {
|
||||||
|
return parsed.deleteErrorsRecursively();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIncluded() {
|
||||||
|
return included;
|
||||||
|
}
|
||||||
|
}
|
49
slangc/model/SpecialisedTypeModel.sauce
Normal file
49
slangc/model/SpecialisedTypeModel.sauce
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public class SpecialisedTypeModel extends SyntheticTypeModel {
|
||||||
|
private PackageModel templatePackage;
|
||||||
|
private String templateName;
|
||||||
|
private TypeType typeType;
|
||||||
|
private TemplateArguments templateArguments;
|
||||||
|
|
||||||
|
public SpecialisedTypeModel(PackageModel packageModel, String name, TypeLevel level, TypeModel owner, PackageModel templatePackage, String templateName, TypeType typeType, TemplateArguments arguments) {
|
||||||
|
super(packageModel, name, level, owner);
|
||||||
|
this.templatePackage = templatePackage;
|
||||||
|
this.templateName = templateName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeType getTypeType() {
|
||||||
|
return typeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackageModel getTemplatePackage() {
|
||||||
|
return templatePackage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTemplateName() {
|
||||||
|
return templateName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemplateArguments getTemplateArguments() {
|
||||||
|
return templateArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int expand() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int resolveTypes() {
|
||||||
|
Log.line("TODO: resolveTypes in " + Type.of(this));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isObjectType() {
|
||||||
|
// TODO?
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
99
slangc/model/StatementModel.sauce
Normal file
99
slangc/model/StatementModel.sauce
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
import slangc.api.BytecodeInstructionWriter;
|
||||||
|
import slangc.api.Reporter;
|
||||||
|
import slangc.model.statements.*;
|
||||||
|
import slangc.parser.Branch;
|
||||||
|
import slangc.parser.Node;
|
||||||
|
import slangc.parser.NodeType;
|
||||||
|
|
||||||
|
public abstract class StatementModel extends StatementOrExpression {
|
||||||
|
private StatementOwner owner;
|
||||||
|
private Node source;
|
||||||
|
|
||||||
|
public StatementModel(StatementOwner owner, Node source) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatementOwner getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StatementModel construct(StatementOwner owner, Node source) {
|
||||||
|
switch (source.getNodeType()) {
|
||||||
|
case NodeType.VARIABLE_STATEMENT:
|
||||||
|
return new VariableStatement(owner, (Branch)source);
|
||||||
|
case NodeType.RETURN_NOTHING_STATEMENT:
|
||||||
|
return new ReturnNothingStatement(owner, (Branch)source);
|
||||||
|
case NodeType.RETURN_EXPRESSION_STATEMENT:
|
||||||
|
return new ReturnExpressionStatement(owner, (Branch)source);
|
||||||
|
case NodeType.EXPRESSION_STATEMENT:
|
||||||
|
return new ExpressionStatement(owner, (Branch)source);
|
||||||
|
case NodeType.TRY_STATEMENT:
|
||||||
|
return new TryStatement(owner, (Branch)source);
|
||||||
|
case NodeType.THROW_STATEMENT:
|
||||||
|
return new ThrowStatement(owner, (Branch)source);
|
||||||
|
case NodeType.ASSERT_STATEMENT:
|
||||||
|
return new AssertStatement(owner, (Branch)source);
|
||||||
|
case NodeType.BLOCK_STATEMENT:
|
||||||
|
return new BlockStatement(owner, (Branch)source);
|
||||||
|
case NodeType.IF_STATEMENT:
|
||||||
|
return new IfStatement(owner, (Branch)source);
|
||||||
|
case NodeType.WHILE_STATEMENT:
|
||||||
|
return new WhileStatement(owner, (Branch)source);
|
||||||
|
case NodeType.DO_WHILE_STATEMENT:
|
||||||
|
return new DoWhileStatement(owner, (Branch) source);
|
||||||
|
case NodeType.BREAK_STATEMENT:
|
||||||
|
return new BreakStatement(owner, (Branch) source);
|
||||||
|
case NodeType.CONTINUE_STATEMENT:
|
||||||
|
return new ContinueStatement(owner, (Branch) source);
|
||||||
|
case NodeType.FOR_STATEMENT:
|
||||||
|
return new ForStatement(owner, (Branch) source);
|
||||||
|
case NodeType.SWITCH_STATEMENT:
|
||||||
|
return new SwitchStatement(owner, (Branch) source);
|
||||||
|
case NodeType.CASE_LABEL:
|
||||||
|
return new CaseLabelStatement(owner, (Branch)source);
|
||||||
|
case NodeType.DEFAULT_LABEL:
|
||||||
|
return new DefaultLabelStatement(owner, (Branch)source);
|
||||||
|
case NodeType.SYNCHRONIZED_STATEMENT:
|
||||||
|
return new SynchronizedStatement(owner, (Branch) source);
|
||||||
|
case NodeType.SEMICOLON:
|
||||||
|
return new EmptyStatement(owner, (Branch) source);
|
||||||
|
case NodeType.CLASS_DECLARATION:
|
||||||
|
case NodeType.INTERFACE_DECLARATION:
|
||||||
|
case NodeType.ENUM_DECLARATION:
|
||||||
|
case NodeType.ATTRIBUTE_DECLARATION:
|
||||||
|
return new TypeDeclarationStatement(owner, (Branch) source);
|
||||||
|
default:
|
||||||
|
return new UnrecognisedStatement(owner, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump(Reporter reporter, String indent, String incr) {
|
||||||
|
reporter.note("DUMP", indent + incr + "TODO: dump " + Type.of(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Named lookupSimpleName(String name) {
|
||||||
|
return getOwner().lookupSimpleName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel[] lookupSimpleMethod(String name) {
|
||||||
|
return getOwner().lookupSimpleMethod(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract int resolveExpressions();
|
||||||
|
|
||||||
|
public abstract void innerGenerate(BytecodeInstructionWriter w);
|
||||||
|
|
||||||
|
public final void generate(BytecodeInstructionWriter w) {
|
||||||
|
w.pushSource(getSource());
|
||||||
|
innerGenerate(w);
|
||||||
|
w.popSource();
|
||||||
|
}
|
||||||
|
}
|
15
slangc/model/StatementOrExpression.sauce
Normal file
15
slangc/model/StatementOrExpression.sauce
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package slangc.model;
|
||||||
|
|
||||||
|
public abstract class StatementOrExpression {
|
||||||
|
|
||||||
|
public StatementOrExpression() {
|
||||||
|
// TODO Auto-generated constructor stub
|
||||||
|
}
|
||||||
|
|
||||||
|
public int resolveExpressions() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Named lookupSimpleName(String name);
|
||||||
|
public abstract MethodModel[] lookupSimpleMethod(String name);
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user