From 7302265436e1e77553759dcf6a2da3a06eb465b3 Mon Sep 17 00:00:00 2001 From: me Date: Sat, 20 Dec 2025 17:36:24 +0200 Subject: [PATCH] many fixes and full program tests --- game.ayin | 33 +++++++++++++---- src/interpret/interpret.rs | 29 +++++++++++++-- src/interpret/types.rs | 17 ++++++--- src/lib.rs | 39 +++++++++++++++++++- src/runtime/primitive_functions.rs | 12 +++++- src/runtime/runtime.rs | 1 + src/snapshots/ayin__tests__bor_onearm_4.snap | 6 ++- src/snapshots/ayin__tests__direction.snap | 30 +++++++++++++++ src/snapshots/ayin__tests__int_108.snap | 6 ++- src/snapshots/ayin__tests__let_add_3.snap | 6 ++- src/snapshots/ayin__tests__let_if_4.snap | 6 ++- 11 files changed, 159 insertions(+), 26 deletions(-) create mode 100644 src/snapshots/ayin__tests__direction.snap diff --git a/game.ayin b/game.ayin index a4f1c49..e883f0a 100644 --- a/game.ayin +++ b/game.ayin @@ -1,23 +1,42 @@ +let min = 40 +let max = 101 +let speed = 60 # how many degrees in a second + let setup = fn() { return { .color: { .r: 0, .g: 0, .b: 0, - } + }, + .dir: 1, }; -}; +} let update = fn(state, input) { - state.color.g = state.color.g + (random_u8() % 3) % 50; - state.color.b = (state.color.b + 1) % 255; + let dir = state.dir * speed * get_frame_time(); + 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; -}; +} let draw = fn(state) { frame_clear(state.color.r, state.color.g, state.color.b); -}; +} let migrate = fn(state) { return { .player: { .pos: state.player.position } }; -}; +} diff --git a/src/interpret/interpret.rs b/src/interpret/interpret.rs index 0dc7f27..ddfec18 100644 --- a/src/interpret/interpret.rs +++ b/src/interpret/interpret.rs @@ -39,9 +39,10 @@ pub fn run( program: ast::Program, func: ast::Name, args: Vec, -) -> Result { +) -> Result { 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 { @@ -153,7 +154,7 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result Result { + 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)) => { let cop = match cop { ast::Cmp::Eq => |a, b| a == b, diff --git a/src/interpret/types.rs b/src/interpret/types.rs index 3a6c629..e08859a 100644 --- a/src/interpret/types.rs +++ b/src/interpret/types.rs @@ -9,7 +9,7 @@ use std::collections::HashMap; pub enum Error { DuplicateEnvNames(ast::EnvName, Backtrace), DuplicateNames(ast::Name, Backtrace), - NameNotFound(ast::Name, Backtrace), + NameNotFound(ast::Name, Env, Backtrace), FieldNotFound(ast::Label, Backtrace), EnvNotFound(ast::EnvName, Backtrace), LastStatementNotAnExpr(Backtrace), @@ -25,7 +25,7 @@ impl PartialEq for Error { match (self, other) { (Error::DuplicateEnvNames(a1, _), Error::DuplicateEnvNames(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::EnvNotFound(a1, _), Error::EnvNotFound(a2, _)) => a1 == a2, (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::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::EnvNotFound(a, b) => write!(f, "Env not found: {a:?}\n{b}"), Error::LastStatementNotAnExpr(a) => { @@ -170,9 +170,14 @@ impl Env { } } pub fn get(&self, name: &ast::Name) -> Result<&ast::Value, Error> { - self.env - .get(name) - .ok_or(Error::NameNotFound(name.clone(), Backtrace::capture())) + match self.env.get(name) { + None => Err(Error::NameNotFound( + name.clone(), + self.clone(), + Backtrace::capture(), + )), + Some(v) => Ok(v), + } } pub fn insert(&mut self, name: ast::Name, value: ast::Value) { self.env.insert(name.clone(), value); diff --git a/src/lib.rs b/src/lib.rs index 3a9b34c..28f1915 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ pub mod interpret; pub mod parser; pub mod runtime; -pub fn run_main(code: &str) -> Result { +pub fn run_main(code: &str) -> Result { match parser::parse_file(code.into()) { Err(err) => Err(format!("Error: {err:?}")), Ok(program) => match interpret::run(program, "main".into(), vec![]) { @@ -63,6 +63,43 @@ let main = fn() { }; 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); insta::assert_debug_snapshot!(result); diff --git a/src/runtime/primitive_functions.rs b/src/runtime/primitive_functions.rs index 16efb1a..aec77fd 100644 --- a/src/runtime/primitive_functions.rs +++ b/src/runtime/primitive_functions.rs @@ -1,3 +1,4 @@ +use macroquad::time::get_frame_time; use rand::prelude::*; use crate::ast; @@ -5,7 +6,11 @@ use crate::interpret::PrimitiveFuncs; use macroquad::prelude as mq; 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 { @@ -19,6 +24,7 @@ fn clear(args: Vec) -> ast::Value { fn to_u32(value: Option<&ast::Value>) -> u8 { match value { Some(ast::Value::Int(i)) => *i as u8, + Some(ast::Value::Float(f)) => *f as u8, _ => 0, } } @@ -27,3 +33,7 @@ fn random_u8(_args: Vec) -> ast::Value { let random: u8 = rand::rng().random::(); ast::Value::Int(random as i32) } + +fn frame_time(_args: Vec) -> ast::Value { + ast::Value::Float(get_frame_time() as f32) +} diff --git a/src/runtime/runtime.rs b/src/runtime/runtime.rs index b346073..69098fb 100644 --- a/src/runtime/runtime.rs +++ b/src/runtime/runtime.rs @@ -160,6 +160,7 @@ pub fn draw(state: &mut State) { Ok(_) => {} Err(err) => println!("Error: {}", err), } + draw_fps(); /* println!( diff --git a/src/snapshots/ayin__tests__bor_onearm_4.snap b/src/snapshots/ayin__tests__bor_onearm_4.snap index c4230c2..742fff0 100644 --- a/src/snapshots/ayin__tests__bor_onearm_4.snap +++ b/src/snapshots/ayin__tests__bor_onearm_4.snap @@ -3,7 +3,9 @@ source: src/lib.rs expression: result --- Ok( - Int( - 4, + Value( + Int( + 4, + ), ), ) diff --git a/src/snapshots/ayin__tests__direction.snap b/src/snapshots/ayin__tests__direction.snap new file mode 100644 index 0000000..e2ee693 --- /dev/null +++ b/src/snapshots/ayin__tests__direction.snap @@ -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, + ), + ), + }, + ), +) diff --git a/src/snapshots/ayin__tests__int_108.snap b/src/snapshots/ayin__tests__int_108.snap index aa607b5..4d8cf69 100644 --- a/src/snapshots/ayin__tests__int_108.snap +++ b/src/snapshots/ayin__tests__int_108.snap @@ -3,7 +3,9 @@ source: src/lib.rs expression: result --- Ok( - Int( - 108, + Value( + Int( + 108, + ), ), ) diff --git a/src/snapshots/ayin__tests__let_add_3.snap b/src/snapshots/ayin__tests__let_add_3.snap index ca8446c..f041b6a 100644 --- a/src/snapshots/ayin__tests__let_add_3.snap +++ b/src/snapshots/ayin__tests__let_add_3.snap @@ -3,7 +3,9 @@ source: src/lib.rs expression: result --- Ok( - Int( - 3, + Value( + Int( + 3, + ), ), ) diff --git a/src/snapshots/ayin__tests__let_if_4.snap b/src/snapshots/ayin__tests__let_if_4.snap index c4230c2..742fff0 100644 --- a/src/snapshots/ayin__tests__let_if_4.snap +++ b/src/snapshots/ayin__tests__let_if_4.snap @@ -3,7 +3,9 @@ source: src/lib.rs expression: result --- Ok( - Int( - 4, + Value( + Int( + 4, + ), ), )