From 517513645afb8eaf4841e7b7035f1ba3a9c7cd57 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Thu, 15 Jun 2017 13:12:51 -0700 Subject: Rename `Slang::Compiler` -> `Slang` This gets rid of one unecessary namespace. --- source/slang/parser.cpp | 5103 +++++++++++++++++++++++------------------------ 1 file changed, 2550 insertions(+), 2553 deletions(-) (limited to 'source/slang/parser.cpp') diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp index 9e76a68b9..df2986959 100644 --- a/source/slang/parser.cpp +++ b/source/slang/parser.cpp @@ -6,3149 +6,3146 @@ namespace Slang { - namespace Compiler - { - 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 + 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: + CompileOptions& options; + int anonymousCounter = 0; + + RefPtr outerScope; + RefPtr currentScope; + + TokenReader tokenReader; + DiagnosticSink * sink; + String fileName; + int genericDepth = 0; + + // 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->Position = tokenReader.PeekLoc(); + } + void PushScope(ContainerDecl* containerDecl) + { + RefPtr newScope = new Scope(); + newScope->containerDecl = containerDecl; + newScope->parent = currentScope; + + currentScope = newScope; + } + void PopScope() + { + currentScope = currentScope->parent; + } + Parser( + CompileOptions& options, + TokenSpan const& _tokens, + DiagnosticSink * sink, + String _fileName, + RefPtr const& outerScope) + : options(options) + , tokenReader(_tokens) + , sink(sink) + , fileName(_fileName) + , outerScope(outerScope) + {} + RefPtr Parse(); + + 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(ProgramSyntaxNode* program); + RefPtr ParseProgram(); + RefPtr ParseStruct(); + RefPtr ParseClass(); + RefPtr ParseStatement(); + RefPtr ParseBlockStatement(); + RefPtr ParseVarDeclrStatement(Modifiers modifiers); + RefPtr ParseIfStatement(); + RefPtr ParseForStatement(); + RefPtr ParseWhileStatement(); + RefPtr ParseDoWhileStatement(); + RefPtr ParseBreakStatement(); + RefPtr ParseContinueStatement(); + RefPtr ParseReturnStatement(); + RefPtr ParseExpressionStatement(); + RefPtr 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 ParseInitExpr() { return ParseExpression(Precedence::Assignment); } + inline RefPtr ParseArgExpr() { return ParseExpression(Precedence::Assignment); } + + RefPtr ParseLeafExpression(); + RefPtr ParseParameter(); + RefPtr ParseType(); + TypeExp ParseTypeExp(); + + Parser & operator = (const Parser &) = delete; + }; + + // Forward Declarations + + static void ParseDeclBody( + Parser* parser, + ContainerDecl* containerDecl, + TokenType closingToken); + + // Parse the `{}`-delimeted body of an aggregate type declaration + static void parseAggTypeDeclBody( + Parser* parser, + AggTypeDeclBase* decl); + + static RefPtr ParseOptSemantics( + Parser* parser); + + static void ParseOptSemantics( + Parser* parser, + Decl* decl); + + static RefPtr ParseDecl( + Parser* parser, + ContainerDecl* containerDecl); + + static RefPtr 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) { - public: - CompileOptions& options; - int anonymousCounter = 0; - - RefPtr outerScope; - RefPtr currentScope; - - TokenReader tokenReader; - DiagnosticSink * sink; - String fileName; - int genericDepth = 0; - - // 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->Position = tokenReader.PeekLoc(); - } - void PushScope(ContainerDecl* containerDecl) - { - RefPtr newScope = new Scope(); - newScope->containerDecl = containerDecl; - newScope->parent = currentScope; - - currentScope = newScope; - } - void PopScope() - { - currentScope = currentScope->parent; - } - Parser( - CompileOptions& options, - TokenSpan const& _tokens, - DiagnosticSink * sink, - String _fileName, - RefPtr const& outerScope) - : options(options) - , tokenReader(_tokens) - , sink(sink) - , fileName(_fileName) - , outerScope(outerScope) - {} - RefPtr Parse(); - - 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(ProgramSyntaxNode* program); - RefPtr ParseProgram(); - RefPtr ParseStruct(); - RefPtr ParseClass(); - RefPtr ParseStatement(); - RefPtr ParseBlockStatement(); - RefPtr ParseVarDeclrStatement(Modifiers modifiers); - RefPtr ParseIfStatement(); - RefPtr ParseForStatement(); - RefPtr ParseWhileStatement(); - RefPtr ParseDoWhileStatement(); - RefPtr ParseBreakStatement(); - RefPtr ParseContinueStatement(); - RefPtr ParseReturnStatement(); - RefPtr ParseExpressionStatement(); - RefPtr 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 ParseInitExpr() { return ParseExpression(Precedence::Assignment); } - inline RefPtr ParseArgExpr() { return ParseExpression(Precedence::Assignment); } - - RefPtr ParseLeafExpression(); - RefPtr ParseParameter(); - RefPtr ParseType(); - TypeExp ParseTypeExp(); - - Parser & operator = (const Parser &) = delete; - }; - - // Forward Declarations - - static void ParseDeclBody( - Parser* parser, - ContainerDecl* containerDecl, - TokenType closingToken); + parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedToken, + parser->tokenReader.PeekTokenType()); - // Parse the `{}`-delimeted body of an aggregate type declaration - static void parseAggTypeDeclBody( - Parser* parser, - AggTypeDeclBase* decl); + // Switch into recovery mode, to suppress additional errors + parser->isRecovering = true; + } + } - static RefPtr ParseOptSemantics( - Parser* parser); + 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); - static void ParseOptSemantics( - Parser* parser, - Decl* decl); + // Switch into recovery mode, to suppress additional errors + parser->isRecovering = true; + } + } - static RefPtr ParseDecl( - Parser* parser, - ContainerDecl* containerDecl); + 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); - static RefPtr ParseSingleDecl( - Parser* parser, - ContainerDecl* containerDecl); + // Switch into recovery mode, to suppress additional errors + parser->isRecovering = true; + } + } - // + static TokenType SkipToMatchingToken(TokenReader* reader, TokenType tokenType); - static void Unexpected( - Parser* parser) + // 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) { - // 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()); + default: + break; - // Switch into recovery mode, to suppress additional errors - parser->isRecovering = true; - } + 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; + } - static void Unexpected( - Parser* parser, - char const* expected) + // Skip balanced + static TokenType SkipToMatchingToken( + TokenReader* reader, + TokenType tokenType) + { + for (;;) { - // Don't emit "unexpected token" errors if we are in recovering mode - if (!parser->isRecovering) + if (reader->IsAtEnd()) return TokenType::EndOfFile; + if (reader->PeekTokenType() == tokenType) { - parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedTokenExpectedTokenName, - parser->tokenReader.PeekTokenType(), - expected); - - // Switch into recovery mode, to suppress additional errors - parser->isRecovering = true; + reader->AdvanceToken(); + return tokenType; } + SkipBalancedToken(reader); } + } - static void Unexpected( - Parser* parser, - TokenType expected) + // Is the given token type one that is used to "close" a + // balanced construct. + static bool IsClosingToken(TokenType tokenType) + { + switch (tokenType) { - // 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); + case TokenType::EndOfFile: + case TokenType::RBracket: + case TokenType::RParent: + case TokenType::RBrace: + return true; - // Switch into recovery mode, to suppress additional errors - parser->isRecovering = true; - } + default: + return false; } + } - 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) + // 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) { - 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; + isRecovering = false; + return tokenReader.AdvanceToken(); } - // Skip balanced - static TokenType SkipToMatchingToken( - TokenReader* reader, - TokenType tokenType) + if (!isRecovering) + { + Unexpected(this, expected); + return tokenReader.PeekToken(); + } + else { + // Try to find a place to recover for (;;) { - if (reader->IsAtEnd()) return TokenType::EndOfFile; - if (reader->PeekTokenType() == tokenType) + // The token we expected? + // Then exit recovery mode and pretend like all is well. + if (tokenReader.PeekTokenType() == TokenType::Identifier + && tokenReader.PeekToken().Content == expected) { - reader->AdvanceToken(); - return tokenType; + isRecovering = false; + return tokenReader.AdvanceToken(); } - 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; - } - } + // Don't skip past any "closing" tokens. + if (IsClosingToken(tokenReader.PeekTokenType())) + { + return tokenReader.PeekToken(); + } - // 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(); + // Skip balanced tokens and try again. + SkipBalancedToken(&tokenReader); } - 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(); - } + } + } + Token Parser::ReadToken() + { + return tokenReader.AdvanceToken(); + } - // Don't skip past any "closing" tokens. - if (IsClosingToken(tokenReader.PeekTokenType())) - { - return tokenReader.PeekToken(); - } + static bool TryRecover( + Parser* parser, + TokenType const* recoverBefore, + int recoverBeforeCount, + TokenType const* recoverAfter, + int recoverAfterCount) + { + if (!parser->isRecovering) + return true; - // Skip balanced tokens and try again. - SkipBalancedToken(&tokenReader); - } - } + // Determine if we are looking for a closing token at all... + bool lookingForClose = false; + for (int ii = 0; ii < recoverBeforeCount; ++ii) + { + if (IsClosingToken(recoverBefore[ii])) + lookingForClose = true; } - - Token Parser::ReadToken() + for (int ii = 0; ii < recoverAfterCount; ++ii) { - return tokenReader.AdvanceToken(); + if (IsClosingToken(recoverAfter[ii])) + lookingForClose = true; } - static bool TryRecover( - Parser* parser, - TokenType const* recoverBefore, - int recoverBeforeCount, - TokenType const* recoverAfter, - int recoverAfterCount) + TokenReader* tokenReader = &parser->tokenReader; + for (;;) { - if (!parser->isRecovering) - return true; + TokenType peek = tokenReader->PeekTokenType(); - // Determine if we are looking for a closing token at all... - bool lookingForClose = false; + // Is the next token in our recover-before set? + // If so, then we have recovered successfully! for (int ii = 0; ii < recoverBeforeCount; ++ii) { - if (IsClosingToken(recoverBefore[ii])) - lookingForClose = true; - } - for (int ii = 0; ii < recoverAfterCount; ++ii) - { - if (IsClosingToken(recoverAfter[ii])) - lookingForClose = true; + if (peek == recoverBefore[ii]) + { + parser->isRecovering = false; + return true; + } } - TokenReader* tokenReader = &parser->tokenReader; - for (;;) + // If we are looking at a token in our recover-after set, + // then consume it and recover + for (int ii = 0; ii < recoverAfterCount; ++ii) { - 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 == recoverAfter[ii]) { - if (peek == recoverBefore[ii]) - { - parser->isRecovering = false; - return true; - } + tokenReader->AdvanceToken(); + 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; - // Don't try to skip past end of file - if (peek == TokenType::EndOfFile) + switch (peek) + { + // Don't skip past simple "closing" tokens, *unless* + // we are looking for a closing token + case TokenType::RParent: + case TokenType::RBracket: + if (!lookingForClose) return false; + break; - switch (peek) - { - // Don't skip past simple "closing" tokens, *unless* - // we are looking for a closing token - case TokenType::RParent: - case TokenType::RBracket: - if (!lookingForClose) - return false; - break; - - // never skip a `}`, to avoid spurious errors - case TokenType::RBrace: - return false; - } + // never skip a `}`, to avoid spurious errors + case TokenType::RBrace: + return false; + } - // Skip balanced tokens and try again. - TokenType skipped = SkipBalancedToken(tokenReader); + // 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 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]) { - if (skipped == recoverAfter[ii]) - { - parser->isRecovering = false; - return true; - } + 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); + } - static bool TryRecoverBefore( - Parser* parser, - TokenType before0) + Token Parser::ReadToken(TokenType expected) + { + if (tokenReader.PeekTokenType() == expected) { - TokenType recoverBefore[] = { before0 }; - return TryRecover(parser, recoverBefore, 1, nullptr, 0); + isRecovering = false; + return tokenReader.AdvanceToken(); } - // Default recovery strategy, to use inside `{}`-delimeted blocks. - static bool TryRecover( - Parser* parser) + if (!isRecovering) { - TokenType recoverBefore[] = { TokenType::RBrace }; - TokenType recoverAfter[] = { TokenType::Semicolon }; - return TryRecover(parser, recoverBefore, 1, recoverAfter, 1); + Unexpected(this, expected); + return tokenReader.PeekToken(); } - - Token Parser::ReadToken(TokenType expected) + else { - if (tokenReader.PeekTokenType() == expected) + // Try to find a place to recover + if (TryRecoverBefore(this, 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(); - } + return tokenReader.PeekToken(); } + } - bool Parser::LookAheadToken(const char * string, int offset) - { - TokenReader r = tokenReader; - for (int ii = 0; ii < offset; ++ii) - r.AdvanceToken(); + 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; - } + 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(); + bool Parser::LookAheadToken(TokenType type, int offset) + { + TokenReader r = tokenReader; + for (int ii = 0; ii < offset; ++ii) + r.AdvanceToken(); - return r.PeekTokenType() == type; - } + return r.PeekTokenType() == type; + } - // Consume a token and return true it if matches, otherwise false - bool AdvanceIf(Parser* parser, TokenType tokenType) + // Consume a token and return true it if matches, otherwise false + bool AdvanceIf(Parser* parser, TokenType tokenType) + { + if (parser->LookAheadToken(tokenType)) { - if (parser->LookAheadToken(tokenType)) - { - parser->ReadToken(); - return true; - } - return false; + parser->ReadToken(); + return true; } + return false; + } - // Consume a token and return true it if matches, otherwise false - bool AdvanceIf(Parser* parser, char const* text) + // Consume a token and return true it if matches, otherwise false + bool AdvanceIf(Parser* parser, char const* text) + { + if (parser->LookAheadToken(text)) { - if (parser->LookAheadToken(text)) - { - parser->ReadToken(); - return true; - } - return false; + 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) + // 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) { - // 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; + TryRecoverBefore(parser, tokenType); } - - RefPtr Parser::Parse() + if (AdvanceIf(parser, tokenType)) + return true; + if (parser->tokenReader.PeekTokenType() == TokenType::EndOfFile) { - return ParseProgram(); + parser->ReadToken(tokenType); + return true; } + return false; + } - RefPtr ParseTypeDef(Parser* parser) - { - // Consume the `typedef` keyword - parser->ReadToken("typedef"); + RefPtr Parser::Parse() + { + return ParseProgram(); + } - // TODO(tfoley): parse an actual declarator - auto type = parser->ParseTypeExp(); + RefPtr ParseTypeDef(Parser* parser) + { + // Consume the `typedef` keyword + parser->ReadToken("typedef"); - auto nameToken = parser->ReadToken(TokenType::Identifier); + // TODO(tfoley): parse an actual declarator + auto type = parser->ParseTypeExp(); - RefPtr typeDefDecl = new TypeDefDecl(); - typeDefDecl->Name = nameToken; - typeDefDecl->Type = type; + auto nameToken = parser->ReadToken(TokenType::Identifier); - return typeDefDecl; - } + RefPtr typeDefDecl = new TypeDefDecl(); + typeDefDecl->Name = nameToken; + typeDefDecl->Type = type; - // Add a modifier to a list of modifiers being built - static void AddModifier(RefPtr** ioModifierLink, RefPtr modifier) - { - RefPtr*& modifierLink = *ioModifierLink; + return typeDefDecl; + } - while(*modifierLink) - modifierLink = &(*modifierLink)->next; + // Add a modifier to a list of modifiers being built + static void AddModifier(RefPtr** ioModifierLink, RefPtr modifier) + { + RefPtr*& modifierLink = *ioModifierLink; - *modifierLink = modifier; - modifierLink = &modifier->next; - } + while(*modifierLink) + modifierLink = &(*modifierLink)->next; - void addModifier( - RefPtr syntax, - RefPtr modifier) - { - auto modifierLink = &syntax->modifiers.first; - AddModifier(&modifierLink, modifier); - } + *modifierLink = modifier; + modifierLink = &modifier->next; + } + + void addModifier( + RefPtr syntax, + RefPtr modifier) + { + auto modifierLink = &syntax->modifiers.first; + AddModifier(&modifierLink, modifier); + } - // Parse HLSL-style `[name(arg, ...)]` style "attribute" modifiers - static void ParseSquareBracketAttributes(Parser* parser, RefPtr** ioModifierLink) + // Parse HLSL-style `[name(arg, ...)]` style "attribute" modifiers + static void ParseSquareBracketAttributes(Parser* parser, RefPtr** ioModifierLink) + { + parser->ReadToken(TokenType::LBracket); + for(;;) { - parser->ReadToken(TokenType::LBracket); - for(;;) + auto nameToken = parser->ReadToken(TokenType::Identifier); + RefPtr modifier = new HLSLUncheckedAttribute(); + modifier->nameToken = nameToken; + + if (AdvanceIf(parser, TokenType::LParent)) { - auto nameToken = parser->ReadToken(TokenType::Identifier); - RefPtr modifier = new HLSLUncheckedAttribute(); - modifier->nameToken = nameToken; + // HLSL-style `[name(arg0, ...)]` attribute - if (AdvanceIf(parser, TokenType::LParent)) + while (!AdvanceIfMatch(parser, TokenType::RParent)) { - // HLSL-style `[name(arg0, ...)]` attribute - - while (!AdvanceIfMatch(parser, TokenType::RParent)) + auto arg = parser->ParseArgExpr(); + if (arg) { - auto arg = parser->ParseArgExpr(); - if (arg) - { - modifier->args.Add(arg); - } + modifier->args.Add(arg); + } - if (AdvanceIfMatch(parser, TokenType::RParent)) - break; + if (AdvanceIfMatch(parser, TokenType::RParent)) + break; - parser->ReadToken(TokenType::Comma); - } + parser->ReadToken(TokenType::Comma); } - AddModifier(ioModifierLink, modifier); + } + AddModifier(ioModifierLink, modifier); - if (AdvanceIfMatch(parser, TokenType::RBracket)) - break; + if (AdvanceIfMatch(parser, TokenType::RBracket)) + break; - parser->ReadToken(TokenType::Comma); - } + parser->ReadToken(TokenType::Comma); } + } - static Modifiers ParseModifiers(Parser* parser) - { - Modifiers modifiers; - RefPtr* modifierLink = &modifiers.first; - for (;;) - { - CodePosition loc = parser->tokenReader.PeekLoc(); - - if (0) {} - - #define CASE(KEYWORD, TYPE) \ - else if(AdvanceIf(parser, #KEYWORD)) do { \ - RefPtr modifier = new TYPE(); \ - modifier->Position = loc; \ - AddModifier(&modifierLink, modifier); \ - } while(0) - - CASE(in, InModifier); - CASE(input, InputModifier); - CASE(out, OutModifier); - CASE(inout, InOutModifier); - CASE(const, ConstModifier); - CASE(instance, InstanceModifier); - CASE(__builtin, BuiltinModifier); - - CASE(inline, InlineModifier); - CASE(public, PublicModifier); - CASE(require, RequireModifier); - CASE(param, ParamModifier); - CASE(extern, ExternModifier); - - CASE(row_major, HLSLRowMajorLayoutModifier); - CASE(column_major, HLSLColumnMajorLayoutModifier); - - CASE(nointerpolation, HLSLNoInterpolationModifier); - CASE(linear, HLSLLinearModifier); - CASE(sample, HLSLSampleModifier); - CASE(centroid, HLSLCentroidModifier); - CASE(precise, HLSLPreciseModifier); - CASE(shared, HLSLEffectSharedModifier); - CASE(groupshared, HLSLGroupSharedModifier); - CASE(static, HLSLStaticModifier); - CASE(uniform, HLSLUniformModifier); - CASE(volatile, HLSLVolatileModifier); - - // Modifiers for geometry shader input - CASE(point, HLSLPointModifier); - CASE(line, HLSLLineModifier); - CASE(triangle, HLSLTriangleModifier); - CASE(lineadj, HLSLLineAdjModifier); - CASE(triangleadj, HLSLTriangleAdjModifier); - - // Modifiers for unary operator declarations - CASE(__prefix, PrefixModifier); - CASE(__postfix, PostfixModifier); - - #undef CASE - - else if (AdvanceIf(parser, "__intrinsic_op")) + static Modifiers ParseModifiers(Parser* parser) + { + Modifiers modifiers; + RefPtr* modifierLink = &modifiers.first; + for (;;) + { + CodePosition loc = parser->tokenReader.PeekLoc(); + + if (0) {} + + #define CASE(KEYWORD, TYPE) \ + else if(AdvanceIf(parser, #KEYWORD)) do { \ + RefPtr modifier = new TYPE(); \ + modifier->Position = loc; \ + AddModifier(&modifierLink, modifier); \ + } while(0) + + CASE(in, InModifier); + CASE(input, InputModifier); + CASE(out, OutModifier); + CASE(inout, InOutModifier); + CASE(const, ConstModifier); + CASE(instance, InstanceModifier); + CASE(__builtin, BuiltinModifier); + + CASE(inline, InlineModifier); + CASE(public, PublicModifier); + CASE(require, RequireModifier); + CASE(param, ParamModifier); + CASE(extern, ExternModifier); + + CASE(row_major, HLSLRowMajorLayoutModifier); + CASE(column_major, HLSLColumnMajorLayoutModifier); + + CASE(nointerpolation, HLSLNoInterpolationModifier); + CASE(linear, HLSLLinearModifier); + CASE(sample, HLSLSampleModifier); + CASE(centroid, HLSLCentroidModifier); + CASE(precise, HLSLPreciseModifier); + CASE(shared, HLSLEffectSharedModifier); + CASE(groupshared, HLSLGroupSharedModifier); + CASE(static, HLSLStaticModifier); + CASE(uniform, HLSLUniformModifier); + CASE(volatile, HLSLVolatileModifier); + + // Modifiers for geometry shader input + CASE(point, HLSLPointModifier); + CASE(line, HLSLLineModifier); + CASE(triangle, HLSLTriangleModifier); + CASE(lineadj, HLSLLineAdjModifier); + CASE(triangleadj, HLSLTriangleAdjModifier); + + // Modifiers for unary operator declarations + CASE(__prefix, PrefixModifier); + CASE(__postfix, PostfixModifier); + + #undef CASE + + else if (AdvanceIf(parser, "__intrinsic_op")) + { + auto modifier = new IntrinsicOpModifier(); + modifier->Position = loc; + + parser->ReadToken(TokenType::LParent); + if (parser->LookAheadToken(TokenType::IntLiterial)) + { + modifier->op = (IntrinsicOp)StringToInt(parser->ReadToken().Content); + } + else { - auto modifier = new IntrinsicOpModifier(); - modifier->Position = loc; + modifier->opToken = parser->ReadToken(TokenType::Identifier); - parser->ReadToken(TokenType::LParent); - if (parser->LookAheadToken(TokenType::IntLiterial)) + modifier->op = findIntrinsicOp(modifier->opToken.Content.Buffer()); + + if (modifier->op == IntrinsicOp::Unknown) { - modifier->op = (IntrinsicOp)StringToInt(parser->ReadToken().Content); + parser->sink->diagnose(loc, Diagnostics::unimplemented, "unknown intrinsic op"); } - else - { - modifier->opToken = parser->ReadToken(TokenType::Identifier); - - modifier->op = findIntrinsicOp(modifier->opToken.Content.Buffer()); + } - if (modifier->op == IntrinsicOp::Unknown) - { - parser->sink->diagnose(loc, Diagnostics::unimplemented, "unknown intrinsic op"); - } - } + parser->ReadToken(TokenType::RParent); - parser->ReadToken(TokenType::RParent); + AddModifier(&modifierLink, modifier); + } - AddModifier(&modifierLink, modifier); - } + else if (AdvanceIf(parser, "__intrinsic")) + { + auto modifier = new TargetIntrinsicModifier(); + modifier->Position = loc; - else if (AdvanceIf(parser, "__intrinsic")) + if (AdvanceIf(parser, TokenType::LParent)) { - auto modifier = new TargetIntrinsicModifier(); - modifier->Position = loc; + modifier->targetToken = parser->ReadToken(TokenType::Identifier); - if (AdvanceIf(parser, TokenType::LParent)) + if( AdvanceIf(parser, TokenType::Comma) ) { - modifier->targetToken = parser->ReadToken(TokenType::Identifier); - - if( AdvanceIf(parser, TokenType::Comma) ) + if( parser->LookAheadToken(TokenType::StringLiterial) ) { - if( parser->LookAheadToken(TokenType::StringLiterial) ) - { - modifier->definitionToken = parser->ReadToken(); - } - else - { - modifier->definitionToken = parser->ReadToken(TokenType::Identifier); - } + modifier->definitionToken = parser->ReadToken(); + } + else + { + modifier->definitionToken = parser->ReadToken(TokenType::Identifier); } - - parser->ReadToken(TokenType::RParent); } - AddModifier(&modifierLink, modifier); + parser->ReadToken(TokenType::RParent); } + AddModifier(&modifierLink, modifier); + } + - else if (AdvanceIf(parser, "layout")) + else if (AdvanceIf(parser, "layout")) + { + parser->ReadToken(TokenType::LParent); + while (!AdvanceIfMatch(parser, TokenType::RParent)) { - parser->ReadToken(TokenType::LParent); - while (!AdvanceIfMatch(parser, TokenType::RParent)) - { - auto nameToken = parser->ReadToken(TokenType::Identifier); + auto nameToken = parser->ReadToken(TokenType::Identifier); - RefPtr modifier; + RefPtr modifier; - // TODO: better handling of this choise (e.g., lookup in scope) - if(0) {} - #define CASE(KEYWORD, CLASS) \ - else if(nameToken.Content == #KEYWORD) modifier = new CLASS() + // TODO: better handling of this choise (e.g., lookup in scope) + if(0) {} + #define CASE(KEYWORD, CLASS) \ + else if(nameToken.Content == #KEYWORD) modifier = new CLASS() - CASE(constant_id, GLSLConstantIDLayoutModifier); - CASE(binding, GLSLBindingLayoutModifier); - CASE(set, GLSLSetLayoutModifier); - CASE(location, GLSLLocationLayoutModifier); + CASE(constant_id, GLSLConstantIDLayoutModifier); + CASE(binding, GLSLBindingLayoutModifier); + CASE(set, GLSLSetLayoutModifier); + CASE(location, GLSLLocationLayoutModifier); - #undef CASE - else - { - modifier = new GLSLUnparsedLayoutModifier(); - } + #undef CASE + else + { + modifier = new GLSLUnparsedLayoutModifier(); + } - modifier->nameToken = nameToken; + modifier->nameToken = nameToken; - if(AdvanceIf(parser, TokenType::OpAssign)) - { - modifier->valToken = parser->ReadToken(TokenType::IntLiterial); - } + if(AdvanceIf(parser, TokenType::OpAssign)) + { + modifier->valToken = parser->ReadToken(TokenType::IntLiterial); + } - AddModifier(&modifierLink, modifier); + AddModifier(&modifierLink, modifier); - if (AdvanceIf(parser, TokenType::RParent)) - break; - parser->ReadToken(TokenType::Comma); - } + if (AdvanceIf(parser, TokenType::RParent)) + break; + parser->ReadToken(TokenType::Comma); } - else if (parser->tokenReader.PeekTokenType() == TokenType::LBracket) + } + else if (parser->tokenReader.PeekTokenType() == TokenType::LBracket) + { + ParseSquareBracketAttributes(parser, &modifierLink); + } + else if (AdvanceIf(parser,"__builtin_type")) + { + RefPtr modifier = new BuiltinTypeModifier(); + parser->ReadToken(TokenType::LParent); + modifier->tag = BaseType(StringToInt(parser->ReadToken(TokenType::IntLiterial).Content)); + parser->ReadToken(TokenType::RParent); + + AddModifier(&modifierLink, modifier); + } + else if (AdvanceIf(parser,"__magic_type")) + { + RefPtr modifier = new MagicTypeModifier(); + parser->ReadToken(TokenType::LParent); + modifier->name = parser->ReadToken(TokenType::Identifier).Content; + if (AdvanceIf(parser, TokenType::Comma)) { - ParseSquareBracketAttributes(parser, &modifierLink); + modifier->tag = uint32_t(StringToInt(parser->ReadToken(TokenType::IntLiterial).Content)); } - else if (AdvanceIf(parser,"__builtin_type")) - { - RefPtr modifier = new BuiltinTypeModifier(); - parser->ReadToken(TokenType::LParent); - modifier->tag = BaseType(StringToInt(parser->ReadToken(TokenType::IntLiterial).Content)); - parser->ReadToken(TokenType::RParent); + parser->ReadToken(TokenType::RParent); - AddModifier(&modifierLink, modifier); - } - else if (AdvanceIf(parser,"__magic_type")) - { - RefPtr 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::IntLiterial).Content)); - } - parser->ReadToken(TokenType::RParent); + AddModifier(&modifierLink, modifier); + } + else + { + // Fallback case if none of the above explicit cases matched. - AddModifier(&modifierLink, modifier); - } - else + // If we are looking at an identifier, then it may map to a + // modifier declaration visible in the current scope + if( parser->LookAheadToken(TokenType::Identifier) ) { - // Fallback case if none of the above explicit cases matched. + LookupResult lookupResult = LookUp( + parser->tokenReader.PeekToken().Content, + parser->currentScope); - // If we are looking at an identifier, then it may map to a - // modifier declaration visible in the current scope - if( parser->LookAheadToken(TokenType::Identifier) ) + if( lookupResult.isValid() && !lookupResult.isOverloaded() ) { - LookupResult lookupResult = LookUp( - parser->tokenReader.PeekToken().Content, - parser->currentScope); + auto& item = lookupResult.item; + auto decl = item.declRef.GetDecl(); - if( lookupResult.isValid() && !lookupResult.isOverloaded() ) + if( auto modifierDecl = dynamic_cast(decl) ) { - auto& item = lookupResult.item; - auto decl = item.declRef.GetDecl(); + // We found a declaration for some modifier syntax, + // so lets create an instance of the type it names + // here. + + auto syntax = createInstanceOfSyntaxClassByName(modifierDecl->classNameToken.Content); + auto modifier = dynamic_cast(syntax); + + if( modifier ) + { + modifier->Position = parser->tokenReader.PeekLoc(); + modifier->nameToken = parser->ReadToken(TokenType::Identifier); - if( auto modifierDecl = dynamic_cast(decl) ) + AddModifier(&modifierLink, modifier); + continue; + } + else { - // We found a declaration for some modifier syntax, - // so lets create an instance of the type it names - // here. - - auto syntax = createInstanceOfSyntaxClassByName(modifierDecl->classNameToken.Content); - auto modifier = dynamic_cast(syntax); - - if( modifier ) - { - modifier->Position = parser->tokenReader.PeekLoc(); - modifier->nameToken = parser->ReadToken(TokenType::Identifier); - - AddModifier(&modifierLink, modifier); - continue; - } - else - { - parser->ReadToken(TokenType::Identifier); - assert(!"unexpected"); - } + parser->ReadToken(TokenType::Identifier); + assert(!"unexpected"); } } } - - // Done with modifier list - return modifiers; } + + // Done with modifier list + return modifiers; } } + } - static RefPtr parseImportDecl( - Parser* parser) - { - parser->ReadToken("__import"); + static RefPtr parseImportDecl( + Parser* parser) + { + parser->ReadToken("__import"); - auto decl = new ImportDecl(); - decl->nameToken = parser->ReadToken(TokenType::Identifier); - decl->scope = parser->currentScope; + auto decl = new ImportDecl(); + decl->nameToken = parser->ReadToken(TokenType::Identifier); + decl->scope = parser->currentScope; - parser->ReadToken(TokenType::Semicolon); + parser->ReadToken(TokenType::Semicolon); - return decl; - } + return decl; + } - static Token ParseDeclName( - Parser* parser) + static Token ParseDeclName( + Parser* parser) + { + Token name; + if (AdvanceIf(parser, "operator")) { - Token name; - if (AdvanceIf(parser, "operator")) + name = parser->ReadToken(); + switch (name.Type) { - name = parser->ReadToken(); - switch (name.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; + 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): Even more of a hack! - case TokenType::QuestionMark: - if (AdvanceIf(parser, TokenType::Colon)) - { - name.Content = name.Content + ":"; - break; - } + // Note(tfoley): A bit of a hack: + case TokenType::Comma: + case TokenType::OpAssign: + break; - default: - parser->sink->diagnose(name.Position, Diagnostics::invalidOperator, name.Content); + // Note(tfoley): Even more of a hack! + case TokenType::QuestionMark: + if (AdvanceIf(parser, TokenType::Colon)) + { + name.Content = name.Content + ":"; break; } + + default: + parser->sink->diagnose(name.Position, Diagnostics::invalidOperator, name.Content); + break; } - else - { - name = parser->ReadToken(TokenType::Identifier); - } - return name; } - - // A "declarator" as used in C-style languages - struct Declarator : RefObject + else { - // Different cases of declarator appear as "flavors" here - enum class Flavor - { - Name, - Pointer, - Array, - }; - Flavor flavor; - }; + name = parser->ReadToken(TokenType::Identifier); + } + return name; + } - // The most common case of declarator uses a simple name - struct NameDeclarator : Declarator + // A "declarator" as used in C-style languages + struct Declarator : RefObject + { + // Different cases of declarator appear as "flavors" here + enum class Flavor { - Token nameToken; + Name, + Pointer, + Array, }; + Flavor flavor; + }; - // A declarator that declares a pointer type - struct PointerDeclarator : Declarator - { - // location of the `*` token - CodePosition starLoc; + // The most common case of declarator uses a simple name + struct NameDeclarator : Declarator + { + Token nameToken; + }; - RefPtr inner; - }; + // A declarator that declares a pointer type + struct PointerDeclarator : Declarator + { + // location of the `*` token + CodePosition starLoc; - // A declarator that declares an array type - struct ArrayDeclarator : Declarator - { - RefPtr inner; + RefPtr inner; + }; - // location of the `[` token - CodePosition openBracketLoc; + // A declarator that declares an array type + struct ArrayDeclarator : Declarator + { + RefPtr inner; - // The expression that yields the element count, or NULL - RefPtr elementCountExpr; - }; + // location of the `[` token + CodePosition openBracketLoc; - // "Unwrapped" information about a declarator - struct DeclaratorInfo - { - RefPtr typeSpec; - Token nameToken; - RefPtr semantics; - RefPtr initializer; - }; + // The expression that yields the element count, or NULL + RefPtr elementCountExpr; + }; - // Add a member declaration to its container, and ensure that its - // parent link is set up correctly. - static void AddMember(RefPtr container, RefPtr member) + // "Unwrapped" information about a declarator + struct DeclaratorInfo + { + RefPtr typeSpec; + Token nameToken; + RefPtr semantics; + RefPtr initializer; + }; + + // Add a member declaration to its container, and ensure that its + // parent link is set up correctly. + static void AddMember(RefPtr container, RefPtr member) + { + if (container) { - if (container) - { - member->ParentDecl = container.Ptr(); - container->Members.Add(member); + member->ParentDecl = container.Ptr(); + container->Members.Add(member); - container->memberDictionaryIsValid = false; - } + container->memberDictionaryIsValid = false; } + } - static void AddMember(RefPtr scope, RefPtr member) + static void AddMember(RefPtr scope, RefPtr member) + { + if (scope) { - if (scope) - { - AddMember(scope->containerDecl, member); - } + AddMember(scope->containerDecl, member); } + } - static void parseParameterList( - Parser* parser, - RefPtr 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; - } + static void parseParameterList( + Parser* parser, + RefPtr decl) + { + parser->ReadToken(TokenType::LParent); - while (!AdvanceIfMatch(parser, TokenType::RParent)) - { - AddMember(decl, parser->ParseParameter()); - if (AdvanceIf(parser, TokenType::RParent)) - break; - parser->ReadToken(TokenType::Comma); - } + // 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; } - static void ParseFuncDeclHeader( - Parser* parser, - DeclaratorInfo const& declaratorInfo, - RefPtr decl) + while (!AdvanceIfMatch(parser, TokenType::RParent)) { - parser->PushScope(decl.Ptr()); + AddMember(decl, parser->ParseParameter()); + if (AdvanceIf(parser, TokenType::RParent)) + break; + parser->ReadToken(TokenType::Comma); + } + } - parser->FillPosition(decl.Ptr()); - decl->Position = declaratorInfo.nameToken.Position; + static void ParseFuncDeclHeader( + Parser* parser, + DeclaratorInfo const& declaratorInfo, + RefPtr decl) + { + parser->PushScope(decl.Ptr()); - decl->Name = declaratorInfo.nameToken; - decl->ReturnType = TypeExp(declaratorInfo.typeSpec); - parseParameterList(parser, decl); - ParseOptSemantics(parser, decl.Ptr()); - } + parser->FillPosition(decl.Ptr()); + decl->Position = declaratorInfo.nameToken.Position; - static RefPtr ParseFuncDecl( - Parser* parser, - ContainerDecl* /*containerDecl*/, - DeclaratorInfo const& declaratorInfo) - { - RefPtr decl = new FunctionSyntaxNode(); - ParseFuncDeclHeader(parser, declaratorInfo, decl); + decl->Name = declaratorInfo.nameToken; + decl->ReturnType = TypeExp(declaratorInfo.typeSpec); + parseParameterList(parser, decl); + ParseOptSemantics(parser, decl.Ptr()); + } - if (AdvanceIf(parser, TokenType::Semicolon)) - { - // empty body - } - else - { - decl->Body = parser->ParseBlockStatement(); - } + static RefPtr ParseFuncDecl( + Parser* parser, + ContainerDecl* /*containerDecl*/, + DeclaratorInfo const& declaratorInfo) + { + RefPtr decl = new FunctionSyntaxNode(); + ParseFuncDeclHeader(parser, declaratorInfo, decl); - parser->PopScope(); - return decl; + if (AdvanceIf(parser, TokenType::Semicolon)) + { + // empty body } - - static RefPtr CreateVarDeclForContext( - ContainerDecl* containerDecl ) + else { - if (dynamic_cast(containerDecl) || dynamic_cast(containerDecl)) - { - return new StructField(); - } - else if (dynamic_cast(containerDecl)) - { - return new ParameterSyntaxNode(); - } - else - { - return new Variable(); - } + decl->Body = parser->ParseBlockStatement(); } - // Add modifiers to the end of the modifier list for a declaration - void AddModifiers(Decl* decl, RefPtr modifiers) - { - if (!modifiers) - return; + parser->PopScope(); + return decl; + } - RefPtr* link = &decl->modifiers.first; - while (*link) - { - link = &(*link)->next; - } - *link = modifiers; + static RefPtr CreateVarDeclForContext( + ContainerDecl* containerDecl ) + { + if (dynamic_cast(containerDecl) || dynamic_cast(containerDecl)) + { + return new StructField(); + } + else if (dynamic_cast(containerDecl)) + { + return new ParameterSyntaxNode(); + } + else + { + return new Variable(); } + } + // Add modifiers to the end of the modifier list for a declaration + void AddModifiers(Decl* decl, RefPtr modifiers) + { + if (!modifiers) + return; - static String GenerateName(Parser* /*parser*/, String const& base) + RefPtr* link = &decl->modifiers.first; + while (*link) { - // TODO: somehow mangle the name to avoid clashes - return base; + link = &(*link)->next; } + *link = modifiers; + } + + + static String GenerateName(Parser* /*parser*/, String const& base) + { + // TODO: somehow mangle the name to avoid clashes + return base; + } + + static String 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 decl, + DeclaratorInfo const& declaratorInfo) + { + parser->FillPosition(decl.Ptr()); - static String GenerateName(Parser* parser) + if( declaratorInfo.nameToken.Type == TokenType::Unknown ) { - return GenerateName(parser, "_anonymous_" + String(parser->anonymousCounter++)); + // HACK(tfoley): we always give a name, even if the declarator didn't include one... :( + decl->Name.Content = GenerateName(parser); } + else + { + decl->Position = declaratorInfo.nameToken.Position; + decl->Name = declaratorInfo.nameToken; + } + decl->Type = TypeExp(declaratorInfo.typeSpec); + AddModifiers(decl.Ptr(), declaratorInfo.semantics); - // Set up a variable declaration based on what we saw in its declarator... - static void CompleteVarDecl( - Parser* parser, - RefPtr decl, - DeclaratorInfo const& declaratorInfo) - { - parser->FillPosition(decl.Ptr()); + decl->Expr = declaratorInfo.initializer; + } - if( declaratorInfo.nameToken.Type == TokenType::Unknown ) + static RefPtr ParseDeclarator(Parser* parser); + + static RefPtr ParseDirectAbstractDeclarator( + Parser* parser) + { + RefPtr declarator; + switch( parser->tokenReader.PeekTokenType() ) + { + case TokenType::Identifier: { - // HACK(tfoley): we always give a name, even if the declarator didn't include one... :( - decl->Name.Content = GenerateName(parser); + auto nameDeclarator = new NameDeclarator(); + nameDeclarator->flavor = Declarator::Flavor::Name; + nameDeclarator->nameToken = ParseDeclName(parser); + declarator = nameDeclarator; } - else + break; + + case TokenType::LParent: { - decl->Position = declaratorInfo.nameToken.Position; - decl->Name = declaratorInfo.nameToken; + // 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); } - decl->Type = TypeExp(declaratorInfo.typeSpec); + break; - AddModifiers(decl.Ptr(), declaratorInfo.semantics); - - decl->Expr = declaratorInfo.initializer; + default: + // an empty declarator is allowed + return nullptr; } - static RefPtr ParseDeclarator(Parser* parser); - - static RefPtr ParseDirectAbstractDeclarator( - Parser* parser) + // postifx additions + for( ;;) { - RefPtr declarator; switch( parser->tokenReader.PeekTokenType() ) { - case TokenType::Identifier: - { - auto nameDeclarator = new NameDeclarator(); - nameDeclarator->flavor = Declarator::Flavor::Name; - nameDeclarator->nameToken = ParseDeclName(parser); - declarator = nameDeclarator; - } - break; - - case TokenType::LParent: + case TokenType::LBracket: { - // 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; - } + auto arrayDeclarator = new ArrayDeclarator(); + arrayDeclarator->openBracketLoc = parser->tokenReader.PeekLoc(); + arrayDeclarator->flavor = Declarator::Flavor::Array; + arrayDeclarator->inner = declarator; - // postifx additions - for( ;;) - { - switch( parser->tokenReader.PeekTokenType() ) - { - case TokenType::LBracket: + parser->ReadToken(TokenType::LBracket); + if( parser->tokenReader.PeekTokenType() != TokenType::RBracket ) { - 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; + arrayDeclarator->elementCountExpr = parser->ParseExpression(); } + parser->ReadToken(TokenType::RBracket); - case TokenType::LParent: - break; - - default: - break; + declarator = arrayDeclarator; + continue; } + case TokenType::LParent: + break; + + default: break; } - return declarator; + break; } - // Parse a declarator (or at least as much of one as we support) - static RefPtr ParseDeclarator( - Parser* parser) + return declarator; + } + + // Parse a declarator (or at least as much of one as we support) + static RefPtr ParseDeclarator( + Parser* parser) + { + if( parser->tokenReader.PeekTokenType() == TokenType::OpMul ) { - if( parser->tokenReader.PeekTokenType() == TokenType::OpMul ) - { - auto ptrDeclarator = new PointerDeclarator(); - ptrDeclarator->starLoc = parser->tokenReader.PeekLoc(); - ptrDeclarator->flavor = Declarator::Flavor::Pointer; + auto ptrDeclarator = new PointerDeclarator(); + ptrDeclarator->starLoc = parser->tokenReader.PeekLoc(); + ptrDeclarator->flavor = Declarator::Flavor::Pointer; - parser->ReadToken(TokenType::OpMul); + parser->ReadToken(TokenType::OpMul); - // TODO(tfoley): allow qualifiers like `const` here? + // TODO(tfoley): allow qualifiers like `const` here? - ptrDeclarator->inner = ParseDeclarator(parser); - return ptrDeclarator; - } - else - { - return ParseDirectAbstractDeclarator(parser); - } + ptrDeclarator->inner = ParseDeclarator(parser); + return ptrDeclarator; } - - // A declarator plus optional semantics and initializer - struct InitDeclarator - { - RefPtr declarator; - RefPtr semantics; - RefPtr initializer; - }; - - // Parse a declarator plus optional semantics - static InitDeclarator ParseSemanticDeclarator( - Parser* parser) + else { - InitDeclarator result; - result.declarator = ParseDeclarator(parser); - result.semantics = ParseOptSemantics(parser); - return result; + return ParseDirectAbstractDeclarator(parser); } + } + + // A declarator plus optional semantics and initializer + struct InitDeclarator + { + RefPtr declarator; + RefPtr semantics; + RefPtr 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) + // Parse a declarator plus optional semantics and initializer + static InitDeclarator ParseInitDeclarator( + Parser* parser) + { + InitDeclarator result = ParseSemanticDeclarator(parser); + if (AdvanceIf(parser, TokenType::OpAssign)) { - InitDeclarator result = ParseSemanticDeclarator(parser); - if (AdvanceIf(parser, TokenType::OpAssign)) - { - result.initializer = parser->ParseInitExpr(); - } - return result; + result.initializer = parser->ParseInitExpr(); } + return result; + } - static void UnwrapDeclarator( - RefPtr declarator, - DeclaratorInfo* ioInfo) + static void UnwrapDeclarator( + RefPtr declarator, + DeclaratorInfo* ioInfo) + { + while( declarator ) { - while( declarator ) + switch(declarator->flavor) { - switch(declarator->flavor) + case Declarator::Flavor::Name: { - case Declarator::Flavor::Name: - { - auto nameDeclarator = (NameDeclarator*) declarator.Ptr(); - ioInfo->nameToken = nameDeclarator->nameToken; - return; - } - break; - - case Declarator::Flavor::Pointer: - { - auto ptrDeclarator = (PointerDeclarator*) declarator.Ptr(); + auto nameDeclarator = (NameDeclarator*) declarator.Ptr(); + ioInfo->nameToken = nameDeclarator->nameToken; + return; + } + break; - // TODO(tfoley): we don't support pointers for now - // ioInfo->typeSpec = new PointerTypeExpr(ioInfo->typeSpec); + case Declarator::Flavor::Pointer: + { + auto ptrDeclarator = (PointerDeclarator*) declarator.Ptr(); - declarator = ptrDeclarator->inner; - } - break; + // TODO(tfoley): we don't support pointers for now + // ioInfo->typeSpec = new PointerTypeExpr(ioInfo->typeSpec); - case Declarator::Flavor::Array: - { - // TODO(tfoley): we don't support pointers for now - auto arrayDeclarator = (ArrayDeclarator*) declarator.Ptr(); + declarator = ptrDeclarator->inner; + } + break; - auto arrayTypeExpr = new IndexExpressionSyntaxNode(); - arrayTypeExpr->Position = arrayDeclarator->openBracketLoc; - arrayTypeExpr->BaseExpression = ioInfo->typeSpec; - arrayTypeExpr->IndexExpression = arrayDeclarator->elementCountExpr; - ioInfo->typeSpec = arrayTypeExpr; + case Declarator::Flavor::Array: + { + // TODO(tfoley): we don't support pointers for now + auto arrayDeclarator = (ArrayDeclarator*) declarator.Ptr(); - declarator = arrayDeclarator->inner; - } - break; + auto arrayTypeExpr = new IndexExpressionSyntaxNode(); + arrayTypeExpr->Position = arrayDeclarator->openBracketLoc; + arrayTypeExpr->BaseExpression = ioInfo->typeSpec; + arrayTypeExpr->IndexExpression = arrayDeclarator->elementCountExpr; + ioInfo->typeSpec = arrayTypeExpr; - default: - SLANG_UNREACHABLE("all cases handled"); - break; + 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; - } + 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 - { - CodePosition startPosition; - RefPtr decl; - RefPtr group; + // Either a single declaration, or a group of them + struct DeclGroupBuilder + { + CodePosition startPosition; + RefPtr decl; + RefPtr group; - // Add a new declaration to the potential group - void addDecl( - RefPtr newDecl) - { - assert(newDecl); + // Add a new declaration to the potential group + void addDecl( + RefPtr newDecl) + { + assert(newDecl); - if( decl ) - { - group = new DeclGroup(); - group->Position = startPosition; - group->decls.Add(decl); - decl = nullptr; - } - - if( group ) - { - group->decls.Add(newDecl); - } - else - { - decl = newDecl; - } + if( decl ) + { + group = new DeclGroup(); + group->Position = startPosition; + group->decls.Add(decl); + decl = nullptr; } - RefPtr getResult() + if( group ) { - if(group) return group; - return decl; + group->decls.Add(newDecl); } - }; + else + { + decl = newDecl; + } + } - // Pares an argument to an application of a generic - RefPtr ParseGenericArg(Parser* parser) + RefPtr getResult() { - return parser->ParseArgExpr(); + if(group) return group; + return decl; } + }; - // Create a type expression that will refer to the given declaration - static RefPtr - createDeclRefType(Parser* parser, RefPtr 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 + // Pares an argument to an application of a generic + RefPtr ParseGenericArg(Parser* parser) + { + return parser->ParseArgExpr(); + } - auto expr = new VarExpressionSyntaxNode(); - expr->scope = parser->currentScope.Ptr(); - expr->Position = decl->getNameToken().Position; - expr->Variable = decl->getName(); - return expr; - } + // Create a type expression that will refer to the given declaration + static RefPtr + createDeclRefType(Parser* parser, RefPtr 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 - // 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; + auto expr = new VarExpressionSyntaxNode(); + expr->scope = parser->currentScope.Ptr(); + expr->Position = decl->getNameToken().Position; + expr->Variable = decl->getName(); + return expr; + } - // Put the resulting expression (which should evaluate to a type) here - RefPtr 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; - static TypeSpec - parseTypeSpec(Parser* parser) - { - TypeSpec typeSpec; + // Put the resulting expression (which should evaluate to a type) here + RefPtr expr; + }; - // We may see a `struct` type 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;`) - // - 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; - } + static TypeSpec + parseTypeSpec(Parser* parser) + { + TypeSpec typeSpec; - Token typeName = parser->ReadToken(TokenType::Identifier); + // We may see a `struct` type 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;`) + // + 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; + } - auto basicType = new VarExpressionSyntaxNode(); - basicType->scope = parser->currentScope.Ptr(); - basicType->Position = typeName.Position; - basicType->Variable = typeName.Content; + Token typeName = parser->ReadToken(TokenType::Identifier); - RefPtr typeExpr = basicType; + auto basicType = new VarExpressionSyntaxNode(); + basicType->scope = parser->currentScope.Ptr(); + basicType->Position = typeName.Position; + basicType->Variable = typeName.Content; - if (parser->LookAheadToken(TokenType::OpLess)) + RefPtr typeExpr = basicType; + + if (parser->LookAheadToken(TokenType::OpLess)) + { + RefPtr gtype = new GenericAppExpr(); + parser->FillPosition(gtype.Ptr()); // set up scope for lookup + gtype->Position = typeName.Position; + gtype->FunctionExpr = typeExpr; + parser->ReadToken(TokenType::OpLess); + parser->genericDepth++; + // For now assume all generics have at least one argument + gtype->Arguments.Add(ParseGenericArg(parser)); + while (AdvanceIf(parser, TokenType::Comma)) { - RefPtr gtype = new GenericAppExpr(); - parser->FillPosition(gtype.Ptr()); // set up scope for lookup - gtype->Position = typeName.Position; - gtype->FunctionExpr = typeExpr; - parser->ReadToken(TokenType::OpLess); - parser->genericDepth++; - // For now assume all generics have at least one argument gtype->Arguments.Add(ParseGenericArg(parser)); - while (AdvanceIf(parser, TokenType::Comma)) - { - gtype->Arguments.Add(ParseGenericArg(parser)); - } - parser->genericDepth--; - parser->ReadToken(TokenType::OpGreater); - typeExpr = gtype; } - - typeSpec.expr = typeExpr; - return typeSpec; + parser->genericDepth--; + parser->ReadToken(TokenType::OpGreater); + typeExpr = gtype; } + typeSpec.expr = typeExpr; + return typeSpec; + } - static RefPtr ParseDeclaratorDecl( - Parser* parser, - ContainerDecl* containerDecl) - { - CodePosition startPosition = parser->tokenReader.PeekLoc(); - auto typeSpec = parseTypeSpec(parser); + static RefPtr ParseDeclaratorDecl( + Parser* parser, + ContainerDecl* containerDecl) + { + CodePosition startPosition = parser->tokenReader.PeekLoc(); - // 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; + auto typeSpec = parseTypeSpec(parser); - // The type specifier may include a declaration. E.g., - // it might declare a `struct` type. - if(typeSpec.decl) - declGroupBuilder.addDecl(typeSpec.decl); + // 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; - if( AdvanceIf(parser, TokenType::Semicolon) ) - { - // No actual variable is being declared here, but - // that might not be an error. + // The type specifier may include a declaration. E.g., + // it might declare a `struct` type. + if(typeSpec.decl) + declGroupBuilder.addDecl(typeSpec.decl); - auto result = declGroupBuilder.getResult(); - if( !result ) - { - parser->sink->diagnose(startPosition, Diagnostics::declarationDidntDeclareAnything); - } - return result; - } + 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; + } - InitDeclarator initDeclarator = ParseInitDeclarator(parser); - DeclaratorInfo declaratorInfo; - declaratorInfo.typeSpec = typeSpec.expr; + 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 - // 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 ParseFuncDecl(parser, containerDecl, declaratorInfo); - } + // 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 - // Otherwise we are looking at a variable declaration, which could be one in a sequence... + // 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 ParseFuncDecl(parser, containerDecl, declaratorInfo); + } - if( AdvanceIf(parser, TokenType::Semicolon) ) - { - // easy case: we only had a single declaration! - UnwrapDeclarator(initDeclarator, &declaratorInfo); - RefPtr firstDecl = CreateVarDeclForContext(containerDecl); - CompleteVarDecl(parser, firstDecl, declaratorInfo); + // Otherwise we are looking at a variable declaration, which could be one in a sequence... - declGroupBuilder.addDecl(firstDecl); - return declGroupBuilder.getResult(); - } + if( AdvanceIf(parser, TokenType::Semicolon) ) + { + // easy case: we only had a single declaration! + UnwrapDeclarator(initDeclarator, &declaratorInfo); + RefPtr firstDecl = CreateVarDeclForContext(containerDecl); + CompleteVarDecl(parser, firstDecl, declaratorInfo); - // 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. + declGroupBuilder.addDecl(firstDecl); + return declGroupBuilder.getResult(); + } - auto sharedTypeSpec = new SharedTypeExpr(); - sharedTypeSpec->Position = typeSpec.expr->Position; - sharedTypeSpec->base = TypeExp(typeSpec.expr); + // 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. - for(;;) - { - declaratorInfo.typeSpec = sharedTypeSpec; - UnwrapDeclarator(initDeclarator, &declaratorInfo); + auto sharedTypeSpec = new SharedTypeExpr(); + sharedTypeSpec->Position = typeSpec.expr->Position; + sharedTypeSpec->base = TypeExp(typeSpec.expr); - RefPtr varDecl = CreateVarDeclForContext(containerDecl); - CompleteVarDecl(parser, varDecl, declaratorInfo); + for(;;) + { + declaratorInfo.typeSpec = sharedTypeSpec; + UnwrapDeclarator(initDeclarator, &declaratorInfo); - declGroupBuilder.addDecl(varDecl); + RefPtr varDecl = CreateVarDeclForContext(containerDecl); + CompleteVarDecl(parser, varDecl, declaratorInfo); - // end of the sequence? - if(AdvanceIf(parser, TokenType::Semicolon)) - return declGroupBuilder.getResult(); + declGroupBuilder.addDecl(varDecl); - // ad-hoc recovery, to avoid infinite loops - if( parser->isRecovering ) - { - parser->ReadToken(TokenType::Semicolon); - return declGroupBuilder.getResult(); - } + // end of the sequence? + if(AdvanceIf(parser, 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... + // ad-hoc recovery, to avoid infinite loops + if( parser->isRecovering ) + { + parser->ReadToken(TokenType::Semicolon); + return declGroupBuilder.getResult(); + } - if (!AdvanceIf(parser, TokenType::Comma)) - { - 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... - // expect another variable declaration... - initDeclarator = ParseInitDeclarator(parser); + if (!AdvanceIf(parser, TokenType::Comma)) + { + parser->ReadToken(TokenType::Semicolon); + return declGroupBuilder.getResult(); } + + // expect another variable declaration... + initDeclarator = ParseInitDeclarator(parser); } + } - // - // layout-semantic ::= (register | packoffset) '(' register-name component-mask? ')' - // register-name ::= identifier - // component-mask ::= '.' identifier - // - static void ParseHLSLLayoutSemantic( - Parser* parser, - HLSLLayoutSemantic* semantic) + // + // layout-semantic ::= (register | packoffset) '(' register-name component-mask? ')' + // register-name ::= identifier + // component-mask ::= '.' identifier + // + static void ParseHLSLLayoutSemantic( + Parser* parser, + HLSLLayoutSemantic* semantic) + { + semantic->name = parser->ReadToken(TokenType::Identifier); + + parser->ReadToken(TokenType::LParent); + semantic->registerName = parser->ReadToken(TokenType::Identifier); + if (AdvanceIf(parser, TokenType::Dot)) { - semantic->name = parser->ReadToken(TokenType::Identifier); + semantic->componentMask = parser->ReadToken(TokenType::Identifier); + } + parser->ReadToken(TokenType::RParent); + } - parser->ReadToken(TokenType::LParent); - semantic->registerName = parser->ReadToken(TokenType::Identifier); - if (AdvanceIf(parser, TokenType::Dot)) - { - semantic->componentMask = parser->ReadToken(TokenType::Identifier); - } - parser->ReadToken(TokenType::RParent); + // + // semantic ::= identifier ( '(' args ')' )? + // + static RefPtr ParseSemantic( + Parser* parser) + { + if (parser->LookAheadToken("register")) + { + RefPtr semantic = new HLSLRegisterSemantic(); + ParseHLSLLayoutSemantic(parser, semantic.Ptr()); + return semantic; + } + else if (parser->LookAheadToken("packoffset")) + { + RefPtr semantic = new HLSLPackOffsetSemantic(); + ParseHLSLLayoutSemantic(parser, semantic.Ptr()); + return semantic; } + else + { + RefPtr semantic = new HLSLSimpleSemantic(); + semantic->name = parser->ReadToken(TokenType::Identifier); + return semantic; + } + } - // - // semantic ::= identifier ( '(' args ')' )? - // - static RefPtr ParseSemantic( - Parser* parser) + // + // opt-semantics ::= (':' semantic)* + // + static RefPtr ParseOptSemantics( + Parser* parser) + { + if (!AdvanceIf(parser, TokenType::Colon)) + return nullptr; + + RefPtr result; + RefPtr* link = &result; + assert(!*link); + + for (;;) { - if (parser->LookAheadToken("register")) - { - RefPtr semantic = new HLSLRegisterSemantic(); - ParseHLSLLayoutSemantic(parser, semantic.Ptr()); - return semantic; - } - else if (parser->LookAheadToken("packoffset")) + RefPtr semantic = ParseSemantic(parser); + if (semantic) { - RefPtr semantic = new HLSLPackOffsetSemantic(); - ParseHLSLLayoutSemantic(parser, semantic.Ptr()); - return semantic; + *link = semantic; + link = &semantic->next; } - else + + switch (parser->tokenReader.PeekTokenType()) { - RefPtr semantic = new HLSLSimpleSemantic(); - semantic->name = parser->ReadToken(TokenType::Identifier); - return semantic; + case TokenType::LBrace: + case TokenType::Semicolon: + case TokenType::Comma: + case TokenType::RParent: + case TokenType::EndOfFile: + return result; + + default: + break; } + + parser->ReadToken(TokenType::Colon); } + } + + + static void ParseOptSemantics( + Parser* parser, + Decl* decl) + { + AddModifiers(decl, ParseOptSemantics(parser)); + } + + static RefPtr ParseHLSLBufferDecl( + Parser* parser) + { + // An HLSL declaration of a constant buffer like this: // - // opt-semantics ::= (':' semantic)* + // cbuffer Foo : register(b0) { int a; float b; }; // - static RefPtr ParseOptSemantics( - Parser* parser) + // 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. + + // We first look at the declaration keywrod to determine + // the type of buffer to declare: + String bufferWrapperTypeName; + CodePosition bufferWrapperTypeNamePos = parser->tokenReader.PeekLoc(); + if (AdvanceIf(parser, "cbuffer")) + { + bufferWrapperTypeName = "ConstantBuffer"; + } + else if (AdvanceIf(parser, "tbuffer")) + { + bufferWrapperTypeName = "TextureBuffer"; + } + else { - if (!AdvanceIf(parser, TokenType::Colon)) - return nullptr; + Unexpected(parser); + } - RefPtr result; - RefPtr* link = &result; - assert(!*link); + // 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 bufferDataTypeDecl = new StructSyntaxNode(); + RefPtr bufferVarDecl = new Variable(); - for (;;) - { - RefPtr semantic = ParseSemantic(parser); - if (semantic) - { - *link = semantic; - link = &semantic->next; - } + // Both declarations will have a location that points to the name + parser->FillPosition(bufferDataTypeDecl.Ptr()); + parser->FillPosition(bufferVarDecl.Ptr()); - switch (parser->tokenReader.PeekTokenType()) - { - case TokenType::LBrace: - case TokenType::Semicolon: - case TokenType::Comma: - case TokenType::RParent: - case TokenType::EndOfFile: - return result; + auto reflectionNameToken = parser->ReadToken(TokenType::Identifier); - default: - break; - } + // Attach the reflection name to the block so we can use it + auto reflectionNameModifier = new ParameterBlockReflectionName(); + reflectionNameModifier->nameToken = reflectionNameToken; + addModifier(bufferVarDecl, reflectionNameModifier); - parser->ReadToken(TokenType::Colon); - } + // Both the buffer variable and its type need to have names generated + bufferVarDecl->Name.Content = GenerateName(parser, "SLANG_constantBuffer_" + reflectionNameToken.Content); + bufferDataTypeDecl->Name.Content = GenerateName(parser, "SLANG_ConstantBuffer_" + reflectionNameToken.Content); - } + addModifier(bufferDataTypeDecl, new ImplicitParameterBlockElementTypeModifier()); + addModifier(bufferVarDecl, new ImplicitParameterBlockVariableModifier()); + // 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. - static void ParseOptSemantics( - Parser* parser, - Decl* decl) - { - AddModifiers(decl, ParseOptSemantics(parser)); - } + // Construct a type expression to reference the buffer data type + auto bufferDataTypeExpr = new VarExpressionSyntaxNode(); + bufferDataTypeExpr->Position = bufferDataTypeDecl->Position; + bufferDataTypeExpr->Variable = bufferDataTypeDecl->Name.Content; + bufferDataTypeExpr->scope = parser->currentScope.Ptr(); - static RefPtr ParseHLSLBufferDecl( - Parser* parser) - { - // 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. - - // We first look at the declaration keywrod to determine - // the type of buffer to declare: - String bufferWrapperTypeName; - CodePosition bufferWrapperTypeNamePos = parser->tokenReader.PeekLoc(); - if (AdvanceIf(parser, "cbuffer")) - { - bufferWrapperTypeName = "ConstantBuffer"; - } - else if (AdvanceIf(parser, "tbuffer")) - { - bufferWrapperTypeName = "TextureBuffer"; - } - else - { - Unexpected(parser); - } + // Construct a type exrpession to reference the type constructor + auto bufferWrapperTypeExpr = new VarExpressionSyntaxNode(); + bufferWrapperTypeExpr->Position = bufferWrapperTypeNamePos; + bufferWrapperTypeExpr->Variable = bufferWrapperTypeName; - // 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 bufferDataTypeDecl = new StructSyntaxNode(); - RefPtr bufferVarDecl = new Variable(); - - // 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 ParameterBlockReflectionName(); - reflectionNameModifier->nameToken = reflectionNameToken; - addModifier(bufferVarDecl, reflectionNameModifier); - - // Both the buffer variable and its type need to have names generated - bufferVarDecl->Name.Content = GenerateName(parser, "SLANG_constantBuffer_" + reflectionNameToken.Content); - bufferDataTypeDecl->Name.Content = GenerateName(parser, "SLANG_ConstantBuffer_" + reflectionNameToken.Content); - - addModifier(bufferDataTypeDecl, new ImplicitParameterBlockElementTypeModifier()); - addModifier(bufferVarDecl, new ImplicitParameterBlockVariableModifier()); - - // 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 VarExpressionSyntaxNode(); - bufferDataTypeExpr->Position = bufferDataTypeDecl->Position; - bufferDataTypeExpr->Variable = bufferDataTypeDecl->Name.Content; - bufferDataTypeExpr->scope = parser->currentScope.Ptr(); - - // Construct a type exrpession to reference the type constructor - auto bufferWrapperTypeExpr = new VarExpressionSyntaxNode(); - bufferWrapperTypeExpr->Position = bufferWrapperTypeNamePos; - bufferWrapperTypeExpr->Variable = 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->Position = bufferVarDecl->Position; - bufferVarTypeExpr->FunctionExpr = bufferWrapperTypeExpr; - bufferVarTypeExpr->Arguments.Add(bufferDataTypeExpr); - - bufferVarDecl->Type.exp = bufferVarTypeExpr; - - // Any semantics applied to the bufer 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. + // 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; - AddMember(parser->currentScope, bufferDataTypeDecl); + // 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->Position = bufferVarDecl->Position; + bufferVarTypeExpr->FunctionExpr = bufferWrapperTypeExpr; + bufferVarTypeExpr->Arguments.Add(bufferDataTypeExpr); - return bufferVarDecl; - } + bufferVarDecl->Type.exp = bufferVarTypeExpr; + + // Any semantics applied to the bufer 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 void removeModifier( - Modifiers& modifiers, - RefPtr modifier) + static void removeModifier( + Modifiers& modifiers, + RefPtr modifier) + { + RefPtr* link = &modifiers.first; + while (*link) { - RefPtr* link = &modifiers.first; - while (*link) + if (*link == modifier) { - if (*link == modifier) - { - *link = (*link)->next; - return; - } - - link = &(*link)->next; + *link = (*link)->next; + return; } + + link = &(*link)->next; } + } + + static RefPtr parseGLSLBlockDecl( + Parser* parser, + Modifiers& modifiers) + { + // An GLSL block like this: + // + // uniform Foo { int a; float b; } foo; + // + // is treated as syntax sugar for a type declaration + // and then a global variable declaration using that type: + // + // struct $anonymous { int a; float b; }; + // Block<$anonymous> foo; + // + // where `$anonymous` is a fresh name. + // + // If a "local name" like `foo` is not given, then + // we make the declaration "transparent" so that lookup + // will see through it to the members inside. - static RefPtr parseGLSLBlockDecl( - Parser* parser, - Modifiers& modifiers) + + CodePosition pos = parser->tokenReader.PeekLoc(); + + // The initial name before the `{` is only supposed + // to be made visible to reflection + auto reflectionNameToken = parser->ReadToken(TokenType::Identifier); + + // Look at the qualifiers present on the block to decide what kind + // of block we are looking at. Also *remove* those qualifiers so + // that they don't interfere with downstream work. + String blockWrapperTypeName; + if( auto uniformMod = modifiers.findModifier() ) { - // An GLSL block like this: - // - // uniform Foo { int a; float b; } foo; - // - // is treated as syntax sugar for a type declaration - // and then a global variable declaration using that type: - // - // struct $anonymous { int a; float b; }; - // Block<$anonymous> foo; - // - // where `$anonymous` is a fresh name. - // - // If a "local name" like `foo` is not given, then - // we make the declaration "transparent" so that lookup - // will see through it to the members inside. + removeModifier(modifiers, uniformMod); + blockWrapperTypeName = "ConstantBuffer"; + } + else if( auto inMod = modifiers.findModifier() ) + { + removeModifier(modifiers, inMod); + blockWrapperTypeName = "__GLSLInputParameterBlock"; + } + else if( auto outMod = modifiers.findModifier() ) + { + removeModifier(modifiers, outMod); + blockWrapperTypeName = "__GLSLOutputParameterBlock"; + } + else if( auto bufferMod = modifiers.findModifier() ) + { + removeModifier(modifiers, bufferMod); + blockWrapperTypeName = "__GLSLShaderStorageBuffer"; + } + else + { + // Unknown case: just map to a constant buffer and hope for the best + blockWrapperTypeName = "ConstantBuffer"; + } + // 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 blockDataTypeDecl = new StructSyntaxNode(); + RefPtr blockVarDecl = new Variable(); - CodePosition pos = parser->tokenReader.PeekLoc(); + addModifier(blockDataTypeDecl, new ImplicitParameterBlockElementTypeModifier()); + addModifier(blockVarDecl, new ImplicitParameterBlockVariableModifier()); - // The initial name before the `{` is only supposed - // to be made visible to reflection - auto reflectionNameToken = parser->ReadToken(TokenType::Identifier); + // Attach the reflection name to the block so we can use it + auto reflectionNameModifier = new ParameterBlockReflectionName(); + reflectionNameModifier->nameToken = reflectionNameToken; + addModifier(blockVarDecl, reflectionNameModifier); - // Look at the qualifiers present on the block to decide what kind - // of block we are looking at. Also *remove* those qualifiers so - // that they don't interfere with downstream work. - String blockWrapperTypeName; - if( auto uniformMod = modifiers.findModifier() ) - { - removeModifier(modifiers, uniformMod); - blockWrapperTypeName = "ConstantBuffer"; - } - else if( auto inMod = modifiers.findModifier() ) - { - removeModifier(modifiers, inMod); - blockWrapperTypeName = "__GLSLInputParameterBlock"; - } - else if( auto outMod = modifiers.findModifier() ) - { - removeModifier(modifiers, outMod); - blockWrapperTypeName = "__GLSLOutputParameterBlock"; - } - else if( auto bufferMod = modifiers.findModifier() ) - { - removeModifier(modifiers, bufferMod); - blockWrapperTypeName = "__GLSLShaderStorageBuffer"; - } - else - { - // Unknown case: just map to a constant buffer and hope for the best - blockWrapperTypeName = "ConstantBuffer"; - } + // Both declarations will have a location that points to the name + parser->FillPosition(blockDataTypeDecl.Ptr()); + parser->FillPosition(blockVarDecl.Ptr()); - // 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 blockDataTypeDecl = new StructSyntaxNode(); - RefPtr blockVarDecl = new Variable(); - - addModifier(blockDataTypeDecl, new ImplicitParameterBlockElementTypeModifier()); - addModifier(blockVarDecl, new ImplicitParameterBlockVariableModifier()); - - // Attach the reflection name to the block so we can use it - auto reflectionNameModifier = new ParameterBlockReflectionName(); - reflectionNameModifier->nameToken = reflectionNameToken; - addModifier(blockVarDecl, reflectionNameModifier); - - // Both declarations will have a location that points to the name - parser->FillPosition(blockDataTypeDecl.Ptr()); - parser->FillPosition(blockVarDecl.Ptr()); - - // Generate a unique name for the data type - blockDataTypeDecl->Name.Content = GenerateName(parser, "SLANG_ParameterBlock_" + reflectionNameToken.Content); - - // 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 blockDataTypeExpr = new VarExpressionSyntaxNode(); - blockDataTypeExpr->Position = blockDataTypeDecl->Position; - blockDataTypeExpr->Variable = blockDataTypeDecl->Name.Content; - blockDataTypeExpr->scope = parser->currentScope.Ptr(); - - // Construct a type exrpession to reference the type constructor - auto blockWrapperTypeExpr = new VarExpressionSyntaxNode(); - blockWrapperTypeExpr->Position = pos; - blockWrapperTypeExpr->Variable = blockWrapperTypeName; - // Always need to look this up in the outer scope, - // so that it won't collide with, e.g., a local variable called `ConstantBuffer` - blockWrapperTypeExpr->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 blockVarTypeExpr = new GenericAppExpr(); - blockVarTypeExpr->Position = blockVarDecl->Position; - blockVarTypeExpr->FunctionExpr = blockWrapperTypeExpr; - blockVarTypeExpr->Arguments.Add(blockDataTypeExpr); - - blockVarDecl->Type.exp = blockVarTypeExpr; - - // The declarations in the body belong to the data type. - parseAggTypeDeclBody(parser, blockDataTypeDecl.Ptr()); - - if( parser->LookAheadToken(TokenType::Identifier) ) - { - // The user gave an explicit name to the block, - // so we need to use that as our variable name - blockVarDecl->Name = parser->ReadToken(TokenType::Identifier); + // Generate a unique name for the data type + blockDataTypeDecl->Name.Content = GenerateName(parser, "SLANG_ParameterBlock_" + reflectionNameToken.Content); - // TODO: in this case we make actually have a more complex - // declarator, including `[]` brackets. - } - else - { - // synthesize a dummy name - blockVarDecl->Name.Content = GenerateName(parser, "SLANG_parameterBlock_" + reflectionNameToken.Content); - - // Otherwise we have a transparent declaration, similar - // to an HLSL `cbuffer` - auto transparentModifier = new TransparentModifier(); - transparentModifier->Position = pos; - addModifier(blockVarDecl, transparentModifier); - } + // 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. - // Expect a trailing `;` - parser->ReadToken(TokenType::Semicolon); + // Construct a type expression to reference the buffer data type + auto blockDataTypeExpr = new VarExpressionSyntaxNode(); + blockDataTypeExpr->Position = blockDataTypeDecl->Position; + blockDataTypeExpr->Variable = blockDataTypeDecl->Name.Content; + blockDataTypeExpr->scope = parser->currentScope.Ptr(); - // 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. + // Construct a type exrpession to reference the type constructor + auto blockWrapperTypeExpr = new VarExpressionSyntaxNode(); + blockWrapperTypeExpr->Position = pos; + blockWrapperTypeExpr->Variable = blockWrapperTypeName; + // Always need to look this up in the outer scope, + // so that it won't collide with, e.g., a local variable called `ConstantBuffer` + blockWrapperTypeExpr->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 blockVarTypeExpr = new GenericAppExpr(); + blockVarTypeExpr->Position = blockVarDecl->Position; + blockVarTypeExpr->FunctionExpr = blockWrapperTypeExpr; + blockVarTypeExpr->Arguments.Add(blockDataTypeExpr); - AddMember(parser->currentScope, blockDataTypeDecl); + blockVarDecl->Type.exp = blockVarTypeExpr; - return blockVarDecl; + // The declarations in the body belong to the data type. + parseAggTypeDeclBody(parser, blockDataTypeDecl.Ptr()); + + if( parser->LookAheadToken(TokenType::Identifier) ) + { + // The user gave an explicit name to the block, + // so we need to use that as our variable name + blockVarDecl->Name = parser->ReadToken(TokenType::Identifier); + + // TODO: in this case we make actually have a more complex + // declarator, including `[]` brackets. + } + else + { + // synthesize a dummy name + blockVarDecl->Name.Content = GenerateName(parser, "SLANG_parameterBlock_" + reflectionNameToken.Content); + + // Otherwise we have a transparent declaration, similar + // to an HLSL `cbuffer` + auto transparentModifier = new TransparentModifier(); + transparentModifier->Position = pos; + addModifier(blockVarDecl, transparentModifier); } + // Expect a trailing `;` + parser->ReadToken(TokenType::Semicolon); + + // 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, blockDataTypeDecl); + + return blockVarDecl; + } + - static RefPtr ParseGenericParamDecl( - Parser* parser, - RefPtr genericDecl) + static RefPtr ParseGenericParamDecl( + Parser* parser, + RefPtr genericDecl) + { + // simple syntax to introduce a value parameter + if (AdvanceIf(parser, "let")) { - // simple syntax to introduce a value parameter - if (AdvanceIf(parser, "let")) + // default case is a type parameter + auto paramDecl = new GenericValueParamDecl(); + paramDecl->Name = parser->ReadToken(TokenType::Identifier); + if (AdvanceIf(parser, TokenType::Colon)) { - // default case is a type parameter - auto paramDecl = new GenericValueParamDecl(); - paramDecl->Name = parser->ReadToken(TokenType::Identifier); - if (AdvanceIf(parser, TokenType::Colon)) - { - paramDecl->Type = parser->ParseTypeExp(); - } - if (AdvanceIf(parser, TokenType::OpAssign)) - { - paramDecl->Expr = parser->ParseInitExpr(); - } - return paramDecl; + paramDecl->Type = parser->ParseTypeExp(); } - else + if (AdvanceIf(parser, TokenType::OpAssign)) { - // default case is a type parameter - auto paramDecl = new GenericTypeParamDecl(); - parser->FillPosition(paramDecl); - paramDecl->Name = parser->ReadToken(TokenType::Identifier); - if (AdvanceIf(parser, TokenType::Colon)) - { - // The user is apply a constraint to this type parameter... + paramDecl->Expr = parser->ParseInitExpr(); + } + return paramDecl; + } + else + { + // default case is a type parameter + auto paramDecl = new GenericTypeParamDecl(); + parser->FillPosition(paramDecl); + paramDecl->Name = 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 paramConstraint = new GenericTypeConstraintDecl(); + parser->FillPosition(paramConstraint); - auto paramType = DeclRefType::Create(DeclRef(paramDecl, nullptr)); + auto paramType = DeclRefType::Create(DeclRef(paramDecl, nullptr)); - auto paramTypeExpr = new SharedTypeExpr(); - paramTypeExpr->Position = paramDecl->Position; - paramTypeExpr->base.type = paramType; - paramTypeExpr->Type = new TypeType(paramType); + auto paramTypeExpr = new SharedTypeExpr(); + paramTypeExpr->Position = paramDecl->Position; + paramTypeExpr->base.type = paramType; + paramTypeExpr->Type = new TypeType(paramType); - paramConstraint->sub = TypeExp(paramTypeExpr); - paramConstraint->sup = parser->ParseTypeExp(); + paramConstraint->sub = TypeExp(paramTypeExpr); + paramConstraint->sup = parser->ParseTypeExp(); - AddMember(genericDecl, paramConstraint); + AddMember(genericDecl, paramConstraint); - } - if (AdvanceIf(parser, TokenType::OpAssign)) - { - paramDecl->initType = parser->ParseTypeExp(); - } - return paramDecl; } + if (AdvanceIf(parser, TokenType::OpAssign)) + { + paramDecl->initType = parser->ParseTypeExp(); + } + return paramDecl; } + } - static RefPtr ParseGenericDecl( - Parser* parser) + static RefPtr ParseGenericDecl( + Parser* parser) + { + RefPtr decl = new GenericDecl(); + parser->FillPosition(decl.Ptr()); + parser->PushScope(decl.Ptr()); + parser->ReadToken("__generic"); + parser->ReadToken(TokenType::OpLess); + parser->genericDepth++; + while (!parser->LookAheadToken(TokenType::OpGreater)) { - RefPtr decl = new GenericDecl(); - parser->FillPosition(decl.Ptr()); - parser->PushScope(decl.Ptr()); - parser->ReadToken("__generic"); - parser->ReadToken(TokenType::OpLess); - parser->genericDepth++; - while (!parser->LookAheadToken(TokenType::OpGreater)) - { - AddMember(decl, ParseGenericParamDecl(parser, decl)); + AddMember(decl, ParseGenericParamDecl(parser, decl)); if( parser->LookAheadToken(TokenType::OpGreater) ) break; parser->ReadToken(TokenType::Comma); - } - parser->genericDepth--; - parser->ReadToken(TokenType::OpGreater); + } + parser->genericDepth--; + parser->ReadToken(TokenType::OpGreater); - decl->inner = ParseSingleDecl(parser, decl.Ptr()); + decl->inner = ParseSingleDecl(parser, decl.Ptr()); - // A generic decl hijacks the name of the declaration - // it wraps, so that lookup can find it. - decl->Name = decl->inner->Name; + // A generic decl hijacks the name of the declaration + // it wraps, so that lookup can find it. + decl->Name = decl->inner->Name; - parser->PopScope(); - return decl; - } + parser->PopScope(); + return decl; + } - static RefPtr ParseExtensionDecl(Parser* parser) - { - RefPtr decl = new ExtensionDecl(); - parser->FillPosition(decl.Ptr()); - parser->ReadToken("__extension"); - decl->targetType = parser->ParseTypeExp(); + static RefPtr ParseExtensionDecl(Parser* parser) + { + RefPtr decl = new ExtensionDecl(); + parser->FillPosition(decl.Ptr()); + parser->ReadToken("__extension"); + decl->targetType = parser->ParseTypeExp(); - parseAggTypeDeclBody(parser, decl.Ptr()); + parseAggTypeDeclBody(parser, decl.Ptr()); - return decl; - } + return decl; + } - static void parseOptionalInheritanceClause(Parser* parser, AggTypeDecl* decl) + static void parseOptionalInheritanceClause(Parser* parser, AggTypeDecl* decl) + { + if( AdvanceIf(parser, TokenType::Colon) ) { - if( AdvanceIf(parser, TokenType::Colon) ) + do { - do - { - auto base = parser->ParseTypeExp(); + auto base = parser->ParseTypeExp(); - auto inheritanceDecl = new InheritanceDecl(); - inheritanceDecl->Position = base.exp->Position; - inheritanceDecl->base = base; + auto inheritanceDecl = new InheritanceDecl(); + inheritanceDecl->Position = base.exp->Position; + inheritanceDecl->base = base; - AddMember(decl, inheritanceDecl); + AddMember(decl, inheritanceDecl); - } while( AdvanceIf(parser, TokenType::Comma) ); - } + } while( AdvanceIf(parser, TokenType::Comma) ); } + } - static RefPtr parseInterfaceDecl(Parser* parser) - { - RefPtr decl = new InterfaceDecl(); - parser->FillPosition(decl.Ptr()); - parser->ReadToken("interface"); - decl->Name = parser->ReadToken(TokenType::Identifier); + static RefPtr parseInterfaceDecl(Parser* parser) + { + RefPtr decl = new InterfaceDecl(); + parser->FillPosition(decl.Ptr()); + parser->ReadToken("interface"); + decl->Name = parser->ReadToken(TokenType::Identifier); - parseOptionalInheritanceClause(parser, decl.Ptr()); + parseOptionalInheritanceClause(parser, decl.Ptr()); - parseAggTypeDeclBody(parser, decl.Ptr()); + parseAggTypeDeclBody(parser, decl.Ptr()); - return decl; - } + return decl; + } - static RefPtr ParseConstructorDecl(Parser* parser) - { - RefPtr decl = new ConstructorDecl(); - parser->FillPosition(decl.Ptr()); - parser->ReadToken("__init"); + static RefPtr ParseConstructorDecl(Parser* parser) + { + RefPtr decl = new ConstructorDecl(); + parser->FillPosition(decl.Ptr()); + parser->ReadToken("__init"); - parseParameterList(parser, decl); + parseParameterList(parser, decl); - if( AdvanceIf(parser, TokenType::Semicolon) ) - { - // empty body - } - else - { - decl->Body = parser->ParseBlockStatement(); - } - return decl; + if( AdvanceIf(parser, TokenType::Semicolon) ) + { + // empty body } - - static RefPtr parseAccessorDecl(Parser* parser) + else { - RefPtr decl; - if( AdvanceIf(parser, "get") ) - { - decl = new GetterDecl(); - } - else if( AdvanceIf(parser, "set") ) - { - decl = new SetterDecl(); - } - else - { - Unexpected(parser); - return nullptr; - } - - if( parser->tokenReader.PeekTokenType() == TokenType::LBrace ) - { - decl->Body = parser->ParseBlockStatement(); - } - else - { - parser->ReadToken(TokenType::Semicolon); - } + decl->Body = parser->ParseBlockStatement(); + } + return decl; + } - return decl; + static RefPtr parseAccessorDecl(Parser* parser) + { + RefPtr decl; + if( AdvanceIf(parser, "get") ) + { + decl = new GetterDecl(); + } + else if( AdvanceIf(parser, "set") ) + { + decl = new SetterDecl(); + } + else + { + Unexpected(parser); + return nullptr; } - static RefPtr ParseSubscriptDecl(Parser* parser) + if( parser->tokenReader.PeekTokenType() == TokenType::LBrace ) + { + decl->Body = parser->ParseBlockStatement(); + } + else { - RefPtr decl = new SubscriptDecl(); - parser->FillPosition(decl.Ptr()); - parser->ReadToken("__subscript"); + parser->ReadToken(TokenType::Semicolon); + } - // TODO: the use of this name here is a bit magical... - decl->Name.Content = "operator[]"; + return decl; + } - parseParameterList(parser, decl); + static RefPtr ParseSubscriptDecl(Parser* parser) + { + RefPtr decl = new SubscriptDecl(); + parser->FillPosition(decl.Ptr()); + parser->ReadToken("__subscript"); - if( AdvanceIf(parser, TokenType::RightArrow) ) - { - decl->ReturnType = parser->ParseTypeExp(); - } + // TODO: the use of this name here is a bit magical... + decl->Name.Content = "operator[]"; - 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); + parseParameterList(parser, decl); + + if( AdvanceIf(parser, TokenType::RightArrow) ) + { + decl->ReturnType = parser->ParseTypeExp(); + } - // empty body should be treated like `{ get; }` + 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); - return decl; + // empty body should be treated like `{ get; }` } - // Parse a declaration of a new modifier keyword - static RefPtr parseModifierDecl(Parser* parser) - { - RefPtr decl = new ModifierDecl(); + return decl; + } - // read the `__modifier` keyword - parser->ReadToken(TokenType::Identifier); + // Parse a declaration of a new modifier keyword + static RefPtr parseModifierDecl(Parser* parser) + { + RefPtr decl = new ModifierDecl(); - parser->ReadToken(TokenType::LParent); - decl->classNameToken = parser->ReadToken(TokenType::Identifier); - parser->ReadToken(TokenType::RParent); + // read the `__modifier` keyword + parser->ReadToken(TokenType::Identifier); - parser->FillPosition(decl.Ptr()); - decl->Name = parser->ReadToken(TokenType::Identifier); + parser->ReadToken(TokenType::LParent); + decl->classNameToken = parser->ReadToken(TokenType::Identifier); + parser->ReadToken(TokenType::RParent); - parser->ReadToken(TokenType::Semicolon); - return decl; - } + parser->FillPosition(decl.Ptr()); + decl->Name = parser->ReadToken(TokenType::Identifier); - // Finish up work on a declaration that was parsed - static void CompleteDecl( - Parser* /*parser*/, - RefPtr decl, - ContainerDecl* containerDecl, - Modifiers modifiers) - { - // Add any modifiers we parsed before the declaration to the list - // of modifiers on the declaration itself. - AddModifiers(decl.Ptr(), modifiers.first); + parser->ReadToken(TokenType::Semicolon); + return decl; + } - // Make sure the decl is properly nested inside its lexical parent - if (containerDecl) - { - AddMember(containerDecl, decl); - } - } + // Finish up work on a declaration that was parsed + static void CompleteDecl( + Parser* /*parser*/, + RefPtr decl, + ContainerDecl* containerDecl, + Modifiers modifiers) + { + // Add any modifiers we parsed before the declaration to the list + // of modifiers on the declaration itself. + AddModifiers(decl.Ptr(), modifiers.first); - static RefPtr ParseDeclWithModifiers( - Parser* parser, - ContainerDecl* containerDecl, - Modifiers modifiers ) - { - RefPtr decl; - - auto loc = parser->tokenReader.PeekLoc(); - - // TODO: actual dispatch! - if (parser->LookAheadToken("struct")) - decl = ParseDeclaratorDecl(parser, containerDecl); - else if (parser->LookAheadToken("class")) - decl = ParseDeclaratorDecl(parser, containerDecl); - else if (parser->LookAheadToken("typedef")) - decl = ParseTypeDef(parser); - else if (parser->LookAheadToken("cbuffer") || parser->LookAheadToken("tbuffer")) - decl = ParseHLSLBufferDecl(parser); - else if (parser->LookAheadToken("__generic")) - decl = ParseGenericDecl(parser); - else if (parser->LookAheadToken("__extension")) - decl = ParseExtensionDecl(parser); - else if (parser->LookAheadToken("__init")) - decl = ParseConstructorDecl(parser); - else if (parser->LookAheadToken("__subscript")) - decl = ParseSubscriptDecl(parser); - else if (parser->LookAheadToken("interface")) - decl = parseInterfaceDecl(parser); - else if(parser->LookAheadToken("__modifier")) - decl = parseModifierDecl(parser); - else if(parser->LookAheadToken("__import")) - decl = parseImportDecl(parser); - else if (AdvanceIf(parser, TokenType::Semicolon)) - { - decl = new EmptyDecl(); - decl->Position = loc; - } - // GLSL requires that we be able to parse "block" declarations, - // which look superficially similar to declarator declarations - else if( parser->LookAheadToken(TokenType::Identifier) - && parser->LookAheadToken(TokenType::LBrace, 1) ) - { - decl = parseGLSLBlockDecl(parser, modifiers); - } - else - { - // Default case: just parse a declarator-based declaration - decl = ParseDeclaratorDecl(parser, containerDecl); - } + // Make sure the decl is properly nested inside its lexical parent + if (containerDecl) + { + AddMember(containerDecl, decl); + } + } - if (decl) - { - if( auto dd = decl.As() ) - { - CompleteDecl(parser, dd, containerDecl, modifiers); - } - else if(auto declGroup = decl.As()) - { - // 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. + static RefPtr ParseDeclWithModifiers( + Parser* parser, + ContainerDecl* containerDecl, + Modifiers modifiers ) + { + RefPtr decl; - auto sharedModifiers = new SharedModifiers(); - sharedModifiers->next = modifiers.first; - modifiers.first = sharedModifiers; + auto loc = parser->tokenReader.PeekLoc(); - for( auto subDecl : declGroup->decls ) - { - CompleteDecl(parser, subDecl, containerDecl, modifiers); - } - } - } - return decl; + // TODO: actual dispatch! + if (parser->LookAheadToken("struct")) + decl = ParseDeclaratorDecl(parser, containerDecl); + else if (parser->LookAheadToken("class")) + decl = ParseDeclaratorDecl(parser, containerDecl); + else if (parser->LookAheadToken("typedef")) + decl = ParseTypeDef(parser); + else if (parser->LookAheadToken("cbuffer") || parser->LookAheadToken("tbuffer")) + decl = ParseHLSLBufferDecl(parser); + else if (parser->LookAheadToken("__generic")) + decl = ParseGenericDecl(parser); + else if (parser->LookAheadToken("__extension")) + decl = ParseExtensionDecl(parser); + else if (parser->LookAheadToken("__init")) + decl = ParseConstructorDecl(parser); + else if (parser->LookAheadToken("__subscript")) + decl = ParseSubscriptDecl(parser); + else if (parser->LookAheadToken("interface")) + decl = parseInterfaceDecl(parser); + else if(parser->LookAheadToken("__modifier")) + decl = parseModifierDecl(parser); + else if(parser->LookAheadToken("__import")) + decl = parseImportDecl(parser); + else if (AdvanceIf(parser, TokenType::Semicolon)) + { + decl = new EmptyDecl(); + decl->Position = loc; } - - static RefPtr ParseDecl( - Parser* parser, - ContainerDecl* containerDecl) + // GLSL requires that we be able to parse "block" declarations, + // which look superficially similar to declarator declarations + else if( parser->LookAheadToken(TokenType::Identifier) + && parser->LookAheadToken(TokenType::LBrace, 1) ) + { + decl = parseGLSLBlockDecl(parser, modifiers); + } + else { - Modifiers modifiers = ParseModifiers(parser); - return ParseDeclWithModifiers(parser, containerDecl, modifiers); + // Default case: just parse a declarator-based declaration + decl = ParseDeclaratorDecl(parser, containerDecl); } - static RefPtr ParseSingleDecl( - Parser* parser, - ContainerDecl* containerDecl) + if (decl) { - auto declBase = ParseDecl(parser, containerDecl); - if(!declBase) - return nullptr; - if( auto decl = declBase.As() ) + if( auto dd = decl.As() ) { - return decl; + CompleteDecl(parser, dd, containerDecl, modifiers); } - else if( auto declGroup = declBase.As() ) + else if(auto declGroup = decl.As()) { - if( declGroup->decls.Count() == 1 ) + // 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 ) { - return declGroup->decls[0]; + CompleteDecl(parser, subDecl, containerDecl, modifiers); } } - - parser->sink->diagnose(declBase->Position, Diagnostics::unimplemented, "didn't expect multiple declarations here"); - return nullptr; } + return decl; + } + static RefPtr ParseDecl( + Parser* parser, + ContainerDecl* containerDecl) + { + Modifiers modifiers = ParseModifiers(parser); + return ParseDeclWithModifiers(parser, containerDecl, modifiers); + } - // Parse a body consisting of declarations - static void ParseDeclBody( - Parser* parser, - ContainerDecl* containerDecl, - TokenType closingToken) + static RefPtr ParseSingleDecl( + Parser* parser, + ContainerDecl* containerDecl) + { + auto declBase = ParseDecl(parser, containerDecl); + if(!declBase) + return nullptr; + if( auto decl = declBase.As() ) { - while(!AdvanceIfMatch(parser, closingToken)) + return decl; + } + else if( auto declGroup = declBase.As() ) + { + if( declGroup->decls.Count() == 1 ) { - ParseDecl(parser, containerDecl); - TryRecover(parser); + return declGroup->decls[0]; } } - // 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->sink->diagnose(declBase->Position, Diagnostics::unimplemented, "didn't expect multiple declarations here"); + return nullptr; + } - parser->ReadToken(TokenType::LBrace); - ParseDeclBody(parser, decl, TokenType::RBrace); - parser->PopScope(); + // Parse a body consisting of declarations + static void ParseDeclBody( + Parser* parser, + ContainerDecl* containerDecl, + TokenType closingToken) + { + while(!AdvanceIfMatch(parser, closingToken)) + { + ParseDecl(parser, containerDecl); + TryRecover(parser); } + } + // 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); - void Parser::parseSourceFile(ProgramSyntaxNode* program) - { - if (outerScope) - { - currentScope = outerScope; - } + parser->ReadToken(TokenType::LBrace); + ParseDeclBody(parser, decl, TokenType::RBrace); - PushScope(program); - program->Position = CodePosition(0, 0, 0, fileName); - ParseDeclBody(this, program, TokenType::EndOfFile); - PopScope(); + parser->PopScope(); + } - assert(currentScope == outerScope); - currentScope = nullptr; - } - RefPtr Parser::ParseProgram() + void Parser::parseSourceFile(ProgramSyntaxNode* program) + { + if (outerScope) { - RefPtr program = new ProgramSyntaxNode(); - - parseSourceFile(program.Ptr()); - - return program; + currentScope = outerScope; } - RefPtr Parser::ParseStruct() - { - RefPtr rs = new StructSyntaxNode(); - FillPosition(rs.Ptr()); - ReadToken("struct"); - - // TODO: support `struct` declaration without tag - rs->Name = ReadToken(TokenType::Identifier); - - // We allow for an inheritance clause on a `struct` - // so that it can conform to interfaces. - parseOptionalInheritanceClause(this, rs.Ptr()); + PushScope(program); + program->Position = CodePosition(0, 0, 0, fileName); + ParseDeclBody(this, program, TokenType::EndOfFile); + PopScope(); - parseAggTypeDeclBody(this, rs.Ptr()); - - return rs; - } + assert(currentScope == outerScope); + currentScope = nullptr; + } - RefPtr Parser::ParseClass() - { - RefPtr rs = new ClassSyntaxNode(); - FillPosition(rs.Ptr()); - ReadToken("class"); - rs->Name = ReadToken(TokenType::Identifier); - ReadToken(TokenType::LBrace); - parseOptionalInheritanceClause(this, rs.Ptr()); - parseAggTypeDeclBody(this, rs.Ptr()); - return rs; - } + RefPtr Parser::ParseProgram() + { + RefPtr program = new ProgramSyntaxNode(); - static RefPtr ParseSwitchStmt(Parser* parser) - { - RefPtr 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; - } + parseSourceFile(program.Ptr()); - static RefPtr ParseCaseStmt(Parser* parser) - { - RefPtr stmt = new CaseStmt(); - parser->FillPosition(stmt.Ptr()); - parser->ReadToken("case"); - stmt->expr = parser->ParseExpression(); - parser->ReadToken(TokenType::Colon); - return stmt; - } + return program; + } - static RefPtr ParseDefaultStmt(Parser* parser) - { - RefPtr stmt = new DefaultStmt(); - parser->FillPosition(stmt.Ptr()); - parser->ReadToken("default"); - parser->ReadToken(TokenType::Colon); - return stmt; - } + RefPtr Parser::ParseStruct() + { + RefPtr rs = new StructSyntaxNode(); + FillPosition(rs.Ptr()); + ReadToken("struct"); - static bool peekTypeName(Parser* parser) - { - if(!parser->LookAheadToken(TokenType::Identifier)) - return false; + // TODO: support `struct` declaration without tag + rs->Name = ReadToken(TokenType::Identifier); - auto name = parser->tokenReader.PeekToken().Content; + // We allow for an inheritance clause on a `struct` + // so that it can conform to interfaces. + parseOptionalInheritanceClause(this, rs.Ptr()); - auto lookupResult = LookUp(name, parser->currentScope); - if(!lookupResult.isValid() || lookupResult.isOverloaded()) - return false; + parseAggTypeDeclBody(this, rs.Ptr()); - auto decl = lookupResult.item.declRef.GetDecl(); - if( auto typeDecl = dynamic_cast(decl) ) - { - return true; - } - else if( auto typeVarDecl = dynamic_cast(decl) ) - { - return true; - } - else - { - return false; - } - } + return rs; + } - RefPtr Parser::ParseStatement() - { - auto modifiers = ParseModifiers(this); + RefPtr Parser::ParseClass() + { + RefPtr rs = new ClassSyntaxNode(); + FillPosition(rs.Ptr()); + ReadToken("class"); + rs->Name = ReadToken(TokenType::Identifier); + ReadToken(TokenType::LBrace); + parseOptionalInheritanceClause(this, rs.Ptr()); + parseAggTypeDeclBody(this, rs.Ptr()); + return rs; + } - RefPtr 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 DiscardStatementSyntaxNode(); - 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::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. + static RefPtr ParseSwitchStmt(Parser* parser) + { + RefPtr 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; + } - Token* startPos = tokenReader.mCursor; + static RefPtr ParseCaseStmt(Parser* parser) + { + RefPtr stmt = new CaseStmt(); + parser->FillPosition(stmt.Ptr()); + parser->ReadToken("case"); + stmt->expr = parser->ParseExpression(); + parser->ReadToken(TokenType::Colon); + return stmt; + } - // Try to parse a type (knowing that the type grammar is - // a subset of the expression grammar, and so this should - // always succeed). - RefPtr type = ParseType(); - // We don't actually care about the type, though, so - // don't retain it - type = nullptr; + static RefPtr ParseDefaultStmt(Parser* parser) + { + RefPtr stmt = new DefaultStmt(); + parser->FillPosition(stmt.Ptr()); + parser->ReadToken("default"); + parser->ReadToken(TokenType::Colon); + return stmt; + } - // 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.mCursor = startPos; - statement = ParseVarDeclrStatement(modifiers); - return statement; - } + static bool peekTypeName(Parser* parser) + { + if(!parser->LookAheadToken(TokenType::Identifier)) + return false; - // Fallback: reset and parse an expression - tokenReader.mCursor = startPos; - statement = ParseExpressionStatement(); - } - else if (LookAheadToken(TokenType::Semicolon)) - { - statement = new EmptyStatementSyntaxNode(); - 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(); - } + auto name = parser->tokenReader.PeekToken().Content; - if (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; - } + auto lookupResult = LookUp(name, parser->currentScope); + if(!lookupResult.isValid() || lookupResult.isOverloaded()) + return false; - return statement; + auto decl = lookupResult.item.declRef.GetDecl(); + if( auto typeDecl = dynamic_cast(decl) ) + { + return true; } - - RefPtr Parser::ParseBlockStatement() + else if( auto typeVarDecl = dynamic_cast(decl) ) { - if( options.flags & SLANG_COMPILE_FLAG_NO_CHECKING ) - { - // We have been asked to parse the input, but not attempt to understand it. + return true; + } + else + { + return false; + } + } - // TODO: record start/end locations... + RefPtr Parser::ParseStatement() + { + auto modifiers = ParseModifiers(this); + + RefPtr 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 DiscardStatementSyntaxNode(); + 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::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. - List tokens; + Token* startPos = tokenReader.mCursor; - ReadToken(TokenType::LBrace); + // Try to parse a type (knowing that the type grammar is + // a subset of the expression grammar, and so this should + // always succeed). + RefPtr type = ParseType(); + // We don't actually care about the type, though, so + // don't retain it + type = nullptr; - int depth = 1; - for( ;;) - { - switch( tokenReader.PeekTokenType() ) - { - case TokenType::EndOfFile: - goto done; + // 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.mCursor = startPos; + statement = ParseVarDeclrStatement(modifiers); + return statement; + } - case TokenType::RBrace: - depth--; - if(depth == 0) - goto done; - break; + // Fallback: reset and parse an expression + tokenReader.mCursor = startPos; + statement = ParseExpressionStatement(); + } + else if (LookAheadToken(TokenType::Semicolon)) + { + statement = new EmptyStatementSyntaxNode(); + 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(); + } - case TokenType::LBrace: - depth++; - break; + if (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; + } - default: - break; - } + return statement; + } - auto token = tokenReader.AdvanceToken(); - tokens.Add(token); - } - done: - ReadToken(TokenType::RBrace); + RefPtr Parser::ParseBlockStatement() + { + if( options.flags & SLANG_COMPILE_FLAG_NO_CHECKING ) + { + // We have been asked to parse the input, but not attempt to understand it. - RefPtr unparsedStmt = new UnparsedStmt(); - unparsedStmt->tokens = tokens; - return unparsedStmt; - } + // TODO: record start/end locations... + List tokens; - RefPtr scopeDecl = new ScopeDecl(); - RefPtr blockStatement = new BlockStatementSyntaxNode(); - blockStatement->scopeDecl = scopeDecl; - PushScope(scopeDecl.Ptr()); ReadToken(TokenType::LBrace); - if(!tokenReader.IsAtEnd()) - { - FillPosition(blockStatement.Ptr()); - } - while (!AdvanceIfMatch(this, TokenType::RBrace)) + + int depth = 1; + for( ;;) { - auto stmt = ParseStatement(); - if(stmt) + switch( tokenReader.PeekTokenType() ) { - blockStatement->Statements.Add(stmt); + case TokenType::EndOfFile: + goto done; + + case TokenType::RBrace: + depth--; + if(depth == 0) + goto done; + break; + + case TokenType::LBrace: + depth++; + break; + + default: + break; } - TryRecover(this); + + auto token = tokenReader.AdvanceToken(); + tokens.Add(token); } - PopScope(); - return blockStatement; + done: + ReadToken(TokenType::RBrace); + + RefPtr unparsedStmt = new UnparsedStmt(); + unparsedStmt->tokens = tokens; + return unparsedStmt; } - RefPtr Parser::ParseVarDeclrStatement( - Modifiers modifiers) + + RefPtr scopeDecl = new ScopeDecl(); + RefPtr blockStatement = new BlockStatementSyntaxNode(); + blockStatement->scopeDecl = scopeDecl; + PushScope(scopeDecl.Ptr()); + ReadToken(TokenType::LBrace); + if(!tokenReader.IsAtEnd()) { - RefPtrvarDeclrStatement = new VarDeclrStatementSyntaxNode(); - - FillPosition(varDeclrStatement.Ptr()); - auto decl = ParseDeclWithModifiers(this, currentScope->containerDecl, modifiers); - varDeclrStatement->decl = decl; - return varDeclrStatement; + FillPosition(blockStatement.Ptr()); } - - RefPtr Parser::ParseIfStatement() + while (!AdvanceIfMatch(this, TokenType::RBrace)) { - RefPtr ifStatement = new IfStatementSyntaxNode(); - FillPosition(ifStatement.Ptr()); - ReadToken("if"); - ReadToken(TokenType::LParent); - ifStatement->Predicate = ParseExpression(); - ReadToken(TokenType::RParent); - ifStatement->PositiveStatement = ParseStatement(); - if (LookAheadToken("else")) + auto stmt = ParseStatement(); + if(stmt) { - ReadToken("else"); - ifStatement->NegativeStatement = ParseStatement(); + blockStatement->Statements.Add(stmt); } - return ifStatement; + TryRecover(this); } + PopScope(); + return blockStatement; + } - RefPtr Parser::ParseForStatement() - { - RefPtr scopeDecl = new ScopeDecl(); - RefPtr stmt = new ForStatementSyntaxNode(); - stmt->scopeDecl = scopeDecl; + RefPtr Parser::ParseVarDeclrStatement( + Modifiers modifiers) + { + RefPtrvarDeclrStatement = new VarDeclrStatementSyntaxNode(); + + FillPosition(varDeclrStatement.Ptr()); + auto decl = ParseDeclWithModifiers(this, currentScope->containerDecl, modifiers); + varDeclrStatement->decl = decl; + return varDeclrStatement; + } - // Note(tfoley): HLSL implements `for` with incorrect scoping. - // We need an option to turn on this behavior in a kind of "legacy" mode + RefPtr Parser::ParseIfStatement() + { + RefPtr ifStatement = new IfStatementSyntaxNode(); + 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 Parser::ParseForStatement() + { + RefPtr scopeDecl = new ScopeDecl(); + RefPtr stmt = new ForStatementSyntaxNode(); + stmt->scopeDecl = scopeDecl; + + // Note(tfoley): HLSL implements `for` with incorrect scoping. + // We need an option to turn on this behavior in a kind of "legacy" mode // PushScope(scopeDecl.Ptr()); - FillPosition(stmt.Ptr()); - ReadToken("for"); - ReadToken(TokenType::LParent); - if (peekTypeName(this)) + FillPosition(stmt.Ptr()); + ReadToken("for"); + ReadToken(TokenType::LParent); + if (peekTypeName(this)) + { + stmt->InitialStatement = ParseVarDeclrStatement(Modifiers()); + } + else + { + if (!LookAheadToken(TokenType::Semicolon)) { - stmt->InitialStatement = ParseVarDeclrStatement(Modifiers()); + stmt->InitialStatement = ParseExpressionStatement(); } else { - if (!LookAheadToken(TokenType::Semicolon)) - { - stmt->InitialStatement = ParseExpressionStatement(); - } - else - { - ReadToken(TokenType::Semicolon); - } + 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(); -// PopScope(); - return stmt; } + if (!LookAheadToken(TokenType::Semicolon)) + stmt->PredicateExpression = ParseExpression(); + ReadToken(TokenType::Semicolon); + if (!LookAheadToken(TokenType::RParent)) + stmt->SideEffectExpression = ParseExpression(); + ReadToken(TokenType::RParent); + stmt->Statement = ParseStatement(); +// PopScope(); + return stmt; + } - RefPtr Parser::ParseWhileStatement() - { - RefPtr whileStatement = new WhileStatementSyntaxNode(); - FillPosition(whileStatement.Ptr()); - ReadToken("while"); - ReadToken(TokenType::LParent); - whileStatement->Predicate = ParseExpression(); - ReadToken(TokenType::RParent); - whileStatement->Statement = ParseStatement(); - return whileStatement; - } + RefPtr Parser::ParseWhileStatement() + { + RefPtr whileStatement = new WhileStatementSyntaxNode(); + FillPosition(whileStatement.Ptr()); + ReadToken("while"); + ReadToken(TokenType::LParent); + whileStatement->Predicate = ParseExpression(); + ReadToken(TokenType::RParent); + whileStatement->Statement = ParseStatement(); + return whileStatement; + } - RefPtr Parser::ParseDoWhileStatement() - { - RefPtr doWhileStatement = new DoWhileStatementSyntaxNode(); - 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 Parser::ParseDoWhileStatement() + { + RefPtr doWhileStatement = new DoWhileStatementSyntaxNode(); + 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 Parser::ParseBreakStatement() - { - RefPtr breakStatement = new BreakStatementSyntaxNode(); - FillPosition(breakStatement.Ptr()); - ReadToken("break"); - ReadToken(TokenType::Semicolon); - return breakStatement; - } + RefPtr Parser::ParseBreakStatement() + { + RefPtr breakStatement = new BreakStatementSyntaxNode(); + FillPosition(breakStatement.Ptr()); + ReadToken("break"); + ReadToken(TokenType::Semicolon); + return breakStatement; + } - RefPtr Parser::ParseContinueStatement() - { - RefPtr continueStatement = new ContinueStatementSyntaxNode(); - FillPosition(continueStatement.Ptr()); - ReadToken("continue"); - ReadToken(TokenType::Semicolon); - return continueStatement; - } + RefPtr Parser::ParseContinueStatement() + { + RefPtr continueStatement = new ContinueStatementSyntaxNode(); + FillPosition(continueStatement.Ptr()); + ReadToken("continue"); + ReadToken(TokenType::Semicolon); + return continueStatement; + } - RefPtr Parser::ParseReturnStatement() - { - RefPtr returnStatement = new ReturnStatementSyntaxNode(); - FillPosition(returnStatement.Ptr()); - ReadToken("return"); - if (!LookAheadToken(TokenType::Semicolon)) - returnStatement->Expression = ParseExpression(); - ReadToken(TokenType::Semicolon); - return returnStatement; - } + RefPtr Parser::ParseReturnStatement() + { + RefPtr returnStatement = new ReturnStatementSyntaxNode(); + FillPosition(returnStatement.Ptr()); + ReadToken("return"); + if (!LookAheadToken(TokenType::Semicolon)) + returnStatement->Expression = ParseExpression(); + ReadToken(TokenType::Semicolon); + return returnStatement; + } - RefPtr Parser::ParseExpressionStatement() - { - RefPtr statement = new ExpressionStatementSyntaxNode(); + RefPtr Parser::ParseExpressionStatement() + { + RefPtr statement = new ExpressionStatementSyntaxNode(); - FillPosition(statement.Ptr()); - statement->Expression = ParseExpression(); + FillPosition(statement.Ptr()); + statement->Expression = ParseExpression(); - ReadToken(TokenType::Semicolon); - return statement; - } + ReadToken(TokenType::Semicolon); + return statement; + } - RefPtr Parser::ParseParameter() - { - RefPtr parameter = new ParameterSyntaxNode(); - parameter->modifiers = ParseModifiers(this); + RefPtr Parser::ParseParameter() + { + RefPtr parameter = new ParameterSyntaxNode(); + parameter->modifiers = ParseModifiers(this); - DeclaratorInfo declaratorInfo; - declaratorInfo.typeSpec = ParseType(); + DeclaratorInfo declaratorInfo; + declaratorInfo.typeSpec = ParseType(); - InitDeclarator initDeclarator = ParseInitDeclarator(this); - UnwrapDeclarator(initDeclarator, &declaratorInfo); + InitDeclarator initDeclarator = ParseInitDeclarator(this); + UnwrapDeclarator(initDeclarator, &declaratorInfo); - // Assume it is a variable-like declarator - CompleteVarDecl(this, parameter, declaratorInfo); - return parameter; - } + // Assume it is a variable-like declarator + CompleteVarDecl(this, parameter, declaratorInfo); + return parameter; + } - RefPtr Parser::ParseType() + RefPtr Parser::ParseType() + { + auto typeSpec = parseTypeSpec(this); + if( typeSpec.decl ) { - auto typeSpec = parseTypeSpec(this); - if( typeSpec.decl ) - { - AddMember(currentScope, typeSpec.decl); - } - auto typeExpr = typeSpec.expr; + AddMember(currentScope, typeSpec.decl); + } + auto typeExpr = typeSpec.expr; - while (LookAheadToken(TokenType::LBracket)) + while (LookAheadToken(TokenType::LBracket)) + { + RefPtr arrType = new IndexExpressionSyntaxNode(); + arrType->Position = typeExpr->Position; + arrType->BaseExpression = typeExpr; + ReadToken(TokenType::LBracket); + if (!LookAheadToken(TokenType::RBracket)) { - RefPtr arrType = new IndexExpressionSyntaxNode(); - arrType->Position = typeExpr->Position; - arrType->BaseExpression = typeExpr; - ReadToken(TokenType::LBracket); - if (!LookAheadToken(TokenType::RBracket)) - { - arrType->IndexExpression = ParseExpression(); - } - ReadToken(TokenType::RBracket); - typeExpr = arrType; + arrType->IndexExpression = ParseExpression(); } - - return typeExpr; + ReadToken(TokenType::RBracket); + typeExpr = arrType; } + return typeExpr; + } - TypeExp Parser::ParseTypeExp() - { - return TypeExp(ParseType()); - } - enum class Associativity - { - Left, Right - }; + 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; - } + 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::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; - 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; - 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; - } + + Precedence GetOpLevel(Parser* parser, TokenType type) + { + switch(type) + { + 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; + 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; + 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; } + } - Operator GetOpFromToken(Token & token) - { - switch(token.Type) - { - case TokenType::Comma: - return Operator::Sequence; - case TokenType::OpAssign: - return Operator::Assign; - case TokenType::OpAddAssign: - return Operator::AddAssign; - case TokenType::OpSubAssign: - return Operator::SubAssign; - case TokenType::OpMulAssign: - return Operator::MulAssign; - case TokenType::OpDivAssign: - return Operator::DivAssign; - case TokenType::OpModAssign: - return Operator::ModAssign; - case TokenType::OpShlAssign: - return Operator::LshAssign; - case TokenType::OpShrAssign: - return Operator::RshAssign; - case TokenType::OpOrAssign: - return Operator::OrAssign; - case TokenType::OpAndAssign: - return Operator::AddAssign; - case TokenType::OpXorAssign: - return Operator::XorAssign; - case TokenType::OpOr: - return Operator::Or; - case TokenType::OpAnd: - return Operator::And; - case TokenType::OpBitOr: - return Operator::BitOr; - case TokenType::OpBitXor: - return Operator::BitXor; - case TokenType::OpBitAnd: - return Operator::BitAnd; - case TokenType::OpEql: - return Operator::Eql; - case TokenType::OpNeq: - return Operator::Neq; - case TokenType::OpGeq: - return Operator::Geq; - case TokenType::OpLeq: - return Operator::Leq; - case TokenType::OpGreater: - return Operator::Greater; - case TokenType::OpLess: - return Operator::Less; - case TokenType::OpLsh: - return Operator::Lsh; - case TokenType::OpRsh: - return Operator::Rsh; - case TokenType::OpAdd: - return Operator::Add; - case TokenType::OpSub: - return Operator::Sub; - case TokenType::OpMul: - return Operator::Mul; - case TokenType::OpDiv: - return Operator::Div; - case TokenType::OpMod: - return Operator::Mod; - case TokenType::OpInc: - return Operator::PostInc; - case TokenType::OpDec: - return Operator::PostDec; - case TokenType::OpNot: - return Operator::Not; - case TokenType::OpBitNot: - return Operator::BitNot; - default: - throw "Illegal TokenType."; - } + Operator GetOpFromToken(Token & token) + { + switch(token.Type) + { + case TokenType::Comma: + return Operator::Sequence; + case TokenType::OpAssign: + return Operator::Assign; + case TokenType::OpAddAssign: + return Operator::AddAssign; + case TokenType::OpSubAssign: + return Operator::SubAssign; + case TokenType::OpMulAssign: + return Operator::MulAssign; + case TokenType::OpDivAssign: + return Operator::DivAssign; + case TokenType::OpModAssign: + return Operator::ModAssign; + case TokenType::OpShlAssign: + return Operator::LshAssign; + case TokenType::OpShrAssign: + return Operator::RshAssign; + case TokenType::OpOrAssign: + return Operator::OrAssign; + case TokenType::OpAndAssign: + return Operator::AddAssign; + case TokenType::OpXorAssign: + return Operator::XorAssign; + case TokenType::OpOr: + return Operator::Or; + case TokenType::OpAnd: + return Operator::And; + case TokenType::OpBitOr: + return Operator::BitOr; + case TokenType::OpBitXor: + return Operator::BitXor; + case TokenType::OpBitAnd: + return Operator::BitAnd; + case TokenType::OpEql: + return Operator::Eql; + case TokenType::OpNeq: + return Operator::Neq; + case TokenType::OpGeq: + return Operator::Geq; + case TokenType::OpLeq: + return Operator::Leq; + case TokenType::OpGreater: + return Operator::Greater; + case TokenType::OpLess: + return Operator::Less; + case TokenType::OpLsh: + return Operator::Lsh; + case TokenType::OpRsh: + return Operator::Rsh; + case TokenType::OpAdd: + return Operator::Add; + case TokenType::OpSub: + return Operator::Sub; + case TokenType::OpMul: + return Operator::Mul; + case TokenType::OpDiv: + return Operator::Div; + case TokenType::OpMod: + return Operator::Mod; + case TokenType::OpInc: + return Operator::PostInc; + case TokenType::OpDec: + return Operator::PostDec; + case TokenType::OpNot: + return Operator::Not; + case TokenType::OpBitNot: + return Operator::BitNot; + default: + throw "Illegal TokenType."; } + } - static RefPtr parseOperator(Parser* parser) + static RefPtr parseOperator(Parser* parser) + { + Token opToken; + switch(parser->tokenReader.PeekTokenType()) { - Token opToken; - switch(parser->tokenReader.PeekTokenType()) - { - case TokenType::QuestionMark: - opToken = parser->ReadToken(); - opToken.Content = "?:"; - break; + case TokenType::QuestionMark: + opToken = parser->ReadToken(); + opToken.Content = "?:"; + break; - default: - opToken = parser->ReadToken(); - break; - } + default: + opToken = parser->ReadToken(); + break; + } - auto opExpr = new VarExpressionSyntaxNode(); - opExpr->Variable = opToken.Content; - opExpr->scope = parser->currentScope; - opExpr->Position = opToken.Position; + auto opExpr = new VarExpressionSyntaxNode(); + opExpr->Variable = opToken.Content; + opExpr->scope = parser->currentScope; + opExpr->Position = opToken.Position; - return opExpr; + return opExpr; - } + } - RefPtr Parser::ParseExpression(Precedence level) + RefPtr Parser::ParseExpression(Precedence level) + { + if (level == Precedence::Prefix) + return ParseLeafExpression(); + if (level == Precedence::TernaryConditional) { - if (level == Precedence::Prefix) - return ParseLeafExpression(); - if (level == Precedence::TernaryConditional) + // parse select clause + auto condition = ParseExpression(Precedence(level + 1)); + if (LookAheadToken(TokenType::QuestionMark)) { - // parse select clause - auto condition = ParseExpression(Precedence(level + 1)); - if (LookAheadToken(TokenType::QuestionMark)) - { - RefPtr select = new SelectExpressionSyntaxNode(); - FillPosition(select.Ptr()); + RefPtr select = new SelectExpressionSyntaxNode(); + FillPosition(select.Ptr()); - select->Arguments.Add(condition); + select->Arguments.Add(condition); - select->FunctionExpr = parseOperator(this); + select->FunctionExpr = parseOperator(this); - select->Arguments.Add(ParseExpression(level)); - ReadToken(TokenType::Colon); - select->Arguments.Add(ParseExpression(level)); - return select; - } - else - return condition; + select->Arguments.Add(ParseExpression(level)); + ReadToken(TokenType::Colon); + select->Arguments.Add(ParseExpression(level)); + return select; } else + return condition; + } + else + { + if (GetAssociativityFromLevel(level) == Associativity::Left) { - if (GetAssociativityFromLevel(level) == Associativity::Left) + auto left = ParseExpression(Precedence(level + 1)); + while (GetOpLevel(this, tokenReader.PeekTokenType()) == level) { - auto left = ParseExpression(Precedence(level + 1)); - while (GetOpLevel(this, tokenReader.PeekTokenType()) == level) - { - RefPtr tmp = new InfixExpr(); - tmp->FunctionExpr = parseOperator(this); + RefPtr 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; + tmp->Arguments.Add(left); + FillPosition(tmp.Ptr()); + tmp->Arguments.Add(ParseExpression(Precedence(level + 1))); + left = tmp; } - else + return left; + } + else + { + auto left = ParseExpression(Precedence(level + 1)); + if (GetOpLevel(this, tokenReader.PeekTokenType()) == level) { - auto left = ParseExpression(Precedence(level + 1)); - if (GetOpLevel(this, tokenReader.PeekTokenType()) == level) - { - RefPtr tmp = new InfixExpr(); - tmp->Arguments.Add(left); - FillPosition(tmp.Ptr()); - tmp->FunctionExpr = parseOperator(this); - tmp->Arguments.Add(ParseExpression(level)); - left = tmp; - } - return left; + RefPtr tmp = new InfixExpr(); + tmp->Arguments.Add(left); + FillPosition(tmp.Ptr()); + tmp->FunctionExpr = parseOperator(this); + tmp->Arguments.Add(ParseExpression(level)); + left = tmp; } + return left; } } + } + + RefPtr Parser::ParseLeafExpression() + { + RefPtr rs; + if (LookAheadToken(TokenType::OpInc) || + LookAheadToken(TokenType::OpDec) || + LookAheadToken(TokenType::OpNot) || + LookAheadToken(TokenType::OpBitNot) || + LookAheadToken(TokenType::OpSub)) + { + RefPtr unaryExpr = new PrefixExpr(); + FillPosition(unaryExpr.Ptr()); + unaryExpr->FunctionExpr = parseOperator(this); + unaryExpr->Arguments.Add(ParseLeafExpression()); + rs = unaryExpr; + return rs; + } - RefPtr Parser::ParseLeafExpression() + if (LookAheadToken(TokenType::LParent)) { - RefPtr rs; - if (LookAheadToken(TokenType::OpInc) || - LookAheadToken(TokenType::OpDec) || - LookAheadToken(TokenType::OpNot) || - LookAheadToken(TokenType::OpBitNot) || - LookAheadToken(TokenType::OpSub)) + ReadToken(TokenType::LParent); + RefPtr expr; + if (peekTypeName(this) && LookAheadToken(TokenType::RParent, 1)) { - RefPtr unaryExpr = new PrefixExpr(); - FillPosition(unaryExpr.Ptr()); - unaryExpr->FunctionExpr = parseOperator(this); - unaryExpr->Arguments.Add(ParseLeafExpression()); - rs = unaryExpr; - return rs; + RefPtr tcexpr = new TypeCastExpressionSyntaxNode(); + FillPosition(tcexpr.Ptr()); + tcexpr->TargetType = ParseTypeExp(); + ReadToken(TokenType::RParent); + tcexpr->Expression = ParseExpression(Precedence::Multiplicative); // Note(tfoley): need to double-check this + expr = tcexpr; } - - if (LookAheadToken(TokenType::LParent)) + else { - ReadToken(TokenType::LParent); - RefPtr expr; - if (peekTypeName(this) && LookAheadToken(TokenType::RParent, 1)) - { - RefPtr tcexpr = new TypeCastExpressionSyntaxNode(); - FillPosition(tcexpr.Ptr()); - tcexpr->TargetType = ParseTypeExp(); - ReadToken(TokenType::RParent); - tcexpr->Expression = ParseExpression(Precedence::Multiplicative); // Note(tfoley): need to double-check this - expr = tcexpr; - } - else - { - expr = ParseExpression(); - ReadToken(TokenType::RParent); - } - rs = expr; + expr = ParseExpression(); + ReadToken(TokenType::RParent); } - else if( LookAheadToken(TokenType::LBrace) ) - { - RefPtr initExpr = new InitializerListExpr(); - FillPosition(initExpr.Ptr()); + rs = expr; + } + else if( LookAheadToken(TokenType::LBrace) ) + { + RefPtr initExpr = new InitializerListExpr(); + FillPosition(initExpr.Ptr()); + + // Initializer list + ReadToken(TokenType::LBrace); - // Initializer list - ReadToken(TokenType::LBrace); + List> exprs; - List> exprs; + for(;;) + { + if(AdvanceIfMatch(this, TokenType::RBrace)) + break; - for(;;) + auto expr = ParseArgExpr(); + if( expr ) { - if(AdvanceIfMatch(this, TokenType::RBrace)) - break; + initExpr->args.Add(expr); + } - auto expr = ParseArgExpr(); - if( expr ) - { - initExpr->args.Add(expr); - } + if(AdvanceIfMatch(this, TokenType::RBrace)) + break; - if(AdvanceIfMatch(this, TokenType::RBrace)) - break; + ReadToken(TokenType::Comma); + } + rs = initExpr; + } - ReadToken(TokenType::Comma); - } - rs = initExpr; + else if (LookAheadToken(TokenType::IntLiterial) || + LookAheadToken(TokenType::DoubleLiterial)) + { + RefPtr constExpr = new ConstantExpressionSyntaxNode(); + auto token = tokenReader.AdvanceToken(); + FillPosition(constExpr.Ptr()); + if (token.Type == TokenType::IntLiterial) + { + constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Int; + constExpr->IntValue = StringToInt(token.Content); } + else if (token.Type == TokenType::DoubleLiterial) + { + constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Float; + constExpr->FloatValue = (FloatingPointLiteralValue) StringToDouble(token.Content); + } + rs = constExpr; + } + else if (LookAheadToken("true") || LookAheadToken("false")) + { + RefPtr constExpr = new ConstantExpressionSyntaxNode(); + auto token = tokenReader.AdvanceToken(); + FillPosition(constExpr.Ptr()); + constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Bool; + constExpr->IntValue = token.Content == "true" ? 1 : 0; + rs = constExpr; + } + else if (LookAheadToken(TokenType::Identifier)) + { + RefPtr varExpr = new VarExpressionSyntaxNode(); + varExpr->scope = currentScope.Ptr(); + FillPosition(varExpr.Ptr()); + auto token = ReadToken(TokenType::Identifier); + varExpr->Variable = token.Content; + rs = varExpr; + } - else if (LookAheadToken(TokenType::IntLiterial) || - LookAheadToken(TokenType::DoubleLiterial)) + while (!tokenReader.IsAtEnd() && + (LookAheadToken(TokenType::OpInc) || + LookAheadToken(TokenType::OpDec) || + LookAheadToken(TokenType::Dot) || + LookAheadToken(TokenType::LBracket) || + LookAheadToken(TokenType::LParent))) + { + if (LookAheadToken(TokenType::OpInc)) { - RefPtr constExpr = new ConstantExpressionSyntaxNode(); - auto token = tokenReader.AdvanceToken(); - FillPosition(constExpr.Ptr()); - if (token.Type == TokenType::IntLiterial) - { - constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Int; - constExpr->IntValue = StringToInt(token.Content); - } - else if (token.Type == TokenType::DoubleLiterial) - { - constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Float; - constExpr->FloatValue = (FloatingPointLiteralValue) StringToDouble(token.Content); - } - rs = constExpr; + RefPtr unaryExpr = new PostfixExpr(); + FillPosition(unaryExpr.Ptr()); + unaryExpr->FunctionExpr = parseOperator(this); + unaryExpr->Arguments.Add(rs); + rs = unaryExpr; } - else if (LookAheadToken("true") || LookAheadToken("false")) + else if (LookAheadToken(TokenType::OpDec)) { - RefPtr constExpr = new ConstantExpressionSyntaxNode(); - auto token = tokenReader.AdvanceToken(); - FillPosition(constExpr.Ptr()); - constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Bool; - constExpr->IntValue = token.Content == "true" ? 1 : 0; - rs = constExpr; + RefPtr unaryExpr = new PostfixExpr(); + FillPosition(unaryExpr.Ptr()); + unaryExpr->FunctionExpr = parseOperator(this); + unaryExpr->Arguments.Add(rs); + rs = unaryExpr; } - else if (LookAheadToken(TokenType::Identifier)) + else if (LookAheadToken(TokenType::LBracket)) { - RefPtr varExpr = new VarExpressionSyntaxNode(); - varExpr->scope = currentScope.Ptr(); - FillPosition(varExpr.Ptr()); - auto token = ReadToken(TokenType::Identifier); - varExpr->Variable = token.Content; - rs = varExpr; + RefPtr indexExpr = new IndexExpressionSyntaxNode(); + indexExpr->BaseExpression = rs; + FillPosition(indexExpr.Ptr()); + ReadToken(TokenType::LBracket); + indexExpr->IndexExpression = ParseExpression(); + ReadToken(TokenType::RBracket); + rs = indexExpr; } - - while (!tokenReader.IsAtEnd() && - (LookAheadToken(TokenType::OpInc) || - LookAheadToken(TokenType::OpDec) || - LookAheadToken(TokenType::Dot) || - LookAheadToken(TokenType::LBracket) || - LookAheadToken(TokenType::LParent))) + else if (LookAheadToken(TokenType::LParent)) { - if (LookAheadToken(TokenType::OpInc)) - { - RefPtr unaryExpr = new PostfixExpr(); - FillPosition(unaryExpr.Ptr()); - unaryExpr->FunctionExpr = parseOperator(this); - unaryExpr->Arguments.Add(rs); - rs = unaryExpr; - } - else if (LookAheadToken(TokenType::OpDec)) - { - RefPtr unaryExpr = new PostfixExpr(); - FillPosition(unaryExpr.Ptr()); - unaryExpr->FunctionExpr = parseOperator(this); - unaryExpr->Arguments.Add(rs); - rs = unaryExpr; - } - else if (LookAheadToken(TokenType::LBracket)) - { - RefPtr indexExpr = new IndexExpressionSyntaxNode(); - indexExpr->BaseExpression = rs; - FillPosition(indexExpr.Ptr()); - ReadToken(TokenType::LBracket); - indexExpr->IndexExpression = ParseExpression(); - ReadToken(TokenType::RBracket); - rs = indexExpr; - } - else if (LookAheadToken(TokenType::LParent)) + RefPtr invokeExpr = new InvokeExpressionSyntaxNode(); + invokeExpr->FunctionExpr = rs; + FillPosition(invokeExpr.Ptr()); + ReadToken(TokenType::LParent); + while (!tokenReader.IsAtEnd()) { - RefPtr invokeExpr = new InvokeExpressionSyntaxNode(); - invokeExpr->FunctionExpr = rs; - FillPosition(invokeExpr.Ptr()); - ReadToken(TokenType::LParent); - while (!tokenReader.IsAtEnd()) + if (!LookAheadToken(TokenType::RParent)) + invokeExpr->Arguments.Add(ParseArgExpr()); + else { - if (!LookAheadToken(TokenType::RParent)) - invokeExpr->Arguments.Add(ParseArgExpr()); - else - { - break; - } - if (!LookAheadToken(TokenType::Comma)) - break; - ReadToken(TokenType::Comma); + break; } - ReadToken(TokenType::RParent); - rs = invokeExpr; - } - else if (LookAheadToken(TokenType::Dot)) - { - RefPtr memberExpr = new MemberExpressionSyntaxNode(); - memberExpr->scope = currentScope.Ptr(); - FillPosition(memberExpr.Ptr()); - memberExpr->BaseExpression = rs; - ReadToken(TokenType::Dot); - memberExpr->MemberName = ReadToken(TokenType::Identifier).Content; - rs = memberExpr; + if (!LookAheadToken(TokenType::Comma)) + break; + ReadToken(TokenType::Comma); } + ReadToken(TokenType::RParent); + rs = invokeExpr; } - if (!rs) + else if (LookAheadToken(TokenType::Dot)) { - sink->diagnose(tokenReader.PeekLoc(), Diagnostics::syntaxError); + RefPtr memberExpr = new MemberExpressionSyntaxNode(); + memberExpr->scope = currentScope.Ptr(); + FillPosition(memberExpr.Ptr()); + memberExpr->BaseExpression = rs; + ReadToken(TokenType::Dot); + memberExpr->MemberName = ReadToken(TokenType::Identifier).Content; + rs = memberExpr; } - return rs; } - - // Parse a source file into an existing translation unit - void parseSourceFile( - ProgramSyntaxNode* translationUnitSyntax, - CompileOptions& options, - TokenSpan const& tokens, - DiagnosticSink* sink, - String const& fileName, - RefPtr const&outerScope) + if (!rs) { - Parser parser(options, tokens, sink, fileName, outerScope); - return parser.parseSourceFile(translationUnitSyntax); + sink->diagnose(tokenReader.PeekLoc(), Diagnostics::syntaxError); } + return rs; + } + + // Parse a source file into an existing translation unit + void parseSourceFile( + ProgramSyntaxNode* translationUnitSyntax, + CompileOptions& options, + TokenSpan const& tokens, + DiagnosticSink* sink, + String const& fileName, + RefPtr const&outerScope) + { + Parser parser(options, tokens, sink, fileName, outerScope); + return parser.parseSourceFile(translationUnitSyntax); } -} \ No newline at end of file +} -- cgit v1.2.3