slcom/slangc/api/Unit.sauce

246 lines
7.4 KiB
Plaintext
Raw Normal View History

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