many fixes and full program tests
This commit is contained in:
parent
0abada448b
commit
7302265436
11 changed files with 159 additions and 26 deletions
33
game.ayin
33
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;
|
||||
return state;
|
||||
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 } };
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,9 +39,10 @@ pub fn run(
|
|||
program: ast::Program,
|
||||
func: ast::Name,
|
||||
args: Vec<ast::Expr>,
|
||||
) -> Result<ast::Value, Error> {
|
||||
) -> Result<ast::Expr, Error> {
|
||||
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<ast:
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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)))
|
||||
}
|
||||
(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)) => {
|
||||
let cop = match cop {
|
||||
ast::Cmp::Eq => |a, b| a == b,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
39
src/lib.rs
39
src/lib.rs
|
|
@ -3,7 +3,7 @@ pub mod interpret;
|
|||
pub mod parser;
|
||||
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()) {
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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>) -> ast::Value {
|
||||
|
|
@ -19,6 +24,7 @@ fn clear(args: Vec<ast::Value>) -> 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>) -> ast::Value {
|
|||
let random: u8 = rand::rng().random::<u8>();
|
||||
ast::Value::Int(random as i32)
|
||||
}
|
||||
|
||||
fn frame_time(_args: Vec<ast::Value>) -> ast::Value {
|
||||
ast::Value::Float(get_frame_time() as f32)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ pub fn draw(state: &mut State) {
|
|||
Ok(_) => {}
|
||||
Err(err) => println!("Error: {}", err),
|
||||
}
|
||||
draw_fps();
|
||||
|
||||
/*
|
||||
println!(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ source: src/lib.rs
|
|||
expression: result
|
||||
---
|
||||
Ok(
|
||||
Value(
|
||||
Int(
|
||||
4,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
30
src/snapshots/ayin__tests__direction.snap
Normal file
30
src/snapshots/ayin__tests__direction.snap
Normal 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,
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
@ -3,7 +3,9 @@ source: src/lib.rs
|
|||
expression: result
|
||||
---
|
||||
Ok(
|
||||
Value(
|
||||
Int(
|
||||
108,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ source: src/lib.rs
|
|||
expression: result
|
||||
---
|
||||
Ok(
|
||||
Value(
|
||||
Int(
|
||||
3,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ source: src/lib.rs
|
|||
expression: result
|
||||
---
|
||||
Ok(
|
||||
Value(
|
||||
Int(
|
||||
4,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue