ported "unused and uninited" checker back to compiler
[gaemu.git] / loader.d
blob775e4ec6f3926325a05352344102512c2d29e555
1 module loader is aliced;
3 import std.stdio;
5 import gmlparser;
6 import ungmk;
9 // ////////////////////////////////////////////////////////////////////////// //
10 NodeFunc[] loadScript (string filename, bool warnings=true) {
11 import std.algorithm : startsWith;
12 import std.file : readText;
13 import std.path : baseName, extension;
14 import std.stdio;
15 import std.string : replace;
17 auto s = readText(filename);
19 NodeFunc[] res;
20 auto parser = new Parser(s, filename);
21 parser.warnings = warnings;
22 bool asGmx = (filename.extension == ".gmx");
23 try {
24 if (asGmx) {
25 while (!parser.lex.empty) {
26 auto fn = parser.parseFunction();
27 fn.pp = parser; // store parsed source
28 res ~= fn;
30 } else {
31 string scname = filename.baseName(".gml");
32 auto fn = parser.parseFunctionBody(scname);
33 fn.pp = parser; // store parsed source
34 res ~= fn;
36 assert(parser.lex.empty);
37 } catch (ErrorAt e) {
38 import std.stdio;
39 writeln("ERROR at ", e.loc, ": ", e.msg);
40 writeln(typeid(e).name, "@", e.file, "(", e.line, "): ", e.msg);
41 assert(0);
42 } catch (Exception e) {
43 import std.stdio;
44 writeln(typeid(e).name, "@", e.file, "(", e.line, "): ", e.msg);
45 assert(0);
47 return res;
51 // ////////////////////////////////////////////////////////////////////////// //
52 NodeFunc parseScript (string code, string scname, bool warnings=true) {
53 auto parser = new Parser(code, scname);
54 parser.warnings = warnings;
55 try {
56 auto fn = parser.parseFunctionBody(scname);
57 fn.pp = parser; // store parsed source
58 return fn;
59 } catch (ErrorAt e) {
60 import std.stdio;
61 writeln("ERROR at ", e.loc, ": ", e.msg);
62 writeln(typeid(e).name, "@", e.file, "(", e.line, "): ", e.msg);
63 parser.printCaret(e.loc);
64 writeln(code);
65 throw e;
66 } catch (Exception e) {
67 import std.stdio;
68 writeln(typeid(e).name, "@", e.file, "(", e.line, "): ", e.msg);
69 throw e;
71 assert(0);
75 // ////////////////////////////////////////////////////////////////////////// //
76 NodeFunc[] gmkLoadScripts (Gmk gmk, bool doScripts, bool doActions, bool warnings=true, bool checkReturns=true) {
77 NodeFunc[] funcs;
79 import std.conv : to;
81 void setupObject (GMObject obj, GMObject oparent) {
82 string parent = (oparent !is null ? oparent.name : null);
84 void parseECode (ref string evcode, string evname) {
85 import iv.strex;
86 import std.string : replace;
87 scope(exit) evcode = null;
88 evcode = evcode.replace("\r\n", "\n").replace("\r", "\n").outdentAll;
89 //while (evcode.length && evcode[0] <= ' ') evcode = evcode[1..$];
90 while (evcode.length && evcode[$-1] <= ' ') evcode = evcode[0..$-1];
91 if (evcode.length) {
92 auto fn = evcode.parseScript(obj.name~":"~evname, warnings:warnings);
93 if (!isEmpty(fn)) {
94 if (checkReturns && hasReturn(fn)) throw new Exception("event '"~evname~"' for object '"~obj.name~"' contains `return`");
95 funcs ~= fn;
100 void createEvent (GMEvent.Type evtype) {
101 import std.conv : to;
102 string evcode;
103 foreach (immutable evidx, auto ev; obj.events[evtype]) {
104 foreach (immutable aidx, auto act; ev.actions) {
105 if (act.type == act.Type.Nothing) continue; // comment
106 if (act.kind == act.Kind.act_normal) {
107 // normal action
108 if (act.type == act.Type.Function) {
109 if (act.funcname == "action_inherited") {
110 assert(parent.length);
111 evcode ~= "_action_inherited(\""~to!string(evtype)~"\", \""~parent~"\");\n";
112 continue;
114 if (act.funcname == "action_kill_object") {
115 evcode ~= "_action_kill_object();\n";
116 continue;
118 if (act.funcname == "action_execute_script") {
119 import std.conv : to;
120 if (act.argused < 1 || act.argtypes[0] != act.ArgType.t_script) assert(0, "invalid action function arguments: '"~act.funcname~"' for object '"~obj.name~"'");
121 string s = gmk.scriptByNum(to!int(act.argvals[0])).name~"(";
122 foreach (immutable idx; 1..act.argused) {
123 if (act.argtypes[idx] != act.ArgType.t_expr) assert(0, "invalid action type for execscript: "~to!string(act.argtypes[idx])~" for object '"~obj.name~"'");
124 if (idx != 1) s ~= ", ";
125 s ~= act.argvals[idx];
127 s ~= "); // action_execute_script\n";
128 evcode ~= s;
129 continue;
131 assert(0, "invalid action function: '"~act.funcname~"' for object '"~obj.name~"'");
133 assert(0, "invalid normal action type");
135 if (act.kind == act.Kind.act_code) {
136 // script
137 if (act.type == act.Type.Code) {
138 if (act.argused < 1 || act.argtypes[0] != act.ArgType.t_string) {
139 import std.conv : to;
140 assert(0, "invalid action code arguments for '"~obj.name~"': used="~to!string(act.argused)~"; kinds="~to!string(act.argtypes));
142 import std.string : format;
143 evcode ~= act.argvals[0];
144 while (evcode.length && evcode[$-1] <= ' ') evcode = evcode[0..$-1];
145 if (evcode.length > 0) evcode ~= "\n";
146 continue;
148 assert(0, "invalid code action type: "~to!string(act.type));
150 if (act.kind == act.Kind.act_var) {
151 // variable assignment
152 if (act.argused != 2 || act.argtypes[0] != act.ArgType.t_string || act.argtypes[1] != act.ArgType.t_expr) {
153 assert(0, "invalid action code arguments for '"~obj.name~"': used="~to!string(act.argused)~"; kinds="~to!string(act.argtypes));
155 evcode ~= act.argvals[0]~" = "~act.argvals[1]~"; // act_var";
156 continue;
159 assert(0, "FUUUCK: "~to!string(act.kind));
162 string baseevname = to!string(evtype);
163 if (evidx > 0) baseevname ~= to!string(evidx);
164 if (evtype == GMEvent.Type.ev_alarm) {
165 parseECode(evcode, "ev_alarm:"~to!string(ev.id));
166 //{ import std.stdio; writeln("alarm #", evidx, " for '", obj.name, "'"); }
167 } else if (evtype == GMEvent.Type.ev_step) {
168 if (ev.id == 0) {
169 // normal
170 parseECode(evcode, baseevname);
171 } else if (ev.id == 1) {
172 // begin
173 parseECode(evcode, to!string(evtype)~":begin");
174 } else if (ev.id == 2) {
175 // end
176 parseECode(evcode, to!string(evtype)~":end");
177 } else {
178 assert(0);
180 } else if (evtype == GMEvent.Type.ev_keypress || evtype == GMEvent.Type.ev_keyrelease || evtype == GMEvent.Type.ev_keyboard) {
181 if (auto keyName = cast(uint)ev.id in evKeyNames) {
182 import std.string : replace;
183 string kn = (*keyName).replace(" ", "_");
184 parseECode(evcode, to!string(evtype)~":"~kn);
185 } else {
186 parseECode(evcode, to!string(evtype)~":vcode_"~to!string(ev.id));
188 } else if (evtype == GMEvent.Type.ev_mouse) {
189 if (auto msName = cast(uint)ev.id in evMouseNames) {
190 import std.string : replace;
191 string kn = (*msName).replace(" ", "_");
192 parseECode(evcode, to!string(evtype)~":"~kn);
193 } else {
194 parseECode(evcode, to!string(evtype)~":mcode_"~to!string(ev.id));
196 } else if (evtype == GMEvent.Type.ev_collision) {
197 auto co = gmk.objByNum(ev.id);
198 if (co is null) assert(0, "no collision object for 'ev_collision' for '"~obj.name~"'");
199 parseECode(evcode, to!string(evtype)~":"~co.name);
200 } else if (evtype == GMEvent.Type.ev_other) {
201 auto nmp = cast(uint)ev.id in evOtherNames;
202 if (nmp is null) assert(0, "unknown event id "~to!string(ev.id)~" for 'ev_other' for '"~obj.name~"'");
203 import std.string : replace;
204 string nm = (*nmp).replace(" ", "_");
205 parseECode(evcode, to!string(evtype)~":"~nm);
206 } else if (evtype == GMEvent.Type.ev_draw || evtype == GMEvent.Type.ev_destroy || evtype == GMEvent.Type.ev_create) {
207 parseECode(evcode, baseevname);
208 } else {
209 /*if (evidx > 0)*/ {
210 { import std.stdio; writeln("fuck! ", evtype, " #", evidx, " for '", obj.name, "'"); }
211 if (checkReturns) assert(0);
213 parseECode(evcode, to!string(evtype)~to!string(evidx)~"_"~to!string(ev.id));
218 foreach (immutable evtype; 0..GMEvent.Type.max+1) {
219 if (evtype != GMEvent.Type.ev_create) {
220 if (obj.name == "oGamepad") continue;
222 createEvent(cast(GMEvent.Type)evtype);
226 void processChildren (string parent) {
227 auto po = gmk.objByName(parent);
228 if (po is null) assert(0, "wtf?! "~parent);
229 gmk.forEachObject((o) {
230 if (o.parentobjidx == po.idx) {
231 if (doActions) setupObject(o, po);
232 processChildren(o.name);
234 return false;
238 // objects
239 gmk.forEachObject((o) {
240 if (o.parentobjidx < 0) {
241 if (doActions) setupObject(o, null);
242 processChildren(o.name);
244 return false;
247 // scripts
248 gmk.forEachScript((sc) {
249 assert(sc.name.length);
250 if (doScripts) {
251 NodeFunc fn = sc.code.parseScript(sc.name, warnings:warnings);
252 assert(fn.ebody !is null);
253 funcs ~= fn;
255 return false;
258 return funcs;