code cleanup
[gaemu.git] / checker.d
blob415f0c31f8c4c8b469be04c03d4997e818b2ba43
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~"'");
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]));
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~"'");
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 {
170 if (evidx > 0) {
171 { import std.stdio; writeln("fuck! ", evtype, " #", evidx, " for '", obj.name, "'"); }
172 assert(0);
174 parseECode(evcode, to!string(evtype));
179 foreach (immutable evtype; 0..GMEvent.Type.max+1) {
180 createEvent(cast(GMEvent.Type)evtype);
182 //if (obj.name != "oGamepad") createEvent(GMEvent.Type.ev_step);
185 void processChildren (string parent) {
186 auto po = gmk.objByName(parent);
187 if (po is null) assert(0, "wtf?! "~parent);
188 gmk.forEachObject((o) {
189 if (o.parentobjidx == po.idx) {
190 setupObject(o, po);
191 processChildren(o.name);
193 return false;
197 // objects
198 gmk.forEachObject((o) {
199 if (o.parentobjidx < 0) {
200 setupObject(o, null);
201 processChildren(o.name);
203 return false;
206 // scripts
207 gmk.forEachScript((sc) {
208 assert(sc.name.length);
209 NodeFunc fn = sc.code.parseScript(sc.name);
210 assert(fn.ebody !is null);
211 funcs ~= fn;
212 return false;
215 return funcs;
219 // ////////////////////////////////////////////////////////////////////////// //
220 void main (string[] args) {
221 NodeFunc[] funcs;
223 bool dumpFileNames = false;
224 bool styleWarnings = false;
226 bool nomore = false;
227 string[] scargs;
228 foreach (string fname; args[1..$]) {
229 import std.file;
230 import std.path;
231 if (nomore) {
232 scargs ~= fname;
233 } else {
234 if (fname.length == 0) continue;
235 if (fname == "--") { nomore = true; continue; }
236 if (fname == "-d") { dumpFileNames = true; continue; }
237 if (fname == "-w") { styleWarnings = true; continue; }
238 if (fname[0] == '@') {
239 if (fname.length < 2) assert(0, "gmk file?");
240 auto gmk = new Gmk(fname[1..$]);
241 funcs ~= gmkLoadScripts(gmk);
242 continue;
244 if (isDir(fname)) {
245 foreach (auto de; dirEntries(fname, "*.gm[lx]", SpanMode.breadth)) {
246 bool doit = true;
247 foreach (auto pt; pathSplitter(de.dirName)) {
248 if (pt.length && pt[0] == '_') { doit = false; break; }
250 if (doit) {
251 if (dumpFileNames) { import std.stdio; writeln("loading '", de.name, "'..."); }
252 funcs ~= loadScript(de.name, true);
255 } else {
256 if (dumpFileNames) { import std.stdio; writeln("loading '", fname, "'..."); }
257 funcs ~= loadScript(fname, true);
262 if (funcs.length > 1) {
263 writeln(funcs.length, " functions parsed");