1 /*
2  * Hunt - A high-level D Programming Language Web framework that encourages rapid development and clean, pragmatic design.
3  *
4  * Copyright (C) 2015-2019, HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.framework.view.ast.Node;
13 
14 public
15 {
16     import std.typecons : Nullable, nullable;
17     import hunt.framework.view.Lexer : Position;
18 }
19 
20 private
21 {
22     import std.meta : AliasSeq;
23 
24     import hunt.framework.view.ast.Visitor;
25 }
26 
27 
28 alias NodeTypes = AliasSeq!(
29         TemplateNode,
30         BlockNode,
31         StmtBlockNode,
32         RawNode,
33         ExprNode,
34         UnaryOpNode,
35         BinOpNode,
36         StringNode,
37         BooleanNode,
38         NilNode,
39         ListNode,
40         DictNode,
41         NumNode,
42         IdentNode,
43         IfNode,
44         ForNode,
45         SetNode,
46         AssignableNode,
47         MacroNode,
48         CallNode,
49         InlineIfNode,
50         FilterBlockNode,
51         ImportNode,
52         IncludeNode,
53         ExtendsNode,
54     );
55 
56 
57 
58 interface NodeInterface
59 {
60     void accept(VisitorInterface);
61 }
62 
63 
64 mixin template AcceptVisitor()
65 {
66     override void accept(VisitorInterface visitor)
67     {
68         visitor.visit(this);
69     }
70 }
71 
72 
73 abstract class Node : NodeInterface
74 {
75     public Position pos;
76 
77     void accept(VisitorInterface visitor) {}
78 }
79 
80 
81 class TemplateNode : Node
82 {
83     Nullable!StmtBlockNode stmt;
84     BlockNode[string] blocks;
85 
86     this(Position pos, StmtBlockNode stmt, BlockNode[string] blocks)
87     {
88         this.pos = pos;
89         this.stmt = stmt.toNullable;
90         this.blocks = blocks;
91     }
92 
93     mixin AcceptVisitor;
94 }
95 
96 
97 
98 class BlockNode : Node
99 {
100     string name;
101     Nullable!Node stmt;
102 
103     this(Position pos, string name, Node stmt)
104     {
105         this.pos = pos;
106         this.name = name;
107         this.stmt = stmt.toNullable;
108     }
109 
110     mixin AcceptVisitor;
111 }
112 
113 
114 
115 class StmtBlockNode : Node
116 {
117     Node[] children;
118 
119     this(Position pos)
120     {
121         this.pos = pos;
122     }
123 
124     mixin AcceptVisitor;
125 }
126 
127 
128 
129 class RawNode : Node
130 {
131     string raw;
132 
133     this(Position pos, string raw)
134     {
135         this.pos = pos;
136         this.raw = raw;
137     }
138 
139     mixin AcceptVisitor;
140 }
141 
142 
143 
144 class ExprNode : Node
145 {
146     Nullable!Node expr;
147 
148     this(Position pos, Node expr)
149     {
150         this.pos = pos;
151         this.expr = expr.toNullable;
152     }
153 
154     mixin AcceptVisitor;
155 }
156 
157 
158 class InlineIfNode : Node
159 {
160     Nullable!Node expr, cond, other;
161 
162     this(Position pos, Node expr, Node cond, Node other)
163     {
164         this.pos = pos;
165         this.expr = expr.toNullable;
166         this.cond = cond.toNullable;
167         this.other = other.toNullable;
168     }
169 
170     mixin AcceptVisitor;
171 }
172 
173 
174 class BinOpNode : Node
175 {
176     string op;
177     Node lhs, rhs;
178 
179     this(Position pos, string op, Node lhs, Node rhs)
180     {
181         this.pos = pos;
182         this.op = op;
183         this.lhs = lhs;
184         this.rhs = rhs;
185     }
186 
187     mixin AcceptVisitor;
188 }
189 
190 
191 class UnaryOpNode : Node
192 {
193     string op;
194     Node expr;
195 
196     this(Position pos, string op, Node expr)
197     {
198         this.pos = pos;
199         this.op = op;
200         this.expr = expr;
201     }
202 
203     mixin AcceptVisitor;
204 }
205 
206 
207 class NumNode : Node
208 {
209     enum Type
210     {
211         Integer,
212         Float,
213     }
214 
215     union Data
216     {
217         long _integer;
218         double _float;
219     }
220 
221     Data data;
222     Type type;
223 
224     this(Position pos, long num)
225     {
226         this.pos = pos;
227         data._integer = num;
228         type = Type.Integer;
229     }
230 
231     this(Position pos, double num)
232     {
233         this.pos = pos;
234         data._float = num;
235         type = Type.Float;
236     }
237 
238     mixin AcceptVisitor;
239 }
240 
241 
242 class BooleanNode : Node
243 {
244     bool boolean;
245 
246     this(Position pos, bool boolean)
247     {
248         this.pos = pos;
249         this.boolean = boolean;
250     }
251 
252     mixin AcceptVisitor;
253 }
254 
255 
256 class NilNode : Node
257 {
258     mixin AcceptVisitor;
259 }
260 
261 
262 class IdentNode : Node
263 {
264     string name;
265     Node[] subIdents;
266 
267 
268     this(Position pos, string name, Node[] subIdents)
269     {
270         this.pos = pos;
271         this.name = name;
272         this.subIdents = subIdents;
273     }
274 
275     mixin AcceptVisitor;
276 }
277 
278 
279 class AssignableNode : Node
280 {
281     string name;
282     Node[] subIdents;
283 
284 
285     this(Position pos, string name, Node[] subIdents)
286     {
287         this.pos = pos;
288         this.name = name;
289         this.subIdents = subIdents;
290     }
291 
292     mixin AcceptVisitor;
293 }
294 
295 
296 class IfNode : Node
297 {
298     Node cond, then, other;
299 
300     this(Position pos, Node cond, Node then, Node other)
301     {
302         this.pos = pos;
303         this.cond = cond;
304         this.then = then;
305         this.other = other;
306     }
307 
308     mixin AcceptVisitor;
309 }
310 
311 
312 class ForNode : Node
313 {
314     string[] keys;
315     Nullable!Node iterable;
316     Nullable!Node block;
317     Nullable!Node other;
318     Nullable!Node cond;
319     bool isRecursive;
320 
321     this(Position pos, string[] keys, Node iterable, Node block, Node other, Node cond, bool isRecursive)
322     {
323         this.pos = pos;
324         this.keys = keys;
325         this.iterable = iterable.toNullable;
326         this.block = block.toNullable;
327         this.other = other.toNullable;
328         this.cond = cond.toNullable;
329         this.isRecursive = isRecursive;
330     }
331 
332     mixin AcceptVisitor;
333 }
334 
335 
336 class StringNode : Node
337 {
338     string str;
339 
340     this(Position pos, string str)
341     {
342         this.pos = pos;
343         this.str = str;
344     }
345 
346     mixin AcceptVisitor;
347 }
348 
349 
350 class ListNode : Node
351 {
352     Node[] list;
353 
354     this(Position pos, Node[] list)
355     {
356         this.pos = pos;
357         this.list = list;
358     }
359 
360     mixin AcceptVisitor;
361 }
362 
363 
364 class DictNode : Node
365 {
366     Node[string] dict;
367 
368     this(Position pos, Node[string] dict)
369     {
370         this.pos = pos;
371         this.dict = dict;
372     }
373 
374     mixin AcceptVisitor;
375 }
376 
377 
378 class SetNode : Node
379 {
380     Node[] assigns;
381     Node expr;
382 
383     this(Position pos, Node[] assigns, Node expr)
384     {
385         this.pos = pos;
386         this.assigns = assigns;
387         this.expr = expr;
388     }
389 
390     mixin AcceptVisitor;
391 }
392 
393 
394 class MacroNode : Node
395 {
396     string name;
397     Arg[] args;
398     Nullable!Node block;
399     bool isReturn;
400 
401     this(Position pos, string name, Arg[] args, Node block, bool isReturn)
402     {
403         this.pos = pos;
404         this.name = name;
405         this.args = args;
406         this.block = block.toNullable;
407         this.isReturn = isReturn;
408     }
409 
410     mixin AcceptVisitor;
411 }
412 
413 
414 class CallNode : Node
415 {
416     string macroName;
417     Arg[] formArgs;
418     Nullable!Node factArgs;
419     Nullable!Node block;
420 
421     this(Position pos, string macroName, Arg[] formArgs, Node factArgs, Node block)
422     {
423         this.pos = pos;
424         this.macroName = macroName;
425         this.formArgs = formArgs;
426         this.factArgs = factArgs.toNullable;
427         this.block = block.toNullable;
428     }
429 
430     mixin AcceptVisitor;
431 }
432 
433 
434 class FilterBlockNode : Node
435 {
436     string filterName;
437     Nullable!Node args;
438     Nullable!Node block;
439 
440     this(Position pos, string filterName, Node args, Node block)
441     {
442         this.pos = pos;
443         this.filterName = filterName;
444         this.args = args.toNullable;
445         this.block = block.toNullable;
446     }
447 
448     mixin AcceptVisitor;
449 }
450 
451 
452 
453 class ImportNode : Node
454 {
455     struct Rename
456     {
457         string was, become;
458     }
459 
460     string fileName;
461     Rename[] macrosNames;
462     Nullable!TemplateNode tmplBlock;
463     bool withContext;
464 
465     this(Position pos, string fileName, Rename[] macrosNames, TemplateNode tmplBlock, bool withContext)
466     {
467         this.pos = pos;
468         this.fileName = fileName;
469         this.macrosNames = macrosNames;
470         this.tmplBlock = tmplBlock.toNullable;
471         this.withContext = withContext;
472     }
473 
474     mixin AcceptVisitor;
475 }
476 
477 
478 
479 class IncludeNode : Node
480 {
481     string fileName;
482     Nullable!TemplateNode tmplBlock;
483     bool withContext;
484 
485     this(Position pos, string fileName, TemplateNode tmplBlock, bool withContext)
486     {
487         this.pos = pos;
488         this.fileName = fileName;
489         this.tmplBlock = tmplBlock.toNullable;
490         this.withContext = withContext;
491     }
492 
493     mixin AcceptVisitor;
494 }
495 
496 
497 
498 class ExtendsNode : Node
499 {
500     string fileName;
501     Nullable!TemplateNode tmplBlock;
502 
503     this(Position pos, string fileName, TemplateNode tmplBlock)
504     {
505         this.pos = pos;
506         this.fileName = fileName;
507         this.tmplBlock = tmplBlock.toNullable;
508     }
509 
510     mixin AcceptVisitor;
511 }
512 
513 
514 
515 struct Arg
516 {
517     string name;
518     Nullable!Node defaultExpr;
519 
520     this(string name, Node def)
521     {
522         this.name = name;
523         this.defaultExpr = def.toNullable;
524     }
525 }
526 
527 
528 
529 auto toNullable(T)(T val)
530     if (is(T == class))
531 {
532     if (val is null)
533         return Nullable!T.init;
534     else
535         return Nullable!T(val);
536 }