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() {
|
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 } };
|
||||||
};
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
39
src/lib.rs
39
src/lib.rs
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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!(
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ source: src/lib.rs
|
||||||
expression: result
|
expression: result
|
||||||
---
|
---
|
||||||
Ok(
|
Ok(
|
||||||
Int(
|
Value(
|
||||||
4,
|
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
|
expression: result
|
||||||
---
|
---
|
||||||
Ok(
|
Ok(
|
||||||
Int(
|
Value(
|
||||||
108,
|
Int(
|
||||||
|
108,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ source: src/lib.rs
|
||||||
expression: result
|
expression: result
|
||||||
---
|
---
|
||||||
Ok(
|
Ok(
|
||||||
Int(
|
Value(
|
||||||
3,
|
Int(
|
||||||
|
3,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ source: src/lib.rs
|
||||||
expression: result
|
expression: result
|
||||||
---
|
---
|
||||||
Ok(
|
Ok(
|
||||||
Int(
|
Value(
|
||||||
4,
|
Int(
|
||||||
|
4,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue