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 mgr.set(src.id, preparse(mgr, src.id, preOptions)); 85 86 if (options.preparsePrint) 87 writeln(mgr.get(src.id).buffer); 88 89 ParserOptions parserOptions; 90 parserOptions.compress = options.compress ? CompressOptions.defaults : CompressOptions.none; 91 92 auto ast = parse(mgr, src.id, parserOptions); 93 if (options.astPrint) 94 ast.print.writeln; 95 96 Emitter emitter; 97 emitter.emitModule(cast(Module)ast); 98 99 if (options.constPrint) { 100 foreach (i, k; emitter.constants) 101 writeln(format("%5d %-16s %s", i, k.type, k.value)); 102 } 103 104 if (options.instrPrint || options.byteCodePrint) { 105 auto fmt = "%5d " ~ (options.byteCodePrint ? "%-58s" : "%-24s"); 106 107 if (options.lineNumbers) 108 fmt ~= " ; %s"; 109 110 if (options.lineNumbers) { 111 foreach (ip, instr; emitter.instrs) 112 writeln(format(fmt, ip, options.byteCodePrint ? instr.toStringFull : instr.toString, mgr.loc(emitter.locs[ip]))); 113 } else { 114 foreach (ip, instr; emitter.instrs) 115 writeln(format(fmt, ip, options.byteCodePrint ? instr.toStringFull : instr.toString)); 116 } 117 } 118 119 CompiledCode result; 120 with (result) { 121 registerCount = emitter.registerCount; 122 123 instrs = emitter.instrs; 124 locs = emitter.locs; 125 sources = mgr.sourceNames; 126 dependencies = mgr.dependencies.map!(x => mgr.fileNames[x]).array; 127 128 constants.reserve(emitter.constants.length); 129 foreach (i, k; emitter.constants) { 130 final switch (k.type) with (Emitter.ConstantSlot.Type) { 131 case Null: 132 constants ~= CompiledCode.Constant(ConstantType.Null, k.value); 133 break; 134 case Boolean: 135 constants ~= CompiledCode.Constant(ConstantType.Boolean, k.value); 136 break; 137 case Integer: 138 constants ~= CompiledCode.Constant(ConstantType.Integer, k.value); 139 break; 140 case Float: 141 constants ~= CompiledCode.Constant(ConstantType.Float, k.value); 142 break; 143 case String: 144 constants ~= CompiledCode.Constant(ConstantType.String, k.value); 145 break; 146 } 147 } 148 } 149 150 return result; 151 } catch (Exception error) { 152 string[] errors; 153 154 if (auto parserErrors = cast(ParserErrorsException)error) { 155 errors = parserErrors.errors; 156 } else { 157 errors ~= error.msg; 158 } 159 160 throw new CompileErrorsException(errors); 161 } 162 }