logo_interp/
stdlib.rs

1use rand::{Rng, thread_rng};
2use crate::core::*;
3use crate::executor::execute;
4use crate::executor_state::*;
5
6pub fn add_stdlib<S: 'static>(es: &mut EState<S>) {
7    es.functions.insert("repeat".to_string(), Function::from_proc2(repeat));
8    es.functions.insert("show".to_string(), Function::from_proc1(show));
9
10    es.functions.insert("abs".to_string(), Function::from_fn1(abs));
11    es.functions.insert("arctan".to_string(), Function::from_fn1(arctan));
12    es.functions.insert("cos".to_string(), Function::from_fn1(cos));
13    es.functions.insert("difference".to_string(), Function::from_fn2(difference));
14    es.functions.insert("exp".to_string(), Function::from_fn1(exp));
15    es.functions.insert("greater?".to_string(), Function::from_fn2(greater));
16    es.functions.insert("less?".to_string(), Function::from_fn2(less));
17    es.functions.insert("int".to_string(), Function::from_fn1(int));
18    es.functions.insert("log".to_string(), Function::from_fn1(log));
19    es.functions.insert("ln".to_string(), Function::from_fn1(ln));
20    es.functions.insert("minus".to_string(), Function::from_fn1(minus));
21    es.functions.insert("pi".to_string(), Function::from_fn(pi));
22    es.functions.insert("power".to_string(), Function::from_fn2(power));
23    es.functions.insert("product".to_string(), Function::from_fn2(product));
24    es.functions.insert("quotient".to_string(), Function::from_fn2(quotient));
25    es.functions.insert("remainder".to_string(), Function::from_fn2(remainder));
26    es.functions.insert("random".to_string(), Function::from_fn1(random));
27    es.functions.insert("round".to_string(), Function::from_fn1(round));
28    es.functions.insert("sin".to_string(), Function::from_fn1(sin));
29    es.functions.insert("sqrt".to_string(), Function::from_fn1(sqrt));
30    es.functions.insert("sum".to_string(), Function::from_fn2(sum));
31    es.functions.insert("tan".to_string(), Function::from_fn1(tan));
32
33    es.functions.insert("bf".to_string(), Function::from_fn1(bf));
34    es.functions.insert("butfirst".to_string(), Function::from_fn1(bf));
35    es.functions.insert("bl".to_string(), Function::from_fn1(bl));
36    es.functions.insert("butlast".to_string(), Function::from_fn1(bl));
37    es.functions.insert("count".to_string(), Function::from_fn1(count));
38    es.functions.insert("empty?".to_string(), Function::from_fn1(empty));
39    es.functions.insert("equal?".to_string(), Function::from_fn2(equal));
40    es.functions.insert("identical?".to_string(), Function::from_fn2(equal));
41    es.functions.insert("first".to_string(), Function::from_fn1(first));
42    es.functions.insert("fput".to_string(), Function::from_fn2(fput));
43    es.functions.insert("item".to_string(), Function::from_fn2(item));
44    es.functions.insert("last".to_string(), Function::from_fn1(last));
45    es.functions.insert("list".to_string(), Function::from_fn2(list));
46    es.functions.insert("list?".to_string(), Function::from_fn1(is_list));
47    es.functions.insert("lput".to_string(), Function::from_fn2(lput));
48    es.functions.insert("member?".to_string(), Function::from_fn2(member));
49    es.functions.insert("number?".to_string(), Function::from_fn1(number));
50    es.functions.insert("pick".to_string(), Function::from_fn1(pick));
51    es.functions.insert("word?".to_string(), Function::from_fn1(word));
52
53    es.functions.insert("and".to_string(), Function::from_fn2(and));
54    es.functions.insert("or".to_string(), Function::from_fn2(or));
55    es.functions.insert("not".to_string(), Function::from_fn1(not));
56    es.functions.insert("if".to_string(), Function::from_proc2(if_fn));
57    es.functions.insert("ifelse".to_string(), Function::from_proc3(if_else_fn));
58
59    es.functions.insert("make".to_string(), Function::from_proc2(make));
60    es.functions.insert("clearname".to_string(), Function::from_proc1(clearname));
61    es.functions.insert("clearnames".to_string(), Function::from_proc(clearnames));
62    es.functions.insert("name?".to_string(), Function::from_fn1(name));
63    es.functions.insert("names".to_string(), Function::from_fn(names));
64    es.functions.insert("thing".to_string(), Function::from_fn1(thing));
65
66    es.functions.insert("output".to_string(), Function::from_proc1(output));
67}
68
69fn repeat<S>(state: &mut EState<S>, n: i32, cmd: Vec<LogoValue>) -> Result<(), String> {
70    for _ in 0..n {
71        execute(state, cmd.clone())?;
72    }
73    Ok(())
74}
75
76fn show<S>(_: &mut EState<S>, val: LogoValue) -> Result<(), String> {
77    println!("{}", val);
78    Ok(())
79}
80
81fn abs<S>(_: &mut EState<S>, val: f64) -> Result<f64, String> {
82    Ok(val.abs())
83}
84
85fn arctan<S>(_: &mut EState<S>, val: f64) -> Result<f64, String> {
86    Ok(val.atan().to_degrees())
87}
88
89fn cos<S>(_: &mut EState<S>, val: f64) -> Result<f64, String> {
90    Ok(val.to_radians().cos())
91}
92
93fn difference<S>(_: &mut EState<S>, a: f64, b: f64) -> Result<f64, String> {
94    Ok(a - b)
95}
96
97fn exp<S>(_: &mut EState<S>, val: f64) -> Result<f64, String> {
98    Ok(val.exp())
99}
100
101fn greater<S>(_: &mut EState<S>, a: f64, b: f64) -> Result<bool, String> {
102    Ok(a > b)
103}
104
105fn less<S>(_: &mut EState<S>, a: f64, b: f64) -> Result<bool, String> {
106    Ok(a < b)
107}
108
109fn int<S>(_: &mut EState<S>, val: f64) -> Result<i32, String> {
110    Ok(val as i32)
111}
112
113fn log<S>(_: &mut EState<S>, val: f64) -> Result<f64, String> {
114    Ok(val.log(10f64))
115}
116
117fn ln<S>(_: &mut EState<S>, val: f64) -> Result<f64, String> {
118    Ok(val.ln())
119}
120
121fn minus<S>(_: &mut EState<S>, val: f64) -> Result<f64, String> {
122    Ok(-val)
123}
124
125fn pi<S>(_: &mut EState<S>) -> Result<f64, String> {
126    Ok(std::f64::consts::PI)
127}
128
129fn power<S>(_: &mut EState<S>, a: f64, b: f64) -> Result<f64, String> {
130    Ok(a.powf(b))
131}
132
133fn product<S>(_: &mut EState<S>, a: f64, b: f64) -> Result<f64, String> {
134    Ok(a * b)
135}
136
137fn quotient<S>(_: &mut EState<S>, a: f64, b: f64) -> Result<f64, String> {
138    Ok(a / b)
139}
140
141fn remainder<S>(_: &mut EState<S>, a: i32, b: i32) -> Result<i32, String> {
142    Ok(a % b)
143}
144
145fn random<S>(_: &mut EState<S>, val: i32) -> Result<i32, String> {
146    if val < 1 {
147        return Err("Input to random must be greater than 0".to_string());
148    }
149    Ok((rand::thread_rng().gen::<u32>() % val as u32) as i32)
150}
151
152fn round<S>(_: &mut EState<S>, val: f64) -> Result<i32, String> {
153    Ok(val.round() as i32)
154}
155
156fn sin<S>(_: &mut EState<S>, val: f64) -> Result<f64, String> {
157    Ok(val.to_radians().sin())
158}
159
160fn sqrt<S>(_: &mut EState<S>, val: f64) -> Result<f64, String> {
161    Ok(val.sqrt())
162}
163
164fn sum<S>(_: &mut EState<S>, x: f64, y: f64) -> Result<f64, String> {
165    Ok(x + y)
166}
167
168fn tan<S>(_: &mut EState<S>, val: f64) -> Result<f64, String> {
169    Ok(val.to_radians().tan())
170}
171
172
173fn bf<S>(_: &mut EState<S>, mut val: Vec<LogoValue>) -> Result<Vec<LogoValue>, String> {
174    if val.len() == 0 {
175        return Err("Can't remove an element from an empty list".to_string());
176    }
177    val.remove(0);
178    Ok(val)
179}
180
181fn bl<S>(_: &mut EState<S>, mut val: Vec<LogoValue>) -> Result<Vec<LogoValue>, String> {
182    if val.len() == 0 {
183        return Err("Can't remove an element from an empty list".to_string());
184    }
185    val.pop();
186    Ok(val)
187}
188
189fn count<S>(_: &mut EState<S>, val: Vec<LogoValue>) -> Result<i32, String> {
190    Ok(val.len() as i32)
191}
192
193fn empty<S>(_: &mut EState<S>, val: Vec<LogoValue>) -> Result<bool, String> {
194    Ok(val.is_empty())
195}
196
197fn equal<S>(_: &mut EState<S>, a: LogoValue, b: LogoValue) -> Result<bool, String> {
198    Ok(a == b)
199}
200
201fn first<S>(_: &mut EState<S>, val: Vec<LogoValue>) -> Result<LogoValue, String> {
202    if val.len() == 0 {
203        return Err("Can't get an element from an empty list".to_string());
204    }
205    Ok(val.first().unwrap().clone())
206}
207
208fn fput<S>(_: &mut EState<S>, a: LogoValue, mut b: Vec<LogoValue>) -> Result<Vec<LogoValue>, String> {
209    b.insert(0, a);
210    Ok(b)
211}
212
213fn item<S>(_: &mut EState<S>, idx: i32, val: Vec<LogoValue>) -> Result<LogoValue, String> {
214    if idx < 0 || idx >= val.len() as i32 {
215        return Err("No such item".to_string());
216    }
217    Ok(val[idx as usize].clone())
218}
219
220fn last<S>(_: &mut EState<S>, val: Vec<LogoValue>) -> Result<LogoValue, String> {
221    if val.len() == 0 {
222        return Err("Can't get an element from an empty list".to_string());
223    }
224    Ok(val.last().unwrap().clone())
225}
226
227fn list<S>(_: &mut EState<S>, mut a: Vec<LogoValue>, mut b: Vec<LogoValue>) -> Result<Vec<LogoValue>, String> {
228    a.append(&mut b);
229    Ok(a)
230}
231
232fn is_list<S>(_: &mut EState<S>, a: LogoValue) -> Result<bool, String> {
233    if let LogoValue::List(_) = a {
234        Ok(true)
235    }
236    else {
237        Ok(false)
238    }
239}
240
241fn lput<S>(_: &mut EState<S>, a: LogoValue, mut b: Vec<LogoValue>) -> Result<Vec<LogoValue>, String> {
242    b.push(a);
243    Ok(b)
244}
245
246fn member<S>(_: &mut EState<S>, a: LogoValue, b: Vec<LogoValue>) -> Result<bool, String> {
247    for b_el in b {
248        if a == b_el {
249            return Ok(true)
250        }
251    }
252    Ok(false)
253}
254
255fn number<S>(_: &mut EState<S>, a: LogoValue) -> Result<bool, String> {
256    if let LogoValue::Word(word) = a {
257        if let Ok(_) = word.0.parse::<f32>() {
258            Ok(true)
259        }
260        else {
261            Ok(false)
262        }
263    }
264    else {
265        Ok(false)
266    }
267}
268
269fn pick<S>(_: &mut EState<S>, val: Vec<LogoValue>) -> Result<LogoValue, String> {
270    if val.len() == 0 {
271        return Err("Can't get an element from an empty list".to_string());
272    }
273    Ok(val[thread_rng().gen::<usize>() % val.len()].clone())
274}
275
276fn word<S>(_: &mut EState<S>, a: LogoValue) -> Result<bool, String> {
277    if let LogoValue::Word(_) = a {
278        Ok(true)
279    }
280    else {
281        Ok(false)
282    }
283}
284
285
286fn and<S>(_: &mut EState<S>, a: bool, b: bool) -> Result<bool, String> {
287    Ok(a && b)
288}
289
290fn or<S>(_: &mut EState<S>, a: bool, b: bool) -> Result<bool, String> {
291    Ok(a || b)
292}
293
294fn not<S>(_: &mut EState<S>, a: bool) -> Result<bool, String> {
295    Ok(!a)
296}
297
298fn if_fn<S>(state: &mut EState<S>, a: bool, cmd: Vec<LogoValue>) -> Result<(), String> {
299    if a {
300        execute(state, cmd)?;
301    }
302    Ok(())
303}
304
305fn if_else_fn<S>(state: &mut EState<S>, a: bool, cmd_true: Vec<LogoValue>, cmd_false: Vec<LogoValue>) -> Result<(), String> {
306    if a {
307        execute(state, cmd_true)?;
308    }
309    else {
310        execute(state, cmd_false)?;
311    }
312    Ok(())
313}
314
315
316fn make<S>(state: &mut EState<S>, name: String, val: LogoValue) -> Result<(), String> {
317    state.vars.insert(name.to_lowercase(), val);
318    Ok(())
319}
320
321fn clearname<S>(state: &mut EState<S>, name: String) -> Result<(), String> {
322    state.vars.remove(name.to_lowercase().as_str());
323    Ok(())
324}
325
326fn clearnames<S>(state: &mut EState<S>) -> Result<(), String> {
327    state.vars.clear();
328    Ok(())
329}
330
331fn name<S>(state: &mut EState<S>, name: String) -> Result<bool, String> {
332    Ok(state.vars.contains_key(name.to_lowercase().as_str()))
333}
334
335fn names<S>(state: &mut EState<S>) -> Result<Vec<LogoValue>, String> {
336    let mut result = Vec::with_capacity(state.vars.len());
337    for key in state.vars.keys() {
338        result.push(LogoValue::String(key.clone()));
339    }
340    Ok(result)
341}
342
343fn thing<S>(state: &mut EState<S>, name: String) -> Result<LogoValue, String> {
344    let name = name.to_lowercase();
345    if !state.vars.contains_key(name.as_str()) {
346        return Err("No such variable".to_string());
347    }
348    Ok(state.vars[name.as_str()].clone())
349}
350
351
352fn output<S>(state: &mut EState<S>, val: LogoValue) -> Result<(), String> {
353    state.output = Some(val);
354    Err("Output".to_string())
355}