yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
cfd08da10
master
1// slang-fiddle-scrape.cpp 2#include "slang-fiddle-scrape.h" 3 4#include "core/slang-string-util.h" 5#include "slang-fiddle-script.h" 6 7namespace fiddle 8{ 9 10// Parser 11 12struct Parser 13{ 14private : 15DiagnosticSink & _sink ; 16List < TokenWithTrivia > _tokens ; 17 18TokenWithTrivia const * _cursor = nullptr ; 19TokenWithTrivia const * _end = nullptr ; 20 21LogicalModule * _module = nullptr ; 22 23ContainerDecl * _currentParentDecl = nullptr ; 24 25struct WithParentDecl 26 { 27public : 28WithParentDecl (Parser * outer ,ContainerDecl * decl ) 29 { 30_outer = outer ; 31_saved = outer -> _currentParentDecl ; 32 33outer -> _currentParentDecl = decl ; 34 } 35 36 ~WithParentDecl () {_outer -> _currentParentDecl = _saved ; } 37 38private : 39Parser * _outer ; 40ContainerDecl * _saved ; 41 }; 42 43public : 44Parser (DiagnosticSink & sink ,List < TokenWithTrivia > const & tokens ,LogicalModule * module ) 45 :_sink (sink ),_tokens (tokens ),_module (module ) 46 { 47_cursor = tokens .begin (); 48_end = tokens .end ()- 1 ; 49 } 50 51bool _isRecovering = false; 52 53TokenWithTrivia const & peek () {return * _cursor ; } 54 55SourceLoc const & peekLoc () {return peek ().getLoc (); } 56 57TokenType peekType () {return peek ().getType (); } 58 59TokenWithTrivia read () 60 { 61_isRecovering = false; 62if (peekType ()!= TokenType ::EndOfFile ) 63return * _cursor ++ ; 64else 65return * _cursor ; 66 } 67 68TokenWithTrivia expect (TokenType expected ) 69 { 70if (peekType ()== expected ) 71 { 72return read (); 73 } 74 75if (!_isRecovering ) 76 { 77_sink .diagnose (peekLoc (), fiddle::Diagnostics ::unexpected ,peekType (),expected ); 78 } 79else 80 { 81// TODO: need to skip until we see what we expected... 82_sink .diagnose (SourceLoc (), fiddle::Diagnostics ::internalError ); 83 } 84 85return TokenWithTrivia (); 86 } 87 88TokenWithTrivia expect (const char * expected ) 89 { 90if (peekType ()== TokenType ::Identifier ) 91 { 92if (peek ().getContent ()== expected ) 93 { 94return read (); 95 } 96 } 97 98if (!_isRecovering ) 99 { 100_sink .diagnose (peekLoc (), fiddle::Diagnostics ::unexpected ,peekType (),expected ); 101 } 102else 103 { 104// TODO: need to skip until we see what we expected... 105_sink .diagnose (SourceLoc (), fiddle::Diagnostics ::internalError ); 106 } 107 108return TokenWithTrivia (); 109 } 110 111bool advanceIf (TokenType type ) 112 { 113if (peekType ()== type ) 114 { 115read (); 116return true; 117 } 118 119return false; 120 } 121 122bool advanceIf (char const * name ) 123 { 124if (peekType ()== TokenType ::Identifier ) 125 { 126if (peek ().getContent ()== name ) 127 { 128read (); 129return true; 130 } 131 } 132 133return false; 134 } 135 136RefPtr < Expr > parseCppSimpleExpr () 137 { 138switch (peekType ()) 139 { 140case TokenType ::Identifier : 141 { 142auto nameToken = expect (TokenType ::Identifier ); 143return new NameExpr (nameToken ); 144 } 145break ; 146 147case TokenType ::IntegerLiteral : 148case TokenType ::StringLiteral : 149 { 150auto token = read (); 151return new LiteralExpr (token ); 152 } 153break ; 154 155case TokenType ::LParent : 156 { 157expect (TokenType ::LParent ); 158auto inner = parseCppExpr (); 159expect (TokenType ::RParent ); 160 161// TODO: handle a cast, in the case that the lookahead 162// implies we should parse one... 163switch (peekType ()) 164 { 165case TokenType ::Identifier : 166case TokenType ::LParent : 167 { 168auto arg = parseCppExpr (); 169return inner ; 170 } 171break ; 172 173default : 174return inner ; 175 } 176 } 177break ; 178 179default : 180expect (TokenType ::Identifier ); 181_sink .diagnose (SourceLoc (), fiddle::Diagnostics ::internalError ); 182return nullptr ; 183 } 184return nullptr ; 185 } 186 187RefPtr < Expr > parseCppExpr () 188 { 189auto base = parseCppSimpleExpr (); 190for (;;) 191 { 192switch (peekType ()) 193 { 194default : 195return base ; 196 197case TokenType ::OpMul : 198 { 199expect (TokenType ::OpMul ); 200switch (peekType ()) 201 { 202default : 203// treat as introducting a pointer type 204return base ; 205 } 206 } 207break ; 208 209case TokenType ::Scope : 210 { 211expect (TokenType ::Scope ); 212auto memberName = expect (TokenType ::Identifier ); 213base = new StaticMemberRef (base ,memberName ); 214 } 215break ; 216case TokenType ::LParent : 217 { 218// TODO: actually parse this! 219readBalanced (); 220 } 221break ; 222 223case TokenType ::OpLess : 224 { 225auto specialize = RefPtr (new SpecializeExpr ()); 226specialize -> base = base ; 227 228// Okay, we have a template application here. 229expect (TokenType ::OpLess ); 230specialize -> args = parseCppTemplateArgs (); 231parseGenericCloser (); 232 233base = specialize ; 234 } 235break ; 236 } 237 } 238 } 239 240RefPtr < Expr > parseCppSimpleTypeSpecififer () 241 { 242while (advanceIf ("const" )|| advanceIf ("static" )) 243 ; 244 245switch (peekType ()) 246 { 247case TokenType ::Identifier : 248 { 249auto nameToken = expect (TokenType ::Identifier ); 250return new NameExpr (nameToken ); 251 } 252break ; 253 254default : 255expect (TokenType ::Identifier ); 256_sink .diagnose (SourceLoc (), fiddle::Diagnostics ::internalError ); 257return nullptr ; 258 } 259 } 260 261List < RefPtr < Expr >> parseCppTemplateArgs () 262 { 263List < RefPtr < Expr >> args ; 264for (;;) 265 { 266switch (peekType ()) 267 { 268case TokenType ::OpGeq : 269case TokenType ::OpGreater : 270case TokenType ::OpRsh : 271case TokenType ::EndOfFile : 272return args ; 273 } 274 275auto arg = parseCppExpr (); 276if (arg ) 277args .add (arg ); 278 279if (!advanceIf (TokenType ::Comma )) 280return args ; 281 } 282 } 283 284void parseGenericCloser () 285 { 286if (advanceIf (TokenType ::OpGreater )) 287return ; 288 289if (peekType ()== TokenType ::OpRsh ) 290 { 291peek ().setType (TokenType ::OpGreater ); 292 293return ; 294 } 295 296expect (TokenType ::OpGreater ); 297 } 298 299RefPtr < Expr > parseCppTypeSpecifier () 300 { 301auto result = parseCppSimpleTypeSpecififer (); 302for (;;) 303 { 304switch (peekType ()) 305 { 306default : 307return result ; 308 309case TokenType ::Scope : 310 { 311expect (TokenType ::Scope ); 312auto memberName = expect (TokenType ::Identifier ); 313auto memberRef = RefPtr (new StaticMemberRef (result ,memberName )); 314result = memberRef ; 315 } 316break ; 317 318case TokenType ::OpLess : 319 { 320auto specialize = RefPtr (new SpecializeExpr ()); 321specialize -> base = result ; 322 323// Okay, we have a template application here. 324expect (TokenType ::OpLess ); 325specialize -> args = parseCppTemplateArgs (); 326parseGenericCloser (); 327 328result = specialize ; 329 } 330break ; 331 } 332 } 333 } 334 335struct UnwrappedDeclarator 336 { 337RefPtr < Expr > type ; 338TokenWithTrivia nameToken ; 339 }; 340 341UnwrappedDeclarator unwrapDeclarator (RefPtr < Declarator > declarator ,RefPtr < Expr > type ) 342 { 343if (!declarator ) 344 { 345UnwrappedDeclarator result ; 346result .type = type ; 347return result ; 348 } 349 350if (auto ptrDeclarator = as < PtrDeclarator > (declarator )) 351 { 352return unwrapDeclarator (ptrDeclarator -> base ,new PtrType (type )); 353 } 354else if (auto nameDeclarator = as < NameDeclarator > (declarator )) 355 { 356UnwrappedDeclarator result ; 357result .type = type ; 358result .nameToken = nameDeclarator -> nameToken ; 359return result ; 360 } 361else 362 { 363_sink .diagnose (SourceLoc (),Diagnostics ::unexpected ,"declarator type" ,"known" ); 364return UnwrappedDeclarator (); 365 } 366 } 367 368RefPtr < Expr > parseCppType () 369 { 370auto typeSpecifier = parseCppTypeSpecifier (); 371auto declarator = parseCppDeclarator (); 372return unwrapDeclarator (declarator ,typeSpecifier ).type ; 373 } 374 375RefPtr < Expr > parseCppBase () 376 { 377// TODO: allow `private` and `protected` 378// TODO: insert a default `public` keyword, if one is missing... 379advanceIf ("public" ); 380return parseCppType (); 381 } 382 383void parseCppAggTypeDecl (RefPtr < AggTypeDecl > decl ) 384 { 385decl -> mode = Mode ::Cpp ; 386 387// read the type name 388decl -> nameToken = expect (TokenType ::Identifier ); 389 390// Read the bases clause. 391// 392// TODO: handle multiple bases... 393// 394if (advanceIf (TokenType ::Colon )) 395 { 396decl -> directBaseType = parseCppBase (); 397 } 398 399expect (TokenType ::LBrace ); 400addDecl (decl ); 401WithParentDecl withParent (this ,decl ); 402 403// We expect any `FIDDLE()`-marked aggregate type declaration to start 404// with a `FIDDLE(...)` or `FIDDLE(myFunc(a,b,c))` invocation, so that 405// there is a suitable insertion point for the expansion step or the 406// user has specific a custom step 407// 408 { 409auto saved = _cursor ; 410bool found = peekFiddleEllipsisInvocation ()|| peekFiddleLuaCall (); 411_cursor = saved ; 412if (!found ) 413 { 414_sink .diagnose ( 415peekLoc (), 416 fiddle::Diagnostics ::expectedFiddleEllipsisInvocation , 417decl -> nameToken .getContent ()); 418 } 419 } 420 421parseCppDecls (decl ); 422expect (TokenType ::RBrace ); 423 } 424 425bool peekFiddleEllipsisInvocation () 426 { 427if (!advanceIf ("FIDDLE" )) 428return false; 429 430if (!advanceIf (TokenType ::LParent )) 431return false; 432 433if (!advanceIf (TokenType ::Ellipsis )) 434return false; 435 436return true; 437 } 438 439bool peekFiddleLuaCall () 440 { 441auto saved = _cursor ; 442const bool found = advanceIf (TokenType ::Identifier )&& 443 (peekType ()== TokenType ::LParent || peekType ()== TokenType ::LBrace ); 444_cursor = saved ; 445return found ; 446 } 447 448RefPtr < Declarator > parseCppSimpleDeclarator () 449 { 450switch (peekType ()) 451 { 452case TokenType ::Identifier : 453 { 454auto nameToken = expect (TokenType ::Identifier ); 455return RefPtr (new NameDeclarator (nameToken )); 456 } 457 458default : 459return nullptr ; 460 } 461 } 462 463RefPtr < Declarator > parseCppPostfixDeclarator () 464 { 465auto result = parseCppSimpleDeclarator (); 466for (;;) 467 { 468switch (peekType ()) 469 { 470default : 471return result ; 472 473case TokenType ::LBracket : 474readBalanced (); 475return result ; 476 } 477 } 478return result ; 479 } 480 481RefPtr < Declarator > parseCppDeclarator () 482 { 483while (advanceIf ("const" )|| advanceIf ("static" )) 484 ; 485 486if (advanceIf (TokenType ::OpMul )) 487 { 488auto base = parseCppDeclarator (); 489return RefPtr (new PtrDeclarator (base )); 490 } 491else 492 { 493return parseCppPostfixDeclarator (); 494 } 495 } 496 497void parseCppDeclaratorBasedDecl (List < RefPtr < ModifierNode >> const & fiddleModifiers ) 498 { 499auto typeSpecifier = parseCppTypeSpecifier (); 500auto declarator = parseCppDeclarator (); 501 502auto unwrapped = unwrapDeclarator (declarator ,typeSpecifier ); 503 504auto varDecl = RefPtr (new VarDecl ()); 505varDecl -> nameToken = unwrapped .nameToken ; 506varDecl -> type = unwrapped .type ; 507addDecl (varDecl ); 508 509if (advanceIf (TokenType ::OpAssign )) 510 { 511varDecl -> initExpr = parseCppExpr (); 512 } 513expect (TokenType ::Semicolon ); 514 } 515 516void parseNativeDeclaration (List < RefPtr < ModifierNode >> const & fiddleModifiers ) 517 { 518auto keyword = peek (); 519if (advanceIf ("namespace" )) 520 { 521RefPtr < PhysicalNamespaceDecl > namespaceDecl = new PhysicalNamespaceDecl (); 522namespaceDecl -> modifiers = fiddleModifiers ; 523 524 525// read the namespace name 526namespaceDecl -> nameToken = expect (TokenType ::Identifier ); 527 528expect (TokenType ::LBrace ); 529 530addDecl (namespaceDecl ); 531WithParentDecl withNamespace (this ,namespaceDecl ); 532 533parseCppDecls (namespaceDecl ); 534 535expect (TokenType ::RBrace ); 536 } 537else if (advanceIf ("class" )) 538 { 539auto decl = RefPtr (new ClassDecl ()); 540decl -> modifiers = fiddleModifiers ; 541parseCppAggTypeDecl (decl ); 542 } 543else if (advanceIf ("struct" )) 544 { 545auto decl = RefPtr (new StructDecl ()); 546decl -> modifiers = fiddleModifiers ; 547parseCppAggTypeDecl (decl ); 548 } 549else if (peekType ()== TokenType ::Identifier ) 550 { 551// try to parse a declarator-based declaration 552// (which for now is probably a field); 553// 554parseCppDeclaratorBasedDecl (fiddleModifiers ); 555 } 556else 557 { 558_sink .diagnose (peekLoc (), fiddle::Diagnostics ::unexpected ,peekType (),"OTHER" ); 559_sink .diagnose (SourceLoc (), fiddle::Diagnostics ::internalError ); 560 } 561 } 562 563List < RefPtr < ModifierNode >> parseFiddleModifiers () 564 { 565List < RefPtr < ModifierNode >> modifiers ; 566 567for (;;) 568 { 569switch (peekType ()) 570 { 571default : 572return modifiers ; 573 574case TokenType ::Identifier : 575if (advanceIf ("abstract" )) 576 { 577modifiers .add (new AbstractModifier ()); 578 } 579else if (advanceIf ("hidden" )) 580 { 581modifiers .add (new HiddenModifier ()); 582 } 583else 584 { 585return modifiers ; 586 } 587break ; 588 589case TokenType ::LBrace : 590 { 591const auto b = read (); 592StringBuilder sb ; 593sb <<b .getContent (); 594for (int i = 0 ;i < b .getSkipCount ();++ i ) 595sb <<read ().getContent () <<" " ; 596modifiers .add (new TableModifier (std::move (sb ))); 597 } 598break ; 599 } 600 } 601 602return modifiers ; 603 } 604 605RefPtr < Expr > parseFiddlePrimaryExpr () 606 { 607switch (peekType ()) 608 { 609case TokenType ::Identifier : 610return new NameExpr (read ()); 611 612case TokenType ::LParent : 613 { 614expect (TokenType ::LParent ); 615auto expr = parseFiddleExpr (); 616expect (TokenType ::RParent ); 617return expr ; 618 } 619 620default : 621expect (TokenType ::Identifier ); 622return nullptr ; 623 } 624 } 625 626List < RefPtr < Arg >> parseFiddleArgs () 627 { 628List < RefPtr < Arg >> args ; 629for (;;) 630 { 631switch (peekType ()) 632 { 633case TokenType ::RBrace : 634case TokenType ::RBracket : 635case TokenType ::RParent : 636case TokenType ::EndOfFile : 637return args ; 638 639default : 640break ; 641 } 642 643auto arg = parseFiddleExpr (); 644args .add (arg ); 645 646if (!advanceIf (TokenType ::Comma )) 647return args ; 648 } 649 } 650 651RefPtr < Expr > parseFiddlePostifxExpr () 652 { 653auto result = parseFiddlePrimaryExpr (); 654 655for (;;) 656 { 657switch (peekType ()) 658 { 659default : 660return result ; 661 662case TokenType ::Dot : 663 { 664expect (TokenType ::Dot ); 665auto memberName = expect (TokenType ::Identifier ); 666 667result = new MemberExpr (result ,memberName ); 668 } 669break ; 670 671case TokenType ::LParent : 672 { 673expect (TokenType ::LParent ); 674auto args = parseFiddleArgs (); 675expect (TokenType ::RParent ); 676 677result = new CallExpr (result ,args ); 678 } 679break ; 680 } 681 } 682 } 683RefPtr < Expr > parseFiddleExpr () {return parseFiddlePostifxExpr (); } 684 685RefPtr < Expr > parseFiddleTypeExpr () {return parseFiddleExpr (); } 686 687void parseFiddleAggTypeDecl (RefPtr < AggTypeDecl > decl ) 688 { 689decl -> mode = Mode ::Fiddle ; 690 691// read the type name 692decl -> nameToken = expect (TokenType ::Identifier ); 693 694// Read the bases clause. 695if (advanceIf (TokenType ::Colon )) 696 { 697decl -> directBaseType = parseFiddleTypeExpr (); 698 } 699 700addDecl (decl ); 701WithParentDecl withParent (this ,decl ); 702 703if (advanceIf (TokenType ::LBrace )) 704 { 705parseOptionalFiddleModeDecls (); 706 707expect (TokenType ::RBrace ); 708 } 709else 710 { 711expect (TokenType ::Semicolon ); 712 } 713 } 714 715void parseFiddleModeDecl (List < RefPtr < ModifierNode >> modifiers ) 716 { 717if (advanceIf ("class" )) 718 { 719auto decl = RefPtr (new ClassDecl ()); 720decl -> modifiers = modifiers ; 721parseFiddleAggTypeDecl (decl ); 722 } 723else 724 { 725_sink .diagnose ( 726peekLoc (), 727Diagnostics ::unexpected , 728peekType (), 729"fiddle-mode declaration" ); 730 } 731 } 732 733void parseFiddleModeDecl () 734 { 735auto modifiers = parseFiddleModifiers (); 736parseFiddleModeDecl (modifiers ); 737 } 738 739void parseOptionalFiddleModeDecls () 740 { 741for (;;) 742 { 743switch (peekType ()) 744 { 745case TokenType ::RParent : 746case TokenType ::RBrace : 747case TokenType ::RBracket : 748case TokenType ::EndOfFile : 749return ; 750 } 751 752parseFiddleModeDecl (); 753 } 754 } 755 756void parseFiddleModeDecls (List < RefPtr < ModifierNode >> modifiers ) 757 { 758parseFiddleModeDecl (modifiers ); 759parseOptionalFiddleModeDecls (); 760 } 761 762void parseFiddleNode () 763 { 764auto fiddleToken = expect ("FIDDLE" ); 765 766// We will capture the token at this invocation site, 767// because later on we will generate a macro that 768// this invocation will expand into. 769// 770auto fiddleMacroInvocation = RefPtr (new FiddleMacroInvocation ()); 771fiddleMacroInvocation -> fiddleToken = fiddleToken ; 772addDecl (fiddleMacroInvocation ); 773 774// The `FIDDLE` keyword can be followed by parentheses around a bunch of 775// fiddle-mode modifiers. 776List < RefPtr < ModifierNode >> fiddleModifiers ; 777if (advanceIf (TokenType ::LParent )) 778 { 779if (advanceIf (TokenType ::Ellipsis )) 780 { 781// A `FIDDLE(...)` invocation is a hook for 782// our expansion step to insert the generated 783// declarations that go into the body of 784// the parent declaration. 785 786fiddleMacroInvocation -> node = _currentParentDecl ; 787 788expect (TokenType ::RParent ); 789return ; 790 } 791 792 793// We start off by parsing optional modifiers 794fiddleModifiers = parseFiddleModifiers (); 795 796if (peekType ()!= TokenType ::RParent ) 797 { 798if (peekFiddleLuaCall ()) 799 { 800StringBuilder sb ; 801const auto f = expect (TokenType ::Identifier ); 802const auto b = read (); 803sb <<f .getContent () <<b .getContent (); 804for (int i = 0 ;i < b .getSkipCount ();++ i ) 805sb <<read ().getContent () <<" " ; 806auto fiddleLuaCall = RefPtr (new FiddleLuaCallInvocation ()); 807fiddleLuaCall -> fiddleToken = fiddleToken ; 808fiddleLuaCall -> parentDecl = _currentParentDecl ; 809fiddleLuaCall -> callString = std::move (sb ); 810addDecl (fiddleLuaCall ); 811 812expect (TokenType ::RParent ); 813return ; 814 } 815else 816 { 817 818// In this case we are expecting a fiddle-mode declaration 819// to appear, in which case we will allow any number of full 820// fiddle-mode declarations, but won't expect a C++-mode 821// declaration to follow. 822 823// TODO: We should associate these declarations 824// as children of the `FiddleMacroInvocation`, 825// so that they can be emitted as part of its 826// expansion (if we decide to make more use 827// of the `FIDDLE()` approach...). 828 829parseFiddleModeDecls (fiddleModifiers ); 830expect (TokenType ::RParent ); 831return ; 832 } 833 } 834expect (TokenType ::RParent ); 835 } 836else 837 { 838// TODO: diagnose this! 839 } 840 841// Any tokens from here on are expected to be in C++-mode 842 843parseNativeDeclaration (fiddleModifiers ); 844 } 845 846void addDecl (ContainerDecl * parentDecl ,Decl * memberDecl ) 847 { 848if (!memberDecl ) 849return ; 850 851parentDecl -> members .add (memberDecl ); 852 853auto physicalParent = as < PhysicalContainerDecl > (parentDecl ); 854if (!physicalParent ) 855return ; 856 857auto logicalParent = physicalParent -> logicalVersion ; 858if (!logicalParent ) 859return ; 860 861if (auto physicalNamespace = as < PhysicalNamespaceDecl > (memberDecl )) 862 { 863auto namespaceName = physicalNamespace -> nameToken .getContent (); 864auto logicalNamespace = findDecl < LogicalNamespace > (logicalParent ,namespaceName ); 865if (!logicalNamespace ) 866 { 867logicalNamespace = new LogicalNamespace (); 868 869logicalNamespace -> nameToken = physicalNamespace -> nameToken ; 870 871logicalParent -> members .add (logicalNamespace ); 872logicalParent -> mapNameToMember .add (namespaceName ,logicalNamespace ); 873 } 874physicalNamespace -> logicalVersion = logicalNamespace ; 875 } 876else 877 { 878logicalParent -> members .add (memberDecl ); 879 } 880 } 881 882void addDecl (RefPtr < Decl > decl ) {addDecl (_currentParentDecl ,decl ); } 883 884void parseCppDecls (RefPtr < ContainerDecl > parentDecl ) 885 { 886for (;;) 887 { 888switch (peekType ()) 889 { 890case TokenType ::EndOfFile : 891case TokenType ::RBrace : 892case TokenType ::RBracket : 893case TokenType ::RParent : 894return ; 895 896default : 897break ; 898 } 899 900parseCppDecl (); 901 } 902 } 903 904void readBalanced () 905 { 906Count skipCount = read ().getSkipCount (); 907_cursor = _cursor + skipCount ; 908 } 909 910void parseCppDecl () 911 { 912// We consume raw tokens until we see something 913// that ought to start a reflected/extracted declaration. 914// 915for (;;) 916 { 917switch (peekType ()) 918 { 919default : 920 { 921readBalanced (); 922continue ; 923 } 924 925case TokenType ::RBrace : 926case TokenType ::RBracket : 927case TokenType ::RParent : 928case TokenType ::EndOfFile : 929return ; 930 931case TokenType ::Identifier : 932break ; 933 934case TokenType ::Pound : 935// a `#` means we have run into a preprocessor directive 936// (or, somehow, we are already *inside* one...). 937// 938// We don't want to try to intercept anything to do with 939// these lines, so we will read until the next end-of-line. 940// 941read (); 942while (!(peek ().getToken ().flags & TokenFlag ::AtStartOfLine )) 943 { 944if (peekType ()== TokenType ::EndOfFile ) 945break ; 946read (); 947 } 948continue ; 949 } 950 951// Okay, we have an identifier, but is its name 952// one that we want to pay attention to? 953// 954// 955auto name = peek ().getContent (); 956if (name == "FIDDLE" ) 957 { 958// If the `FIDDLE` is the first token we are seeing, then we will 959// start parsing a construct in fiddle-mode: 960// 961parseFiddleNode (); 962 } 963else 964 { 965// If the name isn't one we recognize, then 966// we are just reading raw tokens as usual. 967// 968readBalanced (); 969continue ; 970 } 971 } 972 } 973 974RefPtr < SourceUnit > parseSourceUnit () 975 { 976RefPtr < SourceUnit > sourceUnit = new SourceUnit (); 977sourceUnit -> logicalVersion = _module ; 978 979WithParentDecl withSourceUnit (this ,sourceUnit ); 980while (_cursor != _end ) 981 { 982parseCppDecl (); 983 984switch (peekType ()) 985 { 986default : 987break ; 988 989case TokenType ::RBrace : 990case TokenType ::RBracket : 991case TokenType ::RParent : 992case TokenType ::EndOfFile : 993read (); 994break ; 995 } 996 } 997read (); 998 999return sourceUnit ; 1000 } 1001}; 1002 1003 1004// Check 1005 1006struct CheckContext 1007{ 1008private : 1009DiagnosticSink & sink ; 1010 1011public : 1012CheckContext (DiagnosticSink & sink ) 1013 :sink (sink ) 1014 { 1015 } 1016 1017void checkModule (LogicalModule * module ) {checkMemberDecls (module ); } 1018 1019private : 1020struct Scope 1021 { 1022public : 1023Scope (ContainerDecl * containerDecl ,Scope * outer ) 1024 :containerDecl (containerDecl ),outer (outer ) 1025 { 1026 } 1027 1028ContainerDecl * containerDecl = nullptr ; 1029Scope * outer = nullptr ; 1030 }; 1031Scope * currentScope = nullptr ; 1032 1033struct WithScope :Scope 1034 { 1035WithScope (CheckContext * context ,ContainerDecl * containerDecl ) 1036 :Scope (containerDecl ,context -> currentScope ) 1037 ,_context (context ) 1038 ,_saved (context -> currentScope ) 1039 { 1040context -> currentScope = this ; 1041 } 1042 1043 ~WithScope () {_context -> currentScope = _saved ; } 1044 1045private : 1046CheckContext * _context = nullptr ; 1047Scope * _saved = nullptr ; 1048 }; 1049 1050 1051// 1052void checkDecl (Decl * decl ) 1053 { 1054if (auto aggTypeDecl = as < AggTypeDecl > (decl )) 1055 { 1056checkTypeExprInPlace (aggTypeDecl -> directBaseType ); 1057 1058if (auto baseType = aggTypeDecl -> directBaseType ) 1059 { 1060if (auto baseDeclRef = as < DirectDeclRef > (baseType )) 1061 { 1062auto baseDecl = baseDeclRef -> decl ; 1063if (auto baseAggTypeDecl = as < AggTypeDecl > (baseDecl )) 1064 { 1065baseAggTypeDecl -> directSubTypeDecls .add (aggTypeDecl ); 1066 } 1067 } 1068 } 1069 1070checkMemberDecls (aggTypeDecl ); 1071 } 1072else if (auto namespaceDecl = as < LogicalNamespace > (decl )) 1073 { 1074checkMemberDecls (namespaceDecl ); 1075 } 1076else if (auto varDecl = as < VarDecl > (decl )) 1077 { 1078// Note: for now we aren't trying to check the type 1079// or the initial-value expression of a field. 1080 } 1081else if (as < FiddleMacroInvocation > (decl )) 1082 { 1083 } 1084else if (as < FiddleLuaCallInvocation > (decl )) 1085 { 1086 } 1087else 1088 { 1089sink .diagnose (SourceLoc (),Diagnostics ::unexpected ,"case in checkDecl" ,"known type" ); 1090 } 1091 } 1092 1093void checkMemberDecls (ContainerDecl * containerDecl ) 1094 { 1095WithScope moduleScope (this ,containerDecl ); 1096for (auto memberDecl :containerDecl -> members ) 1097 { 1098checkDecl (memberDecl ); 1099 } 1100 } 1101 1102void checkTypeExprInPlace (RefPtr < Expr >& ioTypeExpr ) 1103 { 1104if (!ioTypeExpr ) 1105return ; 1106ioTypeExpr = checkTypeExpr (ioTypeExpr ); 1107 } 1108 1109RefPtr < Expr > checkTypeExpr (Expr * expr ) {return checkExpr (expr ); } 1110 1111RefPtr < Expr > checkExpr (Expr * expr ) 1112 { 1113if (auto nameExpr = as < NameExpr > (expr )) 1114 { 1115return lookUp (nameExpr -> nameToken .getContent ()); 1116 } 1117else 1118 { 1119sink .diagnose (SourceLoc (),Diagnostics ::unexpected ,"case in checkExpr" ,"known type" ); 1120return nullptr ; 1121 } 1122 } 1123 1124RefPtr < Expr > lookUp (UnownedStringSlice const & name ) 1125 { 1126for (auto scope = currentScope ;scope ;scope = scope -> outer ) 1127 { 1128auto containerDecl = scope -> containerDecl ; 1129// TODO: accelerate lookup with a dictionary on the container... 1130for (auto memberDecl :containerDecl -> members ) 1131 { 1132if (memberDecl -> nameToken .getContent ()== name ) 1133 { 1134return new DirectDeclRef (memberDecl ); 1135 } 1136 } 1137 } 1138sink .diagnose (SourceLoc (),Diagnostics ::undefinedIdentifier ,name ); 1139return nullptr ; 1140 } 1141}; 1142 1143void push (lua_State * L ,Val * val ); 1144 1145// Emit 1146 1147struct EmitContext 1148{ 1149private : 1150SourceManager & _sourceManager ; 1151RefPtr < LogicalModule > _module ; 1152StringBuilder & _builder ; 1153DiagnosticSink & _sink ; 1154 1155public : 1156EmitContext ( 1157StringBuilder & builder , 1158DiagnosticSink & sink , 1159SourceManager & sourceManager , 1160LogicalModule * module ) 1161 :_builder (builder ),_sourceManager (sourceManager ),_module (module ),_sink (sink ) 1162 { 1163 } 1164 1165void emitMacrosRec (Decl * decl ) 1166 { 1167emitMacrosForDecl (decl ); 1168if (auto container = as < ContainerDecl > (decl )) 1169 { 1170for (auto member :container -> members ) 1171emitMacrosRec (member ); 1172 } 1173 } 1174 1175private : 1176void emitMacrosForDecl (Decl * decl ) 1177 { 1178if (auto fiddleMacroInvocation = as < FiddleMacroInvocation > (decl )) 1179 { 1180emitMacroForFiddleInvocation (fiddleMacroInvocation ); 1181 } 1182else if (const auto fiddleLuaCallInvocation = as < FiddleLuaCallInvocation > (decl )) 1183 { 1184emitMacroForFiddleLuaCallInvocation (fiddleLuaCallInvocation ); 1185 } 1186else 1187 { 1188// do nothing with most decls 1189 } 1190 } 1191 1192#define MACRO_LINE_ENDING " \\\n" 1193 1194void emitMacroForFiddleInvocationPreamble (const TokenWithTrivia & fiddleToken ) 1195 { 1196const auto loc = fiddleToken .getLoc (); 1197const auto humaneLoc = _sourceManager .getHumaneLoc (loc ); 1198const auto lineNumber = humaneLoc .line ; 1199// Un-define the old `FIDDLE_#` macro for the 1200// given line number, since this file might 1201// be pulling in another generated header 1202// via one of its dependencies. 1203// 1204_builder .append ("#ifdef FIDDLE_" ); 1205_builder .append (lineNumber ); 1206_builder .append ("\n#undef FIDDLE_" ); 1207_builder .append (lineNumber ); 1208_builder .append ("\n#endif\n" ); 1209 1210_builder .append ("#define FIDDLE_" ); 1211_builder .append (lineNumber ); 1212_builder .append ("(...)" ); 1213_builder .append (MACRO_LINE_ENDING ); 1214 } 1215 1216void emitMacroForFiddleInvocationPostamble () {_builder .append ("/* end */\n\n" ); } 1217 1218void emitMacroForFiddleLuaCallInvocation (FiddleLuaCallInvocation * fiddleInvocation ) 1219 { 1220_builder .append ("/*\n" ); 1221_builder .append (fiddleInvocation -> callString ); 1222_builder .append ("\n*/\n" ); 1223 1224emitMacroForFiddleInvocationPreamble (fiddleInvocation -> fiddleToken ); 1225 1226const auto file = 1227_sourceManager .getHumaneLoc (fiddleInvocation -> fiddleToken .getLoc ()).pathInfo .getName (); 1228StringBuilder sb ; 1229sb <<"require(\"" <<file <<".lua\")." <<fiddleInvocation -> callString ; 1230 1231// Create the fiddle table 1232const auto L = getLuaState (); 1233lua_newtable (L ); 1234push (L ,fiddleInvocation -> parentDecl ); 1235lua_setfield (L ,-2 ,"current_decl" ); 1236lua_setglobal (L ,"fiddle" ); 1237 1238const auto output = evaluateLuaExpression ( 1239fiddleInvocation -> fiddleToken .getLoc (), 1240file , 1241sb .produceString (), 1242& _sink ); 1243 1244// Deregister the fiddle table 1245lua_pushnil (L ); 1246lua_setglobal (L ,"fiddle" ); 1247 1248_builder .append (StringUtil ::replaceAll ( 1249output .getUnownedSlice (), 1250UnownedStringSlice ("\n" ), 1251UnownedStringSlice (MACRO_LINE_ENDING ))); 1252 1253_builder .append (MACRO_LINE_ENDING ); 1254emitMacroForFiddleInvocationPostamble (); 1255 } 1256 1257void emitMacroForFiddleInvocation (FiddleMacroInvocation * fiddleInvocation ) 1258 { 1259emitMacroForFiddleInvocationPreamble (fiddleInvocation -> fiddleToken ); 1260 1261auto decl = as < AggTypeDecl > (fiddleInvocation -> node ); 1262if (decl ) 1263 { 1264if (auto base = decl -> directBaseType ) 1265 { 1266_builder .append ("private: typedef " ); 1267emitTypedDecl (base ,"Super" ); 1268_builder .append (";" MACRO_LINE_ENDING ); 1269 } 1270 1271if (decl -> isSubTypeOf ("NodeBase" )) 1272 { 1273_builder .append ("friend class ::Slang::ASTBuilder;" MACRO_LINE_ENDING ); 1274_builder .append ("friend struct ::Slang::SyntaxClassInfo;" MACRO_LINE_ENDING ); 1275 1276_builder .append ("public: static const ::Slang::SyntaxClassInfo " 1277"kSyntaxClassInfo;" MACRO_LINE_ENDING ); 1278 1279_builder .append ("public: static constexpr ASTNodeType kType = ASTNodeType::" ); 1280_builder .append (decl -> nameToken .getContent ()); 1281_builder .append (";" MACRO_LINE_ENDING ); 1282 1283if (decl -> findModifier < AbstractModifier > ()) 1284 { 1285_builder .append ("protected: " ); 1286 } 1287else 1288 { 1289_builder .append ("public: " ); 1290 } 1291_builder .append (decl -> nameToken .getContent ()); 1292_builder .append ("() {}" MACRO_LINE_ENDING ); 1293 } 1294_builder .append ("public:" MACRO_LINE_ENDING ); 1295 } 1296emitMacroForFiddleInvocationPostamble (); 1297 } 1298 1299void emitTypedDecl (Expr * expr ,const char * name ) 1300 { 1301if (auto declRef = as < DirectDeclRef > (expr )) 1302 { 1303_builder .append (declRef -> decl -> nameToken .getContent ()); 1304_builder .append (" " ); 1305_builder .append (name ); 1306 } 1307 } 1308 1309#if 0 1310void emitLineDirective (Token const & lexeme ) 1311 { 1312SourceLoc loc = lexeme .getLoc (); 1313auto humaneLoc = _sourceManager .getHumaneLoc (loc ); 1314_builder .append ("\n#line " ); 1315_builder .append (humaneLoc .line ); 1316_builder .append (" \"" ); 1317for (auto c :humaneLoc .pathInfo .getName ()) 1318 { 1319if (c == '\\' )_builder .append ("\\\\" ); 1320else _builder .append (c ); 1321 } 1322_builder .append ("\"\n" ); 1323 } 1324 1325void emitLineDirective (TokenWithTrivia const & token ) 1326 { 1327if (token .getLeadingTrivia ().getCount ()!= 0 ) 1328emitLineDirective (token .getLeadingTrivia ()[0 ]); 1329else 1330emitLineDirective (token .getToken ()); 1331 } 1332 1333void emitLineDirective (RawNode * node ) 1334 { 1335emitLineDirective (node -> tokens [0 ]); 1336 } 1337 1338 1339void emitTrivia (List < Token > const & trivia ) 1340 { 1341for (auto trivium :trivia ) 1342_builder .append (trivium .getContent ()); 1343 } 1344 1345void emitRawNode (RawNode * rawNode ) 1346 { 1347for (auto token :rawNode -> tokens ) 1348 { 1349emitTrivia (token .getLeadingTrivia ()); 1350_builder .append (token .getContent ()); 1351emitTrivia (token .getTrailingTrivia ()); 1352 } 1353 } 1354 1355void emitTopLevelNode (Decl * node ) 1356 { 1357if (!node ) 1358return ; 1359 1360if (node -> findModifier < HiddenModifier > ()) 1361return ; 1362 1363if (auto rawNode = as < RawNode > (node )) 1364 { 1365// TODO: should emit a `#line` to point back to 1366// the original source file... 1367emitLineDirective (rawNode ); 1368 1369emitRawNode (rawNode ); 1370 } 1371else if (auto decl = as < PhysicalNamespaceDecl > (node )) 1372 { 1373for (auto child :decl -> members ) 1374 { 1375emitTopLevelNode (child ); 1376 } 1377 } 1378else if (auto decl = as < AggTypeDecl > (node )) 1379 { 1380emitExtraMembersForAggTypeDecl (decl ); 1381 1382for (auto child :decl -> members ) 1383 { 1384emitTopLevelNode (child ); 1385 } 1386 } 1387else if (auto varDecl = as < VarDecl > (node )) 1388 { 1389// Note: nothing to be done here... 1390 } 1391else 1392 { 1393_sink .diagnose (SourceLoc (), fiddle::Diagnostics ::unexpected ,"emitTopLevelNode" ,"unhandled case" ); 1394 } 1395 } 1396 1397void emitSourceUnit (SourceUnit * sourceUnit ) 1398 { 1399for (auto node :sourceUnit -> members ) 1400 { 1401emitTopLevelNode (node ); 1402 } 1403 } 1404 1405private : 1406#endif 1407}; 1408 1409 1410Decl * findDecl_ (ContainerDecl * outerDecl ,UnownedStringSlice const & name ) 1411{ 1412for (auto memberDecl :outerDecl -> members ) 1413 { 1414if (memberDecl -> nameToken .getContent ()== name ) 1415return memberDecl ; 1416 } 1417return nullptr ; 1418} 1419 1420bool AggTypeDecl ::isSubTypeOf (char const * name ) 1421{ 1422Decl * decl = this ; 1423while (decl ) 1424 { 1425if (decl -> nameToken .getContent ()== UnownedTerminatedStringSlice (name )) 1426 { 1427return true; 1428 } 1429 1430auto aggType = as < AggTypeDecl > (decl ); 1431if (!aggType ) 1432break ; 1433 1434auto baseTypeExpr = aggType -> directBaseType ; 1435if (!baseTypeExpr ) 1436break ; 1437 1438auto declRef = as < DirectDeclRef > (baseTypeExpr ); 1439if (!declRef ) 1440break ; 1441 1442decl = declRef -> decl ; 1443 } 1444return false; 1445} 1446 1447bool isTrivia (TokenType lexemeType ) 1448{ 1449switch (lexemeType ) 1450 { 1451default : 1452return false; 1453 1454case TokenType ::LineComment : 1455case TokenType ::BlockComment : 1456case TokenType ::NewLine : 1457case TokenType ::WhiteSpace : 1458return true; 1459 } 1460} 1461 1462List < TokenWithTrivia > collectTokensWithTrivia (TokenList const & lexemes ) 1463{ 1464TokenReader reader (lexemes ); 1465 1466List < TokenWithTrivia > allTokensWithTrivia ; 1467for (;;) 1468 { 1469RefPtr < TokenWithTriviaNode > currentTokenWithTriviaNode = new TokenWithTriviaNode (); 1470TokenWithTrivia currentTokenWithTrivia = currentTokenWithTriviaNode ; 1471allTokensWithTrivia .add (currentTokenWithTrivia ); 1472 1473while (isTrivia (reader .peekTokenType ())) 1474 { 1475auto trivia = reader .advanceToken (); 1476currentTokenWithTriviaNode -> leadingTrivia .add (trivia ); 1477 } 1478 1479auto token = reader .advanceToken (); 1480currentTokenWithTriviaNode -> token = token ; 1481 1482if (token .type == TokenType ::EndOfFile ) 1483return allTokensWithTrivia ; 1484 1485while (isTrivia (reader .peekTokenType ())) 1486 { 1487auto trivia = reader .advanceToken (); 1488currentTokenWithTriviaNode -> trailingTrivia .add (trivia ); 1489 1490if (trivia .type == TokenType ::NewLine ) 1491break ; 1492 } 1493 } 1494} 1495 1496void readTokenTree (List < TokenWithTrivia > const & tokens ,Index & ioIndex ); 1497 1498void readBalancedToken (List < TokenWithTrivia > const & tokens ,Index & ioIndex ,TokenType closeType ) 1499{ 1500auto open = tokens [ioIndex ++ ]; 1501auto openNode = (TokenWithTriviaNode * )open ; 1502 1503Index startIndex = ioIndex ; 1504for (;;) 1505 { 1506auto token = tokens [ioIndex ]; 1507if (token .getType ()== closeType ) 1508 { 1509ioIndex ++ ; 1510break ; 1511 } 1512 1513switch (token .getType ()) 1514 { 1515default : 1516readTokenTree (tokens ,ioIndex ); 1517continue ; 1518 1519case TokenType ::RBrace : 1520case TokenType ::RBracket : 1521case TokenType ::RParent : 1522case TokenType ::EndOfFile : 1523break ; 1524 } 1525break ; 1526 } 1527openNode -> skipCount = ioIndex - startIndex ; 1528} 1529 1530void readTokenTree (List < TokenWithTrivia > const & tokens ,Index & ioIndex ) 1531{ 1532switch (tokens [ioIndex ].getType ()) 1533 { 1534default : 1535ioIndex ++ ; 1536return ; 1537 1538case TokenType ::LBrace : 1539return readBalancedToken (tokens ,ioIndex ,TokenType ::RBrace ); 1540 1541case TokenType ::LBracket : 1542return readBalancedToken (tokens ,ioIndex ,TokenType ::RBracket ); 1543 1544case TokenType ::LParent : 1545return readBalancedToken (tokens ,ioIndex ,TokenType ::RParent ); 1546 } 1547} 1548 1549void matchBalancedTokens (List < TokenWithTrivia > tokens ) 1550{ 1551Index index = 0 ; 1552for (;;) 1553 { 1554auto & token = tokens [index ]; 1555switch (token .getType ()) 1556 { 1557case TokenType ::EndOfFile : 1558return ; 1559 1560default : 1561readTokenTree (tokens ,index ); 1562break ; 1563 1564case TokenType ::RBrace : 1565case TokenType ::RBracket : 1566case TokenType ::RParent : 1567// error!!! 1568index ++ ; 1569break ; 1570 } 1571 } 1572} 1573 1574bool findOutputFileIncludeDirective (List < TokenWithTrivia > tokens ,String outputFileName ) 1575{ 1576auto cursor = tokens .begin (); 1577auto end = tokens .end ()- 1 ; 1578 1579while (cursor != end ) 1580 { 1581if (cursor -> getType ()!= TokenType ::Pound ) 1582 { 1583cursor ++ ; 1584continue ; 1585 } 1586cursor ++ ; 1587 1588if (cursor -> getContent ()!= "include" ) 1589continue ; 1590cursor ++ ; 1591 1592if (cursor -> getType ()!= TokenType ::StringLiteral ) 1593continue ; 1594 1595auto includedFileName = getStringLiteralTokenValue (cursor -> getToken ()); 1596if (includedFileName == outputFileName ) 1597return true; 1598 } 1599return false; 1600} 1601 1602RefPtr < SourceUnit > parseSourceUnit ( 1603SourceView * inputSourceView , 1604LogicalModule * logicalModule , 1605NamePool * namePool , 1606DiagnosticSink * sink , 1607SourceManager * sourceManager , 1608String outputFileName ) 1609{ 1610Lexer lexer ; 1611 1612// We suppress any diagnostics that might get emitted during lexing, 1613// so that we can ignore any files we don't understand. 1614// 1615DiagnosticSink lexerSink ; 1616lexer .initialize (inputSourceView ,& lexerSink ,namePool ,sourceManager -> getMemoryArena ()); 1617 1618auto inputTokens = lexer .lexAllTokens (); 1619auto tokensWithTrivia = collectTokensWithTrivia (inputTokens ); 1620matchBalancedTokens (tokensWithTrivia ); 1621 1622Parser parser (* sink ,tokensWithTrivia ,logicalModule ); 1623auto sourceUnit = parser .parseSourceUnit (); 1624 1625// As a quick validation check, if the source file had 1626// any `FIDDLE()` invocations in it, then we check to 1627// make sure it also has a `#include` of the corresponding 1628// output file name... 1629if (hasAnyFiddleInvocations (sourceUnit )) 1630 { 1631if (!findOutputFileIncludeDirective (tokensWithTrivia ,outputFileName )) 1632 { 1633sink -> diagnose ( 1634inputSourceView -> getRange ().begin , 1635 fiddle::Diagnostics ::expectedIncludeOfOutputHeader , 1636outputFileName ); 1637 } 1638 } 1639 1640return sourceUnit ; 1641} 1642 1643void push (lua_State * L ,Val * val ); 1644 1645void push (lua_State * L ,UnownedStringSlice const & text ) 1646{ 1647lua_pushlstring (L ,text .begin (),text .getLength ()); 1648} 1649 1650template < typename T > 1651void push (lua_State * L ,List < T > const & values ) 1652{ 1653// Note: Lua tables are naturally indexed starting at 1. 1654Index nextIndex = 1 ; 1655lua_newtable (L ); 1656for (auto value :values ) 1657 { 1658Index index = nextIndex ++ ; 1659 1660push (L ,value ); 1661lua_seti (L ,-2 ,index ); 1662 } 1663} 1664 1665List < RefPtr < AggTypeDecl >> getDirectSubclasses (AggTypeDecl * decl ) 1666{ 1667List < RefPtr < AggTypeDecl >> result ; 1668for (auto subclass :decl -> directSubTypeDecls ) 1669result .add (subclass ); 1670return result ; 1671} 1672 1673void getAllSubclasses (AggTypeDecl * decl ,List < RefPtr < AggTypeDecl >>& ioSubclasses ) 1674{ 1675ioSubclasses .add (decl ); 1676for (auto subclass :decl -> directSubTypeDecls ) 1677getAllSubclasses (subclass ,ioSubclasses ); 1678} 1679 1680List < RefPtr < AggTypeDecl >> getAllSubclasses (AggTypeDecl * decl ) 1681{ 1682List < RefPtr < AggTypeDecl >> result ; 1683getAllSubclasses (decl ,result ); 1684return result ; 1685} 1686 1687int _toStringVal (lua_State * L ) 1688{ 1689Val * val = (Val * )lua_touserdata (L ,1 ); 1690 1691if (auto directDeclRef = as < DirectDeclRef > (val )) 1692 { 1693val = directDeclRef -> decl ; 1694 } 1695 1696if (auto decl = as < Decl > (val )) 1697 { 1698push (L ,decl -> nameToken .getContent ()); 1699return 1 ; 1700 } 1701 1702lua_pushfstring (L ,"fiddle::Val @ 0x%p" ,val ); 1703return 1 ; 1704} 1705 1706int _indexVal (lua_State * L ) 1707{ 1708Val * val = (Val * )lua_touserdata (L ,1 ); 1709char const * name = lua_tostring (L ,2 ); 1710 1711// If we have some user data attached to this declaration, index that 1712if (auto decl = as < Decl > (val )) 1713 { 1714if (auto tableModifier = decl -> findModifier < TableModifier > ()) 1715 { 1716// Check if we have a cached table 1717if (tableModifier -> tableRef == LUA_NOREF ) 1718 { 1719// Evaluate the table string and cache it 1720 std::string tableCode = 1721"return " + std::string (tableModifier -> tableSource .getBuffer ()); 1722 1723if (luaL_dostring (L ,tableCode .c_str ())== LUA_OK ) 1724 { 1725// Store the table in the registry 1726tableModifier -> tableRef = luaL_ref (L ,LUA_REGISTRYINDEX ); 1727 } 1728else 1729 { 1730// Handle error - pop error message and continue 1731lua_pop (L ,1 ); 1732 } 1733 } 1734 1735// If we have a cached table, try to index it 1736if (tableModifier -> tableRef != LUA_NOREF ) 1737 { 1738// Get the cached table from registry 1739lua_rawgeti (L ,LUA_REGISTRYINDEX ,tableModifier -> tableRef ); 1740 1741// Index the table with the requested name 1742lua_pushstring (L ,name ); 1743lua_gettable (L ,-2 ); 1744 1745// Remove the table from stack, leaving just the result 1746lua_remove (L ,-2 ); 1747 1748// Check if we found something 1749if (!lua_isnil (L ,-1 )) 1750 { 1751return 1 ; 1752 } 1753else 1754 { 1755lua_pop (L ,1 );// Pop the nil 1756// Fall through to check other properties 1757 } 1758 } 1759 } 1760 } 1761 1762if (auto containerDecl = as < ContainerDecl > (val )) 1763 { 1764for (auto m :containerDecl -> members ) 1765 { 1766if (m -> nameToken .getContent ()== UnownedTerminatedStringSlice (name )) 1767 { 1768push (L ,m ); 1769return 1 ; 1770 } 1771 } 1772 } 1773 1774if (auto aggTypeDecl = as < AggTypeDecl > (val )) 1775 { 1776if (strcmp (name ,"directSubclasses" )== 0 ) 1777 { 1778auto value = getDirectSubclasses (aggTypeDecl ); 1779push (L ,value ); 1780return 1 ; 1781 } 1782 1783if (strcmp (name ,"subclasses" )== 0 ) 1784 { 1785auto value = getAllSubclasses (aggTypeDecl ); 1786push (L ,value ); 1787return 1 ; 1788 } 1789 1790if (strcmp (name ,"directSuperClass" )== 0 ) 1791 { 1792push (L ,aggTypeDecl -> directBaseType ); 1793return 1 ; 1794 } 1795 } 1796 1797if (auto aggTypeDecl = as < AggTypeDecl > (val )) 1798 { 1799if (strcmp (name ,"directFields" )== 0 ) 1800 { 1801List < RefPtr < Decl >> fields ; 1802for (auto m :aggTypeDecl -> members ) 1803 { 1804if (auto f = as < VarDecl > (m )) 1805fields .add (f ); 1806 } 1807push (L ,fields ); 1808return 1 ; 1809 } 1810 } 1811 1812if (auto decl = as < Decl > (val )) 1813 { 1814if (strcmp (name ,"isAbstract" )== 0 ) 1815 { 1816lua_pushboolean (L ,decl -> findModifier < AbstractModifier > ()!= nullptr ); 1817return 1 ; 1818 } 1819if (strcmp (name ,"getDebugVisType" )== 0 ) 1820 { 1821auto aggTypeDecl = as < AggTypeDecl > (decl ); 1822if (aggTypeDecl ) 1823 { 1824if (aggTypeDecl -> isSubTypeOf ("Decl" )) 1825lua_pushstring (L ,"SyntaxClassInfoDebugVisType::Decl" ); 1826else if (aggTypeDecl -> isSubTypeOf ("Expr" )) 1827lua_pushstring (L ,"SyntaxClassInfoDebugVisType::Expr" ); 1828else if (aggTypeDecl -> isSubTypeOf ("Modifier" )) 1829lua_pushstring (L ,"SyntaxClassInfoDebugVisType::Modifier" ); 1830else if (aggTypeDecl -> isSubTypeOf ("Stmt" )) 1831lua_pushstring (L ,"SyntaxClassInfoDebugVisType::Stmt" ); 1832else if (aggTypeDecl -> isSubTypeOf ("Val" )) 1833lua_pushstring (L ,"SyntaxClassInfoDebugVisType::Val" ); 1834else if (aggTypeDecl -> isSubTypeOf ("Scope" )) 1835lua_pushstring (L ,"SyntaxClassInfoDebugVisType::Scope" ); 1836else 1837lua_pushstring (L ,"SyntaxClassInfoDebugVisType::Unknown" ); 1838 } 1839else 1840lua_pushstring (L ,"SyntaxClassInfoDebugVisType::Unknown" ); 1841return 1 ; 1842 } 1843 } 1844 1845if (auto varDecl = as < VarDecl > (val )) 1846 { 1847if (strcmp (name ,"initExpr" )== 0 ) 1848 { 1849// TODO: do any expression here 1850if (const auto literalExpr = as < LiteralExpr > (varDecl -> initExpr )) 1851 { 1852lua_pushlstring ( 1853L , 1854literalExpr -> token .getContent ().begin (), 1855literalExpr -> token .getContent ().getLength ()); 1856return 1 ; 1857 } 1858return 0 ; 1859 } 1860 } 1861 1862return 0 ; 1863} 1864 1865void push (lua_State * L ,Val * val ) 1866{ 1867if (!val ) 1868 { 1869lua_pushnil (L ); 1870return ; 1871 } 1872 1873lua_pushlightuserdata (L ,val ); 1874if (luaL_newmetatable (L ,"fiddle::Val" )) 1875 { 1876lua_pushcfunction (L ,& _indexVal ); 1877lua_setfield (L ,-2 ,"__index" ); 1878 1879lua_pushcfunction (L ,& _toStringVal ); 1880lua_setfield (L ,-2 ,"__tostring" ); 1881 } 1882lua_setmetatable (L ,-2 ); 1883} 1884 1885void registerValWithScript (String name ,Val * val ) 1886{ 1887auto L = getLuaState (); 1888 1889push (L ,val ); 1890lua_setglobal (L ,name .getBuffer ()); 1891} 1892 1893 1894void registerScrapedStuffWithScript (LogicalModule * logicalModule ) 1895{ 1896for (auto decl :logicalModule -> members ) 1897 { 1898if (!decl -> nameToken ) 1899continue ; 1900 1901registerValWithScript (decl -> nameToken .getContent (),decl ); 1902 } 1903} 1904 1905bool _hasAnyFiddleInvocationsRec (Decl * decl ) 1906{ 1907if (as < FiddleMacroInvocation > (decl )) 1908return true; 1909 1910if (auto container = as < ContainerDecl > (decl )) 1911 { 1912for (auto m :container -> members ) 1913 { 1914if (_hasAnyFiddleInvocationsRec (m )) 1915return true; 1916 } 1917 } 1918return false; 1919} 1920 1921bool hasAnyFiddleInvocations (SourceUnit * sourceUnit ) 1922{ 1923return _hasAnyFiddleInvocationsRec (sourceUnit ); 1924} 1925 1926void checkModule (LogicalModule * module ,DiagnosticSink * sink ) 1927{ 1928CheckContext context (* sink ); 1929context .checkModule (module ); 1930} 1931 1932 1933void emitSourceUnitMacros ( 1934SourceUnit * sourceUnit , 1935StringBuilder & builder , 1936DiagnosticSink * sink , 1937SourceManager * sourceManager , 1938LogicalModule * logicalModule ) 1939{ 1940// The basic task here is to find each of the 1941// `FIDDLE()` macro invocations, and for each 1942// of them produce a matching definition that 1943// will be used as the expansion of that one 1944// 1945 1946EmitContext context (builder ,* sink ,* sourceManager ,logicalModule ); 1947context .emitMacrosRec (sourceUnit ); 1948} 1949 1950}// namespace fiddle