Skip to content

Commit f1cd1ee

Browse files
committed
feat: add support for returnless FOR loops with diagnostic and semantic validation
1 parent 5dcb976 commit f1cd1ee

2 files changed

Lines changed: 19 additions & 7 deletions

File tree

pkg/compiler/internal/loop.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ type (
3535
passThroughCtx fql.IForExpressionContext
3636
kind loopResultKind
3737
distinct bool
38-
bodyCount int
38+
// bodyEnd is the exclusive end of ordinary body entries compiled before finalization.
39+
bodyEnd int
3940
}
4041

4142
loopOperandContext struct {
@@ -308,8 +309,8 @@ func (c *LoopCompiler) compileInitialization(
308309
func (c *LoopCompiler) resolveLoopResultSpec(ctx fql.IForExpressionContext) loopResultSpec {
309310
bodies := ctx.AllForExpressionBody()
310311
result := loopResultSpec{
311-
kind: loopResultEffectOnly,
312-
bodyCount: len(bodies),
312+
kind: loopResultEffectOnly,
313+
bodyEnd: len(bodies),
313314
}
314315

315316
if re := ctx.ReturnExpression(); re != nil {
@@ -343,7 +344,7 @@ func (c *LoopCompiler) resolveLoopResultSpec(ctx fql.IForExpressionContext) loop
343344
if nested := stmt.ForExpression(); nested != nil {
344345
result.passThroughCtx = nested
345346
result.kind = loopResultPassThrough
346-
result.bodyCount--
347+
result.bodyEnd = len(bodies) - 1
347348
}
348349
}
349350
}
@@ -641,10 +642,10 @@ func (c *LoopCompiler) compileLoopBody(ctx fql.IForExpressionContext, resultSpec
641642

642643
body := ctx.AllForExpressionBody()
643644

644-
for i := 0; i < resultSpec.bodyCount; i++ {
645-
if statement := body[i].ForExpressionStatement(); statement != nil {
645+
for _, entry := range body[:resultSpec.bodyEnd] {
646+
if statement := entry.ForExpressionStatement(); statement != nil {
646647
c.compileForExpressionStatement(statement)
647-
} else if clause := body[i].ForExpressionClause(); clause != nil {
648+
} else if clause := entry.ForExpressionClause(); clause != nil {
648649
c.compileForExpressionClause(clause)
649650
}
650651
}

test/integration/compiler/compiler_returnless_for_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ func TestReturnlessForValueDiagnostics(t *testing.T) {
4141
query: `RETURN FOR outer IN [1] { FOR inner IN [outer] {} }`,
4242
marker: "FOR inner",
4343
},
44+
{
45+
name: "nested pass-through operand after outer statements",
46+
query: `VAR n = 0
47+
RETURN FOR outer IN [1] {
48+
n += 1
49+
FOR inner IN [outer] {
50+
n += inner
51+
}
52+
}`,
53+
marker: "FOR inner",
54+
},
4455
{name: "while return", query: `RETURN FOR WHILE false {}`, marker: "FOR WHILE"},
4556
{name: "do while return", query: `RETURN FOR DO WHILE false {}`, marker: "FOR DO"},
4657
}

0 commit comments

Comments
 (0)