yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Lauro OyenMove c++ parsing code from slang-cpp-extractor to static library (#5675)eaa8dcfcc

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