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