diff --git a/Makefile b/Makefile index 4a46cca..acf6b17 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ test: .PHONY: run run: - RUST_BACKTRACE=1 cargo run -- game.ayin + RUST_BACKTRACE=1 cargo run -- colorgame.ayin .PHONY: review review: diff --git a/colorgame.ayin b/colorgame.ayin new file mode 100644 index 0000000..ae0cdfa --- /dev/null +++ b/colorgame.ayin @@ -0,0 +1,32 @@ +let setup = fn() { + return { + .color: { + .r: random_u8(), + .g: random_u8(), + .b: random_u8(), + }, + .rect: { + .dimensions: { + .x: 100, + .y: 100, + .w: 100, + .h: 100, + }, + .color: { + .r: random_u8(), + .g: random_u8(), + .b: random_u8(), + }, + }, + }; +} + +let update = fn(state, input) { + let delta = get_frame_time(); + return state; +} + +let draw = fn(state) { + frame_clear(state.color.r, state.color.g, state.color.b); + draw_rectangle(state.rect.dimensions, state.rect.color); +} diff --git a/src/interpret/interpret.rs b/src/interpret/interpret.rs index ddfec18..209e3b5 100644 --- a/src/interpret/interpret.rs +++ b/src/interpret/interpret.rs @@ -168,7 +168,8 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result Result { +pub fn value_to_stadnalone_expr(state: &State, value: ast::Value) -> Result { match value { ast::Value::Ref(reference) => { let value = state.variables.get(&reference).clone(); @@ -444,7 +445,11 @@ pub fn value_to_stadnalone_expr(state: &State, value: ast::Value) -> Result Err("Closure migration not supported".into()), + ast::Value::Closure { .. } => Err(Error::MigrationError( + value.clone(), + "Closure migration not supported".into(), + Backtrace::capture(), + )), _ => Ok(ast::Expr::Value(value)), } } diff --git a/src/interpret/types.rs b/src/interpret/types.rs index e08859a..b7eefb1 100644 --- a/src/interpret/types.rs +++ b/src/interpret/types.rs @@ -18,6 +18,7 @@ pub enum Error { NotAReference(ast::Value, Backtrace), NotABoolean(ast::Value, Backtrace), OpError(ast::Value, ast::Op, ast::Value, Backtrace), + MigrationError(ast::Value, String, Backtrace), ArgumentsMismatch(Backtrace), } impl PartialEq for Error { @@ -34,6 +35,9 @@ impl PartialEq for Error { (Error::NotARecord(a1, _), Error::NotARecord(a2, _)) => a1 == a2, (Error::NotAReference(a1, _), Error::NotAReference(a2, _)) => a1 == a2, (Error::NotABoolean(a1, _), Error::NotABoolean(a2, _)) => a1 == a2, + (Error::MigrationError(a1, b1, _), Error::MigrationError(a2, b2, _)) => { + a1 == a2 && b1 == b2 + } (Error::ArgumentsMismatch(_), Error::ArgumentsMismatch(_)) => true, _ => false, } @@ -62,6 +66,9 @@ impl std::fmt::Display for Error { Error::NotABoolean(a, b) => write!(f, "Not a boolean {a:?}\n{b}"), Error::ArgumentsMismatch(a) => write!(f, "Arguments mismatch\n{a}"), Error::OpError(a, b, c, d) => write!(f, "Op Error {a:?} {b:?} {c:?}\n{d}"), + Error::MigrationError(a, b, c) => { + write!(f, "Migration error for:\n{a:#?}\n{b:#?}\n{c}") + } } } } @@ -100,7 +107,7 @@ pub struct PrimitiveFuncs { pub map: HashMap, } -pub type PrimFunc = fn(Vec) -> ast::Value; +pub type PrimFunc = fn(Vec) -> ast::Value; impl PrimitiveFuncs { pub fn new(prims: Vec<(&str, PrimFunc)>) -> Self { diff --git a/src/runtime/primitive_functions.rs b/src/runtime/primitive_functions.rs index aec77fd..23bb32e 100644 --- a/src/runtime/primitive_functions.rs +++ b/src/runtime/primitive_functions.rs @@ -8,32 +8,74 @@ use macroquad::prelude as mq; pub fn primitive_funcs() -> PrimitiveFuncs { PrimitiveFuncs::new(vec![ ("frame_clear", clear), + ("draw_rectangle", draw_rectangle), ("get_frame_time", frame_time), ("random_u8", random_u8), ]) } -fn clear(args: Vec) -> ast::Value { - let r = to_u32(args.get(0)); - let g = to_u32(args.get(1)); - let b = to_u32(args.get(2)); +fn clear(args: Vec) -> ast::Value { + let r = to_u8(args.get(0)); + let g = to_u8(args.get(1)); + let b = to_u8(args.get(2)); mq::clear_background(mq::Color::from_rgba(r, g, b, 255)); ast::UNIT_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, - } -} - -fn random_u8(_args: Vec) -> ast::Value { +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 { +fn frame_time(_args: Vec) -> ast::Value { ast::Value::Float(get_frame_time() as f32) } + +struct Rectangle { + x: f32, + y: f32, + w: f32, + h: f32, +} + +fn draw_rectangle(args: Vec) -> ast::Value { + let rectangle = match args.get(0) { + Some(ast::Expr::Record(record)) => { + let x = to_f32(record.get(&"x".into())); + let y = to_f32(record.get(&"y".into())); + let w = to_f32(record.get(&"w".into())); + let h = to_f32(record.get(&"h".into())); + Rectangle { x, y, w, h } + } + _ => todo!(), + }; + let color = match args.get(1) { + Some(ast::Expr::Record(record)) => { + let r = to_u8(record.get(&"r".into())); + let g = to_u8(record.get(&"g".into())); + let b = to_u8(record.get(&"b".into())); + mq::Color::from_rgba(r, g, b, 255) + } + _ => todo!(), + }; + mq::draw_rectangle(rectangle.x, rectangle.y, rectangle.w, rectangle.h, color); + ast::UNIT_VALUE +} + +/////////////// + +fn to_u8(value: Option<&ast::Expr>) -> u8 { + match value { + Some(ast::Expr::Value(ast::Value::Int(i))) => *i as u8, + Some(ast::Expr::Value(ast::Value::Float(f))) => *f as u8, + _ => 0, + } +} + +fn to_f32(value: Option<&ast::Expr>) -> f32 { + match value { + Some(ast::Expr::Value(ast::Value::Int(i))) => *i as f32, + Some(ast::Expr::Value(ast::Value::Float(f))) => *f as f32, + _ => 0.0, + } +}