summaryrefslogtreecommitdiffstats
path: root/source/slang/parser.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-05-31 17:20:37 -0400
committerGitHub <noreply@github.com>2019-05-31 17:20:37 -0400
commit6cbc3929a54d37bd23cb5efa8e3320ba02f78b2f (patch)
tree5a23cb47782e9e2a77762c90dd35da1005eba8d0 /source/slang/parser.cpp
parentb81ff3ef968d1cc4e954b31a1812b3c391d17b02 (diff)
Use slang- prefix on slang compiler and core source (#973)
* Prefixing source files in source/slang with slang- * Prefix source in source/slang with slang- prefix. * Rename core source files with slang- prefix. * Update project files. * Fix problems from automatic merge.
Diffstat (limited to 'source/slang/parser.cpp')
-rw-r--r--source/slang/parser.cpp4725
1 files changed, 0 insertions, 4725 deletions
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
deleted file mode 100644
index 825aea324..000000000
--- a/source/slang/parser.cpp
+++ /dev/null
@@ -1,4725 +0,0 @@
-#include "parser.h"
-
-#include <assert.h>
-
-#include "compiler.h"
-#include "lookup.h"
-#include "visitor.h"
-
-namespace Slang
-{
- // pre-declare
- static Name* getName(Parser* parser, String const& text);
-
- // Helper class useful to build a list of modifiers.
- struct ModifierListBuilder
- {
- ModifierListBuilder()
- {
- m_next = &m_result;
- }
- void add(Modifier* modifier)
- {
- // Doesn't handle SharedModifiers
- SLANG_ASSERT(as<SharedModifiers>(modifier) == nullptr);
-
- // Splice at end
- *m_next = modifier;
- m_next = &modifier->next;
- }
- template <typename T>
- T* find() const
- {
- Modifier* cur = m_result;
- while (cur)
- {
- T* castCur = as<T>(cur);
- if (castCur)
- {
- return castCur;
- }
- cur = cur->next;
- }
- return nullptr;
- }
- template <typename T>
- bool hasType() const
- {
- return find<T>() != nullptr;
- }
- RefPtr<Modifier> getFirst() { return m_result; };
- protected:
-
- RefPtr<Modifier> m_result;
- RefPtr<Modifier>* m_next;
- };
-
- enum Precedence : int
- {
- Invalid = -1,
- Comma,
- Assignment,
- TernaryConditional,
- LogicalOr,
- LogicalAnd,
- BitOr,
- BitXor,
- BitAnd,
- EqualityComparison,
- RelationalComparison,
- BitShift,
- Additive,
- Multiplicative,
- Prefix,
- Postfix,
- };
-
- // TODO: implement two pass parsing for file reference and struct type recognition
-
- class Parser
- {
- public:
- NamePool* namePool;
- SourceLanguage sourceLanguage;
-
- NamePool* getNamePool() { return namePool; }
- SourceLanguage getSourceLanguage() { return sourceLanguage; }
-
- int anonymousCounter = 0;
-
- RefPtr<Scope> outerScope;
- RefPtr<Scope> currentScope;
-
- TokenReader tokenReader;
- DiagnosticSink* sink;
- int genericDepth = 0;
-
- // Have we seen any `import` declarations? If so, we need
- // to parse function bodies completely, even if we are in
- // "rewrite" mode.
- bool haveSeenAnyImportDecls = false;
-
- // Is the parser in a "recovering" state?
- // During recovery we don't emit additional errors, until we find
- // a token that we expected, when we exit recovery.
- bool isRecovering = false;
-
- void FillPosition(SyntaxNode * node)
- {
- node->loc = tokenReader.PeekLoc();
- }
- void PushScope(ContainerDecl* containerDecl)
- {
- RefPtr<Scope> newScope = new Scope();
- newScope->containerDecl = containerDecl;
- newScope->parent = currentScope;
-
- currentScope = newScope;
- }
-
- void pushScopeAndSetParent(ContainerDecl* containerDecl)
- {
- containerDecl->ParentDecl = currentScope->containerDecl;
- PushScope(containerDecl);
- }
-
- void PopScope()
- {
- currentScope = currentScope->parent;
- }
- Parser(
- Session* session,
- TokenSpan const& _tokens,
- DiagnosticSink * sink,
- RefPtr<Scope> const& outerScope)
- : tokenReader(_tokens)
- , sink(sink)
- , outerScope(outerScope)
- , m_session(session)
- {}
- Parser(const Parser & other) = default;
-
- Session* m_session = nullptr;
- Session* getSession() { return m_session; }
-
- Token ReadToken();
- Token ReadToken(TokenType type);
- Token ReadToken(const char * string);
- bool LookAheadToken(TokenType type, int offset = 0);
- bool LookAheadToken(const char * string, int offset = 0);
- void parseSourceFile(ModuleDecl* program);
- RefPtr<Decl> ParseStruct();
- RefPtr<ClassDecl> ParseClass();
- RefPtr<Stmt> ParseStatement();
- RefPtr<Stmt> parseBlockStatement();
- RefPtr<DeclStmt> parseVarDeclrStatement(Modifiers modifiers);
- RefPtr<IfStmt> parseIfStatement();
- RefPtr<ForStmt> ParseForStatement();
- RefPtr<WhileStmt> ParseWhileStatement();
- RefPtr<DoWhileStmt> ParseDoWhileStatement();
- RefPtr<BreakStmt> ParseBreakStatement();
- RefPtr<ContinueStmt> ParseContinueStatement();
- RefPtr<ReturnStmt> ParseReturnStatement();
- RefPtr<ExpressionStmt> ParseExpressionStatement();
- RefPtr<Expr> ParseExpression(Precedence level = Precedence::Comma);
-
- // Parse an expression that might be used in an initializer or argument context, so we should avoid operator-comma
- inline RefPtr<Expr> ParseInitExpr() { return ParseExpression(Precedence::Assignment); }
- inline RefPtr<Expr> ParseArgExpr() { return ParseExpression(Precedence::Assignment); }
-
- RefPtr<Expr> ParseLeafExpression();
- RefPtr<ParamDecl> ParseParameter();
- RefPtr<Expr> ParseType();
- TypeExp ParseTypeExp();
-
- Parser & operator = (const Parser &) = delete;
- };
-
- // Forward Declarations
-
- static void ParseDeclBody(
- Parser* parser,
- ContainerDecl* containerDecl,
- TokenType closingToken);
-
- static RefPtr<Decl> parseEnumDecl(Parser* parser);
-
- // Parse the `{}`-delimeted body of an aggregate type declaration
- static void parseAggTypeDeclBody(
- Parser* parser,
- AggTypeDeclBase* decl);
-
- static RefPtr<Modifier> ParseOptSemantics(
- Parser* parser);
-
- static void ParseOptSemantics(
- Parser* parser,
- Decl* decl);
-
- static RefPtr<DeclBase> ParseDecl(
- Parser* parser,
- ContainerDecl* containerDecl);
-
- static RefPtr<Decl> ParseSingleDecl(
- Parser* parser,
- ContainerDecl* containerDecl);
-
- //
-
- static void Unexpected(
- Parser* parser)
- {
- // Don't emit "unexpected token" errors if we are in recovering mode
- if (!parser->isRecovering)
- {
- parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedToken,
- parser->tokenReader.PeekTokenType());
-
- // Switch into recovery mode, to suppress additional errors
- parser->isRecovering = true;
- }
- }
-
- static void Unexpected(
- Parser* parser,
- char const* expected)
- {
- // Don't emit "unexpected token" errors if we are in recovering mode
- if (!parser->isRecovering)
- {
- parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedTokenExpectedTokenName,
- parser->tokenReader.PeekTokenType(),
- expected);
-
- // Switch into recovery mode, to suppress additional errors
- parser->isRecovering = true;
- }
- }
-
- static void Unexpected(
- Parser* parser,
- TokenType expected)
- {
- // Don't emit "unexpected token" errors if we are in recovering mode
- if (!parser->isRecovering)
- {
- parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedTokenExpectedTokenType,
- parser->tokenReader.PeekTokenType(),
- expected);
-
- // Switch into recovery mode, to suppress additional errors
- parser->isRecovering = true;
- }
- }
-
- static TokenType SkipToMatchingToken(TokenReader* reader, TokenType tokenType);
-
- // Skip a singel balanced token, which is either a single token in
- // the common case, or a matched pair of tokens for `()`, `[]`, and `{}`
- static TokenType SkipBalancedToken(
- TokenReader* reader)
- {
- TokenType tokenType = reader->AdvanceToken().type;
- switch (tokenType)
- {
- default:
- break;
-
- case TokenType::LParent: tokenType = SkipToMatchingToken(reader, TokenType::RParent); break;
- case TokenType::LBrace: tokenType = SkipToMatchingToken(reader, TokenType::RBrace); break;
- case TokenType::LBracket: tokenType = SkipToMatchingToken(reader, TokenType::RBracket); break;
- }
- return tokenType;
- }
-
- // Skip balanced
- static TokenType SkipToMatchingToken(
- TokenReader* reader,
- TokenType tokenType)
- {
- for (;;)
- {
- if (reader->IsAtEnd()) return TokenType::EndOfFile;
- if (reader->PeekTokenType() == tokenType)
- {
- reader->AdvanceToken();
- return tokenType;
- }
- SkipBalancedToken(reader);
- }
- }
-
- // Is the given token type one that is used to "close" a
- // balanced construct.
- static bool IsClosingToken(TokenType tokenType)
- {
- switch (tokenType)
- {
- case TokenType::EndOfFile:
- case TokenType::RBracket:
- case TokenType::RParent:
- case TokenType::RBrace:
- return true;
-
- default:
- return false;
- }
- }
-
-
- // Expect an identifier token with the given content, and consume it.
- Token Parser::ReadToken(const char* expected)
- {
- if (tokenReader.PeekTokenType() == TokenType::Identifier
- && tokenReader.PeekToken().Content == expected)
- {
- isRecovering = false;
- return tokenReader.AdvanceToken();
- }
-
- if (!isRecovering)
- {
- Unexpected(this, expected);
- return tokenReader.PeekToken();
- }
- else
- {
- // Try to find a place to recover
- for (;;)
- {
- // The token we expected?
- // Then exit recovery mode and pretend like all is well.
- if (tokenReader.PeekTokenType() == TokenType::Identifier
- && tokenReader.PeekToken().Content == expected)
- {
- isRecovering = false;
- return tokenReader.AdvanceToken();
- }
-
-
- // Don't skip past any "closing" tokens.
- if (IsClosingToken(tokenReader.PeekTokenType()))
- {
- return tokenReader.PeekToken();
- }
-
- // Skip balanced tokens and try again.
- SkipBalancedToken(&tokenReader);
- }
- }
- }
-
- Token Parser::ReadToken()
- {
- return tokenReader.AdvanceToken();
- }
-
- static bool TryRecover(
- Parser* parser,
- TokenType const* recoverBefore,
- int recoverBeforeCount,
- TokenType const* recoverAfter,
- int recoverAfterCount)
- {
- if (!parser->isRecovering)
- return true;
-
- // Determine if we are looking for common closing tokens,
- // so that we can know whether or we are allowed to skip
- // over them.
-
- bool lookingForEOF = false;
- bool lookingForRCurly = false;
- bool lookingForRParen = false;
- bool lookingForRSquare = false;
-
- for (int ii = 0; ii < recoverBeforeCount; ++ii)
- {
- switch (recoverBefore[ii])
- {
- default:
- break;
-
- case TokenType::EndOfFile: lookingForEOF = true; break;
- case TokenType::RBrace: lookingForRCurly = true; break;
- case TokenType::RParent: lookingForRParen = true; break;
- case TokenType::RBracket: lookingForRSquare = true; break;
- }
- }
- for (int ii = 0; ii < recoverAfterCount; ++ii)
- {
- switch (recoverAfter[ii])
- {
- default:
- break;
-
- case TokenType::EndOfFile: lookingForEOF = true; break;
- case TokenType::RBrace: lookingForRCurly = true; break;
- case TokenType::RParent: lookingForRParen = true; break;
- case TokenType::RBracket: lookingForRSquare = true; break;
- }
- }
-
- TokenReader* tokenReader = &parser->tokenReader;
- for (;;)
- {
- TokenType peek = tokenReader->PeekTokenType();
-
- // Is the next token in our recover-before set?
- // If so, then we have recovered successfully!
- for (int ii = 0; ii < recoverBeforeCount; ++ii)
- {
- if (peek == recoverBefore[ii])
- {
- parser->isRecovering = false;
- return true;
- }
- }
-
- // If we are looking at a token in our recover-after set,
- // then consume it and recover
- for (int ii = 0; ii < recoverAfterCount; ++ii)
- {
- if (peek == recoverAfter[ii])
- {
- tokenReader->AdvanceToken();
- parser->isRecovering = false;
- return true;
- }
- }
-
- // Don't try to skip past end of file
- if (peek == TokenType::EndOfFile)
- return false;
-
- switch (peek)
- {
- // Don't skip past simple "closing" tokens, *unless*
- // we are looking for a closing token
- case TokenType::RParent:
- case TokenType::RBracket:
- if (lookingForRParen || lookingForRSquare || lookingForRCurly || lookingForEOF)
- {
- // We are looking for a closing token, so it is okay to skip these
- }
- else
- return false;
- break;
-
- // Don't skip a `}`, to avoid spurious errors,
- // with the exception of when we are looking for EOF
- case TokenType::RBrace:
- if (lookingForRCurly || lookingForEOF)
- {
- // We are looking for end-of-file, so it is okay to skip here
- }
- else
- {
- return false;
- }
- }
-
- // Skip balanced tokens and try again.
- TokenType skipped = SkipBalancedToken(tokenReader);
-
- // If we happened to find a matched pair of tokens, and
- // the end of it was a token we were looking for,
- // then recover here
- for (int ii = 0; ii < recoverAfterCount; ++ii)
- {
- if (skipped == recoverAfter[ii])
- {
- parser->isRecovering = false;
- return true;
- }
- }
- }
- }
-
- static bool TryRecoverBefore(
- Parser* parser,
- TokenType before0)
- {
- TokenType recoverBefore[] = { before0 };
- return TryRecover(parser, recoverBefore, 1, nullptr, 0);
- }
-
- // Default recovery strategy, to use inside `{}`-delimeted blocks.
- static bool TryRecover(
- Parser* parser)
- {
- TokenType recoverBefore[] = { TokenType::RBrace };
- TokenType recoverAfter[] = { TokenType::Semicolon };
- return TryRecover(parser, recoverBefore, 1, recoverAfter, 1);
- }
-
- Token Parser::ReadToken(TokenType expected)
- {
- if (tokenReader.PeekTokenType() == expected)
- {
- isRecovering = false;
- return tokenReader.AdvanceToken();
- }
-
- if (!isRecovering)
- {
- Unexpected(this, expected);
- return tokenReader.PeekToken();
- }
- else
- {
- // Try to find a place to recover
- if (TryRecoverBefore(this, expected))
- {
- isRecovering = false;
- return tokenReader.AdvanceToken();
- }
-
- return tokenReader.PeekToken();
- }
- }
-
- bool Parser::LookAheadToken(const char * string, int offset)
- {
- TokenReader r = tokenReader;
- for (int ii = 0; ii < offset; ++ii)
- r.AdvanceToken();
-
- return r.PeekTokenType() == TokenType::Identifier
- && r.PeekToken().Content == string;
-}
-
- bool Parser::LookAheadToken(TokenType type, int offset)
- {
- TokenReader r = tokenReader;
- for (int ii = 0; ii < offset; ++ii)
- r.AdvanceToken();
-
- return r.PeekTokenType() == type;
- }
-
- // Consume a token and return true it if matches, otherwise false
- bool AdvanceIf(Parser* parser, TokenType tokenType)
- {
- if (parser->LookAheadToken(tokenType))
- {
- parser->ReadToken();
- return true;
- }
- return false;
- }
-
- // Consume a token and return true it if matches, otherwise false
- bool AdvanceIf(Parser* parser, char const* text)
- {
- if (parser->LookAheadToken(text))
- {
- parser->ReadToken();
- return true;
- }
- return false;
- }
-
- // Consume a token and return true if it matches, otherwise check
- // for end-of-file and expect that token (potentially producing
- // an error) and return true to maintain forward progress.
- // Otherwise return false.
- bool AdvanceIfMatch(Parser* parser, TokenType tokenType)
- {
- // If we've run into a syntax error, but haven't recovered inside
- // the block, then try to recover here.
- if (parser->isRecovering)
- {
- TryRecoverBefore(parser, tokenType);
- }
- if (AdvanceIf(parser, tokenType))
- return true;
- if (parser->tokenReader.PeekTokenType() == TokenType::EndOfFile)
- {
- parser->ReadToken(tokenType);
- return true;
- }
- return false;
- }
-
- RefPtr<RefObject> ParseTypeDef(Parser* parser, void* /*userData*/)
- {
- RefPtr<TypeDefDecl> typeDefDecl = new TypeDefDecl();
-
- // TODO(tfoley): parse an actual declarator
- auto type = parser->ParseTypeExp();
-
- auto nameToken = parser->ReadToken(TokenType::Identifier);
- typeDefDecl->loc = nameToken.loc;
-
- typeDefDecl->nameAndLoc = NameLoc(nameToken);
- typeDefDecl->type = type;
-
- return typeDefDecl;
- }
-
- // Add a modifier to a list of modifiers being built
- static void AddModifier(RefPtr<Modifier>** ioModifierLink, RefPtr<Modifier> modifier)
- {
- RefPtr<Modifier>*& modifierLink = *ioModifierLink;
-
- // We'd like to add the modifier to the end of the list,
- // but we need to be careful, in case there is a "shared"
- // section of modifiers for multiple declarations.
- //
- // TODO: This whole approach is a mess because we are "accidentally quadratic"
- // when adding many modifiers.
- for(;;)
- {
- // At end of the chain? Done.
- if(!*modifierLink)
- break;
-
- // About to look at shared modifiers? Done.
- RefPtr<Modifier> linkMod = *modifierLink;
- if(as<SharedModifiers>(linkMod))
- {
- break;
- }
-
- // Otherwise: keep traversing the modifier list.
- modifierLink = &(*modifierLink)->next;
- }
-
- // Splice the modifier into the linked list
-
- // We need to deal with the case where the modifier to
- // be spliced in might actually be a modifier *list*,
- // so that we actually want to splice in at the
- // end of the new list...
- auto spliceLink = &modifier->next;
- while(*spliceLink)
- spliceLink = &(*spliceLink)->next;
-
- // Do the splice.
- *spliceLink = *modifierLink;
-
- *modifierLink = modifier;
- modifierLink = &modifier->next;
- }
-
- void addModifier(
- RefPtr<ModifiableSyntaxNode> syntax,
- RefPtr<Modifier> modifier)
- {
- auto modifierLink = &syntax->modifiers.first;
- AddModifier(&modifierLink, modifier);
- }
-
- //
- // '::'? identifier ('::' identifier)*
- static Token parseAttributeName(Parser* parser)
- {
- const SourceLoc scopedIdSourceLoc = parser->tokenReader.PeekLoc();
-
- // Strip initial :: if there is one
- const TokenType initialTokenType = parser->tokenReader.PeekTokenType();
- if (initialTokenType == TokenType::Scope)
- {
- parser->ReadToken(TokenType::Scope);
- }
-
- const Token firstIdentifier = parser->ReadToken(TokenType::Identifier);
- if (initialTokenType != TokenType::Scope && parser->tokenReader.PeekTokenType() != TokenType::Scope)
- {
- return firstIdentifier;
- }
-
- // Build up scoped string
- StringBuilder scopedIdentifierBuilder;
- if (initialTokenType == TokenType::Scope)
- {
- scopedIdentifierBuilder.Append('_');
- }
- scopedIdentifierBuilder.Append(firstIdentifier.Content);
-
- while (parser->tokenReader.PeekTokenType() == TokenType::Scope)
- {
- parser->ReadToken(TokenType::Scope);
- scopedIdentifierBuilder.Append('_');
-
- const Token nextIdentifier(parser->ReadToken(TokenType::Identifier));
- scopedIdentifierBuilder.Append(nextIdentifier.Content);
- }
-
- // Make a 'token'
- SourceManager* sourceManager = parser->sink->sourceManager;
- const UnownedStringSlice scopedIdentifier(sourceManager->allocateStringSlice(scopedIdentifierBuilder.getUnownedSlice()));
- Token token(TokenType::Identifier, scopedIdentifier, scopedIdSourceLoc);
-
- // Get the name pool
- auto namePool = parser->getNamePool();
-
- // Since it's an Identifier have to set the name.
- token.ptrValue = namePool->getName(token.Content);
-
- return token;
- }
-
- // Parse HLSL-style `[name(arg, ...)]` style "attribute" modifiers
- static void ParseSquareBracketAttributes(Parser* parser, RefPtr<Modifier>** ioModifierLink)
- {
- parser->ReadToken(TokenType::LBracket);
-
- const bool hasDoubleBracket = AdvanceIf(parser, TokenType::LBracket);
-
- for(;;)
- {
- // Note: When parsing we just construct an AST node for an
- // "unchecked" attribute, and defer all detailed semantic
- // checking until later.
- //
- // An alternative would be to perform lookup of an `AttributeDecl`
- // at this point, similar to what we do for `SyntaxDecl`, but it
- // seems better to not complicate the parsing process any more.
- //
-
- Token nameToken = parseAttributeName(parser);
-
- RefPtr<UncheckedAttribute> modifier = new UncheckedAttribute();
- modifier->name = nameToken.getName();
- modifier->loc = nameToken.getLoc();
- modifier->scope = parser->currentScope;
-
- if (AdvanceIf(parser, TokenType::LParent))
- {
- // HLSL-style `[name(arg0, ...)]` attribute
-
- while (!AdvanceIfMatch(parser, TokenType::RParent))
- {
- auto arg = parser->ParseArgExpr();
- if (arg)
- {
- modifier->args.add(arg);
- }
-
- if (AdvanceIfMatch(parser, TokenType::RParent))
- break;
-
- parser->ReadToken(TokenType::Comma);
- }
- }
- AddModifier(ioModifierLink, modifier);
-
-
- if (AdvanceIfMatch(parser, TokenType::RBracket))
- break;
-
- parser->ReadToken(TokenType::Comma);
- }
-
- if (hasDoubleBracket)
- {
- // Read the second ]
- parser->ReadToken(TokenType::RBracket);
- }
- }
-
- static TokenType peekTokenType(Parser* parser)
- {
- return parser->tokenReader.PeekTokenType();
- }
-
- static Token advanceToken(Parser* parser)
- {
- return parser->ReadToken();
- }
-
- static Token peekToken(Parser* parser)
- {
- return parser->tokenReader.PeekToken();
- }
-
- static SyntaxDecl* tryLookUpSyntaxDecl(
- Parser* parser,
- Name* name)
- {
- // Let's look up the name and see what we find.
-
- auto lookupResult = lookUp(
- parser->getSession(),
- nullptr, // no semantics visitor available yet
- name,
- parser->currentScope);
-
- // If we didn't find anything, or the result was overloaded,
- // then we aren't going to be able to extract a single decl.
- if(!lookupResult.isValid() || lookupResult.isOverloaded())
- return nullptr;
-
- auto decl = lookupResult.item.declRef.getDecl();
- if( auto syntaxDecl = as<SyntaxDecl>(decl) )
- {
- return syntaxDecl;
- }
- else
- {
- return nullptr;
- }
- }
-
- template<typename T>
- bool tryParseUsingSyntaxDecl(
- Parser* parser,
- SyntaxDecl* syntaxDecl,
- RefPtr<T>* outSyntax)
- {
- if (!syntaxDecl)
- return false;
-
- if (!syntaxDecl->syntaxClass.isSubClassOf<T>())
- return false;
-
- // Consume the token that specified the keyword
- auto keywordToken = advanceToken(parser);
-
- RefPtr<RefObject> parsedObject = syntaxDecl->parseCallback(parser, syntaxDecl->parseUserData);
- if (!parsedObject)
- {
- return false;
- }
-
- auto syntax = as<T>(parsedObject);
- if (syntax)
- {
- if (!syntax->loc.isValid())
- {
- syntax->loc = keywordToken.loc;
- }
- }
- else if (parsedObject)
- {
- // Something was parsed, but it didn't have the expected type!
- SLANG_DIAGNOSE_UNEXPECTED(parser->sink, keywordToken, "parser callback did not return the expected type");
- }
-
- *outSyntax = syntax;
- return true;
- }
-
- template<typename T>
- bool tryParseUsingSyntaxDecl(
- Parser* parser,
- RefPtr<T>* outSyntax)
- {
- if (peekTokenType(parser) != TokenType::Identifier)
- return false;
-
- auto nameToken = peekToken(parser);
- auto name = nameToken.getName();
-
- auto syntaxDecl = tryLookUpSyntaxDecl(parser, name);
-
- if (!syntaxDecl)
- return false;
-
- return tryParseUsingSyntaxDecl(parser, syntaxDecl, outSyntax);
- }
-
- static Modifiers ParseModifiers(Parser* parser)
- {
- Modifiers modifiers;
- RefPtr<Modifier>* modifierLink = &modifiers.first;
- for (;;)
- {
- SourceLoc loc = parser->tokenReader.PeekLoc();
-
- switch (peekTokenType(parser))
- {
- default:
- // If we don't see a token type that we recognize, then
- // assume we are done with the modifier sequence.
- return modifiers;
-
- case TokenType::Identifier:
- {
- // We see an identifier ahead, and it might be the name
- // of a modifier keyword of some kind.
-
- Token nameToken = peekToken(parser);
-
- RefPtr<Modifier> parsedModifier;
- if (tryParseUsingSyntaxDecl<Modifier>(parser, &parsedModifier))
- {
- parsedModifier->name = nameToken.getName();
- if (!parsedModifier->loc.isValid())
- {
- parsedModifier->loc = nameToken.loc;
- }
-
- AddModifier(&modifierLink, parsedModifier);
- continue;
- }
-
- // If there was no match for a modifier keyword, then we
- // must be at the end of the modifier sequence
- return modifiers;
- }
- break;
-
- // HLSL uses `[attributeName]` style for its modifiers, which closely
- // matches the C++ `[[attributeName]]` style.
- case TokenType::LBracket:
- ParseSquareBracketAttributes(parser, &modifierLink);
- break;
- }
- }
- }
-
- static Name* getName(Parser* parser, String const& text)
- {
- return parser->getNamePool()->getName(text);
- }
-
- static NameLoc expectIdentifier(Parser* parser)
- {
- return NameLoc(parser->ReadToken(TokenType::Identifier));
- }
-
-
- static RefPtr<RefObject> parseImportDecl(
- Parser* parser, void* /*userData*/)
- {
- parser->haveSeenAnyImportDecls = true;
-
- auto decl = new ImportDecl();
- decl->scope = parser->currentScope;
-
- if (peekTokenType(parser) == TokenType::StringLiteral)
- {
- auto nameToken = parser->ReadToken(TokenType::StringLiteral);
- auto nameString = getStringLiteralTokenValue(nameToken);
- auto moduleName = getName(parser, nameString);
-
- decl->moduleNameAndLoc = NameLoc(moduleName, nameToken.loc);
- }
- else
- {
- auto moduleNameAndLoc = expectIdentifier(parser);
-
- // We allow a dotted format for the name, as sugar
- if (peekTokenType(parser) == TokenType::Dot)
- {
- StringBuilder sb;
- sb << getText(moduleNameAndLoc.name);
- while (AdvanceIf(parser, TokenType::Dot))
- {
- sb << "/";
- sb << parser->ReadToken(TokenType::Identifier).Content;
- }
-
- moduleNameAndLoc.name = getName(parser, sb.ProduceString());
- }
-
- decl->moduleNameAndLoc = moduleNameAndLoc;
- }
-
- parser->ReadToken(TokenType::Semicolon);
-
- return decl;
- }
-
- static NameLoc ParseDeclName(
- Parser* parser)
- {
- Token nameToken;
- if (AdvanceIf(parser, "operator"))
- {
- nameToken = parser->ReadToken();
- switch (nameToken.type)
- {
- case TokenType::OpAdd: case TokenType::OpSub: case TokenType::OpMul: case TokenType::OpDiv:
- case TokenType::OpMod: case TokenType::OpNot: case TokenType::OpBitNot: case TokenType::OpLsh: case TokenType::OpRsh:
- case TokenType::OpEql: case TokenType::OpNeq: case TokenType::OpGreater: case TokenType::OpLess: case TokenType::OpGeq:
- case TokenType::OpLeq: case TokenType::OpAnd: case TokenType::OpOr: case TokenType::OpBitXor: case TokenType::OpBitAnd:
- case TokenType::OpBitOr: case TokenType::OpInc: case TokenType::OpDec:
- case TokenType::OpAddAssign:
- case TokenType::OpSubAssign:
- case TokenType::OpMulAssign:
- case TokenType::OpDivAssign:
- case TokenType::OpModAssign:
- case TokenType::OpShlAssign:
- case TokenType::OpShrAssign:
- case TokenType::OpOrAssign:
- case TokenType::OpAndAssign:
- case TokenType::OpXorAssign:
-
- // Note(tfoley): A bit of a hack:
- case TokenType::Comma:
- case TokenType::OpAssign:
- break;
-
- // Note(tfoley): Even more of a hack!
- case TokenType::QuestionMark:
- if (AdvanceIf(parser, TokenType::Colon))
- {
- // Concat : onto ?
- nameToken.Content = UnownedStringSlice::fromLiteral("?:");
- break;
- }
- ; // fall-thru
- default:
- parser->sink->diagnose(nameToken.loc, Diagnostics::invalidOperator, nameToken);
- break;
- }
-
- return NameLoc(
- getName(parser, nameToken.Content),
- nameToken.loc);
- }
- else
- {
- nameToken = parser->ReadToken(TokenType::Identifier);
- return NameLoc(nameToken);
- }
- }
-
- // A "declarator" as used in C-style languages
- struct Declarator : RefObject
- {
- // Different cases of declarator appear as "flavors" here
- enum class Flavor
- {
- name,
- Pointer,
- Array,
- };
- Flavor flavor;
- };
-
- // The most common case of declarator uses a simple name
- struct NameDeclarator : Declarator
- {
- NameLoc nameAndLoc;
- };
-
- // A declarator that declares a pointer type
- struct PointerDeclarator : Declarator
- {
- // location of the `*` token
- SourceLoc starLoc;
-
- RefPtr<Declarator> inner;
- };
-
- // A declarator that declares an array type
- struct ArrayDeclarator : Declarator
- {
- RefPtr<Declarator> inner;
-
- // location of the `[` token
- SourceLoc openBracketLoc;
-
- // The expression that yields the element count, or NULL
- RefPtr<Expr> elementCountExpr;
- };
-
- // "Unwrapped" information about a declarator
- struct DeclaratorInfo
- {
- RefPtr<Expr> typeSpec;
- NameLoc nameAndLoc;
- RefPtr<Modifier> semantics;
- RefPtr<Expr> initializer;
- };
-
- // Add a member declaration to its container, and ensure that its
- // parent link is set up correctly.
- static void AddMember(RefPtr<ContainerDecl> container, RefPtr<Decl> member)
- {
- if (container)
- {
- member->ParentDecl = container.Ptr();
- container->Members.add(member);
-
- container->memberDictionaryIsValid = false;
- }
- }
-
- static void AddMember(RefPtr<Scope> scope, RefPtr<Decl> member)
- {
- if (scope)
- {
- AddMember(scope->containerDecl, member);
- }
- }
-
- static RefPtr<Decl> ParseGenericParamDecl(
- Parser* parser,
- RefPtr<GenericDecl> genericDecl)
- {
- // simple syntax to introduce a value parameter
- if (AdvanceIf(parser, "let"))
- {
- // default case is a type parameter
- auto paramDecl = new GenericValueParamDecl();
- paramDecl->nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
- if (AdvanceIf(parser, TokenType::Colon))
- {
- paramDecl->type = parser->ParseTypeExp();
- }
- if (AdvanceIf(parser, TokenType::OpAssign))
- {
- paramDecl->initExpr = parser->ParseInitExpr();
- }
- return paramDecl;
- }
- else
- {
- // default case is a type parameter
- RefPtr<GenericTypeParamDecl> paramDecl = new GenericTypeParamDecl();
- parser->FillPosition(paramDecl);
- paramDecl->nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
- if (AdvanceIf(parser, TokenType::Colon))
- {
- // The user is apply a constraint to this type parameter...
-
- auto paramConstraint = new GenericTypeConstraintDecl();
- parser->FillPosition(paramConstraint);
-
- auto paramType = DeclRefType::Create(
- parser->getSession(),
- DeclRef<Decl>(paramDecl, nullptr));
-
- auto paramTypeExpr = new SharedTypeExpr();
- paramTypeExpr->loc = paramDecl->loc;
- paramTypeExpr->base.type = paramType;
- paramTypeExpr->type = QualType(getTypeType(paramType));
-
- paramConstraint->sub = TypeExp(paramTypeExpr);
- paramConstraint->sup = parser->ParseTypeExp();
-
- AddMember(genericDecl, paramConstraint);
-
-
- }
- if (AdvanceIf(parser, TokenType::OpAssign))
- {
- paramDecl->initType = parser->ParseTypeExp();
- }
- return paramDecl;
- }
- }
-
- template<typename TFunc>
- static void ParseGenericDeclImpl(
- Parser* parser, GenericDecl* decl, const TFunc & parseInnerFunc)
- {
- parser->ReadToken(TokenType::OpLess);
- parser->genericDepth++;
- while (!parser->LookAheadToken(TokenType::OpGreater))
- {
- AddMember(decl, ParseGenericParamDecl(parser, decl));
-
- if (parser->LookAheadToken(TokenType::OpGreater))
- break;
-
- parser->ReadToken(TokenType::Comma);
- }
- parser->genericDepth--;
- parser->ReadToken(TokenType::OpGreater);
- decl->inner = parseInnerFunc(decl);
- decl->inner->ParentDecl = decl;
-
- // A generic decl hijacks the name of the declaration
- // it wraps, so that lookup can find it.
- if (decl->inner)
- {
- decl->nameAndLoc = decl->inner->nameAndLoc;
- decl->loc = decl->inner->loc;
- }
- }
-
- template<typename ParseFunc>
- static RefPtr<Decl> parseOptGenericDecl(
- Parser* parser, const ParseFunc& parseInner)
- {
- // TODO: may want more advanced disambiguation than this...
- if (parser->LookAheadToken(TokenType::OpLess))
- {
- RefPtr<GenericDecl> genericDecl = new GenericDecl();
- parser->FillPosition(genericDecl);
- parser->PushScope(genericDecl);
- ParseGenericDeclImpl(parser, genericDecl, parseInner);
- parser->PopScope();
- return genericDecl;
- }
- else
- {
- return parseInner(nullptr);
- }
- }
-
- static RefPtr<RefObject> ParseGenericDecl(Parser* parser, void*)
- {
- RefPtr<GenericDecl> decl = new GenericDecl();
- parser->FillPosition(decl.Ptr());
- parser->PushScope(decl.Ptr());
- ParseGenericDeclImpl(parser, decl.Ptr(), [=](GenericDecl* genDecl) {return ParseSingleDecl(parser, genDecl); });
- parser->PopScope();
- return decl;
- }
-
- static void parseParameterList(
- Parser* parser,
- RefPtr<CallableDecl> decl)
- {
- parser->ReadToken(TokenType::LParent);
-
- // Allow a declaration to use the keyword `void` for a parameter list,
- // since that was required in ancient C, and continues to be supported
- // in a bunc hof its derivatives even if it is a Bad Design Choice
- //
- // TODO: conditionalize this so we don't keep this around for "pure"
- // Slang code
- if( parser->LookAheadToken("void") && parser->LookAheadToken(TokenType::RParent, 1) )
- {
- parser->ReadToken("void");
- parser->ReadToken(TokenType::RParent);
- return;
- }
-
- while (!AdvanceIfMatch(parser, TokenType::RParent))
- {
- AddMember(decl, parser->ParseParameter());
- if (AdvanceIf(parser, TokenType::RParent))
- break;
- parser->ReadToken(TokenType::Comma);
- }
- }
-
- // systematically replace all scopes in an expression tree
- class ReplaceScopeVisitor : public ExprVisitor<ReplaceScopeVisitor>
- {
- public:
- RefPtr<Scope> scope;
- void visitDeclRefExpr(DeclRefExpr* expr)
- {
- expr->scope = scope;
- }
- void visitGenericAppExpr(GenericAppExpr * expr)
- {
- expr->FunctionExpr->accept(this, nullptr);
- for (auto arg : expr->Arguments)
- arg->accept(this, nullptr);
- }
- void visitIndexExpr(IndexExpr * expr)
- {
- expr->BaseExpression->accept(this, nullptr);
- expr->IndexExpression->accept(this, nullptr);
- }
- void visitMemberExpr(MemberExpr * expr)
- {
- expr->BaseExpression->accept(this, nullptr);
- expr->scope = scope;
- }
- void visitStaticMemberExpr(StaticMemberExpr * expr)
- {
- expr->BaseExpression->accept(this, nullptr);
- expr->scope = scope;
- }
- void visitExpr(Expr* /*expr*/)
- {}
- };
-
- /// Parse an optional body statement for a declaration that can have a body.
- static RefPtr<Stmt> parseOptBody(Parser* parser)
- {
- if (AdvanceIf(parser, TokenType::Semicolon))
- {
- // empty body
- return nullptr;
- }
- else
- {
- return parser->parseBlockStatement();
- }
- }
-
- /// Complete parsing of a function using traditional (C-like) declarator syntax
- static RefPtr<Decl> parseTraditionalFuncDecl(
- Parser* parser,
- DeclaratorInfo const& declaratorInfo)
- {
- RefPtr<FuncDecl> decl = new FuncDecl();
- parser->FillPosition(decl.Ptr());
- decl->loc = declaratorInfo.nameAndLoc.loc;
- decl->nameAndLoc = declaratorInfo.nameAndLoc;
-
- return parseOptGenericDecl(parser, [&](GenericDecl*)
- {
- // HACK: The return type of the function will already have been
- // parsed in a scope that didn't include the function's generic
- // parameters.
- //
- // We will use a visitor here to try and replace the scope associated
- // with any name expressiosn in the reuslt type.
- //
- // TODO: This should be fixed by not associating scopes with
- // such expressions at parse time, and instead pushing down scopes
- // as part of the state during semantic checking.
- //
- ReplaceScopeVisitor replaceScopeVisitor;
- replaceScopeVisitor.scope = parser->currentScope;
- declaratorInfo.typeSpec->accept(&replaceScopeVisitor, nullptr);
-
- decl->ReturnType = TypeExp(declaratorInfo.typeSpec);
-
- parser->PushScope(decl);
-
- parseParameterList(parser, decl);
- ParseOptSemantics(parser, decl.Ptr());
- decl->Body = parseOptBody(parser);
-
- parser->PopScope();
-
- return decl;
- });
- }
-
- static RefPtr<VarDeclBase> CreateVarDeclForContext(
- ContainerDecl* containerDecl )
- {
- if (as<CallableDecl>(containerDecl))
- {
- // Function parameters always use their dedicated syntax class.
- //
- return new ParamDecl();
- }
- else
- {
- // Globals, locals, and member variables all use the same syntax class.
- //
- return new VarDecl();
- }
- }
-
- // Add modifiers to the end of the modifier list for a declaration
- void AddModifiers(Decl* decl, RefPtr<Modifier> modifiers)
- {
- if (!modifiers)
- return;
-
- RefPtr<Modifier>* link = &decl->modifiers.first;
- while (*link)
- {
- link = &(*link)->next;
- }
- *link = modifiers;
- }
-
- static Name* generateName(Parser* parser, String const& base)
- {
- // TODO: somehow mangle the name to avoid clashes
- return getName(parser, "SLANG_" + base);
- }
-
- static Name* generateName(Parser* parser)
- {
- return generateName(parser, "anonymous_" + String(parser->anonymousCounter++));
- }
-
-
- // Set up a variable declaration based on what we saw in its declarator...
- static void CompleteVarDecl(
- Parser* parser,
- RefPtr<VarDeclBase> decl,
- DeclaratorInfo const& declaratorInfo)
- {
- parser->FillPosition(decl.Ptr());
-
- if( !declaratorInfo.nameAndLoc.name )
- {
- // HACK(tfoley): we always give a name, even if the declarator didn't include one... :(
- decl->nameAndLoc = NameLoc(generateName(parser));
- }
- else
- {
- decl->loc = declaratorInfo.nameAndLoc.loc;
- decl->nameAndLoc = declaratorInfo.nameAndLoc;
- }
- decl->type = TypeExp(declaratorInfo.typeSpec);
-
- AddModifiers(decl.Ptr(), declaratorInfo.semantics);
-
- decl->initExpr = declaratorInfo.initializer;
- }
-
- static RefPtr<Declarator> ParseDeclarator(Parser* parser);
-
- static RefPtr<Declarator> ParseDirectAbstractDeclarator(
- Parser* parser)
- {
- RefPtr<Declarator> declarator;
- switch( parser->tokenReader.PeekTokenType() )
- {
- case TokenType::Identifier:
- {
- auto nameDeclarator = new NameDeclarator();
- nameDeclarator->flavor = Declarator::Flavor::name;
- nameDeclarator->nameAndLoc = ParseDeclName(parser);
- declarator = nameDeclarator;
- }
- break;
-
- case TokenType::LParent:
- {
- // Note(tfoley): This is a point where disambiguation is required.
- // We could be looking at an abstract declarator for a function-type
- // parameter:
- //
- // void F( int(int) );
- //
- // Or we could be looking at the use of parenthesese in an ordinary
- // declarator:
- //
- // void (*f)(int);
- //
- // The difference really doesn't matter right now, but we err in
- // the direction of assuming the second case.
- parser->ReadToken(TokenType::LParent);
- declarator = ParseDeclarator(parser);
- parser->ReadToken(TokenType::RParent);
- }
- break;
-
- default:
- // an empty declarator is allowed
- return nullptr;
- }
-
- // postifx additions
- for( ;;)
- {
- switch( parser->tokenReader.PeekTokenType() )
- {
- case TokenType::LBracket:
- {
- auto arrayDeclarator = new ArrayDeclarator();
- arrayDeclarator->openBracketLoc = parser->tokenReader.PeekLoc();
- arrayDeclarator->flavor = Declarator::Flavor::Array;
- arrayDeclarator->inner = declarator;
-
- parser->ReadToken(TokenType::LBracket);
- if( parser->tokenReader.PeekTokenType() != TokenType::RBracket )
- {
- arrayDeclarator->elementCountExpr = parser->ParseExpression();
- }
- parser->ReadToken(TokenType::RBracket);
-
- declarator = arrayDeclarator;
- continue;
- }
-
- case TokenType::LParent:
- break;
-
- default:
- break;
- }
-
- break;
- }
-
- return declarator;
- }
-
- // Parse a declarator (or at least as much of one as we support)
- static RefPtr<Declarator> ParseDeclarator(
- Parser* parser)
- {
- if( parser->tokenReader.PeekTokenType() == TokenType::OpMul )
- {
- auto ptrDeclarator = new PointerDeclarator();
- ptrDeclarator->starLoc = parser->tokenReader.PeekLoc();
- ptrDeclarator->flavor = Declarator::Flavor::Pointer;
-
- parser->ReadToken(TokenType::OpMul);
-
- // TODO(tfoley): allow qualifiers like `const` here?
-
- ptrDeclarator->inner = ParseDeclarator(parser);
- return ptrDeclarator;
- }
- else
- {
- return ParseDirectAbstractDeclarator(parser);
- }
- }
-
- // A declarator plus optional semantics and initializer
- struct InitDeclarator
- {
- RefPtr<Declarator> declarator;
- RefPtr<Modifier> semantics;
- RefPtr<Expr> initializer;
- };
-
- // Parse a declarator plus optional semantics
- static InitDeclarator ParseSemanticDeclarator(
- Parser* parser)
- {
- InitDeclarator result;
- result.declarator = ParseDeclarator(parser);
- result.semantics = ParseOptSemantics(parser);
- return result;
- }
-
- // Parse a declarator plus optional semantics and initializer
- static InitDeclarator ParseInitDeclarator(
- Parser* parser)
- {
- InitDeclarator result = ParseSemanticDeclarator(parser);
- if (AdvanceIf(parser, TokenType::OpAssign))
- {
- result.initializer = parser->ParseInitExpr();
- }
- return result;
- }
-
- static void UnwrapDeclarator(
- RefPtr<Declarator> declarator,
- DeclaratorInfo* ioInfo)
- {
- while( declarator )
- {
- switch(declarator->flavor)
- {
- case Declarator::Flavor::name:
- {
- auto nameDeclarator = (NameDeclarator*) declarator.Ptr();
- ioInfo->nameAndLoc = nameDeclarator->nameAndLoc;
- return;
- }
- break;
-
- case Declarator::Flavor::Pointer:
- {
- auto ptrDeclarator = (PointerDeclarator*) declarator.Ptr();
-
- // TODO(tfoley): we don't support pointers for now
- // ioInfo->typeSpec = new PointerTypeExpr(ioInfo->typeSpec);
-
- declarator = ptrDeclarator->inner;
- }
- break;
-
- case Declarator::Flavor::Array:
- {
- // TODO(tfoley): we don't support pointers for now
- auto arrayDeclarator = (ArrayDeclarator*) declarator.Ptr();
-
- auto arrayTypeExpr = new IndexExpr();
- arrayTypeExpr->loc = arrayDeclarator->openBracketLoc;
- arrayTypeExpr->BaseExpression = ioInfo->typeSpec;
- arrayTypeExpr->IndexExpression = arrayDeclarator->elementCountExpr;
- ioInfo->typeSpec = arrayTypeExpr;
-
- declarator = arrayDeclarator->inner;
- }
- break;
-
- default:
- SLANG_UNREACHABLE("all cases handled");
- break;
- }
- }
- }
-
- static void UnwrapDeclarator(
- InitDeclarator const& initDeclarator,
- DeclaratorInfo* ioInfo)
- {
- UnwrapDeclarator(initDeclarator.declarator, ioInfo);
- ioInfo->semantics = initDeclarator.semantics;
- ioInfo->initializer = initDeclarator.initializer;
- }
-
- // Either a single declaration, or a group of them
- struct DeclGroupBuilder
- {
- SourceLoc startPosition;
- RefPtr<Decl> decl;
- RefPtr<DeclGroup> group;
-
- // Add a new declaration to the potential group
- void addDecl(
- RefPtr<Decl> newDecl)
- {
- SLANG_ASSERT(newDecl);
-
- if( decl )
- {
- group = new DeclGroup();
- group->loc = startPosition;
- group->decls.add(decl);
- decl = nullptr;
- }
-
- if( group )
- {
- group->decls.add(newDecl);
- }
- else
- {
- decl = newDecl;
- }
- }
-
- RefPtr<DeclBase> getResult()
- {
- if(group) return group;
- return decl;
- }
- };
-
- // Pares an argument to an application of a generic
- RefPtr<Expr> ParseGenericArg(Parser* parser)
- {
- return parser->ParseArgExpr();
- }
-
- // Create a type expression that will refer to the given declaration
- static RefPtr<Expr>
- createDeclRefType(Parser* parser, RefPtr<Decl> decl)
- {
- // For now we just construct an expression that
- // will look up the given declaration by name.
- //
- // TODO: do this better, e.g. by filling in the `declRef` field directly
-
- auto expr = new VarExpr();
- expr->scope = parser->currentScope.Ptr();
- expr->loc = decl->getNameLoc();
- expr->name = decl->getName();
- return expr;
- }
-
- // Representation for a parsed type specifier, which might
- // include a declaration (e.g., of a `struct` type)
- struct TypeSpec
- {
- // If the type-spec declared something, then put it here
- RefPtr<Decl> decl;
-
- // Put the resulting expression (which should evaluate to a type) here
- RefPtr<Expr> expr;
- };
-
- static RefPtr<Expr> parseGenericApp(
- Parser* parser,
- RefPtr<Expr> base)
- {
- RefPtr<GenericAppExpr> genericApp = new GenericAppExpr();
-
- parser->FillPosition(genericApp.Ptr()); // set up scope for lookup
- genericApp->FunctionExpr = base;
- parser->ReadToken(TokenType::OpLess);
- parser->genericDepth++;
- // For now assume all generics have at least one argument
- genericApp->Arguments.add(ParseGenericArg(parser));
- while (AdvanceIf(parser, TokenType::Comma))
- {
- genericApp->Arguments.add(ParseGenericArg(parser));
- }
- parser->genericDepth--;
-
- if (parser->tokenReader.PeekToken().type == TokenType::OpRsh)
- {
- parser->tokenReader.PeekToken().type = TokenType::OpGreater;
- parser->tokenReader.PeekToken().loc.setRaw(parser->tokenReader.PeekToken().loc.getRaw() + 1);
- }
- else if (parser->LookAheadToken(TokenType::OpGreater))
- parser->ReadToken(TokenType::OpGreater);
- else
- parser->sink->diagnose(parser->tokenReader.PeekToken(), Diagnostics::tokenTypeExpected, "'>'");
- return genericApp;
- }
-
- static bool isGenericName(Parser* parser, Name* name)
- {
- auto lookupResult = lookUp(
- parser->getSession(),
- nullptr, // no semantics visitor available yet
- name,
- parser->currentScope);
- if (!lookupResult.isValid() || lookupResult.isOverloaded())
- return false;
-
- return lookupResult.item.declRef.is<GenericDecl>();
- }
-
- static RefPtr<Expr> tryParseGenericApp(
- Parser* parser,
- RefPtr<Expr> base)
- {
- Name * baseName = nullptr;
- if (auto varExpr = as<VarExpr>(base))
- baseName = varExpr->name;
- // if base is a known generics, parse as generics
- if (baseName && isGenericName(parser, baseName))
- return parseGenericApp(parser, base);
-
- // otherwise, we speculate as generics, and fallback to comparison when parsing failed
- TokenSpan tokenSpan;
- tokenSpan.mBegin = parser->tokenReader.mCursor;
- tokenSpan.mEnd = parser->tokenReader.mEnd;
- DiagnosticSink newSink;
- newSink.sourceManager = parser->sink->sourceManager;
- Parser newParser(*parser);
- newParser.sink = &newSink;
- auto speculateParseRs = parseGenericApp(&newParser, base);
- if (newSink.errorCount == 0)
- {
- // disambiguate based on FOLLOW set
- switch (peekTokenType(&newParser))
- {
- case TokenType::Dot:
- case TokenType::LParent:
- case TokenType::RParent:
- case TokenType::RBracket:
- case TokenType::Colon:
- case TokenType::Comma:
- case TokenType::QuestionMark:
- case TokenType::Semicolon:
- case TokenType::OpEql:
- case TokenType::OpNeq:
- {
- return parseGenericApp(parser, base);
- }
- }
- }
- return base;
- }
- static RefPtr<Expr> parseMemberType(Parser * parser, RefPtr<Expr> base)
- {
- // When called the :: or . have been consumed, so don't need to consume here.
-
- RefPtr<MemberExpr> memberExpr = new MemberExpr();
-
- parser->FillPosition(memberExpr.Ptr());
- memberExpr->BaseExpression = base;
- memberExpr->name = expectIdentifier(parser).name;
- return memberExpr;
- }
-
- // Parse option `[]` braces after a type expression, that indicate an array type
- static RefPtr<Expr> parsePostfixTypeSuffix(
- Parser* parser,
- RefPtr<Expr> inTypeExpr)
- {
- auto typeExpr = inTypeExpr;
- while (parser->LookAheadToken(TokenType::LBracket))
- {
- RefPtr<IndexExpr> arrType = new IndexExpr();
- arrType->loc = typeExpr->loc;
- arrType->BaseExpression = typeExpr;
- parser->ReadToken(TokenType::LBracket);
- if (!parser->LookAheadToken(TokenType::RBracket))
- {
- arrType->IndexExpression = parser->ParseExpression();
- }
- parser->ReadToken(TokenType::RBracket);
- typeExpr = arrType;
- }
- return typeExpr;
- }
-
- static RefPtr<Expr> parseTaggedUnionType(Parser* parser)
- {
- RefPtr<TaggedUnionTypeExpr> taggedUnionType = new TaggedUnionTypeExpr();
-
- parser->ReadToken(TokenType::LParent);
- while(!AdvanceIfMatch(parser, TokenType::RParent))
- {
- auto caseType = parser->ParseTypeExp();
- taggedUnionType->caseTypes.add(caseType);
-
- if(AdvanceIf(parser, TokenType::RParent))
- break;
-
- parser->ReadToken(TokenType::Comma);
- }
-
- return taggedUnionType;
- }
-
- static TypeSpec parseTypeSpec(Parser* parser)
- {
- TypeSpec typeSpec;
-
- // We may see a `struct` (or `enum` or `class`) tag specified here, and need to act accordingly
- //
- // TODO(tfoley): Handle the case where the user is just using `struct`
- // as a way to name an existing struct "tag" (e.g., `struct Foo foo;`)
- //
- // TODO: We should really make these keywords be registered like any other
- // syntax category, rather than be special-cased here. The main issue here
- // is that we need to allow them to be used as type specifiers, as in:
- //
- // struct Foo { int x } foo;
- //
- // The ideal answer would be to register certain keywords as being able
- // to parse a type specifier, and look for those keywords here.
- // We should ideally add special case logic that bails out of declarator
- // parsing iff we have one of these kinds of type specifiers and the
- // closing `}` is at the end of its line, as a bit of a special case
- // to allow the common idiom.
- //
- if( parser->LookAheadToken("struct") )
- {
- auto decl = parser->ParseStruct();
- typeSpec.decl = decl;
- typeSpec.expr = createDeclRefType(parser, decl);
- return typeSpec;
- }
- else if( parser->LookAheadToken("class") )
- {
- auto decl = parser->ParseClass();
- typeSpec.decl = decl;
- typeSpec.expr = createDeclRefType(parser, decl);
- return typeSpec;
- }
- else if(parser->LookAheadToken("enum"))
- {
- auto decl = parseEnumDecl(parser);
- typeSpec.decl = decl;
- typeSpec.expr = createDeclRefType(parser, decl);
- return typeSpec;
- }
- else if(AdvanceIf(parser, "__TaggedUnion"))
- {
- typeSpec.expr = parseTaggedUnionType(parser);
- return typeSpec;
- }
-
- Token typeName = parser->ReadToken(TokenType::Identifier);
-
- auto basicType = new VarExpr();
- basicType->scope = parser->currentScope.Ptr();
- basicType->loc = typeName.loc;
- basicType->name = typeName.getNameOrNull();
-
- RefPtr<Expr> typeExpr = basicType;
-
- bool shouldLoop = true;
- while (shouldLoop)
- {
- switch (peekTokenType(parser))
- {
- case TokenType::OpLess:
- typeExpr = parseGenericApp(parser, typeExpr);
- break;
- case TokenType::Scope:
- parser->ReadToken(TokenType::Scope);
- typeExpr = parseMemberType(parser, typeExpr);
- break;
- case TokenType::Dot:
- parser->ReadToken(TokenType::Dot);
- typeExpr = parseMemberType(parser, typeExpr);
- break;
- default:
- shouldLoop = false;
- }
- }
-
- typeSpec.expr = typeExpr;
- return typeSpec;
- }
-
- static RefPtr<DeclBase> ParseDeclaratorDecl(
- Parser* parser,
- ContainerDecl* containerDecl)
- {
- SourceLoc startPosition = parser->tokenReader.PeekLoc();
-
- auto typeSpec = parseTypeSpec(parser);
-
- // We may need to build up multiple declarations in a group,
- // but the common case will be when we have just a single
- // declaration
- DeclGroupBuilder declGroupBuilder;
- declGroupBuilder.startPosition = startPosition;
-
- // The type specifier may include a declaration. E.g.,
- // it might declare a `struct` type.
- if(typeSpec.decl)
- declGroupBuilder.addDecl(typeSpec.decl);
-
- if( AdvanceIf(parser, TokenType::Semicolon) )
- {
- // No actual variable is being declared here, but
- // that might not be an error.
-
- auto result = declGroupBuilder.getResult();
- if( !result )
- {
- parser->sink->diagnose(startPosition, Diagnostics::declarationDidntDeclareAnything);
- }
- return result;
- }
-
- // It is possible that we have a plain `struct`, `enum`,
- // or similar declaration that isn't being used to declare
- // any variable, and the user didn't put a trailing
- // semicolon on it:
- //
- // struct Batman
- // {
- // int cape;
- // }
- //
- // We want to allow this syntax (rather than give an
- // inscrutable error), but also support the less common
- // idiom where that declaration is used as part of
- // a variable declaration:
- //
- // struct Robin
- // {
- // float tights;
- // } boyWonder;
- //
- // As a bit of a hack (insofar as it means we aren't
- // *really* compatible with arbitrary HLSL code), we
- // will check if there are any more tokens on the
- // same line as the closing `}`, and if not, we
- // will treat it like the end of the declaration.
- //
- // Just as a safety net, only apply this logic for
- // a file that is being passed in as "true" Slang code.
- //
- if(parser->getSourceLanguage() == SourceLanguage::Slang)
- {
- if(typeSpec.decl)
- {
- if(peekToken(parser).flags & TokenFlag::AtStartOfLine)
- {
- // The token after the `}` is at the start of its
- // own line, which means it can't be on the same line.
- //
- // This means the programmer probably wants to
- // just treat this as a declaration.
- return declGroupBuilder.getResult();
- }
- }
- }
-
-
- InitDeclarator initDeclarator = ParseInitDeclarator(parser);
-
- DeclaratorInfo declaratorInfo;
- declaratorInfo.typeSpec = typeSpec.expr;
-
-
- // Rather than parse function declarators properly for now,
- // we'll just do a quick disambiguation here. This won't
- // matter unless we actually decide to support function-type parameters,
- // using C syntax.
- //
- if ((parser->tokenReader.PeekTokenType() == TokenType::LParent ||
- parser->tokenReader.PeekTokenType() == TokenType::OpLess)
-
- // Only parse as a function if we didn't already see mutually-exclusive
- // constructs when parsing the declarator.
- && !initDeclarator.initializer
- && !initDeclarator.semantics)
- {
- // Looks like a function, so parse it like one.
- UnwrapDeclarator(initDeclarator, &declaratorInfo);
- return parseTraditionalFuncDecl(parser, declaratorInfo);
- }
-
- // Otherwise we are looking at a variable declaration, which could be one in a sequence...
-
- if( AdvanceIf(parser, TokenType::Semicolon) )
- {
- // easy case: we only had a single declaration!
- UnwrapDeclarator(initDeclarator, &declaratorInfo);
- RefPtr<VarDeclBase> firstDecl = CreateVarDeclForContext(containerDecl);
- CompleteVarDecl(parser, firstDecl, declaratorInfo);
-
- declGroupBuilder.addDecl(firstDecl);
- return declGroupBuilder.getResult();
- }
-
- // Otherwise we have multiple declarations in a sequence, and these
- // declarations need to somehow share both the type spec and modifiers.
- //
- // If there are any errors in the type specifier, we only want to hear
- // about it once, so we need to share structure rather than just
- // clone syntax.
-
- auto sharedTypeSpec = new SharedTypeExpr();
- sharedTypeSpec->loc = typeSpec.expr->loc;
- sharedTypeSpec->base = TypeExp(typeSpec.expr);
-
- for(;;)
- {
- declaratorInfo.typeSpec = sharedTypeSpec;
- UnwrapDeclarator(initDeclarator, &declaratorInfo);
-
- RefPtr<VarDeclBase> varDecl = CreateVarDeclForContext(containerDecl);
- CompleteVarDecl(parser, varDecl, declaratorInfo);
-
- declGroupBuilder.addDecl(varDecl);
-
- // end of the sequence?
- if(AdvanceIf(parser, TokenType::Semicolon))
- return declGroupBuilder.getResult();
-
- // ad-hoc recovery, to avoid infinite loops
- if( parser->isRecovering )
- {
- parser->ReadToken(TokenType::Semicolon);
- return declGroupBuilder.getResult();
- }
-
- // Let's default to assuming that a missing `,`
- // indicates the end of a declaration,
- // where a `;` would be expected, and not
- // a continuation of this declaration, where
- // a `,` would be expected (this is tailoring
- // the diagnostic message a bit).
- //
- // TODO: a more advanced heuristic here might
- // look at whether the next token is on the
- // same line, to predict whether `,` or `;`
- // would be more likely...
-
- if (!AdvanceIf(parser, TokenType::Comma))
- {
- parser->ReadToken(TokenType::Semicolon);
- return declGroupBuilder.getResult();
- }
-
- // expect another variable declaration...
- initDeclarator = ParseInitDeclarator(parser);
- }
- }
-
- /// Parse the "register name" part of a `register` or `packoffset` semantic.
- ///
- /// The syntax matched is:
- ///
- /// register-name-and-component-mask ::= register-name component-mask?
- /// register-name ::= identifier
- /// component-mask ::= '.' identifier
- ///
- static void parseHLSLRegisterNameAndOptionalComponentMask(
- Parser* parser,
- HLSLLayoutSemantic* semantic)
- {
- semantic->registerName = parser->ReadToken(TokenType::Identifier);
- if (AdvanceIf(parser, TokenType::Dot))
- {
- semantic->componentMask = parser->ReadToken(TokenType::Identifier);
- }
- }
-
- /// Parse an HLSL `register` semantic.
- ///
- /// The syntax matched is:
- ///
- /// register-semantic ::= 'register' '(' register-name-and-component-mask register-space? ')'
- /// register-space ::= ',' identifier
- ///
- static void parseHLSLRegisterSemantic(
- Parser* parser,
- HLSLRegisterSemantic* semantic)
- {
- // Read the `register` keyword
- semantic->name = parser->ReadToken(TokenType::Identifier);
-
- // Expect a parenthized list of additional arguments
- parser->ReadToken(TokenType::LParent);
-
- // First argument is a required register name and optional component mask
- parseHLSLRegisterNameAndOptionalComponentMask(parser, semantic);
-
- // Second argument is an optional register space
- if(AdvanceIf(parser, TokenType::Comma))
- {
- semantic->spaceName = parser->ReadToken(TokenType::Identifier);
- }
-
- parser->ReadToken(TokenType::RParent);
- }
-
- /// Parse an HLSL `packoffset` semantic.
- ///
- /// The syntax matched is:
- ///
- /// packoffset-semantic ::= 'packoffset' '(' register-name-and-component-mask ')'
- ///
- static void parseHLSLPackOffsetSemantic(
- Parser* parser,
- HLSLPackOffsetSemantic* semantic)
- {
- // Read the `packoffset` keyword
- semantic->name = parser->ReadToken(TokenType::Identifier);
-
- // Expect a parenthized list of additional arguments
- parser->ReadToken(TokenType::LParent);
-
- // First and only argument is a required register name and optional component mask
- parseHLSLRegisterNameAndOptionalComponentMask(parser, semantic);
-
- parser->ReadToken(TokenType::RParent);
-
- parser->sink->diagnose(semantic, Diagnostics::packOffsetNotSupported);
- }
-
- //
- // semantic ::= identifier ( '(' args ')' )?
- //
- static RefPtr<Modifier> ParseSemantic(
- Parser* parser)
- {
- if (parser->LookAheadToken("register"))
- {
- RefPtr<HLSLRegisterSemantic> semantic = new HLSLRegisterSemantic();
- parser->FillPosition(semantic);
- parseHLSLRegisterSemantic(parser, semantic.Ptr());
- return semantic;
- }
- else if (parser->LookAheadToken("packoffset"))
- {
- RefPtr<HLSLPackOffsetSemantic> semantic = new HLSLPackOffsetSemantic();
- parser->FillPosition(semantic);
- parseHLSLPackOffsetSemantic(parser, semantic.Ptr());
- return semantic;
- }
- else if (parser->LookAheadToken(TokenType::Identifier))
- {
- RefPtr<HLSLSimpleSemantic> semantic = new HLSLSimpleSemantic();
- parser->FillPosition(semantic);
- semantic->name = parser->ReadToken(TokenType::Identifier);
- return semantic;
- }
- else
- {
- // expect an identifier, just to produce an error message
- parser->ReadToken(TokenType::Identifier);
- return nullptr;
- }
- }
-
- //
- // opt-semantics ::= (':' semantic)*
- //
- static RefPtr<Modifier> ParseOptSemantics(
- Parser* parser)
- {
- if (!AdvanceIf(parser, TokenType::Colon))
- return nullptr;
-
- RefPtr<Modifier> result;
- RefPtr<Modifier>* link = &result;
- SLANG_ASSERT(!*link);
-
- for (;;)
- {
- RefPtr<Modifier> semantic = ParseSemantic(parser);
- if (semantic)
- {
- *link = semantic;
- link = &semantic->next;
- }
-
- // If we see another `:`, then that means there
- // is yet another semantic to be processed.
- // Otherwise we assume we are at the end of the list.
- //
- // TODO: This could produce sub-optimal diagnostics
- // when the user *meant* to apply multiple semantics
- // to a single declaration:
- //
- // Foo foo : register(t0) register(s0);
- // ^
- // missing ':' here |
- //
- // However, that is an uncommon occurence, and trying
- // to continue parsing semantics here even if we didn't
- // see a colon forces us to be careful about
- // avoiding an infinite loop here.
- if (!AdvanceIf(parser, TokenType::Colon))
- {
- return result;
- }
- }
-
- }
-
-
- static void ParseOptSemantics(
- Parser* parser,
- Decl* decl)
- {
- AddModifiers(decl, ParseOptSemantics(parser));
- }
-
- static RefPtr<Decl> ParseHLSLBufferDecl(
- Parser* parser,
- String bufferWrapperTypeName)
- {
- // An HLSL declaration of a constant buffer like this:
- //
- // cbuffer Foo : register(b0) { int a; float b; };
- //
- // is treated as syntax sugar for a type declaration
- // and then a global variable declaration using that type:
- //
- // struct $anonymous { int a; float b; };
- // ConstantBuffer<$anonymous> Foo;
- //
- // where `$anonymous` is a fresh name, and the variable
- // declaration is made to be "transparent" so that lookup
- // will see through it to the members inside.
-
- auto bufferWrapperTypeNamePos = parser->tokenReader.PeekLoc();
-
- // We are going to represent each buffer as a pair of declarations.
- // The first is a type declaration that holds all the members, while
- // the second is a variable declaration that uses the buffer type.
- RefPtr<StructDecl> bufferDataTypeDecl = new StructDecl();
- RefPtr<VarDecl> bufferVarDecl = new VarDecl();
-
- // Both declarations will have a location that points to the name
- parser->FillPosition(bufferDataTypeDecl.Ptr());
- parser->FillPosition(bufferVarDecl.Ptr());
-
- auto reflectionNameToken = parser->ReadToken(TokenType::Identifier);
-
- // Attach the reflection name to the block so we can use it
- auto reflectionNameModifier = new ParameterGroupReflectionName();
- reflectionNameModifier->nameAndLoc = NameLoc(reflectionNameToken);
- addModifier(bufferVarDecl, reflectionNameModifier);
-
- // Both the buffer variable and its type need to have names generated
- bufferVarDecl->nameAndLoc.name = generateName(parser, "parameterGroup_" + String(reflectionNameToken.Content));
- bufferDataTypeDecl->nameAndLoc.name = generateName(parser, "ParameterGroup_" + String(reflectionNameToken.Content));
-
- addModifier(bufferDataTypeDecl, new ImplicitParameterGroupElementTypeModifier());
- addModifier(bufferVarDecl, new ImplicitParameterGroupVariableModifier());
-
- // TODO(tfoley): We end up constructing unchecked syntax here that
- // is expected to type check into the right form, but it might be
- // cleaner to have a more explicit desugaring pass where we parse
- // these constructs directly into the AST and *then* desugar them.
-
- // Construct a type expression to reference the buffer data type
- auto bufferDataTypeExpr = new VarExpr();
- bufferDataTypeExpr->loc = bufferDataTypeDecl->loc;
- bufferDataTypeExpr->name = bufferDataTypeDecl->nameAndLoc.name;
- bufferDataTypeExpr->scope = parser->currentScope.Ptr();
-
- // Construct a type expression to reference the type constructor
- auto bufferWrapperTypeExpr = new VarExpr();
- bufferWrapperTypeExpr->loc = bufferWrapperTypeNamePos;
- bufferWrapperTypeExpr->name = getName(parser, bufferWrapperTypeName);
-
- // Always need to look this up in the outer scope,
- // so that it won't collide with, e.g., a local variable called `ConstantBuffer`
- bufferWrapperTypeExpr->scope = parser->outerScope;
-
- // Construct a type expression that represents the type for the variable,
- // which is the wrapper type applied to the data type
- auto bufferVarTypeExpr = new GenericAppExpr();
- bufferVarTypeExpr->loc = bufferVarDecl->loc;
- bufferVarTypeExpr->FunctionExpr = bufferWrapperTypeExpr;
- bufferVarTypeExpr->Arguments.add(bufferDataTypeExpr);
-
- bufferVarDecl->type.exp = bufferVarTypeExpr;
-
- // Any semantics applied to the buffer declaration are taken as applying
- // to the variable instead.
- ParseOptSemantics(parser, bufferVarDecl.Ptr());
-
- // The declarations in the body belong to the data type.
- parseAggTypeDeclBody(parser, bufferDataTypeDecl.Ptr());
-
- // All HLSL buffer declarations are "transparent" in that their
- // members are implicitly made visible in the parent scope.
- // We achieve this by applying the transparent modifier to the variable.
- auto transparentModifier = new TransparentModifier();
- transparentModifier->next = bufferVarDecl->modifiers.first;
- bufferVarDecl->modifiers.first = transparentModifier;
-
- // Because we are constructing two declarations, we have a thorny
- // issue that were are only supposed to return one.
- // For now we handle this by adding the type declaration to
- // the current scope manually, and then returning the variable
- // declaration.
- //
- // Note: this means that any modifiers that have already been parsed
- // will get attached to the variable declaration, not the type.
- // There might be cases where we need to shuffle things around.
-
- AddMember(parser->currentScope, bufferDataTypeDecl);
-
- return bufferVarDecl;
- }
-
- static RefPtr<RefObject> parseHLSLCBufferDecl(
- Parser* parser, void* /*userData*/)
- {
- return ParseHLSLBufferDecl(parser, "ConstantBuffer");
- }
-
- static RefPtr<RefObject> parseHLSLTBufferDecl(
- Parser* parser, void* /*userData*/)
- {
- return ParseHLSLBufferDecl(parser, "TextureBuffer");
- }
-
- static void parseOptionalInheritanceClause(Parser* parser, AggTypeDeclBase* decl)
- {
- if (AdvanceIf(parser, TokenType::Colon))
- {
- do
- {
- auto base = parser->ParseTypeExp();
-
- auto inheritanceDecl = new InheritanceDecl();
- inheritanceDecl->loc = base.exp->loc;
- inheritanceDecl->nameAndLoc.name = getName(parser, "$inheritance");
- inheritanceDecl->base = base;
-
- AddMember(decl, inheritanceDecl);
-
- } while (AdvanceIf(parser, TokenType::Comma));
- }
- }
-
- static RefPtr<RefObject> ParseExtensionDecl(Parser* parser, void* /*userData*/)
- {
- RefPtr<ExtensionDecl> decl = new ExtensionDecl();
- parser->FillPosition(decl.Ptr());
- decl->targetType = parser->ParseTypeExp();
- parseOptionalInheritanceClause(parser, decl);
- parseAggTypeDeclBody(parser, decl.Ptr());
-
- return decl;
- }
-
-
- void parseOptionalGenericConstraints(Parser * parser, ContainerDecl* decl)
- {
- if (AdvanceIf(parser, TokenType::Colon))
- {
- do
- {
- RefPtr<GenericTypeConstraintDecl> paramConstraint = new GenericTypeConstraintDecl();
- parser->FillPosition(paramConstraint);
-
- // substitution needs to be filled during check
- RefPtr<DeclRefType> paramType = DeclRefType::Create(
- parser->getSession(),
- DeclRef<Decl>(decl, nullptr));
-
- RefPtr<SharedTypeExpr> paramTypeExpr = new SharedTypeExpr();
- paramTypeExpr->loc = decl->loc;
- paramTypeExpr->base.type = paramType;
- paramTypeExpr->type = QualType(getTypeType(paramType));
-
- paramConstraint->sub = TypeExp(paramTypeExpr);
- paramConstraint->sup = parser->ParseTypeExp();
-
- AddMember(decl, paramConstraint);
- } while (AdvanceIf(parser, TokenType::Comma));
- }
- }
-
- RefPtr<RefObject> parseAssocType(Parser * parser, void *)
- {
- RefPtr<AssocTypeDecl> assocTypeDecl = new AssocTypeDecl();
-
- auto nameToken = parser->ReadToken(TokenType::Identifier);
- assocTypeDecl->nameAndLoc = NameLoc(nameToken);
- assocTypeDecl->loc = nameToken.loc;
- parseOptionalGenericConstraints(parser, assocTypeDecl);
- parser->ReadToken(TokenType::Semicolon);
- return assocTypeDecl;
- }
-
- RefPtr<RefObject> parseGlobalGenericParamDecl(Parser * parser, void *)
- {
- RefPtr<GlobalGenericParamDecl> genParamDecl = new GlobalGenericParamDecl();
- auto nameToken = parser->ReadToken(TokenType::Identifier);
- genParamDecl->nameAndLoc = NameLoc(nameToken);
- genParamDecl->loc = nameToken.loc;
- parseOptionalGenericConstraints(parser, genParamDecl);
- parser->ReadToken(TokenType::Semicolon);
- return genParamDecl;
- }
-
- static RefPtr<RefObject> parseInterfaceDecl(Parser* parser, void* /*userData*/)
- {
- RefPtr<InterfaceDecl> decl = new InterfaceDecl();
- parser->FillPosition(decl.Ptr());
- decl->nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
-
- parseOptionalInheritanceClause(parser, decl.Ptr());
-
- parseAggTypeDeclBody(parser, decl.Ptr());
-
- return decl;
- }
-
- static RefPtr<RefObject> parseConstructorDecl(Parser* parser, void* /*userData*/)
- {
- RefPtr<ConstructorDecl> decl = new ConstructorDecl();
- parser->FillPosition(decl.Ptr());
-
- // TODO: we need to make sure that all initializers have
- // the same name, but that this name doesn't conflict
- // with any user-defined names.
- // Giving them a name (rather than leaving it null)
- // ensures that we can use name-based lookup to find
- // all of the initializers on a type (and has
- // the potential to unify initializer lookup with
- // ordinary member lookup).
- decl->nameAndLoc.name = getName(parser, "$init");
-
- parseParameterList(parser, decl);
-
- decl->Body = parseOptBody(parser);
-
- return decl;
- }
-
- static RefPtr<AccessorDecl> parseAccessorDecl(Parser* parser)
- {
- Modifiers modifiers = ParseModifiers(parser);
-
- RefPtr<AccessorDecl> decl;
- if( AdvanceIf(parser, "get") )
- {
- decl = new GetterDecl();
- }
- else if( AdvanceIf(parser, "set") )
- {
- decl = new SetterDecl();
- }
- else if( AdvanceIf(parser, "ref") )
- {
- decl = new RefAccessorDecl();
- }
- else
- {
- Unexpected(parser);
- return nullptr;
- }
-
- AddModifiers(decl, modifiers.first);
-
- if( parser->tokenReader.PeekTokenType() == TokenType::LBrace )
- {
- decl->Body = parser->parseBlockStatement();
- }
- else
- {
- parser->ReadToken(TokenType::Semicolon);
- }
-
- return decl;
- }
-
- static RefPtr<RefObject> ParseSubscriptDecl(Parser* parser, void* /*userData*/)
- {
- RefPtr<SubscriptDecl> decl = new SubscriptDecl();
- parser->FillPosition(decl.Ptr());
-
- // TODO: the use of this name here is a bit magical...
- decl->nameAndLoc.name = getName(parser, "operator[]");
-
- parseParameterList(parser, decl);
-
- if( AdvanceIf(parser, TokenType::RightArrow) )
- {
- decl->ReturnType = parser->ParseTypeExp();
- }
-
- if( AdvanceIf(parser, TokenType::LBrace) )
- {
- // We want to parse nested "accessor" declarations
- while( !AdvanceIfMatch(parser, TokenType::RBrace) )
- {
- auto accessor = parseAccessorDecl(parser);
- AddMember(decl, accessor);
- }
- }
- else
- {
- parser->ReadToken(TokenType::Semicolon);
-
- // empty body should be treated like `{ get; }`
- }
-
- return decl;
- }
-
- static bool expect(Parser* parser, TokenType tokenType)
- {
- return parser->ReadToken(tokenType).type == tokenType;
- }
-
- static void parseModernVarDeclBaseCommon(
- Parser* parser,
- RefPtr<VarDeclBase> decl)
- {
- parser->FillPosition(decl.Ptr());
- decl->nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
-
- if(AdvanceIf(parser, TokenType::Colon))
- {
- decl->type = parser->ParseTypeExp();
- }
-
- if(AdvanceIf(parser, TokenType::OpAssign))
- {
- decl->initExpr = parser->ParseInitExpr();
- }
- }
-
- static void parseModernVarDeclCommon(
- Parser* parser,
- RefPtr<VarDecl> decl)
- {
- parseModernVarDeclBaseCommon(parser, decl);
- expect(parser, TokenType::Semicolon);
- }
-
- static RefPtr<RefObject> parseLetDecl(
- Parser* parser, void* /*userData*/)
- {
- RefPtr<LetDecl> decl = new LetDecl();
- parseModernVarDeclCommon(parser, decl);
- return decl;
- }
-
- static RefPtr<RefObject> parseVarDecl(
- Parser* parser, void* /*userData*/)
- {
- RefPtr<VarDecl> decl = new VarDecl();
- parseModernVarDeclCommon(parser, decl);
- return decl;
- }
-
- static RefPtr<ParamDecl> parseModernParamDecl(
- Parser* parser)
- {
- RefPtr<ParamDecl> decl = new ParamDecl();
-
- // TODO: "modern" parameters should not accept keyword-based
- // modifiers and should only accept `[attribute]` syntax for
- // modifiers to keep the grammar as simple as possible.
- //
- // Further, they should accept `out` and `in out`/`inout`
- // before the type (e.g., `a: inout float4`).
- //
- decl->modifiers = ParseModifiers(parser);
- parseModernVarDeclBaseCommon(parser, decl);
- return decl;
- }
-
- static void parseModernParamList(
- Parser* parser,
- RefPtr<CallableDecl> decl)
- {
- parser->ReadToken(TokenType::LParent);
-
- while (!AdvanceIfMatch(parser, TokenType::RParent))
- {
- AddMember(decl, parseModernParamDecl(parser));
- if (AdvanceIf(parser, TokenType::RParent))
- break;
- parser->ReadToken(TokenType::Comma);
- }
- }
-
- static RefPtr<RefObject> parseFuncDecl(
- Parser* parser, void* /*userData*/)
- {
- RefPtr<FuncDecl> decl = new FuncDecl();
-
- parser->FillPosition(decl.Ptr());
- decl->nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
-
- return parseOptGenericDecl(parser, [&](GenericDecl*)
- {
- parser->PushScope(decl.Ptr());
- parseModernParamList(parser, decl);
- if(AdvanceIf(parser, TokenType::RightArrow))
- {
- decl->ReturnType = parser->ParseTypeExp();
- }
- decl->Body = parseOptBody(parser);
- parser->PopScope();
- return decl;
- });
- }
-
- static RefPtr<RefObject> parseTypeAliasDecl(
- Parser* parser, void* /*userData*/)
- {
- RefPtr<TypeAliasDecl> decl = new TypeAliasDecl();
-
- parser->FillPosition(decl.Ptr());
- decl->nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
-
- return parseOptGenericDecl(parser, [&](GenericDecl*)
- {
- if( expect(parser, TokenType::OpAssign) )
- {
- decl->type = parser->ParseTypeExp();
- }
- expect(parser, TokenType::Semicolon);
- return decl;
- });
- }
-
- // This is a catch-all syntax-construction callback to handle cases where
- // a piece of syntax is fully defined by the keyword to use, along with
- // the class of AST node to construct.
- static RefPtr<RefObject> parseSimpleSyntax(Parser* /*parser*/, void* userData)
- {
- SyntaxClassBase syntaxClass((SyntaxClassBase::ClassInfo*) userData);
- return (RefObject*) syntaxClass.createInstanceImpl();
- }
-
- // Parse a declaration of a keyword that can be used to define further syntax.
- static RefPtr<RefObject> parseSyntaxDecl(Parser* parser, void* /*userData*/)
- {
- // Right now the basic form is:
- //
- // syntax <name:id> [: <syntaxClass:id>] [= <existingKeyword:id>];
- //
- // - `name` gives the name of the keyword to define.
- // - `syntaxClass` is the name of an AST node class that we expect
- // this syntax to construct when parsed.
- // - `existingKeyword` is the name of an existing keyword that
- // the new syntax should be an alias for.
-
- // First we parse the keyword name.
- auto nameAndLoc = expectIdentifier(parser);
-
- // Next we look for a clause that specified the AST node class.
- SyntaxClass<RefObject> syntaxClass;
- if (AdvanceIf(parser, TokenType::Colon))
- {
- // User is specifying the class that should be construted
- auto classNameAndLoc = expectIdentifier(parser);
-
- syntaxClass = parser->getSession()->findSyntaxClass(classNameAndLoc.name);
- }
-
- // If the user specified a syntax class, then we will default
- // to the `parseSimpleSyntax` callback that will just construct
- // an instance of that type to represent the keyword in the AST.
- SyntaxParseCallback parseCallback = &parseSimpleSyntax;
- void* parseUserData = (void*) syntaxClass.classInfo;
-
- // Next we look for an initializer that will make this keyword
- // an alias for some existing keyword.
- if (AdvanceIf(parser, TokenType::OpAssign))
- {
- auto existingKeywordNameAndLoc = expectIdentifier(parser);
-
- auto existingSyntax = tryLookUpSyntaxDecl(parser, existingKeywordNameAndLoc.name);
- if (!existingSyntax)
- {
- // TODO: diagnose: keyword did not name syntax
- }
- else
- {
- // The user is expecting us to parse our new syntax like
- // the existing syntax given, so we need to override
- // the callback.
- parseCallback = existingSyntax->parseCallback;
- parseUserData = existingSyntax->parseUserData;
-
- // If we don't already have a syntax class specified, then
- // we will crib the one from the existing syntax, to ensure
- // that we are creating a drop-in alias.
- if (!syntaxClass.classInfo)
- syntaxClass = existingSyntax->syntaxClass;
- }
- }
-
- // It is an error if the user didn't give us either an existing keyword
- // to use to the define the callback, or a valid AST node class to construct.
- //
- // TODO: down the line this should be expanded so that the user can reference
- // an existing *function* to use to parse the chosen syntax.
- if (!syntaxClass.classInfo)
- {
- // TODO: diagnose: either a type or an existing keyword needs to be specified
- }
-
- expect(parser, TokenType::Semicolon);
-
- // TODO: skip creating the declaration if anything failed, just to not screw things
- // up for downstream code?
-
- RefPtr<SyntaxDecl> syntaxDecl = new SyntaxDecl();
- syntaxDecl->nameAndLoc = nameAndLoc;
- syntaxDecl->loc = nameAndLoc.loc;
- syntaxDecl->syntaxClass = syntaxClass;
- syntaxDecl->parseCallback = parseCallback;
- syntaxDecl->parseUserData = parseUserData;
- return syntaxDecl;
- }
-
- // A parameter declaration in an attribute declaration.
- //
- // We are going to use `name: type` syntax just for simplicty, and let the type
- // be optional, because we don't actually need it in all cases.
- //
- static RefPtr<ParamDecl> parseAttributeParamDecl(Parser* parser)
- {
- auto nameAndLoc = expectIdentifier(parser);
-
- RefPtr<ParamDecl> paramDecl = new ParamDecl();
- paramDecl->nameAndLoc = nameAndLoc;
-
- if(AdvanceIf(parser, TokenType::Colon))
- {
- paramDecl->type = parser->ParseTypeExp();
- }
-
- if(AdvanceIf(parser, TokenType::OpAssign))
- {
- paramDecl->initExpr = parser->ParseInitExpr();
- }
-
- return paramDecl;
- }
-
- // Parse declaration of a name to be used for resolving `[attribute(...)]` style modifiers.
- //
- // These are distinct from `syntax` declarations, because their names don't get added
- // to the current scope using their default name.
- //
- // Also, attribute-specific code doesn't get invokved during parsing. We always parse
- // using the default attribute-parsing logic and then all specialized behavior takes
- // place during semantic checking.
- //
- static RefPtr<RefObject> parseAttributeSyntaxDecl(Parser* parser, void* /*userData*/)
- {
- // Right now the basic form is:
- //
- // attribute_syntax <name:id> : <syntaxClass:id>;
- //
- // - `name` gives the name of the attribute to define.
- // - `syntaxClass` is the name of an AST node class that we expect
- // this attribute to create when checked.
- // - `existingKeyword` is the name of an existing keyword that
- // the new syntax should be an alias for.
-
- expect(parser, TokenType::LBracket);
-
- // First we parse the attribute name.
- auto nameAndLoc = expectIdentifier(parser);
-
- RefPtr<AttributeDecl> attrDecl = new AttributeDecl();
- if(AdvanceIf(parser, TokenType::LParent))
- {
- while(!AdvanceIfMatch(parser, TokenType::RParent))
- {
- auto param = parseAttributeParamDecl(parser);
-
- AddMember(attrDecl, param);
-
- if(AdvanceIfMatch(parser, TokenType::RParent))
- break;
-
- expect(parser, TokenType::Comma);
- }
- }
-
- expect(parser, TokenType::RBracket);
-
- // TODO: we should allow parameters to be specified here, to cut down
- // on the amount of per-attribute-type logic that has to occur later.
-
- // Next we look for a clause that specified the AST node class.
- SyntaxClass<RefObject> syntaxClass;
- if (AdvanceIf(parser, TokenType::Colon))
- {
- // User is specifying the class that should be construted
- auto classNameAndLoc = expectIdentifier(parser);
-
- syntaxClass = parser->getSession()->findSyntaxClass(classNameAndLoc.name);
- }
- else
- {
- // For now we don't support the alternative approach where
- // an existing piece of syntax is named to provide the parsing
- // support.
-
- // TODO: diagnose: a syntax class must be specified.
- }
-
- expect(parser, TokenType::Semicolon);
-
- // TODO: skip creating the declaration if anything failed, just to not screw things
- // up for downstream code?
-
- attrDecl->nameAndLoc = nameAndLoc;
- attrDecl->loc = nameAndLoc.loc;
- attrDecl->syntaxClass = syntaxClass;
- return attrDecl;
- }
-
- // Finish up work on a declaration that was parsed
- static void CompleteDecl(
- Parser* /*parser*/,
- RefPtr<Decl> decl,
- ContainerDecl* containerDecl,
- Modifiers modifiers)
- {
- // Add any modifiers we parsed before the declaration to the list
- // of modifiers on the declaration itself.
- //
- // We need to be careful, because if `decl` is a generic declaration,
- // then we really want the modifiers to apply to the inner declaration.
- //
- RefPtr<Decl> declToModify = decl;
- if(auto genericDecl = as<GenericDecl>(decl))
- declToModify = genericDecl->inner;
- AddModifiers(declToModify.Ptr(), modifiers.first);
-
- // Make sure the decl is properly nested inside its lexical parent
- if (containerDecl)
- {
- AddMember(containerDecl, decl);
- }
- }
-
- static RefPtr<DeclBase> ParseDeclWithModifiers(
- Parser* parser,
- ContainerDecl* containerDecl,
- Modifiers modifiers )
- {
- RefPtr<DeclBase> decl;
-
- auto loc = parser->tokenReader.PeekLoc();
-
- switch (peekTokenType(parser))
- {
- case TokenType::Identifier:
- {
- // A declaration that starts with an identifier might be:
- //
- // - A keyword-based declaration (e.g., `cbuffer ...`)
- // - The beginning of a type in a declarator-based declaration (e.g., `int ...`)
-
- // First we will check whether we can use the identifier token
- // as a declaration keyword and parse a declaration using
- // its associated callback:
- RefPtr<Decl> parsedDecl;
- if (tryParseUsingSyntaxDecl<Decl>(parser, &parsedDecl))
- {
- decl = parsedDecl;
- break;
- }
-
- // Our final fallback case is to assume that the user is
- // probably writing a C-style declarator-based declaration.
- decl = ParseDeclaratorDecl(parser, containerDecl);
- break;
- }
- break;
-
- // It is valid in HLSL/GLSL to have an "empty" declaration
- // that consists of just a semicolon. In particular, this
- // gets used a lot in GLSL to attach custom semantics to
- // shader input or output.
- //
- case TokenType::Semicolon:
- {
- advanceToken(parser);
-
- decl = new EmptyDecl();
- decl->loc = loc;
- }
- break;
-
- // If nothing else matched, we try to parse an "ordinary" declarator-based declaration
- default:
- decl = ParseDeclaratorDecl(parser, containerDecl);
- break;
- }
-
- if (decl)
- {
- if( auto dd = as<Decl>(decl) )
- {
- CompleteDecl(parser, dd, containerDecl, modifiers);
- }
- else if(auto declGroup = as<DeclGroup>(decl))
- {
- // We are going to add the same modifiers to *all* of these declarations,
- // so we want to give later passes a way to detect which modifiers
- // were shared, vs. which ones are specific to a single declaration.
-
- auto sharedModifiers = new SharedModifiers();
- sharedModifiers->next = modifiers.first;
- modifiers.first = sharedModifiers;
-
- for( auto subDecl : declGroup->decls )
- {
- CompleteDecl(parser, subDecl, containerDecl, modifiers);
- }
- }
- }
- return decl;
- }
-
- static RefPtr<DeclBase> ParseDecl(
- Parser* parser,
- ContainerDecl* containerDecl)
- {
- Modifiers modifiers = ParseModifiers(parser);
- return ParseDeclWithModifiers(parser, containerDecl, modifiers);
- }
-
- static RefPtr<Decl> ParseSingleDecl(
- Parser* parser,
- ContainerDecl* containerDecl)
- {
- auto declBase = ParseDecl(parser, containerDecl);
- if(!declBase)
- return nullptr;
- if( auto decl = as<Decl>(declBase) )
- {
- return decl;
- }
- else if( auto declGroup = as<DeclGroup>(declBase) )
- {
- if( declGroup->decls.getCount() == 1 )
- {
- return declGroup->decls[0];
- }
- }
-
- parser->sink->diagnose(declBase->loc, Diagnostics::unimplemented, "didn't expect multiple declarations here");
- return nullptr;
- }
-
-
- // Parse a body consisting of declarations
- static void ParseDeclBody(
- Parser* parser,
- ContainerDecl* containerDecl,
- TokenType closingToken)
- {
- while(!AdvanceIfMatch(parser, closingToken))
- {
- ParseDecl(parser, containerDecl);
- }
- }
-
- // Parse the `{}`-delimeted body of an aggregate type declaration
- static void parseAggTypeDeclBody(
- Parser* parser,
- AggTypeDeclBase* decl)
- {
- // TODO: the scope used for the body might need to be
- // slightly specialized to deal with the complexity
- // of how `this` works.
- //
- // Alternatively, that complexity can be pushed down
- // to semantic analysis so that it doesn't clutter
- // things here.
- parser->PushScope(decl);
-
- parser->ReadToken(TokenType::LBrace);
- ParseDeclBody(parser, decl, TokenType::RBrace);
-
- parser->PopScope();
- }
-
-
- void Parser::parseSourceFile(ModuleDecl* program)
- {
- if (outerScope)
- {
- currentScope = outerScope;
- }
-
- PushScope(program);
- program->loc = tokenReader.PeekLoc();
- program->scope = currentScope;
- ParseDeclBody(this, program, TokenType::EndOfFile);
- PopScope();
-
- SLANG_RELEASE_ASSERT(currentScope == outerScope);
- currentScope = nullptr;
- }
-
- RefPtr<Decl> Parser::ParseStruct()
- {
- RefPtr<StructDecl> rs = new StructDecl();
- FillPosition(rs.Ptr());
- ReadToken("struct");
-
- // TODO: support `struct` declaration without tag
- rs->nameAndLoc = expectIdentifier(this);
-
- return parseOptGenericDecl(this, [&](GenericDecl*)
- {
- // We allow for an inheritance clause on a `struct`
- // so that it can conform to interfaces.
- parseOptionalInheritanceClause(this, rs.Ptr());
- parseAggTypeDeclBody(this, rs.Ptr());
- return rs;
- });
- }
-
- RefPtr<ClassDecl> Parser::ParseClass()
- {
- RefPtr<ClassDecl> rs = new ClassDecl();
- FillPosition(rs.Ptr());
- ReadToken("class");
- rs->nameAndLoc = expectIdentifier(this);
-
- parseOptionalInheritanceClause(this, rs.Ptr());
-
- parseAggTypeDeclBody(this, rs.Ptr());
- return rs;
- }
-
- static RefPtr<EnumCaseDecl> parseEnumCaseDecl(Parser* parser)
- {
- RefPtr<EnumCaseDecl> decl = new EnumCaseDecl();
- decl->nameAndLoc = expectIdentifier(parser);
-
- if(AdvanceIf(parser, TokenType::OpAssign))
- {
- decl->tagExpr = parser->ParseArgExpr();
- }
-
- return decl;
- }
-
- static RefPtr<Decl> parseEnumDecl(Parser* parser)
- {
- RefPtr<EnumDecl> decl = new EnumDecl();
- parser->FillPosition(decl);
-
- parser->ReadToken("enum");
-
- // HACK: allow the user to write `enum class` in case
- // they are trying to share a header between C++ and Slang.
- //
- // TODO: diagnose this with a warning some day, and move
- // toward deprecating it.
- //
- AdvanceIf(parser, "class");
-
- decl->nameAndLoc = expectIdentifier(parser);
-
-
- return parseOptGenericDecl(parser, [&](GenericDecl*)
- {
- parseOptionalInheritanceClause(parser, decl);
- parser->ReadToken(TokenType::LBrace);
-
- while(!AdvanceIfMatch(parser, TokenType::RBrace))
- {
- RefPtr<EnumCaseDecl> caseDecl = parseEnumCaseDecl(parser);
- AddMember(decl, caseDecl);
-
- if(AdvanceIf(parser, TokenType::RBrace))
- break;
-
- parser->ReadToken(TokenType::Comma);
- }
- return decl;
- });
- }
-
- static RefPtr<Stmt> ParseSwitchStmt(Parser* parser)
- {
- RefPtr<SwitchStmt> stmt = new SwitchStmt();
- parser->FillPosition(stmt.Ptr());
- parser->ReadToken("switch");
- parser->ReadToken(TokenType::LParent);
- stmt->condition = parser->ParseExpression();
- parser->ReadToken(TokenType::RParent);
- stmt->body = parser->parseBlockStatement();
- return stmt;
- }
-
- static RefPtr<Stmt> ParseCaseStmt(Parser* parser)
- {
- RefPtr<CaseStmt> stmt = new CaseStmt();
- parser->FillPosition(stmt.Ptr());
- parser->ReadToken("case");
- stmt->expr = parser->ParseExpression();
- parser->ReadToken(TokenType::Colon);
- return stmt;
- }
-
- static RefPtr<Stmt> ParseDefaultStmt(Parser* parser)
- {
- RefPtr<DefaultStmt> stmt = new DefaultStmt();
- parser->FillPosition(stmt.Ptr());
- parser->ReadToken("default");
- parser->ReadToken(TokenType::Colon);
- return stmt;
- }
-
- static bool isTypeName(Parser* parser, Name* name)
- {
- auto lookupResult = lookUp(
- parser->getSession(),
- nullptr, // no semantics visitor available yet
- name,
- parser->currentScope);
- if(!lookupResult.isValid() || lookupResult.isOverloaded())
- return false;
-
- auto decl = lookupResult.item.declRef.getDecl();
- if( auto typeDecl = as<AggTypeDecl>(decl) )
- {
- return true;
- }
- else if( auto typeVarDecl = as<SimpleTypeDecl>(decl) )
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
- static bool peekTypeName(Parser* parser)
- {
- if(!parser->LookAheadToken(TokenType::Identifier))
- return false;
-
- auto name = parser->tokenReader.PeekToken().getName();
- return isTypeName(parser, name);
- }
-
- RefPtr<Stmt> parseCompileTimeForStmt(
- Parser* parser)
- {
- RefPtr<ScopeDecl> scopeDecl = new ScopeDecl();
- RefPtr<CompileTimeForStmt> stmt = new CompileTimeForStmt();
- stmt->scopeDecl = scopeDecl;
-
-
- parser->ReadToken("for");
- parser->ReadToken(TokenType::LParent);
-
- NameLoc varNameAndLoc = expectIdentifier(parser);
- RefPtr<VarDecl> varDecl = new VarDecl();
- varDecl->nameAndLoc = varNameAndLoc;
- varDecl->loc = varNameAndLoc.loc;
-
- stmt->varDecl = varDecl;
-
- parser->ReadToken("in");
- parser->ReadToken("Range");
- parser->ReadToken(TokenType::LParent);
-
- RefPtr<Expr> rangeBeginExpr;
- RefPtr<Expr> rangeEndExpr = parser->ParseArgExpr();
- if (AdvanceIf(parser, TokenType::Comma))
- {
- rangeBeginExpr = rangeEndExpr;
- rangeEndExpr = parser->ParseArgExpr();
- }
-
- stmt->rangeBeginExpr = rangeBeginExpr;
- stmt->rangeEndExpr = rangeEndExpr;
-
- parser->ReadToken(TokenType::RParent);
- parser->ReadToken(TokenType::RParent);
-
- parser->pushScopeAndSetParent(scopeDecl);
- AddMember(parser->currentScope, varDecl);
-
- stmt->body = parser->ParseStatement();
-
- parser->PopScope();
-
- return stmt;
- }
-
- RefPtr<Stmt> parseCompileTimeStmt(
- Parser* parser)
- {
- parser->ReadToken(TokenType::Dollar);
- if (parser->LookAheadToken("for"))
- {
- return parseCompileTimeForStmt(parser);
- }
- else
- {
- Unexpected(parser);
- return nullptr;
- }
- }
-
- RefPtr<Stmt> Parser::ParseStatement()
- {
- auto modifiers = ParseModifiers(this);
-
- RefPtr<Stmt> statement;
- if (LookAheadToken(TokenType::LBrace))
- statement = parseBlockStatement();
- else if (peekTypeName(this))
- statement = parseVarDeclrStatement(modifiers);
- else if (LookAheadToken("if"))
- statement = parseIfStatement();
- else if (LookAheadToken("for"))
- statement = ParseForStatement();
- else if (LookAheadToken("while"))
- statement = ParseWhileStatement();
- else if (LookAheadToken("do"))
- statement = ParseDoWhileStatement();
- else if (LookAheadToken("break"))
- statement = ParseBreakStatement();
- else if (LookAheadToken("continue"))
- statement = ParseContinueStatement();
- else if (LookAheadToken("return"))
- statement = ParseReturnStatement();
- else if (LookAheadToken("discard"))
- {
- statement = new DiscardStmt();
- FillPosition(statement.Ptr());
- ReadToken("discard");
- ReadToken(TokenType::Semicolon);
- }
- else if (LookAheadToken("switch"))
- statement = ParseSwitchStmt(this);
- else if (LookAheadToken("case"))
- statement = ParseCaseStmt(this);
- else if (LookAheadToken("default"))
- statement = ParseDefaultStmt(this);
- else if (LookAheadToken(TokenType::Dollar))
- {
- statement = parseCompileTimeStmt(this);
- }
- else if (LookAheadToken(TokenType::Identifier))
- {
- // We might be looking at a local declaration, or an
- // expression statement, and we need to figure out which.
- //
- // We'll solve this with backtracking for now.
-
- TokenReader::ParsingCursor startPos = tokenReader.getCursor();
-
- // Try to parse a type (knowing that the type grammar is
- // a subset of the expression grammar, and so this should
- // always succeed).
- RefPtr<Expr> type = ParseType();
- // We don't actually care about the type, though, so
- // don't retain it
- type = nullptr;
-
- // If the next token after we parsed a type looks like
- // we are going to declare a variable, then lets guess
- // that this is a declaration.
- //
- // TODO(tfoley): this wouldn't be robust for more
- // general kinds of declarators (notably pointer declarators),
- // so we'll need to be careful about this.
- if (LookAheadToken(TokenType::Identifier))
- {
- // Reset the cursor and try to parse a declaration now.
- // Note: the declaration will consume any modifiers
- // that had been in place on the statement.
- tokenReader.setCursor(startPos);
- statement = parseVarDeclrStatement(modifiers);
- return statement;
- }
-
- // Fallback: reset and parse an expression
- tokenReader.setCursor(startPos);
- statement = ParseExpressionStatement();
- }
- else if (LookAheadToken(TokenType::Semicolon))
- {
- statement = new EmptyStmt();
- FillPosition(statement.Ptr());
- ReadToken(TokenType::Semicolon);
- }
- else
- {
- // Default case should always fall back to parsing an expression,
- // and then let that detect any errors
- statement = ParseExpressionStatement();
- }
-
- if (statement && !as<DeclStmt>(statement))
- {
- // Install any modifiers onto the statement.
- // Note: this path is bypassed in the case of a
- // declaration statement, so we don't end up
- // doubling up the modifiers.
- statement->modifiers = modifiers;
- }
-
- return statement;
- }
-
- RefPtr<Stmt> Parser::parseBlockStatement()
- {
- RefPtr<ScopeDecl> scopeDecl = new ScopeDecl();
- RefPtr<BlockStmt> blockStatement = new BlockStmt();
- blockStatement->scopeDecl = scopeDecl;
- pushScopeAndSetParent(scopeDecl.Ptr());
- ReadToken(TokenType::LBrace);
-
- RefPtr<Stmt> body;
-
- if(!tokenReader.IsAtEnd())
- {
- FillPosition(blockStatement.Ptr());
- }
- while (!AdvanceIfMatch(this, TokenType::RBrace))
- {
- auto stmt = ParseStatement();
- if(stmt)
- {
- if (!body)
- {
- body = stmt;
- }
- else if (auto seqStmt = as<SeqStmt>(body))
- {
- seqStmt->stmts.add(stmt);
- }
- else
- {
- RefPtr<SeqStmt> newBody = new SeqStmt();
- newBody->loc = blockStatement->loc;
- newBody->stmts.add(body);
- newBody->stmts.add(stmt);
-
- body = newBody;
- }
- }
- TryRecover(this);
- }
- PopScope();
-
- if(!body)
- {
- body = new EmptyStmt();
- body->loc = blockStatement->loc;
- }
-
- blockStatement->body = body;
- return blockStatement;
- }
-
- RefPtr<DeclStmt> Parser::parseVarDeclrStatement(
- Modifiers modifiers)
- {
- RefPtr<DeclStmt>varDeclrStatement = new DeclStmt();
-
- FillPosition(varDeclrStatement.Ptr());
- auto decl = ParseDeclWithModifiers(this, currentScope->containerDecl, modifiers);
- varDeclrStatement->decl = decl;
- return varDeclrStatement;
- }
-
- RefPtr<IfStmt> Parser::parseIfStatement()
- {
- RefPtr<IfStmt> ifStatement = new IfStmt();
- FillPosition(ifStatement.Ptr());
- ReadToken("if");
- ReadToken(TokenType::LParent);
- ifStatement->Predicate = ParseExpression();
- ReadToken(TokenType::RParent);
- ifStatement->PositiveStatement = ParseStatement();
- if (LookAheadToken("else"))
- {
- ReadToken("else");
- ifStatement->NegativeStatement = ParseStatement();
- }
- return ifStatement;
- }
-
- RefPtr<ForStmt> Parser::ParseForStatement()
- {
- RefPtr<ScopeDecl> scopeDecl = new ScopeDecl();
-
- // HLSL implements the bad approach to scoping a `for` loop
- // variable, and we want to respect that, but *only* when
- // parsing HLSL code.
- //
-
- bool brokenScoping = getSourceLanguage() == SourceLanguage::HLSL;
-
- // We will create a distinct syntax node class for the unscoped
- // case, just so that we can correctly handle it in downstream
- // logic.
- //
- RefPtr<ForStmt> stmt;
- if (brokenScoping)
- {
- stmt = new UnscopedForStmt();
- }
- else
- {
- stmt = new ForStmt();
- }
-
- stmt->scopeDecl = scopeDecl;
-
- if(!brokenScoping)
- pushScopeAndSetParent(scopeDecl.Ptr());
- FillPosition(stmt.Ptr());
- ReadToken("for");
- ReadToken(TokenType::LParent);
- if (peekTypeName(this))
- {
- stmt->InitialStatement = parseVarDeclrStatement(Modifiers());
- }
- else
- {
- if (!LookAheadToken(TokenType::Semicolon))
- {
- stmt->InitialStatement = ParseExpressionStatement();
- }
- else
- {
- ReadToken(TokenType::Semicolon);
- }
- }
- if (!LookAheadToken(TokenType::Semicolon))
- stmt->PredicateExpression = ParseExpression();
- ReadToken(TokenType::Semicolon);
- if (!LookAheadToken(TokenType::RParent))
- stmt->SideEffectExpression = ParseExpression();
- ReadToken(TokenType::RParent);
- stmt->Statement = ParseStatement();
-
- if (!brokenScoping)
- PopScope();
-
- return stmt;
- }
-
- RefPtr<WhileStmt> Parser::ParseWhileStatement()
- {
- RefPtr<WhileStmt> whileStatement = new WhileStmt();
- FillPosition(whileStatement.Ptr());
- ReadToken("while");
- ReadToken(TokenType::LParent);
- whileStatement->Predicate = ParseExpression();
- ReadToken(TokenType::RParent);
- whileStatement->Statement = ParseStatement();
- return whileStatement;
- }
-
- RefPtr<DoWhileStmt> Parser::ParseDoWhileStatement()
- {
- RefPtr<DoWhileStmt> doWhileStatement = new DoWhileStmt();
- FillPosition(doWhileStatement.Ptr());
- ReadToken("do");
- doWhileStatement->Statement = ParseStatement();
- ReadToken("while");
- ReadToken(TokenType::LParent);
- doWhileStatement->Predicate = ParseExpression();
- ReadToken(TokenType::RParent);
- ReadToken(TokenType::Semicolon);
- return doWhileStatement;
- }
-
- RefPtr<BreakStmt> Parser::ParseBreakStatement()
- {
- RefPtr<BreakStmt> breakStatement = new BreakStmt();
- FillPosition(breakStatement.Ptr());
- ReadToken("break");
- ReadToken(TokenType::Semicolon);
- return breakStatement;
- }
-
- RefPtr<ContinueStmt> Parser::ParseContinueStatement()
- {
- RefPtr<ContinueStmt> continueStatement = new ContinueStmt();
- FillPosition(continueStatement.Ptr());
- ReadToken("continue");
- ReadToken(TokenType::Semicolon);
- return continueStatement;
- }
-
- RefPtr<ReturnStmt> Parser::ParseReturnStatement()
- {
- RefPtr<ReturnStmt> returnStatement = new ReturnStmt();
- FillPosition(returnStatement.Ptr());
- ReadToken("return");
- if (!LookAheadToken(TokenType::Semicolon))
- returnStatement->Expression = ParseExpression();
- ReadToken(TokenType::Semicolon);
- return returnStatement;
- }
-
- RefPtr<ExpressionStmt> Parser::ParseExpressionStatement()
- {
- RefPtr<ExpressionStmt> statement = new ExpressionStmt();
-
- FillPosition(statement.Ptr());
- statement->Expression = ParseExpression();
-
- ReadToken(TokenType::Semicolon);
- return statement;
- }
-
- RefPtr<ParamDecl> Parser::ParseParameter()
- {
- RefPtr<ParamDecl> parameter = new ParamDecl();
- parameter->modifiers = ParseModifiers(this);
-
- DeclaratorInfo declaratorInfo;
- declaratorInfo.typeSpec = ParseType();
-
- InitDeclarator initDeclarator = ParseInitDeclarator(this);
- UnwrapDeclarator(initDeclarator, &declaratorInfo);
-
- // Assume it is a variable-like declarator
- CompleteVarDecl(this, parameter, declaratorInfo);
- return parameter;
- }
-
- RefPtr<Expr> Parser::ParseType()
- {
- auto typeSpec = parseTypeSpec(this);
- if( typeSpec.decl )
- {
- AddMember(currentScope, typeSpec.decl);
- }
- auto typeExpr = typeSpec.expr;
-
- typeExpr = parsePostfixTypeSuffix(this, typeExpr);
-
- return typeExpr;
- }
-
-
-
- TypeExp Parser::ParseTypeExp()
- {
- return TypeExp(ParseType());
- }
-
- enum class Associativity
- {
- Left, Right
- };
-
-
-
- Associativity GetAssociativityFromLevel(Precedence level)
- {
- if (level == Precedence::Assignment)
- return Associativity::Right;
- else
- return Associativity::Left;
- }
-
-
-
-
- Precedence GetOpLevel(Parser* parser, TokenType type)
- {
- switch(type)
- {
- case TokenType::QuestionMark:
- return Precedence::TernaryConditional;
- case TokenType::Comma:
- return Precedence::Comma;
- case TokenType::OpAssign:
- case TokenType::OpMulAssign:
- case TokenType::OpDivAssign:
- case TokenType::OpAddAssign:
- case TokenType::OpSubAssign:
- case TokenType::OpModAssign:
- case TokenType::OpShlAssign:
- case TokenType::OpShrAssign:
- case TokenType::OpOrAssign:
- case TokenType::OpAndAssign:
- case TokenType::OpXorAssign:
- return Precedence::Assignment;
- case TokenType::OpOr:
- return Precedence::LogicalOr;
- case TokenType::OpAnd:
- return Precedence::LogicalAnd;
- case TokenType::OpBitOr:
- return Precedence::BitOr;
- case TokenType::OpBitXor:
- return Precedence::BitXor;
- case TokenType::OpBitAnd:
- return Precedence::BitAnd;
- case TokenType::OpEql:
- case TokenType::OpNeq:
- return Precedence::EqualityComparison;
- case TokenType::OpGreater:
- case TokenType::OpGeq:
- // Don't allow these ops inside a generic argument
- if (parser->genericDepth > 0) return Precedence::Invalid;
- ; // fall-thru
- case TokenType::OpLeq:
- case TokenType::OpLess:
- return Precedence::RelationalComparison;
- case TokenType::OpRsh:
- // Don't allow this op inside a generic argument
- if (parser->genericDepth > 0) return Precedence::Invalid;
- ; // fall-thru
- case TokenType::OpLsh:
- return Precedence::BitShift;
- case TokenType::OpAdd:
- case TokenType::OpSub:
- return Precedence::Additive;
- case TokenType::OpMul:
- case TokenType::OpDiv:
- case TokenType::OpMod:
- return Precedence::Multiplicative;
- default:
- return Precedence::Invalid;
- }
- }
-
- static RefPtr<Expr> parseOperator(Parser* parser)
- {
- Token opToken;
- switch(parser->tokenReader.PeekTokenType())
- {
- case TokenType::QuestionMark:
- opToken = parser->ReadToken();
- opToken.Content = UnownedStringSlice::fromLiteral("?:");
- break;
-
- default:
- opToken = parser->ReadToken();
- break;
- }
-
- auto opExpr = new VarExpr();
- opExpr->name = getName(parser, opToken.Content);
- opExpr->scope = parser->currentScope;
- opExpr->loc = opToken.loc;
-
- return opExpr;
-
- }
-
- static RefPtr<Expr> createInfixExpr(
- Parser* /*parser*/,
- RefPtr<Expr> left,
- RefPtr<Expr> op,
- RefPtr<Expr> right)
- {
- RefPtr<InfixExpr> expr = new InfixExpr();
- expr->loc = op->loc;
- expr->FunctionExpr = op;
- expr->Arguments.add(left);
- expr->Arguments.add(right);
- return expr;
- }
-
- static RefPtr<Expr> parseInfixExprWithPrecedence(
- Parser* parser,
- RefPtr<Expr> inExpr,
- Precedence prec)
- {
- auto expr = inExpr;
- for(;;)
- {
- auto opTokenType = parser->tokenReader.PeekTokenType();
- auto opPrec = GetOpLevel(parser, opTokenType);
- if(opPrec < prec)
- break;
-
- auto op = parseOperator(parser);
-
- // Special case the `?:` operator since it is the
- // one non-binary case we need to deal with.
- if(opTokenType == TokenType::QuestionMark)
- {
- RefPtr<SelectExpr> select = new SelectExpr();
- select->loc = op->loc;
- select->FunctionExpr = op;
-
- select->Arguments.add(expr);
-
- select->Arguments.add(parser->ParseExpression(opPrec));
- parser->ReadToken(TokenType::Colon);
- select->Arguments.add(parser->ParseExpression(opPrec));
-
- expr = select;
- continue;
- }
-
- auto right = parser->ParseLeafExpression();
-
- for(;;)
- {
- auto nextOpPrec = GetOpLevel(parser, parser->tokenReader.PeekTokenType());
-
- if((GetAssociativityFromLevel(nextOpPrec) == Associativity::Right) ? (nextOpPrec < opPrec) : (nextOpPrec <= opPrec))
- break;
-
- right = parseInfixExprWithPrecedence(parser, right, nextOpPrec);
- }
-
- if (opTokenType == TokenType::OpAssign)
- {
- RefPtr<AssignExpr> assignExpr = new AssignExpr();
- assignExpr->loc = op->loc;
- assignExpr->left = expr;
- assignExpr->right = right;
-
- expr = assignExpr;
- }
- else
- {
- expr = createInfixExpr(parser, expr, op, right);
- }
- }
- return expr;
- }
-
- RefPtr<Expr> Parser::ParseExpression(Precedence level)
- {
- auto expr = ParseLeafExpression();
- return parseInfixExprWithPrecedence(this, expr, level);
-
-#if 0
-
- if (level == Precedence::Prefix)
- return ParseLeafExpression();
- if (level == Precedence::TernaryConditional)
- {
- // parse select clause
- auto condition = ParseExpression(Precedence(level + 1));
- if (LookAheadToken(TokenType::QuestionMark))
- {
- RefPtr<SelectExpr> select = new SelectExpr();
- FillPosition(select.Ptr());
-
- select->Arguments.Add(condition);
-
- select->FunctionExpr = parseOperator(this);
-
- select->Arguments.Add(ParseExpression(level));
- ReadToken(TokenType::Colon);
- select->Arguments.Add(ParseExpression(level));
- return select;
- }
- else
- return condition;
- }
- else
- {
- if (GetAssociativityFromLevel(level) == Associativity::Left)
- {
- auto left = ParseExpression(Precedence(level + 1));
- while (GetOpLevel(this, tokenReader.PeekTokenType()) == level)
- {
- RefPtr<OperatorExpr> tmp = new InfixExpr();
- tmp->FunctionExpr = parseOperator(this);
-
- tmp->Arguments.Add(left);
- FillPosition(tmp.Ptr());
- tmp->Arguments.Add(ParseExpression(Precedence(level + 1)));
- left = tmp;
- }
- return left;
- }
- else
- {
- auto left = ParseExpression(Precedence(level + 1));
- if (GetOpLevel(this, tokenReader.PeekTokenType()) == level)
- {
- RefPtr<OperatorExpr> tmp = new InfixExpr();
- tmp->Arguments.Add(left);
- FillPosition(tmp.Ptr());
- tmp->FunctionExpr = parseOperator(this);
- tmp->Arguments.Add(ParseExpression(level));
- left = tmp;
- }
- return left;
- }
- }
-#endif
- }
-
- // We *might* be looking at an application of a generic to arguments,
- // but we need to disambiguate to make sure.
- static RefPtr<Expr> maybeParseGenericApp(
- Parser* parser,
-
- // TODO: need to support more general expressions here
- RefPtr<Expr> base)
- {
- if(peekTokenType(parser) != TokenType::OpLess)
- return base;
- return tryParseGenericApp(parser, base);
- }
-
- static RefPtr<Expr> parsePrefixExpr(Parser* parser);
-
- // Parse OOP `this` expression syntax
- static RefPtr<RefObject> parseThisExpr(Parser* parser, void* /*userData*/)
- {
- RefPtr<ThisExpr> expr = new ThisExpr();
- expr->scope = parser->currentScope;
- return expr;
- }
-
- static RefPtr<Expr> parseBoolLitExpr(Parser* /*parser*/, bool value)
- {
- RefPtr<BoolLiteralExpr> expr = new BoolLiteralExpr();
- expr->value = value;
- return expr;
- }
-
- static RefPtr<RefObject> parseTrueExpr(Parser* parser, void* /*userData*/)
- {
- return parseBoolLitExpr(parser, true);
- }
-
- static RefPtr<RefObject> parseFalseExpr(Parser* parser, void* /*userData*/)
- {
- return parseBoolLitExpr(parser, false);
- }
-
- static RefPtr<Expr> parseAtomicExpr(Parser* parser)
- {
- switch( peekTokenType(parser) )
- {
- default:
- // TODO: should this return an error expression instead of NULL?
- parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::syntaxError);
- return nullptr;
-
- // Either:
- // - parenthized expression `(exp)`
- // - cast `(type) exp`
- //
- // Proper disambiguation requires mixing up parsing
- // and semantic checking (which we should do eventually)
- // but for now we will follow some heuristics.
- case TokenType::LParent:
- {
- Token openParen = parser->ReadToken(TokenType::LParent);
-
- if (peekTypeName(parser) && parser->LookAheadToken(TokenType::RParent, 1))
- {
- RefPtr<TypeCastExpr> tcexpr = new ExplicitCastExpr();
- parser->FillPosition(tcexpr.Ptr());
- tcexpr->FunctionExpr = parser->ParseType();
- parser->ReadToken(TokenType::RParent);
-
- auto arg = parsePrefixExpr(parser);
- tcexpr->Arguments.add(arg);
-
- return tcexpr;
- }
- else
- {
- RefPtr<Expr> base = parser->ParseExpression();
- parser->ReadToken(TokenType::RParent);
-
- RefPtr<ParenExpr> parenExpr = new ParenExpr();
- parenExpr->loc = openParen.loc;
- parenExpr->base = base;
- return parenExpr;
- }
- }
-
- // An initializer list `{ expr, ... }`
- case TokenType::LBrace:
- {
- RefPtr<InitializerListExpr> initExpr = new InitializerListExpr();
- parser->FillPosition(initExpr.Ptr());
-
- // Initializer list
- parser->ReadToken(TokenType::LBrace);
-
- List<RefPtr<Expr>> exprs;
-
- for(;;)
- {
- if(AdvanceIfMatch(parser, TokenType::RBrace))
- break;
-
- auto expr = parser->ParseArgExpr();
- if( expr )
- {
- initExpr->args.add(expr);
- }
-
- if(AdvanceIfMatch(parser, TokenType::RBrace))
- break;
-
- parser->ReadToken(TokenType::Comma);
- }
-
- return initExpr;
- }
-
- case TokenType::IntegerLiteral:
- {
- RefPtr<IntegerLiteralExpr> constExpr = new IntegerLiteralExpr();
- parser->FillPosition(constExpr.Ptr());
-
- auto token = parser->tokenReader.AdvanceToken();
- constExpr->token = token;
-
- UnownedStringSlice suffix;
- IntegerLiteralValue value = getIntegerLiteralValue(token, &suffix);
-
- // Look at any suffix on the value
- char const* suffixCursor = suffix.begin();
- const char*const suffixEnd = suffix.end();
-
- RefPtr<Type> suffixType = nullptr;
- if( suffixCursor < suffixEnd )
- {
- int lCount = 0;
- int uCount = 0;
- int unknownCount = 0;
- while(suffixCursor < suffixEnd)
- {
- switch( *suffixCursor++ )
- {
- case 'l': case 'L':
- lCount++;
- break;
-
- case 'u': case 'U':
- uCount++;
- break;
-
- default:
- unknownCount++;
- break;
- }
- }
-
- if(unknownCount)
- {
- parser->sink->diagnose(token, Diagnostics::invalidIntegerLiteralSuffix, suffix);
- suffixType = parser->getSession()->getErrorType();
- }
- // `u` or `ul` suffix -> `uint`
- else if(uCount == 1 && (lCount <= 1))
- {
- suffixType = parser->getSession()->getUIntType();
- }
- // `l` suffix on integer -> `int` (== `long`)
- else if(lCount == 1 && !uCount)
- {
- suffixType = parser->getSession()->getIntType();
- }
- // `ull` suffix -> `uint64_t`
- else if(uCount == 1 && lCount == 2)
- {
- suffixType = parser->getSession()->getUInt64Type();
- }
- // `ll` suffix -> `int64_t`
- else if(uCount == 0 && lCount == 2)
- {
- suffixType = parser->getSession()->getInt64Type();
- }
- // TODO: do we need suffixes for smaller integer types?
- else
- {
- parser->sink->diagnose(token, Diagnostics::invalidIntegerLiteralSuffix, suffix);
- suffixType = parser->getSession()->getErrorType();
- }
- }
-
- constExpr->value = value;
- constExpr->type = QualType(suffixType);
-
- return constExpr;
- }
-
-
- case TokenType::FloatingPointLiteral:
- {
- RefPtr<FloatingPointLiteralExpr> constExpr = new FloatingPointLiteralExpr();
- parser->FillPosition(constExpr.Ptr());
-
- auto token = parser->tokenReader.AdvanceToken();
- constExpr->token = token;
-
- UnownedStringSlice suffix;
- FloatingPointLiteralValue value = getFloatingPointLiteralValue(token, &suffix);
-
- // Look at any suffix on the value
- char const* suffixCursor = suffix.begin();
- const char*const suffixEnd = suffix.end();
-
- RefPtr<Type> suffixType = nullptr;
- if( suffixCursor < suffixEnd )
- {
- int fCount = 0;
- int lCount = 0;
- int hCount = 0;
- int unknownCount = 0;
- while(suffixCursor < suffixEnd)
- {
- switch( *suffixCursor++ )
- {
- case 'f': case 'F':
- fCount++;
- break;
-
- case 'l': case 'L':
- lCount++;
- break;
-
- case 'h': case 'H':
- hCount++;
- break;
-
- default:
- unknownCount++;
- break;
- }
- }
-
- if (unknownCount)
- {
- parser->sink->diagnose(token, Diagnostics::invalidFloatingPointLiteralSuffix, suffix);
- suffixType = parser->getSession()->getErrorType();
- }
- // `f` suffix -> `float`
- if(fCount == 1 && !lCount)
- {
- suffixType = parser->getSession()->getFloatType();
- }
- // `l` or `lf` suffix on floating-point literal -> `double`
- else if(lCount == 1 && (fCount <= 1))
- {
- suffixType = parser->getSession()->getDoubleType();
- }
- // `h` or `hf` suffix on floating-point literal -> `half`
- else if(lCount == 1 && (fCount <= 1))
- {
- suffixType = parser->getSession()->getHalfType();
- }
- // TODO: are there other suffixes we need to handle?
- else
- {
- parser->sink->diagnose(token, Diagnostics::invalidFloatingPointLiteralSuffix, suffix);
- suffixType = parser->getSession()->getErrorType();
- }
- }
-
- constExpr->value = value;
- constExpr->type = QualType(suffixType);
-
- return constExpr;
- }
-
- case TokenType::StringLiteral:
- {
- RefPtr<StringLiteralExpr> constExpr = new StringLiteralExpr();
- auto token = parser->tokenReader.AdvanceToken();
- constExpr->token = token;
- parser->FillPosition(constExpr.Ptr());
-
- if (!parser->LookAheadToken(TokenType::StringLiteral))
- {
- // Easy/common case: a single string
- constExpr->value = getStringLiteralTokenValue(token);
- }
- else
- {
- StringBuilder sb;
- sb << getStringLiteralTokenValue(token);
- while (parser->LookAheadToken(TokenType::StringLiteral))
- {
- token = parser->tokenReader.AdvanceToken();
- sb << getStringLiteralTokenValue(token);
- }
- constExpr->value = sb.ProduceString();
- }
-
- return constExpr;
- }
-
- case TokenType::Identifier:
- {
- // We will perform name lookup here so that we can find syntax
- // keywords registered for use as expressions.
- Token nameToken = peekToken(parser);
-
- RefPtr<Expr> parsedExpr;
- if (tryParseUsingSyntaxDecl<Expr>(parser, &parsedExpr))
- {
- if (!parsedExpr->loc.isValid())
- {
- parsedExpr->loc = nameToken.loc;
- }
- return parsedExpr;
- }
-
- // Default behavior is just to create a name expression
- RefPtr<VarExpr> varExpr = new VarExpr();
- varExpr->scope = parser->currentScope.Ptr();
- parser->FillPosition(varExpr.Ptr());
-
- auto nameAndLoc = expectIdentifier(parser);
- varExpr->name = nameAndLoc.name;
-
- if(peekTokenType(parser) == TokenType::OpLess)
- {
- return maybeParseGenericApp(parser, varExpr);
- }
-
- return varExpr;
- }
- }
- }
-
- static RefPtr<Expr> parsePostfixExpr(Parser* parser)
- {
- auto expr = parseAtomicExpr(parser);
- for(;;)
- {
- switch( peekTokenType(parser) )
- {
- default:
- return expr;
-
- // Postfix increment/decrement
- case TokenType::OpInc:
- case TokenType::OpDec:
- {
- RefPtr<OperatorExpr> postfixExpr = new PostfixExpr();
- parser->FillPosition(postfixExpr.Ptr());
- postfixExpr->FunctionExpr = parseOperator(parser);
- postfixExpr->Arguments.add(expr);
-
- expr = postfixExpr;
- }
- break;
-
- // Subscript operation `a[i]`
- case TokenType::LBracket:
- {
- RefPtr<IndexExpr> indexExpr = new IndexExpr();
- indexExpr->BaseExpression = expr;
- parser->FillPosition(indexExpr.Ptr());
- parser->ReadToken(TokenType::LBracket);
- // TODO: eventually we may want to support multiple arguments inside the `[]`
- if (!parser->LookAheadToken(TokenType::RBracket))
- {
- indexExpr->IndexExpression = parser->ParseExpression();
- }
- parser->ReadToken(TokenType::RBracket);
-
- expr = indexExpr;
- }
- break;
-
- // Call oepration `f(x)`
- case TokenType::LParent:
- {
- RefPtr<InvokeExpr> invokeExpr = new InvokeExpr();
- invokeExpr->FunctionExpr = expr;
- parser->FillPosition(invokeExpr.Ptr());
- parser->ReadToken(TokenType::LParent);
- while (!parser->tokenReader.IsAtEnd())
- {
- if (!parser->LookAheadToken(TokenType::RParent))
- invokeExpr->Arguments.add(parser->ParseArgExpr());
- else
- {
- break;
- }
- if (!parser->LookAheadToken(TokenType::Comma))
- break;
- parser->ReadToken(TokenType::Comma);
- }
- parser->ReadToken(TokenType::RParent);
-
- expr = invokeExpr;
- }
- break;
-
- // Scope access `x::m`
- case TokenType::Scope:
- {
- RefPtr<StaticMemberExpr> staticMemberExpr = new StaticMemberExpr();
-
- // TODO(tfoley): why would a member expression need this?
- staticMemberExpr->scope = parser->currentScope.Ptr();
-
- parser->FillPosition(staticMemberExpr.Ptr());
- staticMemberExpr->BaseExpression = expr;
- parser->ReadToken(TokenType::Scope);
- staticMemberExpr->name = expectIdentifier(parser).name;
-
- if (peekTokenType(parser) == TokenType::OpLess)
- expr = maybeParseGenericApp(parser, staticMemberExpr);
- else
- expr = staticMemberExpr;
-
- break;
- }
- // Member access `x.m`
- case TokenType::Dot:
- {
- RefPtr<MemberExpr> memberExpr = new MemberExpr();
-
- // TODO(tfoley): why would a member expression need this?
- memberExpr->scope = parser->currentScope.Ptr();
-
- parser->FillPosition(memberExpr.Ptr());
- memberExpr->BaseExpression = expr;
- parser->ReadToken(TokenType::Dot);
- memberExpr->name = expectIdentifier(parser).name;
-
- if (peekTokenType(parser) == TokenType::OpLess)
- expr = maybeParseGenericApp(parser, memberExpr);
- else
- expr = memberExpr;
- }
- break;
- }
- }
- }
-
- static RefPtr<Expr> parsePrefixExpr(Parser* parser)
- {
- switch( peekTokenType(parser) )
- {
- default:
- return parsePostfixExpr(parser);
-
- case TokenType::OpInc:
- case TokenType::OpDec:
- case TokenType::OpNot:
- case TokenType::OpBitNot:
- case TokenType::OpAdd:
- case TokenType::OpSub:
- {
- RefPtr<PrefixExpr> prefixExpr = new PrefixExpr();
- parser->FillPosition(prefixExpr.Ptr());
- prefixExpr->FunctionExpr = parseOperator(parser);
- prefixExpr->Arguments.add(parsePrefixExpr(parser));
- return prefixExpr;
- }
- break;
- }
- }
-
- RefPtr<Expr> Parser::ParseLeafExpression()
- {
- return parsePrefixExpr(this);
- }
-
- RefPtr<Expr> parseTypeFromSourceFile(
- Session* session,
- TokenSpan const& tokens,
- DiagnosticSink* sink,
- RefPtr<Scope> const& outerScope,
- NamePool* namePool,
- SourceLanguage sourceLanguage)
- {
- Parser parser(session, tokens, sink, outerScope);
- parser.currentScope = outerScope;
- parser.namePool = namePool;
- parser.sourceLanguage = sourceLanguage;
- return parser.ParseType();
- }
-
- // Parse a source file into an existing translation unit
- void parseSourceFile(
- TranslationUnitRequest* translationUnit,
- TokenSpan const& tokens,
- DiagnosticSink* sink,
- RefPtr<Scope> const& outerScope)
- {
- Parser parser(translationUnit->getSession(), tokens, sink, outerScope);
- parser.namePool = translationUnit->getNamePool();
- parser.sourceLanguage = translationUnit->sourceLanguage;
-
- return parser.parseSourceFile(translationUnit->getModuleDecl());
- }
-
- static void addBuiltinSyntaxImpl(
- Session* session,
- Scope* scope,
- char const* nameText,
- SyntaxParseCallback callback,
- void* userData,
- SyntaxClass<RefObject> syntaxClass)
- {
- Name* name = session->getNamePool()->getName(nameText);
-
- RefPtr<SyntaxDecl> syntaxDecl = new SyntaxDecl();
- syntaxDecl->nameAndLoc = NameLoc(name);
- syntaxDecl->syntaxClass = syntaxClass;
- syntaxDecl->parseCallback = callback;
- syntaxDecl->parseUserData = userData;
-
- AddMember(scope, syntaxDecl);
- }
-
- template<typename T>
- static void addBuiltinSyntax(
- Session* session,
- Scope* scope,
- char const* name,
- SyntaxParseCallback callback,
- void* userData = nullptr)
- {
- addBuiltinSyntaxImpl(session, scope, name, callback, userData, getClass<T>());
- }
-
- template<typename T>
- static void addSimpleModifierSyntax(
- Session* session,
- Scope* scope,
- char const* name)
- {
- auto syntaxClass = getClass<T>();
- addBuiltinSyntaxImpl(session, scope, name, &parseSimpleSyntax, (void*) syntaxClass.classInfo, getClass<T>());
- }
-
- static RefPtr<RefObject> parseIntrinsicOpModifier(Parser* parser, void* /*userData*/)
- {
- RefPtr<IntrinsicOpModifier> modifier = new IntrinsicOpModifier();
-
- // We allow a few difference forms here:
- //
- // First, we can specify the intrinsic op `enum` value directly:
- //
- // __intrinsic_op(<integer literal>)
- //
- // Second, we can specify the operation by name:
- //
- // __intrinsic_op(<identifier>)
- //
- // Finally, we can leave off the specification, so that the
- // op name will be derived from the function name:
- //
- // __intrinsic_op
- //
- if (AdvanceIf(parser, TokenType::LParent))
- {
- if (AdvanceIf(parser, TokenType::OpSub))
- {
- modifier->op = IROp(-StringToInt(parser->ReadToken().Content));
- }
- else if (parser->LookAheadToken(TokenType::IntegerLiteral))
- {
- modifier->op = IROp(StringToInt(parser->ReadToken().Content));
- }
- else
- {
- modifier->opToken = parser->ReadToken(TokenType::Identifier);
-
- modifier->op = findIROp(modifier->opToken.Content);
-
- if (modifier->op == kIROp_Invalid)
- {
- parser->sink->diagnose(modifier->opToken, Diagnostics::unimplemented, "unknown intrinsic op");
- }
- }
-
- parser->ReadToken(TokenType::RParent);
- }
-
-
- return modifier;
- }
-
- static RefPtr<RefObject> parseTargetIntrinsicModifier(Parser* parser, void* /*userData*/)
- {
- auto modifier = new TargetIntrinsicModifier();
-
- if (AdvanceIf(parser, TokenType::LParent))
- {
- modifier->targetToken = parser->ReadToken(TokenType::Identifier);
-
- if( AdvanceIf(parser, TokenType::Comma) )
- {
- if( parser->LookAheadToken(TokenType::StringLiteral) )
- {
- modifier->definitionToken = parser->ReadToken();
- }
- else
- {
- modifier->definitionToken = parser->ReadToken(TokenType::Identifier);
- }
- }
-
- parser->ReadToken(TokenType::RParent);
- }
-
- return modifier;
- }
-
- static RefPtr<RefObject> parseSpecializedForTargetModifier(Parser* parser, void* /*userData*/)
- {
- auto modifier = new SpecializedForTargetModifier();
- if (AdvanceIf(parser, TokenType::LParent))
- {
- modifier->targetToken = parser->ReadToken(TokenType::Identifier);
- parser->ReadToken(TokenType::RParent);
- }
- return modifier;
- }
-
- static RefPtr<RefObject> parseGLSLExtensionModifier(Parser* parser, void* /*userData*/)
- {
- auto modifier = new RequiredGLSLExtensionModifier();
-
- parser->ReadToken(TokenType::LParent);
- modifier->extensionNameToken = parser->ReadToken(TokenType::Identifier);
- parser->ReadToken(TokenType::RParent);
-
- return modifier;
- }
-
- static RefPtr<RefObject> parseGLSLVersionModifier(Parser* parser, void* /*userData*/)
- {
- auto modifier = new RequiredGLSLVersionModifier();
-
- parser->ReadToken(TokenType::LParent);
- modifier->versionNumberToken = parser->ReadToken(TokenType::IntegerLiteral);
- parser->ReadToken(TokenType::RParent);
-
- return modifier;
- }
-
- static RefPtr<RefObject> parseLayoutModifier(Parser* parser, void* /*userData*/)
- {
- ModifierListBuilder listBuilder;
-
- listBuilder.add(new GLSLLayoutModifierGroupBegin());
-
- parser->ReadToken(TokenType::LParent);
- while (!AdvanceIfMatch(parser, TokenType::RParent))
- {
- auto nameAndLoc = expectIdentifier(parser);
- const String& nameText = nameAndLoc.name->text;
-
- if (nameText == "binding" ||
- nameText == "set")
- {
- GLSLBindingAttribute* attr = listBuilder.find<GLSLBindingAttribute>();
- if (!attr)
- {
- attr = new GLSLBindingAttribute();
- listBuilder.add(attr);
- }
-
- parser->ReadToken(TokenType::OpAssign);
-
- // If the token asked for is not returned found will put in recovering state, and return token found
- Token valToken = parser->ReadToken(TokenType::IntegerLiteral);
- // If wasn't the desired IntegerLiteral return that couldn't parse
- if (valToken.type != TokenType::IntegerLiteral)
- {
- return nullptr;
- }
-
- // Work out the value
- auto value = getIntegerLiteralValue(valToken);
-
- if (nameText == "binding")
- {
- attr->binding = int32_t(value);
- }
- else
- {
- attr->set = int32_t(value);
- }
- }
- else
- {
- RefPtr<Modifier> modifier;
-
-#define CASE(key, type) if (nameText == #key) { modifier = new type; } else
- CASE(push_constant, PushConstantAttribute)
- CASE(shaderRecordNV, ShaderRecordAttribute)
- CASE(constant_id, GLSLConstantIDLayoutModifier)
- CASE(location, GLSLLocationLayoutModifier)
- CASE(local_size_x, GLSLLocalSizeXLayoutModifier)
- CASE(local_size_y, GLSLLocalSizeYLayoutModifier)
- CASE(local_size_z, GLSLLocalSizeZLayoutModifier)
- {
- modifier = new GLSLUnparsedLayoutModifier();
- }
- SLANG_ASSERT(modifier);
-#undef CASE
-
- modifier->name = nameAndLoc.name;
- modifier->loc = nameAndLoc.loc;
-
- // Special handling for GLSLLayoutModifier
- if (auto glslModifier = as<GLSLLayoutModifier>(modifier))
- {
- if (AdvanceIf(parser, TokenType::OpAssign))
- {
- glslModifier->valToken = parser->ReadToken(TokenType::IntegerLiteral);
- }
- }
-
- listBuilder.add(modifier);
- }
-
- if (AdvanceIf(parser, TokenType::RParent))
- break;
- parser->ReadToken(TokenType::Comma);
- }
-
- listBuilder.add(new GLSLLayoutModifierGroupEnd());
-
- return listBuilder.getFirst();
- }
-
- static RefPtr<RefObject> parseBuiltinTypeModifier(Parser* parser, void* /*userData*/)
- {
- RefPtr<BuiltinTypeModifier> modifier = new BuiltinTypeModifier();
- parser->ReadToken(TokenType::LParent);
- modifier->tag = BaseType(StringToInt(parser->ReadToken(TokenType::IntegerLiteral).Content));
- parser->ReadToken(TokenType::RParent);
-
- return modifier;
- }
-
- static RefPtr<RefObject> parseMagicTypeModifier(Parser* parser, void* /*userData*/)
- {
- RefPtr<MagicTypeModifier> modifier = new MagicTypeModifier();
- parser->ReadToken(TokenType::LParent);
- modifier->name = parser->ReadToken(TokenType::Identifier).Content;
- if (AdvanceIf(parser, TokenType::Comma))
- {
- modifier->tag = uint32_t(StringToInt(parser->ReadToken(TokenType::IntegerLiteral).Content));
- }
- parser->ReadToken(TokenType::RParent);
-
- return modifier;
- }
-
- static RefPtr<RefObject> parseIntrinsicTypeModifier(Parser* parser, void* /*userData*/)
- {
- RefPtr<IntrinsicTypeModifier> modifier = new IntrinsicTypeModifier();
- parser->ReadToken(TokenType::LParent);
- modifier->irOp = uint32_t(StringToInt(parser->ReadToken(TokenType::IntegerLiteral).Content));
- while( AdvanceIf(parser, TokenType::Comma) )
- {
- auto operand = uint32_t(StringToInt(parser->ReadToken(TokenType::IntegerLiteral).Content));
- modifier->irOperands.add(operand);
- }
- parser->ReadToken(TokenType::RParent);
-
- return modifier;
- }
- static RefPtr<RefObject> parseImplicitConversionModifier(Parser* parser, void* /*userData*/)
- {
- RefPtr<ImplicitConversionModifier> modifier = new ImplicitConversionModifier();
-
- ConversionCost cost = kConversionCost_Default;
- if( AdvanceIf(parser, TokenType::LParent) )
- {
- cost = ConversionCost(StringToInt(parser->ReadToken(TokenType::IntegerLiteral).Content));
- parser->ReadToken(TokenType::RParent);
- }
- modifier->cost = cost;
- return modifier;
- }
-
- static RefPtr<RefObject> parseAttributeTargetModifier(Parser* parser, void* /*userData*/)
- {
- expect(parser, TokenType::LParent);
- auto syntaxClassNameAndLoc = expectIdentifier(parser);
- expect(parser, TokenType::RParent);
-
- auto syntaxClass = parser->getSession()->findSyntaxClass(syntaxClassNameAndLoc.name);
-
- RefPtr<AttributeTargetModifier> modifier = new AttributeTargetModifier();
- modifier->syntaxClass = syntaxClass;
-
- return modifier;
- }
-
- RefPtr<ModuleDecl> populateBaseLanguageModule(
- Session* session,
- RefPtr<Scope> scope)
- {
- RefPtr<ModuleDecl> moduleDecl = new ModuleDecl();
- scope->containerDecl = moduleDecl;
-
- // Add syntax for declaration keywords
- #define DECL(KEYWORD, CALLBACK) \
- addBuiltinSyntax<Decl>(session, scope, #KEYWORD, &CALLBACK)
- DECL(typedef, ParseTypeDef);
- DECL(associatedtype, parseAssocType);
- DECL(type_param, parseGlobalGenericParamDecl);
- DECL(cbuffer, parseHLSLCBufferDecl);
- DECL(tbuffer, parseHLSLTBufferDecl);
- DECL(__generic, ParseGenericDecl);
- DECL(__extension, ParseExtensionDecl);
- DECL(extension, ParseExtensionDecl);
- DECL(__init, parseConstructorDecl);
- DECL(__subscript, ParseSubscriptDecl);
- DECL(interface, parseInterfaceDecl);
- DECL(syntax, parseSyntaxDecl);
- DECL(attribute_syntax,parseAttributeSyntaxDecl);
- DECL(__import, parseImportDecl);
- DECL(import, parseImportDecl);
- DECL(let, parseLetDecl);
- DECL(var, parseVarDecl);
- DECL(func, parseFuncDecl);
- DECL(typealias, parseTypeAliasDecl);
-
- #undef DECL
-
- // Add syntax for "simple" modifier keywords.
- // These are the ones that just appear as a single
- // keyword (no further tokens expected/allowed),
- // and which can be represented just by creating
- // a new AST node of the corresponding type.
- #define MODIFIER(KEYWORD, CLASS) \
- addSimpleModifierSyntax<CLASS>(session, scope, #KEYWORD)
-
- MODIFIER(in, InModifier);
- MODIFIER(input, InputModifier);
- MODIFIER(out, OutModifier);
- MODIFIER(inout, InOutModifier);
- MODIFIER(__ref, RefModifier);
- MODIFIER(const, ConstModifier);
- MODIFIER(instance, InstanceModifier);
- MODIFIER(__builtin, BuiltinModifier);
-
- MODIFIER(inline, InlineModifier);
- MODIFIER(public, PublicModifier);
- MODIFIER(require, RequireModifier);
- MODIFIER(param, ParamModifier);
- MODIFIER(extern, ExternModifier);
-
- MODIFIER(row_major, HLSLRowMajorLayoutModifier);
- MODIFIER(column_major, HLSLColumnMajorLayoutModifier);
-
- MODIFIER(nointerpolation, HLSLNoInterpolationModifier);
- MODIFIER(noperspective, HLSLNoPerspectiveModifier);
- MODIFIER(linear, HLSLLinearModifier);
- MODIFIER(sample, HLSLSampleModifier);
- MODIFIER(centroid, HLSLCentroidModifier);
- MODIFIER(precise, PreciseModifier);
- MODIFIER(shared, HLSLEffectSharedModifier);
- MODIFIER(groupshared, HLSLGroupSharedModifier);
- MODIFIER(static, HLSLStaticModifier);
- MODIFIER(uniform, HLSLUniformModifier);
- MODIFIER(volatile, HLSLVolatileModifier);
-
- // Modifiers for geometry shader input
- MODIFIER(point, HLSLPointModifier);
- MODIFIER(line, HLSLLineModifier);
- MODIFIER(triangle, HLSLTriangleModifier);
- MODIFIER(lineadj, HLSLLineAdjModifier);
- MODIFIER(triangleadj, HLSLTriangleAdjModifier);
-
- // Modifiers for unary operator declarations
- MODIFIER(__prefix, PrefixModifier);
- MODIFIER(__postfix, PostfixModifier);
-
- // Modifier to apply to `import` that should be re-exported
- MODIFIER(__exported, ExportedModifier);
-
- #undef MODIFIER
-
- // Add syntax for more complex modifiers, which allow
- // or expect more tokens after the initial keyword.
- #define MODIFIER(KEYWORD, CALLBACK) \
- addBuiltinSyntax<Modifier>(session, scope, #KEYWORD, &CALLBACK)
-
- MODIFIER(layout, parseLayoutModifier);
-
- MODIFIER(__intrinsic_op, parseIntrinsicOpModifier);
- MODIFIER(__target_intrinsic, parseTargetIntrinsicModifier);
- MODIFIER(__specialized_for_target, parseSpecializedForTargetModifier);
- MODIFIER(__glsl_extension, parseGLSLExtensionModifier);
- MODIFIER(__glsl_version, parseGLSLVersionModifier);
-
- MODIFIER(__builtin_type, parseBuiltinTypeModifier);
- MODIFIER(__magic_type, parseMagicTypeModifier);
- MODIFIER(__intrinsic_type, parseIntrinsicTypeModifier);
- MODIFIER(__implicit_conversion, parseImplicitConversionModifier);
-
- MODIFIER(__attributeTarget, parseAttributeTargetModifier);
-
-
-#undef MODIFIER
-
- // Add syntax for expression keywords
- #define EXPR(KEYWORD, CALLBACK) \
- addBuiltinSyntax<Expr>(session, scope, #KEYWORD, &CALLBACK)
-
- EXPR(this, parseThisExpr);
- EXPR(true, parseTrueExpr);
- EXPR(false, parseFalseExpr);
-
- #undef EXPR
-
- return moduleDecl;
- }
-
-}