From 2476c035ec15d3ee22239ebd1fe10e6e8c1e01e3 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Tue, 18 Jul 2017 14:51:12 -0700 Subject: 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. --- source/slang/parser.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'source/slang/parser.cpp') 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 parseCompileTimeForStmt( + Parser* parser) + { + RefPtr scopeDecl = new ScopeDecl(); + RefPtr stmt = new CompileTimeForStmt(); + stmt->scopeDecl = scopeDecl; + + + parser->ReadToken("for"); + parser->ReadToken(TokenType::LParent); + + Token varNameToken = parser->ReadToken(TokenType::Identifier); + RefPtr varDecl = new Variable(); + varDecl->Name = varNameToken; + varDecl->Position = varNameToken.Position; + + stmt->varDecl = varDecl; + + parser->ReadToken("in"); + parser->ReadToken("Range"); + parser->ReadToken(TokenType::LParent); + + RefPtr rangeBeginExpr; + RefPtr 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 parseCompileTimeStmt( + Parser* parser) + { + parser->ReadToken(TokenType::Dollar); + if (parser->LookAheadToken("for")) + { + return parseCompileTimeForStmt(parser); + } + else + { + Unexpected(parser); + return nullptr; + } + } + RefPtr 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 -- cgit v1.2.3