Skip to content

Commit d1f8d67

Browse files
authored
Chapter 9: Control Flow (#6)
This implements [chapter 9](http://craftinginterpreters.com/control-flow.html). Most code should be a straight forward translation. Rust's `Option` and `if let` makes it easy to handle the cases when there is an initializer or not in a loop.
1 parent 941cbba commit d1f8d67

File tree

7 files changed

+246
-5
lines changed

7 files changed

+246
-5
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ Each commit corresponds to one chapter in the book:
99
* [Chapter 5: Representing Code](https://github.com/jeschkies/lox-rs/commit/0156a95b4bf448dbff9cb4341a2339b741a163ca)
1010
* [Chapter 6: Parsing Expressions](https://github.com/jeschkies/lox-rs/commit/9508c9d887a88540597d314520ae6aa045256e7d)
1111
* [Chapter 7: Evaluating Expressions](https://github.com/jeschkies/lox-rs/commit/fd90ef985c88832c9af6f193e0614e41dd13ef28)
12+
* [Chapter 8: Statements and State](https://github.com/jeschkies/lox-rs/commit/941cbba900acb5876dbe6031b24ef31ff81ca99e)

examples/loop.lox

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
var a = 0;
2+
var b = 1;
3+
4+
while (a < 10000) {
5+
print a;
6+
var temp = a;
7+
a = b;
8+
b = temp + b;
9+
}

examples/scope.lox

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
var a = "global a";
2+
var b = "global b";
3+
var c = "global c";
4+
{
5+
var a = "outer a";
6+
var b = "outer b";
7+
{
8+
var a = "inner a";
9+
print a;
10+
print b;
11+
print c;
12+
}
13+
print a;
14+
print b;
15+
print c;
16+
}
17+
print a;
18+
print b;
19+
print c;
20+

examples/simple.lox

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
print "one";
2+
print true;
3+
print 2 + 1;

src/interpreter.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,26 @@ impl expr::Visitor<Object> for Interpreter {
166166
}
167167
}
168168

169+
fn visit_logical_expr(
170+
&mut self,
171+
left: &Expr,
172+
operator: &Token,
173+
right: &Expr,
174+
) -> Result<Object, Error> {
175+
let l = self.evaluate(left)?;
176+
177+
if operator.tpe == TokenType::Or {
178+
if self.is_truthy(&l) {
179+
return Ok(l);
180+
}
181+
} else {
182+
if !self.is_truthy(&l) {
183+
return Ok(l);
184+
}
185+
}
186+
self.evaluate(right)
187+
}
188+
169189
fn visit_unary_expr(&mut self, operator: &Token, right: &Expr) -> Result<Object, Error> {
170190
let right = self.evaluate(right)?;
171191

@@ -204,6 +224,22 @@ impl stmt::Visitor<()> for Interpreter {
204224
Ok(())
205225
}
206226

227+
fn visit_if_stmt(
228+
&mut self,
229+
condition: &Expr,
230+
else_branch: &Option<Stmt>,
231+
then_branch: &Stmt,
232+
) -> Result<(), Error> {
233+
let condition_value = self.evaluate(condition)?;
234+
if self.is_truthy(&condition_value) {
235+
self.execute(then_branch)?;
236+
} else if let Some(other) = else_branch {
237+
self.execute(other)?;
238+
}
239+
240+
Ok(())
241+
}
242+
207243
fn visit_print_stmt(&mut self, expression: &Expr) -> Result<(), Error> {
208244
let value = self.evaluate(expression)?;
209245
println!("{}", self.stringify(value));
@@ -216,7 +252,19 @@ impl stmt::Visitor<()> for Interpreter {
216252
.map(|i| self.evaluate(i))
217253
.unwrap_or(Ok(Object::Null))?;
218254

219-
self.environment.borrow_mut().define(name.lexeme.clone(), value);
255+
self.environment
256+
.borrow_mut()
257+
.define(name.lexeme.clone(), value);
258+
Ok(())
259+
}
260+
261+
fn visit_while_stmt(&mut self, condition: &Expr, body: &Stmt) -> Result<(), Error> {
262+
let mut value = self.evaluate(condition)?;
263+
while self.is_truthy(&value) {
264+
self.execute(body)?;
265+
value = self.evaluate(condition)?
266+
}
267+
220268
Ok(())
221269
}
222270
}

src/parser.rs

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,14 @@ impl<'t> Parser<'t> {
5555
}
5656

5757
fn statement(&mut self) -> Result<Stmt, Error> {
58-
if matches!(self, TokenType::Print) {
58+
if matches!(self, TokenType::For) {
59+
self.for_statement()
60+
} else if matches!(self, TokenType::If) {
61+
self.if_statement()
62+
} else if matches!(self, TokenType::Print) {
5963
self.print_statement()
64+
} else if matches!(self, TokenType::While) {
65+
self.while_statement()
6066
} else if matches!(self, TokenType::LeftBrace) {
6167
Ok(Stmt::Block {
6268
statements: self.block()?,
@@ -66,6 +72,75 @@ impl<'t> Parser<'t> {
6672
}
6773
}
6874

75+
fn for_statement(&mut self) -> Result<Stmt, Error> {
76+
self.consume(TokenType::LeftParen, "Expect '(' after 'for'.")?;
77+
78+
let initializer = if matches!(self, TokenType::Semicolon) {
79+
None
80+
} else if matches!(self, TokenType::Var) {
81+
Some(self.var_declaration()?)
82+
} else {
83+
Some(self.expression_statement()?)
84+
};
85+
86+
let condition = if !self.check(TokenType::Semicolon) {
87+
Some(self.expression()?)
88+
} else {
89+
None
90+
};
91+
self.consume(TokenType::Semicolon, "Expect ';' after loop condition.")?;
92+
93+
let increment = if !self.check(TokenType::RightParen) {
94+
Some(self.expression()?)
95+
} else {
96+
None
97+
};
98+
self.consume(TokenType::RightParen, "Expect ')' after for clauses.")?;
99+
100+
let mut body = self.statement()?;
101+
102+
if let Some(inc) = increment {
103+
let inc_stmt = Stmt::Expression { expression: inc };
104+
body = Stmt::Block {
105+
statements: vec![body, inc_stmt],
106+
}
107+
}
108+
109+
body = Stmt::While {
110+
condition: condition.unwrap_or(Expr::Literal {
111+
value: LiteralValue::Boolean(true),
112+
}),
113+
body: Box::new(body),
114+
};
115+
116+
if let Some(init_stmt) = initializer {
117+
body = Stmt::Block {
118+
statements: vec![init_stmt, body],
119+
}
120+
}
121+
122+
Ok(body)
123+
}
124+
125+
fn if_statement(&mut self) -> Result<Stmt, Error> {
126+
self.consume(TokenType::LeftParen, "Expect '(' after 'if'.")?;
127+
let condition = self.expression()?;
128+
self.consume(TokenType::RightParen, "Expect ')' after if condition.")?;
129+
130+
let then_branch = Box::new(self.statement()?);
131+
let else_branch = if matches!(self, TokenType::Else) {
132+
Box::new(Some(self.statement()?))
133+
} else {
134+
Box::new(None)
135+
};
136+
137+
Ok(Stmt::If {
138+
condition,
139+
else_branch,
140+
then_branch,
141+
})
142+
}
143+
69144
fn print_statement(&mut self) -> Result<Stmt, Error> {
70145
let value = self.expression()?;
71146
self.consume(TokenType::Semicolon, "Expect ';' after value.")?;
@@ -88,6 +163,14 @@ impl<'t> Parser<'t> {
88163
Ok(Stmt::Var { name, initializer })
89164
}
90165

166+
fn while_statement(&mut self) -> Result<Stmt, Error> {
167+
self.consume(TokenType::LeftParen, "Expect '(' after 'while'.")?;
168+
let condition = self.expression()?;
169+
self.consume(TokenType::RightParen, "Expect ')' after condition.")?;
170+
let body = Box::new(self.statement()?);
171+
Ok(Stmt::While { condition, body })
172+
}
173+
91174
fn expression_statement(&mut self) -> Result<Stmt, Error> {
92175
let expr = self.expression()?;
93176
self.consume(TokenType::Semicolon, "Expect ';' after expression.")?;
@@ -106,7 +189,7 @@ impl<'t> Parser<'t> {
106189
}
107190

108191
fn assignment(&mut self) -> Result<Expr, Error> {
109-
let expr = self.equality()?;
192+
let expr = self.or_()?;
110193

111194
if matches!(self, TokenType::Equal) {
112195
let value = Box::new(self.assignment()?);
@@ -124,6 +207,38 @@ impl<'t> Parser<'t> {
124207
Ok(expr)
125208
}
126209

210+
fn or_(&mut self) -> Result<Expr, Error> {
211+
let mut expr = self.and_()?;
212+
213+
while matches!(self, TokenType::Or) {
214+
let operator: Token = (*self.previous()).clone();
215+
let right: Expr = self.and_()?;
216+
expr = Expr::Logical {
217+
left: Box::new(expr),
218+
operator: operator,
219+
right: Box::new(right),
220+
};
221+
}
222+
223+
Ok(expr)
224+
}
225+
226+
fn and_(&mut self) -> Result<Expr, Error> {
227+
let mut expr = self.equality()?;
228+
229+
while matches!(self, TokenType::And) {
230+
let operator: Token = (*self.previous()).clone();
231+
let right: Expr = self.equality()?;
232+
expr = Expr::Logical {
233+
left: Box::new(expr),
234+
operator: operator,
235+
right: Box::new(right),
236+
};
237+
}
238+
239+
Ok(expr)
240+
}
241+
127242
fn equality(&mut self) -> Result<Expr, Error> {
128243
let mut expr = self.comparison()?;
129244

src/syntax.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ pub enum Expr {
1919
Literal {
2020
value: LiteralValue,
2121
},
22+
Logical {
23+
left: Box<Expr>,
24+
operator: Token,
25+
right: Box<Expr>,
26+
},
2227
Unary {
2328
operator: Token,
2429
right: Box<Expr>,
@@ -64,6 +69,11 @@ impl Expr {
6469
} => visitor.visit_binary_expr(left, operator, right),
6570
Expr::Grouping { expression } => visitor.visit_grouping_expr(expression),
6671
Expr::Literal { value } => visitor.visit_literal_expr(value),
72+
Expr::Logical {
73+
left,
74+
operator,
75+
right,
76+
} => visitor.visit_logical_expr(left, operator, right),
6777
Expr::Unary { operator, right } => visitor.visit_unary_expr(operator, right),
6878
Expr::Variable { name } => visitor.visit_variable_expr(name),
6979
}
@@ -91,6 +101,12 @@ pub mod expr {
91101
/// * `expression` - This is the *inner* expression of the grouping.
92102
fn visit_grouping_expr(&mut self, expression: &Expr) -> Result<R, Error>;
93103
fn visit_literal_expr(&self, value: &LiteralValue) -> Result<R, Error>;
104+
fn visit_logical_expr(
105+
&mut self,
106+
left: &Expr,
107+
operator: &Token,
108+
right: &Expr,
109+
) -> Result<R, Error>;
94110
fn visit_unary_expr(&mut self, operator: &Token, right: &Expr) -> Result<R, Error>;
95111
fn visit_variable_expr(&mut self, name: &Token) -> Result<R, Error>;
96112
}
@@ -103,13 +119,22 @@ pub enum Stmt {
103119
Expression {
104120
expression: Expr,
105121
},
122+
If {
123+
condition: Expr,
124+
else_branch: Box<Option<Stmt>>,
125+
then_branch: Box<Stmt>,
126+
},
106127
Print {
107128
expression: Expr,
108129
},
109130
Var {
110131
name: Token,
111132
initializer: Option<Expr>,
112133
},
134+
While {
135+
condition: Expr,
136+
body: Box<Stmt>,
137+
},
113138
Null, // TODO see how stmt is handled after synchronize
114139
}
115140

@@ -118,8 +143,14 @@ impl Stmt {
118143
match self {
119144
Stmt::Block { statements } => visitor.visit_block_stmt(statements),
120145
Stmt::Expression { expression } => visitor.visit_expression_stmt(expression),
146+
Stmt::If {
147+
condition,
148+
else_branch,
149+
then_branch,
150+
} => visitor.visit_if_stmt(condition, else_branch, then_branch),
121151
Stmt::Print { expression } => visitor.visit_print_stmt(expression),
122152
Stmt::Var { name, initializer } => visitor.visit_var_stmt(name, initializer),
153+
Stmt::While { condition, body } => visitor.visit_while_stmt(condition, body),
123154
Stmt::Null => unimplemented!(),
124155
}
125156
}
@@ -135,11 +166,16 @@ pub mod stmt {
135166
// fn visit_class_stmt(&self, Class stmt); TODO: Classes chapter
136167
fn visit_expression_stmt(&mut self, expression: &Expr) -> Result<R, Error>;
137168
// fn visit_function_stmt(&self, Function stmt); TODO: Functions chapter
138-
// fn visit_if_stmt(&self, If stmt); TODO: Control Flows chapter
169+
fn visit_if_stmt(
170+
&mut self,
171+
condition: &Expr,
172+
else_branch: &Option<Stmt>,
173+
then_branch: &Stmt,
174+
) -> Result<R, Error>;
139175
fn visit_print_stmt(&mut self, expression: &Expr) -> Result<R, Error>;
140176
// fn visit_return_stmt(&self, Return stmt); TODO: Functions chapter
141177
fn visit_var_stmt(&mut self, name: &Token, initializer: &Option<Expr>) -> Result<R, Error>;
142-
// fn visit_while_stmt(&self, While stmt); TODO: Control Flows chapter
178+
fn visit_while_stmt(&mut self, condition: &Expr, body: &Stmt) -> Result<R, Error>;
143179
}
144180
}
145181

@@ -181,6 +217,15 @@ impl expr::Visitor<String> for AstPrinter {
181217
Ok(value.to_string()) // check for null
182218
}
183219

220+
fn visit_logical_expr(
221+
&mut self,
222+
left: &Expr,
223+
operator: &Token,
224+
right: &Expr,
225+
) -> Result<String, Error> {
226+
self.parenthesize(operator.lexeme.clone(), vec![left, right])
227+
}
228+
184229
fn visit_unary_expr(&mut self, operator: &Token, right: &Expr) -> Result<String, Error> {
185230
self.parenthesize(operator.lexeme.clone(), vec![right])
186231
}

0 commit comments

Comments
 (0)