246 lines
7.4 KiB
Plaintext
246 lines
7.4 KiB
Plaintext
|
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);
|
||
|
}
|
||
|
}
|