summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-parser.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-08-14 18:41:48 -0700
committerGitHub <noreply@github.com>2024-08-14 18:41:48 -0700
commit071f1b6062b459928ebfd6f2f60a8d6ad021112b (patch)
tree2ba65eb40f39701db6fc775a9258ec8079d161a0 /source/slang/slang-parser.cpp
parent35a3d32c87f079749f6b100d01b289c3da02d7d6 (diff)
Variadic Generics Part 1: parsing and type checking. (#4833)
Diffstat (limited to 'source/slang/slang-parser.cpp')
-rw-r--r--source/slang/slang-parser.cpp174
1 files changed, 84 insertions, 90 deletions
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 10b52611f..c1f0f91c2 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -112,6 +112,10 @@ namespace Slang
bool hasSeenCompletionToken = false;
+ // Track whether or not we are inside a generics that has variadic parameters.
+ // If so we will enable the new `expand` and `each` keyword.
+ bool isInVariadicGenerics = false;
+
TokenReader tokenReader;
DiagnosticSink* sink;
SourceLoc lastErrorLoc;
@@ -1476,41 +1480,50 @@ namespace Slang
}
return paramDecl;
}
+ Decl* paramDecl = nullptr;
+ if (AdvanceIf(parser, "each"))
+ {
+ // A type pack parameter.
+ paramDecl = parser->astBuilder->create<GenericTypePackParamDecl>();
+ parser->FillPosition(paramDecl);
+ paramDecl->nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
+ }
else
{
// default case is a type parameter
- GenericTypeParamDecl* paramDecl = parser->astBuilder->create<GenericTypeParamDecl>();
+ paramDecl = parser->astBuilder->create<GenericTypeParamDecl>();
parser->FillPosition(paramDecl);
paramDecl->nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
- if (AdvanceIf(parser, TokenType::Colon))
- {
- // The user is apply a constraint to this type parameter...
-
- auto paramConstraint = parser->astBuilder->create<GenericTypeConstraintDecl>();
- parser->FillPosition(paramConstraint);
+ }
+ if (AdvanceIf(parser, TokenType::Colon))
+ {
+ // The user is apply a constraint to this type parameter...
- auto paramType = DeclRefType::create(
- parser->astBuilder,
- DeclRef<Decl>(paramDecl));
+ auto paramConstraint = parser->astBuilder->create<GenericTypeConstraintDecl>();
+ parser->FillPosition(paramConstraint);
- auto paramTypeExpr = parser->astBuilder->create<SharedTypeExpr>();
- paramTypeExpr->loc = paramDecl->loc;
- paramTypeExpr->base.type = paramType;
- paramTypeExpr->type = QualType(parser->astBuilder->getTypeType(paramType));
-
- paramConstraint->sub = TypeExp(paramTypeExpr);
- paramConstraint->sup = parser->ParseTypeExp();
+ auto paramType = DeclRefType::create(
+ parser->astBuilder,
+ DeclRef<Decl>(paramDecl));
- AddMember(genericDecl, paramConstraint);
+ auto paramTypeExpr = parser->astBuilder->create<SharedTypeExpr>();
+ paramTypeExpr->loc = paramDecl->loc;
+ paramTypeExpr->base.type = paramType;
+ paramTypeExpr->type = QualType(parser->astBuilder->getTypeType(paramType));
+ paramConstraint->sub = TypeExp(paramTypeExpr);
+ paramConstraint->sup = parser->ParseTypeExp();
- }
+ AddMember(genericDecl, paramConstraint);
+ }
+ if (auto typeParameter = as<GenericTypeParamDecl>(paramDecl))
+ {
if (AdvanceIf(parser, TokenType::OpAssign))
{
- paramDecl->initType = parser->ParseTypeExp();
+ typeParameter->initType = parser->ParseTypeExp();
}
- return paramDecl;
}
+ return paramDecl;
}
template<typename TFunc>
@@ -1519,6 +1532,9 @@ namespace Slang
{
parser->ReadToken(TokenType::OpLess);
parser->genericDepth++;
+ bool oldIsInVariadicGenerics = parser->isInVariadicGenerics;
+ SLANG_DEFER(parser->isInVariadicGenerics = oldIsInVariadicGenerics);
+
for (;;)
{
const TokenType tokenType = parser->tokenReader.peekTokenType();
@@ -1530,7 +1546,13 @@ namespace Slang
auto currentCursor = parser->tokenReader.getCursor();
- AddMember(decl, ParseGenericParamDecl(parser, decl));
+ auto genericParam = ParseGenericParamDecl(parser, decl);
+ AddMember(decl, genericParam);
+
+ if (as<GenericTypePackParamDecl>(genericParam))
+ {
+ parser->isInVariadicGenerics = true;
+ }
// Make sure we make forward progress.
if (parser->tokenReader.getCursor() == currentCursor)
@@ -2567,6 +2589,11 @@ namespace Slang
typeSpec.expr = createDeclRefType(parser, decl);
return typeSpec;
}
+ else if (parser->LookAheadToken("expand") || parser->LookAheadToken("each"))
+ {
+ typeSpec.expr = parser->ParseExpression();
+ return typeSpec;
+ }
// Uncomment should we decide to enable (a,b,c) tuple types
// else if(parser->LookAheadToken(TokenType::LParent))
// {
@@ -6161,65 +6188,6 @@ namespace Slang
{
auto expr = ParseLeafExpression();
return parseInfixExprWithPrecedence(this, expr, level);
-
-#if 0
-
- if (level == Precedence::Prefix)
- return ParseLeafExpression();
- if (level == Precedence::TernaryConditional)
- {
- // parse select clause
- auto condition = ParseExpression(Precedence(level + 1));
- if (LookAheadToken(TokenType::QuestionMark))
- {
- SelectExpr* select = new SelectExpr();
- FillPosition(select.Ptr());
-
- select->Arguments.add(condition);
-
- select->FunctionExpr = parseOperator(this);
-
- select->Arguments.add(ParseExpression(level));
- ReadToken(TokenType::Colon);
- select->Arguments.add(ParseExpression(level));
- return select;
- }
- else
- return condition;
- }
- else
- {
- if (GetAssociativityFromLevel(level) == Associativity::Left)
- {
- auto left = ParseExpression(Precedence(level + 1));
- while (GetOpLevel(this, tokenReader.PeekTokenType()) == level)
- {
- OperatorExpr* tmp = new InfixExpr();
- tmp->FunctionExpr = parseOperator(this);
-
- tmp->Arguments.add(left);
- FillPosition(tmp.Ptr());
- tmp->Arguments.add(ParseExpression(Precedence(level + 1)));
- left = tmp;
- }
- return left;
- }
- else
- {
- auto left = ParseExpression(Precedence(level + 1));
- if (GetOpLevel(this, tokenReader.PeekTokenType()) == level)
- {
- OperatorExpr* tmp = new InfixExpr();
- tmp->Arguments.add(left);
- FillPosition(tmp.Ptr());
- tmp->FunctionExpr = parseOperator(this);
- tmp->Arguments.add(ParseExpression(level));
- left = tmp;
- }
- return left;
- }
- }
-#endif
}
// We *might* be looking at an application of a generic to arguments,
@@ -7549,10 +7517,10 @@ namespace Slang
return ret;
}
- static Expr* parseSPIRVAsmExpr(Parser* parser)
+ static Expr* parseSPIRVAsmExpr(Parser* parser, SourceLoc loc)
{
SPIRVAsmExpr* asmExpr = parser->astBuilder->create<SPIRVAsmExpr>();
- parser->FillPosition(asmExpr);
+ asmExpr->loc = loc;
parser->ReadToken(TokenType::LBrace);
while(!parser->tokenReader.isAtEnd())
{
@@ -7577,6 +7545,22 @@ namespace Slang
return asmExpr;
}
+ static Expr* parseExpandExpr(Parser* parser, SourceLoc loc)
+ {
+ ExpandExpr* expandExpr = parser->astBuilder->create<ExpandExpr>();
+ expandExpr->loc = loc;
+ expandExpr->baseExpr = parser->ParseExpression();
+ return expandExpr;
+ }
+
+ static Expr* parseEachExpr(Parser* parser, SourceLoc loc)
+ {
+ EachExpr* eachExpr = parser->astBuilder->create<EachExpr>();
+ eachExpr->loc = loc;
+ eachExpr->baseExpr = parser->ParseExpression();
+ return eachExpr;
+ }
+
static Expr* parsePrefixExpr(Parser* parser)
{
auto tokenType = peekTokenType(parser);
@@ -7584,13 +7568,11 @@ namespace Slang
{
case TokenType::Identifier:
{
- auto identifierToken = peekToken(parser);
- const auto identifierTokenContent = identifierToken.getContent();
- if (identifierTokenContent == toSlice("new"))
+ auto tokenLoc = peekToken(parser).getLoc();
+ if (AdvanceIf(parser, "new"))
{
NewExpr* newExpr = parser->astBuilder->create<NewExpr>();
- parser->FillPosition(newExpr);
- parser->ReadToken();
+ newExpr->loc = tokenLoc;
auto subExpr = parsePostfixExpr(parser);
if (as<VarExpr>(subExpr) || as<GenericAppExpr>(subExpr))
{
@@ -7611,9 +7593,21 @@ namespace Slang
}
else if (AdvanceIf(parser, "spirv_asm"))
{
- return parseSPIRVAsmExpr(parser);
+ return parseSPIRVAsmExpr(parser, tokenLoc);
+ }
+ else if (parser->isInVariadicGenerics)
+ {
+ // If we are inside a variadic generic, we also need to recognize
+ // the new `expand` and `each` keyword for dealing with variadic packs.
+ if (AdvanceIf(parser, "expand"))
+ {
+ return parseExpandExpr(parser, tokenLoc);
+ }
+ else if (AdvanceIf(parser, "each"))
+ {
+ return parseEachExpr(parser, tokenLoc);
+ }
}
-
return parsePostfixExpr(parser);
}
default: