events renaming
[gaemu.git] / gmlparser / ast.d
blobb8c75e536313b06a32ee252f897ac0137b5ed5b8
1 /* GML parser
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 module gmlparser.ast is aliced;
20 import gmlparser.lexer;
21 import gmlparser.tokens;
22 import gmlparser.utils;
25 // ////////////////////////////////////////////////////////////////////////// //
26 auto selectNode(RetType=void, A...) (Node node, scope A args) => selector!RetType(node, args);
29 // ////////////////////////////////////////////////////////////////////////// //
30 private string killEB (string r) {
31 if (r.length < 2 || r[0] != '(' || r[$-1] != ')') return r;
32 int depth = 1;
33 usize pos = 1;
34 while (pos < r.length-1) {
35 if (r.ptr[pos] == '(') {
36 ++depth;
37 } else if (r.ptr[pos] == ')') {
38 if (--depth == 0) return r;
40 ++pos;
42 return r[1..$-1];
46 // ////////////////////////////////////////////////////////////////////////// //
47 class Node {
48 enum DontVisitMe; // mark nodes that should not be visited with this
49 enum CompoundVisitor; // mark struct/class fields that should be processed by visitor with this
50 enum SkipChildren = int.min;
52 Loc loc;
53 bool textual; // used for unary and binary nodes where, for example, "and" is used instead of "&&"
55 this (Node n=null) { if (n !is null) loc = n.loc; }
56 this (Loc aloc) { loc = aloc; }
58 override string toString () const { return "<invalid node:"~typeof(this).stringof~">"; }
62 // ////////////////////////////////////////////////////////////////////////// //
63 class NodeLiteral : Node {
64 this (Node n=null) { super(n); }
65 this (Loc aloc) { super(aloc); }
68 class NodeLiteralString : NodeLiteral {
69 string val;
71 //this (Node n, string aval) { val = aval; super(n); }
72 this (Loc aloc, string aval) { val = aval; super(aloc); }
74 override string toString () const {
75 import std.array : appender;
76 import std.format : formatElement, FormatSpec;
77 auto res = appender!string();
78 FormatSpec!char fspc; // defaults to 's'
79 formatElement(res, val, fspc);
80 return res.data;
84 class NodeLiteralNum : NodeLiteral {
85 float val;
87 //this (float aval, Node n=null) { val = aval; super(n); }
88 this (Loc aloc, float aval) { val = aval; super(aloc); }
90 override string toString () const { import std.string : format; return "%s".format(val); }
94 // ////////////////////////////////////////////////////////////////////////// //
95 class NodeExpr : Node {
96 string name;
98 this (string aname) { name = aname; super(); }
99 this (Node ae, string aname) { name = aname; super(ae); }
100 this (Loc aloc, string aname) { name = aname; super(aloc); }
101 this (Node ae, Loc aloc, string aname) { name = aname; super(aloc); }
105 // ////////////////////////////////////////////////////////////////////////// //
106 class NodeUnary : NodeExpr {
107 Node e;
109 this (Node ae, string aname) { e = ae; super(ae, aname); }
110 this (Node ae, Loc aloc, string aname) { e = ae; super(ae, aloc, aname); }
112 override string toString () const { return name~e.toString; }
115 private enum UnaryOpMixin(string name, string opstr) =
116 "class NodeUnary"~name~" : NodeUnary {\n"~
117 " this (Node ae) { super(ae, \""~opstr~"\"); }\n"~
118 " this (Node ae, Loc aloc) { super(ae, loc, \""~opstr~"\"); }\n"~
119 "}";
121 mixin(UnaryOpMixin!("Not", "!"));
122 mixin(UnaryOpMixin!("Neg", "-"));
123 mixin(UnaryOpMixin!("BitNeg", "~"));
126 // ////////////////////////////////////////////////////////////////////////// //
127 class NodeBinary : NodeExpr {
128 Node el, er;
130 this (Node ael, Node aer, string aname) { el = ael; er = aer; super(ael, aname); }
131 this (Node ael, Node aer, Loc aloc, string aname) { el = ael; er = aer; super(ael, aloc, aname); }
133 override string toString () const {
134 if (name == "=") return el.toString~" = "~killEB(er.toString);
135 string spc = " ";
136 switch (name) {
137 case "+":
138 case "-":
139 case "*":
140 case "/":
141 case "|":
142 case "&":
143 case "^":
144 spc = "";
145 break;
146 default:
148 return "("~el.toString~spc~name~spc~er.toString~")";
152 private enum BinaryOpMixin(string name, string opstr) =
153 "class NodeBinary"~name~" : NodeBinary {\n"~
154 " this (Node ael, Node aer) { super(ael, aer, \""~opstr~"\"); }\n"~
155 " this (Node ael, Node aer, Loc aloc) { super(ael, aer, aloc, \""~opstr~"\"); }\n"~
156 "}";
158 mixin(BinaryOpMixin!("Add", "+"));
159 mixin(BinaryOpMixin!("Sub", "-"));
160 mixin(BinaryOpMixin!("Mul", "*"));
161 mixin(BinaryOpMixin!("RDiv", "/"));
162 mixin(BinaryOpMixin!("Div", "div"));
163 mixin(BinaryOpMixin!("Mod", "mod"));
164 mixin(BinaryOpMixin!("BitOr", "|"));
165 mixin(BinaryOpMixin!("BitAnd", "&"));
166 mixin(BinaryOpMixin!("BitXor", "^"));
167 mixin(BinaryOpMixin!("LShift", "<<"));
168 mixin(BinaryOpMixin!("RShift", ">>"));
170 mixin(BinaryOpMixin!("Less", "<"));
171 mixin(BinaryOpMixin!("Great", ">"));
172 mixin(BinaryOpMixin!("LessEqu", "<="));
173 mixin(BinaryOpMixin!("GreatEqu", ">="));
174 mixin(BinaryOpMixin!("Equ", "=="));
175 mixin(BinaryOpMixin!("NotEqu", "!="));
177 mixin(BinaryOpMixin!("LogOr", "||"));
178 mixin(BinaryOpMixin!("LogAnd", "&&"));
179 mixin(BinaryOpMixin!("LogXor", "^^"));
181 mixin(BinaryOpMixin!("Ass", "=")); // assign ;-)
183 // these nodes will never end up in AST, it's for parser
184 mixin(BinaryOpMixin!("And", "and"));
185 mixin(BinaryOpMixin!("Or", "or"));
186 mixin(BinaryOpMixin!("Xor", "xor"));
189 // ////////////////////////////////////////////////////////////////////////// //
190 // variable access (as lvalue and as rvalue)
191 class NodeId : NodeExpr {
192 //string name; // for semantic
194 this (string aname) { super(aname); }
195 this (Loc aloc, string aname) { super(aloc, aname); }
197 override string toString () const { return name; }
201 // ////////////////////////////////////////////////////////////////////////// //
202 // field access (as lvalue and as rvalue)
203 class NodeDot : NodeExpr {
204 Node e; // base
206 this (Node ae, string name) { e = ae; super(ae, name); }
207 this (Node ae, Loc aloc, string name) { e = ae; super(ae, aloc, name); }
209 override string toString () const {
210 if (cast(NodeId)e) return e.toString~"."~name;
211 return "("~e.toString~")."~name;
216 // ////////////////////////////////////////////////////////////////////////// //
217 // field access (as lvalue and as rvalue)
218 class NodeIndex : NodeExpr {
219 Node e; // base
220 Node ei0, ei1; // indicies, `ei1` can be `null`
222 this (Node ae) { e = ae; super(ae, "index"); }
223 this (Node ae, Loc aloc) { e = ae; super(ae, aloc, "index"); }
225 override string toString () const {
226 string res;
227 if (cast(NodeId)e) res = e.toString; else res = "("~e.toString~")";
228 res ~= "["~ei0.toString;
229 if (ei1 !is null) res ~= ", "~ei1.toString;
230 return res~"]";
235 // ////////////////////////////////////////////////////////////////////////// //
236 // function call
237 class NodeFCall : NodeExpr {
238 Node fe; // function expression
239 Node[] args;
241 //this (Loc aloc, string aname) { fe = new NodeId(aname, aloc); super(aloc); }
242 this (Loc aloc, Node afe) { fe = afe; super(aloc, "fcall"); }
244 override string toString () const {
245 string res = fe.toString~"(";
246 foreach (immutable idx, const Node a; args) {
247 if (idx != 0) res ~= ", ";
248 res ~= killEB(a.toString);
250 return res~")";
255 // ////////////////////////////////////////////////////////////////////////// //
256 class NodeStatement : Node {
257 this () { super(); }
258 this (Node ae) { super(ae); }
259 this (Loc aloc) { super(aloc); }
263 // ////////////////////////////////////////////////////////////////////////// //
264 // local var
265 class NodeVarDecl : NodeStatement {
266 string[] names;
267 bool asGlobal;
269 this (Loc aloc) { super(aloc); }
271 bool hasVar (const(char)[] name) {
272 foreach (string n; names) if (n == name) return true;
273 return false;
276 override string toString () const {
277 string res = (asGlobal ? "globalvar " : "var ");
278 foreach (immutable idx, string n; names) {
279 if (idx != 0) res ~= ", ";
280 res ~= n;
282 return res~";";
287 // ////////////////////////////////////////////////////////////////////////// //
288 // statement block
289 class NodeBlock : NodeStatement {
290 Node[] stats;
292 this () {}
293 this (Loc aloc) { loc = aloc; }
295 void addStatement (Node n) {
296 if (n is null) return;
297 stats ~= n;
300 override string toString () const {
301 string res = "{";
302 foreach (const n; stats) res ~= "\n"~killEB(n.toString);
303 res ~= "\n}";
304 return res;
309 // ////////////////////////////////////////////////////////////////////////// //
310 class NodeStatementEmpty : NodeStatement {
311 this () {}
312 this (Loc aloc) { loc = aloc; }
314 override string toString () const { return "{}"; }
318 // ////////////////////////////////////////////////////////////////////////// //
319 // `expression` operator
320 class NodeStatementExpr : NodeStatement {
321 Node e; // expression
323 this (Node ae) { e = ae; super(ae); if (ae !is null) loc = ae.loc; }
324 this (Node ae, Loc aloc) { e = ae; loc = aloc; }
326 override string toString () const {
327 return killEB(e.toString)~";";
332 // ////////////////////////////////////////////////////////////////////////// //
333 // `return` and `exit` operators
334 class NodeReturn : NodeStatement {
335 Node e; // return expression (if any); can be `null`
337 this (Node ae) { e = ae; if (ae !is null) loc = ae.loc; }
338 this (Node ae, Loc aloc) { e = ae; loc = aloc; }
340 override string toString () const { return (e !is null ? "return "~e.toString~";" : "exit;"); }
344 // ////////////////////////////////////////////////////////////////////////// //
345 // `with` operator
346 class NodeWith : NodeStatement {
347 Node e;
348 Node ebody;
350 this (Node ae) { e = ae; if (ae !is null) loc = ae.loc; }
351 this (Node ae, Loc aloc) { e = ae; loc = aloc; }
353 override string toString () const { return "with ("~killEB(e.toString)~") "~ebody.toString; }
357 // ////////////////////////////////////////////////////////////////////////// //
358 // `with_object` operator
359 class NodeWithObject : NodeStatement {
360 Node e;
361 Node ebody;
363 this (Node ae) { e = ae; if (ae !is null) loc = ae.loc; }
364 this (Node ae, Loc aloc) { e = ae; loc = aloc; }
366 override string toString () const { return "with_object ("~killEB(e.toString)~") "~ebody.toString; }
370 // ////////////////////////////////////////////////////////////////////////// //
371 // `if` operator
372 class NodeIf : NodeStatement {
373 Node ec, et, ef;
375 this (Node aec, Node aet, Node aef) { ec = aec; et = aet; ef = aef; super(aec); }
376 this (Node aec, Node aet, Node aef, Loc aloc) { ec = aec; et = aet; ef = aef; loc = aloc; }
378 override string toString () const {
379 return "if ("~killEB(ec.toString)~") "~et.toString~(ef !is null && !cast(NodeStatementEmpty)ef ? " else "~ef.toString : "");
384 // ////////////////////////////////////////////////////////////////////////// //
385 // `break` and `continue` operators
386 class NodeStatementBreakCont : NodeStatement {
387 Node ewhich; // loop/switch node
389 this (Loc aloc, Node awhich) { ewhich = awhich; super(aloc); }
392 // `break` operator
393 class NodeStatementBreak : NodeStatementBreakCont {
394 this (Loc aloc, Node awhich) { super(aloc, awhich); }
396 override string toString () const { return "break;"; }
399 // `continue` operator
400 class NodeStatementContinue : NodeStatementBreakCont {
401 this (Loc aloc, Node awhich) { super(aloc, awhich); }
403 override string toString () const { return "continue;"; }
407 // ////////////////////////////////////////////////////////////////////////// //
408 // `for` operator
409 class NodeFor : NodeStatement {
410 Node einit, econd, enext;
411 Node ebody;
413 this () {}
414 this (Loc aloc) { loc = aloc; }
416 override string toString () const {
417 if (cast(NodeBlock)ebody) {
418 return "for ("~killEB(einit.toString)~"; "~killEB(econd.toString)~"; "~killEB(enext.toString)~") "~killEB(ebody.toString);
419 } else {
420 return "for ("~killEB(einit.toString)~"; "~killEB(econd.toString)~"; "~killEB(enext.toString)~") {\n"~killEB(ebody.toString)~"\n}";
426 // ////////////////////////////////////////////////////////////////////////// //
427 // `while` operator
428 class NodeWhile : NodeStatement {
429 Node econd;
430 Node ebody;
432 this () {}
433 this (Loc aloc) { loc = aloc; }
435 override string toString () const {
436 if (cast(NodeBlock)ebody) {
437 return "while ("~killEB(econd.toString)~" "~killEB(ebody.toString);
438 } else {
439 return "while ("~killEB(econd.toString)~" {\n"~ebody.toString~"\n}";
445 // ////////////////////////////////////////////////////////////////////////// //
446 // `do/until` operator
447 class NodeDoUntil : NodeStatement {
448 Node econd;
449 Node ebody;
451 this () {}
452 this (Loc aloc) { loc = aloc; }
454 override string toString () const {
455 if (cast(NodeBlock)ebody) {
456 return "do "~ebody.toString~"\n while ("~killEB(econd.toString)~");";
457 } else {
458 return "do {\n"~killEB(ebody.toString)~"\n} while ("~killEB(econd.toString)~");";
464 // ////////////////////////////////////////////////////////////////////////// //
465 // `repeat` operator
466 class NodeRepeat : NodeStatement {
467 Node ecount;
468 Node ebody;
470 this () {}
471 this (Loc aloc) { loc = aloc; }
473 override string toString () const {
474 if (cast(NodeBlock)ebody) {
475 return "repeat("~killEB(ecount.toString)~") "~ebody.toString;
476 } else {
477 return "repeat("~killEB(ecount.toString)~") {\n"~killEB(ebody.toString)~"\n}";
483 // ////////////////////////////////////////////////////////////////////////// //
484 // `switch` operator
485 class NodeSwitch : NodeStatement {
486 static struct Case {
487 Node e; // condition; `null` means "default"
488 Node st; // can be `null`
490 Node e; // switch expression
491 Case[] cases; // never mutate directly!
493 this () {}
494 this (Loc aloc) { loc = aloc; }
496 void appendCase (Node ae, Node ast) {
497 if (ae is null) {
498 foreach (ref cc; cases) {
499 if (cc.e is null) throw new ErrorAt(loc, "duplicate `default`");
502 cases ~= Case(ae, ast);
505 override string toString () const {
506 string res = "switch ("~killEB(e.toString)~") {";
507 foreach (ref c; cases) {
508 if (c.e !is null) {
509 res ~= "\ncase "~killEB(c.e.toString)~":";
510 } else {
511 res ~= "\ndefault:";
513 res ~= (c.st !is null ? " "~killEB(c.st.toString) : "");
515 return res~"\n}";
520 // ////////////////////////////////////////////////////////////////////////// //
521 // function with body
522 class NodeFunc : Node {
523 string name;
524 NodeBlock ebody;
526 this (string aname, Loc aloc) { name = aname; loc = aloc; }
528 override string toString () const {
529 string res = "function "~name~" ";
530 if (cast(NodeBlock)ebody) {
531 res ~= ebody.toString;
532 } else {
533 res ~= "{\n"~killEB(ebody.toString)~"\n}";
535 return res;