1 module vayne.compiler; 2 3 4 import std.algorithm; 5 import std.array; 6 import std.file; 7 import std.path; 8 import std.stdio; 9 import std.string; 10 11 import vayne.ast.node; 12 import vayne.ast.printer; 13 import vayne.code.emitter; 14 import vayne.op; 15 import vayne.serializer; 16 import vayne.source.compress; 17 import vayne.source.parser; 18 import vayne.source.preparser; 19 import vayne.source.source; 20 21 22 struct CompilerOptions { 23 auto preparsePrint = false; 24 auto astPrint = false; 25 auto instrPrint = false; 26 auto byteCodePrint = false; 27 auto constPrint = false; 28 auto lineNumbers = true; 29 auto compress = false; 30 31 string[] search; 32 string ext = ".html"; 33 } 34 35 36 enum ConstantType : ubyte { 37 Null, 38 Boolean, 39 String, 40 Integer, 41 Float, 42 } 43 44 45 struct CompiledCode { 46 uint registerCount; 47 48 const(Instr)[] instrs; 49 const(SourceLoc)[] locs; 50 const(string)[] sources; 51 const(Constant)[] constants; 52 const(string)[] dependencies; 53 54 static struct Constant { 55 ConstantType type; 56 string value; 57 } 58 } 59 60 61 class CompileErrorsException : Exception { 62 this(string[] errors) { 63 assert(!errors.empty); 64 super(errors[0]); 65 66 this.errors = errors; 67 } 68 69 string[] errors; 70 } 71 72 73 CompiledCode compile(string fileName, CompilerOptions options) { 74 try { 75 SourceManagerOptions mgrOptions; 76 mgrOptions.search ~= options.search; 77 mgrOptions.extension = options.ext; 78 79 auto mgr = SourceManager(mgrOptions); 80 auto src = mgr.open(fileName); 81 82 PreParserOptions preOptions; 83 preOptions.lineNumbers = options.lineNumbers; 84 85 mgr.set(src.id, preparse(mgr, src.id, preOptions)); 86 87 if (options.preparsePrint) 88 writeln(mgr.get(src.id).buffer); 89 90 ParserOptions parserOptions; 91 parserOptions.compress = options.compress ? CompressOptions.defaults : CompressOptions.none; 92 93 auto ast = parse(mgr, src.id, parserOptions); 94 if (options.astPrint) 95 ast.print.writeln; 96 97 Emitter emitter; 98 emitter.emitModule(cast(Module)ast); 99 100 if (options.constPrint) { 101 foreach (i, k; emitter.constants) 102 writeln(format("%4d %-16s %s", i, k.type, k.value)); 103 } 104 105 if (options.instrPrint || options.byteCodePrint) { 106 auto fmt = "%5d " ~ (options.byteCodePrint ? "%-58s" : "%-24s"); 107 108 if (options.lineNumbers) 109 fmt ~= " ; %s"; 110 111 if (options.lineNumbers) { 112 foreach (ip, instr; emitter.instrs) 113 writeln(format(fmt, ip, options.byteCodePrint ? instr.toStringFull : instr.toString, mgr.loc(emitter.locs[ip]))); 114 } else { 115 foreach (ip, instr; emitter.instrs) 116 writeln(format(fmt, ip, options.byteCodePrint ? instr.toStringFull : instr.toString)); 117 } 118 } 119 120 CompiledCode result; 121 with (result) { 122 registerCount = emitter.registerCount; 123 124 instrs = emitter.instrs; 125 locs = emitter.locs; 126 sources = mgr.sourceNames; 127 dependencies = mgr.dependencies.map!(x => mgr.fileNames[x]).array; 128 129 constants.reserve(emitter.constants.length); 130 foreach (i, k; emitter.constants) { 131 final switch (k.type) with (Emitter.ConstantSlot.Type) { 132 case Null: 133 constants ~= CompiledCode.Constant(ConstantType.Null, k.value); 134 break; 135 case Boolean: 136 constants ~= CompiledCode.Constant(ConstantType.Boolean, k.value); 137 break; 138 case Integer: 139 constants ~= CompiledCode.Constant(ConstantType.Integer, k.value); 140 break; 141 case Float: 142 constants ~= CompiledCode.Constant(ConstantType.Float, k.value); 143 break; 144 case String: 145 constants ~= CompiledCode.Constant(ConstantType.String, k.value); 146 break; 147 } 148 } 149 } 150 151 return result; 152 } catch (Exception error) { 153 string[] errors; 154 155 if (auto parserErrors = cast(ParserErrorsException)error) { 156 errors = parserErrors.errors; 157 } else { 158 errors ~= error.msg; 159 } 160 161 throw new CompileErrorsException(errors); 162 } 163 }