many fixes and full program tests

This commit is contained in:
me 2025-12-20 17:36:24 +02:00
parent 0abada448b
commit 7302265436
11 changed files with 159 additions and 26 deletions

View file

@ -1,23 +1,42 @@
let min = 40
let max = 101
let speed = 60 # how many degrees in a second
let setup = fn() { let setup = fn() {
return { return {
.color: { .color: {
.r: 0, .r: 0,
.g: 0, .g: 0,
.b: 0, .b: 0,
} },
.dir: 1,
}; };
}; }
let update = fn(state, input) { let update = fn(state, input) {
state.color.g = state.color.g + (random_u8() % 3) % 50; let dir = state.dir * speed * get_frame_time();
state.color.b = (state.color.b + 1) % 255; state.color.g = random_u8() % 1;
state.color.r = (state.color.r + dir) % max;
if state.color.r < min {
state.color.r = min;
};
state.dir =
if state.color.r >= (max - 1) {
-1
} else {
if state.color.r <= min {
1
} else {
state.dir
}
};
return state; return state;
}; }
let draw = fn(state) { let draw = fn(state) {
frame_clear(state.color.r, state.color.g, state.color.b); frame_clear(state.color.r, state.color.g, state.color.b);
}; }
let migrate = fn(state) { let migrate = fn(state) {
return { .player: { .pos: state.player.position } }; return { .player: { .pos: state.player.position } };
}; }

View file

