1use std::collections::HashMap;
2use std::rc::Rc;
3use crate::core::*;
4
5
6#[derive(Clone)]
7pub struct Function<S> {
8 pub f: Rc<dyn Fn(&mut EState<S>, Vec<LogoValue>) -> Result<Option<LogoValue>, String>>,
9 pub args: i32
10}
11
12pub struct EState<S> {
13 pub functions: HashMap<String, Function<S>>,
14 pub logo_procedures: HashMap<String, LogoProcedure>,
15 pub vars: HashMap<String, LogoValue>,
16 pub output: Option<LogoValue>,
17 pub state: S
18}
19
20impl<S: 'static> Function<S> {
21 pub fn from_proc(f: fn(&mut EState<S>) -> Result<(), String>) -> Self {
22 return Function{f: Rc::new(
23 move |state: &mut EState<S>, _: Vec<LogoValue>| -> Result<Option<LogoValue>, String> {
24 f(state)?;
25 return Ok(None);
26 }), args: 0};
27 }
28 pub fn from_fn<Out: LogoConvertible + 'static>(f: fn(&mut EState<S>) -> Result<Out, String>) -> Self {
29 return Function{f: Rc::new(move |state: &mut EState<S>, _: Vec<LogoValue>| -> Result<Option<LogoValue>, String> {
30 return Ok(Some(f(state)?.to_logo()));
31 }), args: 0};
32 }
33
34 pub fn from_proc1<T1: LogoConvertible + 'static>
35 (f: fn(&mut EState<S>, T1) -> Result<(), String>) -> Self {
36 return Function{f: Rc::new(move |state: &mut EState<S>, mut args: Vec<LogoValue>| -> Result<Option<LogoValue>, String> {
37 let arg1 = T1::from_logo(args.pop().unwrap())?;
38 f(state, arg1)?;
39 return Ok(None);
40 }), args: 1};
41 }
42 pub fn from_fn1<T1: LogoConvertible + 'static, Out: LogoConvertible + 'static>
43 (f: fn(&mut EState<S>, T1) -> Result<Out, String>) -> Self {
44 return Function{f: Rc::new(move |state: &mut EState<S>, mut args: Vec<LogoValue>| -> Result<Option<LogoValue>, String> {
45 let arg1 = T1::from_logo(args.pop().unwrap())?;
46 return Ok(Some(f(state, arg1)?.to_logo()));
47 }), args: 1};
48 }
49
50 pub fn from_proc2<T1: LogoConvertible + 'static, T2: LogoConvertible + 'static>
51 (f: fn(&mut EState<S>, T1, T2) -> Result<(), String>) -> Self {
52 return Function{f: Rc::new(move |state: &mut EState<S>, mut args: Vec<LogoValue>| -> Result<Option<LogoValue>, String> {
53 let arg2 = T2::from_logo(args.pop().unwrap())?;
54 let arg1 = T1::from_logo(args.pop().unwrap())?;
55 f(state, arg1, arg2)?;
56 return Ok(None);
57 }), args: 2};
58 }
59 pub fn from_fn2<T1: LogoConvertible + 'static, T2: LogoConvertible + 'static, Out: LogoConvertible + 'static>
60 (f: fn(&mut EState<S>, T1, T2) -> Result<Out, String>) -> Self {
61 return Function{f: Rc::new(move |state: &mut EState<S>, mut args: Vec<LogoValue>| -> Result<Option<LogoValue>, String> {
62 let arg2 = T2::from_logo(args.pop().unwrap())?;
63 let arg1 = T1::from_logo(args.pop().unwrap())?;
64 return Ok(Some(f(state, arg1, arg2)?.to_logo()));
65 }), args: 2};
66 }
67
68 pub fn from_proc3<T1: LogoConvertible + 'static, T2: LogoConvertible + 'static, T3: LogoConvertible + 'static>
69 (f: fn(&mut EState<S>, T1, T2, T3) -> Result<(), String>) -> Self {
70 return Function{f: Rc::new(move |state: &mut EState<S>, mut args: Vec<LogoValue>| -> Result<Option<LogoValue>, String> {
71 let arg3 = T3::from_logo(args.pop().unwrap())?;
72 let arg2 = T2::from_logo(args.pop().unwrap())?;
73 let arg1 = T1::from_logo(args.pop().unwrap())?;
74 f(state, arg1, arg2, arg3)?;
75 return Ok(None);
76 }), args: 3};
77 }
78 pub fn from_fn3<T1: LogoConvertible + 'static, T2: LogoConvertible + 'static, T3: LogoConvertible + 'static, Out: LogoConvertible + 'static>
79 (f: fn(&mut EState<S>, T1, T2, T3) -> Result<Out, String>) -> Self {
80 return Function{f: Rc::new(move |state: &mut EState<S>, mut args: Vec<LogoValue>| -> Result<Option<LogoValue>, String> {
81 let arg3 = T3::from_logo(args.pop().unwrap())?;
82 let arg2 = T2::from_logo(args.pop().unwrap())?;
83 let arg1 = T1::from_logo(args.pop().unwrap())?;
84 return Ok(Some(f(state, arg1, arg2, arg3)?.to_logo()));
85 }), args: 3};
86 }
87}
88
89impl<S> EState<S> {
90 pub fn new(state: S) -> Self {
91 return EState {
92 functions: HashMap::new(),
93 logo_procedures: HashMap::new(),
94 vars: HashMap::new(),
95 output: None,
96 state
97 };
98 }
99}
100
101#[test]
102fn test_executor_function() {
103 let mut state = EState::new(5);
104
105 let sum = |_: &mut EState<i32>, x: f64, y: f64| -> Result<f64, String> {
106 Ok(x + y)
107 };
108 state.functions.insert("sum".to_string(), Function::from_fn2(sum));
109
110 let sum_fn = state.functions[&"sum".to_string()].clone();
111 assert_eq!(sum_fn.args, 2);
112 let res = (sum_fn.f)(&mut state,
113 vec![LogoValue::Word(Word("2".to_string())), LogoValue::Word(Word("3".to_string()))]);
114 assert!(res.is_ok());
115 assert!(res.as_ref().unwrap().is_some());
116 assert_eq!(res.unwrap().unwrap(), LogoValue::Word(Word("5".to_string())));
117}