1use std::collections::HashMap;
2use std::mem::swap;
3use crate::core::{LogoValue, Word};
4use crate::executor_state::*;
5use crate::parser;
6
7pub fn execute_str<S>(state: &mut EState<S>, proc_source: &str, source: &str) -> Result<(), String> {
8 state.logo_procedures = parser::parse_procedures(proc_source)?;
9 execute(state, parser::parse(source)?)
10}
11
12pub fn execute<S>(state: &mut EState<S>, source: Vec<LogoValue>) -> Result<(), String> {
13 let transformed_source = math_transform(source)?;
14 let mut it = transformed_source.iter();
15 while it.len() > 0 {
16 match execute_expr(state, &mut it)? {
17 Some(val) => return Err(format!("Don't know what to do with {}", val)),
18 None => {}
19 }
20 }
21 Ok(())
22}
23
24fn execute_expr<'a, S>(state: &mut EState<S>, it: &mut impl Iterator<Item = &'a LogoValue>) -> Result<Option<LogoValue>, String>
25{
26 let cmd = it.next();
27 if cmd.is_none() {
28 return Ok(None)
29 }
30 let cmd = cmd.unwrap();
31 if let LogoValue::Word(word) = cmd {
32 let word = &word.0;
33 if let Ok(_) = word.parse::<f64>() {
34 return Ok(Some(LogoValue::Word(Word(word.clone()))))
35 }
36
37 let word = word.to_lowercase();
38 if let Some(var_name) = word.strip_prefix(":") {
39 if !state.vars.contains_key(var_name) {
40 return Err("No such variable".to_string());
41 }
42 return Ok(Some(state.vars[var_name].clone()));
43 }
44
45 let fun = state.functions.get(word.as_str());
46 if let Some(fun) = fun {
47 let f = fun.f.clone();
48 let mut args = Vec::with_capacity(fun.args as usize);
49 for _ in 0..fun.args {
50 let arg = execute_expr(state, it)?;
51 match arg {
52 Some(arg) => args.push(arg),
53 None => return Err(format!("Missing argument for {}", word))
54 }
55 }
56 return (f)(state, args);
57 }
58
59 if let Some(logo_proc) = state.logo_procedures.get(word.as_str()) {
60 let logo_proc = logo_proc.clone();
61 let backup = backup_vars(state, &logo_proc.arg_names);
62 for arg_name in &logo_proc.arg_names {
63 let expr_result = execute_expr(state, it);
64 if let Err(_) = &expr_result {
65 restore_vars(state, backup);
66 return Err(expr_result.err().unwrap());
67 }
68 let expr_result = expr_result.unwrap();
69 if expr_result.is_none() {
70 restore_vars(state, backup);
71 return Err(format!("Missing argument for {}", word));
72 }
73 state.vars.insert(arg_name.clone(), expr_result.unwrap());
74 }
75 let proc_result = execute(state, logo_proc.code);
76 restore_vars(state, backup);
77 return match proc_result {
78 Err(err) => {
79 if err == "Output" {
80 let output = state.output.clone();
81 state.output = None;
82 return Ok(output);
83 }
84 Err(err)
85 },
86 Ok(()) => Ok(None)
87 }
88 }
89 return Err(format!("Don't know what to do with {}", cmd))
90 }
91
92 return Ok(Some(cmd.clone()));
93}
94
95fn backup_vars<S>(state: &EState<S>, var_names: &Vec<String>) -> Vec<(String, Option<LogoValue>)> {
96 let mut result = Vec::with_capacity(var_names.len());
97 for var_name in var_names {
98 let val = state.vars.get(var_name);
99 match val {
100 Some(val) => result.push((var_name.clone(), Some(val.clone()))),
101 None => result.push((var_name.clone(), None))
102 }
103 }
104 result
105}
106
107fn restore_vars<S>(state: &mut EState<S>, backup: Vec<(String, Option<LogoValue>)>) {
108 for (var_name, val) in backup {
109 match val {
110 Some(val) => {
111 state.vars.insert(var_name, val);
112 },
113 None => {
114 state.vars.remove(var_name.as_str());
115 }
116 }
117 }
118}
119
120fn math_transform(source: Vec<LogoValue>) -> Result<Vec<LogoValue>, String> {
121 let mut tree = BracketTree::parse(source)?;
122 process_math_signs(&mut tree, &HashMap::from([
123 ("*".to_string(), "product".to_string()),
124 ("/".to_string(), "quotient".to_string()),
125 ]))?;
126 process_math_signs(&mut tree, &HashMap::from([
127 ("+".to_string(), "sum".to_string()),
128 ("-".to_string(), "difference".to_string()),
129 ]))?;
130 process_math_signs(&mut tree, &HashMap::from([
131 (">".to_string(), "greater?".to_string()),
132 ("<".to_string(), "less?".to_string()),
133 ("=".to_string(), "equal?".to_string()),
134 ]))?;
135 Ok(tree.to_list())
136}
137
138fn process_math_signs(tree: &mut BracketTree, signs: &HashMap<String, String>) -> Result<(), String> {
139 tree.process(&|nodes: Vec<BracketTreeChild>| -> Result<Vec<BracketTreeChild>, String> {
140 let mut result = Vec::new();
141 let mut it = nodes.into_iter();
142 while let Some(node) = it.next() {
143 if let BracketTreeChild::Value(val) = &node {
144 if let LogoValue::Word(word) = val {
145 if let Some(sing_op) = signs.get(word.0.as_str()) {
146 let prev = match result.pop() {
147 Some(val) => val,
148 None => return Err(format!("Missing first argument for {}", word.0))
149 };
150 let next = match it.next() {
151 Some(val) => val,
152 None => return Err(format!("Missing second argument for {}", word.0))
153 };
154 let subtree = BracketTree{
155 children: vec![
156 BracketTreeChild::Value(LogoValue::Word(Word(sing_op.clone()))),
157 prev,
158 next
159 ]
160 };
161 result.push(BracketTreeChild::Tree(Box::new(subtree)));
162 continue;
163 }
164 }
165 }
166 result.push(node);
167 }
168 Ok(result)
169 })
170}
171
172struct BracketTree {
173 children: Vec<BracketTreeChild>
174}
175
176enum BracketTreeChild {
177 Value(LogoValue),
178 Tree(Box<BracketTree>)
179}
180
181impl BracketTree {
182 fn new() -> Self {
183 BracketTree {children: Vec::new()}
184 }
185
186 fn parse(list: Vec<LogoValue>) -> Result<Self, String> {
187 let mut stack = Vec::new();
188 stack.push(BracketTree::new());
189 for el in list {
190 if let LogoValue::Word(word) = &el {
191 if word.0 == "(" {
192 stack.push(BracketTree::new());
193 continue;
194 }
195 else if word.0 == ")" {
196 if stack.len() == 1 {
197 return Err("Missing corresponding opening bracket for ')'".to_string());
198 }
199 let last_stack = stack.pop().unwrap();
200 stack.last_mut().unwrap().children.push(BracketTreeChild::Tree(Box::new(last_stack)));
201 continue;
202 }
203 }
204 stack.last_mut().unwrap().children.push(BracketTreeChild::Value(el));
205 }
206 if stack.len() > 1 {
207 return Err("Missing corresponding closing bracket for '('".to_string());
208 }
209 Ok(stack.pop().unwrap())
210 }
211
212 fn into_list(self, list: &mut Vec<LogoValue>) {
213 for child in self.children {
214 match child {
215 BracketTreeChild::Value(val) => {
216 list.push(val)
217 },
218 BracketTreeChild::Tree(tree) => {
219 tree.into_list(list);
220 }
221 }
222 }
223 }
224
225 fn to_list(self) -> Vec<LogoValue> {
226 let mut result = Vec::new();
227 self.into_list(&mut result);
228 result
229 }
230
231 fn process(&mut self, f: &impl Fn(Vec<BracketTreeChild>) -> Result<Vec<BracketTreeChild>, String>) -> Result<(), String> {
232 let mut tmp = Vec::new();
233 swap(&mut tmp, &mut self.children);
234 self.children = f(tmp)?;
235 for child in &mut self.children {
236 if let BracketTreeChild::Tree(tree) = child {
237 tree.process(f)?;
238 }
239 }
240 Ok(())
241 }
242}
243
244#[test]
245fn test_execution() {
246 use crate::stdlib::*;
247
248 struct S {
249 total: i32
250 }
251 let mut state = EState::new(S{total: 0});
252 add_stdlib(&mut state);
253 state.functions.insert("add".to_string(), Function::from_proc1(|s: &mut EState<S>, x: i32| -> Result<(), String> {
254 s.state.total += x;
255 Ok(())
256 }));
257
258 execute_str(&mut state, "", "add 5 repeat 4 [add 1] add 10").unwrap();
259 assert_eq!(state.state.total, 19);
260
261 state.state.total = 0;
262 execute_str(&mut state, "", "make 'hi' 5 add :hi add thing 'hi'").unwrap();
263 assert_eq!(state.state.total, 10);
264
265 state.state.total = 0;
266 execute_str(&mut state, "to add4 add 4 end \
267 to add_double :x add :x add :x end \
268 to double :x output sum :x :x end",
269 "add4 add_double 6 add double 3").unwrap();
270 assert_eq!(state.state.total, 22);
271}
272
273#[test]
274fn test_execution_math() {
275 use crate::stdlib::*;
276
277 struct S {
278 result: i32
279 }
280 let mut state = EState::new(S{result: 0});
281 add_stdlib(&mut state);
282 state.functions.insert("return".to_string(), Function::from_proc1(|s: &mut EState<S>, x: i32| -> Result<(), String> {
283 s.state.result = x;
284 Ok(())
285 }));
286
287 execute_str(&mut state, "", "return 2 + 3").unwrap();
288 assert_eq!(state.state.result, 5);
289
290 execute_str(&mut state, "", "return 2 + +4").unwrap();
291 assert_eq!(state.state.result, 6);
292
293 execute_str(&mut state, "", "return 2 + -3").unwrap();
294 assert_eq!(state.state.result, -1);
295
296 execute_str(&mut state, "", "return product 2 3 + sum 4 5").unwrap();
297 assert_eq!(state.state.result, 24);
298
299 execute_str(&mut state, "", "return (product 2 3) + (sum 4 5)").unwrap();
300 assert_eq!(state.state.result, 15);
301
302 execute_str(&mut state, "", "return 3 + 4 * 5 + 2").unwrap();
303 assert_eq!(state.state.result, 25);
304
305 execute_str(&mut state, "", "return (3 + 4) * (5 + 2)").unwrap();
306 assert_eq!(state.state.result, 49);
307
308 execute_str(&mut state, "", "return (1 + (3 + 4)) * ((5 + 2) + 2)").unwrap();
309 assert_eq!(state.state.result, 72);
310}
311
312#[test]
313fn test_execution_comparison() {
314 use crate::stdlib::*;
315
316 struct S {
317 result: bool
318 }
319 let mut state = EState::new(S{result: false});
320 add_stdlib(&mut state);
321 state.functions.insert("return".to_string(), Function::from_proc1(|s: &mut EState<S>, x: bool| -> Result<(), String> {
322 s.state.result = x;
323 Ok(())
324 }));
325
326 execute_str(&mut state, "", "return 2 = 2").unwrap();
327 assert_eq!(state.state.result, true);
328
329 execute_str(&mut state, "", "return 2 = 4 / 2").unwrap();
330 assert_eq!(state.state.result, true);
331
332 execute_str(&mut state, "", "return 1 = pi / pi").unwrap();
333 assert_eq!(state.state.result, true);
334
335 execute_str(&mut state, "", "return 1/3 = 2/6").unwrap();
336 assert_eq!(state.state.result, true);
337
338 execute_str(&mut state, "", "return 1/4 < 1/5").unwrap();
339 assert_eq!(state.state.result, false);
340
341 execute_str(&mut state, "", "return (ln 1) > 0").unwrap();
342 assert_eq!(state.state.result, false);
343}