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.Printer;
13 
14 private
15 {
16     import hunt.framework.view.ast.Node;
17     import hunt.framework.view.ast.Visitor;
18 }
19 
20 
21 class NullVisitor : VisitorInterface
22 {
23     static foreach(NT; NodeTypes)
24     {
25         void visit(NT node)
26         {
27             import std.stdio: wl = writeln;
28             wl("# ", NT.stringof, " #");
29         }
30     }
31 }
32 
33 
34 class Printer : NullVisitor
35 {
36     import std.stdio: wl = writeln, w = write;
37     import std.format: fmt = format;
38 
39     uint _tab = 0;
40 
41     override void visit(StmtBlockNode node)
42     {
43         print("Statement Block:"); 
44         _tab++;
45         foreach(ch; node.children)
46         {
47             ch.accept(this);
48         }
49         _tab--;
50     }
51 
52 
53     override void visit(TemplateNode node)
54     {
55         print("Template:");
56 
57         _tab++;
58 
59         if (!node.blocks.length)
60             print("Blocks: NONE");
61         else
62         {
63             print("Blocks:");
64             _tab++;
65             foreach (key, block; node.blocks)
66                 print(key);
67             _tab--;
68         }
69 
70         print("Statements:");
71         _tab++;
72         if (!node.stmt.isNull)
73             node.stmt.get.accept(this);
74         _tab--;
75 
76         _tab--;
77     }
78 
79 
80     override void visit(BlockNode node)
81     {
82         print("Block: %s".fmt(node.name));
83         _tab++;
84         if (!node.stmt.isNull)
85             node.stmt.get.accept(this);
86         _tab--;
87     }
88 
89 
90     override void visit(RawNode node)
91     {
92         import std.array : replace;
93         print("Raw block: \"%s\"".fmt(node.raw.replace("\n", "\\n").replace(" ", ".")));
94     }
95 
96 
97     override void visit(ExprNode node)
98     {
99         print("Expression block:");
100         _tab++;
101         node.expr.get.accept(this);
102         _tab--;
103     }
104 
105 
106     override void visit(InlineIfNode node)
107     {
108         print("Inline If:");
109 
110         _tab++;
111 
112         if (node.cond.isNull)
113             print("If: NONE");
114         else
115         {
116             print("If:");
117             _tab++;
118             node.cond.get.accept(this);
119             _tab--;
120         }
121 
122         print("Expression:");
123         _tab++;
124         node.expr.get.accept(this);
125         _tab--;
126 
127         if (node.other.isNull)
128             print("Else: nil");
129         else
130         {
131             print("Else:");
132             _tab++;
133             node.other.get.accept(this);
134             _tab--;
135         }
136 
137         _tab--;
138     }
139 
140 
141     override void visit(BinOpNode node)
142     {
143         print("BinaryOp: %s".fmt(node.op));
144         _tab++;
145         node.lhs.accept(this);
146         node.rhs.accept(this);
147         _tab--;
148     }
149 
150 
151     override void visit(UnaryOpNode node)
152     {
153         print("UnaryOp: %s".fmt(node.op));
154         _tab++;
155         node.expr.accept(this);
156         _tab--;
157     }
158 
159 
160     override void visit(NumNode node)
161     {
162         if (node.type == NumNode.Type.Integer)
163             print("Integer: %d".fmt(node.data._integer));
164         else
165             print("Float: %f".fmt(node.data._float));
166     }
167 
168 
169     override void visit(BooleanNode node)
170     {
171         print("Bool: %s".fmt(node.boolean));
172     }
173 
174 
175     override void visit(NilNode node)
176     {
177         print("Nil");
178     }
179 
180 
181     override void visit(IdentNode node)
182     {
183         print("Ident: '%s'".fmt(node.name));
184         if (node.subIdents.length)
185         {
186             print("Sub idents:");
187             _tab++;
188             foreach (id; node.subIdents)
189                 id.accept(this);
190             _tab--;
191         }
192     }
193 
194 
195     override void visit(AssignableNode node)
196     {
197         print("Assignable: %s".fmt(node.name));
198         if (node.subIdents.length)
199         {
200             _tab++;
201             print("Sub idents:");
202             _tab++;
203             foreach (id; node.subIdents)
204                 id.accept(this);
205             _tab--;
206             _tab--;
207         }
208     }
209 
210 
211     override void visit(StringNode node)
212     {
213         print("String: %s".fmt(node.str));
214     }
215 
216 
217     override void visit(ListNode node)
218     {
219         print("List:");
220         _tab++;
221         foreach (l; node.list)
222             l.accept(this);
223         _tab--;
224     }
225 
226 
227     override void visit(DictNode node)
228     {
229         print("Dict:");
230         _tab++;
231         foreach (key, value; node.dict)
232         {
233             print("Key: %s".fmt(key));
234             print("Value:");
235             _tab++;
236             value.accept(this);
237             _tab--;
238         }
239         _tab--;
240     }
241 
242 
243     override void visit(IfNode node)
244     {
245         print("If:");
246         _tab++;
247 
248         print("Condition:");
249         _tab++;
250         node.cond.accept(this);
251         _tab--;
252 
253         print("Then:");
254         _tab++;
255         node.then.accept(this);
256         _tab--;
257 
258         if (node.other)
259         {
260             print("Else:");
261             _tab++;
262             node.other.accept(this);
263             _tab--;
264         }
265         else
266             print("Else: NONE");
267         _tab--;
268     }
269 
270 
271     override void visit(ForNode node)
272     {
273         print("For:");
274         _tab++;
275 
276         print("Keys:");
277         _tab++;
278         foreach (key; node.keys)
279             print(key);
280         _tab--;
281 
282         print("Iterable:");
283         _tab++;
284         node.iterable.get.accept(this);
285         _tab--;
286 
287         print("Block:");
288         _tab++;
289         node.block.get.accept(this);
290         _tab--;
291 
292         if (!node.cond.isNull)
293         {
294             print("Condition:");
295             _tab++;
296             node.cond.get.accept(this);
297             _tab--;
298         }
299         else
300             print("Condition: NONE");
301 
302 
303         if (!node.other.isNull)
304         {
305             print("Else:");
306             _tab++;
307             node.other.get.accept(this);
308             _tab--;
309         }
310         else
311             print("Else: NONE");
312 
313         print("Recursive: %s".fmt(node.isRecursive));
314 
315         _tab--;
316     }
317 
318 
319     override void visit(SetNode node)
320     {
321         print("Set:");
322         _tab++;
323 
324         print("Assigns:");
325         _tab++;
326         foreach (assign; node.assigns)
327             assign.accept(this);
328         _tab--;
329 
330         print("Expression:");
331         _tab++;
332         node.expr.accept(this);
333         _tab--;
334 
335         _tab--;
336     }
337 
338 
339     override void visit(MacroNode node)
340     {
341         print("Macro: '%s'".fmt(node.name));
342 
343         _tab++;
344         if (!node.args.length)
345             print("Args: NONE");
346         else
347         {
348             print("Args:");
349             _tab++;
350             foreach(arg; node.args)
351             {
352                 print("Name: %s".fmt(arg.name));
353                 if (!arg.defaultExpr.isNull)
354                 {
355                     _tab++;
356                     print("Default:");
357                     _tab++;
358                     arg.defaultExpr.get.accept(this);
359                     _tab--;
360                     _tab--;
361                 }
362             }
363             _tab--;
364         }
365 
366         print("Body:");
367         _tab++;
368         node.block.get.accept(this);
369         _tab--;
370 
371         _tab--;
372 
373         print("Return: %s".fmt(node.isReturn));
374     }
375 
376 
377     override void visit(CallNode node)
378     {
379         print("Call: '%s'".fmt(node.macroName));
380 
381         _tab++;
382 
383         if (!node.formArgs.length)
384             print("Formal args: NONE");
385         else
386         {
387             print("Formal args:");
388             _tab++;
389             foreach(arg; node.formArgs)
390             {
391                 print("Name: %s".fmt(arg.name));
392                 if (!arg.defaultExpr.isNull)
393                 {
394                     _tab++;
395                     print("Default:");
396                     _tab++;
397                     arg.defaultExpr.get.accept(this);
398                     _tab--;
399                     _tab--;
400                 }
401             }
402             _tab--;
403         }
404 
405         if (node.factArgs.isNull)
406             print("Fact args: NONE");
407         else
408         {
409             print("Fact args:");
410             _tab++;
411             node.factArgs.get.accept(this);
412             _tab--;
413         }
414 
415         print("Body:");
416         _tab++;
417         node.block.get.accept(this);
418         _tab--;
419 
420         _tab--;
421     }
422 
423 
424     override void visit(FilterBlockNode node)
425     {
426         print("Filter: '%s'".fmt(node.filterName));
427 
428         _tab++;
429 
430         if (node.args.isNull)
431             print("Args: NONE");
432         else
433         {
434             print("Args:");
435             _tab++;
436             node.args.get.accept(this);
437             _tab--;
438         }
439 
440         print("Body:");
441         _tab++;
442         node.block.get.accept(this);
443         _tab--;
444 
445         _tab--;
446     }
447 
448 
449     override void visit(ImportNode node)
450     {
451         print("Import: '%s'".fmt(node.fileName));
452 
453         _tab++;
454 
455         if (!node.macrosNames.length)
456             print("Macros: all");
457         else
458         {
459             print("Macros:");
460             _tab++;
461             foreach(name; node.macrosNames)
462                 print("%s -> %s".fmt(name.was, name.become));
463             _tab--;
464         }
465 
466         if (node.tmplBlock.isNull)
467             print("Block: Missing");
468         else
469             print("Block: %s children".fmt(node.tmplBlock.get.stmt.get.children.length));
470 
471         if (node.withContext)
472             print("Context: with");
473         else
474             print("Context: without");
475 
476         _tab--;
477     }
478 
479 
480     override void visit(IncludeNode node)
481     {
482         print("Include: '%s'".fmt(node.fileName));
483 
484         _tab++;
485 
486         if (node.tmplBlock.isNull)
487             print("Block: Missing");
488         else
489             print("Block: %s children".fmt(node.tmplBlock.get.stmt.get.children.length));
490 
491         if (node.withContext)
492             print("Context: with");
493         else
494             print("Context: without");
495 
496         _tab--;
497     }
498 
499 
500     override void visit(ExtendsNode node)
501     {
502         print("Extends: '%s'".fmt(node.fileName));
503 
504         _tab++;
505 
506         if (node.tmplBlock.isNull)
507             print("Block: Missing");
508         else
509             print("Block: %s children".fmt(node.tmplBlock.get.stmt.get.children.length));
510 
511         _tab--;
512     }
513 
514 
515 protected:
516 
517 
518     void print(string str)
519     {
520         foreach(i; 0 .. _tab)
521             w("-   ");
522         wl(str);
523     }
524 }