diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-07-18 14:51:12 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-07-18 14:51:12 -0700 |
| commit | 2476c035ec15d3ee22239ebd1fe10e6e8c1e01e3 (patch) | |
| tree | 30e1bf209e232d7f8d6723959db68b2c0cb015dd /source/slang/parser.cpp | |
| parent | 3d313d963f29f6ca6a8d12bd5c403a70c49aca2a (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.cpp | 65 |
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 |
