Skip to content

Commit

Permalink
Start working on parser tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lgyanf committed Sep 30, 2023
1 parent 991ed94 commit 7c7c483
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 28 deletions.
7 changes: 7 additions & 0 deletions src/ast/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ impl Expr {
pub fn boxed(&self) -> Box<Self> {
Box::new(self.clone())
}

pub fn with_new_position(self, new_position: PositionRange) -> Self {
Self {
expr_type: self.expr_type,
position: new_position,
}
}
}

impl Display for Expr {
Expand Down
82 changes: 57 additions & 25 deletions src/ast/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,14 @@ impl Parser<'_> {
}
_ => None,
};
self.consume_semicolon(&var_keyword.position, "variable declaration")?;
let semicolon = self.consume_semicolon(&var_keyword.position, "variable declaration")?;
Ok(Statement::Var {
name: name.clone(),
initializer,
position: PositionRange {
start: var_keyword.position.start.clone(),
end: semicolon.position.end.clone(),
},
})
}

Expand All @@ -94,16 +98,30 @@ impl Parser<'_> {

fn print_statement(&mut self) -> Result<Statement, LoxError> {
// consume 'print' keyword
let expression_start = self.token_iterator.next().unwrap();
let print_keyword = self.token_iterator.next().unwrap();
let expr = self.expression()?;
self.consume_semicolon(&expression_start.position, "value")?;
Ok(Statement::Print { expr })
let semicolon = self.consume_semicolon(&expr.position, "value")?;
let end_position = semicolon.position.end.clone();
Ok(Statement::Print {
expr,
position: PositionRange {
start: print_keyword.position.start.clone(),
end: end_position,
},
})
}

fn expression_statement(&mut self) -> Result<Statement, LoxError> {
let expr = self.expression()?;
self.consume_semicolon(&expr.position, "expression")?;
Ok(Statement::Expression { expr })
let semicolon = self.consume_semicolon(&expr.position, "expression")?;
let statement_start = expr.position.start.clone();
Ok(Statement::Expression {
expr,
position: PositionRange {
start: statement_start,
end: semicolon.position.end.clone(),
},
})
}

fn expression(&mut self) -> Result<Expr, LoxError> {
Expand Down Expand Up @@ -277,16 +295,16 @@ impl Parser<'_> {
&mut self,
expression_start: &PositionRange,
error_message_suffix: &str,
) -> Result<(), LoxError> {
) -> Result<&Token, LoxError> {
let next_token_type = self
.token_iterator
.peek()
.map(|t| t.type_.to_string())
.unwrap_or_else(|| "<EOF>".to_owned());
match self.token_iterator.peek() {
Some(token) if token.type_ == TokenType::Semicolon => {
self.token_iterator.next();
Ok(())
let semicolon = self.token_iterator.next().unwrap();
Ok(semicolon)
}
_ => Err(LoxError {
kind: LoxErrorKind::Syntax,
Expand Down Expand Up @@ -342,27 +360,41 @@ mod parser_tests {
#[test]
fn $name() {
let (input, expected) = $value;
let expr = parse(input);
let expr = parse(&input);
assert_eq!(expr, expected);
}
)*
}
}

// parametrized_tests!(
// empty_string: (vec![], Ok(vec![]),),
// number_literal:
// (
// vec![
// Token::new_number(123.1, 1),
// Token::new(TokenType::Semicolon, 1),
// ],
// Ok(
// vec![Statement::Expression {
// expr: Expr::number_literal(123.1, 1),
// }],
// )
// ),
fn range(line: usize, start_column: usize, end_column: usize) -> PositionRange {
PositionRange {
start: Position {
line,
column: start_column,
},
end: Position {
line,
column: end_column,
},
}
}

parametrized_tests!(
empty_string: (vec![], Ok(vec![]),),
number_literal:
(
vec![
Token::new_number(123.1, range(1, 1, 5)),
Token::new(TokenType::Semicolon, range(1, 6, 6)),
],
Ok(
vec![Statement::Expression {
expr: Expr::number_literal(123.1, range(1, 1, 5)),
position: range(1, 1, 6),
}],
)
),
// number_sum:
// (
// vec![
Expand Down Expand Up @@ -573,5 +605,5 @@ mod parser_tests {
// }],
// )
// ),
// );
);
}
19 changes: 19 additions & 0 deletions src/ast/statement.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
use crate::position::PositionRange;

use super::expr::Expr;

#[derive(Debug, Clone, PartialEq)]
pub enum Statement {
Expression {
expr: Expr,
position: PositionRange,
},
Print {
expr: Expr,
position: PositionRange,
},
Var {
name: String,
initializer: Option<Expr>,
position: PositionRange,
},
}

impl Statement {
fn position(&self) -> &PositionRange {
match &self {
Self::Expression { expr: _, position } => position,
Self::Print { expr: _, position } => position,
Self::Var {
name: _,
initializer: _,
position,
} => position,
}
}
}
10 changes: 7 additions & 3 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,15 +205,19 @@ impl StatementVisitor for Interpreter<'_> {

fn visit_statement(&mut self, statement: &ast::Statement) -> Self::Result {
match statement {
ast::Statement::Expression { expr } => {
ast::Statement::Expression { expr, position: _ } => {
self.visit_expr(expr)?;
}
ast::Statement::Print { expr } => {
ast::Statement::Print { expr, position: _ } => {
let value = self.visit_expr(expr)?;
println!("{}", value);
writeln!(self.stdout, "{}", value);
}
ast::Statement::Var { name, initializer } => {
ast::Statement::Var {
name,
initializer,
position: _,
} => {
let value = match initializer {
None => Value::Nil,
Some(expr) => self.interpret_expression(expr)?,
Expand Down

0 comments on commit 7c7c483

Please sign in to comment.