diff options
Diffstat (limited to 'source/slang/parser.cpp')
| -rw-r--r-- | source/slang/parser.cpp | 5087 |
1 files changed, 2542 insertions, 2545 deletions
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<Scope> outerScope; + RefPtr<Scope> 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<Scope> 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<Scope> const& outerScope) + : options(options) + , tokenReader(_tokens) + , sink(sink) + , fileName(_fileName) + , outerScope(outerScope) + {} + RefPtr<ProgramSyntaxNode> 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<ProgramSyntaxNode> ParseProgram(); + RefPtr<StructSyntaxNode> ParseStruct(); + RefPtr<ClassSyntaxNode> ParseClass(); + RefPtr<StatementSyntaxNode> ParseStatement(); + RefPtr<StatementSyntaxNode> ParseBlockStatement(); + RefPtr<VarDeclrStatementSyntaxNode> ParseVarDeclrStatement(Modifiers modifiers); + RefPtr<IfStatementSyntaxNode> ParseIfStatement(); + RefPtr<ForStatementSyntaxNode> ParseForStatement(); + RefPtr<WhileStatementSyntaxNode> ParseWhileStatement(); + RefPtr<DoWhileStatementSyntaxNode> ParseDoWhileStatement(); + RefPtr<BreakStatementSyntaxNode> ParseBreakStatement(); + RefPtr<ContinueStatementSyntaxNode> ParseContinueStatement(); + RefPtr<ReturnStatementSyntaxNode> ParseReturnStatement(); + RefPtr<ExpressionStatementSyntaxNode> ParseExpressionStatement(); + RefPtr<ExpressionSyntaxNode> 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<ExpressionSyntaxNode> ParseInitExpr() { return ParseExpression(Precedence::Assignment); } + inline RefPtr<ExpressionSyntaxNode> ParseArgExpr() { return ParseExpression(Precedence::Assignment); } + + RefPtr<ExpressionSyntaxNode> ParseLeafExpression(); + RefPtr<ParameterSyntaxNode> ParseParameter(); + RefPtr<ExpressionSyntaxNode> 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<Modifier> ParseOptSemantics( + Parser* parser); + + static void ParseOptSemantics( + Parser* parser, + Decl* decl); + + static RefPtr<DeclBase> ParseDecl( + Parser* parser, + ContainerDecl* containerDecl); + + static RefPtr<Decl> ParseSingleDecl( + Parser* parser, + ContainerDecl* containerDecl); + + // + + static void Unexpected( + Parser* parser) + { + // Don't emit "unexpected token" errors if we are in recovering mode + if (!parser->isRecovering) { - public: - CompileOptions& options; - int anonymousCounter = 0; + parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedToken, + parser->tokenReader.PeekTokenType()); - RefPtr<Scope> outerScope; - RefPtr<Scope> 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<Scope> 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<Scope> const& outerScope) - : options(options) - , tokenReader(_tokens) - , sink(sink) - , fileName(_fileName) - , outerScope(outerScope) - {} - RefPtr<ProgramSyntaxNode> 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<ProgramSyntaxNode> ParseProgram(); - RefPtr<StructSyntaxNode> ParseStruct(); - RefPtr<ClassSyntaxNode> ParseClass(); - RefPtr<StatementSyntaxNode> ParseStatement(); - RefPtr<StatementSyntaxNode> ParseBlockStatement(); - RefPtr<VarDeclrStatementSyntaxNode> ParseVarDeclrStatement(Modifiers modifiers); - RefPtr<IfStatementSyntaxNode> ParseIfStatement(); - RefPtr<ForStatementSyntaxNode> ParseForStatement(); - RefPtr<WhileStatementSyntaxNode> ParseWhileStatement(); - RefPtr<DoWhileStatementSyntaxNode> ParseDoWhileStatement(); - RefPtr<BreakStatementSyntaxNode> ParseBreakStatement(); - RefPtr<ContinueStatementSyntaxNode> ParseContinueStatement(); - RefPtr<ReturnStatementSyntaxNode> ParseReturnStatement(); - RefPtr<ExpressionStatementSyntaxNode> ParseExpressionStatement(); - RefPtr<ExpressionSyntaxNode> 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<ExpressionSyntaxNode> ParseInitExpr() { return ParseExpression(Precedence::Assignment); } - inline RefPtr<ExpressionSyntaxNode> ParseArgExpr() { return ParseExpression(Precedence::Assignment); } - - RefPtr<ExpressionSyntaxNode> ParseLeafExpression(); - RefPtr<ParameterSyntaxNode> ParseParameter(); - RefPtr<ExpressionSyntaxNode> 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); + // Switch into recovery mode, to suppress additional errors + parser->isRecovering = true; + } + } - static RefPtr<Modifier> 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<DeclBase> 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<Decl> 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; - } - } - // 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(); - } + // Don't skip past any "closing" tokens. + if (IsClosingToken(tokenReader.PeekTokenType())) + { + return tokenReader.PeekToken(); + } - 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) + static bool TryRecoverBefore( + Parser* parser, + TokenType before0) + { + TokenType recoverBefore[] = { before0 }; + return TryRecover(parser, recoverBefore, 1, nullptr, 0); + } + + // Default recovery strategy, to use inside `{}`-delimeted blocks. + static bool TryRecover( + Parser* parser) + { + TokenType recoverBefore[] = { TokenType::RBrace }; + TokenType recoverAfter[] = { TokenType::Semicolon }; + return TryRecover(parser, recoverBefore, 1, recoverAfter, 1); + } + + Token Parser::ReadToken(TokenType expected) + { + if (tokenReader.PeekTokenType() == expected) { - 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<ProgramSyntaxNode> Parser::Parse() + if (AdvanceIf(parser, tokenType)) + return true; + if (parser->tokenReader.PeekTokenType() == TokenType::EndOfFile) { - return ParseProgram(); + parser->ReadToken(tokenType); + return true; } + return false; + } - RefPtr<TypeDefDecl> ParseTypeDef(Parser* parser) - { - // Consume the `typedef` keyword - parser->ReadToken("typedef"); + RefPtr<ProgramSyntaxNode> Parser::Parse() + { + return ParseProgram(); + } - // TODO(tfoley): parse an actual declarator - auto type = parser->ParseTypeExp(); + RefPtr<TypeDefDecl> 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> typeDefDecl = new TypeDefDecl(); - typeDefDecl->Name = nameToken; - typeDefDecl->Type = type; + auto nameToken = parser->ReadToken(TokenType::Identifier); - return typeDefDecl; - } + RefPtr<TypeDefDecl> typeDefDecl = new TypeDefDecl(); + typeDefDecl->Name = nameToken; + typeDefDecl->Type = type; - // Add a modifier to a list of modifiers being built - static void AddModifier(RefPtr<Modifier>** ioModifierLink, RefPtr<Modifier> modifier) - { - RefPtr<Modifier>*& modifierLink = *ioModifierLink; + return typeDefDecl; + } - while(*modifierLink) - modifierLink = &(*modifierLink)->next; + // Add a modifier to a list of modifiers being built + static void AddModifier(RefPtr<Modifier>** ioModifierLink, RefPtr<Modifier> modifier) + { + RefPtr<Modifier>*& modifierLink = *ioModifierLink; - *modifierLink = modifier; - modifierLink = &modifier->next; - } + while(*modifierLink) + modifierLink = &(*modifierLink)->next; - void addModifier( - RefPtr<ModifiableSyntaxNode> syntax, - RefPtr<Modifier> modifier) - { - auto modifierLink = &syntax->modifiers.first; - AddModifier(&modifierLink, modifier); - } + *modifierLink = modifier; + modifierLink = &modifier->next; + } + + void addModifier( + RefPtr<ModifiableSyntaxNode> syntax, + RefPtr<Modifier> modifier) + { + auto modifierLink = &syntax->modifiers.first; + AddModifier(&modifierLink, modifier); + } - // Parse HLSL-style `[name(arg, ...)]` style "attribute" modifiers - static void ParseSquareBracketAttributes(Parser* parser, RefPtr<Modifier>** ioModifierLink) + // Parse HLSL-style `[name(arg, ...)]` style "attribute" modifiers + static void ParseSquareBracketAttributes(Parser* parser, RefPtr<Modifier>** ioModifierLink) + { + parser->ReadToken(TokenType::LBracket); + for(;;) { - parser->ReadToken(TokenType::LBracket); - for(;;) + auto nameToken = parser->ReadToken(TokenType::Identifier); + RefPtr<HLSLUncheckedAttribute> modifier = new HLSLUncheckedAttribute(); + modifier->nameToken = nameToken; + + if (AdvanceIf(parser, TokenType::LParent)) { - auto nameToken = parser->ReadToken(TokenType::Identifier); - RefPtr<HLSLUncheckedAttribute> 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<Modifier>* modifierLink = &modifiers.first; - for (;;) - { - CodePosition loc = parser->tokenReader.PeekLoc(); - - if (0) {} - - #define CASE(KEYWORD, TYPE) \ - else if(AdvanceIf(parser, #KEYWORD)) do { \ - RefPtr<TYPE> 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<Modifier>* modifierLink = &modifiers.first; + for (;;) + { + CodePosition loc = parser->tokenReader.PeekLoc(); + + if (0) {} + + #define CASE(KEYWORD, TYPE) \ + else if(AdvanceIf(parser, #KEYWORD)) do { \ + RefPtr<TYPE> 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); + + modifier->op = findIntrinsicOp(modifier->opToken.Content.Buffer()); - parser->ReadToken(TokenType::LParent); - if (parser->LookAheadToken(TokenType::IntLiterial)) + 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<GLSLLayoutModifier> modifier; + RefPtr<GLSLLayoutModifier> 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<BuiltinTypeModifier> 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<MagicTypeModifier> 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<BuiltinTypeModifier> 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<MagicTypeModifier> modifier = new MagicTypeModifier(); - parser->ReadToken(TokenType::LParent); - modifier->name = parser->ReadToken(TokenType::Identifier).Content; - if (AdvanceIf(parser, TokenType::Comma)) - { - modifier->tag = uint32_t(StringToInt(parser->ReadToken(TokenType::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<ModifierDecl*>(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. - if( auto modifierDecl = dynamic_cast<ModifierDecl*>(decl) ) + auto syntax = createInstanceOfSyntaxClassByName(modifierDecl->classNameToken.Content); + auto modifier = dynamic_cast<Modifier*>(syntax); + + if( modifier ) + { + modifier->Position = parser->tokenReader.PeekLoc(); + modifier->nameToken = parser->ReadToken(TokenType::Identifier); + + 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<Modifier*>(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<Decl> parseImportDecl( - Parser* parser) - { - parser->ReadToken("__import"); + static RefPtr<Decl> 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<Declarator> 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<Declarator> inner; + RefPtr<Declarator> inner; + }; - // location of the `[` token - CodePosition openBracketLoc; + // A declarator that declares an array type + struct ArrayDeclarator : Declarator + { + RefPtr<Declarator> inner; - // The expression that yields the element count, or NULL - RefPtr<ExpressionSyntaxNode> elementCountExpr; - }; + // location of the `[` token + CodePosition openBracketLoc; - // "Unwrapped" information about a declarator - struct DeclaratorInfo - { - RefPtr<ExpressionSyntaxNode> typeSpec; - Token nameToken; - RefPtr<Modifier> semantics; - RefPtr<ExpressionSyntaxNode> initializer; - }; + // The expression that yields the element count, or NULL + RefPtr<ExpressionSyntaxNode> elementCountExpr; + }; - // Add a member declaration to its container, and ensure that its - // parent link is set up correctly. - static void AddMember(RefPtr<ContainerDecl> container, RefPtr<Decl> member) + // "Unwrapped" information about a declarator + struct DeclaratorInfo + { + RefPtr<ExpressionSyntaxNode> typeSpec; + Token nameToken; + RefPtr<Modifier> semantics; + RefPtr<ExpressionSyntaxNode> initializer; + }; + + // Add a member declaration to its container, and ensure that its + // parent link is set up correctly. + static void AddMember(RefPtr<ContainerDecl> container, RefPtr<Decl> member) + { + if (container) { - 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> scope, RefPtr<Decl> member) + static void AddMember(RefPtr<Scope> scope, RefPtr<Decl> member) + { + if (scope) { - if (scope) - { - AddMember(scope->containerDecl, member); - } + AddMember(scope->containerDecl, member); } + } - static void parseParameterList( - Parser* parser, - RefPtr<CallableDecl> decl) - { - parser->ReadToken(TokenType::LParent); - - // Allow a declaration to use the keyword `void` for a parameter list, - // since that was required in ancient C, and continues to be supported - // in a bunc hof its derivatives even if it is a Bad Design Choice - // - // TODO: conditionalize this so we don't keep this around for "pure" - // Slang code - if( parser->LookAheadToken("void") && parser->LookAheadToken(TokenType::RParent, 1) ) - { - parser->ReadToken("void"); - parser->ReadToken(TokenType::RParent); - return; - } + static void parseParameterList( + Parser* parser, + RefPtr<CallableDecl> 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<FunctionSyntaxNode> 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<FunctionSyntaxNode> 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<Decl> ParseFuncDecl( - Parser* parser, - ContainerDecl* /*containerDecl*/, - DeclaratorInfo const& declaratorInfo) - { - RefPtr<FunctionSyntaxNode> 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<Decl> ParseFuncDecl( + Parser* parser, + ContainerDecl* /*containerDecl*/, + DeclaratorInfo const& declaratorInfo) + { + RefPtr<FunctionSyntaxNode> decl = new FunctionSyntaxNode(); + ParseFuncDeclHeader(parser, declaratorInfo, decl); - parser->PopScope(); - return decl; + if (AdvanceIf(parser, TokenType::Semicolon)) + { + // empty body } - - static RefPtr<VarDeclBase> CreateVarDeclForContext( - ContainerDecl* containerDecl ) + else { - if (dynamic_cast<StructSyntaxNode*>(containerDecl) || dynamic_cast<ClassSyntaxNode*>(containerDecl)) - { - return new StructField(); - } - else if (dynamic_cast<CallableDecl*>(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<Modifier> modifiers) - { - if (!modifiers) - return; + parser->PopScope(); + return decl; + } - RefPtr<Modifier>* link = &decl->modifiers.first; - while (*link) - { - link = &(*link)->next; - } - *link = modifiers; + static RefPtr<VarDeclBase> CreateVarDeclForContext( + ContainerDecl* containerDecl ) + { + if (dynamic_cast<StructSyntaxNode*>(containerDecl) || dynamic_cast<ClassSyntaxNode*>(containerDecl)) + { + return new StructField(); + } + else if (dynamic_cast<CallableDecl*>(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<Modifier> modifiers) + { + if (!modifiers) + return; - static String GenerateName(Parser* /*parser*/, String const& base) + RefPtr<Modifier>* 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<VarDeclBase> 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<VarDeclBase> decl, - DeclaratorInfo const& declaratorInfo) - { - parser->FillPosition(decl.Ptr()); + decl->Expr = declaratorInfo.initializer; + } + + static RefPtr<Declarator> ParseDeclarator(Parser* parser); - if( declaratorInfo.nameToken.Type == TokenType::Unknown ) + static RefPtr<Declarator> ParseDirectAbstractDeclarator( + Parser* parser) + { + RefPtr<Declarator> 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); - - AddModifiers(decl.Ptr(), declaratorInfo.semantics); + break; - decl->Expr = declaratorInfo.initializer; + default: + // an empty declarator is allowed + return nullptr; } - static RefPtr<Declarator> ParseDeclarator(Parser* parser); - - static RefPtr<Declarator> ParseDirectAbstractDeclarator( - Parser* parser) + // postifx additions + for( ;;) { - RefPtr<Declarator> declarator; switch( parser->tokenReader.PeekTokenType() ) { - case TokenType::Identifier: + case TokenType::LBracket: { - auto nameDeclarator = new NameDeclarator(); - nameDeclarator->flavor = Declarator::Flavor::Name; - nameDeclarator->nameToken = ParseDeclName(parser); - declarator = nameDeclarator; + 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; } - break; case TokenType::LParent: - { - // Note(tfoley): This is a point where disambiguation is required. - // We could be looking at an abstract declarator for a function-type - // parameter: - // - // void F( int(int) ); - // - // Or we could be looking at the use of parenthesese in an ordinary - // declarator: - // - // void (*f)(int); - // - // The difference really doesn't matter right now, but we err in - // the direction of assuming the second case. - parser->ReadToken(TokenType::LParent); - declarator = ParseDeclarator(parser); - parser->ReadToken(TokenType::RParent); - } break; default: - // an empty declarator is allowed - return nullptr; + break; } - // postifx additions - for( ;;) + break; + } + + return declarator; + } + + // Parse a declarator (or at least as much of one as we support) + static RefPtr<Declarator> ParseDeclarator( + Parser* parser) + { + if( parser->tokenReader.PeekTokenType() == TokenType::OpMul ) + { + auto ptrDeclarator = new PointerDeclarator(); + ptrDeclarator->starLoc = parser->tokenReader.PeekLoc(); + ptrDeclarator->flavor = Declarator::Flavor::Pointer; + + parser->ReadToken(TokenType::OpMul); + + // TODO(tfoley): allow qualifiers like `const` here? + + ptrDeclarator->inner = ParseDeclarator(parser); + return ptrDeclarator; + } + else + { + return ParseDirectAbstractDeclarator(parser); + } + } + + // A declarator plus optional semantics and initializer + struct InitDeclarator + { + RefPtr<Declarator> declarator; + RefPtr<Modifier> semantics; + RefPtr<ExpressionSyntaxNode> initializer; + }; + + // Parse a declarator plus optional semantics + static InitDeclarator ParseSemanticDeclarator( + Parser* parser) + { + InitDeclarator result; + result.declarator = ParseDeclarator(parser); + result.semantics = ParseOptSemantics(parser); + return result; + } + + // Parse a declarator plus optional semantics and initializer + static InitDeclarator ParseInitDeclarator( + Parser* parser) + { + InitDeclarator result = ParseSemanticDeclarator(parser); + if (AdvanceIf(parser, TokenType::OpAssign)) + { + result.initializer = parser->ParseInitExpr(); + } + return result; + } + + static void UnwrapDeclarator( + RefPtr<Declarator> declarator, + DeclaratorInfo* ioInfo) + { + while( declarator ) + { + switch(declarator->flavor) { - switch( parser->tokenReader.PeekTokenType() ) + case Declarator::Flavor::Name: { - case TokenType::LBracket: - { - auto arrayDeclarator = new ArrayDeclarator(); - arrayDeclarator->openBracketLoc = parser->tokenReader.PeekLoc(); - arrayDeclarator->flavor = Declarator::Flavor::Array; - arrayDeclarator->inner = declarator; + auto nameDeclarator = (NameDeclarator*) declarator.Ptr(); + ioInfo->nameToken = nameDeclarator->nameToken; + return; + } + break; - parser->ReadToken(TokenType::LBracket); - if( parser->tokenReader.PeekTokenType() != TokenType::RBracket ) - { - arrayDeclarator->elementCountExpr = parser->ParseExpression(); - } - parser->ReadToken(TokenType::RBracket); + case Declarator::Flavor::Pointer: + { + auto ptrDeclarator = (PointerDeclarator*) declarator.Ptr(); - declarator = arrayDeclarator; - continue; - } + // TODO(tfoley): we don't support pointers for now + // ioInfo->typeSpec = new PointerTypeExpr(ioInfo->typeSpec); - case TokenType::LParent: - break; + declarator = ptrDeclarator->inner; + } + break; - default: - break; + case Declarator::Flavor::Array: + { + // TODO(tfoley): we don't support pointers for now + auto arrayDeclarator = (ArrayDeclarator*) declarator.Ptr(); + + auto arrayTypeExpr = new IndexExpressionSyntaxNode(); + arrayTypeExpr->Position = arrayDeclarator->openBracketLoc; + arrayTypeExpr->BaseExpression = ioInfo->typeSpec; + arrayTypeExpr->IndexExpression = arrayDeclarator->elementCountExpr; + ioInfo->typeSpec = arrayTypeExpr; + + declarator = arrayDeclarator->inner; } + break; + default: + SLANG_UNREACHABLE("all cases handled"); break; } - - return declarator; } + } - // Parse a declarator (or at least as much of one as we support) - static RefPtr<Declarator> ParseDeclarator( - Parser* parser) - { - if( parser->tokenReader.PeekTokenType() == TokenType::OpMul ) - { - auto ptrDeclarator = new PointerDeclarator(); - ptrDeclarator->starLoc = parser->tokenReader.PeekLoc(); - ptrDeclarator->flavor = Declarator::Flavor::Pointer; + static void UnwrapDeclarator( + InitDeclarator const& initDeclarator, + DeclaratorInfo* ioInfo) + { + UnwrapDeclarator(initDeclarator.declarator, ioInfo); + ioInfo->semantics = initDeclarator.semantics; + ioInfo->initializer = initDeclarator.initializer; + } - parser->ReadToken(TokenType::OpMul); + // Either a single declaration, or a group of them + struct DeclGroupBuilder + { + CodePosition startPosition; + RefPtr<Decl> decl; + RefPtr<DeclGroup> group; - // TODO(tfoley): allow qualifiers like `const` here? + // Add a new declaration to the potential group + void addDecl( + RefPtr<Decl> newDecl) + { + assert(newDecl); + + if( decl ) + { + group = new DeclGroup(); + group->Position = startPosition; + group->decls.Add(decl); + decl = nullptr; + } - ptrDeclarator->inner = ParseDeclarator(parser); - return ptrDeclarator; + if( group ) + { + group->decls.Add(newDecl); } else { - return ParseDirectAbstractDeclarator(parser); + decl = newDecl; } } - // A declarator plus optional semantics and initializer - struct InitDeclarator + RefPtr<DeclBase> getResult() { - RefPtr<Declarator> declarator; - RefPtr<Modifier> semantics; - RefPtr<ExpressionSyntaxNode> initializer; - }; + if(group) return group; + return decl; + } + }; + + // Pares an argument to an application of a generic + RefPtr<ExpressionSyntaxNode> ParseGenericArg(Parser* parser) + { + return parser->ParseArgExpr(); + } + + // Create a type expression that will refer to the given declaration + static RefPtr<ExpressionSyntaxNode> + createDeclRefType(Parser* parser, RefPtr<Decl> decl) + { + // For now we just construct an expression that + // will look up the given declaration by name. + // + // TODO: do this better, e.g. by filling in the `declRef` field directly + + auto expr = new VarExpressionSyntaxNode(); + expr->scope = parser->currentScope.Ptr(); + expr->Position = decl->getNameToken().Position; + expr->Variable = decl->getName(); + return expr; + } - // Parse a declarator plus optional semantics - static InitDeclarator ParseSemanticDeclarator( - Parser* parser) + // Representation for a parsed type specifier, which might + // include a declaration (e.g., of a `struct` type) + struct TypeSpec + { + // If the type-spec declared something, then put it here + RefPtr<Decl> decl; + + // Put the resulting expression (which should evaluate to a type) here + RefPtr<ExpressionSyntaxNode> expr; + }; + + static TypeSpec + parseTypeSpec(Parser* parser) + { + TypeSpec typeSpec; + + // 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") ) { - InitDeclarator result; - result.declarator = ParseDeclarator(parser); - result.semantics = ParseOptSemantics(parser); - return result; + 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; } - // Parse a declarator plus optional semantics and initializer - static InitDeclarator ParseInitDeclarator( - Parser* parser) + Token typeName = parser->ReadToken(TokenType::Identifier); + + auto basicType = new VarExpressionSyntaxNode(); + basicType->scope = parser->currentScope.Ptr(); + basicType->Position = typeName.Position; + basicType->Variable = typeName.Content; + + RefPtr<ExpressionSyntaxNode> typeExpr = basicType; + + if (parser->LookAheadToken(TokenType::OpLess)) { - InitDeclarator result = ParseSemanticDeclarator(parser); - if (AdvanceIf(parser, TokenType::OpAssign)) + RefPtr<GenericAppExpr> 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)) { - result.initializer = parser->ParseInitExpr(); + gtype->Arguments.Add(ParseGenericArg(parser)); } - return result; + parser->genericDepth--; + parser->ReadToken(TokenType::OpGreater); + typeExpr = gtype; } - static void UnwrapDeclarator( - RefPtr<Declarator> declarator, - DeclaratorInfo* ioInfo) - { - while( declarator ) - { - switch(declarator->flavor) - { - case Declarator::Flavor::Name: - { - auto nameDeclarator = (NameDeclarator*) declarator.Ptr(); - ioInfo->nameToken = nameDeclarator->nameToken; - return; - } - break; + typeSpec.expr = typeExpr; + return typeSpec; + } - case Declarator::Flavor::Pointer: - { - auto ptrDeclarator = (PointerDeclarator*) declarator.Ptr(); - // TODO(tfoley): we don't support pointers for now - // ioInfo->typeSpec = new PointerTypeExpr(ioInfo->typeSpec); + static RefPtr<DeclBase> ParseDeclaratorDecl( + Parser* parser, + ContainerDecl* containerDecl) + { + CodePosition startPosition = parser->tokenReader.PeekLoc(); - declarator = ptrDeclarator->inner; - } - break; + auto typeSpec = parseTypeSpec(parser); - case Declarator::Flavor::Array: - { - // TODO(tfoley): we don't support pointers for now - auto arrayDeclarator = (ArrayDeclarator*) declarator.Ptr(); + // 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 arrayTypeExpr = new IndexExpressionSyntaxNode(); - arrayTypeExpr->Position = arrayDeclarator->openBracketLoc; - arrayTypeExpr->BaseExpression = ioInfo->typeSpec; - arrayTypeExpr->IndexExpression = arrayDeclarator->elementCountExpr; - ioInfo->typeSpec = arrayTypeExpr; + // The type specifier may include a declaration. E.g., + // it might declare a `struct` type. + if(typeSpec.decl) + declGroupBuilder.addDecl(typeSpec.decl); - declarator = arrayDeclarator->inner; - } - break; + if( AdvanceIf(parser, TokenType::Semicolon) ) + { + // No actual variable is being declared here, but + // that might not be an error. - default: - SLANG_UNREACHABLE("all cases handled"); - break; - } + auto result = declGroupBuilder.getResult(); + if( !result ) + { + parser->sink->diagnose(startPosition, Diagnostics::declarationDidntDeclareAnything); } + return result; } - 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> decl; - RefPtr<DeclGroup> group; + InitDeclarator initDeclarator = ParseInitDeclarator(parser); - // Add a new declaration to the potential group - void addDecl( - RefPtr<Decl> newDecl) - { - assert(newDecl); - - if( decl ) - { - group = new DeclGroup(); - group->Position = startPosition; - group->decls.Add(decl); - decl = nullptr; - } + DeclaratorInfo declaratorInfo; + declaratorInfo.typeSpec = typeSpec.expr; - if( group ) - { - group->decls.Add(newDecl); - } - else - { - decl = newDecl; - } - } - RefPtr<DeclBase> getResult() - { - if(group) return group; - return decl; - } - }; + // 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 - // Pares an argument to an application of a generic - RefPtr<ExpressionSyntaxNode> ParseGenericArg(Parser* parser) + // Only parse as a function if we didn't already see mutually-exclusive + // constructs when parsing the declarator. + && !initDeclarator.initializer + && !initDeclarator.semantics) { - return parser->ParseArgExpr(); + // Looks like a function, so parse it like one. + UnwrapDeclarator(initDeclarator, &declaratorInfo); + return ParseFuncDecl(parser, containerDecl, declaratorInfo); } - // Create a type expression that will refer to the given declaration - static RefPtr<ExpressionSyntaxNode> - createDeclRefType(Parser* parser, RefPtr<Decl> decl) + // Otherwise we are looking at a variable declaration, which could be one in a sequence... + + if( AdvanceIf(parser, TokenType::Semicolon) ) { - // 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 + // easy case: we only had a single declaration! + UnwrapDeclarator(initDeclarator, &declaratorInfo); + RefPtr<VarDeclBase> firstDecl = CreateVarDeclForContext(containerDecl); + CompleteVarDecl(parser, firstDecl, declaratorInfo); - auto expr = new VarExpressionSyntaxNode(); - expr->scope = parser->currentScope.Ptr(); - expr->Position = decl->getNameToken().Position; - expr->Variable = decl->getName(); - return expr; + declGroupBuilder.addDecl(firstDecl); + return declGroupBuilder.getResult(); } - // Representation for a parsed type specifier, which might - // include a declaration (e.g., of a `struct` type) - struct TypeSpec - { - // If the type-spec declared something, then put it here - RefPtr<Decl> decl; + // 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. - // Put the resulting expression (which should evaluate to a type) here - RefPtr<ExpressionSyntaxNode> expr; - }; + auto sharedTypeSpec = new SharedTypeExpr(); + sharedTypeSpec->Position = typeSpec.expr->Position; + sharedTypeSpec->base = TypeExp(typeSpec.expr); - static TypeSpec - parseTypeSpec(Parser* parser) + for(;;) { - TypeSpec typeSpec; + declaratorInfo.typeSpec = sharedTypeSpec; + UnwrapDeclarator(initDeclarator, &declaratorInfo); - // 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; - } + RefPtr<VarDeclBase> varDecl = CreateVarDeclForContext(containerDecl); + CompleteVarDecl(parser, varDecl, declaratorInfo); - Token typeName = parser->ReadToken(TokenType::Identifier); + declGroupBuilder.addDecl(varDecl); + + // end of the sequence? + if(AdvanceIf(parser, TokenType::Semicolon)) + return declGroupBuilder.getResult(); - auto basicType = new VarExpressionSyntaxNode(); - basicType->scope = parser->currentScope.Ptr(); - basicType->Position = typeName.Position; - basicType->Variable = typeName.Content; + // ad-hoc recovery, to avoid infinite loops + if( parser->isRecovering ) + { + parser->ReadToken(TokenType::Semicolon); + return declGroupBuilder.getResult(); + } - RefPtr<ExpressionSyntaxNode> typeExpr = basicType; + // Let's default to assuming that a missing `,` + // indicates the end of a declaration, + // where a `;` would be expected, and not + // a continuation of this declaration, where + // a `,` would be expected (this is tailoring + // the diagnostic message a bit). + // + // TODO: a more advanced heuristic here might + // look at whether the next token is on the + // same line, to predict whether `,` or `;` + // would be more likely... - if (parser->LookAheadToken(TokenType::OpLess)) + if (!AdvanceIf(parser, TokenType::Comma)) { - RefPtr<GenericAppExpr> 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; + parser->ReadToken(TokenType::Semicolon); + return declGroupBuilder.getResult(); } - typeSpec.expr = typeExpr; - return typeSpec; + // 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) + { + semantic->name = parser->ReadToken(TokenType::Identifier); - static RefPtr<DeclBase> ParseDeclaratorDecl( - Parser* parser, - ContainerDecl* containerDecl) + parser->ReadToken(TokenType::LParent); + semantic->registerName = parser->ReadToken(TokenType::Identifier); + if (AdvanceIf(parser, TokenType::Dot)) { - CodePosition startPosition = parser->tokenReader.PeekLoc(); + semantic->componentMask = parser->ReadToken(TokenType::Identifier); + } + parser->ReadToken(TokenType::RParent); + } - auto typeSpec = parseTypeSpec(parser); + // + // semantic ::= identifier ( '(' args ')' )? + // + static RefPtr<Modifier> ParseSemantic( + Parser* parser) + { + if (parser->LookAheadToken("register")) + { + RefPtr<HLSLRegisterSemantic> semantic = new HLSLRegisterSemantic(); + ParseHLSLLayoutSemantic(parser, semantic.Ptr()); + return semantic; + } + else if (parser->LookAheadToken("packoffset")) + { + RefPtr<HLSLPackOffsetSemantic> semantic = new HLSLPackOffsetSemantic(); + ParseHLSLLayoutSemantic(parser, semantic.Ptr()); + return semantic; + } + else + { + RefPtr<HLSLSimpleSemantic> semantic = new HLSLSimpleSemantic(); + semantic->name = parser->ReadToken(TokenType::Identifier); + return semantic; + } + } - // 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; + // + // opt-semantics ::= (':' semantic)* + // + static RefPtr<Modifier> ParseOptSemantics( + Parser* parser) + { + if (!AdvanceIf(parser, TokenType::Colon)) + return nullptr; - // The type specifier may include a declaration. E.g., - // it might declare a `struct` type. - if(typeSpec.decl) - declGroupBuilder.addDecl(typeSpec.decl); + RefPtr<Modifier> result; + RefPtr<Modifier>* link = &result; + assert(!*link); - if( AdvanceIf(parser, TokenType::Semicolon) ) + for (;;) + { + RefPtr<Modifier> semantic = ParseSemantic(parser); + if (semantic) { - // No actual variable is being declared here, but - // that might not be an error. + *link = semantic; + link = &semantic->next; + } - auto result = declGroupBuilder.getResult(); - if( !result ) - { - parser->sink->diagnose(startPosition, Diagnostics::declarationDidntDeclareAnything); - } + switch (parser->tokenReader.PeekTokenType()) + { + case TokenType::LBrace: + case TokenType::Semicolon: + case TokenType::Comma: + case TokenType::RParent: + case TokenType::EndOfFile: return result; + + default: + break; } + parser->ReadToken(TokenType::Colon); + } - InitDeclarator initDeclarator = ParseInitDeclarator(parser); + } - DeclaratorInfo declaratorInfo; - declaratorInfo.typeSpec = typeSpec.expr; + static void ParseOptSemantics( + Parser* parser, + Decl* decl) + { + AddModifiers(decl, ParseOptSemantics(parser)); + } - // 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 + static RefPtr<Decl> 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. - // 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); - } + // 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); + } - // Otherwise we are looking at a variable declaration, which could be one in a sequence... + // 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<StructSyntaxNode> bufferDataTypeDecl = new StructSyntaxNode(); + RefPtr<Variable> bufferVarDecl = new Variable(); - if( AdvanceIf(parser, TokenType::Semicolon) ) - { - // easy case: we only had a single declaration! - UnwrapDeclarator(initDeclarator, &declaratorInfo); - RefPtr<VarDeclBase> firstDecl = CreateVarDeclForContext(containerDecl); - CompleteVarDecl(parser, firstDecl, declaratorInfo); + // Both declarations will have a location that points to the name + parser->FillPosition(bufferDataTypeDecl.Ptr()); + parser->FillPosition(bufferVarDecl.Ptr()); - declGroupBuilder.addDecl(firstDecl); - return declGroupBuilder.getResult(); - } + auto reflectionNameToken = parser->ReadToken(TokenType::Identifier); - // 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. + // Attach the reflection name to the block so we can use it + auto reflectionNameModifier = new ParameterBlockReflectionName(); + reflectionNameModifier->nameToken = reflectionNameToken; + addModifier(bufferVarDecl, reflectionNameModifier); - auto sharedTypeSpec = new SharedTypeExpr(); - sharedTypeSpec->Position = typeSpec.expr->Position; - sharedTypeSpec->base = TypeExp(typeSpec.expr); + // 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); - for(;;) - { - declaratorInfo.typeSpec = sharedTypeSpec; - UnwrapDeclarator(initDeclarator, &declaratorInfo); + addModifier(bufferDataTypeDecl, new ImplicitParameterBlockElementTypeModifier()); + addModifier(bufferVarDecl, new ImplicitParameterBlockVariableModifier()); - RefPtr<VarDeclBase> varDecl = CreateVarDeclForContext(containerDecl); - CompleteVarDecl(parser, varDecl, declaratorInfo); + // 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. - declGroupBuilder.addDecl(varDecl); + // 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(); - // end of the sequence? - if(AdvanceIf(parser, TokenType::Semicolon)) - return declGroupBuilder.getResult(); + // Construct a type exrpession to reference the type constructor + auto bufferWrapperTypeExpr = new VarExpressionSyntaxNode(); + bufferWrapperTypeExpr->Position = bufferWrapperTypeNamePos; + bufferWrapperTypeExpr->Variable = bufferWrapperTypeName; - // ad-hoc recovery, to avoid infinite loops - if( parser->isRecovering ) - { - parser->ReadToken(TokenType::Semicolon); - return declGroupBuilder.getResult(); - } + // 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; - // 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... + // 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); - if (!AdvanceIf(parser, TokenType::Comma)) - { - parser->ReadToken(TokenType::Semicolon); - return declGroupBuilder.getResult(); - } + bufferVarDecl->Type.exp = bufferVarTypeExpr; - // expect another variable declaration... - initDeclarator = ParseInitDeclarator(parser); - } - } + // Any semantics applied to the bufer declaration are taken as applying + // to the variable instead. + ParseOptSemantics(parser, bufferVarDecl.Ptr()); - // - // 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); + // The declarations in the body belong to the data type. + parseAggTypeDeclBody(parser, bufferDataTypeDecl.Ptr()); - 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); - } + // 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. // - // semantic ::= identifier ( '(' args ')' )? - // - static RefPtr<Modifier> ParseSemantic( - Parser* parser) + // 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> modifier) + { + RefPtr<Modifier>* link = &modifiers.first; + while (*link) { - if (parser->LookAheadToken("register")) - { - RefPtr<HLSLRegisterSemantic> semantic = new HLSLRegisterSemantic(); - ParseHLSLLayoutSemantic(parser, semantic.Ptr()); - return semantic; - } - else if (parser->LookAheadToken("packoffset")) + if (*link == modifier) { - RefPtr<HLSLPackOffsetSemantic> semantic = new HLSLPackOffsetSemantic(); - ParseHLSLLayoutSemantic(parser, semantic.Ptr()); - return semantic; - } - else - { - RefPtr<HLSLSimpleSemantic> semantic = new HLSLSimpleSemantic(); - semantic->name = parser->ReadToken(TokenType::Identifier); - return semantic; + *link = (*link)->next; + return; } + + link = &(*link)->next; } + } + static RefPtr<Decl> parseGLSLBlockDecl( + Parser* parser, + Modifiers& modifiers) + { + // An GLSL block like this: // - // opt-semantics ::= (':' semantic)* + // uniform Foo { int a; float b; } foo; // - static RefPtr<Modifier> ParseOptSemantics( - Parser* parser) - { - if (!AdvanceIf(parser, TokenType::Colon)) - return nullptr; - - RefPtr<Modifier> result; - RefPtr<Modifier>* link = &result; - assert(!*link); - - for (;;) - { - RefPtr<Modifier> semantic = ParseSemantic(parser); - if (semantic) - { - *link = semantic; - link = &semantic->next; - } + // 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. - switch (parser->tokenReader.PeekTokenType()) - { - case TokenType::LBrace: - case TokenType::Semicolon: - case TokenType::Comma: - case TokenType::RParent: - case TokenType::EndOfFile: - return result; - default: - break; - } + CodePosition pos = parser->tokenReader.PeekLoc(); - parser->ReadToken(TokenType::Colon); - } + // 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<HLSLUniformModifier>() ) + { + removeModifier(modifiers, uniformMod); + blockWrapperTypeName = "ConstantBuffer"; } - - - static void ParseOptSemantics( - Parser* parser, - Decl* decl) + else if( auto inMod = modifiers.findModifier<InModifier>() ) { - AddModifiers(decl, ParseOptSemantics(parser)); + removeModifier(modifiers, inMod); + blockWrapperTypeName = "__GLSLInputParameterBlock"; } - - static RefPtr<Decl> ParseHLSLBufferDecl( - Parser* parser) + else if( auto outMod = modifiers.findModifier<OutModifier>() ) { - // 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); - } - - // 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<StructSyntaxNode> bufferDataTypeDecl = new StructSyntaxNode(); - RefPtr<Variable> 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. - - AddMember(parser->currentScope, bufferDataTypeDecl); - - return bufferVarDecl; + removeModifier(modifiers, outMod); + blockWrapperTypeName = "__GLSLOutputParameterBlock"; } - - static void removeModifier( - Modifiers& modifiers, - RefPtr<Modifier> modifier) + else if( auto bufferMod = modifiers.findModifier<GLSLBufferModifier>() ) { - RefPtr<Modifier>* link = &modifiers.first; - while (*link) - { - if (*link == modifier) - { - *link = (*link)->next; - return; - } - - link = &(*link)->next; - } + removeModifier(modifiers, bufferMod); + blockWrapperTypeName = "__GLSLShaderStorageBuffer"; } - - static RefPtr<Decl> parseGLSLBlockDecl( - Parser* parser, - Modifiers& modifiers) + else { - // 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. + // 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<StructSyntaxNode> blockDataTypeDecl = new StructSyntaxNode(); + RefPtr<Variable> 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<HLSLUniformModifier>() ) - { - removeModifier(modifiers, uniformMod); - blockWrapperTypeName = "ConstantBuffer"; - } - else if( auto inMod = modifiers.findModifier<InModifier>() ) - { - removeModifier(modifiers, inMod); - blockWrapperTypeName = "__GLSLInputParameterBlock"; - } - else if( auto outMod = modifiers.findModifier<OutModifier>() ) - { - removeModifier(modifiers, outMod); - blockWrapperTypeName = "__GLSLOutputParameterBlock"; - } - else if( auto bufferMod = modifiers.findModifier<GLSLBufferModifier>() ) - { - 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<StructSyntaxNode> blockDataTypeDecl = new StructSyntaxNode(); - RefPtr<Variable> 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); + + 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); - AddMember(parser->currentScope, blockDataTypeDecl); + // 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); - return blockVarDecl; + // 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<Decl> ParseGenericParamDecl( - Parser* parser, - RefPtr<GenericDecl> genericDecl) + static RefPtr<Decl> ParseGenericParamDecl( + Parser* parser, + RefPtr<GenericDecl> 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<Decl> ParseGenericDecl( - Parser* parser) + static RefPtr<Decl> ParseGenericDecl( + Parser* parser) + { + RefPtr<GenericDecl> 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<GenericDecl> 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<ExtensionDecl> ParseExtensionDecl(Parser* parser) - { - RefPtr<ExtensionDecl> decl = new ExtensionDecl(); - parser->FillPosition(decl.Ptr()); - parser->ReadToken("__extension"); - decl->targetType = parser->ParseTypeExp(); + static RefPtr<ExtensionDecl> ParseExtensionDecl(Parser* parser) + { + RefPtr<ExtensionDecl> 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<InterfaceDecl> parseInterfaceDecl(Parser* parser) - { - RefPtr<InterfaceDecl> decl = new InterfaceDecl(); - parser->FillPosition(decl.Ptr()); - parser->ReadToken("interface"); - decl->Name = parser->ReadToken(TokenType::Identifier); + static RefPtr<InterfaceDecl> parseInterfaceDecl(Parser* parser) + { + RefPtr<InterfaceDecl> 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<ConstructorDecl> ParseConstructorDecl(Parser* parser) - { - RefPtr<ConstructorDecl> decl = new ConstructorDecl(); - parser->FillPosition(decl.Ptr()); - parser->ReadToken("__init"); + static RefPtr<ConstructorDecl> ParseConstructorDecl(Parser* parser) + { + RefPtr<ConstructorDecl> 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<AccessorDecl> parseAccessorDecl(Parser* parser) + else { - RefPtr<AccessorDecl> 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<AccessorDecl> parseAccessorDecl(Parser* parser) + { + RefPtr<AccessorDecl> decl; + if( AdvanceIf(parser, "get") ) + { + decl = new GetterDecl(); + } + else if( AdvanceIf(parser, "set") ) + { + decl = new SetterDecl(); + } + else + { + Unexpected(parser); + return nullptr; } - static RefPtr<SubscriptDecl> ParseSubscriptDecl(Parser* parser) + if( parser->tokenReader.PeekTokenType() == TokenType::LBrace ) { - RefPtr<SubscriptDecl> decl = new SubscriptDecl(); - parser->FillPosition(decl.Ptr()); - parser->ReadToken("__subscript"); + decl->Body = parser->ParseBlockStatement(); + } + else + { + 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<SubscriptDecl> ParseSubscriptDecl(Parser* parser) + { + RefPtr<SubscriptDecl> 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); - // empty body should be treated like `{ get; }` + if( AdvanceIf(parser, TokenType::RightArrow) ) + { + decl->ReturnType = parser->ParseTypeExp(); + } + + if( AdvanceIf(parser, TokenType::LBrace) ) + { + // We want to parse nested "accessor" declarations + while( !AdvanceIfMatch(parser, TokenType::RBrace) ) + { + auto accessor = parseAccessorDecl(parser); + AddMember(decl, accessor); } + } + else + { + parser->ReadToken(TokenType::Semicolon); - return decl; + // empty body should be treated like `{ get; }` } - // Parse a declaration of a new modifier keyword - static RefPtr<ModifierDecl> parseModifierDecl(Parser* parser) - { - RefPtr<ModifierDecl> decl = new ModifierDecl(); + return decl; + } - // read the `__modifier` keyword - parser->ReadToken(TokenType::Identifier); + // Parse a declaration of a new modifier keyword + static RefPtr<ModifierDecl> parseModifierDecl(Parser* parser) + { + RefPtr<ModifierDecl> 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> 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> 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<DeclBase> ParseDeclWithModifiers( - Parser* parser, - ContainerDecl* containerDecl, - Modifiers modifiers ) - { - RefPtr<DeclBase> 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<Decl>() ) - { - CompleteDecl(parser, dd, containerDecl, modifiers); - } - else if(auto declGroup = decl.As<DeclGroup>()) - { - // 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<DeclBase> ParseDeclWithModifiers( + Parser* parser, + ContainerDecl* containerDecl, + Modifiers modifiers ) + { + RefPtr<DeclBase> 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<DeclBase> 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<Decl> ParseSingleDecl( - Parser* parser, - ContainerDecl* containerDecl) + if (decl) { - auto declBase = ParseDecl(parser, containerDecl); - if(!declBase) - return nullptr; - if( auto decl = declBase.As<Decl>() ) + if( auto dd = decl.As<Decl>() ) { - return decl; + CompleteDecl(parser, dd, containerDecl, modifiers); } - else if( auto declGroup = declBase.As<DeclGroup>() ) + else if(auto declGroup = decl.As<DeclGroup>()) { - 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<DeclBase> 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<Decl> ParseSingleDecl( + Parser* parser, + ContainerDecl* containerDecl) + { + auto declBase = ParseDecl(parser, containerDecl); + if(!declBase) + return nullptr; + if( auto decl = declBase.As<Decl>() ) { - while(!AdvanceIfMatch(parser, closingToken)) + return decl; + } + else if( auto declGroup = declBase.As<DeclGroup>() ) + { + 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<ProgramSyntaxNode> Parser::ParseProgram() + void Parser::parseSourceFile(ProgramSyntaxNode* program) + { + if (outerScope) { - RefPtr<ProgramSyntaxNode> program = new ProgramSyntaxNode(); + currentScope = outerScope; + } - parseSourceFile(program.Ptr()); + PushScope(program); + program->Position = CodePosition(0, 0, 0, fileName); + ParseDeclBody(this, program, TokenType::EndOfFile); + PopScope(); - return program; - } + assert(currentScope == outerScope); + currentScope = nullptr; + } - RefPtr<StructSyntaxNode> Parser::ParseStruct() - { - RefPtr<StructSyntaxNode> rs = new StructSyntaxNode(); - FillPosition(rs.Ptr()); - ReadToken("struct"); + RefPtr<ProgramSyntaxNode> Parser::ParseProgram() + { + RefPtr<ProgramSyntaxNode> program = new ProgramSyntaxNode(); - // TODO: support `struct` declaration without tag - rs->Name = ReadToken(TokenType::Identifier); + parseSourceFile(program.Ptr()); - // We allow for an inheritance clause on a `struct` - // so that it can conform to interfaces. - parseOptionalInheritanceClause(this, rs.Ptr()); + return program; + } - parseAggTypeDeclBody(this, rs.Ptr()); + RefPtr<StructSyntaxNode> Parser::ParseStruct() + { + RefPtr<StructSyntaxNode> rs = new StructSyntaxNode(); + FillPosition(rs.Ptr()); + ReadToken("struct"); - return rs; - } + // TODO: support `struct` declaration without tag + rs->Name = ReadToken(TokenType::Identifier); - RefPtr<ClassSyntaxNode> Parser::ParseClass() - { - RefPtr<ClassSyntaxNode> 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; - } + // We allow for an inheritance clause on a `struct` + // so that it can conform to interfaces. + parseOptionalInheritanceClause(this, rs.Ptr()); - static RefPtr<StatementSyntaxNode> ParseSwitchStmt(Parser* parser) - { - RefPtr<SwitchStmt> stmt = new SwitchStmt(); - parser->FillPosition(stmt.Ptr()); - parser->ReadToken("switch"); - parser->ReadToken(TokenType::LParent); - stmt->condition = parser->ParseExpression(); - parser->ReadToken(TokenType::RParent); - stmt->body = parser->ParseBlockStatement(); - return stmt; - } + parseAggTypeDeclBody(this, rs.Ptr()); - static RefPtr<StatementSyntaxNode> ParseCaseStmt(Parser* parser) - { - RefPtr<CaseStmt> stmt = new CaseStmt(); - parser->FillPosition(stmt.Ptr()); - parser->ReadToken("case"); - stmt->expr = parser->ParseExpression(); - parser->ReadToken(TokenType::Colon); - return stmt; - } + return rs; + } - static RefPtr<StatementSyntaxNode> ParseDefaultStmt(Parser* parser) - { - RefPtr<DefaultStmt> stmt = new DefaultStmt(); - parser->FillPosition(stmt.Ptr()); - parser->ReadToken("default"); - parser->ReadToken(TokenType::Colon); - return stmt; - } + RefPtr<ClassSyntaxNode> Parser::ParseClass() + { + RefPtr<ClassSyntaxNode> 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; + } - static bool peekTypeName(Parser* parser) - { - if(!parser->LookAheadToken(TokenType::Identifier)) - return false; + static RefPtr<StatementSyntaxNode> ParseSwitchStmt(Parser* parser) + { + RefPtr<SwitchStmt> stmt = new SwitchStmt(); + parser->FillPosition(stmt.Ptr()); + parser->ReadToken("switch"); + parser->ReadToken(TokenType::LParent); + stmt->condition = parser->ParseExpression(); + parser->ReadToken(TokenType::RParent); + stmt->body = parser->ParseBlockStatement(); + return stmt; + } - auto name = parser->tokenReader.PeekToken().Content; + static RefPtr<StatementSyntaxNode> ParseCaseStmt(Parser* parser) + { + RefPtr<CaseStmt> stmt = new CaseStmt(); + parser->FillPosition(stmt.Ptr()); + parser->ReadToken("case"); + stmt->expr = parser->ParseExpression(); + parser->ReadToken(TokenType::Colon); + return stmt; + } - auto lookupResult = LookUp(name, parser->currentScope); - if(!lookupResult.isValid() || lookupResult.isOverloaded()) - return false; + static RefPtr<StatementSyntaxNode> ParseDefaultStmt(Parser* parser) + { + RefPtr<DefaultStmt> stmt = new DefaultStmt(); + parser->FillPosition(stmt.Ptr()); + parser->ReadToken("default"); + parser->ReadToken(TokenType::Colon); + return stmt; + } - auto decl = lookupResult.item.declRef.GetDecl(); - if( auto typeDecl = dynamic_cast<AggTypeDecl*>(decl) ) - { - return true; - } - else if( auto typeVarDecl = dynamic_cast<SimpleTypeDecl*>(decl) ) - { - return true; - } - else - { - return false; - } - } + static bool peekTypeName(Parser* parser) + { + if(!parser->LookAheadToken(TokenType::Identifier)) + return false; - RefPtr<StatementSyntaxNode> Parser::ParseStatement() - { - auto modifiers = ParseModifiers(this); + auto name = parser->tokenReader.PeekToken().Content; - RefPtr<StatementSyntaxNode> 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. + auto lookupResult = LookUp(name, parser->currentScope); + if(!lookupResult.isValid() || lookupResult.isOverloaded()) + return false; - Token* startPos = tokenReader.mCursor; + auto decl = lookupResult.item.declRef.GetDecl(); + if( auto typeDecl = dynamic_cast<AggTypeDecl*>(decl) ) + { + return true; + } + else if( auto typeVarDecl = dynamic_cast<SimpleTypeDecl*>(decl) ) + { + return true; + } + else + { + return false; + } + } + + RefPtr<StatementSyntaxNode> Parser::ParseStatement() + { + auto modifiers = ParseModifiers(this); + + RefPtr<StatementSyntaxNode> 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. - // Try to parse a type (knowing that the type grammar is - // a subset of the expression grammar, and so this should - // always succeed). - RefPtr<ExpressionSyntaxNode> type = ParseType(); - // We don't actually care about the type, though, so - // don't retain it - type = nullptr; + Token* startPos = tokenReader.mCursor; - // 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; - } + // Try to parse a type (knowing that the type grammar is + // a subset of the expression grammar, and so this should + // always succeed). + RefPtr<ExpressionSyntaxNode> type = ParseType(); + // We don't actually care about the type, though, so + // don't retain it + type = nullptr; - // Fallback: reset and parse an expression + // 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 = 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(); + statement = ParseVarDeclrStatement(modifiers); + return statement; } - 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; - } + // 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(); + } - return statement; + 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; } - RefPtr<StatementSyntaxNode> Parser::ParseBlockStatement() + return statement; + } + + RefPtr<StatementSyntaxNode> Parser::ParseBlockStatement() + { + if( options.flags & SLANG_COMPILE_FLAG_NO_CHECKING ) { - if( options.flags & SLANG_COMPILE_FLAG_NO_CHECKING ) - { - // We have been asked to parse the input, but not attempt to understand it. + // We have been asked to parse the input, but not attempt to understand it. - // TODO: record start/end locations... + // TODO: record start/end locations... - List<Token> tokens; + List<Token> tokens; - ReadToken(TokenType::LBrace); + ReadToken(TokenType::LBrace); - int depth = 1; - for( ;;) + int depth = 1; + for( ;;) + { + switch( tokenReader.PeekTokenType() ) { - switch( tokenReader.PeekTokenType() ) - { - case TokenType::EndOfFile: - goto done; - - case TokenType::RBrace: - depth--; - if(depth == 0) - goto done; - break; + case TokenType::EndOfFile: + goto done; - case TokenType::LBrace: - depth++; - break; + case TokenType::RBrace: + depth--; + if(depth == 0) + goto done; + break; - default: - break; - } + case TokenType::LBrace: + depth++; + break; - auto token = tokenReader.AdvanceToken(); - tokens.Add(token); + default: + break; } - done: - ReadToken(TokenType::RBrace); - RefPtr<UnparsedStmt> unparsedStmt = new UnparsedStmt(); - unparsedStmt->tokens = tokens; - return unparsedStmt; + auto token = tokenReader.AdvanceToken(); + tokens.Add(token); } + done: + ReadToken(TokenType::RBrace); - - RefPtr<ScopeDecl> scopeDecl = new ScopeDecl(); - RefPtr<BlockStatementSyntaxNode> blockStatement = new BlockStatementSyntaxNode(); - blockStatement->scopeDecl = scopeDecl; - PushScope(scopeDecl.Ptr()); - ReadToken(TokenType::LBrace); - if(!tokenReader.IsAtEnd()) - { - FillPosition(blockStatement.Ptr()); - } - while (!AdvanceIfMatch(this, TokenType::RBrace)) - { - auto stmt = ParseStatement(); - if(stmt) - { - blockStatement->Statements.Add(stmt); - } - TryRecover(this); - } - PopScope(); - return blockStatement; + RefPtr<UnparsedStmt> unparsedStmt = new UnparsedStmt(); + unparsedStmt->tokens = tokens; + return unparsedStmt; } - RefPtr<VarDeclrStatementSyntaxNode> Parser::ParseVarDeclrStatement( - Modifiers modifiers) + + RefPtr<ScopeDecl> scopeDecl = new ScopeDecl(); + RefPtr<BlockStatementSyntaxNode> blockStatement = new BlockStatementSyntaxNode(); + blockStatement->scopeDecl = scopeDecl; + PushScope(scopeDecl.Ptr()); + ReadToken(TokenType::LBrace); + if(!tokenReader.IsAtEnd()) { - RefPtr<VarDeclrStatementSyntaxNode>varDeclrStatement = new VarDeclrStatementSyntaxNode(); - - FillPosition(varDeclrStatement.Ptr()); - auto decl = ParseDeclWithModifiers(this, currentScope->containerDecl, modifiers); - varDeclrStatement->decl = decl; - return varDeclrStatement; + FillPosition(blockStatement.Ptr()); } - - RefPtr<IfStatementSyntaxNode> Parser::ParseIfStatement() + while (!AdvanceIfMatch(this, TokenType::RBrace)) { - RefPtr<IfStatementSyntaxNode> 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<ForStatementSyntaxNode> Parser::ParseForStatement() - { - RefPtr<ScopeDecl> scopeDecl = new ScopeDecl(); - RefPtr<ForStatementSyntaxNode> stmt = new ForStatementSyntaxNode(); - stmt->scopeDecl = scopeDecl; + RefPtr<VarDeclrStatementSyntaxNode> Parser::ParseVarDeclrStatement( + Modifiers modifiers) + { + RefPtr<VarDeclrStatementSyntaxNode>varDeclrStatement = new VarDeclrStatementSyntaxNode(); + + FillPosition(varDeclrStatement.Ptr()); + auto decl = ParseDeclWithModifiers(this, currentScope->containerDecl, modifiers); + varDeclrStatement->decl = decl; + return varDeclrStatement; + } + + RefPtr<IfStatementSyntaxNode> Parser::ParseIfStatement() + { + RefPtr<IfStatementSyntaxNode> 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<ForStatementSyntaxNode> Parser::ParseForStatement() + { + RefPtr<ScopeDecl> scopeDecl = new ScopeDecl(); + RefPtr<ForStatementSyntaxNode> 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 + // 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<WhileStatementSyntaxNode> Parser::ParseWhileStatement() - { - RefPtr<WhileStatementSyntaxNode> whileStatement = new WhileStatementSyntaxNode(); - FillPosition(whileStatement.Ptr()); - ReadToken("while"); - ReadToken(TokenType::LParent); - whileStatement->Predicate = ParseExpression(); - ReadToken(TokenType::RParent); - whileStatement->Statement = ParseStatement(); - return whileStatement; - } + RefPtr<WhileStatementSyntaxNode> Parser::ParseWhileStatement() + { + RefPtr<WhileStatementSyntaxNode> whileStatement = new WhileStatementSyntaxNode(); + FillPosition(whileStatement.Ptr()); + ReadToken("while"); + ReadToken(TokenType::LParent); + whileStatement->Predicate = ParseExpression(); + ReadToken(TokenType::RParent); + whileStatement->Statement = ParseStatement(); + return whileStatement; + } - RefPtr<DoWhileStatementSyntaxNode> Parser::ParseDoWhileStatement() - { - RefPtr<DoWhileStatementSyntaxNode> 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<DoWhileStatementSyntaxNode> Parser::ParseDoWhileStatement() + { + RefPtr<DoWhileStatementSyntaxNode> 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<BreakStatementSyntaxNode> Parser::ParseBreakStatement() - { - RefPtr<BreakStatementSyntaxNode> breakStatement = new BreakStatementSyntaxNode(); - FillPosition(breakStatement.Ptr()); - ReadToken("break"); - ReadToken(TokenType::Semicolon); - return breakStatement; - } + RefPtr<BreakStatementSyntaxNode> Parser::ParseBreakStatement() + { + RefPtr<BreakStatementSyntaxNode> breakStatement = new BreakStatementSyntaxNode(); + FillPosition(breakStatement.Ptr()); + ReadToken("break"); + ReadToken(TokenType::Semicolon); + return breakStatement; + } - RefPtr<ContinueStatementSyntaxNode> Parser::ParseContinueStatement() - { - RefPtr<ContinueStatementSyntaxNode> continueStatement = new ContinueStatementSyntaxNode(); - FillPosition(continueStatement.Ptr()); - ReadToken("continue"); - ReadToken(TokenType::Semicolon); - return continueStatement; - } + RefPtr<ContinueStatementSyntaxNode> Parser::ParseContinueStatement() + { + RefPtr<ContinueStatementSyntaxNode> continueStatement = new ContinueStatementSyntaxNode(); + FillPosition(continueStatement.Ptr()); + ReadToken("continue"); + ReadToken(TokenType::Semicolon); + return continueStatement; + } - RefPtr<ReturnStatementSyntaxNode> Parser::ParseReturnStatement() - { - RefPtr<ReturnStatementSyntaxNode> returnStatement = new ReturnStatementSyntaxNode(); - FillPosition(returnStatement.Ptr()); - ReadToken("return"); - if (!LookAheadToken(TokenType::Semicolon)) - returnStatement->Expression = ParseExpression(); - ReadToken(TokenType::Semicolon); - return returnStatement; - } + RefPtr<ReturnStatementSyntaxNode> Parser::ParseReturnStatement() + { + RefPtr<ReturnStatementSyntaxNode> returnStatement = new ReturnStatementSyntaxNode(); + FillPosition(returnStatement.Ptr()); + ReadToken("return"); + if (!LookAheadToken(TokenType::Semicolon)) + returnStatement->Expression = ParseExpression(); + ReadToken(TokenType::Semicolon); + return returnStatement; + } - RefPtr<ExpressionStatementSyntaxNode> Parser::ParseExpressionStatement() - { - RefPtr<ExpressionStatementSyntaxNode> statement = new ExpressionStatementSyntaxNode(); + RefPtr<ExpressionStatementSyntaxNode> Parser::ParseExpressionStatement() + { + RefPtr<ExpressionStatementSyntaxNode> 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<ParameterSyntaxNode> Parser::ParseParameter() - { - RefPtr<ParameterSyntaxNode> parameter = new ParameterSyntaxNode(); - parameter->modifiers = ParseModifiers(this); + RefPtr<ParameterSyntaxNode> Parser::ParseParameter() + { + RefPtr<ParameterSyntaxNode> 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<ExpressionSyntaxNode> Parser::ParseType() + RefPtr<ExpressionSyntaxNode> 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<IndexExpressionSyntaxNode> arrType = new IndexExpressionSyntaxNode(); + arrType->Position = typeExpr->Position; + arrType->BaseExpression = typeExpr; + ReadToken(TokenType::LBracket); + if (!LookAheadToken(TokenType::RBracket)) { - RefPtr<IndexExpressionSyntaxNode> 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<ExpressionSyntaxNode> parseOperator(Parser* parser) + static RefPtr<ExpressionSyntaxNode> 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<ExpressionSyntaxNode> Parser::ParseExpression(Precedence level) + RefPtr<ExpressionSyntaxNode> 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<SelectExpressionSyntaxNode> select = new SelectExpressionSyntaxNode(); - FillPosition(select.Ptr()); + RefPtr<SelectExpressionSyntaxNode> 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<OperatorExpressionSyntaxNode> tmp = new InfixExpr(); - tmp->FunctionExpr = parseOperator(this); + RefPtr<OperatorExpressionSyntaxNode> 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<OperatorExpressionSyntaxNode> tmp = new InfixExpr(); - tmp->Arguments.Add(left); - FillPosition(tmp.Ptr()); - tmp->FunctionExpr = parseOperator(this); - tmp->Arguments.Add(ParseExpression(level)); - left = tmp; - } - return left; + RefPtr<OperatorExpressionSyntaxNode> tmp = new InfixExpr(); + tmp->Arguments.Add(left); + FillPosition(tmp.Ptr()); + tmp->FunctionExpr = parseOperator(this); + tmp->Arguments.Add(ParseExpression(level)); + left = tmp; } + return left; } } + } + + RefPtr<ExpressionSyntaxNode> Parser::ParseLeafExpression() + { + RefPtr<ExpressionSyntaxNode> rs; + if (LookAheadToken(TokenType::OpInc) || + LookAheadToken(TokenType::OpDec) || + LookAheadToken(TokenType::OpNot) || + LookAheadToken(TokenType::OpBitNot) || + LookAheadToken(TokenType::OpSub)) + { + RefPtr<OperatorExpressionSyntaxNode> unaryExpr = new PrefixExpr(); + FillPosition(unaryExpr.Ptr()); + unaryExpr->FunctionExpr = parseOperator(this); + unaryExpr->Arguments.Add(ParseLeafExpression()); + rs = unaryExpr; + return rs; + } - RefPtr<ExpressionSyntaxNode> Parser::ParseLeafExpression() + if (LookAheadToken(TokenType::LParent)) { - RefPtr<ExpressionSyntaxNode> rs; - if (LookAheadToken(TokenType::OpInc) || - LookAheadToken(TokenType::OpDec) || - LookAheadToken(TokenType::OpNot) || - LookAheadToken(TokenType::OpBitNot) || - LookAheadToken(TokenType::OpSub)) + ReadToken(TokenType::LParent); + RefPtr<ExpressionSyntaxNode> expr; + if (peekTypeName(this) && LookAheadToken(TokenType::RParent, 1)) { - RefPtr<OperatorExpressionSyntaxNode> unaryExpr = new PrefixExpr(); - FillPosition(unaryExpr.Ptr()); - unaryExpr->FunctionExpr = parseOperator(this); - unaryExpr->Arguments.Add(ParseLeafExpression()); - rs = unaryExpr; - return rs; + RefPtr<TypeCastExpressionSyntaxNode> 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<ExpressionSyntaxNode> expr; - if (peekTypeName(this) && LookAheadToken(TokenType::RParent, 1)) - { - RefPtr<TypeCastExpressionSyntaxNode> 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<InitializerListExpr> initExpr = new InitializerListExpr(); - FillPosition(initExpr.Ptr()); + rs = expr; + } + else if( LookAheadToken(TokenType::LBrace) ) + { + RefPtr<InitializerListExpr> initExpr = new InitializerListExpr(); + FillPosition(initExpr.Ptr()); + + // Initializer list + ReadToken(TokenType::LBrace); - // Initializer list - ReadToken(TokenType::LBrace); + List<RefPtr<ExpressionSyntaxNode>> exprs; - List<RefPtr<ExpressionSyntaxNode>> 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<ConstantExpressionSyntaxNode> 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<ConstantExpressionSyntaxNode> 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<VarExpressionSyntaxNode> 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<ConstantExpressionSyntaxNode> 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<OperatorExpressionSyntaxNode> 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<ConstantExpressionSyntaxNode> 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<OperatorExpressionSyntaxNode> 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<VarExpressionSyntaxNode> varExpr = new VarExpressionSyntaxNode(); - varExpr->scope = currentScope.Ptr(); - FillPosition(varExpr.Ptr()); - auto token = ReadToken(TokenType::Identifier); - varExpr->Variable = token.Content; - rs = varExpr; + RefPtr<IndexExpressionSyntaxNode> 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<OperatorExpressionSyntaxNode> unaryExpr = new PostfixExpr(); - FillPosition(unaryExpr.Ptr()); - unaryExpr->FunctionExpr = parseOperator(this); - unaryExpr->Arguments.Add(rs); - rs = unaryExpr; - } - else if (LookAheadToken(TokenType::OpDec)) - { - RefPtr<OperatorExpressionSyntaxNode> unaryExpr = new PostfixExpr(); - FillPosition(unaryExpr.Ptr()); - unaryExpr->FunctionExpr = parseOperator(this); - unaryExpr->Arguments.Add(rs); - rs = unaryExpr; - } - else if (LookAheadToken(TokenType::LBracket)) - { - RefPtr<IndexExpressionSyntaxNode> 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<InvokeExpressionSyntaxNode> invokeExpr = new InvokeExpressionSyntaxNode(); + invokeExpr->FunctionExpr = rs; + FillPosition(invokeExpr.Ptr()); + ReadToken(TokenType::LParent); + while (!tokenReader.IsAtEnd()) { - RefPtr<InvokeExpressionSyntaxNode> 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<MemberExpressionSyntaxNode> 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<MemberExpressionSyntaxNode> 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<Scope> 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<Scope> const&outerScope) + { + Parser parser(options, tokens, sink, fileName, outerScope); + return parser.parseSourceFile(translationUnitSyntax); } -}
\ No newline at end of file +} |