@ -39,9 +39,10 @@ pub fn run(
program: ast::Program, program: ast::Program,
func: ast::Name, func: ast::Name,
args: Vec<ast::Expr>, args: Vec<ast::Expr>,
) -> Result<ast::Value, Error> { ) -> Result<ast::Expr, Error> {
let mut state = setup(program, PrimitiveFuncs::new(vec![]))?; let mut state = setup(program, PrimitiveFuncs::new(vec![]))?;
interpret(&mut state, func, args) let value = interpret(&mut state, func, args)?;
Ok(value_to_stadnalone_expr(&state, value).unwrap())
} }
enum StatementResult { enum StatementResult {
@ -153,7 +154,7 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result<ast:
} }
for (arg, e) in func.args.into_iter().zip(args.iter()) { for (arg, e) in func.args.into_iter().zip(args.iter()) {
let evalled = eval_expr(&closure_env, state, e)?; let evalled = eval_expr(&expr_env, state, e)?;
closure_env.insert(arg.name, evalled); closure_env.insert(arg.name, evalled);
} }
match eval_expr(&closure_env, state, &func.body)? { match eval_expr(&closure_env, state, &func.body)? {
@ -272,6 +273,28 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result<ast:
}; };
Ok(ast::Value::Boolean(cop(a, b))) Ok(ast::Value::Boolean(cop(a, b)))
} }
(ast::Value::Int(a), ast::Value::Float(b)) => {
let cop = match cop {
ast::Cmp::Eq => |a, b| a == b,
ast::Cmp::NotEq => |a, b| a != b,
ast::Cmp::Gt => |a, b| a > b,
ast::Cmp::Gte => |a, b| a >= b,
ast::Cmp::Lt => |a, b| a < b,
ast::Cmp::Lte => |a, b| a <= b,
};
Ok(ast::Value::Boolean(cop(a as f32, b)))
}
(ast::Value::Float(a), ast::Value::Int(b)) => {
let cop = match cop {
ast::Cmp::Eq => |a, b| a == b,
ast::Cmp::NotEq => |a, b| a != b,
ast::Cmp::Gt => |a, b| a > b,
ast::Cmp::Gte => |a, b| a >= b,
ast::Cmp::Lt => |a, b| a < b,
ast::Cmp::Lte => |a, b| a <= b,
};
Ok(ast::Value::Boolean(cop(a, b as f32)))
}
(ast::Value::Float(a), ast::Value::Float(b)) => { (ast::Value::Float(a), ast::Value::Float(b)) => {
let cop = match cop { let cop = match cop {
ast::Cmp::Eq => |a, b| a == b, ast::Cmp::Eq => |a, b| a == b,

View file

@ -9,7 +9,7 @@ use std::collections::HashMap;
pub enum Error { pub enum Error {
DuplicateEnvNames(ast::EnvName, Backtrace), DuplicateEnvNames(ast::EnvName, Backtrace),
DuplicateNames(ast::Name, Backtrace), DuplicateNames(ast::Name, Backtrace),
NameNotFound(ast::Name, Backtrace), NameNotFound(ast::Name, Env, Backtrace),
FieldNotFound(ast::Label, Backtrace), FieldNotFound(ast::Label, Backtrace),
EnvNotFound(ast::EnvName, Backtrace), EnvNotFound(ast::EnvName, Backtrace),
LastStatementNotAnExpr(Backtrace), LastStatementNotAnExpr(Backtrace),
@ -25,7 +25,7 @@ impl PartialEq for Error {
match (self, other) { match (self, other) {
(Error::DuplicateEnvNames(a1, _), Error::DuplicateEnvNames(a2, _)) => a1 == a2, (Error::DuplicateEnvNames(a1, _), Error::DuplicateEnvNames(a2, _)) => a1 == a2,
(Error::DuplicateNames(a1, _), Error::DuplicateNames(a2, _)) => a1 == a2, (Error::DuplicateNames(a1, _), Error::DuplicateNames(a2, _)) => a1 == a2,
(Error::NameNotFound(a1, _), Error::NameNotFound(a2, _)) => a1 == a2, (Error::NameNotFound(a1, _, _), Error::NameNotFound(a2, _, _)) => a1 == a2,
(Error::FieldNotFound(a1, _), Error::FieldNotFound(a2, _)) => a1 == a2, (Error::FieldNotFound(a1, _), Error::FieldNotFound(a2, _)) => a1 == a2,
(Error::EnvNotFound(a1, _), Error::EnvNotFound(a2, _)) => a1 == a2, (Error::EnvNotFound(a1, _), Error::EnvNotFound(a2, _)) => a1 == a2,
(Error::LastStatementNotAnExpr(_), Error::LastStatementNotAnExpr(_)) => true, (Error::LastStatementNotAnExpr(_), Error::LastStatementNotAnExpr(_)) => true,
@ -50,7 +50,7 @@ impl std::fmt::Display for Error {
) )
} }
Error::DuplicateNames(a, b) => write!(f, "Duplicate names: {a:?}\n{b}"), Error::DuplicateNames(a, b) => write!(f, "Duplicate names: {a:?}\n{b}"),
Error::NameNotFound(a, b) => write!(f, "Name not found: {a:?}\n{b}"), Error::NameNotFound(a, e, b) => write!(f, "Name not found: {a:?} in {e:#?}\n{b}"),
Error::FieldNotFound(a, b) => write!(f, "Field not found: {a:?}\n{b}"), Error::FieldNotFound(a, b) => write!(f, "Field not found: {a:?}\n{b}"),
Error::EnvNotFound(a, b) => write!(f, "Env not found: {a:?}\n{b}"), Error::EnvNotFound(a, b) => write!(f, "Env not found: {a:?}\n{b}"),
Error::LastStatementNotAnExpr(a) => { Error::LastStatementNotAnExpr(a) => {
@ -170,9 +170,14 @@ impl Env {
} }
} }
pub fn get(&self, name: &ast::Name) -> Result<&ast::Value, Error> { pub fn get(&self, name: &ast::Name) -> Result<&ast::Value, Error> {
self.env match self.env.get(name) {
.get(name) None => Err(Error::NameNotFound(
.ok_or(Error::NameNotFound(name.clone(), Backtrace::capture())) name.clone(),
self.clone(),
Backtrace::capture(),
)),
Some(v) => Ok(v),
}
} }
pub fn insert(&mut self, name: ast::Name, value: ast::Value) { pub fn insert(&mut self, name: ast::Name, value: ast::Value) {
self.env.insert(name.clone(), value); self.env.insert(name.clone(), value);

View file

@ -3,7 +3,7 @@ pub mod interpret;
pub mod parser; pub mod parser;
pub mod runtime; pub mod runtime;
pub fn run_main(code: &str) -> Result<ast::Value, String> { pub fn run_main(code: &str) -> Result<ast::Expr, String> {
match parser::parse_file(code.into()) { match parser::parse_file(code.into()) {
Err(err) => Err(format!("Error: {err:?}")), Err(err) => Err(format!("Error: {err:?}")),
Ok(program) => match interpret::run(program, "main".into(), vec![]) { Ok(program) => match interpret::run(program, "main".into(), vec![]) {
@ -63,6 +63,43 @@ let main = fn() {
}; };
return a; return a;
} }
";
let result = run_main(program);
insta::assert_debug_snapshot!(result);
}
#[test]
fn direction() {
let program = "
let main = fn() {
let state = setup();
update(state)
}
let setup = fn() {
return {
.color: {
.b: 254,
},
.dir: 1,
};
}
let update = fn(state) {
state.color.b = (state.color.b + state.dir) % 256;
state.dir =
if state.color.b == 255 {
-1
} else {
if state.color.b == 0 {
1
} else {
state.dir
}
};
return state;
}
"; ";
let result = run_main(program); let result = run_main(program);
insta::assert_debug_snapshot!(result); insta::assert_debug_snapshot!(result);

View file

@ -1,3 +1,4 @@
use macroquad::time::get_frame_time;
use rand::prelude::*; use rand::prelude::*;
use crate::ast; use crate::ast;
@ -5,7 +6,11 @@ use crate::interpret::PrimitiveFuncs;
use macroquad::prelude as mq; use macroquad::prelude as mq;
pub fn primitive_funcs() -> PrimitiveFuncs { pub fn primitive_funcs() -> PrimitiveFuncs {
PrimitiveFuncs::new(vec![("frame_clear", clear), ("random_u8", random_u8)]) PrimitiveFuncs::new(vec![
("frame_clear", clear),
("get_frame_time", frame_time),
("random_u8", random_u8),
])
} }
fn clear(args: Vec<ast::Value>) -> ast::Value { fn clear(args: Vec<ast::Value>) -> ast::Value {
@ -19,6 +24,7 @@ fn clear(args: Vec<ast::Value>) -> ast::Value {
fn to_u32(value: Option<&ast::Value>) -> u8 { fn to_u32(value: Option<&ast::Value>) -> u8 {
match value { match value {
Some(ast::Value::Int(i)) => *i as u8, Some(ast::Value::Int(i)) => *i as u8,
Some(ast::Value::Float(f)) => *f as u8,
_ => 0, _ => 0,
} }
} }
@ -27,3 +33,7 @@ fn random_u8(_args: Vec<ast::Value>) -> ast::Value {
let random: u8 = rand::rng().random::<u8>(); let random: u8 = rand::rng().random::<u8>();
ast::Value::Int(random as i32) ast::Value::Int(random as i32)
} }
fn frame_time(_args: Vec<ast::Value>) -> ast::Value {
ast::Value::Float(get_frame_time() as f32)
}

View file

@ -160,6 +160,7 @@ pub fn draw(state: &mut State) {
Ok(_) => {} Ok(_) => {}
Err(err) => println!("Error: {}", err), Err(err) => println!("Error: {}", err),
} }
draw_fps();
/* /*
println!( println!(

View file

@ -3,7 +3,9 @@ source: src/lib.rs
expression: result expression: result
--- ---
Ok( Ok(
Int( Value(
4, Int(
4,
),
), ),
) )

View file

@ -0,0 +1,30 @@
---
source: src/lib.rs
expression: result
---
Ok(
Record(
{
Label(
"color",
): Record(
{
Label(
"b",
): Value(
Int(
255,
),
),
},
),
Label(
"dir",
): Value(
Int(
-1,
),
),
},
),
)

View file

@ -3,7 +3,9 @@ source: src/lib.rs
expression: result expression: result
--- ---
Ok( Ok(
Int( Value(
108, Int(
108,
),
), ),
) )

View file

@ -3,7 +3,9 @@ source: src/lib.rs
expression: result expression: result
--- ---
Ok( Ok(
Int( Value(
3, Int(
3,
),
), ),
) )

View file

@ -3,7 +3,9 @@ source: src/lib.rs
expression: result expression: result
--- ---
Ok( Ok(
Int( Value(
4, Int(
4,
),
), ),
) )