loops
This commit is contained in:
parent
01d49ff724
commit
62ff55df7a
8 changed files with 232 additions and 8 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
22
src/lib.rs
22
src/lib.rs
|
|
@ -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 = "
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
},
|
||||
),
|
||||
},
|
||||
],
|
||||
),
|
||||
)
|
||||
|
|
@ -37,6 +37,8 @@ pub enum Token {
|
|||
False,
|
||||
Equals,
|
||||
Not,
|
||||
Loop,
|
||||
Break,
|
||||
Op(Op),
|
||||
Int(i32),
|
||||
Float(f32),
|
||||
|
|
|
|||
11
src/snapshots/ayin__tests__loop_counter_9.snap
Normal file
11
src/snapshots/ayin__tests__loop_counter_9.snap
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
source: src/lib.rs
|
||||
expression: result
|
||||
---
|
||||
Ok(
|
||||
Value(
|
||||
Int(
|
||||
9,
|
||||
),
|
||||
),
|
||||
)
|
||||
Loading…
Add table
Reference in a new issue