1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
use oorandom;
use macroquad::prelude::*;
use std::{cell::RefCell, collections::HashMap, rc::Rc, vec::Vec};
use rust_lisp::model::{Env, FloatType, IntType, RuntimeError, Symbol, Value};
use rust_lisp::utils::{require_arg, require_typed_arg};
pub type HashMapRc = Rc<RefCell<HashMap<Value, Value>>>;
pub const BACKGROUND_COLOR : Color = Color::new(0.44, 0.76, 0.27, 1.0);
pub const PAINTED_COLOR : Color = Color::new(0.06, 0.36, 0.20, 1.0);
static mut RNG_INC: u64 = 0;
pub fn extend_environment(env: &Rc<RefCell<Env>>) {
env.borrow_mut().define(
Symbol::from("randi-range"),
Value::NativeFunc(
|_env, args| {
let min = require_typed_arg::<IntType>("randi-range", &args, 0).unwrap();
let max = require_typed_arg::<IntType>("randi-range", &args, 1).unwrap();
unsafe {
let mut rng = oorandom::Rand32::new(RNG_INC);
let r = rng.rand_u32();
let r = r % ((max - min) as u32);
let r = (r as i32) + min;
RNG_INC += 1;
return Ok(Value::Int(r));
}
})
);
env.borrow_mut().define(
Symbol::from("mq-draw-circle"),
Value::NativeFunc(
|_env, args| {
let x = require_typed_arg::<FloatType>("mq-draw-circle", &args, 0).unwrap();
let y = require_typed_arg::<FloatType>("mq-draw-circle", &args, 1).unwrap();
let radius = require_typed_arg::<FloatType>("mq-draw-circle", &args, 2).unwrap();
let color = PAINTED_COLOR;
draw_circle(x, y, radius, color);
return Ok(Value::NIL);
})
);
env.borrow_mut().define(
Symbol::from("mq-draw-rectangle"),
Value::NativeFunc(
|_env, args| {
let x = require_typed_arg::<FloatType>("mq-draw-square", &args, 0).unwrap();
let y = require_typed_arg::<FloatType>("mq-draw-square", &args, 1).unwrap();
let width = require_typed_arg::<FloatType>("mq-draw-square", &args, 2).unwrap();
let height = require_typed_arg::<FloatType>("mq-draw-square", &args, 3).unwrap();
let alpha = require_typed_arg::<FloatType>("mq-draw-square", &args, 4).ok();
let mut color = PAINTED_COLOR.clone();
if let Some(a) = alpha {
color.a = a;
}
draw_rectangle(x, y, width, height, color);
return Ok(Value::NIL);
})
);
env.borrow_mut().define(
Symbol::from("mq-is-key-pressed"),
Value::NativeFunc(|_env, args| {
let keycode = require_typed_arg::<IntType>("mq-get-key-pressed", &args, 0).unwrap();
let keys_down : Vec<i32> = get_keys_down().into_iter().map(|e| e as i32).collect();
if keys_down.contains(&keycode) {
return Ok(Value::True);
}
return Ok(Value::False);
}),
);
// Hashtable functions
// TODO: convert to elisp compatible hash table command
env.borrow_mut().define(
Symbol::from("make-hash-table"),
Value::NativeFunc(|_env, args| {
let chunks = args.chunks(2);
let mut hash = HashMap::new();
for pair in chunks {
let key = pair.get(0).unwrap();
let value = pair.get(1);
if let Some(value) = value {
hash.insert(key.clone(), value.clone());
} else {
return Err(RuntimeError {
msg: format!("Must pass an even number of arguments to 'hash', because they're used as key/value pairs; found extra argument {}", key)
});
}
}
Ok(Value::HashMap(Rc::new(RefCell::new(hash))))
}),
);
env.borrow_mut().define(
Symbol::from("hash_get"),
Value::NativeFunc(|_env, args| {
let hash = require_typed_arg::<&HashMapRc>("hash_get", &args, 0)?;
let key = require_arg("hash_get", &args, 1)?;
Ok(hash
.borrow()
.get(key)
.map(|v| v.clone())
.unwrap_or(Value::NIL))
}),
);
env.borrow_mut().define(
Symbol::from("hash_set"),
Value::NativeFunc(|_env, args| {
let hash = require_typed_arg::<&HashMapRc>("hash_set", &args, 0)?;
let key = require_arg("hash_set", &args, 1)?;
let value = require_arg("hash_set", &args, 2)?;
hash.borrow_mut().insert(key.clone(), value.clone());
Ok(Value::HashMap(hash.clone()))
}),
);
}
|