Skip to content

Commit b3f9e98

Browse files
committed
feat: add if expression ast
1 parent 5e5b1a7 commit b3f9e98

File tree

5 files changed

+116
-13
lines changed

5 files changed

+116
-13
lines changed

interpreter/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ fn eval_expression(expression: &Expression, env: &Env) -> Result<Rc<Object>, Eva
7070
let right = eval_expression(right, &Rc::clone(env))?;
7171
return eval_infix(op, &left, &right);
7272
}
73-
Expression::IF(condition, consequence, alternative) => {
73+
Expression::IF(IF { condition, consequent, alternate, .. }) => {
7474
let condition = eval_expression(condition, &Rc::clone(env))?;
7575
if is_truthy(&condition) {
76-
eval_block_statements(&(consequence.0), env)
76+
eval_block_statements(&(consequent.0), env)
7777
} else {
78-
match alternative {
78+
match alternate {
7979
Some(alt) => eval_block_statements(&(alt.0), env),
8080
None => Ok(Rc::new(Object::Null))
8181
}

parser/ast.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ pub enum Expression {
8989
LITERAL(Literal),
9090
PREFIX(UnaryExpression),
9191
INFIX(BinaryExpression),
92-
IF(Box<Expression>, BlockStatement, Option<BlockStatement>),
92+
IF(IF),
9393
FUNCTION(Vec<String>, BlockStatement),
9494
FunctionCall(Box<Expression>, Vec<Expression>), // function can be Identifier or FunctionLiteral (think iife)
9595
Index(Box<Expression>, Box<Expression>),
@@ -116,6 +116,14 @@ pub struct BinaryExpression {
116116
pub span: Span,
117117
}
118118

119+
#[derive(Clone, Debug, Serialize, Deserialize, Eq, Hash, PartialEq)]
120+
pub struct IF {
121+
pub condition: Box<Expression>,
122+
pub consequent: BlockStatement,
123+
pub alternate: Option<BlockStatement>,
124+
pub span: Span,
125+
}
126+
119127
impl fmt::Display for Expression {
120128
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
121129
match self {
@@ -127,19 +135,19 @@ impl fmt::Display for Expression {
127135
Expression::INFIX(BinaryExpression { op, left, right, .. }) => {
128136
write!(f, "({} {} {})", left, op.kind, right)
129137
},
130-
Expression::IF(condition, if_block, else_block) => {
131-
if let Some(else_block) = else_block {
138+
Expression::IF(IF { condition, consequent, alternate, .. }) => {
139+
if let Some(else_block) = alternate {
132140
write!(f,
133141
"if {} {{ {} }} else {{ {} }}",
134142
condition,
135-
if_block,
136-
else_block
143+
consequent,
144+
else_block,
137145
)
138146
} else {
139147
write!(f,
140148
"if {} {{ {} }}",
141149
condition,
142-
if_block,
150+
consequent,
143151
)
144152
}
145153
}

parser/ast_tree_test.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,10 @@ mod tests {
5454
let input = "1 + 2 * 3";
5555
test_ast_tree("test_binary", input)
5656
}
57+
58+
#[test]
59+
fn test_if() {
60+
let input = "if (x < y) { x } else { y }";
61+
test_ast_tree("test_if", input)
62+
}
5763
}

parser/lib.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub extern crate lexer;
66

77
use lexer::token::{TokenKind, Token, Span};
88
use lexer::Lexer;
9-
use crate::ast::{Program, Statement, Expression, Node, Literal, BlockStatement, Let, Integer, Boolean, StringType, Array, Hash, UnaryExpression, BinaryExpression, IDENTIFIER};
9+
use crate::ast::{Program, Statement, Expression, Node, Literal, BlockStatement, Let, Integer, Boolean, StringType, Array, Hash, UnaryExpression, BinaryExpression, IDENTIFIER, IF};
1010
use crate::precedences::{Precedence, get_token_precedence};
1111

1212
type ParseError = String;
@@ -268,24 +268,35 @@ impl<'a> Parser<'a> {
268268
}
269269

270270
fn parse_if_expression(&mut self) -> Result<Expression, ParseError> {
271+
let start = self.current_token.span.start;
271272
self.expect_peek(&TokenKind::LPAREN)?;
272273
self.next_token();
273274

274275
let condition = self.parse_expression(Precedence::LOWEST)?.0;
275276
self.expect_peek(&TokenKind::RPAREN)?;
276277
self.expect_peek(&TokenKind::LBRACE)?;
277278

278-
let consequence = self.parse_block_statement()?;
279+
let consequent = self.parse_block_statement()?;
279280

280-
let alternative = if self.peek_token_is(&TokenKind::ELSE) {
281+
let alternate = if self.peek_token_is(&TokenKind::ELSE) {
281282
self.next_token();
282283
self.expect_peek(&TokenKind::LBRACE)?;
283284
Some(self.parse_block_statement()?)
284285
} else {
285286
None
286287
};
287288

288-
return Ok(Expression::IF(Box::new(condition), consequence, alternative));
289+
let end = self.current_token.span.end;
290+
291+
return Ok(Expression::IF(IF {
292+
condition: Box::new(condition),
293+
consequent,
294+
alternate,
295+
span: Span {
296+
start,
297+
end,
298+
}
299+
}));
289300
}
290301

291302
fn parse_block_statement(&mut self) -> Result<BlockStatement, ParseError> {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
source: parser/ast_tree_test.rs
3+
expression: let_ast
4+
---
5+
{
6+
"Program": {
7+
"body": [
8+
{
9+
"type": "Expr",
10+
"IF": {
11+
"condition": {
12+
"INFIX": {
13+
"op": {
14+
"span": {
15+
"start": 6,
16+
"end": 7
17+
},
18+
"kind": {
19+
"type": "LT"
20+
}
21+
},
22+
"left": {
23+
"IDENTIFIER": {
24+
"name": "x",
25+
"span": {
26+
"start": 4,
27+
"end": 5
28+
}
29+
}
30+
},
31+
"right": {
32+
"IDENTIFIER": {
33+
"name": "y",
34+
"span": {
35+
"start": 8,
36+
"end": 9
37+
}
38+
}
39+
},
40+
"span": {
41+
"start": 4,
42+
"end": 9
43+
}
44+
}
45+
},
46+
"consequent": [
47+
{
48+
"type": "Expr",
49+
"IDENTIFIER": {
50+
"name": "x",
51+
"span": {
52+
"start": 13,
53+
"end": 14
54+
}
55+
}
56+
}
57+
],
58+
"alternate": [
59+
{
60+
"type": "Expr",
61+
"IDENTIFIER": {
62+
"name": "y",
63+
"span": {
64+
"start": 24,
65+
"end": 25
66+
}
67+
}
68+
}
69+
],
70+
"span": {
71+
"start": 0,
72+
"end": 27
73+
}
74+
}
75+
}
76+
]
77+
}
78+
}

0 commit comments

Comments
 (0)