yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
eaa8dcfcc
master
1#include "parser.h" 2 3#include "compiler-core/slang-name-convention-util.h" 4#include "core/slang-io.h" 5#include "core/slang-string-util.h" 6#include "identifier-lookup.h" 7#include "options.h" 8 9namespace CppParse 10{ 11using namespace Slang ; 12 13// If fails then we need more bits to identify types 14SLANG_COMPILE_TIME_ASSERT (int (Node ::Kind ::CountOf ) <=8 * sizeof (uint32_t )); 15 16// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Parser !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 17 18Parser ::Parser (NodeTree * nodeTree ,DiagnosticSink * sink ) 19 :m_sink (sink ),m_nodeTree (nodeTree ),m_nodeTypeEnabled (0 ) 20{ 21// Enable types by default 22const Node ::Kind defaultEnabled []= { 23Node ::Kind ::ClassType , 24Node ::Kind ::StructType , 25Node ::Kind ::Namespace , 26Node ::Kind ::AnonymousNamespace , 27Node ::Kind ::Field , 28 29// These are disabled by default because AST uses macro magic to build up the types 30// Node::Type::TypeDef, 31// Node::Type::Enum, 32// Node::Type::EnumClass, 33 34Node ::Kind ::Callable , 35 }; 36setKindsEnabled (defaultEnabled ,SLANG_COUNT_OF (defaultEnabled )); 37} 38 39void Parser ::setKindEnabled (Node ::Kind kind ,bool isEnabled ) 40{ 41if (isEnabled ) 42 { 43m_nodeTypeEnabled |= (NodeTypeBitType (1 ) <<int (kind )); 44 } 45else 46 { 47m_nodeTypeEnabled &= ~(NodeTypeBitType (1 ) <<int (kind )); 48 } 49} 50 51void Parser ::setKindsEnabled (const Node ::Kind * kinds ,Index kindsCount ,bool isEnabled ) 52{ 53for (Index i = 0 ;i < kindsCount ;++ i ) 54 { 55setKindEnabled (kinds [i ],isEnabled ); 56 } 57} 58 59bool Parser ::_isMarker (const UnownedStringSlice & name ) 60{ 61return name .startsWith (m_options -> m_markPrefix .getUnownedSlice ())&& 62name .endsWith (m_options -> m_markSuffix .getUnownedSlice ()); 63} 64 65SlangResult Parser ::expect (TokenType type ,Token * outToken ) 66{ 67if (m_reader .peekTokenType ()!= type ) 68 { 69m_sink -> diagnose (m_reader .peekToken (),CPPDiagnostics ::expectingToken ,type ); 70return SLANG_FAIL ; 71 } 72 73if (outToken ) 74 { 75* outToken = m_reader .advanceToken (); 76 } 77else 78 { 79m_reader .advanceToken (); 80 } 81return SLANG_OK ; 82} 83 84bool Parser ::advanceIfToken (TokenType type ,Token * outToken ) 85{ 86if (m_reader .peekTokenType ()== type ) 87 { 88Token token = m_reader .advanceToken (); 89if (outToken ) 90 { 91* outToken = token ; 92 } 93return true; 94 } 95return false; 96} 97 98bool Parser ::advanceIfMarker (Token * outToken ) 99{ 100const Token peekToken = m_reader .peekToken (); 101if (peekToken .type == TokenType ::Identifier && _isMarker (peekToken .getContent ())) 102 { 103m_reader .advanceToken (); 104if (outToken ) 105 { 106* outToken = peekToken ; 107 } 108return true; 109 } 110return false; 111} 112 113bool Parser ::advanceIfStyle (IdentifierStyle style ,Token * outToken ) 114{ 115if (m_reader .peekTokenType ()== TokenType ::Identifier ) 116 { 117IdentifierStyle readStyle = 118m_nodeTree -> m_identifierLookup -> get (m_reader .peekToken ().getContent ()); 119if (readStyle == style ) 120 { 121Token token = m_reader .advanceToken (); 122if (outToken ) 123 { 124* outToken = token ; 125 } 126return true; 127 } 128 } 129return false; 130} 131 132 133SlangResult Parser ::pushAnonymousNamespace () 134{ 135m_currentScope = m_currentScope -> getAnonymousNamespace (); 136 137if (m_sourceOrigin ) 138 { 139m_sourceOrigin -> addNode (m_currentScope ); 140 } 141 142// Add the to the scope stack so can pop. 143m_scopeStack .add (m_currentScope ); 144 145return SLANG_OK ; 146} 147 148SlangResult Parser ::pushScope (ScopeNode * scopeNode ) 149{ 150// We can only have one 'special' scope. 151SLANG_ASSERT (scopeNode || m_scopeStack .getLast ()); 152 153// We keep to track. 154m_scopeStack .add (scopeNode ); 155 156// If we pass nullptr, we don't update the current scope. 157if (scopeNode == nullptr ) 158 { 159return SLANG_OK ; 160 } 161 162if (m_sourceOrigin ) 163 { 164m_sourceOrigin -> addNode (scopeNode ); 165 } 166 167if (scopeNode -> m_name .hasContent ()) 168 { 169// For anonymous namespace, we should look if we already have one and just reopen that. 170// Doing so will mean will find anonymous namespace clashes 171 172if (Node * foundNode = m_currentScope -> findChild (scopeNode -> m_name .getContent ())) 173 { 174if (scopeNode -> isClassLike ()) 175 { 176m_sink -> diagnose ( 177m_reader .peekToken (), 178CPPDiagnostics ::typeAlreadyDeclared , 179scopeNode -> m_name .getContent ()); 180m_sink -> diagnose ( 181foundNode -> m_name , 182CPPDiagnostics ::seeDeclarationOf , 183scopeNode -> m_name .getContent ()); 184return SLANG_FAIL ; 185 } 186 187if (foundNode -> m_kind == Node ::Kind ::Namespace ) 188 { 189if (foundNode -> m_kind != scopeNode -> m_kind ) 190 { 191// Different types can't work 192m_sink -> diagnose ( 193m_reader .peekToken (), 194CPPDiagnostics ::typeAlreadyDeclared , 195scopeNode -> m_name .getContent ()); 196return SLANG_FAIL ; 197 } 198 199ScopeNode * foundScopeNode = as < ScopeNode > (foundNode ); 200SLANG_ASSERT (foundScopeNode ); 201 202// Make sure the node is empty, as we are *not* going to add it, we are just going 203// to use the pre-existing namespace 204SLANG_ASSERT (scopeNode -> m_children .getCount ()== 0 ); 205 206// We can just use the pre-existing namespace 207m_currentScope = foundScopeNode ; 208return SLANG_OK ; 209 } 210 } 211 } 212 213m_currentScope -> addChild (scopeNode ); 214m_currentScope = scopeNode ; 215return SLANG_OK ; 216} 217 218SlangResult Parser ::popScope () 219{ 220if (m_scopeStack .getCount () <=0 ) 221 { 222m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::scopeNotClosed ); 223return SLANG_FAIL ; 224 } 225 226ScopeNode * topScope = m_scopeStack .getLast (); 227m_scopeStack .removeLast (); 228 229// If the top is nullptr, we don't change the current scope 230if (topScope == nullptr ) 231 { 232return SLANG_OK ; 233 } 234 235m_currentScope = m_currentScope -> m_parentScope ; 236return SLANG_OK ; 237} 238 239SlangResult Parser ::_maybeConsumeScope () 240{ 241// Look for either ; or { to open scope 242while (true) 243 { 244const TokenType type = m_reader .peekTokenType (); 245if (type == TokenType ::Semicolon ) 246 { 247m_reader .advanceToken (); 248return SLANG_OK ; 249 } 250else if (type == TokenType ::LBrace ) 251 { 252// m_reader.advanceToken(); 253return consumeToClosingBrace (); 254 } 255else if (type == TokenType ::EndOfFile ) 256 { 257return SLANG_OK ; 258 } 259 260m_reader .advanceToken (); 261 } 262} 263 264SlangResult Parser ::consumeToClosingBrace (const Token * inOpenBraceToken ) 265{ 266Token openToken ; 267if (inOpenBraceToken ) 268 { 269openToken = * inOpenBraceToken ; 270 } 271else 272 { 273openToken = m_reader .advanceToken (); 274 } 275SLANG_ASSERT (openToken .type == TokenType ::LBrace ); 276 277while (true) 278 { 279switch (m_reader .peekTokenType ()) 280 { 281case TokenType ::EndOfFile : 282 { 283m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::didntFindMatchingBrace ); 284m_sink -> diagnose (openToken ,CPPDiagnostics ::seeOpen ); 285return SLANG_FAIL ; 286 } 287case TokenType ::LBrace : 288 { 289SLANG_RETURN_ON_FAIL (consumeToClosingBrace ()); 290break ; 291 } 292case TokenType ::RBrace : 293 { 294m_reader .advanceToken (); 295return SLANG_OK ; 296 } 297default : 298 { 299m_reader .advanceToken (); 300break ; 301 } 302 } 303 } 304} 305 306 307SlangResult Parser ::_parseEnum () 308{ 309// We are looking for 310// enum ([class name] | [name]) [: base] ( { | ; ) 311 312Token enumToken ; 313 314// consume enum 315SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& enumToken )); 316 317if (!m_currentScope -> canContainTypes ()) 318 { 319m_sink -> diagnose (enumToken .loc ,CPPDiagnostics ::cannotDeclareTypeInScope ); 320return SLANG_FAIL ; 321 } 322 323Node ::Kind kind = Node ::Kind ::Enum ; 324 325Token nameToken ; 326if (advanceIfToken (TokenType ::Identifier ,& nameToken )) 327 { 328const IdentifierStyle style = m_nodeTree -> m_identifierLookup -> get (nameToken .getContent ()); 329 330if (style == IdentifierStyle ::Class ) 331 { 332kind = Node ::Kind ::EnumClass ; 333SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& nameToken )); 334 } 335else if (style == IdentifierStyle ::None ) 336 { 337// It holds the name then 338 } 339else 340 { 341m_sink -> diagnose ( 342nameToken .loc , 343CPPDiagnostics ::expectingIdentifier , 344nameToken .getContent ()); 345return SLANG_FAIL ; 346 } 347 } 348 349RefPtr < EnumNode > node = new EnumNode (kind ); 350node -> m_name = nameToken ; 351node -> m_reflectionType = m_currentScope -> getContainedReflectionType (); 352 353if (advanceIfToken (TokenType ::Colon )) 354 { 355// We may have tokens up to { or ; 356List < Token > backingTokens ; 357 358while (true) 359 { 360TokenType tokenType = m_reader .peekTokenType (); 361if (tokenType == TokenType ::Semicolon || tokenType == TokenType ::LBrace || 362tokenType == TokenType ::EndOfFile ) 363 { 364break ; 365 } 366 367backingTokens .add (m_reader .advanceToken ()); 368 } 369 370// TODO - Look up the backing type. It can only be an integral. We can assume it must be 371// defined before lookup for our uses here. If we can't find the type, we could assume it's 372// size is undefined 373 374if (backingTokens .getCount ()> 0 ) 375 { 376node -> m_backingTokens .swapWith (backingTokens ); 377 } 378 } 379 380pushScope (node ); 381 382if (advanceIfToken (TokenType ::Semicolon )) 383 { 384if (nameToken .type != TokenType ::Invalid ) 385 { 386Node * node = m_currentScope -> findChild (nameToken .getContent ()); 387if (node ) 388 { 389// Strictly speaking we should check the backing type etc, match, but for now ignore 390// and assume it's ok 391 392if (node -> m_kind == kind ) 393 { 394return SLANG_OK ; 395 } 396m_sink -> diagnose ( 397nameToken .loc , 398CPPDiagnostics ::typeAlreadyDeclared , 399nameToken .getContent ()); 400return SLANG_FAIL ; 401 } 402return popScope (); 403 } 404 } 405 406SLANG_RETURN_ON_FAIL (expect (TokenType ::LBrace )); 407 408while (true) 409 { 410TokenType tokenType = m_reader .peekTokenType (); 411if (tokenType == TokenType ::RBrace ) 412 { 413break ; 414 } 415 416RefPtr < EnumCaseNode > caseNode (new EnumCaseNode ); 417 418// We could also check if the name is a valid identifier for name, for now just assume. 419SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& caseNode -> m_name )); 420 421if (node -> findChild (caseNode -> m_name .getContent ())) 422 { 423m_sink -> diagnose ( 424caseNode -> m_name .loc , 425CPPDiagnostics ::identifierAlreadyDefined , 426caseNode -> m_name .getContent ()); 427return SLANG_FAIL ; 428 } 429 430caseNode -> m_reflectionType = m_currentScope -> getContainedReflectionType (); 431 432// Add the value 433node -> addChild (caseNode ); 434 435if (advanceIfToken (TokenType ::OpAssign )) 436 { 437List < Token > valueTokens ; 438SLANG_RETURN_ON_FAIL (_parseExpression (valueTokens )); 439 440if (valueTokens .getCount ()> 0 ) 441 { 442caseNode -> m_valueTokens .swapWith (valueTokens ); 443 } 444 } 445 446tokenType = m_reader .peekTokenType (); 447if (tokenType == TokenType ::Comma ) 448 { 449m_reader .advanceToken (); 450continue ; 451 } 452 453break ; 454 } 455 456SLANG_RETURN_ON_FAIL (expect (TokenType ::RBrace )); 457SLANG_RETURN_ON_FAIL (expect (TokenType ::Semicolon )); 458 459return popScope (); 460} 461 462SlangResult Parser ::_consumeTemplate () 463{ 464// Skip the current 'template' token. 465m_reader .advanceToken (); 466 467// Consume everything in <> 468SLANG_RETURN_ON_FAIL (expect (TokenType ::OpLess )); 469 470 { 471Index arrowCount = 1 ; 472while (true) 473 { 474auto tokenType = m_reader .peekTokenType (); 475 476if (tokenType == TokenType ::OpLess ) 477 { 478m_reader .advanceToken (); 479arrowCount ++ ; 480 } 481else if (tokenType == TokenType ::OpGreater ) 482 { 483m_reader .advanceToken (); 484if (arrowCount == 1 ) 485 { 486break ; 487 } 488-- arrowCount ; 489 } 490else if (tokenType == TokenType ::OpRsh ) 491 { 492if (arrowCount < 2 ) 493 { 494m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::unexpectedTemplateClose ); 495return SLANG_FAIL ; 496 } 497m_reader .advanceToken (); 498if (arrowCount == 2 ) 499 { 500break ; 501 } 502arrowCount -= 2 ; 503 } 504else if (tokenType == TokenType ::EndOfFile ) 505 { 506m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::unexpectedEndOfFile ); 507return SLANG_FAIL ; 508 } 509else 510 { 511m_reader .advanceToken (); 512 } 513 } 514 } 515 516// Search for { or ; to consume remaining 517while (true) 518 { 519auto tokenType = m_reader .peekTokenType (); 520 521switch (tokenType ) 522 { 523case TokenType ::EndOfFile : 524 { 525m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::unexpectedEndOfFile ); 526return SLANG_FAIL ; 527 } 528case TokenType ::Semicolon : 529 { 530// Ends with semicolon if it's a template pre-declaration 531m_reader .advanceToken (); 532return SLANG_OK ; 533 } 534case TokenType ::LBrace : 535 { 536// If ends with {, means could be body of a struct/class or a body of a 537// function/method. Consume it 538SLANG_RETURN_ON_FAIL (consumeToClosingBrace ()); 539// If we hit a ; just consume and ignore 540advanceIfToken (TokenType ::Semicolon ); 541return SLANG_OK ; 542 } 543default : 544 { 545// Consume 546m_reader .advanceToken (); 547break ; 548 } 549 } 550 } 551} 552 553SlangResult Parser ::_maybeParseNode (Node ::Kind kind ) 554{ 555// We are looking for 556// struct/class identifier [: [public|private|protected] Identifier ] { 557// [public|private|proctected:]* marker ( identifier ); 558 559if (kind == Node ::Kind ::Namespace ) 560 { 561// consume namespace 562SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier )); 563 564Token name ; 565if (advanceIfToken (TokenType ::LBrace )) 566 { 567return pushAnonymousNamespace (); 568 } 569else if (advanceIfToken (TokenType ::Identifier ,& name )) 570 { 571if (advanceIfToken (TokenType ::LBrace )) 572 { 573// Okay looks like we are opening a namespace 574RefPtr < ScopeNode > node (new ScopeNode (Node ::Kind ::Namespace )); 575node -> m_name = name ; 576 577node -> m_reflectionType = m_currentScope -> getContainedReflectionType (); 578// Push the node 579return pushScope (node ); 580 } 581 } 582 583// Just ignore it then 584return SLANG_OK ; 585 } 586else if (Node ::isKindEnumLike (kind )) 587 { 588return _parseEnum (); 589 } 590 591// Must be class | struct 592 593SLANG_ASSERT (kind == Node ::Kind ::ClassType || kind == Node ::Kind ::StructType ); 594 595Token name ; 596 597// consume class | struct 598SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier )); 599// Next is the class name 600SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& name )); 601 602 603if (m_reader .peekTokenType ()== TokenType ::Semicolon ) 604 { 605// pre declaration; 606return SLANG_OK ; 607 } 608 609RefPtr < ClassLikeNode > node (new ClassLikeNode (kind )); 610node -> m_name = name ; 611 612// We default to the containing scope for reflection type. 613if (!m_options -> m_requireMark ) 614 { 615node -> m_reflectionType = m_currentScope -> getContainedReflectionType (); 616 } 617else 618 { 619// Defaults to not reflected 620SLANG_ASSERT (!node -> isReflected ()); 621 } 622 623if (advanceIfToken (TokenType ::Colon )) 624 { 625// Could have public 626advanceIfStyle (IdentifierStyle ::Access ); 627 628if (!advanceIfToken (TokenType ::Identifier ,& node -> m_super )) 629 { 630return SLANG_OK ; 631 } 632 } 633 634// We only accept a single super class. Consume everything afterwards until we hit the { brace 635 636if (m_reader .peekTokenType ()!= TokenType ::LBrace ) 637 { 638// Consume up until we see a brace else it's an error 639while (true) 640 { 641const TokenType peekTokenType = m_reader .peekTokenType (); 642if (peekTokenType == TokenType ::EndOfFile ) 643 { 644// Expecting brace 645m_sink -> diagnose ( 646m_reader .peekToken (), 647CPPDiagnostics ::expectingToken , 648TokenType ::LBrace ); 649return SLANG_FAIL ; 650 } 651else if (peekTokenType == TokenType ::LBrace ) 652 { 653break ; 654 } 655m_reader .advanceToken (); 656 } 657 658return pushScope (node ); 659 } 660 661const Token braceToken = m_reader .advanceToken (); 662 663// Push the class scope 664return pushScope (node ); 665} 666 667SlangResult Parser ::_consumeToSync () 668{ 669while (true) 670 { 671TokenType type = m_reader .peekTokenType (); 672 673switch (type ) 674 { 675case TokenType ::Semicolon : 676 { 677m_reader .advanceToken (); 678return SLANG_OK ; 679 } 680case TokenType ::Pound : 681case TokenType ::EndOfFile : 682case TokenType ::LBrace : 683case TokenType ::RBrace : 684 { 685return SLANG_OK ; 686 } 687 } 688 689m_reader .advanceToken (); 690 } 691} 692 693SlangResult Parser ::_maybeParseTemplateArg (Index & ioTemplateDepth ) 694{ 695switch (m_reader .peekTokenType ()) 696 { 697case TokenType ::Identifier : 698 { 699TokenReader ::ParsingCursor nameCursor ; 700SLANG_RETURN_ON_FAIL (_maybeParseType (ioTemplateDepth ,nameCursor )); 701return SLANG_OK ; 702 } 703case TokenType ::IntegerLiteral : 704 { 705m_reader .advanceToken (); 706return SLANG_OK ; 707 } 708default : 709break ; 710 } 711return SLANG_FAIL ; 712} 713 714SlangResult Parser ::_maybeParseTemplateArgs (Index & ioTemplateDepth ) 715{ 716if (!advanceIfToken (TokenType ::OpLess )) 717 { 718return SLANG_FAIL ; 719 } 720 721ioTemplateDepth ++ ; 722 723while (true) 724 { 725if (ioTemplateDepth == 0 ) 726 { 727return SLANG_OK ; 728 } 729 730switch (m_reader .peekTokenType ()) 731 { 732case TokenType ::OpGreater : 733 { 734if (ioTemplateDepth <=0 ) 735 { 736m_sink -> diagnose (m_reader .peekToken (),CPPDiagnostics ::unexpectedTemplateClose ); 737return SLANG_FAIL ; 738 } 739ioTemplateDepth -- ; 740m_reader .advanceToken (); 741return SLANG_OK ; 742 } 743case TokenType ::OpRsh : 744 { 745if (ioTemplateDepth <=1 ) 746 { 747m_sink -> diagnose (m_reader .peekToken (),CPPDiagnostics ::unexpectedTemplateClose ); 748return SLANG_FAIL ; 749 } 750ioTemplateDepth -= 2 ; 751m_reader .advanceToken (); 752return SLANG_OK ; 753 } 754default : 755 { 756while (true) 757 { 758SLANG_RETURN_ON_FAIL (_maybeParseTemplateArg (ioTemplateDepth )); 759 760if (m_reader .peekTokenType ()== TokenType ::Comma ) 761 { 762m_reader .advanceToken (); 763// If there is a comma parse another arg 764continue ; 765 } 766break ; 767 } 768break ; 769 } 770 } 771 } 772} 773 774SlangResult Parser ::_maybeConsume (IdentifierStyle style ) 775{ 776while (advanceIfStyle (style )) 777 ; 778return SLANG_OK ; 779} 780 781// True if two of these token types of the same type placed immediately after one another 782// produce a different token. Can be conservative, as if not strictly required 783// it will just mean more spacing in the output 784static bool _canRepeatTokenType (TokenType type ) 785{ 786switch (type ) 787 { 788case TokenType ::OpAdd : 789case TokenType ::OpSub : 790case TokenType ::OpAnd : 791case TokenType ::OpOr : 792case TokenType ::OpGreater : 793case TokenType ::OpLess : 794case TokenType ::Identifier : 795case TokenType ::OpAssign : 796case TokenType ::Colon : 797 { 798return false; 799 } 800default : 801break ; 802 } 803return true; 804} 805 806// Returns true if there needs to be a space between the previous token type, and the current token 807// type for correct output. It is assumed that the token stream is appropriate. 808// The implementation might need more sophistication, but this at least avoids Blah const * -> 809// Blahconst* 810static bool _tokenConcatNeedsSpace (TokenType prev ,TokenType cur ) 811{ 812if ((cur == TokenType ::OpAssign )|| (prev == cur && !_canRepeatTokenType (cur ))) 813 { 814return true; 815 } 816return false; 817} 818 819void Parser ::_getTypeTokens ( 820TokenReader ::ParsingCursor start , 821TokenReader ::ParsingCursor nameCursor , 822List < Token >& outToks ) 823{ 824auto endCursor = m_reader .getCursor (); 825m_reader .setCursor (start ); 826 827while (!m_reader .isAtCursor (endCursor )) 828 { 829if (m_reader .getCursor ()== nameCursor ) 830 { 831m_reader .advanceToken (); 832 } 833else 834 { 835outToks .add (m_reader .advanceToken ()); 836 } 837 } 838} 839 840UnownedStringSlice Parser ::_concatType ( 841TokenReader ::ParsingCursor start , 842TokenReader ::ParsingCursor nameCursor ) 843{ 844List < Token > toks ; 845_getTypeTokens (start ,nameCursor ,toks ); 846return _concatTokens (toks .getBuffer (),toks .getCount ()); 847} 848 849UnownedStringSlice Parser ::_concatTokens (const Token * toks ,Index toksCount ) 850{ 851StringBuilder buf ; 852 853TokenType prevTokenType = TokenType ::Unknown ; 854for (Index i = 0 ;i < toksCount ;++ i ) 855 { 856const auto token = toks [i ]; 857 858// Check if we need a space between tokens 859if (_tokenConcatNeedsSpace (prevTokenType ,token .type )) 860 { 861buf <<" " ; 862 } 863 864buf <<token .getContent (); 865 866prevTokenType = token .type ; 867 } 868 869StringSlicePool * typePool = m_nodeTree -> m_typePool ; 870return typePool -> getSlice (typePool -> add (buf )); 871} 872 873UnownedStringSlice Parser ::_concatTokens (TokenReader ::ParsingCursor start ) 874{ 875auto endCursor = m_reader .getCursor (); 876 877m_reader .setCursor (start ); 878 879TokenType prevTokenType = TokenType ::Unknown ; 880 881StringBuilder buf ; 882while (!m_reader .isAtCursor (endCursor )) 883 { 884const Token token = m_reader .advanceToken (); 885// Check if we need a space between tokens 886if (_tokenConcatNeedsSpace (prevTokenType ,token .type )) 887 { 888buf <<" " ; 889 } 890buf <<token .getContent (); 891 892prevTokenType = token .type ; 893 } 894 895StringSlicePool * typePool = m_nodeTree -> m_typePool ; 896return typePool -> getSlice (typePool -> add (buf )); 897} 898 899SlangResult Parser ::_maybeParseType ( 900Index & ioTemplateDepth , 901TokenReader ::ParsingCursor & outNameCursor ) 902{ 903outNameCursor = TokenReader ::ParsingCursor (); 904 905while (true) 906 { 907if (m_reader .peekTokenType ()== TokenType ::Identifier ) 908 { 909const IdentifierStyle style = 910m_nodeTree -> m_identifierLookup -> get (m_reader .peekToken ().getContent ()); 911 912if (style == IdentifierStyle ::TypeModifier || 913style == IdentifierStyle ::IntegerModifier || style == IdentifierStyle ::Class || 914style == IdentifierStyle ::Struct ) 915 { 916// These are ok keywords in this context 917 } 918else if (hasFlag (style ,IdentifierFlag ::Keyword )) 919 { 920return SLANG_FAIL ; 921 } 922 } 923 924_maybeConsume (IdentifierStyle ::TypeModifier ); 925 926if (advanceIfStyle (IdentifierStyle ::IntegerModifier )) 927 { 928// Consume the integer typename (if there is one) 929const Token peekToken = m_reader .peekToken (); 930if (peekToken .type == TokenType ::Identifier ) 931 { 932const IdentifierStyle style = 933m_nodeTree -> m_identifierLookup -> get (peekToken .getContent ()); 934if (style == IdentifierStyle ::IntegerType ) 935 { 936m_reader .advanceToken (); 937 } 938 } 939break ; 940 } 941 942advanceIfToken (TokenType ::Scope ); 943while (true) 944 { 945// if we have a struct/class prefix in front of a name just consume it. 946if (m_reader .peekTokenType ()== TokenType ::Identifier ) 947 { 948const IdentifierStyle style = 949m_nodeTree -> m_identifierLookup -> get (m_reader .peekToken ().getContent ()); 950if (style == IdentifierStyle ::Class || style == IdentifierStyle ::Struct ) 951 { 952m_reader .advanceToken (); 953 } 954 } 955 956Token identifierToken ; 957if (!advanceIfToken (TokenType ::Identifier ,& identifierToken )) 958 { 959return SLANG_FAIL ; 960 } 961 962const IdentifierStyle style = 963m_nodeTree -> m_identifierLookup -> get (identifierToken .getContent ()); 964if (hasFlag (style ,IdentifierFlag ::Keyword )) 965 { 966return SLANG_FAIL ; 967 } 968 969if (advanceIfToken (TokenType ::Scope )) 970 { 971continue ; 972 } 973break ; 974 } 975 976if (m_reader .peekTokenType ()== TokenType ::OpLess ) 977 { 978SLANG_RETURN_ON_FAIL (_maybeParseTemplateArgs (ioTemplateDepth )); 979 } 980 981if (m_reader .peekTokenType ()== TokenType ::Scope ) 982 { 983// Skip the scope and repeat 984m_reader .advanceToken (); 985continue ; 986 } 987 988break ; 989 } 990 991// Strip all the consts etc modifiers 992_maybeConsume (IdentifierStyle ::TypeModifier ); 993 994// It's a reference and we are done 995if (advanceIfToken (TokenType ::OpBitAnd )) 996 { 997return SLANG_OK ; 998 } 999 1000while (true) 1001 { 1002if (advanceIfToken (TokenType ::OpMul )) 1003 { 1004// Strip all the consts 1005_maybeConsume (IdentifierStyle ::TypeModifier ); 1006continue ; 1007 } 1008break ; 1009 } 1010 1011if (advanceIfToken (TokenType ::LParent )) 1012 { 1013// TODO(JS): 1014// Doesn't handle all the modifiers just (*SomeName) 1015 1016SLANG_RETURN_ON_FAIL (expect (TokenType ::OpMul )); 1017outNameCursor = m_reader .getCursor (); 1018SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier )); 1019 1020SLANG_RETURN_ON_FAIL (expect (TokenType ::RParent )); 1021 1022// We need to parse and add the params 1023if (m_reader .peekTokenType ()!= TokenType ::LParent ) 1024 { 1025m_sink -> diagnose ( 1026m_reader .peekToken (), 1027CPPDiagnostics ::expectingToken , 1028TokenType ::LParent ); 1029return SLANG_FAIL ; 1030 } 1031 1032// Consume the params 1033SLANG_RETURN_ON_FAIL (_consumeBalancedParens ()); 1034 } 1035else if (m_reader .peekTokenType ()== TokenType ::Identifier ) 1036 { 1037auto potentialNameCursor = m_reader .getCursor (); 1038m_reader .advanceToken (); 1039if (m_reader .peekTokenType ()== TokenType ::LBracket ) 1040 { 1041outNameCursor = potentialNameCursor ; 1042while (advanceIfToken (TokenType ::LBracket )) 1043 { 1044List < Token > exprToks ; 1045SLANG_RETURN_ON_FAIL (_parseExpression (exprToks )); 1046SLANG_RETURN_ON_FAIL (expect (TokenType ::RBracket )); 1047 } 1048 } 1049else 1050 { 1051// Wasn't an array type..., so rewind 1052m_reader .setCursor (potentialNameCursor ); 1053 } 1054 } 1055 1056return SLANG_OK ; 1057} 1058 1059SlangResult Parser ::_maybeParseType (List < Token >& outToks ,Token & outName ) 1060{ 1061// Set to unknown 1062outName = Token (); 1063 1064auto startCursor = m_reader .getCursor (); 1065 1066TokenReader ::ParsingCursor nameCursor ; 1067 1068Index templateDepth = 0 ; 1069SlangResult res = _maybeParseType (templateDepth ,nameCursor ); 1070if (SLANG_FAILED (res )&& m_sink -> getErrorCount ()) 1071 { 1072return res ; 1073 } 1074 1075if (templateDepth != 0 ) 1076 { 1077m_sink -> diagnose (m_reader .peekToken (),CPPDiagnostics ::unexpectedTemplateClose ); 1078return SLANG_FAIL ; 1079 } 1080 1081auto endCursor = m_reader .getCursor (); 1082m_reader .setCursor (startCursor ); 1083 1084if (nameCursor .isValid ()) 1085 { 1086while (!m_reader .isAtCursor (endCursor )) 1087 { 1088if (m_reader .getCursor ()== nameCursor ) 1089 { 1090outName = m_reader .advanceToken (); 1091 } 1092else 1093 { 1094outToks .add (m_reader .advanceToken ()); 1095 } 1096 } 1097 } 1098else 1099 { 1100while (!m_reader .isAtCursor (endCursor )) 1101 { 1102outToks .add (m_reader .advanceToken ()); 1103 } 1104 } 1105 1106return SLANG_OK ; 1107} 1108 1109SlangResult Parser ::_parseSpecialMacro () 1110{ 1111Token name ; 1112SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& name )); 1113 1114List < Token > params ; 1115 1116if (m_reader .peekTokenType ()== TokenType ::LParent ) 1117 { 1118// Mark the start 1119auto startCursor = m_reader .getCursor (); 1120 1121// Consume the params 1122SLANG_RETURN_ON_FAIL (_consumeBalancedParens ()); 1123 1124auto endCursor = m_reader .getCursor (); 1125m_reader .setCursor (startCursor ); 1126 1127while (!m_reader .isAtCursor (endCursor )) 1128 { 1129params .add (m_reader .advanceToken ()); 1130 } 1131 } 1132 1133// Can do special handling here 1134const UnownedStringSlice suffix = name .getContent ().tail (m_options -> m_markPrefix .getLength ()); 1135 1136if (suffix == "COM_INTERFACE" ) 1137 { 1138// TODO(JS): It's a com interface. Extact the GUID 1139 } 1140 1141return SLANG_OK ; 1142} 1143 1144SlangResult Parser ::_parseMarker () 1145{ 1146SLANG_ASSERT ( 1147m_reader .peekTokenType ()== TokenType ::Identifier && 1148_isMarker (m_reader .peekToken ().getContent ())&& m_currentScope -> isClassLike ()); 1149 1150ClassLikeNode * node = as < ClassLikeNode > (m_currentScope ); 1151 1152if (node -> m_marker .type != TokenType ::Unknown ) 1153 { 1154m_sink -> diagnose ( 1155m_reader .peekToken (), 1156CPPDiagnostics ::classMarkerAlreadyFound , 1157node -> m_name .getContent ()); 1158m_sink -> diagnose (node -> m_marker ,CPPDiagnostics ::previousLocation ); 1159return SLANG_FAIL ; 1160 } 1161 1162// Set the marker token. 1163node -> m_marker = m_reader .advanceToken (); 1164 1165// Looks like it's a marker 1166UnownedStringSlice slice (node -> m_marker .getContent ()); 1167 1168// Strip the prefix and suffix 1169slice = UnownedStringSlice ( 1170slice .begin ()+ m_options -> m_markPrefix .getLength (), 1171slice .end ()- m_options -> m_markSuffix .getLength ()); 1172 1173// Strip ABSTRACT_ if it's there 1174UnownedStringSlice abstractSlice ("ABSTRACT_" ); 1175if (slice .startsWith (abstractSlice )) 1176 { 1177slice = UnownedStringSlice (slice .begin ()+ abstractSlice .getLength (),slice .end ()); 1178 } 1179 1180// TODO: We could strip other stuff or have other heuristics there, but this is 1181// probably okay for now 1182 1183// Set the typeSet 1184node -> m_typeSet = m_nodeTree -> getOrAddTypeSet (slice ); 1185 1186// Okay now looking for ( identifier) 1187Token typeNameToken ; 1188 1189SLANG_RETURN_ON_FAIL (expect (TokenType ::LParent )); 1190SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& typeNameToken )); 1191SLANG_RETURN_ON_FAIL (expect (TokenType ::RParent )); 1192 1193if (typeNameToken .getContent ()!= node -> m_name .getContent ()) 1194 { 1195m_sink -> diagnose ( 1196typeNameToken , 1197CPPDiagnostics ::typeNameDoesntMatch , 1198node -> m_name .getContent ()); 1199return SLANG_FAIL ; 1200 } 1201 1202// If has the marker it is assumed reflected 1203node -> m_reflectionType = ReflectionType ::Reflected ; 1204return SLANG_OK ; 1205} 1206 1207SlangResult Parser ::_maybeParseType (UnownedStringSlice & outType ,Token & outName ) 1208{ 1209auto startCursor = m_reader .getCursor (); 1210 1211Index templateDepth = 0 ; 1212 1213TokenReader ::ParsingCursor nameCursor ; 1214 1215SlangResult res = _maybeParseType (templateDepth ,nameCursor ); 1216if (SLANG_FAILED (res )&& m_sink -> getErrorCount ()) 1217 { 1218return res ; 1219 } 1220 1221if (templateDepth != 0 ) 1222 { 1223m_sink -> diagnose (m_reader .peekToken (),CPPDiagnostics ::unexpectedTemplateClose ); 1224return SLANG_FAIL ; 1225 } 1226 1227if (nameCursor .isValid ()) 1228 { 1229const auto cursor = m_reader .getCursor (); 1230m_reader .setCursor (nameCursor ); 1231outName = m_reader .peekToken (); 1232m_reader .setCursor (cursor ); 1233 1234// Extract the contents 1235List < Token > toks ; 1236_getTypeTokens (startCursor ,nameCursor ,toks ); 1237outType = _concatTokens (toks .getBuffer (),toks .getCount ()); 1238 } 1239else 1240 { 1241// We can build up the out type, from the tokens we found 1242outType = _concatTokens (startCursor ); 1243 } 1244return SLANG_OK ; 1245} 1246 1247static bool _isBalancedOpen (TokenType tokenType ) 1248{ 1249return tokenType == TokenType ::LBrace || tokenType == TokenType ::LParent || 1250tokenType == TokenType ::LBracket ; 1251} 1252 1253static bool _isBalancedClose (TokenType tokenType ) 1254{ 1255return tokenType == TokenType ::RBrace || tokenType == TokenType ::RParent || 1256tokenType == TokenType ::RBracket ; 1257} 1258 1259static TokenType _getBalancedClose (TokenType tokenType ) 1260{ 1261SLANG_ASSERT (_isBalancedOpen (tokenType )); 1262switch (tokenType ) 1263 { 1264case TokenType ::LBrace : 1265return TokenType ::RBrace ; 1266case TokenType ::LParent : 1267return TokenType ::RParent ; 1268case TokenType ::LBracket : 1269return TokenType ::RBracket ; 1270default : 1271return TokenType ::Unknown ; 1272 } 1273} 1274 1275SlangResult Parser ::_parseBalanced (DiagnosticSink * sink ) 1276{ 1277const TokenType openTokenType = m_reader .peekTokenType (); 1278if (!_isBalancedOpen (openTokenType )) 1279 { 1280return SLANG_FAIL ; 1281 } 1282 1283// Save the start token 1284const Token startToken = m_reader .advanceToken (); 1285// Get the token type that would close the open 1286const TokenType closeTokenType = _getBalancedClose (openTokenType ); 1287 1288while (true) 1289 { 1290const TokenType tokenType = m_reader .peekTokenType (); 1291 1292// If we hit the closing token, we are done 1293if (tokenType == closeTokenType ) 1294 { 1295m_reader .advanceToken (); 1296return SLANG_OK ; 1297 } 1298 1299// If we hit a balanced open, recurse 1300if (_isBalancedOpen (tokenType )) 1301 { 1302SLANG_RETURN_ON_FAIL (_parseBalanced (sink )); 1303continue ; 1304 } 1305 1306// If we hit a close token that doesn't match, then the balancing has gone wrong 1307if (_isBalancedClose (tokenType )) 1308 { 1309// Only diagnose if required 1310if (sink ) 1311 { 1312sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::unexpectedUnbalancedToken ); 1313sink -> diagnose (startToken ,CPPDiagnostics ::seeOpen ); 1314 } 1315return SLANG_FAIL ; 1316 } 1317 1318// If we hit the end of the file and have not hit the closing token, then 1319// somethings gone wrong 1320if (tokenType == TokenType ::EndOfFile ) 1321 { 1322if (sink ) 1323 { 1324sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::unexpectedEndOfFile ); 1325sink -> diagnose (startToken ,CPPDiagnostics ::seeOpen ); 1326 } 1327 1328return SLANG_FAIL ; 1329 } 1330 1331// Skip the token 1332m_reader .advanceToken (); 1333 } 1334} 1335 1336SlangResult Parser ::_consumeBalancedParens () 1337{ 1338SLANG_ASSERT (m_reader .peekTokenType ()== TokenType ::LParent ); 1339 1340Index parenCount = 0 ; 1341 1342while (true) 1343 { 1344const TokenType tokenType = m_reader .peekTokenType (); 1345 1346switch (tokenType ) 1347 { 1348case TokenType ::LParent : 1349 { 1350parenCount ++ ; 1351break ; 1352 } 1353case TokenType ::RParent : 1354 { 1355-- parenCount ; 1356// If no more parens then we are done 1357if (parenCount == 0 ) 1358 { 1359m_reader .advanceToken (); 1360return SLANG_OK ; 1361 } 1362break ; 1363 } 1364case TokenType ::EndOfFile : 1365 { 1366// If we hit the end of the file, then not balanced 1367return SLANG_FAIL ; 1368 } 1369default : 1370break ; 1371 } 1372 1373m_reader .advanceToken (); 1374 } 1375} 1376 1377SlangResult Parser ::_parseExpression (List < Token >& outExprTokens ) 1378{ 1379Index parenCount = 0 ; 1380Index bracketCount = 0 ; 1381 1382// TODO(JS): NOTE! This doesn't handle an expression that contains a template params in 1383// Something<Arg1, 3>, because without knowing what Something is, it's not known if < is a 1384// comparison or or a 'template' bracket 1385// 1386// This can be worked around in the originating source by placing in parens 1387 1388while (true) 1389 { 1390TokenType tokenType = m_reader .peekTokenType (); 1391 1392switch (tokenType ) 1393 { 1394case TokenType ::LParent : 1395 { 1396parenCount ++ ; 1397break ; 1398 } 1399case TokenType ::RParent : 1400 { 1401// If no parens, and nothing else is open then we are done 1402if (parenCount == 0 ) 1403 { 1404if (bracketCount ) 1405 { 1406m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::cannotParseExpression ); 1407return SLANG_FAIL ; 1408 } 1409 1410return SLANG_OK ; 1411 } 1412-- parenCount ; 1413break ; 1414 } 1415case TokenType ::LBracket : 1416 { 1417bracketCount ++ ; 1418break ; 1419 } 1420case TokenType ::RBracket : 1421 { 1422// If no brackets are open we are done 1423if (bracketCount == 0 ) 1424 { 1425if (parenCount ) 1426 { 1427m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::cannotParseExpression ); 1428return SLANG_FAIL ; 1429 } 1430return SLANG_OK ; 1431 } 1432-- bracketCount ; 1433break ; 1434 } 1435case TokenType ::EndOfFile : 1436 { 1437if ((bracketCount |parenCount )== 0 ) 1438 { 1439return SLANG_OK ; 1440 } 1441m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::cannotParseExpression ); 1442return SLANG_FAIL ; 1443 } 1444case TokenType ::RBrace : 1445case TokenType ::Semicolon : 1446case TokenType ::Comma : 1447 { 1448if ((bracketCount |parenCount )== 0 ) 1449 { 1450return SLANG_OK ; 1451 } 1452break ; 1453 } 1454 1455default : 1456break ; 1457 } 1458 1459outExprTokens .add (m_reader .advanceToken ()); 1460 } 1461} 1462 1463SlangResult Parser ::_parseTypeDef () 1464{ 1465if (!m_currentScope -> canContainTypes ()) 1466 { 1467m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::cannotDeclareTypeInScope ); 1468return SLANG_FAIL ; 1469 } 1470 1471// Consume the typedef 1472SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier )); 1473 1474Token nameToken ; 1475// Parse the type 1476List < Token > toks ; 1477SLANG_RETURN_ON_FAIL (_maybeParseType (toks ,nameToken )); 1478 1479// Followed by the name 1480if (nameToken .type != TokenType ::Identifier ) 1481 { 1482SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& nameToken )); 1483 } 1484 1485if (Node ::lookupNameInScope (m_currentScope ,nameToken .getContent ())) 1486 { 1487m_sink -> diagnose ( 1488nameToken .loc , 1489CPPDiagnostics ::identifierAlreadyDefined , 1490nameToken .getContent ()); 1491return SLANG_FAIL ; 1492 } 1493 1494SLANG_RETURN_ON_FAIL (expect (TokenType ::Semicolon )); 1495 1496RefPtr < TypeDefNode > node = new TypeDefNode ; 1497node -> m_name = nameToken ; 1498node -> m_reflectionType = m_currentScope -> getContainedReflectionType (); 1499 1500// Set what aliases too 1501node -> m_targetTypeTokens .swapWith (toks ); 1502 1503m_currentScope -> addChild (node ); 1504 1505return SLANG_OK ; 1506} 1507 1508 1509bool Parser ::_isCtor () 1510{ 1511bool isCtor = false; 1512// It's a constructor 1513if (m_currentScope -> isClassLike ()&& m_reader .peekTokenType ()== TokenType ::Identifier && 1514m_reader .peekToken ().getContent ()== m_currentScope -> m_name .getContent ()) 1515 { 1516// We need to check it's followed immediately by ( to be sure it's a ctor 1517 1518auto cursor = m_reader .getCursor (); 1519m_reader .advanceToken (); 1520isCtor = (m_reader .peekTokenType ()== TokenType ::LParent ); 1521m_reader .setCursor (cursor ); 1522 } 1523 1524return isCtor ; 1525} 1526 1527bool isAlphaNumeric (char c ) 1528{ 1529return (c >='a' && c <='z' )|| (c >='A' && c <='Z' )|| (c >='0' && c <='9' ); 1530} 1531 1532SlangResult Parser ::_maybeParseContained (Node ** outNode ) 1533{ 1534* outNode = nullptr ; 1535 1536_maybeConsume (IdentifierStyle ::CallableMisc ); 1537 1538bool isStatic = false; 1539bool isVirtual = false; 1540 1541while (m_reader .peekTokenType ()== TokenType ::Identifier ) 1542 { 1543const IdentifierStyle style = 1544m_nodeTree -> m_identifierLookup -> get (m_reader .peekToken ().getContent ()); 1545 1546// Check for virtualness 1547if (style == IdentifierStyle ::Virtual ) 1548 { 1549isVirtual = true; 1550m_reader .advanceToken (); 1551continue ; 1552 } 1553 1554// Check if static 1555if (style == IdentifierStyle ::Static ) 1556 { 1557isStatic = true; 1558m_reader .advanceToken (); 1559continue ; 1560 } 1561 1562break ; 1563 } 1564 1565_maybeConsume (IdentifierStyle ::CallableMisc ); 1566 1567UnownedStringSlice typeName ; 1568Token nameToken ; 1569 1570bool isConstructor = false; 1571 1572if (m_currentScope -> isClassLike ()) 1573 { 1574// If it's a dtor 1575if (advanceIfToken (TokenType ::OpBitNot ,& nameToken )) 1576 { 1577// Dtor 1578// For Dtor we don't hold the full name just the ~ 1579Token tok ; 1580SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& tok )); 1581 1582if (tok .getContent ()!= m_currentScope -> m_name .getContent ()) 1583 { 1584m_sink -> diagnose ( 1585m_reader .peekLoc (), 1586CPPDiagnostics ::destructorNameDoesntMatch , 1587m_currentScope -> m_name .getContent ()); 1588return SLANG_FAIL ; 1589 } 1590 } 1591else if (_isCtor ()) 1592 { 1593nameToken = m_reader .advanceToken (); 1594isConstructor = true; 1595 } 1596 } 1597 1598// If don't have a name it's not a dtor or ctor, so see if it's a type 1599if (nameToken .type == TokenType ::Unknown ) 1600 { 1601if (SLANG_FAILED (_maybeParseType (typeName ,nameToken ))) 1602 { 1603if (m_sink -> getErrorCount ()) 1604 { 1605return SLANG_FAIL ; 1606 } 1607 1608_consumeToSync (); 1609return SLANG_OK ; 1610 } 1611 } 1612 1613if (nameToken .type == TokenType ::Unknown ) 1614 { 1615// Has a calling convention (must be a function/method) 1616Token callingConventionToken ; 1617advanceIfStyle (IdentifierStyle ::CallingConvention ,& callingConventionToken ); 1618 1619// Expecting a name 1620if (!advanceIfToken (TokenType ::Identifier ,& nameToken )) 1621 { 1622_consumeToSync (); 1623return SLANG_OK ; 1624 } 1625 } 1626 1627// Handles other scenarios, but here for catching operator overloading 1628if (nameToken .type == TokenType ::Identifier ) 1629 { 1630const auto style = m_nodeTree -> m_identifierLookup -> get (nameToken .getContent ()); 1631if (style != IdentifierStyle ::None ) 1632 { 1633_consumeToSync (); 1634return SLANG_OK ; 1635 } 1636 } 1637 1638if (m_reader .peekTokenType ()== TokenType ::LParent ) 1639 { 1640if (!m_currentScope -> canContainCallable ()) 1641 { 1642SLANG_RETURN_ON_FAIL (_consumeBalancedParens ()); 1643// Consume everything up to ; or { 1644SLANG_RETURN_ON_FAIL (_consumeToSync ()); 1645 1646return SLANG_OK ; 1647 } 1648 1649// Looks like it's a callable 1650m_reader .advanceToken (); 1651 1652List < CallableNode ::Param > params ; 1653 1654if (m_reader .peekTokenType ()!= TokenType ::RParent ) 1655 { 1656while (true) 1657 { 1658Token paramName ; 1659UnownedStringSlice type ; 1660SlangResult res = _maybeParseType (type ,paramName ); 1661 1662if (SLANG_FAILED (res )) 1663 { 1664m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::expectingType ); 1665return res ; 1666 } 1667 1668if (paramName .type != TokenType ::Identifier ) 1669 { 1670if (m_reader .peekTokenType ()== TokenType ::Identifier ) 1671 { 1672paramName = m_reader .advanceToken (); 1673 } 1674 } 1675 1676// If we have a name check for default value 1677if (paramName .type == TokenType ::Identifier && advanceIfToken (TokenType ::OpAssign )) 1678 { 1679// Check if we have a default value 1680List < Token > exprTokens ; 1681SLANG_RETURN_ON_FAIL (_parseExpression (exprTokens )); 1682 } 1683 1684CallableNode ::Param param ; 1685param .m_name = paramName ; 1686param .m_type = type ; 1687 1688params .add (param ); 1689 1690 { 1691const auto peekType = m_reader .peekTokenType (); 1692if (peekType == TokenType ::RParent ) 1693 { 1694break ; 1695 } 1696if (peekType == TokenType ::Comma ) 1697 { 1698m_reader .advanceToken (); 1699continue ; 1700 } 1701 } 1702 1703m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::expectingToken ,", or ) or =" ); 1704return SLANG_FAIL ; 1705 } 1706 } 1707 1708// Skip ) 1709m_reader .advanceToken (); 1710 1711// Parse suffix 1712bool isPure = false; 1713 1714// const? 1715_maybeConsume (IdentifierStyle ::TypeModifier ); 1716 1717if (isConstructor ) 1718 { 1719// Initializer list 1720if (advanceIfToken (TokenType ::Colon )) 1721 { 1722while (true) 1723 { 1724auto peekType = m_reader .peekTokenType (); 1725if (peekType == TokenType ::Semicolon || peekType == TokenType ::LBrace || 1726peekType == TokenType ::EndOfFile ) 1727 { 1728break ; 1729 } 1730// Consume 1731m_reader .advanceToken (); 1732 } 1733 } 1734 } 1735 1736// = 0 ? or = default 1737if (advanceIfToken (TokenType ::OpAssign )) 1738 { 1739if (m_reader .peekTokenType ()== TokenType ::IntegerLiteral ) 1740 { 1741Int value = -1 ; 1742if (SLANG_SUCCEEDED ( 1743StringUtil ::parseInt (m_reader .peekToken ().getContent (),value ))&& 1744value == 0 ) 1745 { 1746isPure = true; 1747m_reader .advanceToken (); 1748 } 1749else 1750 { 1751m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::expectingToken ,"0" ); 1752return SLANG_FAIL ; 1753 } 1754 } 1755else if (advanceIfStyle (IdentifierStyle ::Default )) 1756 { 1757 } 1758else 1759 { 1760m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::cannotParseCallable ); 1761return SLANG_FAIL ; 1762 } 1763 } 1764 1765if (m_reader .peekTokenType ()== TokenType ::Semicolon ) 1766 { 1767m_reader .advanceToken (); 1768 } 1769else if (m_reader .peekTokenType ()== TokenType ::LBrace ) 1770 { 1771SLANG_RETURN_ON_FAIL (consumeToClosingBrace ()); 1772 } 1773else 1774 { 1775m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::expectingToken ,"; or {" ); 1776return SLANG_FAIL ; 1777 } 1778 1779RefPtr < CallableNode > callableNode = new CallableNode ; 1780 1781callableNode -> m_returnType = typeName ; 1782callableNode -> m_name = nameToken ; 1783callableNode -> m_reflectionType = m_currentScope -> getContainedReflectionType (); 1784 1785callableNode -> m_isVirtual = isVirtual ; 1786callableNode -> m_isPure = isPure ; 1787callableNode -> m_isStatic = isStatic ; 1788 1789callableNode -> m_params .swapWith (params ); 1790 1791Node * nodeWithName = m_currentScope -> findChild (nameToken .getContent ()); 1792 1793if (nodeWithName ) 1794 { 1795CallableNode * initialOverload = as < CallableNode > (nodeWithName ); 1796if (!initialOverload ) 1797 { 1798m_sink -> diagnose (m_reader .peekLoc (),CPPDiagnostics ::cannotOverload ); 1799m_sink -> diagnose (nodeWithName -> getSourceLoc (),CPPDiagnostics ::seeDeclarationOf ); 1800return SLANG_FAIL ; 1801 } 1802 1803callableNode -> m_nextOverload = initialOverload -> m_nextOverload ; 1804initialOverload -> m_nextOverload = initialOverload ; 1805 1806m_currentScope -> addChildIgnoringName (callableNode ); 1807 } 1808else 1809 { 1810m_currentScope -> addChild (callableNode ); 1811 } 1812 1813* outNode = callableNode ; 1814return SLANG_OK ; 1815 } 1816else 1817 { 1818// Looks like variable 1819if (!m_currentScope -> canContainFields ()|| nameToken .type != TokenType ::Identifier ) 1820 { 1821_consumeToSync (); 1822return SLANG_OK ; 1823 } 1824 1825// Check if has a default value 1826if (advanceIfToken (TokenType ::OpAssign )) 1827 { 1828List < Token > exprTokens ; 1829SLANG_RETURN_ON_FAIL (_parseExpression (exprTokens )); 1830 } 1831 1832// Hit end of field/variable 1833if (m_reader .peekTokenType ()== TokenType ::Semicolon ) 1834 { 1835RefPtr < FieldNode > fieldNode = new FieldNode ; 1836 1837fieldNode -> m_fieldType = typeName ; 1838fieldNode -> m_name = nameToken ; 1839fieldNode -> m_reflectionType = m_currentScope -> getContainedReflectionType (); 1840fieldNode -> m_isStatic = isStatic ; 1841if (fieldNode -> m_reflectionType == ReflectionType ::Reflected ) 1842 { 1843static const char * illegalTypes []= { 1844"size_t" , 1845"Int" , 1846"UInt" , 1847"Index" , 1848"Count" , 1849"UIndex" , 1850"UCount" , 1851"PtrInt" , 1852"intptr_t" , 1853"uintptr_t" }; 1854for (const auto & illegalType :illegalTypes ) 1855 { 1856int index = typeName .indexOf (UnownedStringSlice (illegalType )); 1857if (index != -1 ) 1858 { 1859index += UnownedStringSlice (illegalType ).getLength (); 1860if (index >=typeName .getLength ()|| !isAlphaNumeric (typeName [index ])) 1861 { 1862// Cannot use this type in a field (as it's arch dependent 1863m_sink -> diagnose ( 1864nameToken , 1865CPPDiagnostics ::cannoseUseArchDependentType , 1866illegalType ); 1867return SLANG_FAIL ; 1868 } 1869 } 1870 } 1871 } 1872m_currentScope -> addChild (fieldNode ); 1873 1874* outNode = fieldNode ; 1875return SLANG_OK ; 1876 } 1877 } 1878 1879_consumeToSync (); 1880return SLANG_OK ; 1881} 1882 1883/* static */ Node ::Kind Parser ::_toNodeKind (IdentifierStyle style ) 1884{ 1885switch (style ) 1886 { 1887case IdentifierStyle ::Class : 1888return Node ::Kind ::ClassType ; 1889case IdentifierStyle ::Struct : 1890return Node ::Kind ::StructType ; 1891case IdentifierStyle ::Namespace : 1892return Node ::Kind ::Namespace ; 1893case IdentifierStyle ::Enum : 1894return Node ::Kind ::Enum ; 1895case IdentifierStyle ::TypeDef : 1896return Node ::Kind ::TypeDef ; 1897default : 1898return Node ::Kind ::Invalid ; 1899 } 1900} 1901 1902static UnownedStringSlice _trimUnderscorePrefix (const UnownedStringSlice & slice ) 1903{ 1904if (slice .getLength ()&& slice [0 ]== '_' ) 1905 { 1906return UnownedStringSlice (slice .begin ()+ 1 ,slice .end ()); 1907 } 1908else 1909 { 1910return slice ; 1911 } 1912} 1913 1914SlangResult Parser ::_parsePreDeclare () 1915{ 1916// Skip the declare type token 1917m_reader .advanceToken (); 1918 1919SLANG_RETURN_ON_FAIL (expect (TokenType ::LParent )); 1920 1921// Get the typeSet 1922Token typeSetToken ; 1923SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& typeSetToken )); 1924TypeSet * typeSet = m_nodeTree -> getOrAddTypeSet (typeSetToken .getContent ()); 1925 1926SLANG_RETURN_ON_FAIL (expect (TokenType ::Comma )); 1927 1928// Get the type of type 1929Node ::Kind nodeKind ; 1930 { 1931Token typeToken ; 1932SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& typeToken )); 1933 1934const IdentifierStyle style = m_nodeTree -> m_identifierLookup -> get (typeToken .getContent ()); 1935 1936if (style != IdentifierStyle ::Struct && style != IdentifierStyle ::Class ) 1937 { 1938m_sink -> diagnose ( 1939typeToken , 1940CPPDiagnostics ::expectingTypeKeyword , 1941typeToken .getContent ()); 1942return SLANG_FAIL ; 1943 } 1944nodeKind = _toNodeKind (style ); 1945 } 1946 1947Token name ; 1948Token super ; 1949 1950SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& name )); 1951 1952if (advanceIfToken (TokenType ::Colon )) 1953 { 1954SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& super )); 1955 } 1956 1957SLANG_RETURN_ON_FAIL (expect (TokenType ::RParent )); 1958 1959switch (nodeKind ) 1960 { 1961case Node ::Kind ::ClassType : 1962case Node ::Kind ::StructType : 1963 { 1964RefPtr < ClassLikeNode > node (new ClassLikeNode (nodeKind )); 1965 1966node -> m_name = name ; 1967node -> m_super = super ; 1968node -> m_typeSet = typeSet ; 1969 1970// Assume it is reflected 1971node -> m_reflectionType = ReflectionType ::Reflected ; 1972 1973SLANG_RETURN_ON_FAIL (pushScope (node )); 1974// Pop out of the node 1975popScope (); 1976break ; 1977 } 1978default : 1979 { 1980return SLANG_FAIL ; 1981 } 1982 } 1983 1984 1985return SLANG_OK ; 1986} 1987 1988SlangResult Parser ::_parseTypeSet () 1989{ 1990// Skip the declare type token 1991m_reader .advanceToken (); 1992 1993SLANG_RETURN_ON_FAIL (expect (TokenType ::LParent )); 1994 1995Token typeSetToken ; 1996SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& typeSetToken )); 1997 1998TypeSet * typeSet = m_nodeTree -> getOrAddTypeSet (typeSetToken .getContent ()); 1999 2000SLANG_RETURN_ON_FAIL (expect (TokenType ::Comma )); 2001 2002// Get the type of type 2003Token typeToken ; 2004SLANG_RETURN_ON_FAIL (expect (TokenType ::Identifier ,& typeToken )); 2005 2006SLANG_RETURN_ON_FAIL (expect (TokenType ::RParent )); 2007 2008// Set the typename 2009typeSet -> m_typeName = typeToken .getContent (); 2010 2011return SLANG_OK ; 2012} 2013 2014SlangResult Parser ::parse (SourceOrigin * sourceOrigin ,const Options * options ) 2015{ 2016SLANG_ASSERT (options ); 2017m_options = options ; 2018 2019// Set the current origin 2020m_sourceOrigin = sourceOrigin ; 2021 2022SourceFile * sourceFile = sourceOrigin -> m_sourceFile ; 2023 2024SourceManager * manager = sourceFile -> getSourceManager (); 2025 2026SourceView * sourceView = manager -> createSourceView (sourceFile ,nullptr ,SourceLoc ::fromRaw (0 )); 2027 2028Lexer lexer ; 2029 2030// Set up the scope stack 2031m_scopeStack .clear (); 2032 2033m_currentScope = m_nodeTree -> m_rootNode ; 2034m_scopeStack .add (m_currentScope ); 2035 2036if (!options -> m_requireMark ) 2037 { 2038m_currentScope -> m_reflectionOverride = ReflectionType ::Reflected ; 2039 } 2040 2041lexer .initialize (sourceView ,m_sink ,m_nodeTree -> m_namePool ,manager -> getMemoryArena ()); 2042m_tokenList = lexer .lexAllSemanticTokens (); 2043// See if there were any errors 2044if (m_sink -> getErrorCount ()) 2045 { 2046return SLANG_FAIL ; 2047 } 2048 2049m_reader = TokenReader (m_tokenList ); 2050 2051while (true) 2052 { 2053switch (m_reader .peekTokenType ()) 2054 { 2055case TokenType ::OpBitNot : 2056 { 2057// Handle dtor 2058if (m_currentScope -> isClassLike ()) 2059 { 2060Node * containedNode = nullptr ; 2061SLANG_RETURN_ON_FAIL (_maybeParseContained (& containedNode )); 2062 } 2063else 2064 { 2065// consume 2066m_reader .advanceToken (); 2067 } 2068break ; 2069 } 2070case TokenType ::Identifier : 2071 { 2072const IdentifierStyle style = 2073m_nodeTree -> m_identifierLookup -> get (m_reader .peekToken ().getContent ()); 2074 2075switch (style ) 2076 { 2077case IdentifierStyle ::Extern : 2078 { 2079m_reader .advanceToken (); 2080 2081Token externType ; 2082SLANG_RETURN_ON_FAIL (expect (TokenType ::StringLiteral ,& externType )); 2083 2084if (advanceIfToken (TokenType ::LBrace )) 2085 { 2086// Push a 'special' scope (which is basically transparent) 2087pushScope (nullptr ); 2088 } 2089break ; 2090 } 2091case IdentifierStyle ::Template : 2092 { 2093SLANG_RETURN_ON_FAIL (_consumeTemplate ()); 2094break ; 2095 } 2096case IdentifierStyle ::PreDeclare : 2097 { 2098SLANG_RETURN_ON_FAIL (_parsePreDeclare ()); 2099break ; 2100 } 2101case IdentifierStyle ::TypeSet : 2102 { 2103SLANG_RETURN_ON_FAIL (_parseTypeSet ()); 2104break ; 2105 } 2106case IdentifierStyle ::Reflected : 2107 { 2108m_reader .advanceToken (); 2109if (m_currentScope ) 2110 { 2111m_currentScope -> m_reflectionOverride = ReflectionType ::Reflected ; 2112 } 2113break ; 2114 } 2115case IdentifierStyle ::Unreflected : 2116 { 2117m_reader .advanceToken (); 2118if (m_currentScope ) 2119 { 2120m_currentScope -> m_reflectionOverride = ReflectionType ::NotReflected ; 2121 } 2122break ; 2123 } 2124case IdentifierStyle ::Access : 2125 { 2126m_reader .advanceToken (); 2127SLANG_RETURN_ON_FAIL (expect (TokenType ::Colon )); 2128break ; 2129 } 2130case IdentifierStyle ::TypeDef : 2131 { 2132if (isTypeEnabled (Node ::Kind ::TypeDef )) 2133 { 2134SLANG_RETURN_ON_FAIL (_parseTypeDef ()); 2135 } 2136else 2137 { 2138m_reader .advanceToken (); 2139SLANG_RETURN_ON_FAIL (_consumeToSync ()); 2140 } 2141break ; 2142 } 2143default : 2144 { 2145IdentifierFlags flags = getFlags (style ); 2146 2147if (flags & IdentifierFlag ::StartScope ) 2148 { 2149Node ::Kind kind = _toNodeKind (style ); 2150SLANG_ASSERT (kind != Node ::Kind ::Invalid ); 2151 2152if (isTypeEnabled (kind )) 2153 { 2154SLANG_RETURN_ON_FAIL (_maybeParseNode (kind )); 2155 } 2156else 2157 { 2158SLANG_RETURN_ON_FAIL (_maybeConsumeScope ()); 2159 } 2160 } 2161else 2162 { 2163UnownedStringSlice content = m_reader .peekToken ().getContent (); 2164 2165// If it's a marker handle it 2166if (_isMarker (content )) 2167 { 2168if (!m_currentScope -> isClassLike ()) 2169 { 2170m_sink -> diagnose ( 2171m_reader .peekLoc (), 2172CPPDiagnostics ::classMarkerOutsideOfClass ); 2173return SLANG_FAIL ; 2174 } 2175 2176SLANG_RETURN_ON_FAIL (_parseMarker ()); 2177break ; 2178 } 2179 2180if (m_options -> m_markPrefix .getLength ()> 0 && 2181content .startsWith (m_options -> m_markPrefix .getUnownedSlice ())) 2182 { 2183SLANG_RETURN_ON_FAIL (_parseSpecialMacro ()); 2184break ; 2185 } 2186 2187 2188// Special case the node that's the root of the hierarchy (as far as 2189// reflection is concerned) This could be a field 2190if (m_currentScope -> canContainFields ()|| 2191m_currentScope -> canContainCallable ()) 2192 { 2193Node * containedNode = nullptr ; 2194SLANG_RETURN_ON_FAIL (_maybeParseContained (& containedNode )); 2195 } 2196else 2197 { 2198m_reader .advanceToken (); 2199 } 2200 } 2201break ; 2202 } 2203 } 2204break ; 2205 } 2206case TokenType ::LBrace : 2207 { 2208SLANG_RETURN_ON_FAIL (consumeToClosingBrace ()); 2209break ; 2210 } 2211case TokenType ::RBrace : 2212 { 2213SLANG_RETURN_ON_FAIL (popScope ()); 2214m_reader .advanceToken (); 2215break ; 2216 } 2217case TokenType ::EndOfFile : 2218 { 2219// Okay we need to confirm that we are in the root node, and with no open braces 2220if (m_currentScope != m_nodeTree -> getRootNode ()) 2221 { 2222m_sink -> diagnose (m_reader .peekToken (),CPPDiagnostics ::braceOpenAtEndOfFile ); 2223return SLANG_FAIL ; 2224 } 2225if (m_sink -> getErrorCount ()) 2226return SLANG_FAIL ; 2227return SLANG_OK ; 2228 } 2229case TokenType ::Pound : 2230 { 2231Token token = m_reader .peekToken (); 2232if (token .flags & TokenFlag ::AtStartOfLine ) 2233 { 2234// We are just going to ignore all of these for now.... 2235m_reader .advanceToken (); 2236for (;;) 2237 { 2238auto t = m_reader .peekToken (); 2239if (t .type == TokenType ::EndOfFile || (t .flags & TokenFlag ::AtStartOfLine )) 2240 { 2241break ; 2242 } 2243m_reader .advanceToken (); 2244 } 2245break ; 2246 } 2247// Skip it then 2248m_reader .advanceToken (); 2249break ; 2250 } 2251default : 2252 { 2253// Skip it then 2254m_reader .advanceToken (); 2255break ; 2256 } 2257 } 2258 } 2259} 2260 2261}// namespace CppParse