Skip to content

Commit c75da7b

Browse files
control flow
1 parent 9af082a commit c75da7b

File tree

9 files changed

+322
-23
lines changed

9 files changed

+322
-23
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,12 @@ Following the order in the [book](https://craftinginterpreters.com/contents.html
5959
* [ ] Interpreter:
6060
* [x] Expressions
6161
* [x] Statements
62-
* [ ] Control flow
62+
* [x] Control flow
6363
* [ ] Functions
6464
* [ ] Variable binding
6565
* [ ] Classes
6666
* [ ] Inheritance
67+
* [ ] Tests
6768

6869
## License
6970

examples/control.lox

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// control flow examples
2+
3+
var i = 0;
4+
while (i < 10) {
5+
if (i == 7)
6+
print "7 (an auspicious number)";
7+
else
8+
print i;
9+
i = i + 1;
10+
}
11+
12+
print "Fibonacci sequence:";
13+
var a = 0;
14+
var temp;
15+
for (var b = 1; a < 10000; b = temp + b) {
16+
print a;
17+
temp = a;
18+
a = b;
19+
}

src/ASTPrinter.st

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Object subclass: ASTPrinter [
5353
| str |
5454
str := WriteStream on: String new.
5555

56-
str
56+
str
5757
nextPutAll: '(' , aName;
5858
nextPutAll: ' ' , (first accept: self).
5959
second ifNotNil: [ str nextPutAll: ' ' , (second accept: self) ].

src/Environment.st

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ Object subclass: Environment [
6565
values at: aName lexeme put: aValue.
6666
^aValue.
6767
].
68-
68+
6969
enclosing ifNotNil: [ ^enclosing assign: aName value: aValue ].
70-
70+
7171
^RuntimeError
7272
error: aName
7373
message: 'Undefined variable ''' , aName lexeme , '''.'.

src/Expr.st

+48-1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,53 @@ Expr subclass: ExprLiteral [
137137
]
138138
]
139139

140+
Expr subclass: ExprLogical [
141+
| left operator right |
142+
143+
ExprLogical class >> left: aLeft operator: anOperator right: aRight [
144+
<category: 'instance creation'>
145+
^self new
146+
left: aLeft;
147+
operator: anOperator;
148+
right: aRight;
149+
yourself.
150+
]
151+
152+
left: aLeft [
153+
<category: 'setter'>
154+
left := aLeft.
155+
]
156+
157+
left [
158+
<category: 'getter'>
159+
^left.
160+
]
161+
162+
operator: anOperator [
163+
<category: 'setter'>
164+
operator := anOperator.
165+
]
166+
167+
operator [
168+
<category: 'getter'>
169+
^operator.
170+
]
171+
172+
right: aRight [
173+
<category: 'setter'>
174+
right := aRight.
175+
]
176+
177+
right [
178+
<category: 'getter'>
179+
^right.
180+
]
181+
182+
accept: aVisitor [
183+
^aVisitor visitLogicalExpr: self.
184+
]
185+
]
186+
140187
Expr subclass: ExprUnary [
141188
| operator right |
142189

@@ -196,4 +243,4 @@ Expr subclass: ExprVariable [
196243
accept: aVisitor [
197244
^aVisitor visitVariableExpr: self.
198245
]
199-
]
246+
]

src/Interpreter.st

+47-7
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,20 @@ Object subclass: Interpreter [
131131
self evaluate: stmt expression.
132132
]
133133

134+
visitIfStmt: stmt [
135+
"Evaluate an if statement"
136+
137+
<category: 'evaluation'>
138+
(self isTruthy: (self evaluate: stmt condition)) ifTrue: [
139+
self execute: stmt thenBranch
140+
] ifFalse: [
141+
stmt elseBranch ifNotNil: [
142+
self execute: stmt elseBranch
143+
]
144+
].
145+
^nil.
146+
]
147+
134148
visitPrintStmt: stmt [
135149
"Evaluate a print statement"
136150

@@ -153,6 +167,16 @@ Object subclass: Interpreter [
153167
^nil.
154168
]
155169

170+
visitWhileStmt: stmt [
171+
"Evaluate a while statement"
172+
173+
<category: 'evaluation'>
174+
[ self isTruthy: (self evaluate: stmt condition) ] whileTrue: [
175+
self execute: stmt body
176+
].
177+
^nil.
178+
]
179+
156180
visitAssignExpr: expr [
157181
"Evaluate a variable assignment expression"
158182

@@ -170,6 +194,22 @@ Object subclass: Interpreter [
170194
^expr value.
171195
]
172196

197+
visitLogicalExpr: expr [
198+
"Evaluate a logical expression"
199+
200+
<category: 'evaluation'>
201+
| left operator type|
202+
left := self evaluate: expr left.
203+
operator := expr operator.
204+
type := operator type.
205+
type = #Or ifTrue: [
206+
(self isTruthy: left) ifTrue: [ ^left ]
207+
] ifFalse: [
208+
(self isTruthy: left) ifFalse: [ ^left ]
209+
].
210+
^self evaluate: expr right.
211+
]
212+
173213
visitGroupingExpr: expr [
174214
"Evaluate a grouping expression"
175215

@@ -185,13 +225,13 @@ Object subclass: Interpreter [
185225
right := self evaluate: expr right.
186226
operator := expr operator.
187227
type := operator type.
188-
228+
189229
type = #Bang ifTrue: [ ^self isTruthy: right not ].
190230
type = #Minus ifTrue: [
191231
self checkNumber: operator operand: right.
192232
^right negated
193233
].
194-
234+
195235
"Unreachable"
196236
^nil
197237
]
@@ -237,13 +277,13 @@ Object subclass: Interpreter [
237277
].
238278
type = #Plus ifTrue: [
239279
((left respondsTo: #+) & (right respondsTo: #+)) ifTrue: [
240-
^left + right
280+
^left + right
241281
].
242282

243283
((left respondsTo: #,) & (right respondsTo: #,)) ifTrue: [
244-
^left , right
284+
^left , right
245285
].
246-
286+
247287
^RuntimeError
248288
error: expr operator
249289
message: 'Operands must be two numbers or two strings.'
@@ -256,8 +296,8 @@ Object subclass: Interpreter [
256296
self checkNumber: operator left: left right: right.
257297
^left * right
258298
].
259-
299+
260300
"Unreachable"
261-
^nil
301+
^nil
262302
]
263303
]

src/Parser.st

+108-4
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ the Lox programming language.'>
113113
].
114114
^false.
115115
]
116-
116+
117117
parse [
118118
"Parse the source tokens into a list of statements"
119119

@@ -152,11 +152,73 @@ the Lox programming language.'>
152152
"Grammar rule for a statement"
153153

154154
<category: 'rule'>
155+
(self match: #(#For)) ifTrue: [ ^self forStatement ].
156+
(self match: #(#If)) ifTrue: [ ^self ifStatement ].
155157
(self match: #(#Print)) ifTrue: [ ^self printStatement ].
158+
(self match: #(#While)) ifTrue: [ ^self whileStatement ].
156159
(self match: #(#LeftBrace)) ifTrue: [ ^StmtBlock statements: self block ].
157160
^self expressionStatement.
158161
]
159162

163+
forStatement [
164+
"Grammar rule for desugaring a for statement"
165+
166+
<category: 'rule'>
167+
| ini cond incr body stmts |
168+
self consume: #LeftParen expect: 'Expect ''('' after ''for''.'.
169+
170+
(self match: #(#Semicolon)) ifTrue: [ ini := nil ].
171+
(self match: #(#Var)) ifTrue: [
172+
ini := self varDeclaration
173+
] ifFalse: [
174+
ini := self expressionStatement
175+
].
176+
177+
cond := nil.
178+
(self check: #Semicolon) ifFalse: [ cond := self expression ].
179+
self consume: #Semicolon expect: 'Expect '';'' after loop condition.'.
180+
181+
incr := nil.
182+
(self check: #RightParen) ifFalse: [ incr := self expression ].
183+
self consume: #RightParen expect: 'Expect '')'' after for clauses.'.
184+
body := self statement.
185+
186+
incr ifNotNil: [
187+
stmts := OrderedCollection new.
188+
stmts
189+
add: body;
190+
add: (StmtExpression expression: incr).
191+
body := StmtBlock statements: stmts
192+
].
193+
194+
cond ifNil: [ cond := ExprLiteral value: true ].
195+
body := StmtWhile condition: cond body: body.
196+
197+
ini ifNotNil: [
198+
stmts := OrderedCollection new.
199+
stmts
200+
add: ini;
201+
add: body.
202+
body := StmtBlock statements: stmts
203+
].
204+
205+
^body.
206+
]
207+
208+
ifStatement [
209+
"Grammar rule for an if statement"
210+
211+
<category: 'rule'>
212+
| cond then else |
213+
self consume: #LeftParen expect: 'Expect ''('' after ''if''.'.
214+
cond := self expression.
215+
self consume: #RightParen expect: 'Expect '')'' after if condition.'.
216+
then := self statement.
217+
else := nil.
218+
(self match: #(#Else)) ifTrue: [ else := self statement ].
219+
^StmtIf condition: cond thenBranch: then elseBranch: else.
220+
]
221+
160222
printStatement [
161223
"Grammar rule for a print statement"
162224

@@ -167,6 +229,18 @@ the Lox programming language.'>
167229
^StmtPrint expression: value.
168230
]
169231

232+
whileStatement [
233+
"Grammar rule for a while statement"
234+
235+
<category: 'rule'>
236+
| cond body |
237+
self consume: #LeftParen expect: 'Expect ''('' after ''while''.'.
238+
cond := self expression.
239+
self consume: #RightParen expect: 'Expect '')'' after condition.'.
240+
body := self statement.
241+
^StmtWhile condition: cond body: body.
242+
]
243+
170244
expressionStatement [
171245
"Grammar rule for an expression statement"
172246

@@ -202,7 +276,7 @@ the Lox programming language.'>
202276

203277
<category: 'rule'>
204278
| expr equals value name |
205-
expr := self equality.
279+
expr := self or.
206280

207281
(self match: #(#Equal)) ifTrue: [
208282
equals := self previous.
@@ -219,6 +293,36 @@ the Lox programming language.'>
219293
^expr.
220294
]
221295

296+
or [
297+
"Grammar rule for an or expression"
298+
299+
<category: 'rule'>
300+
| expr operator right |
301+
expr := self and.
302+
303+
[ self match: #(#Or) ] whileTrue: [
304+
operator := self previous.
305+
right := self and.
306+
expr := ExprLogical left: expr operator: operator right: right
307+
].
308+
^expr.
309+
]
310+
311+
and [
312+
"Grammar rule for an and expression"
313+
314+
<category: 'rule'>
315+
| expr operator right |
316+
expr := self equality.
317+
318+
[ self match: #(#And) ] whileTrue: [
319+
operator := self previous.
320+
right := self equality.
321+
expr := ExprLogical left: expr operator: operator right: right
322+
].
323+
^expr.
324+
]
325+
222326
equality [
223327
"Grammar rule for an equality"
224328

@@ -296,7 +400,7 @@ the Lox programming language.'>
296400
(self match: #(#False)) ifTrue: [ ^ExprLiteral value: false ].
297401
(self match: #(#True)) ifTrue: [ ^ExprLiteral value: true ].
298402
(self match: #(#Nil)) ifTrue: [ ^ExprLiteral value: nil ].
299-
403+
300404
(self match: #(#Number #String)) ifTrue: [
301405
^ExprLiteral value: (self previous literal)
302406
].
@@ -310,7 +414,7 @@ the Lox programming language.'>
310414
self consume: #RightParen expect: 'Expect '')'' after expression'.
311415
^ExprGrouping expression: expr
312416
].
313-
417+
314418
^ParseError error: (self peek) message: 'Expected expression'.
315419
]
316420
]

0 commit comments

Comments
 (0)