This commit is contained in:
me 2025-12-20 23:30:08 +02:00
parent 01d49ff724
commit 62ff55df7a
8 changed files with 232 additions and 8 deletions

View file

@ -30,13 +30,6 @@ pub enum Expr {
},
Record(BTreeMap<Label, Expr>),
Vector(Vec<Expr>),
/*
Loop {
body: Box<Expr>,
},
Continue,
Break,
*/
}
#[derive(PartialEq, PartialOrd, Debug, Clone)]
@ -80,6 +73,8 @@ pub enum Statement {
Expr(Expr),
Let(Definition),
Return(Option<Expr>),
Loop(Box<Expr>),
Break,
}
#[derive(PartialEq, PartialOrd, Debug, Clone)]
@ -103,6 +98,7 @@ pub enum Value {
Closure { env: EnvName, expr: Box<Expr> },
PrimitiveFunc(Name),
Return(Box<Value>),
Break,
}
/// A mutable variable.

View file

@ -48,6 +48,7 @@ pub fn run(
enum StatementResult {
Result(ast::Value),
Return(ast::Value),
Break,
}
fn eval_statement(
@ -56,7 +57,11 @@ fn eval_statement(
statement: &ast::Statement,
) -> Result<StatementResult, Error> {
match statement {
ast::Statement::Expr(expr) => eval_expr(expr_env, state, expr).map(StatementResult::Result),
ast::Statement::Expr(expr) => match eval_expr(expr_env, state, expr)? {
ast::Value::Break => Ok(StatementResult::Break),
ast::Value::Return(v) => Ok(StatementResult::Return(*v)),
v => Ok(StatementResult::Result(v)),
},
ast::Statement::Let(ast::Definition {
mutable,
name,
@ -74,6 +79,18 @@ fn eval_statement(
Some(expr) => eval_expr(expr_env, state, expr).map(StatementResult::Return),
None => eval_expr(expr_env, state, &ast::UNIT).map(StatementResult::Return),
},
ast::Statement::Break => Ok(StatementResult::Break),
ast::Statement::Loop(expr) => {
loop {
match eval_expr(expr_env, state, expr)? {
ast::Value::Break => {
break;
}
_ => {}
}
}
Ok(StatementResult::Result(ast::UNIT_VALUE))
}
}
}
@ -106,6 +123,10 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result<ast:
for statement in statements {
let r = eval_statement(&mut block_env, state, statement)?;
match r {
StatementResult::Break => {
result = ast::Value::Break;
break;
}
StatementResult::Result(ast::Value::Return(r)) => {
result = ast::Value::Return(r);
break;

View file

@ -68,6 +68,28 @@ let main = fn() {
insta::assert_debug_snapshot!(result);
}
#[test]
fn loop_counter_9() {
let program = "
let counter = fn(a,b) {
let mut count = 0;
loop {
if (a + count) >= b {
break;
};
count = count + 1;
};
count
}
let main = fn() {
counter(1,10)
}
";
let result = run_main(program);
insta::assert_debug_snapshot!(result);
}
#[test]
fn direction() {
let program = "

View file

@ -270,6 +270,30 @@ fn parse_statement(tokens: &mut Tokens) -> ParseResult<ast::Statement> {
Ok(None)
}
},
|tokens| {
if let Some(_) = tokens.next_if(&Token::Break) {
Ok(Some(ast::Statement::Break))
} else {
Ok(None)
}
},
|t| {
if let Some(_) = t.next_if(&Token::Loop) {
if let Some(block) = t
.between(&Token::OpenCurly, &Token::CloseCurly, parse_block)?
.map(ast::Expr::Block)
{
Ok(Some(ast::Statement::Loop(Box::new(block))))
} else {
Err(Error::UnexpectedTokenForParser(
"loop expression".into(),
t.next(),
))
}
} else {
Ok(None)
}
},
])
}
@ -515,6 +539,24 @@ mod tests {
insta::assert_debug_snapshot!(result);
}
#[test]
fn let_loop_count() {
let program = "
let counter = fn(a,b) {
let mut count = 0;
loop {
if (a + count) >= b {
break;
};
count = count + 1;
};
count
}
"
.to_string();
let result = parse(&mut scan(program), parse_program);
insta::assert_debug_snapshot!(result);
}
#[test]
fn full_program() {
let program = "
let setup = fn() {

View file

@ -306,6 +306,8 @@ pub fn scan(source: String) -> Tokens {
"if" => Token::If,
"else" => Token::Else,
"return" => Token::Return,
"loop" => Token::Loop,
"break" => Token::Break,
"true" => Token::True,
"false" => Token::False,
_ => Token::Identifier(str),

View file

@ -0,0 +1,128 @@
---
source: src/parser/parser.rs
expression: result
---
Ok(
Program(
[
Definition {
mutable: false,
name: Name(
"counter",
),
expr: Func(
Fn {
args: [
Arg {
name: Name(
"a",
),
},
Arg {
name: Name(
"b",
),
},
],
body: Block(
[
Let(
Definition {
mutable: true,
name: Name(
"count",
),
expr: Value(
Int(
0,
),
),
},
),
Loop(
Block(
[
Expr(
If {
condition: Op {
lhs: Op {
lhs: Var(
Name(
"a",
),
),
op: Calc(
Add,
),
rhs: Var(
Name(
"count",
),
),
},
op: Compare(
Gte,
),
rhs: Var(
Name(
"b",
),
),
},
then: Block(
[
Break,
],
),
else: Value(
Record(
Record(
{},
),
),
),
},
),
Expr(
Op {
lhs: Var(
Name(
"count",
),
),
op: Assign,
rhs: Op {
lhs: Var(
Name(
"count",
),
),
op: Calc(
Add,
),
rhs: Value(
Int(
1,
),
),
},
},
),
],
),
),
Expr(
Var(
Name(
"count",
),
),
),
],
),
},
),
},
],
),
)

View file

@ -37,6 +37,8 @@ pub enum Token {
False,
Equals,
Not,
Loop,
Break,
Op(Op),
Int(i32),
Float(f32),

View file

@ -0,0 +1,11 @@
---
source: src/lib.rs
expression: result
---
Ok(
Value(
Int(
9,
),
),
)