untested code generators for loops
[gaemu.git] / loader.d
blobfaada1faa588d27758052263e04d378184d5c1a7
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 } catch (ErrorAt e) {
59 import std.stdio;
60 writeln("ERROR at ", e.loc, ": ", e.msg);
61 writeln(typeid(e).name, "@", e.file, "(", e.line, "): ", e.msg);
62 parser.printCaret(e.loc);
63 writeln(code);
64 throw e;
65 } catch (Exception e) {
66 import std.stdio;
67 writeln(typeid(e).name, "@", e.file, "(", e.line, "): ", e.msg);
68 throw e;
70 assert(0);
74 // ////////////////////////////////////////////////////////////////////////// //
75 NodeFunc[] gmkLoadScripts (Gmk gmk, bool doScripts, bool doActions, bool warnings=true, bool checkReturns=true) {
76 NodeFunc[] funcs;
78 import std.conv : to;
80 void setupObject (GMObject obj, GMObject oparent) {
81 string parent = (oparent !is null ? oparent.name : null);
83 void parseECode (ref string evcode, string evname) {
84 import iv.strex;
85 import std.string : replace;
86 scope(exit) evcode = null;
87 evcode = evcode.replace("\r\n", "\n").replace("\r", "\n").outdentAll;
88 //while (evcode.length && evcode[0] <= ' ') evcode = evcode[1..$];
89 while (evcode.length && evcode[$-1] <= ' ') evcode = evcode[0..$-1];
90 if (evcode.length) {
91 auto fn = evcode.parseScript(obj.name~":"~evname, warnings:warnings);
92 if (!isEmpty(fn)) {
93 if (checkReturns && hasReturn(fn)) throw new Exception("event '"~evname~"' for object '"~obj.name~"' contains `return`");
94 funcs ~= fn;
99 void createEvent (GMEvent.Type evtype) {
100 import std.conv : to;
101 string evcode;
102 foreach (immutable evidx, auto ev; obj.events[evtype]) {
103 foreach (immutable aidx, auto act; ev.actions) {
104 if (act.type == act.Type.Nothing) continue; // comment
105 if (act.kind == act.Kind.act_normal) {
106 // normal action
107 if (act.type == act.Type.Function) {
108 if (act.funcname == "action_inherited") {
109 assert(parent.length);
110 evcode ~= "_action_inherited(\""~to!string(evtype)~"\", \""~parent~"\");\n";
111 continue;
113 if (act.funcname == "action_kill_object") {
114 evcode ~= "_action_kill_object();\n";
115 continue;
117 if (act.funcname == "action_execute_script") {
118 import std.conv : to;
119 if (act.argused < 1 || act.argtypes[0] != act.ArgType.t_script) assert(0, "invalid action function arguments: '"~act.funcname~"' for object '"~obj.name~"'");
120 string s = gmk.scriptByNum(to!int(act.argvals[0])).name~"(";
121 foreach (immutable idx; 1..act.argused) {
122 if (act.argtypes[idx] != act.ArgType.t_expr) assert(0, "invalid action type for execscript: "~to!string(act.argtypes[idx])~" for object '"~obj.name~"'");
123 if (idx != 1) s ~= ", ";
124 s ~= act.argvals[idx];
126 s ~= "); // action_execute_script\n";
127 evcode ~= s;
128 continue;
130 assert(0, "invalid action function: '"~act.funcname~"' for object '"~obj.name~"'");
132 assert(0, "invalid normal action type");
134 if (act.kind == act.Kind.act_code) {
135 // script
136 if (act.type == act.Type.Code) {
137 if (act.argused < 1 || act.argtypes[0] != act.ArgType.t_string) {
138 import std.conv : to;
139 assert(0, "invalid action code arguments for '"~obj.name~"': used="~to!string(act.argused)~"; kinds="~to!string(act.argtypes));
141 import std.string : format;
142 evcode ~= act.argvals[0];
143 while (evcode.length && evcode[$-1] <= ' ') evcode = evcode[0..$-1];
144 if (evcode.length > 0) evcode ~= "\n";
145 continue;
147 assert(0, "invalid code action type: "~to!string(act.type));
149 if (act.kind == act.Kind.act_var) {
150 // variable assignment
151 if (act.argused != 2 || act.argtypes[0] != act.ArgType.t_string || act.argtypes[1] != act.ArgType.t_expr) {
152 assert(0, "invalid action code arguments for '"~obj.name~"': used="~to!string(act.argused)~"; kinds="~to!string(act.argtypes));
154 evcode ~= act.argvals[0]~" = "~act.argvals[1]~"; // act_var";
155 continue;
158 assert(0, "FUUUCK: "~to!string(act.kind));
161 string baseevname = to!string(evtype);
162 if (evidx > 0) baseevname ~= to!string(evidx);
163 if (evtype == GMEvent.Type.ev_alarm) {
164 parseECode(evcode, "ev_alarm:"~to!string(ev.id));
165 //{ import std.stdio; writeln("alarm #", evidx, " for '", obj.name, "'"); }
166 } else if (evtype == GMEvent.Type.ev_step) {
167 if (ev.id == 0) {
168 // normal
169 parseECode(evcode, baseevname);
170 } else if (ev.id == 1) {
171 // begin
172 parseECode(evcode, to!string(evtype)~":begin");
173 } else if (ev.id == 2) {
174 // end
175 parseECode(evcode, to!string(evtype)~":end");
176 } else {
177 assert(0);
179 } else if (evtype == GMEvent.Type.ev_keypress || evtype == GMEvent.Type.ev_keyrelease || evtype == GMEvent.Type.ev_keyboard) {
180 if (auto keyName = cast(uint)ev.id in evKeyNames) {
181 import std.string : replace;
182 string kn = (*keyName).replace(" ", "_");
183 parseECode(evcode, to!string(evtype)~":"~kn);
184 } else {
185 parseECode(evcode, to!string(evtype)~":vcode_"~to!string(ev.id));
187 } else if (evtype == GMEvent.Type.ev_mouse) {
188 if (auto msName = cast(uint)ev.id in evMouseNames) {
189 import std.string : replace;
190 string kn = (*msName).replace(" ", "_");
191 parseECode(evcode, to!string(evtype)~":"~kn);
192 } else {
193 parseECode(evcode, to!string(evtype)~":mcode_"~to!string(ev.id));
195 } else if (evtype == GMEvent.Type.ev_collision) {
196 auto co = gmk.objByNum(ev.id);
197 if (co is null) assert(0, "no collision object for 'ev_collision' for '"~obj.name~"'");
198 parseECode(evcode, to!string(evtype)~":"~co.name);
199 } else if (evtype == GMEvent.Type.ev_other) {
200 auto nmp = cast(uint)ev.id in evOtherNames;
201 if (nmp is null) assert(0, "unknown event id "~to!string(ev.id)~" for 'ev_other' for '"~obj.name~"'");
202 import std.string : replace;
203 string nm = (*nmp).replace(" ", "_");
204 parseECode(evcode, to!string(evtype)~":"~nm);
205 } else if (evtype == GMEvent.Type.ev_draw || evtype == GMEvent.Type.ev_destroy || evtype == GMEvent.Type.ev_create) {
206 parseECode(evcode, baseevname);
207 } else {
208 /*if (evidx > 0)*/ {
209 { import std.stdio; writeln("fuck! ", evtype, " #", evidx, " for '", obj.name, "'"); }
210 if (checkReturns) assert(0);
212 parseECode(evcode, to!string(evtype)~to!string(evidx)~"_"~to!string(ev.id));
217 foreach (immutable evtype; 0..GMEvent.Type.max+1) {
218 if (evtype != GMEvent.Type.ev_create) {
219 if (obj.name == "oGamepad") continue;
221 createEvent(cast(GMEvent.Type)evtype);
225 void processChildren (string parent) {
226 auto po = gmk.objByName(parent);
227 if (po is null) assert(0, "wtf?! "~parent);
228 gmk.forEachObject((o) {
229 if (o.parentobjidx == po.idx) {
230 if (doActions) setupObject(o, po);
231 processChildren(o.name);
233 return false;
237 // objects
238 gmk.forEachObject((o) {
239 if (o.parentobjidx < 0) {
240 if (doActions) setupObject(o, null);
241 processChildren(o.name);
243 return false;
246 // scripts
247 gmk.forEachScript((sc) {
248 assert(sc.name.length);
249 if (doScripts) {
250 NodeFunc fn = sc.code.parseScript(sc.name, warnings:warnings);
251 assert(fn.ebody !is null);
252 funcs ~= fn;
254 return false;
257 return funcs;