mech_interpreter/stdlib/access/
table.rs

1#[macro_use]
2use crate::stdlib::*;
3use crate::stdlib::access::*;
4
5// Table Access ---------------------------------------------------------------
6
7macro_rules! impl_col_access_fxn {
8  ($fxn_name:ident, $vector_size:ident, $out_type:ty) => {
9    #[derive(Debug)]
10    struct $fxn_name {
11      source: Matrix<Value>,
12      out: Ref<$vector_size<$out_type>>,
13    }
14    impl MechFunctionImpl for $fxn_name {
15      fn solve(&self) {
16        let out_ptr = self.out.as_mut_ptr();
17        unsafe { 
18          for i in 1..=self.source.shape()[0] {
19            paste! {
20              (&mut (*out_ptr))[i-1] = self.source.index1d(i).[<as_ $out_type:lower>]().unwrap().borrow().clone();
21            }
22          }
23        }
24      }
25      fn out(&self) -> Value { self.out.to_value() }
26      fn to_string(&self) -> String { format!("{:#?}", self) }
27    }
28    #[cfg(feature = "compiler")]
29    impl MechFunctionCompiler for $fxn_name {
30      fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
31        todo!();
32      }
33    }
34  }
35}
36
37macro_rules! impl_col_access_fxn_shapes {
38  ($type:ident) => {
39    paste!{
40      #[cfg(feature = "matrix1")]
41      impl_col_access_fxn!([<TableAccessCol $type:camel M1>], Matrix1, [<$type>]);
42      #[cfg(feature = "vector2")]
43      impl_col_access_fxn!([<TableAccessCol $type:camel V2>], Vector2, [<$type>]);
44      #[cfg(feature = "vector3")]
45      impl_col_access_fxn!([<TableAccessCol $type:camel V3>], Vector3, [<$type>]);
46      #[cfg(feature = "vector4")]
47      impl_col_access_fxn!([<TableAccessCol $type:camel V4>], Vector4, [<$type>]);
48      #[cfg(feature = "vectord")]
49      impl_col_access_fxn!([<TableAccessCol $type:camel VD>], DVector, [<$type>]);
50    }
51  }
52}
53
54#[cfg(all(feature = "bool", feature = "matrix"))]
55impl_col_access_fxn_shapes!(bool);
56#[cfg(all(feature = "i8", feature = "matrix"))]
57impl_col_access_fxn_shapes!(i8);
58#[cfg(all(feature = "i16", feature = "matrix"))]
59impl_col_access_fxn_shapes!(i16);
60#[cfg(all(feature = "i32", feature = "matrix"))]
61impl_col_access_fxn_shapes!(i32);
62#[cfg(all(feature = "i64", feature = "matrix"))]
63impl_col_access_fxn_shapes!(i64);
64#[cfg(all(feature = "i128", feature = "matrix"))]
65impl_col_access_fxn_shapes!(i128);
66#[cfg(all(feature = "u8", feature = "matrix"))]
67impl_col_access_fxn_shapes!(u8);
68#[cfg(all(feature = "u16", feature = "matrix"))]
69impl_col_access_fxn_shapes!(u16);
70#[cfg(all(feature = "u32", feature = "matrix"))]
71impl_col_access_fxn_shapes!(u32);
72#[cfg(all(feature = "u64", feature = "matrix"))]
73impl_col_access_fxn_shapes!(u64);
74#[cfg(all(feature = "u128", feature = "matrix"))]
75impl_col_access_fxn_shapes!(u128);
76#[cfg(all(feature = "f32", feature = "matrix"))]
77impl_col_access_fxn_shapes!(F32);
78#[cfg(all(feature = "f64", feature = "matrix"))]
79impl_col_access_fxn_shapes!(F64);
80#[cfg(all(feature = "string", feature = "matrix"))]
81impl_col_access_fxn_shapes!(String);
82#[cfg(all(feature = "complex", feature = "matrix"))]
83impl_col_access_fxn_shapes!(ComplexNumber);
84#[cfg(all(feature = "rational", feature = "matrix"))]
85impl_col_access_fxn_shapes!(RationalNumber);
86
87macro_rules! impl_access_column_table_match_arms {
88  ($arg:expr, $($lhs_type:ident, $($default:expr, $type_string:tt),+);+ $(;)?) => {
89    paste!{
90      match $arg {
91        (Value::Table(tbl),Value::Id(k)) => {
92          let tbl_brrw = tbl.borrow();
93          match (tbl_brrw.get(&k),tbl_brrw.rows()) {
94            $(
95              $(
96                #[cfg(all(feature = $type_string, feature = "matrix1"))]
97                (Some((ValueKind::$lhs_type,value)),1) => Ok(Box::new([<TableAccessCol $lhs_type M1>]{source: value.clone(), out: Ref::new(Matrix1::from_element($default)) })),
98                #[cfg(all(feature = $type_string, feature = "vector2"))]
99                (Some((ValueKind::$lhs_type,value)),2) => Ok(Box::new([<TableAccessCol $lhs_type V2>]{source: value.clone(), out: Ref::new(Vector2::from_element($default)) })),
100                #[cfg(all(feature = $type_string, feature = "vector3"))]
101                (Some((ValueKind::$lhs_type,value)),3) => Ok(Box::new([<TableAccessCol $lhs_type V3>]{source: value.clone(), out: Ref::new(Vector3::from_element($default)) })),
102                #[cfg(all(feature = $type_string, feature = "vector4"))]
103                (Some((ValueKind::$lhs_type,value)),4) => Ok(Box::new([<TableAccessCol $lhs_type V4>]{source: value.clone(), out: Ref::new(Vector4::from_element($default)) })),
104                #[cfg(all(feature = $type_string, feature = "vectord"))]
105                (Some((ValueKind::$lhs_type,value)),n) => Ok(Box::new([<TableAccessCol $lhs_type VD>]{source: value.clone(), out: Ref::new(DVector::from_element(n,$default)) })),
106              )+
107            )+
108            x => return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "no shape".to_string(), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind}),
109          }
110        }
111        x => Err(MechError{file: file!().to_string(),  tokens: vec![], msg: format!("{:#?}",x), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind }),
112      }
113    }
114  }
115}
116
117fn impl_access_column_table_fxn(source: Value, key: Value) -> Result<Box<dyn MechFunction>, MechError> {
118  impl_access_column_table_match_arms!(
119    (source,key),
120    Bool,bool::default(),"bool";
121    I8,i8::default(),"i8";
122    I16,i16::default(),"i16";
123    I32,i32::default(),"i32";
124    I64,i64::default(),"i64";
125    I128,i128::default(),"i128";
126    U8,u8::default(),"u8";
127    U16,u16::default(),"u16";
128    U32,u32::default(),"u32";
129    U64,u64::default(),"u64";
130    U128,u128::default(),"u128";
131    F32,F32::default(),"f32";
132    F64,F64::default(),"f64";
133    String,String::default(),"string";
134    ComplexNumber,ComplexNumber::default(),"complex";
135    RationalNumber,RationalNumber::default(),"rational";
136  )
137}
138
139pub struct TableAccessColumn {}
140impl NativeFunctionCompiler for TableAccessColumn {
141  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
142    if arguments.len() <= 1 {
143      return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::IncorrectNumberOfArguments});
144    }
145    let tbl = arguments[0].clone();
146    let key = arguments[1].clone();
147    match impl_access_column_table_fxn(tbl.clone(), key.clone()) {
148      Ok(fxn) => Ok(fxn),
149      Err(_) => {
150        match (tbl,&key) {
151          (Value::MutableReference(tbl),_) => { impl_access_column_table_fxn(tbl.borrow().clone(), key.clone()) }
152          x => Err(MechError{file: file!().to_string(),  tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind }),
153        }
154      }
155    }
156  }
157}
158  
159// Table Access Swizzle -------------------------------------------------------
160
161#[derive(Debug)]
162pub struct TableAccessSwizzle {
163  pub out: Value,
164}
165
166impl MechFunctionImpl for TableAccessSwizzle {
167  fn solve(&self) {
168    ()
169  }
170  fn out(&self) -> Value { self.out.clone() }
171  fn to_string(&self) -> String { format!("{:#?}", self) }
172}
173#[cfg(feature = "compiler")]
174impl MechFunctionCompiler for TableAccessSwizzle {
175  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
176    todo!();
177  }
178}
179
180// Table Access Scalar -------------------------------------------------------
181
182#[derive(Debug)]
183pub struct TableAccessScalarF {
184  pub source: Ref<MechTable>,
185  pub ix: Ref<usize>,
186  pub out: Ref<MechRecord>,
187}
188
189impl MechFunctionImpl for TableAccessScalarF {
190  fn solve(&self) {
191    let table = self.source.borrow();
192    let mut record = self.out.borrow_mut();
193    let row_ix = *self.ix.borrow();
194    for (key, (kind, matrix)) in table.data.iter() {
195      let value = matrix.index1d(row_ix);
196      record.data.insert(*key, value.clone());
197    }
198  }
199  fn out(&self) -> Value { Value::Record(self.out.clone()) }
200  fn to_string(&self) -> String {format!("{:#?}", self)}
201}
202#[cfg(feature = "compiler")]
203impl MechFunctionCompiler for TableAccessScalarF {
204  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
205    todo!();
206  }
207}
208
209pub struct TableAccessScalar{}
210
211impl NativeFunctionCompiler for TableAccessScalar {
212  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
213    if arguments.len() <= 1 {
214      return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::IncorrectNumberOfArguments});
215    }
216    let tbl = arguments[0].clone();
217    let ix = arguments[1].clone();
218    match (tbl, ix) {
219      #[cfg(feature = "table")]
220      (Value::Table(source), Value::Index(ix)) => {
221        let record = match source.borrow().get_record(*ix.borrow()) {
222          Some(record) => record,
223          None => return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::None}),
224        };
225        Ok(Box::new(TableAccessScalarF{source: source.clone(), ix: ix.clone(), out: Ref::new(record) }))
226      }
227      (Value::MutableReference(src_ref), Value::Index(ix)) => {
228        let src_ref_brrw = src_ref.borrow();
229        match &*src_ref_brrw {
230          #[cfg(feature = "table")]
231          Value::Table(source) => {
232            let record = match source.borrow().get_record(*ix.borrow()) {
233              Some(record) => record,
234              None => return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::None}),
235            };
236            Ok(Box::new(TableAccessScalarF{source: source.clone(), ix: ix.clone(), out: Ref::new(record) }))
237          }
238          _ => Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind}),
239        }
240      }
241      _ => Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind}),
242    }
243  }
244}
245
246// Table Access Range -------------------------------------------------------
247
248#[derive(Debug)]
249pub struct TableAccessRangeIndex {
250  pub source: Ref<MechTable>,
251  pub ix: Ref<DVector<usize>>,
252  pub out: Ref<MechTable>,
253}
254
255impl MechFunctionImpl for TableAccessRangeIndex {
256  fn solve(&self) {
257    let table = self.source.borrow();
258    let mut out_table = self.out.borrow_mut();
259    let ix_brrw = self.ix.borrow();
260
261    for (key, (_kind, matrix)) in table.data.iter() {
262      let (_out_kind, out_matrix) = out_table.data.get_mut(key).unwrap();
263      for (out_i, i) in ix_brrw.iter().enumerate() {
264        let value = matrix.index1d(*i);
265        out_matrix.set_index1d(out_i, value.clone());
266      }
267    }
268  }
269  fn out(&self) -> Value { Value::Table(self.out.clone()) }
270  fn to_string(&self) -> String {format!("{:#?}", self)}
271}
272#[cfg(feature = "compiler")]
273impl MechFunctionCompiler for TableAccessRangeIndex {
274  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
275    todo!();
276  }
277}
278
279#[derive(Debug)]
280pub struct TableAccessRangeBool {
281  pub source: Ref<MechTable>,
282  pub ix: Ref<DVector<bool>>,
283  pub out: Ref<MechTable>,
284}
285
286impl MechFunctionImpl for TableAccessRangeBool {
287  fn solve(&self) {
288    let table = self.source.borrow();
289    let ix_brrw = self.ix.borrow();
290    let true_count = ix_brrw.iter().filter(|&&b| b).count();
291
292    let mut out_table = self.out.borrow_mut();
293
294    for (key, (_kind, matrix)) in table.data.iter() {
295      let (_out_kind, out_matrix) = out_table.data.get_mut(key).unwrap();
296
297      // Resize output to match number of true entries
298      out_matrix.resize_vertically(true_count, Value::Empty);
299
300      // Fill with contiguous values
301      let mut push_index = 0;
302      for (i, flag) in ix_brrw.iter().enumerate() {
303        if *flag {
304          let value = matrix.index1d(i + 1); // 1-based indexing; use `i` if 0-based
305          out_matrix.set_index1d(push_index, value.clone());
306          push_index += 1;
307        }
308      }
309    }
310    out_table.rows = true_count;
311  }
312  fn out(&self) -> Value { Value::Table(self.out.clone()) }
313  fn to_string(&self) -> String {format!("{:#?}", self)}
314}
315#[cfg(feature = "compiler")]
316impl MechFunctionCompiler for TableAccessRangeBool {
317  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
318    todo!();
319  }
320}
321
322pub struct TableAccessRange{}
323
324impl NativeFunctionCompiler for TableAccessRange {
325  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
326    if arguments.len() <= 1 {
327      return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::IncorrectNumberOfArguments});
328    }
329    let ixes = arguments.clone().split_off(1);
330    let tbl = arguments[0].clone();
331    match (tbl, ixes.as_slice()) {
332      #[cfg(all(feature = "table", feature = "matrix"))]
333      (Value::Table(source), [Value::MatrixIndex(Matrix::DVector(ix))])  => {
334        let out_table = source.borrow().empty_table(ix.borrow().len());
335        Ok(Box::new(TableAccessRangeIndex{source: source.clone(), ix: ix.clone(), out: Ref::new(out_table) }))
336      }
337      #[cfg(all(feature = "matrix", feature = "table", feature = "bool"))]
338      (Value::Table(source), [Value::MatrixBool(Matrix::DVector(ix))])  => {
339        let out_table = source.borrow().empty_table(ix.borrow().len());
340        Ok(Box::new(TableAccessRangeBool{source: source.clone(), ix: ix.clone(), out: Ref::new(out_table) }))
341      }
342      #[cfg(all(feature = "table", feature = "matrix"))]
343      (Value::MutableReference(src_ref), [Value::MatrixIndex(Matrix::DVector(ix))]) => {
344        let src_ref_brrw = src_ref.borrow();
345        match &*src_ref_brrw {
346          Value::Table(source) => {
347            let out_table = source.borrow().empty_table(ix.borrow().len());
348            Ok(Box::new(TableAccessRangeIndex{source: source.clone(), ix: ix.clone(), out: Ref::new(out_table) }))
349          }
350          _ => Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind}),
351        }
352      }
353      #[cfg(all(feature = "matrix", feature = "table", feature = "bool"))]
354      (Value::MutableReference(src_ref), [Value::MatrixBool(Matrix::DVector(ix))]) => {
355        let src_ref_brrw = src_ref.borrow();
356        match &*src_ref_brrw {
357          Value::Table(source) => {
358            let out_table = source.borrow().empty_table(ix.borrow().len());
359            Ok(Box::new(TableAccessRangeBool{source: source.clone(), ix: ix.clone(), out: Ref::new(out_table) }))
360          }
361          _ => Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind}),
362        }
363      }
364      _ => Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind}),
365    }
366  }
367}