174 lines
4.9 KiB
Plaintext
174 lines
4.9 KiB
Plaintext
package slangc.parser;
|
|
|
|
import slang.streams.SyncOutput;
|
|
import slang.streams.SyncInput;
|
|
import slang.data.SimpleEnum;
|
|
|
|
public abstract class Node {
|
|
public Object userdata;
|
|
Annotation[] annotations = null;
|
|
|
|
Node() {
|
|
// TODO Auto-generated constructor stub
|
|
}
|
|
|
|
public abstract NodeType getNodeType();
|
|
|
|
public abstract String toString();
|
|
|
|
private static byte[] inbuffer = new byte[1];
|
|
|
|
static SimpleEnum[] toknums = TokenType.values(TokenType.class);
|
|
static SimpleEnum[] nnums = NodeType.values(NodeType.class);
|
|
|
|
public static Node loadBinary(Scan sc, SyncInput<byte> inp) {
|
|
inp.readBuffer(inbuffer, 0, 1);
|
|
if (((int) inbuffer[0]) < 0) {
|
|
int toknum = (-(int)inbuffer[0]) - 1;
|
|
//Log.line("Read number " + inbuffer[0] + " as " + toknum);
|
|
if (toknum == 127) {
|
|
inp.readBuffer(inbuffer, 0, 1);
|
|
toknum = (-(int)inbuffer[0]) - 1;
|
|
TokenType tt = (TokenType)toknums[toknum]; //TokenType.lookup(TokenType.class, toknum);
|
|
return Token.loadBinaryLong(sc, tt, inp);
|
|
} else {
|
|
TokenType tt = (TokenType)toknums[toknum]; //TokenType.lookup(TokenType.class, toknum);
|
|
return Token.loadBinaryShort(sc, tt, inp);
|
|
}
|
|
} else {
|
|
int top = (int)(inbuffer[0] & 0xFF);
|
|
inp.readBuffer(inbuffer, 0, 1);
|
|
int nnum = (top << 8) | (int)(inbuffer[0] & 0xFF);
|
|
NodeType nt = (NodeType)nnums[nnum]; //NodeType.lookup(NodeType.class, nnum);
|
|
return Branch.loadBinary(sc, nt, inp);
|
|
}
|
|
}
|
|
|
|
public abstract void dumpBinary(SyncOutput<byte> o) {
|
|
throw new Error("Can't dump AST nodes of type " + Type.of(this).fullName());
|
|
}
|
|
|
|
public int countAnnotations() {
|
|
if (annotations == null) {
|
|
return 0;
|
|
} else {
|
|
return annotations.length;
|
|
}
|
|
}
|
|
|
|
public Annotation[] getAnnotations(AnnotationType type) {
|
|
Annotation[] result = new Annotation[0];
|
|
for (int i = 0; i < countAnnotations(); i++) {
|
|
Annotation a = getAnnotation(i);
|
|
if (a.getAnnotationType() == type) {
|
|
Annotation[] nresult = new Annotation[result.length + 1];
|
|
for (int j = 0; j < result.length; j++) {
|
|
nresult[j] = result[j];
|
|
}
|
|
nresult[nresult.length - 1] = a;
|
|
result = nresult;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public int deleteAnnotations(AnnotationType type) {
|
|
int ndeleted = 0;
|
|
Annotation[] result = new Annotation[0];
|
|
for (int i = 0; i < countAnnotations(); i++) {
|
|
Annotation a = getAnnotation(i);
|
|
if (a.getAnnotationType() == type) {
|
|
ndeleted++;
|
|
} else {
|
|
Annotation[] nresult = new Annotation[result.length + 1];
|
|
for (int j = 0; j < result.length; j++) {
|
|
nresult[j] = result[j];
|
|
}
|
|
nresult[nresult.length - 1] = a;
|
|
result = nresult;
|
|
}
|
|
}
|
|
annotations = result;
|
|
return result.length;
|
|
}
|
|
|
|
public int countAnnotations(AnnotationType type) {
|
|
return getAnnotations(type).length;
|
|
}
|
|
|
|
public int countErrorsHere() {
|
|
return countAnnotations(AnnotationType.ERROR);
|
|
}
|
|
|
|
public int deleteErrorsHere() {
|
|
return deleteAnnotations(AnnotationType.ERROR);
|
|
}
|
|
|
|
public int countErrorsRecursively() {
|
|
return countErrorsHere();
|
|
}
|
|
|
|
public int deleteErrorsRecursively() {
|
|
return deleteErrorsHere();
|
|
}
|
|
|
|
public Node annotate(ErrorType e) {
|
|
return annotate(new ErrorAnnotation(e));
|
|
}
|
|
|
|
public Node annotate(ErrorType e, String n) {
|
|
ErrorAnnotation a = new ErrorAnnotation(e);
|
|
a.annotate(n);
|
|
return annotate(a);
|
|
}
|
|
|
|
public Node annotate(WarningType w) {
|
|
return annotate(new WarningAnnotation(w));
|
|
}
|
|
|
|
public Node annotate(WarningType w, String n) {
|
|
WarningAnnotation a = new WarningAnnotation(w);
|
|
a.annotate(n);
|
|
return annotate(a);
|
|
}
|
|
|
|
public Node annotate(String note) {
|
|
return annotate(new NoteAnnotation(note));
|
|
}
|
|
|
|
/* As a special optimisation, we set a global flag when an error is found.
|
|
* This means that if no errors have been found in this run, looking for/counting errors in
|
|
* the tree can be avoided entirely!
|
|
*/
|
|
public static boolean mightHaveErrors = true;
|
|
public static boolean mightHaveWarnings = false;
|
|
|
|
public Node annotate(Annotation n) {
|
|
if (n instanceof ErrorAnnotation) {
|
|
mightHaveErrors = true;
|
|
}
|
|
if (n instanceof WarningAnnotation) {
|
|
mightHaveWarnings = true;
|
|
}
|
|
if (annotations == null || annotations.length < 1) {
|
|
annotations = new Annotation[] {n};
|
|
return this;
|
|
}
|
|
Annotation[] nsubnodes = new Annotation[annotations.length + 1];
|
|
for (int i = 0; i < annotations.length; i++) {
|
|
nsubnodes[i] = annotations[i];
|
|
}
|
|
nsubnodes[nsubnodes.length - 1] = n;
|
|
annotations = nsubnodes;
|
|
return this;
|
|
}
|
|
|
|
public Annotation getAnnotation(int i) {
|
|
if (i < 0 || i >= countAnnotations()) {
|
|
return null;
|
|
} else {
|
|
return annotations[i];
|
|
}
|
|
}
|
|
}
|