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 }