1 module cogito.visitor; 2 3 import core.stdc.string; 4 import dmd.ast_node; 5 import dmd.astcodegen; 6 import dmd.parsetimevisitor; 7 import dmd.visitor; 8 import dmd.tokens; 9 10 import cogito.list; 11 import cogito.meter; 12 import std.algorithm; 13 import std.stdio; 14 15 alias AST = ASTCodegen; 16 17 extern(C++) final class CognitiveVisitor : SemanticTimeTransitiveVisitor 18 { 19 alias visit = SemanticTimeTransitiveVisitor.visit; 20 21 private uint depth = 0U; 22 private Source source_; 23 private List!TOK stack; 24 private Meter* parent; 25 26 extern(D) this() 27 { 28 this.source_ = Source(List!Meter()); 29 } 30 31 extern(D) this(string filename) 32 { 33 this.source_ = Source(List!Meter(), filename); 34 } 35 36 /** 37 * Returns collected scores. 38 */ 39 @property ref List!Meter meter() 40 { 41 return this.parent is null ? this.source_.inner : this.parent.inner; 42 } 43 44 /** 45 * Returns collected source file score. 46 */ 47 @property ref Source source() 48 { 49 return this.source_; 50 } 51 52 /** 53 * Increases the score in the current or the top-level scope. 54 */ 55 private void increase(uint by = 1U) 56 { 57 if (this.parent !is null) 58 { 59 this.parent.ownScore += by; 60 } 61 else 62 { 63 this.source.ownScore += by; 64 } 65 } 66 67 override void visit(AST.Dsymbol symbol) 68 { 69 debug printf("Symbol %s\n", symbol.toPrettyChars()); 70 71 super.visit(symbol); 72 } 73 74 override void visit(AST.Expression expression) 75 { 76 debug writeln("Expression ", expression); 77 78 super.visit(expression); 79 } 80 81 override void visit(AST.TemplateParameter parameter) 82 { 83 debug writeln("Parameter ", parameter); 84 85 super.visit(parameter); 86 } 87 88 override void visit(AST.Condition condition) 89 { 90 debug writeln("Condition ", condition); 91 92 super.visit(condition); 93 } 94 95 override void visit(AST.Initializer initializer) 96 { 97 debug writeln("Initializer ", initializer); 98 99 super.visit(initializer); 100 } 101 102 override void visit(AST.PeelStatement statement) 103 { 104 debug writeln("Peel statement ", statement); 105 106 super.visit(statement); 107 } 108 109 override void visit(AST.UnrolledLoopStatement statement) 110 { 111 debug writeln("Unrolled loop statement ", statement); 112 113 super.visit(statement); 114 } 115 116 override void visit(AST.DebugStatement statement) 117 { 118 debug writeln("Debug statement ", statement); 119 // Handled as ConditionalStatement or Condition 120 super.visit(statement); 121 } 122 123 override void visit(AST.ForwardingStatement statement) 124 { 125 debug writeln("Forwarding statement ", statement); 126 127 super.visit(statement); 128 } 129 130 override void visit(AST.StructLiteralExp expression) 131 { 132 debug writeln("Struct literal expression ", expression); 133 134 super.visit(expression); 135 } 136 137 override void visit(AST.CompoundLiteralExp expression) 138 { 139 debug writeln("Compound literal expression ", expression); 140 141 super.visit(expression); 142 } 143 144 override void visit(AST.DotTemplateExp expression) 145 { 146 debug writeln("Dot template expression ", expression); 147 148 super.visit(expression); 149 } 150 151 override void visit(AST.DotVarExp expression) 152 { 153 debug writeln("dot var expression ", expression); 154 155 super.visit(expression); 156 } 157 158 override void visit(AST.DelegateExp expression) 159 { 160 debug writeln("Delegate expression ", expression); 161 162 super.visit(expression); 163 } 164 165 override void visit(AST.DelegatePtrExp expression) 166 { 167 debug writeln("Delegate pointer expression ", expression); 168 169 super.visit(expression); 170 } 171 172 override void visit(AST.DelegateFuncptrExp expression) 173 { 174 debug writeln("Delegate function pointer expression ", expression); 175 176 super.visit(expression); 177 } 178 179 override void visit(AST.DotTypeExp expression) 180 { 181 debug writeln("Dot type expression ", expression); 182 183 super.visit(expression); 184 } 185 186 override void visit(AST.VectorExp expression) 187 { 188 debug writeln("Vector expression ", expression); 189 190 super.visit(expression); 191 } 192 193 override void visit(AST.VectorArrayExp expression) 194 { 195 debug writeln("Vector array expression ", expression); 196 197 super.visit(expression); 198 } 199 200 override void visit(AST.SliceExp expression) 201 { 202 debug writeln("Slice expression ", expression); 203 204 super.visit(expression); 205 } 206 207 override void visit(AST.ArrayLengthExp expression) 208 { 209 debug writeln("Array length expression ", expression); 210 211 super.visit(expression); 212 } 213 214 override void visit(AST.DotExp expression) 215 { 216 debug writeln("Dot expression ", expression); 217 218 super.visit(expression); 219 } 220 221 override void visit(AST.IndexExp expression) 222 { 223 debug writeln("Index expression ", expression); 224 225 super.visit(expression); 226 } 227 228 override void visit(AST.RemoveExp expression) 229 { 230 debug writeln("Remove expression ", expression); 231 232 super.visit(expression); 233 } 234 235 override void visit(AST.Declaration declaration) 236 { 237 debug writeln("Declaration ", declaration); 238 239 super.visit(declaration); 240 } 241 242 override void visit(AST.ScopeDsymbol statement) 243 { 244 debug writeln("Scope symbol ", statement); 245 246 super.visit(statement); 247 } 248 249 override void visit(AST.Package statement) 250 { 251 debug writeln("Package ", statement); 252 253 super.visit(statement); 254 } 255 256 override void visit(AST.AggregateDeclaration statement) 257 { 258 debug writeln("Aggregate declaration ", statement); 259 260 super.visit(statement); 261 } 262 263 override void visit(AST.TupleDeclaration statement) 264 { 265 debug writeln("Tuple declaration ", statement); 266 267 super.visit(statement); 268 } 269 270 override void visit(AST.CtorDeclaration statement) 271 { 272 debug writeln("Constructor declaration ", statement); 273 274 super.visit(statement); 275 } 276 277 override void visit(AST.SharedStaticCtorDeclaration declaration) 278 { 279 debug writeln("Shared static constructor declaration ", declaration); 280 281 stepInFunction!(AST.SharedStaticCtorDeclaration)(declaration); 282 } 283 284 override void visit(AST.SharedStaticDtorDeclaration declaration) 285 { 286 debug writeln("Shared static destructor declaration ", declaration); 287 288 stepInFunction!(AST.SharedStaticDtorDeclaration)(declaration); 289 } 290 291 override void visit(AST.UnionDeclaration statement) 292 { 293 debug writeln("Union ", statement); 294 295 // Unions are handled as StructDeclarations 296 super.visit(statement); 297 } 298 299 override void visit(AST.InterfaceDeclaration statement) 300 { 301 debug writeln("Interface ", statement); 302 303 // Interfaces are handled as ClassDeclarations 304 super.visit(statement); 305 } 306 307 override void visit(AST.BitFieldDeclaration statement) 308 { 309 debug writeln(statement.stringof, ' ', statement); 310 311 super.visit(statement); 312 } 313 314 override void visit(AST.StaticForeachStatement statement) 315 { 316 debug writeln("Static foreach statement ", statement); 317 318 stepInStaticDeclaration(statement); 319 } 320 321 override void visit(AST.GotoStatement statement) 322 { // There are also GotoDefaultStatement and GotoCaseStatement 323 debug writeln("Goto statement ", statement); 324 325 increase; 326 super.visit(statement); 327 } 328 329 override void visit(AST.StructDeclaration structDeclaration) 330 { 331 debug writeln("Struct declaration ", structDeclaration); 332 333 stepInAggregate!(AST.StructDeclaration)(structDeclaration); 334 } 335 336 override void visit(AST.ClassDeclaration classDeclaration) 337 { 338 debug writeln("Class declaration ", classDeclaration); 339 340 stepInAggregate!(AST.ClassDeclaration)(classDeclaration); 341 } 342 343 private void stepInAggregate(Declaration : AST.Dsymbol)(Declaration declaration) 344 { 345 auto newMeter = Meter(declaration.ident, declaration.loc, Meter.Type.aggregate); 346 auto parent = this.parent; 347 this.parent = &newMeter; 348 349 super.visit(declaration); 350 351 this.parent = parent; 352 this.meter.insert(newMeter); 353 } 354 355 override void visit(AST.FuncLiteralDeclaration declaration) 356 { 357 debug writeln("Function literal ", declaration); 358 359 stepInFunction(declaration); 360 } 361 362 override void visit(AST.FuncDeclaration declaration) 363 { 364 debug writeln("Function declaration ", declaration); 365 366 stepInFunction(declaration); 367 } 368 369 override void visit(AST.DtorDeclaration declaration) 370 { 371 debug writeln("Destructor ", declaration); 372 373 stepInFunction(declaration); 374 } 375 376 private void stepInFunction(T : AST.FuncDeclaration)(T declaration) 377 { 378 auto newMeter = Meter(declaration.ident, declaration.loc, Meter.Type.callable); 379 auto parent = this.parent; 380 this.parent = &newMeter; 381 382 ++this.depth; 383 super.visit(declaration); 384 --this.depth; 385 386 this.parent = parent; 387 this.meter.insert(newMeter); 388 } 389 390 override void visit(AST.Statement s) 391 { 392 debug writeln("Statement ", s.stmt); 393 394 super.visit(s); 395 } 396 397 override void visit(AST.TemplateDeclaration declaration) 398 { 399 debug writeln("Template declaration ", declaration); 400 401 stepInAggregate!(AST.TemplateDeclaration)(declaration); 402 } 403 404 override void visit(AST.BinExp expression) 405 { 406 debug writeln("Binary expression ", expression); 407 408 if (expression.isLogicalExp()) { 409 // Each operator like && or || is counted once in an expression 410 // chain. 411 if (find(this.stack[], expression.op).empty) 412 { 413 increase; 414 } 415 this.stack.insert(expression.op); 416 } 417 418 super.visit(expression); 419 420 if (expression.isLogicalExp()) { 421 this.stack.removeFront(); 422 } 423 } 424 425 override void visit(AST.IfStatement statement) 426 { 427 debug writeln("if statement ", statement); 428 429 statement.condition.accept(this); 430 431 if (statement.ifbody) 432 { 433 increase(this.depth); 434 435 ++this.depth; 436 statement.ifbody.accept(this); 437 --this.depth; 438 } 439 visitElseStatement(statement.elsebody); 440 } 441 442 private void visitElseStatement(AST.Statement statement) 443 { 444 if (statement is null) 445 { 446 return; 447 } 448 auto elseIf = statement.isIfStatement(); 449 if (elseIf !is null) 450 { 451 if (elseIf.ifbody) 452 { 453 increase; 454 455 ++this.depth; 456 elseIf.ifbody.accept(this); 457 --this.depth; 458 } 459 visitElseStatement(elseIf.elsebody); 460 } 461 else 462 { 463 increase; 464 465 ++this.depth; 466 statement.accept(this); 467 --this.depth; 468 } 469 } 470 471 override void visit(AST.StaticIfDeclaration declaration) 472 { 473 debug writeln("static if declaration ", declaration); 474 475 declaration.condition.accept(this); 476 477 if (declaration.decl) 478 { 479 increase(max(1, this.depth)); 480 visitNestedDeclarations(declaration); 481 } 482 visitStaticElseDeclaration(declaration.elsedecl); 483 } 484 485 private void visitStaticElseDeclaration(AST.Dsymbols* declaration) 486 { 487 if (declaration is null) 488 { 489 return; 490 } 491 if (declaration.length == 0) 492 { 493 increase; 494 } 495 each!(x => forEachStaticElseDeclaration(x))((*declaration)[]); 496 } 497 498 private void forEachStaticElseDeclaration(AST.Dsymbol elseDeclaration) 499 { 500 if (strcmp(elseDeclaration.kind, "static if") == 0) 501 { 502 auto elseIf = cast(AST.StaticIfDeclaration) elseDeclaration; 503 if (elseIf.decl !is null) 504 { 505 increase; 506 visitNestedDeclarations(elseIf); 507 } 508 visitStaticElseDeclaration(elseIf.elsedecl); 509 } 510 else 511 { 512 increase; 513 514 ++this.depth; 515 elseDeclaration.accept(this); 516 --this.depth; 517 } 518 } 519 520 private void visitNestedDeclarations(ref AST.StaticIfDeclaration elseIf) 521 { 522 ++this.depth; 523 foreach (de; *elseIf.decl) 524 { 525 de.accept(this); 526 } 527 --this.depth; 528 } 529 530 override void visit(AST.ConditionalStatement statement) 531 { 532 debug writeln("Conditional statement ", statement); 533 534 statement.condition.accept(this); 535 536 if (statement.ifbody) 537 { 538 increase(this.depth); 539 540 ++this.depth; 541 statement.ifbody.accept(this); 542 --this.depth; 543 } 544 visitStaticElseStatement(statement.elsebody); 545 } 546 547 private void visitStaticElseStatement(AST.Statement statement) 548 { 549 if (statement is null) 550 { 551 return; 552 } 553 auto elseIf = statement.isConditionalStatement(); 554 if (elseIf !is null) 555 { 556 if (elseIf.ifbody) 557 { 558 increase; 559 560 ++this.depth; 561 elseIf.ifbody.accept(this); 562 --this.depth; 563 } 564 visitStaticElseStatement(elseIf.elsebody); 565 } 566 else 567 { 568 increase; 569 570 ++this.depth; 571 statement.accept(this); 572 --this.depth; 573 } 574 } 575 576 override void visit(AST.StaticForeachDeclaration foreachDeclaration) 577 { 578 debug writeln("Static foreach declaration ", foreachDeclaration); 579 580 stepInStaticDeclaration(foreachDeclaration); 581 } 582 583 private void stepInStaticDeclaration(T : ASTNode)(T declaration) 584 { 585 increase(max(this.depth, 1)); 586 587 ++this.depth; 588 super.visit(declaration); 589 --this.depth; 590 } 591 592 override void visit(AST.WhileStatement whileStatement) 593 { 594 debug writeln("while statement ", whileStatement); 595 596 stepInLoop(whileStatement); 597 } 598 599 override void visit(AST.DoStatement doStatement) 600 { 601 debug writeln("do statement ", doStatement); 602 603 stepInLoop(doStatement); 604 } 605 606 override void visit(AST.ForStatement forStatement) 607 { 608 debug writeln("for statement ", forStatement); 609 610 stepInLoop(forStatement); 611 } 612 613 override void visit(AST.ForeachStatement foreachStatement) 614 { 615 debug writeln("foreach statement ", foreachStatement); 616 617 stepInLoop(foreachStatement); 618 } 619 620 private void stepInLoop(T : ASTNode)(T statement) 621 { 622 increase(this.depth); 623 624 ++this.depth; 625 super.visit(statement); 626 --this.depth; 627 } 628 629 override void visit(AST.Module moduleDeclaration) 630 { 631 debug writeln("Module declaration ", moduleDeclaration); 632 633 this.source_.moduleName = moduleDeclaration.md is null 634 ? "app" 635 : moduleDeclaration.md.toString.idup; 636 637 super.visit(moduleDeclaration); 638 } 639 640 override void visit(AST.CondExp expression) 641 { 642 debug writeln("Ternary operator ", expression); 643 644 stepInLoop(expression); 645 } 646 647 override void visit(AST.SwitchStatement statement) 648 { 649 debug writeln("Switch ", statement); 650 651 stepInLoop(statement); 652 } 653 654 override void visit(AST.TryCatchStatement statement) 655 { 656 debug writeln("try-catch statement ", statement); 657 658 if (statement._body) 659 { 660 increase(this.depth); 661 662 statement._body.accept(this); 663 } 664 foreach (catch_; *statement.catches) 665 { 666 ++this.depth; 667 this.visit(catch_); 668 --this.depth; 669 } 670 } 671 672 override void visit(AST.BreakStatement statement) 673 { 674 debug writeln("Break ", statement.ident); 675 676 stepInStatementWithLabel(statement); 677 } 678 679 private void stepInStatementWithLabel(T : AST.Statement)(T statement) 680 { 681 if (statement.ident !is null) 682 { 683 increase; 684 } 685 super.visit(statement); 686 } 687 688 override void visit(AST.ContinueStatement statement) 689 { 690 debug writeln("Label ", statement); 691 692 stepInStatementWithLabel(statement); 693 } 694 695 override void visit(AST.PostBlitDeclaration declaration) 696 { 697 debug writeln("Blit ", declaration); 698 699 stepInFunction(declaration); 700 } 701 702 override void visit(AST.VersionCondition condition) 703 { 704 debug writeln("Version condition ", condition); 705 706 stepInStaticDeclaration(condition); 707 } 708 }