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