Add whlie loop support

master
Nick Krichevsky 2024-05-24 11:09:41 -04:00
parent 32266d07f6
commit f2bde7ddcb
3 changed files with 37 additions and 1 deletions

View File

@ -68,6 +68,7 @@ fn do_ast_codegen<W: Write>(mut output: W) {
"If",
"condition: Expr, then_branch: Box<Stmt>, else_branch: Option<Box<Stmt>>",
),
("While", "condition: Expr, body: Box<Stmt>"),
]);
define_ast(&mut output, "Stmt", &statement_types).expect("failed to generate ast values");

View File

@ -269,6 +269,14 @@ impl StmtVisitor<Result<(), ScriptError>> for InterpreterRunner<'_> {
Ok(())
}
}
fn visit_while(&mut self, condition: &Expr, body: &Stmt) -> Result<(), ScriptError> {
while self.visit_expr(condition)?.is_truthy() {
self.visit_stmt(body)?;
}
Ok(())
}
}
fn convert_arithmetic_operands(

View File

@ -175,6 +175,8 @@ fn parse_statement<I: Iterator<Item = Token>>(
) -> Result<ParsedStatement, ParseError> {
if let Ok(token) = match_token_kind!(iter, TokenKind::If) {
parse_if_statement(iter, &token)
} else if let Ok(token) = match_token_kind!(iter, TokenKind::While) {
parse_while_statement(iter, &token)
} else if match_token_kind!(iter, TokenKind::Print).is_ok() {
parse_statement_containing_expression(
iter,
@ -205,7 +207,7 @@ fn parse_if_statement<I: Iterator<Item = Token>>(
let condition = parse_expression(iter)?;
match_token_kind!(iter, TokenKind::RightParen).map_err(|_| ParseError {
message: "Expected ')' after 'if'".to_string(),
message: "Expected ')' after 'if' condition".to_string(),
line: if_token.line().into(),
})?;
@ -224,6 +226,31 @@ fn parse_if_statement<I: Iterator<Item = Token>>(
Ok(ParsedStatement::Stmt { stmt: if_stmt })
}
fn parse_while_statement<I: Iterator<Item = Token>>(
iter: &mut Peekable<I>,
while_token: &Token,
) -> Result<ParsedStatement, ParseError> {
match_token_kind!(iter, TokenKind::LeftParen).map_err(|_| ParseError {
message: "Expected '(' after 'while'".to_string(),
line: while_token.line().into(),
})?;
let condition = parse_expression(iter)?;
match_token_kind!(iter, TokenKind::RightParen).map_err(|_| ParseError {
message: "Expected ')' after 'while' condition".to_string(),
line: while_token.line().into(),
})?;
let body = parse_statement(iter).and_then(ensure_explicit_statement)?;
let while_stmt = Stmt::While {
condition,
body: Box::new(body),
};
Ok(ParsedStatement::Stmt { stmt: while_stmt })
}
fn parse_statement_containing_expression<
I: Iterator<Item = Token>,
F: Fn(Expr) -> Stmt,