summaryrefslogtreecommitdiffstats
path: root/source/slang/parser.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-06-09 11:34:21 -0700
committerTim Foley <tfoley@nvidia.com>2017-06-09 13:44:59 -0700
commitfcf83dbf9effab3bd98bad2b83b2468b7eb05cfd (patch)
tree41047c94883b86ec085a81597391ce3ef557cd43 /source/slang/parser.cpp
parent52e8d4b9a27ab0060f874c3a63ab531847be35c0 (diff)
Initial import of code.
Diffstat (limited to 'source/slang/parser.cpp')
-rw-r--r--source/slang/parser.cpp3106
1 files changed, 3106 insertions, 0 deletions
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
new file mode 100644
index 000000000..773e3b74b
--- /dev/null
+++ b/source/slang/parser.cpp
@@ -0,0 +1,3106 @@
+#include "Parser.h"
+
+#include <assert.h>
+
+#include "lookup.h"
+
+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
+ {
+ 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);
+
+ static RefPtr<Modifier> ParseOptSemantics(
+ Parser* parser);
+
+ static void ParseOptSemantics(
+ Parser* parser,
+ Decl* decl);
+
+ static RefPtr<DeclBase> ParseDecl(
+ Parser* parser,
+ ContainerDecl* containerDecl);
+
+ static RefPtr<Decl> ParseSingleDecl(
+ Parser* parser,
+ ContainerDecl* containerDecl);
+
+ //
+
+ static void Unexpected(
+ Parser* parser)
+ {
+ // Don't emit "unexpected token" errors if we are in recovering mode
+ if (!parser->isRecovering)
+ {
+ parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedToken,
+ parser->tokenReader.PeekTokenType());
+
+ // Switch into recovery mode, to suppress additional errors
+ parser->isRecovering = true;
+ }
+ }
+
+ static void Unexpected(
+ Parser* parser,
+ char const* expected)
+ {
+ // Don't emit "unexpected token" errors if we are in recovering mode
+ if (!parser->isRecovering)
+ {
+ parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedTokenExpectedTokenName,
+ parser->tokenReader.PeekTokenType(),
+ expected);
+
+ // Switch into recovery mode, to suppress additional errors
+ parser->isRecovering = true;
+ }
+ }
+
+ static void Unexpected(
+ Parser* parser,
+ TokenType expected)
+ {
+ // Don't emit "unexpected token" errors if we are in recovering mode
+ if (!parser->isRecovering)
+ {
+ parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::unexpectedTokenExpectedTokenType,
+ parser->tokenReader.PeekTokenType(),
+ expected);
+
+ // Switch into recovery mode, to suppress additional errors
+ parser->isRecovering = true;
+ }
+ }
+
+ static TokenType SkipToMatchingToken(TokenReader* reader, TokenType tokenType);
+
+ // Skip a singel balanced token, which is either a single token in
+ // the common case, or a matched pair of tokens for `()`, `[]`, and `{}`
+ static TokenType SkipBalancedToken(
+ TokenReader* reader)
+ {
+ TokenType tokenType = reader->AdvanceToken().Type;
+ switch (tokenType)
+ {
+ default:
+ break;
+
+ case TokenType::LParent: tokenType = SkipToMatchingToken(reader, TokenType::RParent); break;
+ case TokenType::LBrace: tokenType = SkipToMatchingToken(reader, TokenType::RBrace); break;
+ case TokenType::LBracket: tokenType = SkipToMatchingToken(reader, TokenType::RBracket); break;
+ }
+ return tokenType;
+ }
+
+ // Skip balanced
+ static TokenType SkipToMatchingToken(
+ TokenReader* reader,
+ TokenType tokenType)
+ {
+ for (;;)
+ {
+ if (reader->IsAtEnd()) return TokenType::EndOfFile;
+ if (reader->PeekTokenType() == tokenType)
+ {
+ reader->AdvanceToken();
+ return tokenType;
+ }
+ SkipBalancedToken(reader);
+ }
+ }
+
+ // Is the given token type one that is used to "close" a
+ // balanced construct.
+ static bool IsClosingToken(TokenType tokenType)
+ {
+ switch (tokenType)
+ {
+ case TokenType::EndOfFile:
+ case TokenType::RBracket:
+ case TokenType::RParent:
+ case TokenType::RBrace:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+
+ // Expect an identifier token with the given content, and consume it.
+ Token Parser::ReadToken(const char* expected)
+ {
+ if (tokenReader.PeekTokenType() == TokenType::Identifier
+ && tokenReader.PeekToken().Content == expected)
+ {
+ isRecovering = false;
+ return tokenReader.AdvanceToken();
+ }
+
+ if (!isRecovering)
+ {
+ Unexpected(this, expected);
+ return tokenReader.PeekToken();
+ }
+ else
+ {
+ // Try to find a place to recover
+ for (;;)
+ {
+ // The token we expected?
+ // Then exit recovery mode and pretend like all is well.
+ if (tokenReader.PeekTokenType() == TokenType::Identifier
+ && tokenReader.PeekToken().Content == expected)
+ {
+ isRecovering = false;
+ return tokenReader.AdvanceToken();
+ }
+
+
+ // Don't skip past any "closing" tokens.
+ if (IsClosingToken(tokenReader.PeekTokenType()))
+ {
+ return tokenReader.PeekToken();
+ }
+
+ // Skip balanced tokens and try again.
+ SkipBalancedToken(&tokenReader);
+ }
+ }
+ }
+
+ Token Parser::ReadToken()
+ {
+ return tokenReader.AdvanceToken();
+ }
+
+ static bool TryRecover(
+ Parser* parser,
+ TokenType const* recoverBefore,
+ int recoverBeforeCount,
+ TokenType const* recoverAfter,
+ int recoverAfterCount)
+ {
+ if (!parser->isRecovering)
+ return true;
+
+ // Determine if we are looking for a closing token at all...
+ bool lookingForClose = false;
+ 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;
+ }
+
+ TokenReader* tokenReader = &parser->tokenReader;
+ for (;;)
+ {
+ TokenType peek = tokenReader->PeekTokenType();
+
+ // Is the next token in our recover-before set?
+ // If so, then we have recovered successfully!
+ for (int ii = 0; ii < recoverBeforeCount; ++ii)
+ {
+ if (peek == recoverBefore[ii])
+ {
+ parser->isRecovering = false;
+ return true;
+ }
+ }
+
+ // If we are looking at a token in our recover-after set,
+ // then consume it and recover
+ for (int ii = 0; ii < recoverAfterCount; ++ii)
+ {
+ if (peek == recoverAfter[ii])
+ {
+ tokenReader->AdvanceToken();
+ parser->isRecovering = false;
+ return true;
+ }
+ }
+
+ // Don't try to skip past end of file
+ if (peek == TokenType::EndOfFile)
+ return false;
+
+ switch (peek)
+ {
+ // Don't skip past simple "closing" tokens, *unless*
+ // we are looking for a closing token
+ case TokenType::RParent:
+ case TokenType::RBracket:
+ if (!lookingForClose)
+ return false;
+ break;
+
+ // never skip a `}`, to avoid spurious errors
+ case TokenType::RBrace:
+ return false;
+ }
+
+ // Skip balanced tokens and try again.
+ TokenType skipped = SkipBalancedToken(tokenReader);
+
+ // If we happened to find a matched pair of tokens, and
+ // the end of it was a token we were looking for,
+ // then recover here
+ for (int ii = 0; ii < recoverAfterCount; ++ii)
+ {
+ if (skipped == recoverAfter[ii])
+ {
+ parser->isRecovering = false;
+ return true;
+ }
+ }
+ }
+ }
+
+ static bool TryRecoverBefore(
+ Parser* parser,
+ TokenType before0)
+ {
+ TokenType recoverBefore[] = { before0 };
+ return TryRecover(parser, recoverBefore, 1, nullptr, 0);
+ }
+
+ // Default recovery strategy, to use inside `{}`-delimeted blocks.
+ static bool TryRecover(
+ Parser* parser)
+ {
+ TokenType recoverBefore[] = { TokenType::RBrace };
+ TokenType recoverAfter[] = { TokenType::Semicolon };
+ return TryRecover(parser, recoverBefore, 1, recoverAfter, 1);
+ }
+
+ Token Parser::ReadToken(TokenType expected)
+ {
+ if (tokenReader.PeekTokenType() == expected)
+ {
+ isRecovering = false;
+ return tokenReader.AdvanceToken();
+ }
+
+ if (!isRecovering)
+ {
+ Unexpected(this, expected);
+ return tokenReader.PeekToken();
+ }
+ else
+ {
+ // Try to find a place to recover
+ if (TryRecoverBefore(this, expected))
+ {
+ isRecovering = false;
+ return tokenReader.AdvanceToken();
+ }
+
+ return tokenReader.PeekToken();
+ }
+ }
+
+ bool Parser::LookAheadToken(const char * string, int offset)
+ {
+ TokenReader r = tokenReader;
+ for (int ii = 0; ii < offset; ++ii)
+ r.AdvanceToken();
+
+ return r.PeekTokenType() == TokenType::Identifier
+ && r.PeekToken().Content == string;
+ }
+
+ bool Parser::LookAheadToken(TokenType type, int offset)
+ {
+ TokenReader r = tokenReader;
+ for (int ii = 0; ii < offset; ++ii)
+ r.AdvanceToken();
+
+ return r.PeekTokenType() == type;
+ }
+
+ // Consume a token and return true it if matches, otherwise false
+ bool AdvanceIf(Parser* parser, TokenType tokenType)
+ {
+ if (parser->LookAheadToken(tokenType))
+ {
+ parser->ReadToken();
+ return true;
+ }
+ return false;
+ }
+
+ // Consume a token and return true it if matches, otherwise false
+ bool AdvanceIf(Parser* parser, char const* text)
+ {
+ if (parser->LookAheadToken(text))
+ {
+ parser->ReadToken();
+ return true;
+ }
+ return false;
+ }
+
+ // Consume a token and return true if it matches, otherwise check
+ // for end-of-file and expect that token (potentially producing
+ // an error) and return true to maintain forward progress.
+ // Otherwise return false.
+ bool AdvanceIfMatch(Parser* parser, TokenType tokenType)
+ {
+ // If we've run into a syntax error, but haven't recovered inside
+ // the block, then try to recover here.
+ if (parser->isRecovering)
+ {
+ TryRecoverBefore(parser, tokenType);
+ }
+ if (AdvanceIf(parser, tokenType))
+ return true;
+ if (parser->tokenReader.PeekTokenType() == TokenType::EndOfFile)
+ {
+ parser->ReadToken(tokenType);
+ return true;
+ }
+ return false;
+ }
+
+ RefPtr<ProgramSyntaxNode> Parser::Parse()
+ {
+ return ParseProgram();
+ }
+
+ RefPtr<TypeDefDecl> ParseTypeDef(Parser* parser)
+ {
+ // Consume the `typedef` keyword
+ parser->ReadToken("typedef");
+
+ // TODO(tfoley): parse an actual declarator
+ auto type = parser->ParseTypeExp();
+
+ auto nameToken = parser->ReadToken(TokenType::Identifier);
+
+ RefPtr<TypeDefDecl> typeDefDecl = new TypeDefDecl();
+ typeDefDecl->Name = nameToken;
+ typeDefDecl->Type = type;
+
+ return typeDefDecl;
+ }
+
+ // Add a modifier to a list of modifiers being built
+ static void AddModifier(RefPtr<Modifier>** ioModifierLink, RefPtr<Modifier> modifier)
+ {
+ RefPtr<Modifier>*& modifierLink = *ioModifierLink;
+
+ while(*modifierLink)
+ modifierLink = &(*modifierLink)->next;
+
+ *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)
+ {
+ parser->ReadToken(TokenType::LBracket);
+ for(;;)
+ {
+ auto nameToken = parser->ReadToken(TokenType::Identifier);
+ RefPtr<HLSLUncheckedAttribute> modifier = new HLSLUncheckedAttribute();
+ modifier->nameToken = nameToken;
+
+ if (AdvanceIf(parser, TokenType::LParent))
+ {
+ // HLSL-style `[name(arg0, ...)]` attribute
+
+ while (!AdvanceIfMatch(parser, TokenType::RParent))
+ {
+ auto arg = parser->ParseArgExpr();
+ if (arg)
+ {
+ modifier->args.Add(arg);
+ }
+
+ if (AdvanceIfMatch(parser, TokenType::RParent))
+ break;
+
+ parser->ReadToken(TokenType::Comma);
+ }
+ }
+ AddModifier(ioModifierLink, modifier);
+
+
+ if (AdvanceIfMatch(parser, TokenType::RBracket))
+ break;
+
+ parser->ReadToken(TokenType::Comma);
+ }
+ }
+
+ 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"))
+ {
+ auto modifier = new IntrinsicModifier();
+ modifier->Position = loc;
+
+ if (AdvanceIf(parser, TokenType::LParent))
+ {
+ if (parser->LookAheadToken(TokenType::IntLiterial))
+ {
+ modifier->op = (IntrinsicOp)StringToInt(parser->ReadToken().Content);
+ }
+ 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);
+ }
+
+ AddModifier(&modifierLink, modifier);
+ }
+
+
+ else if (AdvanceIf(parser, "layout"))
+ {
+ parser->ReadToken(TokenType::LParent);
+ while (!AdvanceIfMatch(parser, TokenType::RParent))
+ {
+ auto nameToken = parser->ReadToken(TokenType::Identifier);
+
+ 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()
+
+ CASE(constant_id, GLSLConstantIDLayoutModifier);
+ CASE(binding, GLSLBindingLayoutModifier);
+ CASE(set, GLSLSetLayoutModifier);
+ CASE(location, GLSLLocationLayoutModifier);
+
+ #undef CASE
+ else
+ {
+ modifier = new GLSLUnparsedLayoutModifier();
+ }
+
+ modifier->nameToken = nameToken;
+
+ if(AdvanceIf(parser, TokenType::OpAssign))
+ {
+ modifier->valToken = parser->ReadToken(TokenType::IntLiterial);
+ }
+
+ AddModifier(&modifierLink, modifier);
+
+ if (AdvanceIf(parser, TokenType::RParent))
+ break;
+ parser->ReadToken(TokenType::Comma);
+ }
+ }
+ 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))
+ {
+ 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.
+
+ // 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) )
+ {
+ LookupResult lookupResult = LookUp(
+ parser->tokenReader.PeekToken().Content,
+ parser->currentScope);
+
+ if( lookupResult.isValid() && !lookupResult.isOverloaded() )
+ {
+ auto& item = lookupResult.item;
+ auto decl = item.declRef.GetDecl();
+
+ if( auto modifierDecl = dynamic_cast<ModifierDecl*>(decl) )
+ {
+ // 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");
+ }
+ }
+ }
+ }
+
+ // Done with modifier list
+ return modifiers;
+ }
+ }
+ }
+
+ static RefPtr<Decl> ParseUsing(
+ Parser* parser)
+ {
+ parser->ReadToken("using");
+ if (parser->tokenReader.PeekTokenType() == TokenType::StringLiterial)
+ {
+ auto usingDecl = new UsingFileDecl();
+ usingDecl->fileName = parser->ReadToken(TokenType::StringLiterial);
+ parser->ReadToken(TokenType::Semicolon);
+ return usingDecl;
+ }
+ else
+ {
+ unexpected();
+ }
+ }
+
+ static Token ParseDeclName(
+ Parser* parser)
+ {
+ Token name;
+ if (AdvanceIf(parser, "operator"))
+ {
+ 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;
+
+ // 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
+ {
+ // Different cases of declarator appear as "flavors" here
+ enum class Flavor
+ {
+ Name,
+ Pointer,
+ Array,
+ };
+ Flavor flavor;
+ };
+
+ // The most common case of declarator uses a simple name
+ struct NameDeclarator : Declarator
+ {
+ Token nameToken;
+ };
+
+ // A declarator that declares a pointer type
+ struct PointerDeclarator : Declarator
+ {
+ // location of the `*` token
+ CodePosition starLoc;
+
+ RefPtr<Declarator> inner;
+ };
+
+ // A declarator that declares an array type
+ struct ArrayDeclarator : Declarator
+ {
+ RefPtr<Declarator> inner;
+
+ // location of the `[` token
+ CodePosition openBracketLoc;
+
+ // The expression that yields the element count, or NULL
+ RefPtr<ExpressionSyntaxNode> elementCountExpr;
+ };
+
+ // "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)
+ {
+ member->ParentDecl = container.Ptr();
+ container->Members.Add(member);
+
+ container->memberDictionaryIsValid = false;
+ }
+ }
+
+ static void AddMember(RefPtr<Scope> scope, RefPtr<Decl> member)
+ {
+ if (scope)
+ {
+ AddMember(scope->containerDecl, member);
+ }
+ }
+
+ static void parseParameterList(
+ Parser* parser,
+ RefPtr<CallableDecl> decl)
+ {
+ parser->ReadToken(TokenType::LParent);
+
+ // Allow a declaration to use the keyword `void` for a parameter list,
+ // since that was required in ancient C, and continues to be supported
+ // in a bunc hof its derivatives even if it is a Bad Design Choice
+ //
+ // TODO: conditionalize this so we don't keep this around for "pure"
+ // Slang code
+ if( parser->LookAheadToken("void") && parser->LookAheadToken(TokenType::RParent, 1) )
+ {
+ parser->ReadToken("void");
+ parser->ReadToken(TokenType::RParent);
+ return;
+ }
+
+ while (!AdvanceIfMatch(parser, TokenType::RParent))
+ {
+ AddMember(decl, parser->ParseParameter());
+ if (AdvanceIf(parser, TokenType::RParent))
+ break;
+ parser->ReadToken(TokenType::Comma);
+ }
+ }
+
+ static void ParseFuncDeclHeader(
+ Parser* parser,
+ DeclaratorInfo const& declaratorInfo,
+ RefPtr<FunctionSyntaxNode> decl)
+ {
+ parser->PushScope(decl.Ptr());
+
+ parser->FillPosition(decl.Ptr());
+ decl->Position = declaratorInfo.nameToken.Position;
+
+ decl->Name = declaratorInfo.nameToken;
+ decl->ReturnType = TypeExp(declaratorInfo.typeSpec);
+ parseParameterList(parser, decl);
+ ParseOptSemantics(parser, decl.Ptr());
+ }
+
+ static RefPtr<Decl> ParseFuncDecl(
+ Parser* parser,
+ ContainerDecl* /*containerDecl*/,
+ DeclaratorInfo const& declaratorInfo)
+ {
+ RefPtr<FunctionSyntaxNode> decl = new FunctionSyntaxNode();
+ ParseFuncDeclHeader(parser, declaratorInfo, decl);
+
+ if (AdvanceIf(parser, TokenType::Semicolon))
+ {
+ // empty body
+ }
+ else
+ {
+ decl->Body = parser->ParseBlockStatement();
+ }
+
+ parser->PopScope();
+ return decl;
+ }
+
+ 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;
+
+ RefPtr<Modifier>* link = &decl->modifiers.first;
+ while (*link)
+ {
+ 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());
+
+ if( declaratorInfo.nameToken.Type == TokenType::Unknown )
+ {
+ // 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);
+
+ decl->Expr = declaratorInfo.initializer;
+ }
+
+ static RefPtr<Declarator> ParseDeclarator(Parser* parser);
+
+ static RefPtr<Declarator> ParseDirectAbstractDeclarator(
+ Parser* parser)
+ {
+ RefPtr<Declarator> declarator;
+ switch( parser->tokenReader.PeekTokenType() )
+ {
+ case TokenType::Identifier:
+ {
+ auto nameDeclarator = new NameDeclarator();
+ nameDeclarator->flavor = Declarator::Flavor::Name;
+ nameDeclarator->nameToken = ParseDeclName(parser);
+ declarator = nameDeclarator;
+ }
+ break;
+
+ case TokenType::LParent:
+ {
+ // Note(tfoley): This is a point where disambiguation is required.
+ // We could be looking at an abstract declarator for a function-type
+ // parameter:
+ //
+ // void F( int(int) );
+ //
+ // Or we could be looking at the use of parenthesese in an ordinary
+ // declarator:
+ //
+ // void (*f)(int);
+ //
+ // The difference really doesn't matter right now, but we err in
+ // the direction of assuming the second case.
+ parser->ReadToken(TokenType::LParent);
+ declarator = ParseDeclarator(parser);
+ parser->ReadToken(TokenType::RParent);
+ }
+ break;
+
+ default:
+ // an empty declarator is allowed
+ return nullptr;
+ }
+
+ // postifx additions
+ for( ;;)
+ {
+ switch( parser->tokenReader.PeekTokenType() )
+ {
+ case TokenType::LBracket:
+ {
+ auto arrayDeclarator = new ArrayDeclarator();
+ arrayDeclarator->openBracketLoc = parser->tokenReader.PeekLoc();
+ arrayDeclarator->flavor = Declarator::Flavor::Array;
+ arrayDeclarator->inner = declarator;
+
+ parser->ReadToken(TokenType::LBracket);
+ if( parser->tokenReader.PeekTokenType() != TokenType::RBracket )
+ {
+ arrayDeclarator->elementCountExpr = parser->ParseExpression();
+ }
+ parser->ReadToken(TokenType::RBracket);
+
+ declarator = arrayDeclarator;
+ continue;
+ }
+
+ case TokenType::LParent:
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ return declarator;
+ }
+
+ // Parse a declarator (or at least as much of one as we support)
+ static RefPtr<Declarator> ParseDeclarator(
+ Parser* parser)
+ {
+ if( parser->tokenReader.PeekTokenType() == TokenType::OpMul )
+ {
+ auto ptrDeclarator = new PointerDeclarator();
+ ptrDeclarator->starLoc = parser->tokenReader.PeekLoc();
+ ptrDeclarator->flavor = Declarator::Flavor::Pointer;
+
+ parser->ReadToken(TokenType::OpMul);
+
+ // TODO(tfoley): allow qualifiers like `const` here?
+
+ ptrDeclarator->inner = ParseDeclarator(parser);
+ return ptrDeclarator;
+ }
+ else
+ {
+ return ParseDirectAbstractDeclarator(parser);
+ }
+ }
+
+ // A declarator plus optional semantics and initializer
+ struct InitDeclarator
+ {
+ RefPtr<Declarator> declarator;
+ RefPtr<Modifier> semantics;
+ RefPtr<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)
+ {
+ case Declarator::Flavor::Name:
+ {
+ auto nameDeclarator = (NameDeclarator*) declarator.Ptr();
+ ioInfo->nameToken = nameDeclarator->nameToken;
+ return;
+ }
+ break;
+
+ case Declarator::Flavor::Pointer:
+ {
+ auto ptrDeclarator = (PointerDeclarator*) declarator.Ptr();
+
+ // TODO(tfoley): we don't support pointers for now
+ // ioInfo->typeSpec = new PointerTypeExpr(ioInfo->typeSpec);
+
+ declarator = ptrDeclarator->inner;
+ }
+ break;
+
+ case Declarator::Flavor::Array:
+ {
+ // TODO(tfoley): we don't support pointers for now
+ auto arrayDeclarator = (ArrayDeclarator*) declarator.Ptr();
+
+ auto arrayTypeExpr = new 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;
+ }
+ }
+ }
+
+ 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;
+
+ // 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;
+ }
+
+ if( group )
+ {
+ group->decls.Add(newDecl);
+ }
+ else
+ {
+ decl = newDecl;
+ }
+ }
+
+ RefPtr<DeclBase> getResult()
+ {
+ if(group) return group;
+ return decl;
+ }
+ };
+
+ // Pares an argument to an application of a generic
+ RefPtr<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;
+ }
+
+ // 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") )
+ {
+ 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;
+ }
+
+ 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))
+ {
+ 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;
+ }
+
+ typeSpec.expr = typeExpr;
+ return typeSpec;
+ }
+
+
+ static RefPtr<DeclBase> ParseDeclaratorDecl(
+ Parser* parser,
+ ContainerDecl* containerDecl)
+ {
+ CodePosition startPosition = parser->tokenReader.PeekLoc();
+
+ auto typeSpec = parseTypeSpec(parser);
+
+ // We may need to build up multiple declarations in a group,
+ // but the common case will be when we have just a single
+ // declaration
+ DeclGroupBuilder declGroupBuilder;
+ declGroupBuilder.startPosition = startPosition;
+
+ // The type specifier may include a declaration. E.g.,
+ // it might declare a `struct` type.
+ if(typeSpec.decl)
+ declGroupBuilder.addDecl(typeSpec.decl);
+
+ if( AdvanceIf(parser, TokenType::Semicolon) )
+ {
+ // No actual variable is being declared here, but
+ // that might not be an error.
+
+ auto result = declGroupBuilder.getResult();
+ if( !result )
+ {
+ parser->sink->diagnose(startPosition, Diagnostics::declarationDidntDeclareAnything);
+ }
+ return result;
+ }
+
+
+ InitDeclarator initDeclarator = ParseInitDeclarator(parser);
+
+ DeclaratorInfo declaratorInfo;
+ declaratorInfo.typeSpec = typeSpec.expr;
+
+
+ // Rather than parse function declarators properly for now,
+ // we'll just do a quick disambiguation here. This won't
+ // matter unless we actually decide to support function-type parameters,
+ // using C syntax.
+ //
+ if( parser->tokenReader.PeekTokenType() == TokenType::LParent
+
+ // Only parse as a function if we didn't already see mutually-exclusive
+ // constructs when parsing the declarator.
+ && !initDeclarator.initializer
+ && !initDeclarator.semantics)
+ {
+ // Looks like a function, so parse it like one.
+ UnwrapDeclarator(initDeclarator, &declaratorInfo);
+ return ParseFuncDecl(parser, containerDecl, declaratorInfo);
+ }
+
+ // Otherwise we are looking at a variable declaration, which could be one in a sequence...
+
+ if( AdvanceIf(parser, TokenType::Semicolon) )
+ {
+ // easy case: we only had a single declaration!
+ UnwrapDeclarator(initDeclarator, &declaratorInfo);
+ RefPtr<VarDeclBase> firstDecl = CreateVarDeclForContext(containerDecl);
+ CompleteVarDecl(parser, firstDecl, declaratorInfo);
+
+ declGroupBuilder.addDecl(firstDecl);
+ return declGroupBuilder.getResult();
+
+ return firstDecl;
+ }
+
+ // Otherwise we have multiple declarations in a sequence, and these
+ // declarations need to somehow share both the type spec and modifiers.
+ //
+ // If there are any errors in the type specifier, we only want to hear
+ // about it once, so we need to share structure rather than just
+ // clone syntax.
+
+ auto sharedTypeSpec = new SharedTypeExpr();
+ sharedTypeSpec->Position = typeSpec.expr->Position;
+ sharedTypeSpec->base = TypeExp(typeSpec.expr);
+
+ for(;;)
+ {
+ declaratorInfo.typeSpec = sharedTypeSpec;
+ UnwrapDeclarator(initDeclarator, &declaratorInfo);
+
+ RefPtr<VarDeclBase> varDecl = CreateVarDeclForContext(containerDecl);
+ CompleteVarDecl(parser, varDecl, declaratorInfo);
+
+ declGroupBuilder.addDecl(varDecl);
+
+ // end of the sequence?
+ if(AdvanceIf(parser, TokenType::Semicolon))
+ return declGroupBuilder.getResult();
+
+ // ad-hoc recovery, to avoid infinite loops
+ if( parser->isRecovering )
+ {
+ parser->ReadToken(TokenType::Semicolon);
+ return declGroupBuilder.getResult();
+ }
+
+ // Let's default to assuming that a missing `,`
+ // indicates the end of a declaration,
+ // where a `;` would be expected, and not
+ // a continuation of this declaration, where
+ // a `,` would be expected (this is tailoring
+ // the diagnostic message a bit).
+ //
+ // TODO: a more advanced heuristic here might
+ // look at whether the next token is on the
+ // same line, to predict whether `,` or `;`
+ // would be more likely...
+
+ if (!AdvanceIf(parser, TokenType::Comma))
+ {
+ parser->ReadToken(TokenType::Semicolon);
+ return declGroupBuilder.getResult();
+ }
+
+ // expect another variable declaration...
+ initDeclarator = ParseInitDeclarator(parser);
+ }
+ }
+
+ //
+ // layout-semantic ::= (register | packoffset) '(' register-name component-mask? ')'
+ // register-name ::= identifier
+ // component-mask ::= '.' identifier
+ //
+ static void ParseHLSLLayoutSemantic(
+ Parser* parser,
+ HLSLLayoutSemantic* semantic)
+ {
+ semantic->name = parser->ReadToken(TokenType::Identifier);
+
+ parser->ReadToken(TokenType::LParent);
+ semantic->registerName = parser->ReadToken(TokenType::Identifier);
+ if (AdvanceIf(parser, TokenType::Dot))
+ {
+ semantic->componentMask = parser->ReadToken(TokenType::Identifier);
+ }
+ parser->ReadToken(TokenType::RParent);
+ }
+
+ //
+ // 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;
+ }
+ }
+
+ //
+ // opt-semantics ::= (':' semantic)*
+ //
+ 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;
+ }
+
+ 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);
+ }
+
+ }
+
+
+ static void ParseOptSemantics(
+ Parser* parser,
+ Decl* decl)
+ {
+ AddModifiers(decl, ParseOptSemantics(parser));
+ }
+
+ 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.
+
+ // 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.
+ parser->ReadToken(TokenType::LBrace);
+ ParseDeclBody(parser, bufferDataTypeDecl.Ptr(), TokenType::RBrace);
+
+ // All HLSL buffer declarations are "transparent" in that their
+ // members are implicitly made visible in the parent scope.
+ // We achieve this by applying the transparent modifier to the variable.
+ auto transparentModifier = new TransparentModifier();
+ transparentModifier->next = bufferVarDecl->modifiers.first;
+ bufferVarDecl->modifiers.first = transparentModifier;
+
+ // Because we are constructing two declarations, we have a thorny
+ // issue that were are only supposed to return one.
+ // For now we handle this by adding the type declaration to
+ // the current scope manually, and then returning the variable
+ // declaration.
+ //
+ // Note: this means that any modifiers that have already been parsed
+ // will get attached to the variable declaration, not the type.
+ // There might be cases where we need to shuffle things around.
+
+ AddMember(parser->currentScope, bufferDataTypeDecl);
+
+ return bufferVarDecl;
+ }
+
+ static void removeModifier(
+ Modifiers& modifiers,
+ RefPtr<Modifier> modifier)
+ {
+ RefPtr<Modifier>* link = &modifiers.first;
+ while (*link)
+ {
+ if (*link == modifier)
+ {
+ *link = (*link)->next;
+ return;
+ }
+
+ link = &(*link)->next;
+ }
+ }
+
+ static RefPtr<Decl> parseGLSLBlockDecl(
+ Parser* parser,
+ Modifiers& modifiers)
+ {
+ // An GLSL block like this:
+ //
+ // uniform Foo { int a; float b; } foo;
+ //
+ // is treated as syntax sugar for a type declaration
+ // and then a global variable declaration using that type:
+ //
+ // struct $anonymous { int a; float b; };
+ // Block<$anonymous> foo;
+ //
+ // where `$anonymous` is a fresh name.
+ //
+ // If a "local name" like `foo` is not given, then
+ // we make the declaration "transparent" so that lookup
+ // will see through it to the members inside.
+
+
+ CodePosition pos = parser->tokenReader.PeekLoc();
+
+ // The initial name before the `{` is only supposed
+ // to be made visible to reflection
+ auto reflectionNameToken = parser->ReadToken(TokenType::Identifier);
+
+ // Look at the qualifiers present on the block to decide what kind
+ // of block we are looking at. Also *remove* those qualifiers so
+ // that they don't interfere with downstream work.
+ String blockWrapperTypeName;
+ if( auto uniformMod = modifiers.findModifier<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";
+ }
+
+ // 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.
+ parser->ReadToken(TokenType::LBrace);
+ ParseDeclBody(parser, blockDataTypeDecl.Ptr(), TokenType::RBrace);
+
+ if( parser->LookAheadToken(TokenType::Identifier) )
+ {
+ // The user gave an explicit name to the block,
+ // so we need to use that as our variable name
+ blockVarDecl->Name = parser->ReadToken(TokenType::Identifier);
+
+ // TODO: in this case we make actually have a more complex
+ // declarator, including `[]` brackets.
+ }
+ else
+ {
+ // synthesize a dummy name
+ blockVarDecl->Name.Content = GenerateName(parser, "SLANG_parameterBlock_" + reflectionNameToken.Content);
+
+ // Otherwise we have a transparent declaration, similar
+ // to an HLSL `cbuffer`
+ auto transparentModifier = new TransparentModifier();
+ transparentModifier->Position = pos;
+ addModifier(blockVarDecl, transparentModifier);
+ }
+
+ // Expect a trailing `;`
+ parser->ReadToken(TokenType::Semicolon);
+
+ // Because we are constructing two declarations, we have a thorny
+ // issue that were are only supposed to return one.
+ // For now we handle this by adding the type declaration to
+ // the current scope manually, and then returning the variable
+ // declaration.
+ //
+ // Note: this means that any modifiers that have already been parsed
+ // will get attached to the variable declaration, not the type.
+ // There might be cases where we need to shuffle things around.
+
+ AddMember(parser->currentScope, blockDataTypeDecl);
+
+ return blockVarDecl;
+ }
+
+
+
+
+ static RefPtr<Decl> ParseGenericParamDecl(
+ Parser* parser,
+ RefPtr<GenericDecl> genericDecl)
+ {
+ // simple syntax to introduce a value parameter
+ if (AdvanceIf(parser, "let"))
+ {
+ // default case is a type parameter
+ auto paramDecl = new GenericValueParamDecl();
+ paramDecl->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;
+ }
+ 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 paramType = DeclRefType::Create(DeclRef(paramDecl, nullptr));
+
+ 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();
+
+ AddMember(genericDecl, paramConstraint);
+
+
+ }
+ if (AdvanceIf(parser, TokenType::OpAssign))
+ {
+ paramDecl->initType = parser->ParseTypeExp();
+ }
+ return paramDecl;
+ }
+ }
+
+ 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))
+ {
+ AddMember(decl, ParseGenericParamDecl(parser, decl));
+
+if( parser->LookAheadToken(TokenType::OpGreater) )
+break;
+
+parser->ReadToken(TokenType::Comma);
+ }
+ parser->genericDepth--;
+ parser->ReadToken(TokenType::OpGreater);
+
+ 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;
+
+ parser->PopScope();
+ return decl;
+ }
+
+ static RefPtr<Decl> ParseTraitConformanceDecl(
+ Parser* parser)
+ {
+ RefPtr<TraitConformanceDecl> decl = new TraitConformanceDecl();
+ parser->FillPosition(decl.Ptr());
+ parser->ReadToken("__conforms");
+
+ decl->base = parser->ParseTypeExp();
+
+ return decl;
+ }
+
+
+ static RefPtr<ExtensionDecl> ParseExtensionDecl(Parser* parser)
+ {
+ RefPtr<ExtensionDecl> decl = new ExtensionDecl();
+ parser->FillPosition(decl.Ptr());
+ parser->ReadToken("__extension");
+ decl->targetType = parser->ParseTypeExp();
+ parser->ReadToken(TokenType::LBrace);
+ ParseDeclBody(parser, decl.Ptr(), TokenType::RBrace);
+ return decl;
+ }
+
+ static RefPtr<TraitDecl> ParseTraitDecl(Parser* parser)
+ {
+ RefPtr<TraitDecl> decl = new TraitDecl();
+ parser->FillPosition(decl.Ptr());
+ parser->ReadToken("__trait");
+ decl->Name = parser->ReadToken(TokenType::Identifier);
+
+ if( AdvanceIf(parser, TokenType::Colon) )
+ {
+ do
+ {
+ auto base = parser->ParseTypeExp();
+ decl->bases.Add(base);
+ } while( AdvanceIf(parser, TokenType::Comma) );
+ }
+
+ parser->ReadToken(TokenType::LBrace);
+ ParseDeclBody(parser, decl.Ptr(), TokenType::RBrace);
+ return decl;
+ }
+
+ static RefPtr<ConstructorDecl> ParseConstructorDecl(Parser* parser)
+ {
+ RefPtr<ConstructorDecl> decl = new ConstructorDecl();
+ parser->FillPosition(decl.Ptr());
+ parser->ReadToken("__init");
+
+ parseParameterList(parser, decl);
+
+ if( AdvanceIf(parser, TokenType::Semicolon) )
+ {
+ // empty body
+ }
+ else
+ {
+ decl->Body = parser->ParseBlockStatement();
+ }
+ 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;
+ }
+
+ if( parser->tokenReader.PeekTokenType() == TokenType::LBrace )
+ {
+ decl->Body = parser->ParseBlockStatement();
+ }
+ else
+ {
+ parser->ReadToken(TokenType::Semicolon);
+ }
+
+ return decl;
+ }
+
+ static RefPtr<SubscriptDecl> ParseSubscriptDecl(Parser* parser)
+ {
+ RefPtr<SubscriptDecl> decl = new SubscriptDecl();
+ parser->FillPosition(decl.Ptr());
+ parser->ReadToken("__subscript");
+
+ // TODO: the use of this name here is a bit magical...
+ decl->Name.Content = "operator[]";
+
+ parseParameterList(parser, decl);
+
+ if( AdvanceIf(parser, TokenType::RightArrow) )
+ {
+ decl->ReturnType = parser->ParseTypeExp();
+ }
+
+ if( AdvanceIf(parser, TokenType::LBrace) )
+ {
+ // We want to parse nested "accessor" declarations
+ while( !AdvanceIfMatch(parser, TokenType::RBrace) )
+ {
+ auto accessor = parseAccessorDecl(parser);
+ AddMember(decl, accessor);
+ }
+ }
+ else
+ {
+ parser->ReadToken(TokenType::Semicolon);
+
+ // empty body should be treated like `{ get; }`
+ }
+
+ return decl;
+ }
+
+ // Parse a declaration of a new modifier keyword
+ static RefPtr<ModifierDecl> parseModifierDecl(Parser* parser)
+ {
+ RefPtr<ModifierDecl> decl = new ModifierDecl();
+
+ // read the `__modifier` keyword
+ parser->ReadToken(TokenType::Identifier);
+
+ parser->ReadToken(TokenType::LParent);
+ decl->classNameToken = parser->ReadToken(TokenType::Identifier);
+ parser->ReadToken(TokenType::RParent);
+
+ parser->FillPosition(decl.Ptr());
+ decl->Name = parser->ReadToken(TokenType::Identifier);
+
+ parser->ReadToken(TokenType::Semicolon);
+ return 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);
+
+ // Make sure the decl is properly nested inside its lexical parent
+ if (containerDecl)
+ {
+ AddMember(containerDecl, decl);
+ }
+ }
+
+ static RefPtr<DeclBase> ParseDeclWithModifiers(
+ Parser* parser,
+ ContainerDecl* containerDecl,
+ Modifiers modifiers )
+ {
+ RefPtr<DeclBase> decl;
+
+ auto loc = parser->tokenReader.PeekLoc();
+
+ // 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("using"))
+ decl = ParseUsing(parser);
+ else if (parser->LookAheadToken("cbuffer") || parser->LookAheadToken("tbuffer"))
+ decl = ParseHLSLBufferDecl(parser);
+ else if (parser->LookAheadToken("__generic"))
+ decl = ParseGenericDecl(parser);
+ else if (parser->LookAheadToken("__conforms"))
+ decl = ParseTraitConformanceDecl(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("__trait"))
+ decl = ParseTraitDecl(parser);
+ else if(parser->LookAheadToken("__modifier"))
+ decl = parseModifierDecl(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);
+ }
+
+ 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.
+
+ auto sharedModifiers = new SharedModifiers();
+ sharedModifiers->next = modifiers.first;
+ modifiers.first = sharedModifiers;
+
+ for( auto subDecl : declGroup->decls )
+ {
+ CompleteDecl(parser, subDecl, containerDecl, modifiers);
+ }
+ }
+ }
+ return decl;
+ }
+
+ static RefPtr<DeclBase> ParseDecl(
+ Parser* parser,
+ ContainerDecl* containerDecl)
+ {
+ Modifiers modifiers = ParseModifiers(parser);
+ return ParseDeclWithModifiers(parser, containerDecl, modifiers);
+ }
+
+ static RefPtr<Decl> ParseSingleDecl(
+ Parser* parser,
+ ContainerDecl* containerDecl)
+ {
+ auto declBase = ParseDecl(parser, containerDecl);
+ if(!declBase)
+ return nullptr;
+ if( auto decl = declBase.As<Decl>() )
+ {
+ return decl;
+ }
+ else if( auto declGroup = declBase.As<DeclGroup>() )
+ {
+ if( declGroup->decls.Count() == 1 )
+ {
+ return declGroup->decls[0];
+ }
+ }
+
+ parser->sink->diagnose(declBase->Position, Diagnostics::unimplemented, "didn't expect multiple declarations here");
+ return nullptr;
+ }
+
+
+ // Parse a body consisting of declarations
+ static void ParseDeclBody(
+ Parser* parser,
+ ContainerDecl* containerDecl,
+ TokenType closingToken)
+ {
+ while(!AdvanceIfMatch(parser, closingToken))
+ {
+ ParseDecl(parser, containerDecl);
+ TryRecover(parser);
+ }
+ }
+
+ void Parser::parseSourceFile(ProgramSyntaxNode* program)
+ {
+ if (outerScope)
+ {
+ currentScope = outerScope;
+ }
+
+ PushScope(program);
+ program->Position = CodePosition(0, 0, 0, fileName);
+ ParseDeclBody(this, program, TokenType::EndOfFile);
+ PopScope();
+
+ assert(currentScope == outerScope);
+ currentScope = nullptr;
+ }
+
+ RefPtr<ProgramSyntaxNode> Parser::ParseProgram()
+ {
+ RefPtr<ProgramSyntaxNode> program = new ProgramSyntaxNode();
+
+ parseSourceFile(program.Ptr());
+
+ return program;
+ }
+
+ RefPtr<StructSyntaxNode> Parser::ParseStruct()
+ {
+ RefPtr<StructSyntaxNode> rs = new StructSyntaxNode();
+ FillPosition(rs.Ptr());
+ ReadToken("struct");
+ rs->Name = ReadToken(TokenType::Identifier);
+ ReadToken(TokenType::LBrace);
+ ParseDeclBody(this, rs.Ptr(), TokenType::RBrace);
+
+ return rs;
+ }
+
+ RefPtr<ClassSyntaxNode> Parser::ParseClass()
+ {
+ RefPtr<ClassSyntaxNode> rs = new ClassSyntaxNode();
+ FillPosition(rs.Ptr());
+ ReadToken("class");
+ rs->Name = ReadToken(TokenType::Identifier);
+ ReadToken(TokenType::LBrace);
+ ParseDeclBody(this, rs.Ptr(), TokenType::RBrace);
+ return rs;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ static RefPtr<StatementSyntaxNode> ParseDefaultStmt(Parser* parser)
+ {
+ RefPtr<DefaultStmt> stmt = new DefaultStmt();
+ parser->FillPosition(stmt.Ptr());
+ parser->ReadToken("default");
+ parser->ReadToken(TokenType::Colon);
+ return stmt;
+ }
+
+ static bool peekTypeName(Parser* parser)
+ {
+ if(!parser->LookAheadToken(TokenType::Identifier))
+ return false;
+
+ auto name = parser->tokenReader.PeekToken().Content;
+
+ auto lookupResult = LookUp(name, parser->currentScope);
+ if(!lookupResult.isValid() || lookupResult.isOverloaded())
+ return false;
+
+ 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.
+
+ Token* startPos = tokenReader.mCursor;
+
+ // 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;
+
+ // 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;
+ }
+
+ // 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();
+ }
+
+ 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;
+ }
+
+ return statement;
+ }
+
+ RefPtr<StatementSyntaxNode> Parser::ParseBlockStatement()
+ {
+ if( options.flags & SLANG_COMPILE_FLAG_NO_CHECKING )
+ {
+ // We have been asked to parse the input, but not attempt to understand it.
+
+ // TODO: record start/end locations...
+
+ List<Token> tokens;
+
+ ReadToken(TokenType::LBrace);
+
+ int depth = 1;
+ for( ;;)
+ {
+ switch( tokenReader.PeekTokenType() )
+ {
+ case TokenType::EndOfFile:
+ goto done;
+
+ case TokenType::RBrace:
+ depth--;
+ if(depth == 0)
+ goto done;
+ break;
+
+ case TokenType::LBrace:
+ depth++;
+ break;
+
+ default:
+ break;
+ }
+
+ auto token = tokenReader.AdvanceToken();
+ tokens.Add(token);
+ }
+ done:
+ ReadToken(TokenType::RBrace);
+
+ RefPtr<UnparsedStmt> unparsedStmt = new UnparsedStmt();
+ unparsedStmt->tokens = tokens;
+ return unparsedStmt;
+ }
+
+
+ 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<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
+// PushScope(scopeDecl.Ptr());
+ FillPosition(stmt.Ptr());
+ ReadToken("for");
+ ReadToken(TokenType::LParent);
+ if (peekTypeName(this))
+ {
+ stmt->InitialStatement = ParseVarDeclrStatement(Modifiers());
+ }
+ else
+ {
+ if (!LookAheadToken(TokenType::Semicolon))
+ {
+ stmt->InitialStatement = ParseExpressionStatement();
+ }
+ else
+ {
+ ReadToken(TokenType::Semicolon);
+ }
+ }
+ if (!LookAheadToken(TokenType::Semicolon))
+ stmt->PredicateExpression = ParseExpression();
+ ReadToken(TokenType::Semicolon);
+ if (!LookAheadToken(TokenType::RParent))
+ stmt->SideEffectExpression = ParseExpression();
+ ReadToken(TokenType::RParent);
+ stmt->Statement = ParseStatement();
+// 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<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<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<ExpressionStatementSyntaxNode> Parser::ParseExpressionStatement()
+ {
+ RefPtr<ExpressionStatementSyntaxNode> statement = new ExpressionStatementSyntaxNode();
+
+ FillPosition(statement.Ptr());
+ statement->Expression = ParseExpression();
+
+ ReadToken(TokenType::Semicolon);
+ return statement;
+ }
+
+ RefPtr<ParameterSyntaxNode> Parser::ParseParameter()
+ {
+ RefPtr<ParameterSyntaxNode> parameter = new ParameterSyntaxNode();
+ parameter->modifiers = ParseModifiers(this);
+
+ DeclaratorInfo declaratorInfo;
+ declaratorInfo.typeSpec = ParseType();
+
+ InitDeclarator initDeclarator = ParseInitDeclarator(this);
+ UnwrapDeclarator(initDeclarator, &declaratorInfo);
+
+ // Assume it is a variable-like declarator
+ CompleteVarDecl(this, parameter, declaratorInfo);
+ return parameter;
+ }
+
+ RefPtr<ExpressionSyntaxNode> Parser::ParseType()
+ {
+ auto typeSpec = parseTypeSpec(this);
+ if( typeSpec.decl )
+ {
+ AddMember(currentScope, typeSpec.decl);
+ }
+ auto typeExpr = typeSpec.expr;
+
+ while (LookAheadToken(TokenType::LBracket))
+ {
+ 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;
+ }
+
+ return typeExpr;
+ }
+
+
+
+ TypeExp Parser::ParseTypeExp()
+ {
+ return TypeExp(ParseType());
+ }
+
+ enum class Associativity
+ {
+ Left, Right
+ };
+
+
+
+ Associativity GetAssociativityFromLevel(Precedence level)
+ {
+ if (level == Precedence::Assignment)
+ return Associativity::Right;
+ else
+ return Associativity::Left;
+ }
+
+
+
+
+ Precedence GetOpLevel(Parser* parser, TokenType type)
+ {
+ switch(type)
+ {
+ case TokenType::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.";
+ }
+ }
+
+ static RefPtr<ExpressionSyntaxNode> parseOperator(Parser* parser)
+ {
+ Token opToken;
+ switch(parser->tokenReader.PeekTokenType())
+ {
+ case TokenType::QuestionMark:
+ opToken = parser->ReadToken();
+ opToken.Content = "?:";
+ break;
+
+ default:
+ opToken = parser->ReadToken();
+ break;
+ }
+
+ auto opExpr = new VarExpressionSyntaxNode();
+ opExpr->Variable = opToken.Content;
+ opExpr->scope = parser->currentScope;
+ opExpr->Position = opToken.Position;
+
+ return opExpr;
+
+ }
+
+ RefPtr<ExpressionSyntaxNode> Parser::ParseExpression(Precedence level)
+ {
+ if (level == Precedence::Prefix)
+ return ParseLeafExpression();
+ if (level == Precedence::TernaryConditional)
+ {
+ // parse select clause
+ auto condition = ParseExpression(Precedence(level + 1));
+ if (LookAheadToken(TokenType::QuestionMark))
+ {
+ RefPtr<SelectExpressionSyntaxNode> select = new SelectExpressionSyntaxNode();
+ FillPosition(select.Ptr());
+
+ select->Arguments.Add(condition);
+
+ select->FunctionExpr = parseOperator(this);
+
+ select->Arguments.Add(ParseExpression(level));
+ ReadToken(TokenType::Colon);
+ select->Arguments.Add(ParseExpression(level));
+ return select;
+ }
+ else
+ return condition;
+ }
+ else
+ {
+ if (GetAssociativityFromLevel(level) == Associativity::Left)
+ {
+ auto left = ParseExpression(Precedence(level + 1));
+ while (GetOpLevel(this, tokenReader.PeekTokenType()) == level)
+ {
+ RefPtr<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;
+ }
+ else
+ {
+ 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<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;
+ }
+
+ if (LookAheadToken(TokenType::LParent))
+ {
+ 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;
+ }
+ else if( LookAheadToken(TokenType::LBrace) )
+ {
+ RefPtr<InitializerListExpr> initExpr = new InitializerListExpr();
+ FillPosition(initExpr.Ptr());
+
+ // Initializer list
+ ReadToken(TokenType::LBrace);
+
+ List<RefPtr<ExpressionSyntaxNode>> exprs;
+
+ for(;;)
+ {
+ if(AdvanceIfMatch(this, TokenType::RBrace))
+ break;
+
+ auto expr = ParseArgExpr();
+ if( expr )
+ {
+ initExpr->args.Add(expr);
+ }
+
+ if(AdvanceIfMatch(this, TokenType::RBrace))
+ break;
+
+ 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;
+ }
+
+ while (!tokenReader.IsAtEnd() &&
+ (LookAheadToken(TokenType::OpInc) ||
+ LookAheadToken(TokenType::OpDec) ||
+ LookAheadToken(TokenType::Dot) ||
+ LookAheadToken(TokenType::LBracket) ||
+ 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())
+ {
+ if (!LookAheadToken(TokenType::RParent))
+ invokeExpr->Arguments.Add(ParseArgExpr());
+ else
+ {
+ break;
+ }
+ if (!LookAheadToken(TokenType::Comma))
+ break;
+ ReadToken(TokenType::Comma);
+ }
+ 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 (!rs)
+ {
+ 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