one small optimization worth alot!
[gaemu.git] / loader.d
blob69da43f742ac3eb530d487189f287971e3ce76d2
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) res ~= parser.parseFunction();
26 } else {
27 string scname = filename.baseName(".gml");
28 res ~= parser.parseFunctionBody(scname);
30 assert(parser.lex.empty);
31 } catch (ErrorAt e) {
32 import std.stdio;
33 writeln("ERROR at ", e.loc, ": ", e.msg);
34 writeln(typeid(e).name, "@", e.file, "(", e.line, "): ", e.msg);
35 assert(0);
36 } catch (Exception e) {
37 import std.stdio;
38 writeln(typeid(e).name, "@", e.file, "(", e.line, "): ", e.msg);
39 assert(0);
41 return res;
45 // ////////////////////////////////////////////////////////////////////////// //
46 NodeFunc parseScript (string code, string scname, bool warnings=true) {
47 auto parser = new Parser(code, scname);
48 parser.warnings = warnings;
49 try {
50 return parser.parseFunctionBody(scname);
51 } catch (ErrorAt e) {
52 import std.stdio;
53 writeln("ERROR at ", e.loc, ": ", e.msg);
54 writeln(typeid(e).name, "@", e.file, "(", e.line, "): ", e.msg);
55 parser.printCaret(e.loc);
56 writeln(code);
57 throw e;
58 } catch (Exception e) {
59 import std.stdio;
60 writeln(typeid(e).name, "@", e.file, "(", e.line, "): ", e.msg);
61 throw e;
63 assert(0);
67 // ////////////////////////////////////////////////////////////////////////// //
68 NodeFunc[] gmkLoadScripts (Gmk gmk, bool doScripts, bool doActions, bool warnings=true, bool checkReturns=true) {
69 NodeFunc[] funcs;
71 import std.conv : to;
73 void setupObject (GMObject obj, GMObject oparent) {
74 string parent = (oparent !is null ? oparent.name : null);
76 void parseECode (ref string evcode, string evname) {
77 import iv.strex;
78 import std.string : replace;
79 scope(exit) evcode = null;
80 evcode = evcode.replace("\r\n", "\n").replace("\r", "\n").outdentAll;
81 //while (evcode.length && evcode[0] <= ' ') evcode = evcode[1..$];
82 while (evcode.length && evcode[$-1] <= ' ') evcode = evcode[0..$-1];
83 if (evcode.length) {
84 auto fn = evcode.parseScript(obj.name~":"~evname, warnings:warnings);
85 if (!isEmpty(fn)) {
86 if (checkReturns && hasReturn(fn)) throw new Exception("event '"~evname~"' for object '"~obj.name~"' contains `return`");
87 funcs ~= fn;
92 void createEvent (GMEvent.Type evtype) {
93 import std.conv : to;
94 string evcode;
95 foreach (immutable evidx, auto ev; obj.events[evtype]) {
96 foreach (immutable aidx, auto act; ev.actions) {
97 if (act.type == act.Type.Nothing) continue; // comment
98 if (act.kind == act.Kind.act_normal) {
99 // normal action
100 if (act.type == act.Type.Function) {
101 if (act.funcname == "action_inherited") {
102 assert(parent.length);
103 evcode ~= "_action_inherited(\""~to!string(evtype)~"\", \""~parent~"\");\n";
104 continue;
106 if (act.funcname == "action_kill_object") {
107 evcode ~= "_action_kill_object();\n";
108 continue;
110 if (act.funcname == "action_execute_script") {
111 import std.conv : to;
112 if (act.argused < 1 || act.argtypes[0] != act.ArgType.t_script) assert(0, "invalid action function arguments: '"~act.funcname~"' for object '"~obj.name~"'");
113 string s = gmk.scriptByNum(to!int(act.argvals[0])).name~"(";
114 foreach (immutable idx; 1..act.argused) {
115 if (act.argtypes[idx] != act.ArgType.t_expr) assert(0, "invalid action type for execscript: "~to!string(act.argtypes[idx])~" for object '"~obj.name~"'");
116 if (idx != 1) s ~= ", ";
117 s ~= act.argvals[idx];
119 s ~= "); // action_execute_script\n";
120 evcode ~= s;
121 continue;
123 assert(0, "invalid action function: '"~act.funcname~"' for object '"~obj.name~"'");
125 assert(0, "invalid normal action type");
127 if (act.kind == act.Kind.act_code) {
128 // script
129 if (act.type == act.Type.Code) {
130 if (act.argused < 1 || act.argtypes[0] != act.ArgType.t_string) {
131 import std.conv : to;
132 assert(0, "invalid action code arguments for '"~obj.name~"': used="~to!string(act.argused)~"; kinds="~to!string(act.argtypes));
134 import std.string : format;
135 evcode ~= act.argvals[0];
136 while (evcode.length && evcode[$-1] <= ' ') evcode = evcode[0..$-1];
137 if (evcode.length > 0) evcode ~= "\n";
138 continue;
140 assert(0, "invalid code action type: "~to!string(act.type));
142 if (act.kind == act.Kind.act_var) {
143 // variable assignment
144 if (act.argused != 2 || act.argtypes[0] != act.ArgType.t_string || act.argtypes[1] != act.ArgType.t_expr) {
145 assert(0, "invalid action code arguments for '"~obj.name~"': used="~to!string(act.argused)~"; kinds="~to!string(act.argtypes));
147 evcode ~= act.argvals[0]~" = "~act.argvals[1]~"; // act_var";
148 continue;
151 assert(0, "FUUUCK: "~to!string(act.kind));
154 string baseevname = to!string(evtype);
155 if (evidx > 0) baseevname ~= to!string(evidx);
156 if (evtype == GMEvent.Type.ev_alarm) {
157 parseECode(evcode, "ev_alarm:"~to!string(ev.id));
158 //{ import std.stdio; writeln("alarm #", evidx, " for '", obj.name, "'"); }
159 } else if (evtype == GMEvent.Type.ev_step) {
160 if (ev.id == 0) {
161 // normal
162 parseECode(evcode, baseevname);
163 } else if (ev.id == 1) {
164 // begin
165 parseECode(evcode, to!string(evtype)~":begin");
166 } else if (ev.id == 2) {
167 // end
168 parseECode(evcode, to!string(evtype)~":end");
169 } else {
170 assert(0);
172 } else if (evtype == GMEvent.Type.ev_keypress || evtype == GMEvent.Type.ev_keyrelease || evtype == GMEvent.Type.ev_keyboard) {
173 if (auto keyName = cast(uint)ev.id in evKeyNames) {
174 import std.string : replace;
175 string kn = (*keyName).replace(" ", "_");
176 parseECode(evcode, to!string(evtype)~":"~kn);
177 } else {
178 parseECode(evcode, to!string(evtype)~":vcode_"~to!string(ev.id));
180 } else if (evtype == GMEvent.Type.ev_mouse) {
181 if (auto msName = cast(uint)ev.id in evMouseNames) {
182 import std.string : replace;
183 string kn = (*msName).replace(" ", "_");
184 parseECode(evcode, to!string(evtype)~":"~kn);
185 } else {
186 parseECode(evcode, to!string(evtype)~":mcode_"~to!string(ev.id));
188 } else if (evtype == GMEvent.Type.ev_collision) {
189 auto co = gmk.objByNum(ev.id);
190 if (co is null) assert(0, "no collision object for 'ev_collision' for '"~obj.name~"'");
191 parseECode(evcode, to!string(evtype)~":"~co.name);
192 } else if (evtype == GMEvent.Type.ev_other) {
193 auto nmp = cast(uint)ev.id in evOtherNames;
194 if (nmp is null) assert(0, "unknown event id "~to!string(ev.id)~" for 'ev_other' for '"~obj.name~"'");
195 import std.string : replace;
196 string nm = (*nmp).replace(" ", "_");
197 parseECode(evcode, to!string(evtype)~":"~nm);
198 } else if (evtype == GMEvent.Type.ev_draw || evtype == GMEvent.Type.ev_destroy || evtype == GMEvent.Type.ev_create) {
199 parseECode(evcode, baseevname);
200 } else {
201 /*if (evidx > 0)*/ {
202 { import std.stdio; writeln("fuck! ", evtype, " #", evidx, " for '", obj.name, "'"); }
203 if (checkReturns) assert(0);
205 parseECode(evcode, to!string(evtype)~to!string(evidx)~"_"~to!string(ev.id));
210 foreach (immutable evtype; 0..GMEvent.Type.max+1) {
211 if (evtype != GMEvent.Type.ev_create) {
212 if (obj.name == "oGamepad") continue;
214 createEvent(cast(GMEvent.Type)evtype);
218 void processChildren (string parent) {
219 auto po = gmk.objByName(parent);
220 if (po is null) assert(0, "wtf?! "~parent);
221 gmk.forEachObject((o) {
222 if (o.parentobjidx == po.idx) {
223 if (doActions) setupObject(o, po);
224 processChildren(o.name);
226 return false;
230 // objects
231 gmk.forEachObject((o) {
232 if (o.parentobjidx < 0) {
233 if (doActions) setupObject(o, null);
234 processChildren(o.name);
236 return false;
239 // scripts
240 gmk.forEachScript((sc) {
241 assert(sc.name.length);
242 if (doScripts) {
243 NodeFunc fn = sc.code.parseScript(sc.name, warnings:warnings);
244 assert(fn.ebody !is null);
245 funcs ~= fn;
247 return false;
250 return funcs;