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 }