Skip to main content

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        let mut registers = [0, 0];
32        registers[0] = compile_register_brrw!(self.out, ctx);
33        registers[1] = compile_register!(self.source, ctx);
34        ctx.features.insert(FeatureFlag::Builtin(FeatureKind::Access));
35        ctx.emit_unop(
36          hash_str(stringify!($fxn_name)),
37          registers[0],
38          registers[1],
39        );
40        Ok(registers[0])
41      }
42    }
43  }
44}
45
46macro_rules! impl_col_access_fxn_shapes {
47  ($type:ident) => {
48    paste!{
49      #[cfg(feature = "matrix1")]
50      impl_col_access_fxn!([<TableAccessCol $type:camel M1>], Matrix1, [<$type>]);
51      #[cfg(feature = "vector2")]
52      impl_col_access_fxn!([<TableAccessCol $type:camel V2>], Vector2, [<$type>]);
53      #[cfg(feature = "vector3")]
54      impl_col_access_fxn!([<TableAccessCol $type:camel V3>], Vector3, [<$type>]);
55      #[cfg(feature = "vector4")]
56      impl_col_access_fxn!([<TableAccessCol $type:camel V4>], Vector4, [<$type>]);
57      #[cfg(feature = "vectord")]
58      impl_col_access_fxn!([<TableAccessCol $type:camel VD>], DVector, [<$type>]);
59    }
60  }
61}
62
63#[cfg(all(feature = "bool", feature = "matrix"))]
64impl_col_access_fxn_shapes!(bool);
65#[cfg(all(feature = "i8", feature = "matrix"))]
66impl_col_access_fxn_shapes!(i8);
67#[cfg(all(feature = "i16", feature = "matrix"))]
68impl_col_access_fxn_shapes!(i16);
69#[cfg(all(feature = "i32", feature = "matrix"))]
70impl_col_access_fxn_shapes!(i32);
71#[cfg(all(feature = "i64", feature = "matrix"))]
72impl_col_access_fxn_shapes!(i64);
73#[cfg(all(feature = "i128", feature = "matrix"))]
74impl_col_access_fxn_shapes!(i128);
75#[cfg(all(feature = "u8", feature = "matrix"))]
76impl_col_access_fxn_shapes!(u8);
77#[cfg(all(feature = "u16", feature = "matrix"))]
78impl_col_access_fxn_shapes!(u16);
79#[cfg(all(feature = "u32", feature = "matrix"))]
80impl_col_access_fxn_shapes!(u32);
81#[cfg(all(feature = "u64", feature = "matrix"))]
82impl_col_access_fxn_shapes!(u64);
83#[cfg(all(feature = "u128", feature = "matrix"))]
84impl_col_access_fxn_shapes!(u128);
85#[cfg(all(feature = "f32", feature = "matrix"))]
86impl_col_access_fxn_shapes!(f32);
87#[cfg(all(feature = "f64", feature = "matrix"))]
88impl_col_access_fxn_shapes!(f64);
89#[cfg(all(feature = "string", feature = "matrix"))]
90impl_col_access_fxn_shapes!(String);
91#[cfg(all(feature = "complex", feature = "matrix"))]
92impl_col_access_fxn_shapes!(C64);
93#[cfg(all(feature = "rational", feature = "matrix"))]
94impl_col_access_fxn_shapes!(R64);
95
96macro_rules! impl_access_column_table_match_arms {
97  ($arg:expr, $($lhs_type:ident, $($default:expr, $type_string:tt),+);+ $(;)?) => {
98    paste!{
99      match $arg {
100        (Value::Table(tbl),Value::Id(k)) => {
101          let tbl_brrw = tbl.borrow();
102          match (tbl_brrw.get(&k),tbl_brrw.rows()) {
103            $(
104              $(
105                #[cfg(all(feature = $type_string, feature = "matrix1"))]
106                (Some((ValueKind::$lhs_type,value)),1) => Ok(Box::new([<TableAccessCol $lhs_type M1>]{source: value.clone(), out: Ref::new(Matrix1::from_element($default)) })),
107                #[cfg(all(feature = $type_string, feature = "vector2"))]
108                (Some((ValueKind::$lhs_type,value)),2) => Ok(Box::new([<TableAccessCol $lhs_type V2>]{source: value.clone(), out: Ref::new(Vector2::from_element($default)) })),
109                #[cfg(all(feature = $type_string, feature = "vector3"))]
110                (Some((ValueKind::$lhs_type,value)),3) => Ok(Box::new([<TableAccessCol $lhs_type V3>]{source: value.clone(), out: Ref::new(Vector3::from_element($default)) })),
111                #[cfg(all(feature = $type_string, feature = "vector4"))]
112                (Some((ValueKind::$lhs_type,value)),4) => Ok(Box::new([<TableAccessCol $lhs_type V4>]{source: value.clone(), out: Ref::new(Vector4::from_element($default)) })),
113                #[cfg(all(feature = $type_string, feature = "vectord"))]
114                (Some((ValueKind::$lhs_type,value)),n) => Ok(Box::new([<TableAccessCol $lhs_type VD>]{source: value.clone(), out: Ref::new(DVector::from_element(n,$default)) })),
115              )+
116            )+
117            // Column not found
118            _ => Err(MechError::new(TableColumnNotFoundError { column_id: k.clone() }, None).with_compiler_loc()),
119          }
120        }
121        (tbl,key) => Err(MechError::new(UnhandledFunctionArgumentKind2 { arg: (tbl.kind(), key.kind()), fxn_name: "TableAccessColumn".to_string() }, None).with_compiler_loc()),
122      }
123    }
124  }
125}
126
127fn impl_access_column_table_fxn(source: Value, key: Value) -> MResult<Box<dyn MechFunction>> {
128  if let (Value::Table(tbl), Value::Id(k)) = (&source, &key) {
129    let tbl_brrw = tbl.borrow();
130    if let Some((ValueKind::Option(_), value)) = tbl_brrw.get(k) {
131      return Ok(Box::new(TableAccessSwizzle {
132        out: Value::MatrixValue(value.clone()),
133      }));
134    }
135  }
136  impl_access_column_table_match_arms!(
137    (source,key),
138    Bool,bool::default(),"bool";
139    I8,i8::default(),"i8";
140    I16,i16::default(),"i16";
141    I32,i32::default(),"i32";
142    I64,i64::default(),"i64";
143    I128,i128::default(),"i128";
144    U8,u8::default(),"u8";
145    U16,u16::default(),"u16";
146    U32,u32::default(),"u32";
147    U64,u64::default(),"u64";
148    U128,u128::default(),"u128";
149    F32,f32::default(),"f32";
150    F64,f64::default(),"f64";
151    String,String::default(),"string";
152    C64,C64::default(),"complex";
153    R64,R64::default(),"rational";
154  )
155}
156
157pub struct TableAccessColumn {}
158impl NativeFunctionCompiler for TableAccessColumn {
159  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
160    if arguments.len() <= 1 {
161      return Err(MechError::new(IncorrectNumberOfArguments { expected: 1, found: arguments.len() }, None).with_compiler_loc());
162    }
163    let tbl = arguments[0].clone();
164    let key = arguments[1].clone();
165    match impl_access_column_table_fxn(tbl.clone(), key.clone()) {
166      Ok(fxn) => Ok(fxn),
167      Err(_) => {
168        match (tbl.clone(),&key) {
169          (Value::MutableReference(tbl),_) => { impl_access_column_table_fxn(tbl.borrow().clone(), key.clone()) }
170          x => Err(MechError::new(UnhandledFunctionArgumentKind2 { arg: (tbl.kind(), key.kind()), fxn_name: "TableAccessColumn".to_string() }, None).with_compiler_loc()),
171        }
172      }
173    }
174  }
175}
176  
177// Table Access Swizzle -------------------------------------------------------
178
179#[derive(Debug)]
180pub struct TableAccessSwizzle {
181  pub out: Value,
182}
183
184impl MechFunctionImpl for TableAccessSwizzle {
185  fn solve(&self) {
186    ()
187  }
188  fn out(&self) -> Value { self.out.clone() }
189  fn to_string(&self) -> String { format!("{:#?}", self) }
190}
191#[cfg(feature = "compiler")]
192impl MechFunctionCompiler for TableAccessSwizzle {
193  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
194    let mut registers = [0];
195    registers[0] = compile_register!(self.out, ctx);
196    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::Swizzle));
197    ctx.emit_nullop(
198      hash_str("TableAccessSwizzle"),
199      registers[0],
200    );
201    Ok(registers[0])
202  }
203}
204
205// Table Access Scalar -------------------------------------------------------
206
207#[derive(Debug)]
208pub struct TableAccessScalarF {
209  pub source: Ref<MechTable>,
210  pub ix: Ref<usize>,
211  pub out: Ref<MechRecord>,
212}
213
214impl MechFunctionImpl for TableAccessScalarF {
215  fn solve(&self) {
216    let table = self.source.borrow();
217    let mut record = self.out.borrow_mut();
218    let row_ix = *self.ix.borrow();
219    for (key, (kind, matrix)) in table.data.iter() {
220      let value = matrix.index1d(row_ix);
221      record.data.insert(*key, value.clone());
222    }
223  }
224  fn out(&self) -> Value { Value::Record(self.out.clone()) }
225  fn to_string(&self) -> String {format!("{:#?}", self)}
226}
227#[cfg(feature = "compiler")]
228impl MechFunctionCompiler for TableAccessScalarF {
229  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
230    let mut registers = [0,0,0];
231    
232    registers[0] = compile_register_brrw!(self.out,  ctx);
233    registers[1] = compile_register_brrw!(self.source, ctx);
234    registers[2] = compile_register_brrw!(self.ix, ctx);
235
236    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::Table));
237    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::Access));
238
239    ctx.emit_binop(
240      hash_str(stringify!("TableAccessScalarF")),
241      registers[0],
242      registers[1],
243      registers[2],
244    );
245
246    return Ok(registers[0])
247  }
248}
249
250pub struct TableAccessScalar{}
251
252impl NativeFunctionCompiler for TableAccessScalar {
253  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
254    if arguments.len() <= 1 {
255      return Err(MechError::new(IncorrectNumberOfArguments { expected: 1, found: arguments.len() }, None).with_compiler_loc());
256    }
257    let tbl = arguments[0].clone();
258    let ix1 = arguments[1].clone();
259    match (tbl.clone(), ix1.clone()) {
260      #[cfg(feature = "table")]
261      (Value::Table(source), Value::Index(ix)) => {
262        let record = match source.borrow().get_record(*ix.borrow()) {
263          Some(record) => record,
264          None => return Err(MechError::new(UnhandledFunctionArgumentKind2 { arg: (tbl.kind(), ix1.kind()), fxn_name: "TableAccessScalar".to_string() }, None).with_compiler_loc()),
265        };
266        Ok(Box::new(TableAccessScalarF{source: source.clone(), ix: ix.clone(), out: Ref::new(record) }))
267      }
268      (Value::MutableReference(src_ref), Value::Index(ix)) => {
269        let src_ref_brrw = src_ref.borrow();
270        match &*src_ref_brrw {
271          #[cfg(feature = "table")]
272          Value::Table(source) => {
273            let record = match source.borrow().get_record(*ix.borrow()) {
274              Some(record) => record,
275              None => return Err(MechError::new(UnhandledFunctionArgumentKind2 { arg: (tbl.kind(), ix1.kind()), fxn_name: "TableAccessScalar".to_string() }, None).with_compiler_loc()),
276            };
277            Ok(Box::new(TableAccessScalarF{source: source.clone(), ix: ix.clone(), out: Ref::new(record) }))
278          }
279          _ => Err(MechError::new(UnhandledFunctionArgumentKind2 { arg: (tbl.kind(), ix1.kind()), fxn_name: "TableAccessScalar".to_string() }, None).with_compiler_loc()),
280        }
281      }
282      _ => Err(MechError::new(UnhandledFunctionArgumentKind2 { arg: (tbl.kind(), ix1.kind()), fxn_name: "TableAccessScalar".to_string() }, None).with_compiler_loc()),
283    }
284  }
285}
286
287// Table Access Range -------------------------------------------------------
288
289#[derive(Debug)]
290pub struct TableAccessRangeIndex {
291  pub source: Ref<MechTable>,
292  pub ix: Ref<DVector<usize>>,
293  pub out: Ref<MechTable>,
294}
295
296impl MechFunctionImpl for TableAccessRangeIndex {
297  fn solve(&self) {
298    let table = self.source.borrow();
299    let mut out_table = self.out.borrow_mut();
300    let ix_brrw = self.ix.borrow();
301
302    for (key, (_kind, matrix)) in table.data.iter() {
303      let (_out_kind, out_matrix) = out_table.data.get_mut(key).unwrap();
304      for (out_i, i) in ix_brrw.iter().enumerate() {
305        let value = matrix.index1d(*i);
306        out_matrix.set_index1d(out_i, value.clone());
307      }
308    }
309  }
310  fn out(&self) -> Value { Value::Table(self.out.clone()) }
311  fn to_string(&self) -> String {format!("{:#?}", self)}
312}
313#[cfg(feature = "compiler")]
314impl MechFunctionCompiler for TableAccessRangeIndex {
315  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
316    let mut registers = [0,0,0];
317    
318    registers[0] = compile_register_brrw!(self.out,  ctx);
319    registers[1] = compile_register_brrw!(self.source, ctx);
320    registers[2] = compile_register_brrw!(self.ix, ctx);
321
322    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::Table));
323    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::SubscriptRange));
324
325    ctx.emit_binop(
326      hash_str(stringify!("TableAccessRangeIndex")),
327      registers[0],
328      registers[1],
329      registers[2],
330    );
331
332    return Ok(registers[0])
333  }
334}
335
336#[derive(Debug)]
337pub struct TableAccessRangeBool {
338  pub source: Ref<MechTable>,
339  pub ix: Ref<DVector<bool>>,
340  pub out: Ref<MechTable>,
341}
342
343impl MechFunctionImpl for TableAccessRangeBool {
344  fn solve(&self) {
345    let table = self.source.borrow();
346    let ix_brrw = self.ix.borrow();
347    let true_count = ix_brrw.iter().filter(|&&b| b).count();
348
349    let mut out_table = self.out.borrow_mut();
350
351    for (key, (_kind, matrix)) in table.data.iter() {
352      let (_out_kind, out_matrix) = out_table.data.get_mut(key).unwrap();
353
354      // Resize output to match number of true entries
355      out_matrix.resize_vertically(true_count, Value::Empty);
356
357      // Fill with contiguous values
358      let mut push_index = 0;
359      for (i, flag) in ix_brrw.iter().enumerate() {
360        if *flag {
361          let value = matrix.index1d(i + 1); // 1-based indexing; use `i` if 0-based
362          out_matrix.set_index1d(push_index, value.clone());
363          push_index += 1;
364        }
365      }
366    }
367    out_table.rows = true_count;
368  }
369  fn out(&self) -> Value { Value::Table(self.out.clone()) }
370  fn to_string(&self) -> String {format!("{:#?}", self)}
371}
372#[cfg(feature = "compiler")]
373impl MechFunctionCompiler for TableAccessRangeBool {
374  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
375    let mut registers = [0,0,0];
376    
377    registers[0] = compile_register_brrw!(self.out,  ctx);
378    registers[1] = compile_register_brrw!(self.source, ctx);
379    registers[2] = compile_register_brrw!(self.ix, ctx);
380
381    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::Table));
382    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::LogicalIndexing));
383
384    ctx.emit_binop(
385      hash_str(stringify!("TableAccessRangeBool")),
386      registers[0],
387      registers[1],
388      registers[2],
389    );
390
391    return Ok(registers[0])
392  }
393}
394
395pub struct TableAccessRange{}
396
397impl NativeFunctionCompiler for TableAccessRange {
398  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
399    if arguments.len() <= 1 {
400      return Err(MechError::new(IncorrectNumberOfArguments { expected: 1, found: arguments.len() }, None).with_compiler_loc());
401    }
402    let ixes = arguments.clone().split_off(1);
403    let tbl = arguments[0].clone();
404    match (tbl.clone(), ixes.as_slice()) {
405      #[cfg(all(feature = "table", feature = "matrix"))]
406      (Value::Table(source), [Value::MatrixIndex(Matrix::DVector(ix))])  => {
407        let out_table = source.borrow().empty_table(ix.borrow().len());
408        Ok(Box::new(TableAccessRangeIndex{source: source.clone(), ix: ix.clone(), out: Ref::new(out_table) }))
409      }
410      #[cfg(all(feature = "matrix", feature = "table", feature = "logical_indexing"))]
411      (Value::Table(source), [Value::MatrixBool(Matrix::DVector(ix))])  => {
412        let out_table = source.borrow().empty_table(ix.borrow().len());
413        Ok(Box::new(TableAccessRangeBool{source: source.clone(), ix: ix.clone(), out: Ref::new(out_table) }))
414      }
415      #[cfg(all(feature = "table", feature = "matrix"))]
416      (Value::MutableReference(src_ref), [Value::MatrixIndex(Matrix::DVector(ix))]) => {
417        let src_ref_brrw = src_ref.borrow();
418        match &*src_ref_brrw {
419          Value::Table(source) => {
420            let out_table = source.borrow().empty_table(ix.borrow().len());
421            Ok(Box::new(TableAccessRangeIndex{source: source.clone(), ix: ix.clone(), out: Ref::new(out_table) }))
422          }
423          _ => Err(MechError::new(UnhandledFunctionArgumentIxesMono { arg: (tbl.kind(), ixes.iter().map(|x| x.kind()).collect()), fxn_name: "TableAccessRange".to_string() }, None).with_compiler_loc()),
424        }
425      }
426      #[cfg(all(feature = "matrix", feature = "table", feature = "logical_indexing"))]
427      (Value::MutableReference(src_ref), [Value::MatrixBool(Matrix::DVector(ix))]) => {
428        let src_ref_brrw = src_ref.borrow();
429        match &*src_ref_brrw {
430          Value::Table(source) => {
431            let out_table = source.borrow().empty_table(ix.borrow().len());
432            Ok(Box::new(TableAccessRangeBool{source: source.clone(), ix: ix.clone(), out: Ref::new(out_table) }))
433          }
434          _ => Err(MechError::new(UnhandledFunctionArgumentIxesMono { arg: (tbl.kind(), ixes.iter().map(|x| x.kind()).collect()), fxn_name: "TableAccessRange".to_string() }, None).with_compiler_loc()),
435        }
436      }
437      _ => Err(MechError::new(UnhandledFunctionArgumentIxesMono { arg: (tbl.kind(), ixes.iter().map(|x| x.kind()).collect()), fxn_name: "TableAccessRange".to_string() }, None).with_compiler_loc()),
438    }
439  }
440}