summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorkaizhangNV <149626564+kaizhangNV@users.noreply.github.com>2024-04-17 23:23:15 -0700
committerGitHub <noreply@github.com>2024-04-17 23:23:15 -0700
commitd3fd7470e6b71aa080415a3a7c207faebe21b00f (patch)
treede3b9c1642fbea11392bfaf170de31a6d80b2826 /source
parent5dd27a26da9b6b6191f3b1eba0f38f85714c1ae3 (diff)
Implement if(let ...) syntax (#3673) (#3958)
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-parser.cpp109
1 files changed, 108 insertions, 1 deletions
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index e564b4956..2c304a663 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -199,6 +199,7 @@ namespace Slang
Stmt* parseLabelStatement();
DeclStmt* parseVarDeclrStatement(Modifiers modifiers);
IfStmt* parseIfStatement();
+ Stmt* parseIfLetStatement();
ForStmt* ParseForStatement();
WhileStmt* ParseWhileStatement();
DoWhileStmt* ParseDoWhileStatement();
@@ -5276,7 +5277,16 @@ namespace Slang
if (LookAheadToken(TokenType::LBrace))
statement = parseBlockStatement();
else if (LookAheadToken("if"))
- statement = parseIfStatement();
+ {
+ if(LookAheadToken("let", 2))
+ {
+ statement = parseIfLetStatement();
+ }
+ else
+ {
+ statement = parseIfStatement();
+ }
+ }
else if (LookAheadToken("for"))
statement = ParseForStatement();
else if (LookAheadToken("while"))
@@ -5579,6 +5589,103 @@ namespace Slang
return varDeclrStatement;
}
+ static Expr* constructIfLetPredicate(Parser* parser, VarExpr* varExpr)
+ {
+ // create a "var.hasValue" expression
+ MemberExpr* memberExpr = parser->astBuilder->create<MemberExpr>();
+ memberExpr->baseExpression = varExpr;
+ parser->FillPosition(memberExpr);
+ memberExpr->name = getName(parser, "hasValue");
+
+ return memberExpr;
+ }
+
+ // Parse the syntax 'if (let var = X as Y)'
+ Stmt* Parser::parseIfLetStatement()
+ {
+ ScopeDecl* scopeDecl = astBuilder->create<ScopeDecl>();
+ pushScopeAndSetParent(scopeDecl);
+
+ SeqStmt* newBody = astBuilder->create<SeqStmt>();
+
+ IfStmt* ifStatement = astBuilder->create<IfStmt>();
+ FillPosition(ifStatement);
+ ReadToken("if");
+ ReadToken(TokenType::LParent);
+
+ // parse 'let var = X as Y'
+ ReadToken("let");
+ auto identifierToken = ReadToken(TokenType::Identifier);
+ ReadToken(TokenType::OpAssign);
+ auto initExpr = ParseInitExpr();
+
+ // insert 'let tempVarDecl = X as Y;'
+ auto tempVarDecl = astBuilder->create<LetDecl>();
+ tempVarDecl->nameAndLoc = NameLoc(getName(this, "$OptVar"), identifierToken.loc);
+ tempVarDecl->initExpr = initExpr;
+ AddMember(currentScope->containerDecl, tempVarDecl);
+
+ DeclStmt* tmpVarDeclStmt = astBuilder->create<DeclStmt>();
+ FillPosition(tmpVarDeclStmt);
+ tmpVarDeclStmt->decl = tempVarDecl;
+ newBody->stmts.add(tmpVarDeclStmt);
+
+ // construct 'if (tempVarDecl.hasValue == true)'
+ VarExpr* tempVarExpr = astBuilder->create<VarExpr>();
+ tempVarExpr->scope = currentScope;
+ FillPosition(tempVarExpr);
+ tempVarExpr->name = tempVarDecl->getName();
+ ifStatement->predicate = constructIfLetPredicate(this, tempVarExpr);
+
+ ReadToken(TokenType::RParent);
+
+ // Create a new scope surrounding the positive statement, will be used for
+ // the variable declared in the if_let syntax
+ ScopeDecl* positiveScopeDecl = astBuilder->create<ScopeDecl>();
+ pushScopeAndSetParent(positiveScopeDecl);
+ ifStatement->positiveStatement = ParseStatement(ifStatement);
+ PopScope();
+
+ if (LookAheadToken("else"))
+ {
+ ReadToken("else");
+ ifStatement->negativeStatement = ParseStatement(ifStatement);
+ }
+
+ if (ifStatement->positiveStatement)
+ {
+ auto seqPositiveStmt = as<SeqStmt>(ifStatement->positiveStatement);
+ if (!seqPositiveStmt)
+ {
+ seqPositiveStmt = astBuilder->create<SeqStmt>();
+ }
+
+ MemberExpr* memberExpr = astBuilder->create<MemberExpr>();
+ memberExpr->baseExpression = tempVarExpr;
+ memberExpr->name = getName(this, "value");
+
+ auto varDecl = astBuilder->create<LetDecl>();
+ varDecl->nameAndLoc = NameLoc(identifierToken.getName(), identifierToken.loc);
+ varDecl->initExpr = memberExpr;
+
+ DeclStmt* varDeclrStatement = astBuilder->create<DeclStmt>();
+ varDeclrStatement->decl = varDecl;
+
+ // Add scope to the variable declared in the if_let syntax such
+ // that this variable cannot be used outside the positive statement
+ AddMember(positiveScopeDecl, varDecl);
+
+ seqPositiveStmt->stmts.add(varDeclrStatement);
+ seqPositiveStmt->stmts.add(ifStatement->positiveStatement);
+ ifStatement->positiveStatement = seqPositiveStmt;
+ }
+
+ newBody->stmts.add(ifStatement);
+ PopScope();
+
+ return newBody;
+ }
+
IfStmt* Parser::parseIfStatement()
{
IfStmt* ifStatement = astBuilder->create<IfStmt>();