added vk key names
[gaemu.git] / checker.d
blobdc0e62e2511aadb5aa6e3752b8ce9421a7d390df
1 module checker 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 writeln(code);
56 throw e;
57 } catch (Exception e) {
58 import std.stdio;
59 writeln(typeid(e).name, "@", e.file, "(", e.line, "): ", e.msg);
60 throw e;
62 assert(0);
66 // ////////////////////////////////////////////////////////////////////////// //
67 NodeFunc[] gmkLoadScripts (Gmk gmk) {
68 NodeFunc[] funcs;
70 import std.conv : to;
72 void setupObject (GMObject obj, GMObject oparent) {
73 string parent = (oparent !is null ? oparent.name : null);
75 void parseECode (ref string evcode, string evname) {
76 import iv.strex;
77 import std.string : replace;
78 scope(exit) evcode = null;
79 evcode = evcode.replace("\r\n", "\n").replace("\r", "\n").outdentAll;
80 //while (evcode.length && evcode[0] <= ' ') evcode = evcode[1..$];
81 while (evcode.length && evcode[$-1] <= ' ') evcode = evcode[0..$-1];
82 if (evcode.length) {
83 auto fn = evcode.parseScript(obj.name~":"~evname);
84 if (!isEmpty(fn)) {
85 if (hasReturn(fn)) throw new Exception("event '"~evname~"' for object '"~obj.name~"' contains `return`");
86 funcs ~= fn;
91 void createEvent (GMEvent.Type evtype) {
92 import std.conv : to;
93 string evcode;
94 foreach (immutable evidx, auto ev; obj.events[evtype]) {
95 foreach (immutable aidx, auto act; ev.actions) {
96 if (act.type == act.Type.Nothing) continue; // comment
97 if (act.kind == act.Kind.act_normal) {
98 // normal action
99 if (act.type == act.Type.Function) {
100 if (act.funcname == "action_inherited") {
101 assert(parent.length);
102 evcode ~= "_action_inherited(\""~to!string(evtype)~"\", \""~parent~"\");\n";
103 continue;
105 if (act.funcname == "action_kill_object") {
106 evcode ~= "_action_kill_object();\n";
107 continue;
109 if (act.funcname == "action_execute_script") {
110 import std.conv : to;
111 if (act.argused < 1 || act.argtypes[0] != act.ArgType.t_script) assert(0, "invalid action function arguments: '"~act.funcname~"' for object '"~obj.name~"'");
112 string s = gmk.scriptByNum(to!int(act.argvals[0])).name~"(";
113 foreach (immutable idx; 1..act.argused) {
114 if (act.argtypes[idx] != act.ArgType.t_expr) assert(0, "invalid action type for execscript: "~to!string(act.argtypes[idx])~" for object '"~obj.name~"'");
115 if (idx != 1) s ~= ", ";
116 s ~= act.argvals[idx];
118 s ~= "); // action_execute_script\n";
119 evcode ~= s;
120 continue;
122 assert(0, "invalid action function: '"~act.funcname~"' for object '"~obj.name~"'");
124 assert(0, "invalid normal action type");
126 if (act.kind == act.Kind.act_code) {
127 // script
128 if (act.type == act.Type.Code) {
129 if (act.argused < 1 || act.argtypes[0] != act.ArgType.t_string) {
130 import std.conv : to;
131 assert(0, "invalid action code arguments for '"~obj.name~"': used="~to!string(act.argused)~"; kinds="~to!string(act.argtypes));
133 import std.string : format;
134 evcode ~= act.argvals[0];
135 while (evcode.length && evcode[$-1] <= ' ') evcode = evcode[0..$-1];
136 if (evcode.length > 0) evcode ~= "\n";
137 continue;
139 assert(0, "invalid code action type: "~to!string(act.type));
141 if (act.kind == act.Kind.act_var) {
142 // variable assignment
143 if (act.argused != 2 || act.argtypes[0] != act.ArgType.t_string || act.argtypes[1] != act.ArgType.t_expr) {
144 assert(0, "invalid action code arguments for '"~obj.name~"': used="~to!string(act.argused)~"; kinds="~to!string(act.argtypes));
146 evcode ~= act.argvals[0]~" = "~act.argvals[1]~"; // act_var";
147 continue;
150 assert(0, "FUUUCK: "~to!string(act.kind));
153 if (evtype == GMEvent.Type.ev_alarm) {
154 parseECode(evcode, to!string(evtype)~":"~to!string(evidx));
155 //{ import std.stdio; writeln("alarm #", evidx, " for '", obj.name, "'"); }
156 } else if (evtype == GMEvent.Type.ev_step) {
157 if (evidx == 0) {
158 // normal
159 parseECode(evcode, to!string(evtype));
160 } else if (evidx == 1) {
161 // begin
162 parseECode(evcode, to!string(evtype)~":begin");
163 } else if (evidx == 2) {
164 // end
165 parseECode(evcode, to!string(evtype)~":end");
166 } else {
167 assert(0);
169 } else if (evtype == GMEvent.Type.ev_keypress) {
170 if (auto keyName = cast(uint)evidx in evKeyNames) {
171 import std.string : replace;
172 string kn = (*keyName).replace(" ", "_");
173 parseECode(evcode, to!string(evtype)~"_"~kn);
174 } else {
175 parseECode(evcode, to!string(evtype)~"_vcode_"~to!string(evidx));
177 } else if (evtype == GMEvent.Type.ev_keyboard) {
178 parseECode(evcode, to!string(evtype)~to!string(evidx));
179 } else if (evtype == GMEvent.Type.ev_mouse) {
180 parseECode(evcode, to!string(evtype)~to!string(evidx));
181 } else if (evtype == GMEvent.Type.ev_collision) {
182 parseECode(evcode, to!string(evtype)~to!string(evidx));
183 } else if (evtype == GMEvent.Type.ev_other) {
184 parseECode(evcode, to!string(evtype)~to!string(evidx));
185 } else {
186 if (evidx > 0) {
187 { import std.stdio; writeln("fuck! ", evtype, " #", evidx, " for '", obj.name, "'"); }
188 assert(0);
190 parseECode(evcode, to!string(evtype));
195 foreach (immutable evtype; 0..GMEvent.Type.max+1) {
196 if (evtype != GMEvent.Type.ev_create) {
197 if (obj.name == "oGamepad") continue;
199 createEvent(cast(GMEvent.Type)evtype);
203 void processChildren (string parent) {
204 auto po = gmk.objByName(parent);
205 if (po is null) assert(0, "wtf?! "~parent);
206 gmk.forEachObject((o) {
207 if (o.parentobjidx == po.idx) {
208 setupObject(o, po);
209 processChildren(o.name);
211 return false;
215 // objects
216 gmk.forEachObject((o) {
217 if (o.parentobjidx < 0) {
218 setupObject(o, null);
219 processChildren(o.name);
221 return false;
224 // scripts
225 gmk.forEachScript((sc) {
226 assert(sc.name.length);
227 NodeFunc fn = sc.code.parseScript(sc.name);
228 assert(fn.ebody !is null);
229 funcs ~= fn;
230 return false;
233 return funcs;
237 // ////////////////////////////////////////////////////////////////////////// //
238 void main (string[] args) {
239 NodeFunc[] funcs;
241 bool dumpFileNames = false;
242 bool styleWarnings = false;
244 bool nomore = false;
245 string[] scargs;
246 foreach (string fname; args[1..$]) {
247 import std.file;
248 import std.path;
249 if (nomore) {
250 scargs ~= fname;
251 } else {
252 if (fname.length == 0) continue;
253 if (fname == "--") { nomore = true; continue; }
254 if (fname == "-d") { dumpFileNames = true; continue; }
255 if (fname == "-w") { styleWarnings = true; continue; }
256 if (fname[0] == '@') {
257 if (fname.length < 2) assert(0, "gmk file?");
258 auto gmk = new Gmk(fname[1..$]);
259 funcs ~= gmkLoadScripts(gmk);
260 continue;
262 if (isDir(fname)) {
263 foreach (auto de; dirEntries(fname, "*.gm[lx]", SpanMode.breadth)) {
264 bool doit = true;
265 foreach (auto pt; pathSplitter(de.dirName)) {
266 if (pt.length && pt[0] == '_') { doit = false; break; }
268 if (doit) {
269 if (dumpFileNames) { import std.stdio; writeln("loading '", de.name, "'..."); }
270 funcs ~= loadScript(de.name, true);
273 } else {
274 if (dumpFileNames) { import std.stdio; writeln("loading '", fname, "'..."); }
275 funcs ~= loadScript(fname, true);
280 if (funcs.length > 1) {
281 writeln(funcs.length, " functions parsed");