summaryrefslogtreecommitdiffstats
path: root/source/slang/parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/parser.cpp')
-rw-r--r--source/slang/parser.cpp297
1 files changed, 190 insertions, 107 deletions
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index a21d57b05..5cc048cf5 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -1163,6 +1163,7 @@ namespace Slang
parser->ReadToken(TokenType::OpGreater);
decl->inner = parseInnerFunc(decl);
decl->inner->ParentDecl = decl;
+
// A generic decl hijacks the name of the declaration
// it wraps, so that lookup can find it.
if (decl->inner)
@@ -1172,6 +1173,26 @@ namespace Slang
}
}
+ template<typename ParseFunc>
+ static RefPtr<Decl> parseOptGenericDecl(
+ Parser* parser, const ParseFunc& parseInner)
+ {
+ // TODO: may want more advanced disambiguation than this...
+ if (parser->LookAheadToken(TokenType::OpLess))
+ {
+ RefPtr<GenericDecl> genericDecl = new GenericDecl();
+ parser->FillPosition(genericDecl);
+ parser->PushScope(genericDecl);
+ ParseGenericDeclImpl(parser, genericDecl, parseInner);
+ parser->PopScope();
+ return genericDecl;
+ }
+ else
+ {
+ return parseInner(nullptr);
+ }
+ }
+
static RefPtr<RefObject> ParseGenericDecl(Parser* parser, void*)
{
RefPtr<GenericDecl> decl = new GenericDecl();
@@ -1244,79 +1265,59 @@ namespace Slang
{}
};
- static RefPtr<Decl> ParseFuncDeclHeader(
- Parser* parser,
- DeclaratorInfo const& declaratorInfo,
- RefPtr<FuncDecl> decl,
- RefPtr<GenericDecl> genDecl)
+ /// Parse an optional body statement for a declaration that can have a body.
+ static RefPtr<Stmt> parseOptBody(Parser* parser)
{
- RefPtr<Decl> retDecl = decl;
-
- parser->FillPosition(decl.Ptr());
- decl->loc = declaratorInfo.nameAndLoc.loc;
-
- decl->nameAndLoc = declaratorInfo.nameAndLoc;
-
- // if return type is a DeclRef type, we need to update its scope to use this function decl's scope
- // so that LookUp can find the generic type parameters declared after the function name
- ReplaceScopeVisitor replaceScopeVisitor;
- replaceScopeVisitor.scope = parser->currentScope;
- declaratorInfo.typeSpec->accept(&replaceScopeVisitor, nullptr);
-
- decl->ReturnType = TypeExp(declaratorInfo.typeSpec);
- auto parseFuncDeclHeaderInner = [&](GenericDecl *)
- {
- parseParameterList(parser, decl);
- ParseOptSemantics(parser, decl.Ptr());
- return decl;
- };
-
- if (parser->LookAheadToken(TokenType::OpLess))
+ if (AdvanceIf(parser, TokenType::Semicolon))
{
- // parse generic parameters
- ParseGenericDeclImpl(parser, genDecl.Ptr(), parseFuncDeclHeaderInner);
- retDecl = genDecl;
+ // empty body
+ return nullptr;
}
else
- parseFuncDeclHeaderInner(nullptr);
-
- return retDecl;
+ {
+ return parser->parseBlockStatement();
+ }
}
- static RefPtr<Decl> ParseFuncDecl(
+ /// Complete parsing of a function using traditional (C-like) declarator syntax
+ static RefPtr<Decl> parseTraditionalFuncDecl(
Parser* parser,
- ContainerDecl* /*containerDecl*/,
- DeclaratorInfo const& declaratorInfo,
- bool isGeneric)
+ DeclaratorInfo const& declaratorInfo)
{
RefPtr<FuncDecl> decl = new FuncDecl();
- RefPtr<Decl> retDecl = decl;
- RefPtr<GenericDecl> genDecl;
- if (isGeneric)
- {
- genDecl = new GenericDecl();
- parser->FillPosition(genDecl);
- parser->PushScope(genDecl);
- retDecl = genDecl;
- }
- parser->PushScope(decl.Ptr());
- ParseFuncDeclHeader(parser, declaratorInfo, decl, genDecl);
+ parser->FillPosition(decl.Ptr());
+ decl->loc = declaratorInfo.nameAndLoc.loc;
+ decl->nameAndLoc = declaratorInfo.nameAndLoc;
- if (AdvanceIf(parser, TokenType::Semicolon))
+ return parseOptGenericDecl(parser, [&](GenericDecl*)
{
- // empty body
- }
- else
- {
- decl->Body = parser->parseBlockStatement();
- }
+ // HACK: The return type of the function will already have been
+ // parsed in a scope that didn't include the function's generic
+ // parameters.
+ //
+ // We will use a visitor here to try and replace the scope associated
+ // with any name expressiosn in the reuslt type.
+ //
+ // TODO: This should be fixed by not associating scopes with
+ // such expressions at parse time, and instead pushing down scopes
+ // as part of the state during semantic checking.
+ //
+ ReplaceScopeVisitor replaceScopeVisitor;
+ replaceScopeVisitor.scope = parser->currentScope;
+ declaratorInfo.typeSpec->accept(&replaceScopeVisitor, nullptr);
+
+ decl->ReturnType = TypeExp(declaratorInfo.typeSpec);
+
+ parser->PushScope(decl);
+
+ parseParameterList(parser, decl);
+ ParseOptSemantics(parser, decl.Ptr());
+ decl->Body = parseOptBody(parser);
- parser->PopScope();
- if (isGeneric)
- {
parser->PopScope();
- }
- return retDecl;
+
+ return decl;
+ });
}
static RefPtr<VarDeclBase> CreateVarDeclForContext(
@@ -1971,7 +1972,7 @@ namespace Slang
{
// Looks like a function, so parse it like one.
UnwrapDeclarator(initDeclarator, &declaratorInfo);
- return ParseFuncDecl(parser, containerDecl, declaratorInfo, parser->tokenReader.PeekTokenType() == TokenType::OpLess);
+ return parseTraditionalFuncDecl(parser, declaratorInfo);
}
// Otherwise we are looking at a variable declaration, which could be one in a sequence...
@@ -2593,14 +2594,8 @@ namespace Slang
parseParameterList(parser, decl);
- if( AdvanceIf(parser, TokenType::Semicolon) )
- {
- // empty body
- }
- else
- {
- decl->Body = parser->parseBlockStatement();
- }
+ decl->Body = parseOptBody(parser);
+
return decl;
}
@@ -2675,9 +2670,124 @@ namespace Slang
return decl;
}
- static Token expect(Parser* parser, TokenType tokenType)
+ static bool expect(Parser* parser, TokenType tokenType)
{
- return parser->ReadToken(tokenType);
+ return parser->ReadToken(tokenType).type == tokenType;
+ }
+
+ static void parseModernVarDeclBaseCommon(
+ Parser* parser,
+ RefPtr<VarDeclBase> decl)
+ {
+ parser->FillPosition(decl.Ptr());
+ decl->nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
+
+ if(AdvanceIf(parser, TokenType::Colon))
+ {
+ decl->type = parser->ParseTypeExp();
+ }
+
+ if(AdvanceIf(parser, TokenType::OpAssign))
+ {
+ decl->initExpr = parser->ParseInitExpr();
+ }
+ }
+
+ static void parseModernVarDeclCommon(
+ Parser* parser,
+ RefPtr<VarDecl> decl)
+ {
+ parseModernVarDeclBaseCommon(parser, decl);
+ expect(parser, TokenType::Semicolon);
+ }
+
+ static RefPtr<RefObject> parseLetDecl(
+ Parser* parser, void* /*userData*/)
+ {
+ RefPtr<LetDecl> decl = new LetDecl();
+ parseModernVarDeclCommon(parser, decl);
+ return decl;
+ }
+
+ static RefPtr<RefObject> parseVarDecl(
+ Parser* parser, void* /*userData*/)
+ {
+ RefPtr<VarDecl> decl = new VarDecl();
+ parseModernVarDeclCommon(parser, decl);
+ return decl;
+ }
+
+ static RefPtr<ParamDecl> parseModernParamDecl(
+ Parser* parser)
+ {
+ RefPtr<ParamDecl> decl = new ParamDecl();
+
+ // TODO: "modern" parameters should not accept keyword-based
+ // modifiers and should only accept `[attribute]` syntax for
+ // modifiers to keep the grammar as simple as possible.
+ //
+ // Further, they should accept `out` and `in out`/`inout`
+ // before the type (e.g., `a: inout float4`).
+ //
+ decl->modifiers = ParseModifiers(parser);
+ parseModernVarDeclBaseCommon(parser, decl);
+ return decl;
+ }
+
+ static void parseModernParamList(
+ Parser* parser,
+ RefPtr<CallableDecl> decl)
+ {
+ parser->ReadToken(TokenType::LParent);
+
+ while (!AdvanceIfMatch(parser, TokenType::RParent))
+ {
+ AddMember(decl, parseModernParamDecl(parser));
+ if (AdvanceIf(parser, TokenType::RParent))
+ break;
+ parser->ReadToken(TokenType::Comma);
+ }
+ }
+
+ static RefPtr<RefObject> parseFuncDecl(
+ Parser* parser, void* /*userData*/)
+ {
+ RefPtr<FuncDecl> decl = new FuncDecl();
+
+ parser->FillPosition(decl.Ptr());
+ decl->nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
+
+ return parseOptGenericDecl(parser, [&](GenericDecl*)
+ {
+ parser->PushScope(decl.Ptr());
+ parseModernParamList(parser, decl);
+ if(AdvanceIf(parser, TokenType::RightArrow))
+ {
+ decl->ReturnType = parser->ParseTypeExp();
+ }
+ decl->Body = parseOptBody(parser);
+ parser->PopScope();
+ return decl;
+ });
+ }
+
+ static RefPtr<RefObject> parseTypeAliasDecl(
+ Parser* parser, void* /*userData*/)
+ {
+ RefPtr<TypeAliasDecl> decl = new TypeAliasDecl();
+
+ parser->FillPosition(decl.Ptr());
+ decl->nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
+
+ return parseOptGenericDecl(parser, [&](GenericDecl*)
+ {
+ if( expect(parser, TokenType::OpAssign) )
+ {
+ decl->type = parser->ParseTypeExp();
+ }
+ expect(parser, TokenType::Semicolon);
+ return decl;
+ });
}
// This is a catch-all syntax-construction callback to handle cases where
@@ -3084,36 +3194,20 @@ namespace Slang
RefPtr<Decl> Parser::ParseStruct()
{
RefPtr<StructDecl> rs = new StructDecl();
- RefPtr<Decl> retDecl = rs;
FillPosition(rs.Ptr());
ReadToken("struct");
// TODO: support `struct` declaration without tag
rs->nameAndLoc = expectIdentifier(this);
- auto parseStructInner = [&](GenericDecl*)
+ return parseOptGenericDecl(this, [&](GenericDecl*)
{
// We allow for an inheritance clause on a `struct`
// so that it can conform to interfaces.
parseOptionalInheritanceClause(this, rs.Ptr());
parseAggTypeDeclBody(this, rs.Ptr());
return rs;
- };
-
- if (LookAheadToken(TokenType::OpLess))
- {
- RefPtr<GenericDecl> genDecl = new GenericDecl();
- FillPosition(genDecl.Ptr());
- PushScope(genDecl);
- ParseGenericDeclImpl(this, genDecl.Ptr(), parseStructInner);
- PopScope();
- retDecl = genDecl;
- }
- else
- {
- parseStructInner(nullptr);
- }
- return retDecl;
+ });
}
RefPtr<ClassDecl> Parser::ParseClass()
@@ -3158,7 +3252,8 @@ namespace Slang
decl->nameAndLoc = expectIdentifier(parser);
- auto parseEnumDeclInner = [&](GenericDecl*)
+
+ return parseOptGenericDecl(parser, [&](GenericDecl*)
{
parseOptionalInheritanceClause(parser, decl);
parser->ReadToken(TokenType::LBrace);
@@ -3174,23 +3269,7 @@ namespace Slang
parser->ReadToken(TokenType::Comma);
}
return decl;
- };
-
- if (parser->LookAheadToken(TokenType::OpLess))
- {
- RefPtr<GenericDecl> genericDecl = new GenericDecl();
- parser->FillPosition(genericDecl);
- parser->PushScope(genericDecl);
- ParseGenericDeclImpl(parser, genericDecl, parseEnumDeclInner);
- parser->PopScope();
- return genericDecl;
- }
- else
- {
- parseEnumDeclInner(nullptr);
- }
-
- return decl;
+ });
}
static RefPtr<Stmt> ParseSwitchStmt(Parser* parser)
@@ -4717,6 +4796,10 @@ namespace Slang
DECL(attribute_syntax,parseAttributeSyntaxDecl);
DECL(__import, parseImportDecl);
DECL(import, parseImportDecl);
+ DECL(let, parseLetDecl);
+ DECL(var, parseVarDecl);
+ DECL(func, parseFuncDecl);
+ DECL(typealias, parseTypeAliasDecl);
#undef DECL