Skip to content

Commit 251a24b

Browse files
committed
Allow bare zero-arg yield across newlines
1 parent 5baee33 commit 251a24b

3 files changed

Lines changed: 82 additions & 2 deletions

File tree

examples/blocks/yield_patterns.vibe

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ end
2222

2323
def benchmark
2424
start = Time.now
25-
result = yield()
25+
result = yield
2626
elapsed = Time.now - start
2727
{ result: result, elapsed: elapsed }
2828
end

vibes/parser_yield_literals.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func (p *parser) parseYieldExpression() Expression {
1717
return nil
1818
}
1919
}
20-
} else if p.prefixFns[p.peekToken.Type] != nil {
20+
} else if p.peekToken.Pos.Line == pos.Line && p.prefixFns[p.peekToken.Type] != nil {
2121
p.nextToken()
2222
args = append(args, p.parseExpression(lowestPrec))
2323
}

vibes/parser_yield_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package vibes
2+
3+
import "testing"
4+
5+
func TestParserYieldWithoutParensDoesNotConsumeNextLineInAssignment(t *testing.T) {
6+
source := `def run
7+
result = yield
8+
elapsed = 1
9+
end`
10+
11+
p := newParser(source)
12+
program, errs := p.ParseProgram()
13+
if len(errs) > 0 {
14+
t.Fatalf("expected no parse errors, got %v", errs)
15+
}
16+
if len(program.Statements) != 1 {
17+
t.Fatalf("expected 1 statement, got %d", len(program.Statements))
18+
}
19+
20+
fn, ok := program.Statements[0].(*FunctionStmt)
21+
if !ok {
22+
t.Fatalf("expected function statement, got %T", program.Statements[0])
23+
}
24+
if len(fn.Body) != 2 {
25+
t.Fatalf("expected 2 body statements, got %d", len(fn.Body))
26+
}
27+
28+
first, ok := fn.Body[0].(*AssignStmt)
29+
if !ok {
30+
t.Fatalf("expected first statement assignment, got %T", fn.Body[0])
31+
}
32+
yieldExpr, ok := first.Value.(*YieldExpr)
33+
if !ok {
34+
t.Fatalf("expected yield expression, got %T", first.Value)
35+
}
36+
if len(yieldExpr.Args) != 0 {
37+
t.Fatalf("expected zero-arg yield, got %d args", len(yieldExpr.Args))
38+
}
39+
40+
second, ok := fn.Body[1].(*AssignStmt)
41+
if !ok {
42+
t.Fatalf("expected second statement assignment, got %T", fn.Body[1])
43+
}
44+
target, ok := second.Target.(*Identifier)
45+
if !ok || target.Name != "elapsed" {
46+
t.Fatalf("expected second assignment to elapsed, got %#v", second.Target)
47+
}
48+
}
49+
50+
func TestParserYieldWithoutParensAcceptsInlineArgument(t *testing.T) {
51+
source := `def run
52+
result = yield value
53+
end`
54+
55+
p := newParser(source)
56+
program, errs := p.ParseProgram()
57+
if len(errs) > 0 {
58+
t.Fatalf("expected no parse errors, got %v", errs)
59+
}
60+
61+
fn, ok := program.Statements[0].(*FunctionStmt)
62+
if !ok {
63+
t.Fatalf("expected function statement, got %T", program.Statements[0])
64+
}
65+
assign, ok := fn.Body[0].(*AssignStmt)
66+
if !ok {
67+
t.Fatalf("expected assignment, got %T", fn.Body[0])
68+
}
69+
yieldExpr, ok := assign.Value.(*YieldExpr)
70+
if !ok {
71+
t.Fatalf("expected yield expression, got %T", assign.Value)
72+
}
73+
if len(yieldExpr.Args) != 1 {
74+
t.Fatalf("expected one yield arg, got %d", len(yieldExpr.Args))
75+
}
76+
arg, ok := yieldExpr.Args[0].(*Identifier)
77+
if !ok || arg.Name != "value" {
78+
t.Fatalf("expected yield arg value, got %#v", yieldExpr.Args[0])
79+
}
80+
}

0 commit comments

Comments
 (0)