Skip to main content

mech_interpreter/stdlib/
define.rs

1#[macro_use]
2use crate::stdlib::*;
3
4#[macro_export]
5macro_rules! register_define {
6  ($fxn_name:tt, $scalar:tt, $scalar_string:tt, $row1:tt) => {
7    paste! {
8      register_descriptor! {
9        FunctionDescriptor {
10          name: concat!(stringify!($fxn_name), "<", $scalar_string , stringify!($row1), ">") ,
11          ptr: $fxn_name::<$scalar,$row1<$scalar>>::new,
12        }
13      }
14    }
15  };
16}
17
18#[derive(Debug)]
19pub struct VariableDefineMatrix<T, MatA> {
20  pub id: u64,
21  pub name: Ref<String>,
22  pub mutable: Ref<bool>,
23  pub var: Ref<MatA>,
24  pub _marker: PhantomData<T>,
25}
26impl<T, MatA> MechFunctionFactory for VariableDefineMatrix<T, MatA>
27where
28  T: Debug + Clone + Sync + Send + 'static + 
29  CompileConst + ConstElem + AsValueKind,
30  for<'a> &'a MatA: IntoIterator<Item = &'a T>,
31  for<'a> &'a mut MatA: IntoIterator<Item = &'a mut T>,
32  MatA: Debug + CompileConst + ConstElem + AsNaKind + 'static,
33  Ref<MatA>: ToValue
34{
35  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
36    match args {
37      FunctionArgs::Binary(var, arg1, arg2) => {
38        let var: Ref<MatA> = unsafe { var.as_unchecked() }.clone();
39        let name: Ref<String> = unsafe { arg1.as_unchecked() }.clone();
40        let mutable: Ref<bool> = unsafe { arg2.as_unchecked() }.clone();
41        let id = hash_str(&name.borrow());
42        Ok(Box::new(Self {id, name, mutable, var, _marker: PhantomData::default() }))
43      },
44      _ => Err(MechError::new(
45          IncorrectNumberOfArguments { expected: 3, found: args.len() },
46          None
47        ).with_compiler_loc()
48      ),
49    }
50  }
51}
52impl<T, MatA> MechFunctionImpl for VariableDefineMatrix<T, MatA>
53where
54  Ref<MatA>: ToValue,
55  T: Debug + Clone + Sync + Send + 'static + 
56  CompileConst + ConstElem + AsValueKind,
57  MatA: Debug,
58{
59  fn solve(&self) {}
60  fn out(&self) -> Value {self.var.to_value()}
61  fn to_string(&self) -> String { format!("{:#?}", self) }
62}
63#[cfg(feature = "compiler")]
64impl<T, MatA> MechFunctionCompiler for VariableDefineMatrix<T, MatA> 
65where
66  T: CompileConst + ConstElem + AsValueKind,
67  MatA: CompileConst + ConstElem + AsNaKind,
68{
69  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
70    let name = format!("VariableDefineMatrix<{}{}>", T::as_value_kind(), MatA::as_na_kind());
71    compile_binop!(name, self.var, self.name, self.mutable, ctx, FeatureFlag::Builtin(FeatureKind::VariableDefine) );
72  }
73}
74
75#[macro_export]
76macro_rules! impl_variable_define_fxn {
77  ($kind:tt) => {
78    paste! {
79      #[derive(Debug, Clone)]
80      pub struct [<VariableDefine $kind:camel>] {
81        id: u64,
82        name: Ref<String>,
83        mutable: Ref<bool>,
84        var: Ref<$kind>,
85      }
86      impl MechFunctionFactory for [<VariableDefine $kind:camel>] {
87      fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
88          match args {
89            FunctionArgs::Binary(out, arg1, arg2) => {
90              let var: Ref<$kind> = unsafe { out.as_unchecked() }.clone();
91              let name: Ref<String> = unsafe { arg1.as_unchecked() }.clone();
92              let mutable: Ref<bool> = unsafe { arg2.as_unchecked() }.clone();
93              let id = hash_str(&name.borrow());
94              Ok(Box::new(Self { id, name, mutable, var }))
95            },
96            _ => Err(MechError::new(
97                IncorrectNumberOfArguments { expected: 3, found: args.len() },
98                None
99              ).with_compiler_loc()
100            ),
101          }
102        }
103      }
104      impl MechFunctionImpl for [<VariableDefine $kind:camel>] {
105        fn solve(&self) {}
106        fn out(&self) -> Value { self.var.to_value() }
107        fn to_string(&self) -> String { format!("{:#?}", self) }
108      }
109      #[cfg(feature = "compiler")]
110      impl MechFunctionCompiler for [<VariableDefine $kind:camel>] {
111      fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
112          let name = format!(stringify!([<VariableDefine $kind:camel>]));
113          compile_binop!(name, self.var, self.name, self.mutable, ctx, FeatureFlag::Builtin(FeatureKind::VariableDefine) );
114        }
115      }
116      inventory::submit! {
117        FunctionDescriptor {
118          name: stringify!([<VariableDefine $kind:camel>]),
119          ptr: [<VariableDefine $kind:camel>]::new,
120        }
121      }
122    }
123  };
124}
125
126#[cfg(feature = "f64")]
127impl_variable_define_fxn!(f64);
128#[cfg(feature = "f32")]
129impl_variable_define_fxn!(f32);
130#[cfg(feature = "u8")]
131impl_variable_define_fxn!(u8);
132#[cfg(feature = "u16")]
133impl_variable_define_fxn!(u16);
134#[cfg(feature = "u32")]
135impl_variable_define_fxn!(u32);
136#[cfg(feature = "u64")]
137impl_variable_define_fxn!(u64);
138#[cfg(feature = "u128")]
139impl_variable_define_fxn!(u128);
140#[cfg(feature = "i8")]
141impl_variable_define_fxn!(i8);
142#[cfg(feature = "i16")]
143impl_variable_define_fxn!(i16);
144#[cfg(feature = "i32")]
145impl_variable_define_fxn!(i32);
146#[cfg(feature = "i64")]
147impl_variable_define_fxn!(i64);
148#[cfg(feature = "i128")]
149impl_variable_define_fxn!(i128);
150#[cfg(feature = "r64")]
151impl_variable_define_fxn!(R64);
152#[cfg(feature = "c64")]
153impl_variable_define_fxn!(C64);
154#[cfg(feature = "bool")]
155impl_variable_define_fxn!(bool);
156#[cfg(feature = "string")]
157impl_variable_define_fxn!(String);
158#[cfg(feature = "table")]
159impl_variable_define_fxn!(MechTable);
160#[cfg(feature = "set")]
161impl_variable_define_fxn!(MechSet);
162#[cfg(feature = "tuple")]
163impl_variable_define_fxn!(MechTuple);
164#[cfg(feature = "record")]
165impl_variable_define_fxn!(MechRecord);
166#[cfg(feature = "map")]
167impl_variable_define_fxn!(MechMap);
168#[cfg(feature = "atom")]
169impl_variable_define_fxn!(MechAtom);
170
171#[derive(Debug, Clone)]
172pub struct VariableDefineEmpty {
173  id: u64,
174  name: Ref<String>,
175  mutable: Ref<bool>,
176  var: Ref<Value>,
177}
178impl MechFunctionImpl for VariableDefineEmpty {
179  fn solve(&self) {}
180  fn out(&self) -> Value { self.var.borrow().clone() }
181  fn to_string(&self) -> String { format!("{:#?}", self) }
182}
183#[cfg(feature = "compiler")]
184impl MechFunctionCompiler for VariableDefineEmpty {
185  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
186    let name = "VariableDefineEmpty".to_string();
187    compile_binop!(name, self.var, self.name, self.mutable, ctx, FeatureFlag::Builtin(FeatureKind::VariableDefine) );
188  }
189}
190register_descriptor! {
191  FunctionDescriptor {
192    name: "VariableDefineEmpty",
193    ptr: |args: FunctionArgs| -> MResult<Box<dyn MechFunction>> {
194      match args {
195        FunctionArgs::Binary(var, arg1, arg2) => {
196          let var: Ref<Value> = unsafe { var.as_unchecked() }.clone();
197          let name: Ref<String> = unsafe { arg1.as_unchecked() }.clone();
198          let mutable: Ref<bool> = unsafe { arg2.as_unchecked() }.clone();
199          let id = hash_str(&name.borrow());
200          Ok(Box::new(VariableDefineEmpty { id, name, mutable, var }))
201        }
202        _ => Err(MechError::new(
203          IncorrectNumberOfArguments { expected: 3, found: args.len() },
204          None
205        ).with_compiler_loc()),
206      }
207    },
208  }
209}
210
211#[macro_export]
212macro_rules! impl_variable_define_match_arms {
213  ($arg:expr, $value_kind:ty, $feature:expr) => {
214    paste::paste! {
215      match $arg {
216        #[cfg(feature = $feature)]
217        (Value::[<$value_kind:camel>](sink), name, mutable, id) => box_mech_fxn(Ok(Box::new([<VariableDefine $value_kind:camel>]{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id } ))),
218        #[cfg(all(feature = $feature, feature = "matrix1"))]
219        (Value::[<Matrix $value_kind:camel>](Matrix::Matrix1(sink)), name, mutable, id) => {
220          register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix1);
221          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
222        },
223        #[cfg(all(feature = $feature, feature = "matrix2"))]
224        (Value::[<Matrix $value_kind:camel>](Matrix::Matrix2(sink)), name, mutable, id) => {
225          register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix2);
226          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
227        },
228        #[cfg(all(feature = $feature, feature = "matrix2x3"))]
229        (Value::[<Matrix $value_kind:camel>](Matrix::Matrix2x3(sink)), name, mutable, id) => {
230          register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix2x3);
231          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
232        },
233        #[cfg(all(feature = $feature, feature = "matrix3x2"))]
234        (Value::[<Matrix $value_kind:camel>](Matrix::Matrix3x2(sink)), name, mutable, id) => {
235          register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix3x2);
236          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
237        },
238        #[cfg(all(feature = $feature, feature = "matrix3"))]
239        (Value::[<Matrix $value_kind:camel>](Matrix::Matrix3(sink)), name, mutable, id) => {
240          register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix3);
241          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
242        },
243        #[cfg(all(feature = $feature, feature = "matrix4"))]
244        (Value::[<Matrix $value_kind:camel>](Matrix::Matrix4(sink)), name, mutable, id) => {
245          register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix4);
246          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
247        },
248        #[cfg(all(feature = $feature, feature = "matrixd"))]
249        (Value::[<Matrix $value_kind:camel>](Matrix::DMatrix(sink)), name, mutable, id) => {
250          register_define!(VariableDefineMatrix, $value_kind, $feature, DMatrix);
251          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
252        },
253        #[cfg(all(feature = $feature, feature = "vector2"))]
254        (Value::[<Matrix $value_kind:camel>](Matrix::Vector2(sink)), name, mutable, id) => {
255          register_define!(VariableDefineMatrix, $value_kind, $feature, Vector2);
256          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
257        },
258        #[cfg(all(feature = $feature, feature = "vector3"))]
259        (Value::[<Matrix $value_kind:camel>](Matrix::Vector3(sink)), name, mutable, id) => {
260          register_define!(VariableDefineMatrix, $value_kind, $feature, Vector3);
261          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
262        },
263        #[cfg(all(feature = $feature, feature = "vector4"))]
264        (Value::[<Matrix $value_kind:camel>](Matrix::Vector4(sink)), name, mutable, id) => {
265          register_define!(VariableDefineMatrix, $value_kind, $feature, Vector4);
266          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
267        },
268        #[cfg(all(feature = $feature, feature = "vectord"))]
269        (Value::[<Matrix $value_kind:camel>](Matrix::DVector(sink)), name, mutable, id) => {
270          register_define!(VariableDefineMatrix, $value_kind, $feature, DVector);
271          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
272        },
273        #[cfg(all(feature = $feature, feature = "row_vector2"))]
274        (Value::[<Matrix $value_kind:camel>](Matrix::RowVector2(sink)), name, mutable, id) => {
275          register_define!(VariableDefineMatrix, $value_kind, $feature, RowVector2);
276          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
277        },
278        #[cfg(all(feature = $feature, feature = "row_vector3"))]
279        (Value::[<Matrix $value_kind:camel>](Matrix::RowVector3(sink)), name, mutable, id) => {
280          register_define!(VariableDefineMatrix, $value_kind, $feature, RowVector3);
281          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
282        },
283        #[cfg(all(feature = $feature, feature = "row_vector4"))]
284        (Value::[<Matrix $value_kind:camel>](Matrix::RowVector4(sink)), name, mutable, id) => {
285          register_define!(VariableDefineMatrix, $value_kind, $feature, RowVector4);
286          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
287        },
288        #[cfg(all(feature = $feature, feature = "row_vectord"))]
289        (Value::[<Matrix $value_kind:camel>](Matrix::RowDVector(sink)), name, mutable, id) => {
290          register_define!(VariableDefineMatrix, $value_kind, $feature, RowDVector);
291          box_mech_fxn(Ok(Box::new(VariableDefineMatrix{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id: *id, _marker: PhantomData::<$value_kind>::default() })))
292        },
293        (sink, name, mutable, id) => Err(MechError::new(
294            UnhandledFunctionArgumentKind3 {arg: (sink.kind(), name.kind(), mutable.kind()), fxn_name: "var/define".to_string() },
295            None
296          ).with_compiler_loc()
297        ),
298      }
299    }
300  };
301}
302
303fn impl_var_define_fxn(var: Value, name: Value, mutable: Value, id: u64) -> MResult<Box<dyn MechFunction>> {
304  let arg = (var.clone(), name.clone(), mutable.clone(), id);
305  match arg {
306    (Value::Kind(kind), name, mutable, id) => {
307      return box_mech_fxn(Ok(Box::new(VariableDefineEmpty {
308        var: Ref::new(Value::Kind(kind)),
309        name: name.as_string()?,
310        mutable: mutable.as_bool()?,
311        id,
312      })));
313    },
314    (Value::Empty, name, mutable, id) => return box_mech_fxn(Ok(Box::new(VariableDefineEmpty { var: Ref::new(Value::Empty), name: name.as_string()?, mutable: mutable.as_bool()?, id } ))),
315    (Value::Typed(value, kind), name, mutable, id) => return box_mech_fxn(Ok(Box::new(VariableDefineEmpty { var: Ref::new(Value::Typed(value.clone(), kind.clone())), name: name.as_string()?, mutable: mutable.as_bool()?, id } ))),
316    (Value::EmptyKind(kind), name, mutable, id) => return box_mech_fxn(Ok(Box::new(VariableDefineEmpty { var: Ref::new(Value::EmptyKind(kind.clone())), name: name.as_string()?, mutable: mutable.as_bool()?, id } ))),
317    #[cfg(feature = "matrix")]
318    (Value::MatrixValue(sink), name, mutable, id) => return box_mech_fxn(Ok(Box::new(VariableDefineEmpty { var: Ref::new(Value::MatrixValue(sink.clone())), name: name.as_string()?, mutable: mutable.as_bool()?, id } ))),
319    #[cfg(feature = "table")]
320    (Value::Table(sink), name, mutable, id) => return box_mech_fxn(Ok(Box::new(VariableDefineMechTable{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id } ))),
321    #[cfg(feature = "set")]
322    (Value::Set(sink), name, mutable, id) => return box_mech_fxn(Ok(Box::new(VariableDefineMechSet{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id } ))),
323    #[cfg(feature = "tuple")]
324    (Value::Tuple(sink), name, mutable, id) => return box_mech_fxn(Ok(Box::new(VariableDefineMechTuple{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id } ))),
325    #[cfg(feature = "record")]
326    (Value::Record(sink), name, mutable, id) => return box_mech_fxn(Ok(Box::new(VariableDefineMechRecord{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id } ))),
327    #[cfg(feature = "map")]
328    (Value::Map(sink), name, mutable, id) => return box_mech_fxn(Ok(Box::new(VariableDefineMechMap{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id } ))),
329    #[cfg(feature = "atom")]
330    (Value::Atom(sink), name, mutable, id) => return box_mech_fxn(Ok(Box::new(VariableDefineMechAtom{ var: sink.clone(), name: name.as_string()?, mutable: mutable.as_bool()?, id } ))),
331    _ => (),
332  }
333
334
335                 impl_variable_define_match_arms!(&arg, u8,   "u8")
336  .or_else(|_| impl_variable_define_match_arms!(&arg, u16,  "u16"))
337  .or_else(|_| impl_variable_define_match_arms!(&arg, u32,  "u32"))
338  .or_else(|_| impl_variable_define_match_arms!(&arg, u64,  "u64"))
339  .or_else(|_| impl_variable_define_match_arms!(&arg, u128, "u128"))
340  .or_else(|_| impl_variable_define_match_arms!(&arg, i8,   "i8"))
341  .or_else(|_| impl_variable_define_match_arms!(&arg, i16,  "i16"))
342  .or_else(|_| impl_variable_define_match_arms!(&arg, i32,  "i32"))
343  .or_else(|_| impl_variable_define_match_arms!(&arg, i64,  "i64"))
344  .or_else(|_| impl_variable_define_match_arms!(&arg, i128, "i128"))
345  .or_else(|_| impl_variable_define_match_arms!(&arg, f32,  "f32"))
346  .or_else(|_| impl_variable_define_match_arms!(&arg, f64,  "f64"))
347  .or_else(|_| impl_variable_define_match_arms!(&arg, R64,  "rational"))
348  .or_else(|_| impl_variable_define_match_arms!(&arg, C64,  "complex"))
349  .or_else(|_| impl_variable_define_match_arms!(&arg, bool, "bool"))
350  .or_else(|_| impl_variable_define_match_arms!(&arg, String, "string"))
351  .map_err(|_| MechError::new(
352      UnhandledFunctionArgumentKind3 { arg: (var.kind(), name.kind(), mutable.kind()), fxn_name: "var/define".to_string() },
353      None
354    ).with_compiler_loc()
355  )
356}
357
358
359pub struct VarDefine{}
360impl NativeFunctionCompiler for VarDefine {
361  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
362    if arguments.len() != 3 {
363      return Err(MechError::new(IncorrectNumberOfArguments { expected: 1, found: arguments.len() }, None).with_compiler_loc());
364    }
365    let var = arguments[0].clone();
366    let name = &arguments[1].clone();
367    let mutable = &arguments[2].clone();
368    let name_string = name.as_string()?;
369    let id = hash_str(&name_string.borrow());
370    
371    match impl_var_define_fxn(var.clone(), name.clone(), mutable.clone(), id) {
372      Ok(fxn) => Ok(fxn),
373      Err(_) => {
374        match (var) {
375          (Value::MutableReference(input)) => {impl_var_define_fxn(input.borrow().clone(), name.clone(), mutable.clone(), id)}
376          _ => Err(MechError::new(
377              UnhandledFunctionArgumentKind3 { arg: (var.kind(), name.kind(), mutable.kind()), fxn_name: "var/define".to_string() },
378              None
379            ).with_compiler_loc()
380          ),
381        }
382      }
383    }
384  }
385}