switched to GPLv3 ONLY, because i don't trust FSF anymore
[gaemu.git] / gaem / parser / ast.d
blobe89d9dd91833261838319adb4d2065771429e202
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, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module gaem.parser.ast is aliced;
19 import gaem.parser.lexer;
20 import gaem.parser.tokens;
21 import gaem.parser.utils;
24 // ////////////////////////////////////////////////////////////////////////// //
25 auto selectNode(RetType=void, A...) (Node node, scope A args) => selector!RetType(node, args);
28 // ////////////////////////////////////////////////////////////////////////// //
29 abstract class Node {
30 protected import std.string : stripLeft, stripRight;
32 Loc loc;
33 bool textual; // used for unary and binary nodes where, for example, "and" is used instead of "&&"
34 uint pcs, pce; // for codegen: first and last compiled instruction; pce points after last instr
36 this () {}
37 this (Node n) { if (n !is null) loc = n.loc; }
38 this (Loc aloc) { loc = aloc; }
40 string toStringInd (int indent) const => indentStr(indent)~"<invalid node:"~typeof(this).stringof~">";
42 override string toString () const => toStringInd(0);
44 // add outer "()" if there is none
45 string asCondStr () const => (cast(NodeUnaryParens)this ? this.toString : "("~this.toString~")");
47 static string indentStr (int indent) {
48 if (indent < 1) return null;
49 auto s = new char[](indent);
50 s[] = ' ';
51 return cast(string)s; // it is safe here
56 // ////////////////////////////////////////////////////////////////////////// //
57 abstract class NodeLiteral : Node {
58 this () {}
59 this (Loc aloc) { super(aloc); }
62 class NodeLiteralStr : NodeLiteral {
63 string val;
65 this () {}
66 this (Loc aloc, string aval) { val = aval; super(aloc); }
68 override string toStringInd (int indent) const {
69 import std.array : appender;
70 import std.format : formatElement, FormatSpec;
71 auto res = appender!string();
72 res.put(indentStr(indent));
73 FormatSpec!char fspc; // defaults to 's'
74 formatElement(res, val, fspc);
75 return res.data;
79 class NodeLiteralNum : NodeLiteral {
80 float val;
82 this () {}
83 this (Loc aloc, float aval) { val = aval; super(aloc); }
85 override string toStringInd (int indent) const { import std.string : format; return "%s%s".format(indentStr(indent), val); }
89 // ////////////////////////////////////////////////////////////////////////// //
90 abstract class NodeExpr : Node {
91 string name; // various purposes
93 this () {}
94 this (string aname) { name = aname; super(); }
95 this (Node ae, string aname) { name = aname; super(ae); }
96 this (Loc aloc, string aname) { name = aname; super(aloc); }
100 // ////////////////////////////////////////////////////////////////////////// //
101 abstract class NodeUnary : NodeExpr {
102 Node e;
104 this () {}
105 this (Node ae, string aname) { e = ae; super(ae, aname); }
106 this (Loc aloc, Node ae, string aname) { e = ae; super(aloc, aname); }
108 override string toStringInd (int indent) const => indentStr(indent)~name~e.toString;
112 // ////////////////////////////////////////////////////////////////////////// //
113 // "()" expression
114 class NodeUnaryParens : NodeUnary {
115 this () {}
116 this (Node ae) { super(ae, "()"); }
117 this (Loc aloc, Node ae) { super(aloc, ae, "()"); }
119 override string toStringInd (int indent) const => indentStr(indent)~"("~e.toString~")";
123 // ////////////////////////////////////////////////////////////////////////// //
124 private enum UnaryOpMixin(string name, string opstr) =
125 "class NodeUnary"~name~" : NodeUnary {\n"~
126 " this () {}\n"~
127 " this (Node ae) { super(ae, \""~opstr~"\"); }\n"~
128 " this (Loc aloc, Node ae) { super(loc, ae, \""~opstr~"\"); }\n"~
129 "}";
131 mixin(UnaryOpMixin!("Not", "!"));
132 mixin(UnaryOpMixin!("Neg", "-"));
133 mixin(UnaryOpMixin!("BitNeg", "~"));
136 // ////////////////////////////////////////////////////////////////////////// //
137 abstract class NodeBinary : NodeExpr {
138 Node el, er;
140 this () {}
141 this (Node ael, Node aer, string aname) { el = ael; er = aer; super((ael !is null ? ael : aer), aname); }
142 this (Loc aloc, Node ael, Node aer, string aname) { el = ael; er = aer; super(aloc, aname); }
144 override string toStringInd (int indent) const {
145 if (name.length > 1 && name != "<<" && name != ">>") return indentStr(indent)~el.toString~" "~name~" "~er.toString;
146 // to correctly emit "a- -1"
147 if (name == "-") {
148 if (auto l = cast(NodeLiteralNum)er) return indentStr(indent)~el.toString~(l.val < 0 ? " " : "")~name~(l.val < 0 ? " " : "")~er.toString;
150 return indentStr(indent)~el.toString~name~er.toString;
154 abstract class NodeBinaryCmp : NodeBinary {
155 this () {}
156 this (Node ael, Node aer, string aname) { super(ael, aer, aname); }
157 this (Loc aloc, Node ael, Node aer, string aname) { super(aloc, ael, aer, aname); }
159 override string toStringInd (int indent) const => indentStr(indent)~el.toString~" "~name~" "~er.toString;
162 abstract class NodeBinaryLogic : NodeBinary {
163 this () {}
164 this (Node ael, Node aer, string aname) { super(ael, aer, aname); }
165 this (Loc aloc, Node ael, Node aer, string aname) { super(aloc, ael, aer, aname); }
167 override string toStringInd (int indent) const => indentStr(indent)~el.toString~" "~name~" "~er.toString;
170 private enum BinaryOpMixin(string name, string opstr, string base="") =
171 "class NodeBinary"~name~" : NodeBinary"~base~" {\n"~
172 " this () {}\n"~
173 " this (Node ael, Node aer) { super(ael, aer, \""~opstr~"\"); }\n"~
174 " this (Loc aloc, Node ael, Node aer) { super(aloc, ael, aer, \""~opstr~"\"); }\n"~
175 "}";
177 mixin(BinaryOpMixin!("Add", "+"));
178 mixin(BinaryOpMixin!("Sub", "-"));
179 mixin(BinaryOpMixin!("Mul", "*"));
180 mixin(BinaryOpMixin!("RDiv", "/"));
181 mixin(BinaryOpMixin!("Div", "div"));
182 mixin(BinaryOpMixin!("Mod", "mod"));
183 mixin(BinaryOpMixin!("BitOr", "|"));
184 mixin(BinaryOpMixin!("BitAnd", "&"));
185 mixin(BinaryOpMixin!("BitXor", "^"));
186 mixin(BinaryOpMixin!("LShift", "<<"));
187 mixin(BinaryOpMixin!("RShift", ">>"));
189 mixin(BinaryOpMixin!("Less", "<", "Cmp"));
190 mixin(BinaryOpMixin!("Great", ">", "Cmp"));
191 mixin(BinaryOpMixin!("LessEqu", "<=", "Cmp"));
192 mixin(BinaryOpMixin!("GreatEqu", ">=", "Cmp"));
193 mixin(BinaryOpMixin!("Equ", "==", "Cmp"));
194 mixin(BinaryOpMixin!("NotEqu", "!=", "Cmp"));
196 mixin(BinaryOpMixin!("LogOr", "||", "Logic"));
197 mixin(BinaryOpMixin!("LogAnd", "&&", "Logic"));
198 mixin(BinaryOpMixin!("LogXor", "^^", "Logic"));
200 // these nodes will never end up in AST, they are here for parser needs
201 mixin(BinaryOpMixin!("And", "and", "Logic"));
202 mixin(BinaryOpMixin!("Or", "or", "Logic"));
203 mixin(BinaryOpMixin!("Xor", "xor", "Logic"));
206 // ////////////////////////////////////////////////////////////////////////// //
207 // variable access (as lvalue and as rvalue)
208 class NodeId : NodeExpr {
209 this () {}
210 this (string aname) { super(aname); }
211 this (Loc aloc, string aname) { super(aloc, aname); }
213 override string toStringInd (int indent) const => indentStr(indent)~name;
217 // ////////////////////////////////////////////////////////////////////////// //
218 // field access (as lvalue and as rvalue)
219 class NodeDot : NodeExpr {
220 Node e; // base
222 this () {}
223 this (Node ae, string name) { e = ae; super(ae, name); }
224 this (Loc aloc, Node ae, string name) { e = ae; super(aloc, name); }
226 override string toStringInd (int indent) const => indentStr(indent)~e.toString~"."~name;
230 // ////////////////////////////////////////////////////////////////////////// //
231 // field access (as lvalue and as rvalue)
232 class NodeIndex : NodeExpr {
233 Node e; // base
234 Node ei0, ei1; // indicies, `ei1` can be `null`
236 this () {}
237 this (Node ae) { e = ae; super(ae, "index"); }
238 this (Loc aloc, Node ae) { e = ae; super(aloc, "index"); }
240 override string toStringInd (int indent) const {
241 string res = indentStr(indent)~e.toString~"["~ei0.toString;
242 if (ei1 !is null) res ~= ", "~ei1.toString;
243 return res~"]";
248 // ////////////////////////////////////////////////////////////////////////// //
249 // function call
250 class NodeFCall : NodeExpr {
251 Node fe; // function expression
252 Node[] args;
254 this () {}
255 this (Loc aloc, Node afe) { fe = afe; super(aloc, "fcall"); }
257 override string toStringInd (int indent) const {
258 string res = indentStr(indent)~fe.toString~"(";
259 foreach (immutable idx, const Node a; args) {
260 if (idx != 0) res ~= ", ";
261 res ~= a.toString;
263 return res~")";
268 // ////////////////////////////////////////////////////////////////////////// //
269 abstract class NodeStatement : Node {
270 this () {}
271 this (Node ae) { super(ae); }
272 this (Loc aloc) { super(aloc); }
276 // ////////////////////////////////////////////////////////////////////////// //
277 // local var
278 class NodeVarDecl : NodeStatement {
279 string[] names;
280 Loc[] locs; // for names
281 bool asGlobal;
283 this () {}
284 this (Loc aloc) { super(aloc); }
286 bool hasVar (const(char)[] name) {
287 foreach (string n; names) if (n == name) return true;
288 return false;
291 override string toStringInd (int indent) const {
292 string res = indentStr(indent)~(asGlobal ? "globalvar " : "var ");
293 foreach (immutable idx, string n; names) {
294 if (idx != 0) res ~= ", ";
295 res ~= n;
297 return res~";";
302 // ////////////////////////////////////////////////////////////////////////// //
303 // statement block
304 class NodeBlock : NodeStatement {
305 Node[] stats;
307 this () {}
308 this (Loc aloc) { loc = aloc; }
310 void addStatement (Node n) {
311 if (n is null) return;
312 stats ~= n;
315 override string toStringInd (int indent) const {
316 string res = "{";
317 foreach (const n; stats) res ~= "\n"~n.toStringInd(indent+2);
318 res ~= "\n"~indentStr(indent)~"}";
319 return res;
324 // ////////////////////////////////////////////////////////////////////////// //
325 class NodeStatementEmpty : NodeStatement {
326 this () {}
327 this (Loc aloc) { loc = aloc; }
329 override string toStringInd (int indent) const => indentStr(indent)~"{}";
333 // ////////////////////////////////////////////////////////////////////////// //
334 class NodeStatementAss : NodeStatement {
335 Node el, er;
336 bool expanded; // this is expanded opOpAssign
338 this () {}
339 this (Loc aloc, Node ael, Node aer, bool aexpanded=false) { super(aloc); el = ael; er = aer; expanded = aexpanded; }
341 override string toStringInd (int indent) const {
342 string res = indentStr(indent)~el.toString~" ";
343 if (expanded) {
344 if (auto x = cast(NodeBinary)er) {
345 res ~= x.name~"= "~x.er.toString;
346 } else {
347 assert(0, "wtf?!");
349 } else {
350 res ~= "= "~er.toString;
352 return res;
357 // ////////////////////////////////////////////////////////////////////////// //
358 // `expression` operator
359 class NodeStatementExpr : NodeStatement {
360 Node e; // expression
362 this () {}
363 this (Node ae) { e = ae; super(ae); }
364 this (Loc aloc, Node ae) { e = ae; super(aloc); }
366 override string toStringInd (int indent) const => e.toStringInd(indent)~";";
370 // ////////////////////////////////////////////////////////////////////////// //
371 // `return` and `exit` operators
372 class NodeReturn : NodeStatement {
373 Node e; // return expression (if any); can be `null`
375 this () {}
376 this (Node ae) { e = ae; super(ae); }
377 this (Loc aloc, Node ae=null) { e = ae; super(aloc); }
379 override string toStringInd (int indent) const => indentStr(indent)~(e !is null ? "return "~e.toString~";" : "exit;");
383 // ////////////////////////////////////////////////////////////////////////// //
384 // `with` operator
385 class NodeWith : NodeStatement {
386 Node e;
387 Node ebody;
389 this () {}
390 this (Node ae) { e = ae; super(ae); }
391 this (Loc aloc, Node ae) { e = ae; super(aloc); }
393 override string toStringInd (int indent) const => indentStr(indent)~"with "~e.asCondStr~" "~ebody.toStringInd(indent).stripLeft;
397 // ////////////////////////////////////////////////////////////////////////// //
398 // `if` operator
399 class NodeIf : NodeStatement {
400 Node ec;
401 NodeStatement et, ef;
403 this () {}
404 this (Node aec, NodeStatement aet, NodeStatement aef) { ec = aec; et = aet; ef = aef; super((aec !is null ? aec : aet ! is null ? aet : aef)); }
405 this (Loc aloc, Node aec, NodeStatement aet, NodeStatement aef) { ec = aec; et = aet; ef = aef; super(aloc); }
407 override string toStringInd (int indent) const {
408 //{ import std.stdio : stderr; stderr.writeln(loc); }
409 assert(et !is null);
410 string res = indentStr(indent)~"if "~ec.asCondStr~" "~et.toStringInd(indent).stripLeft;
411 if (ef is null) return res;
412 if (cast(NodeBlock)et || cast(NodeBlock)ef) return res~" else "~ef.toStringInd(indent).stripLeft;
413 if (cast(NodeIf)et) return res~" else "~ef.toStringInd(indent).stripLeft;
414 if (cast(NodeIf)ef) return res~"\n"~indentStr(indent)~"else "~ef.toStringInd(indent).stripLeft;
415 string st = et.toString;
416 string sf = ef.toString;
417 if (st.length+sf.length <= 68) return res~" else "~sf;
418 return res~"\n"~indentStr(indent)~"else "~ef.toStringInd(indent).stripLeft;
423 // ////////////////////////////////////////////////////////////////////////// //
424 // `break` and `continue` operators
425 abstract class NodeStatementBreakCont : NodeStatement {
426 Node ewhich; // loop/switch node
428 this () {}
429 this (Loc aloc, Node awhich) { ewhich = awhich; super(aloc); }
432 // `break` operator
433 class NodeStatementBreak : NodeStatementBreakCont {
434 this (Loc aloc, Node awhich) { super(aloc, awhich); }
436 override string toStringInd (int indent) const => indentStr(indent)~"break;";
439 // `continue` operator
440 class NodeStatementContinue : NodeStatementBreakCont {
441 this (Loc aloc, Node awhich) { super(aloc, awhich); }
443 override string toStringInd (int indent) const => indentStr(indent)~"continue;";
447 // ////////////////////////////////////////////////////////////////////////// //
448 // `for` operator
449 class NodeFor : NodeStatement {
450 Node einit, econd, enext;
451 Node ebody;
453 this () {}
454 this (Loc aloc) { super(aloc); }
456 override string toStringInd (int indent) const => indentStr(indent)~"for ("~einit.toString~"; "~econd.toString~"; "~enext.toString~") "~ebody.toStringInd(indent).stripLeft;
460 // ////////////////////////////////////////////////////////////////////////// //
461 // `while` operator
462 class NodeWhile : NodeStatement {
463 Node econd;
464 Node ebody;
466 this () {}
467 this (Loc aloc) { super(aloc); }
469 override string toStringInd (int indent) const => indentStr(indent)~"while "~econd.asCondStr~" "~ebody.toStringInd(indent).stripLeft;
473 // ////////////////////////////////////////////////////////////////////////// //
474 // `do/until` operator
475 class NodeDoUntil : NodeStatement {
476 Node econd;
477 Node ebody;
479 this () {}
480 this (Loc aloc) { super(aloc); }
482 override string toStringInd (int indent) const => indentStr(indent)~"do "~ebody.toStringInd(indent).stripLeft~" until "~econd.asCondStr~";";
486 // ////////////////////////////////////////////////////////////////////////// //
487 // `repeat` operator
488 class NodeRepeat : NodeStatement {
489 Node ecount;
490 Node ebody;
492 this () {}
493 this (Loc aloc) { super(aloc); }
495 override string toStringInd (int indent) const => indentStr(indent)~"repeat "~ecount.asCondStr~" "~ebody.toStringInd(indent).stripLeft;
499 // ////////////////////////////////////////////////////////////////////////// //
500 // `switch` operator
501 class NodeSwitch : NodeStatement {
502 static struct Case {
503 Loc loc;
504 Node e; // condition; `null` means "default"
505 NodeBlock st; // can be `null`
507 Node e; // switch expression
508 Case[] cases; // never mutate directly!
510 this () {}
511 this (Loc aloc) { super(aloc); }
513 void appendCase (Loc aloc, Node ae, NodeBlock ast) {
514 cases ~= Case(aloc, ae, ast);
517 override string toStringInd (int indent) const {
518 string res = indentStr(indent)~"switch "~e.asCondStr~" {";
519 indent += 2;
520 foreach (immutable idx, ref c; cases) {
521 if (c.e !is null) {
522 res ~= "\n"~indentStr(indent)~"case "~c.e.toString~":";
523 } else {
524 res ~= "\n"~indentStr(indent)~"default:";
526 if (c.st !is null && c.st.stats.length > 0) {
528 if (auto blk = cast(NodeBlock)c.st) {
529 import std.string : stripRight;
530 res ~= " "~c.st.toStringInd(indent).stripLeft.stripRight[1..$-1].stripLeft.stripRight;
531 } else {
532 res ~= " "~c.st.toStringInd(indent).stripLeft;
535 if (c.st.stats.length == 1) {
536 res ~= " "~c.st.toStringInd(indent).stripLeft.stripRight[1..$-1].stripLeft.stripRight;
537 } else if (c.st.stats.length == 2 && (idx == 0 || cases[idx-1].st !is null)) {
538 string stx = c.st.stats[0].toString~" "~c.st.stats[1].toString;
539 if (stx.length <= 69) {
540 res ~= " "~stx;
541 } else {
542 res ~= "\n"~indentStr(indent+2)~c.st.toStringInd(indent).stripLeft.stripRight[1..$-1].stripLeft.stripRight;
544 } else {
545 res ~= "\n"~indentStr(indent+2)~c.st.toStringInd(indent).stripLeft.stripRight[1..$-1].stripLeft.stripRight;
549 indent -= 2;
550 return res~"\n"~indentStr(indent)~"}";
555 // ////////////////////////////////////////////////////////////////////////// //
556 // function with body
557 class NodeFunc : Node {
558 import gaem.parser.parser : Parser;
560 string name;
561 NodeBlock ebody;
563 Parser pp;
565 this () {}
566 this (Loc aloc, string aname) { name = aname; super(aloc); }
568 override string toStringInd (int indent) const => indentStr(indent)~"function "~name~" "~ebody.toStringInd(indent).stripLeft;