Skip to content

Commit b316449

Browse files
committed
extract parser control-flow statement handlers
1 parent c93b189 commit b316449

2 files changed

Lines changed: 169 additions & 170 deletions

File tree

vibes/parser_control.go

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package vibes
2+
3+
import "fmt"
4+
5+
func (p *parser) parseIfStatement() Statement {
6+
pos := p.curToken.Pos
7+
p.nextToken()
8+
condition := p.parseExpression(lowestPrec)
9+
10+
p.nextToken()
11+
consequent := p.parseBlock(tokenEnd, tokenElse, tokenElsif)
12+
13+
var elseifClauses []*IfStmt
14+
for p.curToken.Type == tokenElsif {
15+
p.nextToken()
16+
cond := p.parseExpression(lowestPrec)
17+
p.nextToken()
18+
body := p.parseBlock(tokenEnd, tokenElse, tokenElsif)
19+
clause := &IfStmt{Condition: cond, Consequent: body, position: cond.Pos()}
20+
elseifClauses = append(elseifClauses, clause)
21+
}
22+
23+
var alternate []Statement
24+
if p.curToken.Type == tokenElse {
25+
p.nextToken()
26+
alternate = p.parseBlock(tokenEnd)
27+
}
28+
29+
if p.curToken.Type != tokenEnd {
30+
p.errorExpected(p.curToken, "end")
31+
}
32+
33+
return &IfStmt{Condition: condition, Consequent: consequent, ElseIf: elseifClauses, Alternate: alternate, position: pos}
34+
}
35+
36+
func (p *parser) parseForStatement() Statement {
37+
pos := p.curToken.Pos
38+
if !p.expectPeek(tokenIdent) {
39+
return nil
40+
}
41+
iterator := p.curToken.Literal
42+
43+
if !p.expectPeek(tokenIn) {
44+
return nil
45+
}
46+
47+
p.nextToken()
48+
iterable := p.parseExpression(lowestPrec)
49+
50+
p.nextToken()
51+
body := p.parseBlock(tokenEnd)
52+
53+
if p.curToken.Type != tokenEnd {
54+
p.errorExpected(p.curToken, "end")
55+
}
56+
57+
return &ForStmt{Iterator: iterator, Iterable: iterable, Body: body, position: pos}
58+
}
59+
60+
func (p *parser) parseWhileStatement() Statement {
61+
pos := p.curToken.Pos
62+
p.nextToken()
63+
condition := p.parseExpression(lowestPrec)
64+
65+
p.nextToken()
66+
body := p.parseBlock(tokenEnd)
67+
68+
if p.curToken.Type != tokenEnd {
69+
p.errorExpected(p.curToken, "end")
70+
}
71+
72+
return &WhileStmt{Condition: condition, Body: body, position: pos}
73+
}
74+
75+
func (p *parser) parseUntilStatement() Statement {
76+
pos := p.curToken.Pos
77+
p.nextToken()
78+
condition := p.parseExpression(lowestPrec)
79+
80+
p.nextToken()
81+
body := p.parseBlock(tokenEnd)
82+
83+
if p.curToken.Type != tokenEnd {
84+
p.errorExpected(p.curToken, "end")
85+
}
86+
87+
return &UntilStmt{Condition: condition, Body: body, position: pos}
88+
}
89+
90+
func (p *parser) parseBreakStatement() Statement {
91+
return &BreakStmt{position: p.curToken.Pos}
92+
}
93+
94+
func (p *parser) parseNextStatement() Statement {
95+
return &NextStmt{position: p.curToken.Pos}
96+
}
97+
98+
func (p *parser) parseBeginStatement() Statement {
99+
pos := p.curToken.Pos
100+
p.nextToken()
101+
body := p.parseBlock(tokenRescue, tokenEnsure, tokenEnd)
102+
103+
var rescueTy *TypeExpr
104+
var rescueBody []Statement
105+
if p.curToken.Type == tokenRescue {
106+
rescuePos := p.curToken.Pos
107+
if p.peekToken.Type == tokenLParen && p.peekToken.Pos.Line == rescuePos.Line {
108+
p.nextToken()
109+
p.nextToken()
110+
rescueTy = p.parseTypeExpr()
111+
if rescueTy == nil {
112+
return nil
113+
}
114+
if !p.validateRescueTypeExpr(rescueTy, rescuePos) {
115+
return nil
116+
}
117+
if !p.expectPeek(tokenRParen) {
118+
return nil
119+
}
120+
}
121+
p.nextToken()
122+
rescueBody = p.parseBlock(tokenEnsure, tokenEnd)
123+
}
124+
125+
var ensureBody []Statement
126+
if p.curToken.Type == tokenEnsure {
127+
p.nextToken()
128+
ensureBody = p.parseBlock(tokenEnd)
129+
}
130+
131+
if p.curToken.Type != tokenEnd {
132+
p.errorExpected(p.curToken, "end")
133+
return nil
134+
}
135+
136+
if len(rescueBody) == 0 && len(ensureBody) == 0 {
137+
p.addParseError(pos, "begin requires rescue and/or ensure")
138+
return nil
139+
}
140+
141+
return &TryStmt{Body: body, RescueTy: rescueTy, Rescue: rescueBody, Ensure: ensureBody, position: pos}
142+
}
143+
144+
func (p *parser) validateRescueTypeExpr(ty *TypeExpr, pos Position) bool {
145+
if ty == nil {
146+
p.addParseError(pos, "rescue type cannot be empty")
147+
return false
148+
}
149+
150+
if ty.Kind == TypeUnion {
151+
ok := true
152+
for _, option := range ty.Union {
153+
if !p.validateRescueTypeExpr(option, option.position) {
154+
ok = false
155+
}
156+
}
157+
return ok
158+
}
159+
160+
if len(ty.TypeArgs) > 0 || len(ty.Shape) > 0 {
161+
p.addParseError(pos, fmt.Sprintf("rescue type must be an error class, got %s", formatTypeExpr(ty)))
162+
return false
163+
}
164+
if _, ok := canonicalRuntimeErrorType(ty.Name); !ok {
165+
p.addParseError(pos, fmt.Sprintf("unknown rescue error type %s", ty.Name))
166+
return false
167+
}
168+
return true
169+
}

