summaryrefslogtreecommitdiffstats
path: root/source/slang/parser.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-07-18 14:51:12 -0700
committerTim Foley <tfoley@nvidia.com>2017-07-18 14:51:12 -0700
commit2476c035ec15d3ee22239ebd1fe10e6e8c1e01e3 (patch)
tree30e1bf209e232d7f8d6723959db68b2c0cb015dd /source/slang/parser.cpp
parent3d313d963f29f6ca6a8d12bd5c403a70c49aca2a (diff)
Add a compile-time loop construct to Slang
The basic syntax is: $for(i in Range(0,99)) { /* stuff goes here */ } Note that the exact form is very restrictive. All that you are allowed to change is `i`, `0`, `99` or `/* stuff goes here */`. As a tiny bit of syntax sugar, the following should work: $for(i in Range(99)) { /* stuff goes here */ } Note that the range given is half-open (C++ iterator `[begin,end)` style). Both the beginning and end of the range must be compile-time constant expressions that Slang knows how to constant-fold. The implementation will basically generate code for `/* stuff goes here */` N times, once for each value in the half-open range. Each time, the variable `i` will be replaced with a different compile-time-constant expression. While I was working on a test case for this, I also found that our build of glslang had an issue with resource limits, so I fixed that. Clients will need to build a new glslang to use the fix.
Diffstat (limited to 'source/slang/parser.cpp')
-rw-r--r--source/slang/parser.cpp65
1 files changed, 65 insertions, 0 deletions
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index 1ad0c6b94..b821555a9 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -2555,6 +2555,67 @@ namespace Slang
return isTypeName(parser, name);
}
+ RefPtr<StatementSyntaxNode> parseCompileTimeForStmt(
+ Parser* parser)
+ {
+ RefPtr<ScopeDecl> scopeDecl = new ScopeDecl();
+ RefPtr<CompileTimeForStmt> stmt = new CompileTimeForStmt();
+ stmt->scopeDecl = scopeDecl;
+
+
+ parser->ReadToken("for");
+ parser->ReadToken(TokenType::LParent);
+
+ Token varNameToken = parser->ReadToken(TokenType::Identifier);
+ RefPtr<Variable> varDecl = new Variable();
+ varDecl->Name = varNameToken;
+ varDecl->Position = varNameToken.Position;
+
+ stmt->varDecl = varDecl;
+
+ parser->ReadToken("in");
+ parser->ReadToken("Range");
+ parser->ReadToken(TokenType::LParent);
+
+ RefPtr<ExpressionSyntaxNode> rangeBeginExpr;
+ RefPtr<ExpressionSyntaxNode> rangeEndExpr = parser->ParseArgExpr();
+ if (AdvanceIf(parser, TokenType::Comma))
+ {
+ rangeBeginExpr = rangeEndExpr;
+ rangeEndExpr = parser->ParseArgExpr();
+ }
+
+ stmt->rangeBeginExpr = rangeBeginExpr;
+ stmt->rangeEndExpr = rangeEndExpr;
+
+ parser->ReadToken(TokenType::RParent);
+ parser->ReadToken(TokenType::RParent);
+
+ parser->PushScope(scopeDecl);
+ AddMember(parser->currentScope, varDecl);
+
+ stmt->body = parser->ParseStatement();
+
+ parser->PopScope();
+
+ return stmt;
+ }
+
+ RefPtr<StatementSyntaxNode> parseCompileTimeStmt(
+ Parser* parser)
+ {
+ parser->ReadToken(TokenType::Dollar);
+ if (parser->LookAheadToken("for"))
+ {
+ return parseCompileTimeForStmt(parser);
+ }
+ else
+ {
+ Unexpected(parser);
+ return nullptr;
+ }
+ }
+
RefPtr<StatementSyntaxNode> Parser::ParseStatement()
{
auto modifiers = ParseModifiers(this);
@@ -2591,6 +2652,10 @@ namespace Slang
statement = ParseCaseStmt(this);
else if (LookAheadToken("default"))
statement = ParseDefaultStmt(this);
+ else if (LookAheadToken(TokenType::Dollar))
+ {
+ statement = parseCompileTimeStmt(this);
+ }
else if (LookAheadToken(TokenType::Identifier))
{
// We might be looking at a local declaration, or an