slcom/slangc/sdk/CompilerMain.sauce

483 lines
18 KiB
Plaintext

package slangc.sdk;
import slangc.streams.FileInput;
import slangc.streams.File;
import slangc.streams.LogWriter;
import slangc.streams.VFS;
import slangc.streams.SimpleVFS;
import slangc.api.BytecodeTarget;
import slangc.api.CompilerWorld;
import slangc.api.Reporter;
import slangc.api.TypeOption;
import slangc.parser.Annotation;
import slangc.parser.Branch;
import slangc.parser.CleopatraModeLanguage;
import slangc.parser.LegacyLanguage;
import slangc.parser.Node;
import slangc.parser.Token;
public class CompilerMain {
public static int a(int i) {
Log.line("" + i);
return i;
}
public static void b(int a, int b) {
Log.line(a + " " + b);
}
public static void usage(String[] args, int argi, String message) {
Log.line("USAGE:\n\tTODO...\n" + message);
if (message != null) {
throw new Error("TODO: Safe exit"); //System.exit(1);
}
}
private static void doAddSource(CompilerWorld world, File file, boolean isReference) throws Error {
recursiveAddSource(world, null, file, isReference);
}
private static byte[] getFileBytes(File f) throws Error {
FileInput in = f.openInput();
byte[] out = new byte[(int) f.size()];
in.readBuffer(out, 0, out.length);
in.close();
return out;
}
private static void recursiveAddSource(CompilerWorld world, String packagename, File file, boolean isReference) throws Error {
File[] subs = file.list();
if (subs == null) {
//Log.line(" > Processing " + (isReference ? "referenced" : "included") + " file " + file.path());
if (world.matchesIgnorePattern(file.name())) {
//Log.line("Ignoring '" + file.path() + "'...");
} else if (world.matchesDataPattern(file.name())) {
//Log.line("Adding data file '" + file.path() + "'...");
if (!isReference) world.addDataFile(packagename, file.name(), getFileBytes(file), null, null);
} else if (world.matchesSourcePattern(file.name())) {
//Log.line("Adding source file '" + file.path() + "'...");
world.addSource(/*new SimpleSource(file)*/ new UnicodeSource(file), isReference);
} else {
throw new Error("Unrecognised file extension for '" + file.path() + "'");
//Log.line("Ignoring " + file.path() + "...");
}
} else {
if (packagename == null) {
packagename = ""; // This should be used for default/outer directory
} else if (packagename.equals("")) {
packagename = file.name();
} else {
packagename = packagename + "." + file.name();
}
//Log.line("Scanning directory '" + file.path() + "' (as package " + packagename + ")...");
for (int i = 0; i < subs.length; i++) {
recursiveAddSource(world, packagename, subs[i], isReference);
}
}
}
public static void main(String[] args) {
Log.line("Zak's Burrito Compiler, build #13-ish");
//Log.line("Hello, ٣١٤١٥=" + ٣١٤١٥);
int i = 0;
VFS vfs = new SimpleVFS();
CompilerWorld world = new CompilerWorld();
world.addSourcePattern("*.sauce");
/*
world.addIgnorePattern("*.foo");
world.addDataPattern("bar");
*/
/*for (i = 0; i < args.length; i++) {
Log.line("Arg #" + i + " is '" + args[i] + "'");
}
i = 0;*/
boolean doingSomething = false;
Reporter reporter = null;
//Log.line("Doing args...");
//Log.startTracing();
try {
while (i < args.length) {
//Log.line("Handling Arg #" + i + " is '" + args[i] + "'");
/* If it's a "-b" flag, then we translate it into corresponding "-a" and "-r" flags. */
if (args[i].startsWith("-b")) {
if (args[i].intsLength() > 2) {
String path = args[i].sub(2);
args = ArgsLoader.remove(args, i);
args = ArgsLoader.insert(args, i, new String[] {"-a", path + "/compiler.wrap", "-r", path});
} else {
if (i + 1 >= args.length) {
usage(args, i + 1, "Expecting filename following -a flag");
return;
}
String path = args[i+1];
args = ArgsLoader.remove(args, i);
args = ArgsLoader.remove(args, i);
args = ArgsLoader.insert(args, i, new String[] {"-a", path + "/compiler.wrap", "-r", path});
}
/*for (int x = 0; x < args.length; x++) {
Log.line("Arg #" + x + " = '" + args[x] + "'");
}
System.exit(-1);*/
}
/* If it's a "-a" flag, then we want to load the arguments from a file, insert them in the array,
* then continue processing!
*/
if (args[i].startsWith("-a")) {
if (args[i].intsLength() > 2) {
Log.line("NOTE: Loading compiler arguments from " + args[i].sub(2));
String[] newArgs = ArgsLoader.loadArgs(new UnicodeSource(vfs.file(args[i].sub(2))));
args = ArgsLoader.remove(args, i);
args = ArgsLoader.insert(args, i, newArgs);
} else {
if (i + 1 >= args.length) {
usage(args, i + 1, "Expecting filename following -a flag");
return;
}
Log.line("NOTE: Loading compiler arguments from " + args[i+1]);
String[] newArgs = ArgsLoader.loadArgs(new UnicodeSource(vfs.file(args[i+1])));
args = ArgsLoader.remove(args, i);
args = ArgsLoader.remove(args, i);
args = ArgsLoader.insert(args, i, newArgs);
}
/*for (int x = 0; x < args.length; x++) {
Log.line("Arg #" + x + " = '" + args[x] + "'");
}
System.exit(-1);*/
}
//Log.line("Handling Arg #" + i + " is '" + args[i] + "'");
if (args[i].equals("--provides-version")) {
if (i + 2 >= args.length) {
usage(args, i, "Expected name and version following --provides-version");
return;
}
world.addProvidesVersion(args[i + 1], args[i + 2]);
i += 2;
} else if (args[i].equals("--depends-version")) {
if (i + 2 >= args.length) {
usage(args, i, "Expected name and version following --depends-version");
return;
}
world.addDependsVersion(args[i + 1], args[i + 2]);
i += 2;
} else if (args[i].equals("--source-pattern")) {
if (i + 1 >= args.length) {
usage(args, i, "Expected source pattern following --source-pattern (e.g. \"*.slang\" - probably with the quotes)");
return;
}
world.addSourcePattern(args[i + 1]);
i += 1;
} else if (args[i].equals("--ignore-pattern")) {
if (i + 1 >= args.length) {
usage(args, i, "Expected ignore pattern following --ignore-pattern (e.g. \"*.project\" - probably with the quotes)");
return;
}
world.addIgnorePattern(args[i + 1]);
i += 1;
} else if (args[i].equals("--data-pattern")) {
if (i + 1 >= args.length) {
usage(args, i, "Expected source pattern following --data-pattern (e.g. \"*.png\" - probably with the quotes)");
return;
}
world.addDataPattern(args[i + 1]);
i += 1;
} else if (args[i].equals("--global-import")) {
if (i + 1 >= args.length) {
usage(args, i, "Expected package name following --global-import");
return;
}
world.addGlobalImport(args[i + 1]);
i += 1;
} else if (args[i].equals("--alias-type")) {
if (i + 2 >= args.length) {
usage(args, i, "Expected alias and target type names following --alias-type");
return;
}
world.addAliasType(args[i + 1], args[i + 2]);
i += 2;
} else if (args[i].equals("--alias-package")) {
if (i + 2 >= args.length) {
usage(args, i, "Expected alias and target package names following --alias-package");
return;
}
world.addAliasPackage(args[i + 1], args[i + 2]);
i += 2;
} else if (args[i].equals("--main")) {
if (i + 1 >= args.length) {
usage(args, i, "Expected type name following --main");
return;
}
world.addMainType(args[i + 1]);
i += 1;
} else if (args[i].equals("--special-type-format")) {
if (i + 3 >= args.length) {
usage(args, i, "Expected kind name, type name and runtime-specific format string following --special-type-format");
return;
}
TypeOption.Kind k;
k = (TypeOption.Kind) TypeOption.Kind.lookup(TypeOption.Kind.class, args[i + 1]);
if (k == null) {
usage(args, i+1, "Invalid kind name");
return;
}
world.addSpecialType(k, args[i + 2], args[i + 3]);
i += 3;
} else if (args[i].equals("--special-type")) {
if (i + 2 >= args.length) {
usage(args, i, "Expected kind name and type name following --special-type");
return;
}
TypeOption.Kind k;
try {
k = (TypeOption.Kind) TypeOption.Kind.lookup(TypeOption.Kind.class, args[i + 1]);
} catch(Error e) {
e.log();
Log.line("Name of VOID is '" + TypeOption.Kind.VOID.name() + "'");
usage(args, i+1, "Invalid kind name");
return;
}
world.addSpecialType(k, args[i + 2], null);
i += 2;
} else if (args[i].equals("--builtin-type")) {
if (i + 2 >= args.length) {
usage(args, i, "Expected kind name and type name following --builtin-type");
return;
}
TypeOption.Kind k;
try {
k = (TypeOption.Kind) TypeOption.Kind.lookup(TypeOption.Kind.class, args[i + 1]);
} catch(Error e) {
usage(args, i+1, "Invalid kind name");
return;
}
world.addBuiltinType(k, args[i + 2], null);
i += 2;
} else if (args[i].equals("--meta")) {
if (i + 2 >= args.length) {
usage(args, i, "Expected key and typeName following --meta");
return;
}
world.addMeta(false, args[i + 1], args[i + 2]);
i += 2;
} else if (args[i].equals("--important-meta")) {
if (i + 2 >= args.length) {
usage(args, i, "Expected key and typeName following --important-meta");
return;
}
world.addMeta(true, args[i + 1], args[i + 2]);
i += 2;
} else if (args[i].startsWith("-r")) {
if (args[i].ints().length > 2) {
doAddSource(world, vfs.file(args[i].sub(2)), true);
doingSomething = true;
} else {
i++;
if (i >= args.length) {
usage(args, i, "Expecting filename following -r flag");
return;
}
doAddSource(world, vfs.file(args[i]), true);
doingSomething = true;
}
} else if (args[i].startsWith("-o")) {
if (args[i].ints().length > 2) {
world.setTarget(new BytecodeTarget(new SimpleBytecodeOutput(vfs.file(args[i].sub(2)).openOutput())));
//doingSomething = true;
} else {
i++;
if (i >= args.length) {
usage(args, i, "Expecting filename following -o flag");
return;
}
world.setTarget(new BytecodeTarget(new SimpleBytecodeOutput(vfs.file(args[i]).openOutput())));
//doingSomething = true;
}
} else if (args[i].equals("--compliments-to-the-chef") || args[i].equals("--gluten-free")) {
Log.line("**************************************************");
String start = "* Salt Sprinkling Mode ";
boolean merciless = args[i].equals("--gluten-free");
CleopatraModeLanguage herMajesty = new CleopatraModeLanguage(!merciless);
herMajesty.addMedu(CleopatraModeLanguage.Medu.NUBIAN);
herMajesty.addMedu(CleopatraModeLanguage.Medu.COPTIC);
world.setLanguage(herMajesty);
Log.line(start + (merciless ? " TURBO *" : "ACTIVATED *"));
Log.line("**************************************************");
//herMajesty.printTable(System.err);
//return;
} else if (args[i].equals("-ll0")) {
world.setLanguage(new LegacyLanguage(0));
} else if (args[i].equals("-ll1")) {
world.setLanguage(new LegacyLanguage(1));
} else if (args[i].equals("-ll2")) {
world.setLanguage(new LegacyLanguage(2));
} else if (args[i].equals("-ll3")) {
world.setLanguage(new LegacyLanguage(3));
} else if (args[i].equals("-ll4")) {
world.setLanguage(new LegacyLanguage(4));
} else if (args[i].equals("-ll5")) {
world.setLanguage(new LegacyLanguage(5));
} else if (args[i].equals("-ll6")) {
world.setLanguage(new LegacyLanguage(6));
} else if (args[i].equals("-ll7")) {
world.setLanguage(new LegacyLanguage(7));
} else if (args[i].equals("-ll8")) {
world.setLanguage(new LegacyLanguage(8));
} else if (args[i].equals("-ll9")) {
world.setLanguage(new LegacyLanguage(9));
} else if (args[i].equals("-ll10")) {
world.setLanguage(new LegacyLanguage(10));
} else if (args[i].equals("-ll11")) {
world.setLanguage(new LegacyLanguage(11));
} else if (args[i].equals("-ll12")) {
world.setLanguage(new LegacyLanguage(12));
} else if (args[i].equals("-ll13")) {
world.setLanguage(new LegacyLanguage(13));
} else if (args[i].equals("-ll14")) {
world.setLanguage(new LegacyLanguage(14));
} else if (args[i].equals("-ll15")) {
world.setLanguage(new LegacyLanguage(15));
} else if (args[i].equals("-ll16")) {
world.setLanguage(new LegacyLanguage(16));
} else if (args[i].equals("--language-forget")) {
if (i + 1 >= args.length) {
usage(args, i, "Expecting setting name following --language-forget");
return;
}
if (!world.getLanguage().applySetting(args[i+1], null, true, false)) {
usage(args, i+1, "Invalid setting");
return;
}
i += 1;
} /*else if (args[i].equals("--language-set")) {
if (i + 2 >= args.length) {
usage(args, i, "Expecting setting name and value following --language-set");
return;
}
if (!world.getLanguage().applySetting(args[i+1], args[i+2], false, false)) {
usage(args, i+2, "Invalid setting");
return;
}
i += 2;
}*/ else if (args[i].equals("--language-add")) {
if (i + 2 >= args.length) {
usage(args, i, "Expecting setting name and value following --language-append");
return;
}
if (!world.getLanguage().applySetting(args[i+1], args[i+2], false, true)) {
usage(args, i+2, "Invalid setting");
return;
}
i += 2;
} else if (args[i].equals("--array-length-name")) {
if (i + 1 >= args.length) {
usage(args, i, "Expecting setting name following --array-length-name");
return;
}
world.addArrayLengthName(args[i+1]);
i += 1;
} else if (args[i].equals("--errors-brief")) {
world.setErrorVerbosity(0);
} else if (args[i].equals("--errors-nice")) {
world.setErrorVerbosity(2);
} else if (args[i].equals("--errors-ast")) {
world.setErrorVerbosity(5);
} else if (args[i].equals("--errors-full-ast")) {
world.setErrorVerbosity(10);
} else if (args[i].equals("--cache-dir")) {
//Log.line("WTF...");
if (i + 1 >= args.length) {
usage(args, i, "Expecting directory path following --cache-dir");
return;
}
//Log.line("Trying to set cache manager...");
world.setCacheManager(new SimpleCacheManager(vfs.file(args[i+1])));
//Log.line("Done.");
i += 1;
} else {
Log.line("Adding regular sources '" + args[i] + "'");
doAddSource(world, vfs.file(args[i]), false);
doingSomething = true;
}
i++;
}
if (!doingSomething) {
usage(args, i, "Expecting something to do! Try listing some source files?");
}
if (reporter == null) {
reporter = new SimpleReporter();
}
world.setReporter(reporter);
if (world.build()) {
Log.line("Compilation completed.");
} else {
Log.line("Compilation terminated without finishing.");
}
} catch (Error e) {
e.log();
// TODO: Is more reporting needed here?
}
//SimpleSource src = new SimpleSource("package x.y\nimport z.*; import foo.bar.Baz;\npublic final enum X extends a.B, C{X,Y,private static Z,;} class Foo extends Bar {\nvoid x(int a){{}}\nint a = 1, b;\npublic Foo(int... nums){}}\n/* comment 1 */\n// comment 2\nclass Documented {\n/* look, an array of arrays: */\nint[][] arrz = null;\nDocumented(){if(true){return 1;}else{return;}int x = add(1,z().foo[1].mul(2,3)), y = (z).foo();n();x++; x *= 2; x = 1 + 2 * -3 + new fencom.Object;\nx = \"foo bar\";\n}\n}\n");//int add(int x, int y){\nreturn x + y;\n}
/*Scan scan = new Scan(new Language(), src);
int n = scan.scanPedantic();
Log.line("Scanned " + n + " tokens:");
for (int i = 0; i < scan.countTokens(); i++) {
Log.line(" > " + scan.getToken(i));
}
Parse p = new Parse();
Node u = p.parseUnit(scan);
Log.line("Finished parsing!");
// Was just for testing order of operations: b(a(1), a(2));
dump(System.out, u);
*/
}
@SuppressWarnings("unused")
private static void dump(LogWriter out, Node n) {
dump(out, n, "", " ");
}
private static void dump(LogWriter out, Node n, String curindent, String subindent) {
if (n instanceof Branch) {
dumpBranch(out, (Branch) n, curindent, subindent);
} else if (n instanceof Token) {
dumpToken(out, (Token) n, curindent, subindent);
} else if (n instanceof Annotation) {
dumpAnnotation(out, (Annotation) n, curindent, subindent);
} else if (n == null) {
out.println(curindent + "-! UH-OH !- null");
} else {
out.println(curindent + "-! TO-DO !- code to dump " + n);
}
}
private static void dumpAnnotations(LogWriter out, Node n, String curindent, String subindent) {
for (int i = 0; i < n.countAnnotations(); i++) {
dump(out, n.getAnnotation(i), curindent + subindent, subindent);
}
}
private static void dumpBranch(LogWriter out, Branch b, String curindent, String subindent) {
out.println(curindent + "-> " + b.getNodeType());
dumpAnnotations(out, b, curindent, subindent);
for (int i = 0; i < b.countSubnodes(); i++) {
dump(out, b.getSubnode(i), curindent + subindent, subindent);
}
}
private static void dumpToken(LogWriter out, Token t, String curindent, String subindent) {
out.println(curindent + "-. " + t);
dumpAnnotations(out, t, curindent, subindent);
}
private static void dumpAnnotation(LogWriter out, Annotation a, String curindent, String subindent) {
out.println(curindent + "-+ " + a);
dumpAnnotations(out, a, curindent, subindent);
}
}