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(MechError2::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(MechError2::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#[macro_export]
172macro_rules! impl_variable_define_match_arms {
173 ($arg:expr, $value_kind:ty, $feature:expr) => {
174 paste::paste! {
175 match $arg {
176 #[cfg(feature = $feature)]
177 (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 } ))),
178 #[cfg(all(feature = $feature, feature = "matrix1"))]
179 (Value::[<Matrix $value_kind:camel>](Matrix::Matrix1(sink)), name, mutable, id) => {
180 register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix1);
181 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() })))
182 },
183 #[cfg(all(feature = $feature, feature = "matrix2"))]
184 (Value::[<Matrix $value_kind:camel>](Matrix::Matrix2(sink)), name, mutable, id) => {
185 register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix2);
186 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() })))
187 },
188 #[cfg(all(feature = $feature, feature = "matrix2x3"))]
189 (Value::[<Matrix $value_kind:camel>](Matrix::Matrix2x3(sink)), name, mutable, id) => {
190 register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix2x3);
191 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() })))
192 },
193 #[cfg(all(feature = $feature, feature = "matrix3x2"))]
194 (Value::[<Matrix $value_kind:camel>](Matrix::Matrix3x2(sink)), name, mutable, id) => {
195 register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix3x2);
196 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() })))
197 },
198 #[cfg(all(feature = $feature, feature = "matrix3"))]
199 (Value::[<Matrix $value_kind:camel>](Matrix::Matrix3(sink)), name, mutable, id) => {
200 register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix3);
201 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() })))
202 },
203 #[cfg(all(feature = $feature, feature = "matrix4"))]
204 (Value::[<Matrix $value_kind:camel>](Matrix::Matrix4(sink)), name, mutable, id) => {
205 register_define!(VariableDefineMatrix, $value_kind, $feature, Matrix4);
206 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() })))
207 },
208 #[cfg(all(feature = $feature, feature = "matrixd"))]
209 (Value::[<Matrix $value_kind:camel>](Matrix::DMatrix(sink)), name, mutable, id) => {
210 register_define!(VariableDefineMatrix, $value_kind, $feature, DMatrix);
211 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() })))
212 },
213 #[cfg(all(feature = $feature, feature = "vector2"))]
214 (Value::[<Matrix $value_kind:camel>](Matrix::Vector2(sink)), name, mutable, id) => {
215 register_define!(VariableDefineMatrix, $value_kind, $feature, Vector2);
216 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() })))
217 },
218 #[cfg(all(feature = $feature, feature = "vector3"))]
219 (Value::[<Matrix $value_kind:camel>](Matrix::Vector3(sink)), name, mutable, id) => {
220 register_define!(VariableDefineMatrix, $value_kind, $feature, Vector3);
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 = "vector4"))]
224 (Value::[<Matrix $value_kind:camel>](Matrix::Vector4(sink)), name, mutable, id) => {
225 register_define!(VariableDefineMatrix, $value_kind, $feature, Vector4);
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 = "vectord"))]
229 (Value::[<Matrix $value_kind:camel>](Matrix::DVector(sink)), name, mutable, id) => {
230 register_define!(VariableDefineMatrix, $value_kind, $feature, DVector);
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 = "row_vector2"))]
234 (Value::[<Matrix $value_kind:camel>](Matrix::RowVector2(sink)), name, mutable, id) => {
235 register_define!(VariableDefineMatrix, $value_kind, $feature, RowVector2);
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 = "row_vector3"))]
239 (Value::[<Matrix $value_kind:camel>](Matrix::RowVector3(sink)), name, mutable, id) => {
240 register_define!(VariableDefineMatrix, $value_kind, $feature, RowVector3);
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 = "row_vector4"))]
244 (Value::[<Matrix $value_kind:camel>](Matrix::RowVector4(sink)), name, mutable, id) => {
245 register_define!(VariableDefineMatrix, $value_kind, $feature, RowVector4);
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 = "row_vectord"))]
249 (Value::[<Matrix $value_kind:camel>](Matrix::RowDVector(sink)), name, mutable, id) => {
250 register_define!(VariableDefineMatrix, $value_kind, $feature, RowDVector);
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 (sink, name, mutable, id) => Err(MechError2::new(
254 UnhandledFunctionArgumentKind3 {arg: (sink.kind(), name.kind(), mutable.kind()), fxn_name: "var/define".to_string() },
255 None
256 ).with_compiler_loc()
257 ),
258 }
259 }
260 };
261}
262
263fn impl_var_define_fxn(var: Value, name: Value, mutable: Value, id: u64) -> MResult<Box<dyn MechFunction>> {
264 let arg = (var.clone(), name.clone(), mutable.clone(), id);
265 match arg {
266 #[cfg(feature = "table")]
267 (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 } ))),
268 #[cfg(feature = "set")]
269 (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 } ))),
270 #[cfg(feature = "tuple")]
271 (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 } ))),
272 #[cfg(feature = "record")]
273 (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 } ))),
274 #[cfg(feature = "map")]
275 (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 } ))),
276 #[cfg(feature = "atom")]
277 (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 } ))),
278 _ => (),
279 }
280
281
282 impl_variable_define_match_arms!(&arg, u8, "u8")
283 .or_else(|_| impl_variable_define_match_arms!(&arg, u16, "u16"))
284 .or_else(|_| impl_variable_define_match_arms!(&arg, u32, "u32"))
285 .or_else(|_| impl_variable_define_match_arms!(&arg, u64, "u64"))
286 .or_else(|_| impl_variable_define_match_arms!(&arg, u128, "u128"))
287 .or_else(|_| impl_variable_define_match_arms!(&arg, i8, "i8"))
288 .or_else(|_| impl_variable_define_match_arms!(&arg, i16, "i16"))
289 .or_else(|_| impl_variable_define_match_arms!(&arg, i32, "i32"))
290 .or_else(|_| impl_variable_define_match_arms!(&arg, i64, "i64"))
291 .or_else(|_| impl_variable_define_match_arms!(&arg, i128, "i128"))
292 .or_else(|_| impl_variable_define_match_arms!(&arg, f32, "f32"))
293 .or_else(|_| impl_variable_define_match_arms!(&arg, f64, "f64"))
294 .or_else(|_| impl_variable_define_match_arms!(&arg, R64, "rational"))
295 .or_else(|_| impl_variable_define_match_arms!(&arg, C64, "complex"))
296 .or_else(|_| impl_variable_define_match_arms!(&arg, bool, "bool"))
297 .or_else(|_| impl_variable_define_match_arms!(&arg, String, "string"))
298 .map_err(|_| MechError2::new(
299 UnhandledFunctionArgumentKind3 { arg: (var.kind(), name.kind(), mutable.kind()), fxn_name: "var/define".to_string() },
300 None
301 ).with_compiler_loc()
302 )
303}
304
305
306pub struct VarDefine{}
307impl NativeFunctionCompiler for VarDefine {
308 fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
309 if arguments.len() != 3 {
310 return Err(MechError2::new(IncorrectNumberOfArguments { expected: 1, found: arguments.len() }, None).with_compiler_loc());
311 }
312 let var = arguments[0].clone();
313 let name = &arguments[1].clone();
314 let mutable = &arguments[2].clone();
315 let name_string = name.as_string()?;
316 let id = hash_str(&name_string.borrow());
317
318 match impl_var_define_fxn(var.clone(), name.clone(), mutable.clone(), id) {
319 Ok(fxn) => Ok(fxn),
320 Err(_) => {
321 match (var) {
322 (Value::MutableReference(input)) => {impl_var_define_fxn(input.borrow().clone(), name.clone(), mutable.clone(), id)}
323 _ => Err(MechError2::new(
324 UnhandledFunctionArgumentKind3 { arg: (var.kind(), name.kind(), mutable.kind()), fxn_name: "var/define".to_string() },
325 None
326 ).with_compiler_loc()
327 ),
328 }
329 }
330 }
331 }
332}