Skip to content

Commit eec0234

Browse files
committed
extract block literal parsing from expression parser
1 parent c6621a9 commit eec0234

3 files changed

Lines changed: 133 additions & 130 deletions

File tree

docs/architecture.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ Key files:
6363
- `vibes/lexer.go`
6464
- `vibes/parser.go` (parser core initialization + token stream helpers)
6565
- `vibes/parser_errors.go` (parse errors and token labeling)
66-
- `vibes/parser_expressions.go` (expression-level parsing, call/block literals)
66+
- `vibes/parser_expressions.go` (expression-level parsing and call literals)
67+
- `vibes/parser_block_literals.go` (block literals, block params, and typed union param parsing)
6768
- `vibes/parser_statements.go` (statement dispatch + return/raise/block parsing)
6869
- `vibes/parser_expression_statements.go` (expression/assert/assignment statement parsing)
6970
- `vibes/parser_declarations.go` (function/class/property declaration parsing)

vibes/parser_block_literals.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package vibes
2+
3+
import "strings"
4+
5+
func (p *parser) parseBlockLiteral() *BlockLiteral {
6+
pos := p.curToken.Pos
7+
params := []Param{}
8+
9+
p.nextToken()
10+
if p.curToken.Type == tokenPipe {
11+
var ok bool
12+
params, ok = p.parseBlockParameters()
13+
if !ok {
14+
return nil
15+
}
16+
p.nextToken()
17+
}
18+
19+
body := p.parseBlock(tokenEnd)
20+
if p.curToken.Type != tokenEnd {
21+
p.errorExpected(p.curToken, "end")
22+
}
23+
24+
return &BlockLiteral{Params: params, Body: body, position: pos}
25+
}
26+
27+
func (p *parser) parseBlockParameters() ([]Param, bool) {
28+
params := []Param{}
29+
p.nextToken()
30+
if p.curToken.Type == tokenPipe {
31+
return params, true
32+
}
33+
34+
param, ok := p.parseBlockParameter()
35+
if !ok {
36+
return nil, false
37+
}
38+
params = append(params, param)
39+
40+
for p.peekToken.Type == tokenComma {
41+
p.nextToken()
42+
p.nextToken()
43+
if p.curToken.Type == tokenPipe {
44+
p.addParseError(p.curToken.Pos, "trailing comma in block parameter list")
45+
return nil, false
46+
}
47+
param, ok := p.parseBlockParameter()
48+
if !ok {
49+
return nil, false
50+
}
51+
params = append(params, param)
52+
}
53+
54+
if !p.expectPeek(tokenPipe) {
55+
return nil, false
56+
}
57+
58+
return params, true
59+
}
60+
61+
func (p *parser) parseBlockParameter() (Param, bool) {
62+
if p.curToken.Type != tokenIdent {
63+
p.errorExpected(p.curToken, "block parameter")
64+
return Param{}, false
65+
}
66+
param := Param{Name: p.curToken.Literal}
67+
if p.peekToken.Type == tokenColon {
68+
p.nextToken()
69+
p.nextToken()
70+
param.Type = p.parseBlockParamType()
71+
if param.Type == nil {
72+
return Param{}, false
73+
}
74+
}
75+
return param, true
76+
}
77+
78+
func (p *parser) parseBlockParamType() *TypeExpr {
79+
first := p.parseTypeAtom()
80+
if first == nil {
81+
return nil
82+
}
83+
84+
union := []*TypeExpr{first}
85+
for p.peekToken.Type == tokenPipe && p.blockParamUnionContinues() {
86+
p.nextToken()
87+
p.nextToken()
88+
next := p.parseTypeAtom()
89+
if next == nil {
90+
return nil
91+
}
92+
union = append(union, next)
93+
}
94+
95+
if len(union) == 1 {
96+
return first
97+
}
98+
99+
names := make([]string, len(union))
100+
for i, option := range union {
101+
names[i] = formatTypeExpr(option)
102+
}
103+
return &TypeExpr{
104+
Name: strings.Join(names, " | "),
105+
Kind: TypeUnion,
106+
Union: union,
107+
position: first.position,
108+
}
109+
}
110+
111+
func (p *parser) blockParamUnionContinues() bool {
112+
if p.peekToken.Type != tokenPipe {
113+
return false
114+
}
115+
116+
savedLexer := *p.l
117+
savedCur := p.curToken
118+
savedPeek := p.peekToken
119+
savedErrors := len(p.errors)
120+
121+
p.nextToken()
122+
p.nextToken()
123+
atom := p.parseTypeAtom()
124+
ok := atom != nil && (p.peekToken.Type == tokenComma || p.peekToken.Type == tokenPipe)
125+
126+
p.l = &savedLexer
127+
p.curToken = savedCur
128+
p.peekToken = savedPeek
129+
p.errors = p.errors[:savedErrors]
130+
return ok
131+
}

