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