vibes/parser_statements.go

Lines changed: 0 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package vibes
22

3-
import (
4-
"fmt"
5-
)
6-
73
func (p *parser) parseStatement() Statement {
84
switch p.curToken.Type {
95
case tokenDef:
@@ -62,172 +58,6 @@ func (p *parser) parseRaiseStatement() Statement {
6258
return &RaiseStmt{Value: value, position: pos}
6359
}
6460

65-
func (p *parser) parseIfStatement() Statement {
66-
pos := p.curToken.Pos
67-
p.nextToken()
68-
condition := p.parseExpression(lowestPrec)
69-
70-
p.nextToken()
71-
consequent := p.parseBlock(tokenEnd, tokenElse, tokenElsif)
72-
73-
var elseifClauses []*IfStmt
74-
for p.curToken.Type == tokenElsif {
75-
p.nextToken()
76-
cond := p.parseExpression(lowestPrec)
77-
p.nextToken()
78-
body := p.parseBlock(tokenEnd, tokenElse, tokenElsif)
79-
clause := &IfStmt{Condition: cond, Consequent: body, position: cond.Pos()}
80-
elseifClauses = append(elseifClauses, clause)
81-
}
82-
83-
var alternate []Statement
84-
if p.curToken.Type == tokenElse {
85-
p.nextToken()
86-
alternate = p.parseBlock(tokenEnd)
87-
}
88-
89-
if p.curToken.Type != tokenEnd {
90-
p.errorExpected(p.curToken, "end")
91-
}
92-
93-
return &IfStmt{Condition: condition, Consequent: consequent, ElseIf: elseifClauses, Alternate: alternate, position: pos}
94-
}
95-
96-
func (p *parser) parseForStatement() Statement {
97-
pos := p.curToken.Pos
98-
if !p.expectPeek(tokenIdent) {
99-
return nil
100-
}
101-
iterator := p.curToken.Literal
102-
103-
if !p.expectPeek(tokenIn) {
104-
return nil
105-
}
106-
107-
p.nextToken()
108-
iterable := p.parseExpression(lowestPrec)
109-
110-
p.nextToken()
111-
body := p.parseBlock(tokenEnd)
112-
113-
if p.curToken.Type != tokenEnd {
114-
p.errorExpected(p.curToken, "end")
115-
}
116-
117-
return &ForStmt{Iterator: iterator, Iterable: iterable, Body: body, position: pos}
118-
}
119-
120-
func (p *parser) parseWhileStatement() Statement {
121-
pos := p.curToken.Pos
122-
p.nextToken()
123-
condition := p.parseExpression(lowestPrec)
124-
125-
p.nextToken()
126-
body := p.parseBlock(tokenEnd)
127-
128-
if p.curToken.Type != tokenEnd {
129-
p.errorExpected(p.curToken, "end")
130-
}
131-
132-
return &WhileStmt{Condition: condition, Body: body, position: pos}
133-
}
134-
135-
func (p *parser) parseUntilStatement() Statement {
136-
pos := p.curToken.Pos
137-
p.nextToken()
138-
condition := p.parseExpression(lowestPrec)
139-
140-
p.nextToken()
141-
body := p.parseBlock(tokenEnd)
142-
143-
if p.curToken.Type != tokenEnd {
144-
p.errorExpected(p.curToken, "end")
145-
}
146-
147-
return &UntilStmt{Condition: condition, Body: body, position: pos}
148-
}
149-
150-
func (p *parser) parseBreakStatement() Statement {
151-
return &BreakStmt{position: p.curToken.Pos}
152-
}
153-
154-
func (p *parser) parseNextStatement() Statement {
155-
return &NextStmt{position: p.curToken.Pos}
156-
}
157-
158-
func (p *parser) parseBeginStatement() Statement {
159-
pos := p.curToken.Pos
160-
p.nextToken()
161-
body := p.parseBlock(tokenRescue, tokenEnsure, tokenEnd)
162-
163-
var rescueTy *TypeExpr
164-
var rescueBody []Statement
165-
if p.curToken.Type == tokenRescue {
166-
rescuePos := p.curToken.Pos
167-
if p.peekToken.Type == tokenLParen && p.peekToken.Pos.Line == rescuePos.Line {
168-
p.nextToken()
169-
p.nextToken()
170-
rescueTy = p.parseTypeExpr()
171-
if rescueTy == nil {
172-
return nil
173-
}
174-
if !p.validateRescueTypeExpr(rescueTy, rescuePos) {
175-
return nil
176-
}
177-
if !p.expectPeek(tokenRParen) {
178-
return nil
179-
}
180-
}
181-
p.nextToken()
182-
rescueBody = p.parseBlock(tokenEnsure, tokenEnd)
183-
}
184-
185-
var ensureBody []Statement
186-
if p.curToken.Type == tokenEnsure {
187-
p.nextToken()
188-
ensureBody = p.parseBlock(tokenEnd)
189-
}
190-
191-
if p.curToken.Type != tokenEnd {
192-
p.errorExpected(p.curToken, "end")
193-
return nil
194-
}
195-
196-
if len(rescueBody) == 0 && len(ensureBody) == 0 {
197-
p.addParseError(pos, "begin requires rescue and/or ensure")
198-
return nil
199-
}
200-
201-
return &TryStmt{Body: body, RescueTy: rescueTy, Rescue: rescueBody, Ensure: ensureBody, position: pos}
202-
}
203-
204-
func (p *parser) validateRescueTypeExpr(ty *TypeExpr, pos Position) bool {
205-
if ty == nil {
206-
p.addParseError(pos, "rescue type cannot be empty")
207-
return false
208-
}
209-
210-
if ty.Kind == TypeUnion {
211-
ok := true
212-
for _, option := range ty.Union {
213-
if !p.validateRescueTypeExpr(option, option.position) {
214-
ok = false
215-
}
216-
}
217-
return ok
218-
}
219-
220-
if len(ty.TypeArgs) > 0 || len(ty.Shape) > 0 {
221-
p.addParseError(pos, fmt.Sprintf("rescue type must be an error class, got %s", formatTypeExpr(ty)))
222-
return false
223-
}
224-
if _, ok := canonicalRuntimeErrorType(ty.Name); !ok {
225-
p.addParseError(pos, fmt.Sprintf("unknown rescue error type %s", ty.Name))
226-
return false
227-
}
228-
return true
229-
}
230-
23161
func (p *parser) parseBlock(stop ...TokenType) []Statement {
23262
stmts := []Statement{}
23363
stopSet := make(map[TokenType]struct{}, len(stop))

0 commit comments

Comments
 (0)