vibes/parser_expressions.go

Lines changed: 0 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package vibes
33
import (
44
"fmt"
55
"strconv"
6-
"strings"
76
)
87

98
func (p *parser) parseExpression(precedence int) Expression {
@@ -349,134 +348,6 @@ func isLabelNameToken(tt TokenType) bool {
349348
}
350349
}
351350

352-
func (p *parser) parseBlockLiteral() *BlockLiteral {
353-
pos := p.curToken.Pos
354-
params := []Param{}
355-
356-
p.nextToken()
357-
if p.curToken.Type == tokenPipe {
358-
var ok bool
359-
params, ok = p.parseBlockParameters()
360-
if !ok {
361-
return nil
362-
}
363-
p.nextToken()
364-
}
365-
366-
body := p.parseBlock(tokenEnd)
367-
if p.curToken.Type != tokenEnd {
368-
p.errorExpected(p.curToken, "end")
369-
}
370-
371-
return &BlockLiteral{Params: params, Body: body, position: pos}
372-
}
373-
374-
func (p *parser) parseBlockParameters() ([]Param, bool) {
375-
params := []Param{}
376-
p.nextToken()
377-
if p.curToken.Type == tokenPipe {
378-
return params, true
379-
}
380-
381-
param, ok := p.parseBlockParameter()
382-
if !ok {
383-
return nil, false
384-
}
385-
params = append(params, param)
386-
387-
for p.peekToken.Type == tokenComma {
388-
p.nextToken()
389-
p.nextToken()
390-
if p.curToken.Type == tokenPipe {
391-
p.addParseError(p.curToken.Pos, "trailing comma in block parameter list")
392-
return nil, false
393-
}
394-
param, ok := p.parseBlockParameter()
395-
if !ok {
396-
return nil, false
397-
}
398-
params = append(params, param)
399-
}
400-
401-
if !p.expectPeek(tokenPipe) {
402-
return nil, false
403-
}
404-
405-
return params, true
406-
}
407-
408-
func (p *parser) parseBlockParameter() (Param, bool) {
409-
if p.curToken.Type != tokenIdent {
410-
p.errorExpected(p.curToken, "block parameter")
411-
return Param{}, false
412-
}
413-
param := Param{Name: p.curToken.Literal}
414-
if p.peekToken.Type == tokenColon {
415-
p.nextToken()
416-
p.nextToken()
417-
param.Type = p.parseBlockParamType()
418-
if param.Type == nil {
419-
return Param{}, false
420-
}
421-
}
422-
return param, true
423-
}
424-
425-
func (p *parser) parseBlockParamType() *TypeExpr {
426-
first := p.parseTypeAtom()
427-
if first == nil {
428-
return nil
429-
}
430-
431-
union := []*TypeExpr{first}
432-
for p.peekToken.Type == tokenPipe && p.blockParamUnionContinues() {
433-
p.nextToken()
434-
p.nextToken()
435-
next := p.parseTypeAtom()
436-
if next == nil {
437-
return nil
438-
}
439-
union = append(union, next)
440-
}
441-
442-
if len(union) == 1 {
443-
return first
444-
}
445-
446-
names := make([]string, len(union))
447-
for i, option := range union {
448-
names[i] = formatTypeExpr(option)
449-
}
450-
return &TypeExpr{
451-
Name: strings.Join(names, " | "),
452-
Kind: TypeUnion,
453-
Union: union,
454-
position: first.position,
455-
}
456-
}
457-
458-
func (p *parser) blockParamUnionContinues() bool {
459-
if p.peekToken.Type != tokenPipe {
460-
return false
461-
}
462-
463-
savedLexer := *p.l
464-
savedCur := p.curToken
465-
savedPeek := p.peekToken
466-
savedErrors := len(p.errors)
467-
468-
p.nextToken()
469-
p.nextToken()
470-
atom := p.parseTypeAtom()
471-
ok := atom != nil && (p.peekToken.Type == tokenComma || p.peekToken.Type == tokenPipe)
472-
473-
p.l = &savedLexer
474-
p.curToken = savedCur
475-
p.peekToken = savedPeek
476-
p.errors = p.errors[:savedErrors]
477-
return ok
478-
}
479-
480351
func (p *parser) parseMemberExpression(object Expression) Expression {
481352
if object == nil {
482353
return nil

0 commit comments

Comments
 (0)