mech_interpreter/
structures.rs

1use crate::*;
2use std::collections::HashMap;
3
4// Structures
5// ----------------------------------------------------------------------------
6
7pub fn structure(strct: &Structure, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
8  match strct {
9    Structure::Empty => Ok(Value::Empty),
10    #[cfg(feature = "record")]
11    Structure::Record(x) => record(&x, env, p),
12    #[cfg(feature = "matrix")]
13    Structure::Matrix(x) => matrix(&x, env, p),
14    #[cfg(feature = "table")]
15    Structure::Table(x) => table(&x, env, p),
16    #[cfg(feature = "tuple")]
17    Structure::Tuple(x) => tuple(&x, env, p),
18    #[cfg(feature = "tuple_struct")]
19    Structure::TupleStruct(x) => todo!(),
20    #[cfg(feature = "set")]
21    Structure::Set(x) => set(&x, env, p),
22    #[cfg(feature = "map")]
23    Structure::Map(x) => map(&x, env, p),
24    x => Err(MechError2::new(FeatureNotEnabledError, Some(format!("Feature not enabled for `{:?}`", stringify!(x)))).with_compiler_loc()),
25  }
26}
27
28#[cfg(feature = "tuple")]
29pub fn tuple(tpl: &Tuple, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
30  let mut elements = vec![];
31  for el in &tpl.elements {
32    let result = expression(el, env, p)?;
33    elements.push(Box::new(result));
34  }
35  let mech_tuple = Ref::new(MechTuple{elements});
36  Ok(Value::Tuple(mech_tuple))
37}
38
39#[cfg(feature = "map")]
40pub fn map(mp: &Map, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
41  let mut m = IndexMap::new();
42  for b in &mp.elements {
43    let key = expression(&b.key, env, p)?;
44    let val = expression(&b.value, env, p)?;
45    m.insert(key,val);
46  }
47  
48  let key_kind = m.keys().next().unwrap().kind();
49  // verify that all the keys are the same kind:
50  for k in m.keys() {
51    if k.kind() != key_kind {
52      return Err(MechError2::new(
53        MapKeyKindMismatchError{expected_kind: key_kind.clone(), actual_kind: k.kind().clone()},
54        None
55      ).with_compiler_loc());
56    }
57  }
58  
59  let value_kind = m.values().next().unwrap().kind();
60  // verify that all the values are the same kind:
61  for v in m.values() {
62    if v.kind() != value_kind {
63      return Err(MechError2::new(
64        MapValueKindMismatchError{expected_kind: value_kind.clone(), actual_kind: v.kind().clone()},
65        None
66      ).with_compiler_loc());
67    }
68  }
69  Ok(Value::Map(Ref::new(MechMap{
70    num_elements: m.len(),
71    key_kind,
72    value_kind,
73    map: m
74  })))
75}
76
77#[cfg(feature = "record")]
78pub fn record(rcrd: &Record, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
79  let mut data: IndexMap<u64,Value> = IndexMap::new();
80  let cols: usize = rcrd.bindings.len();
81  let mut kinds: Vec<ValueKind> = Vec::new();
82  let mut field_names: HashMap<u64,String> = HashMap::new();
83  for b in &rcrd.bindings {
84    let name_hash = b.name.hash();
85    let name_str = b.name.to_string();
86    let val = expression(&b.value, env, p)?;
87    let knd: ValueKind = match &b.kind {
88      Some(k) => kind_annotation(&k.kind, p)?.to_value_kind(&p.state.borrow().kinds)?,
89      None => val.kind(),
90    };
91    // If the kinds are different, do a conversion.
92    kinds.push(knd.clone());
93    #[cfg(feature = "convert")]
94    if knd != val.kind() {
95      let fxn = ConvertKind{}.compile(&vec![val.clone(), Value::Kind(knd.clone())]);
96      match fxn {
97        Ok(convert_fxn) => {
98          convert_fxn.solve();
99          let converted_result = convert_fxn.out();
100          p.state.borrow_mut().add_plan_step(convert_fxn);
101          data.insert(name_hash, converted_result);
102        },
103        Err(e) => {
104          return Err(MechError2::new(
105            TableColumnKindMismatchError {
106              column_id: name_hash,
107              expected_kind: knd.clone(),
108              actual_kind: val.kind().clone(),
109            },
110            None
111          ).with_compiler_loc());
112        }
113      }
114    } else {
115      data.insert(name_hash, val);
116    }
117    #[cfg(not(feature = "convert"))]
118    if knd != val.kind() {
119      return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::KindMismatch(val.kind(),knd)});
120    } else {
121      data.insert(name_hash, val);
122    }
123    field_names.insert(name_hash, name_str);
124  }
125  Ok(Value::Record(Ref::new(MechRecord{
126    cols,
127    kinds,
128    data,
129    field_names,
130  })))
131}
132
133// Set
134// ----------------------------------------------------------------------------
135
136// Define a MechFunction that creaates a Set from a list of Values
137#[cfg(feature = "set")]
138#[derive(Debug)]
139pub struct ValueSet {
140  pub out: Ref<MechSet>,
141}
142#[cfg(feature = "set")]
143#[cfg(feature = "functions")]
144impl MechFunctionImpl for ValueSet {
145  fn solve(&self) {}
146  fn out(&self) -> Value { Value::Set(self.out.clone()) }
147  fn to_string(&self) -> String { format!("{:#?}", self) }
148}
149#[cfg(feature = "set")]
150#[cfg(feature = "functions")]
151impl MechFunctionFactory for ValueSet {
152  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
153    match args {
154      FunctionArgs::Nullary(out) => {
155        let out: Ref<MechSet> = unsafe{ out.as_unchecked().clone() };
156        Ok(Box::new(ValueSet {out}))
157      },
158      _ => Err(MechError2::new(
159          IncorrectNumberOfArguments { expected: 0, found: args.len() },
160          None
161        ).with_compiler_loc()
162      ),
163    }
164  }
165}
166#[cfg(feature = "set")]
167#[cfg(feature = "compiler")]
168impl MechFunctionCompiler for ValueSet {
169  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
170    compile_nullop!("set/define", self.out, ctx, FeatureFlag::Builtin(FeatureKind::Set));
171  }
172}
173#[cfg(feature = "set")]
174#[cfg(feature = "functions")]
175register_descriptor!{
176  FunctionDescriptor {
177    name: "set/define",
178    ptr: ValueSet::new,
179  }
180}
181
182#[cfg(feature = "set")]
183pub struct SetDefine {}
184#[cfg(feature = "set")]
185#[cfg(feature = "functions")]
186impl NativeFunctionCompiler for SetDefine {
187  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
188    Ok(Box::new(ValueSet {
189      out: Ref::new(MechSet::from_vec(arguments.clone())),
190    }))
191  }
192}
193#[cfg(feature = "set")]
194#[cfg(feature = "functions")]
195register_descriptor!{
196  FunctionCompilerDescriptor {
197    name: "set/define",
198    ptr: &SetDefine{},
199  }
200}
201
202#[cfg(feature = "set")]
203pub fn set(m: &Set, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> { 
204  let mut elements = Vec::new();
205  for el in &m.elements {
206    let result = expression(el, env, p)?;
207    elements.push(result.clone());
208  }
209  let element_kind = if elements.len() > 0 {
210    elements[0].kind()
211  } else {
212    ValueKind::Empty
213  };
214  // Make sure all elements have the same kind
215  for el in &elements {
216    if el.kind() != element_kind {
217      return Err(MechError2::new(
218        SetKindMismatchError{expected_kind: element_kind.clone(), actual_kind: el.kind().clone()},
219        None
220      ).with_compiler_loc());
221    }
222  }
223  #[cfg(feature = "functions")]
224  {
225    let new_fxn = SetDefine {}.compile(&elements)?;
226    new_fxn.solve();
227    let out = new_fxn.out();
228    let plan = p.plan();
229    let mut plan_brrw = plan.borrow_mut();
230    plan_brrw.push(new_fxn);
231    Ok(out)
232  }
233  #[cfg(not(feature = "functions"))]
234  {
235    Ok(Value::Set(Ref::new(MechSet::from_vec(elements))))
236  }
237}
238
239// Table
240// ----------------------------------------------------------------------------
241
242macro_rules! handle_value_kind {
243  ($value_kind:ident, $val:expr, $field_label:expr, $data_map:expr, $converter:ident) => {{
244    let mut vals = Vec::new();
245    let id = $field_label; // <- FIXED: it's already a u64
246    for x in $val.as_vec().iter() {
247      match x.$converter() {
248        Ok(u) => vals.push(u.to_value()),
249        Err(_) => {
250          return Err(MechError2::new(
251            TableColumnKindMismatchError { 
252              column_id: id, 
253              expected_kind: $value_kind.clone(), 
254              actual_kind: x.kind() 
255            },
256            None
257          ).with_compiler_loc());
258        }
259      }
260    }
261    $data_map.insert(id, ($value_kind.clone(), Value::to_matrixd(vals.clone(), vals.len(), 1)));
262  }};
263}
264
265
266#[cfg(feature = "table")]
267fn handle_column_kind(
268    kind: ValueKind,
269    id: u64,
270    val: Matrix<Value>,
271    data_map: &mut IndexMap<u64,(ValueKind,Matrix<Value>)>
272) -> MResult<()> 
273{
274  match kind {
275    #[cfg(feature = "i8")]
276    ValueKind::I8   => handle_value_kind!(kind, val, id, data_map, as_i8),
277    #[cfg(feature = "i16")]
278    ValueKind::I16  => handle_value_kind!(kind, val, id, data_map, as_i16),
279    #[cfg(feature = "i32")]
280    ValueKind::I32  => handle_value_kind!(kind, val, id, data_map, as_i32),
281    #[cfg(feature = "i64")]
282    ValueKind::I64  => handle_value_kind!(kind, val, id, data_map, as_i64),
283    #[cfg(feature = "i128")]
284    ValueKind::I128 => handle_value_kind!(kind, val, id, data_map, as_i128),
285
286    #[cfg(feature = "u8")]
287    ValueKind::U8   => handle_value_kind!(kind, val, id, data_map, as_u8),
288    #[cfg(feature = "u16")]
289    ValueKind::U16  => handle_value_kind!(kind, val, id, data_map, as_u16),
290    #[cfg(feature = "u32")]
291    ValueKind::U32  => handle_value_kind!(kind, val, id, data_map, as_u32),
292    #[cfg(feature = "u64")]
293    ValueKind::U64  => handle_value_kind!(kind, val, id, data_map, as_u64),
294    #[cfg(feature = "u128")]
295    ValueKind::U128 => handle_value_kind!(kind, val, id, data_map, as_u128),
296
297    #[cfg(feature = "f32")]
298    ValueKind::F32  => handle_value_kind!(kind, val, id, data_map, as_f32),
299    #[cfg(feature = "f64")]
300    ValueKind::F64  => handle_value_kind!(kind, val, id, data_map, as_f64),
301
302    #[cfg(feature = "string")]
303    ValueKind::String => handle_value_kind!(kind, val, id, data_map, as_string),
304
305    #[cfg(feature = "complex")]
306    ValueKind::C64 => handle_value_kind!(kind, val, id, data_map, as_c64),
307
308    #[cfg(feature = "rational")]
309    ValueKind::R64 => handle_value_kind!(kind, val, id, data_map, as_r64),
310
311    #[cfg(feature = "bool")]
312    ValueKind::Bool => {
313      let vals: Vec<Value> = val.as_vec()
314          .iter()
315          .map(|x| x.as_bool().unwrap().to_value())
316          .collect();
317      data_map.insert(id, (ValueKind::Bool, Value::to_matrix(vals.clone(), vals.len(), 1)));
318    }
319    ValueKind::Any => {
320      let vals: Vec<Value> = val.as_vec()
321          .iter()
322          .map(|x| x.clone())
323          .collect();
324      data_map.insert(id, (ValueKind::Any, Value::to_matrix(vals.clone(), vals.len(), 1)));
325    }
326
327    x => {
328      println!("Unsupported kind in table column: {:?}", x);
329      todo!()
330    }
331  }
332
333  Ok(())
334}
335
336#[cfg(feature = "table")]
337pub fn table(t: &Table, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> { 
338  let mut rows = vec![];
339  let headings = table_header(&t.header, env, p)?;
340  let mut cols = 0;
341
342  // Interpret rows
343  for row in &t.rows {
344    let result = table_row(row, env, p)?;
345    cols = result.len();
346    rows.push(result);
347  }
348
349  // Allocate columns
350  let mut data = vec![Vec::<Value>::new(); cols];
351
352  // Populate columns
353  for row in rows {
354    for (ix, el) in row.into_iter().enumerate() {
355      data[ix].push(el);
356    }
357  }
358
359  // Build table
360  let mut data_map: IndexMap<u64,(ValueKind,Matrix<Value>)> = IndexMap::new();
361
362  for ((id, knd, _name), column) in headings.iter().zip(data.iter()) {
363    let id_u64 = id.as_u64().unwrap().borrow().clone();
364
365    // Infer kind if None
366    let actual_kind = match knd {
367      ValueKind::None => {
368        match column.first() {
369          Some(v) => v.kind(),
370          None => ValueKind::String, // default for empty column
371        }
372      }
373      _ => knd.clone(),
374    };
375
376    // Convert column to matrix
377    let val = Value::to_matrix(column.clone(), column.len(), 1);
378
379    // Dispatch conversion
380    handle_column_kind(actual_kind, id_u64, val, &mut data_map)?;
381  }
382
383  // Assign names
384  let names: HashMap<u64, String> = headings.iter()
385      .map(|(id, _, name)| (id.as_u64().unwrap().borrow().clone(), name.to_string()))
386      .collect();
387
388  let tbl = MechTable::new(t.rows.len(), cols, data_map.clone(), names);
389  Ok(Value::Table(Ref::new(tbl)))
390}
391
392#[cfg(feature = "kind_annotation")]
393pub fn table_header(fields: &TableHeader, env: Option<&Environment>, p: &Interpreter) -> MResult<Vec<(Value,ValueKind,Identifier)>> {
394  let mut headings: Vec<(Value,ValueKind,Identifier)> = Vec::new();
395  for f in &fields.0 {
396    let id = f.name.hash();
397    let kind = match &f.kind {
398      Some(k) => kind_annotation(&k.kind, p)?,
399      None => Kind::None,
400    };
401    headings.push((Value::Id(id),kind.to_value_kind(&p.state.borrow().kinds)?,f.name.clone()));
402  }
403  Ok(headings)
404}
405
406pub fn table_row(r: &TableRow, env: Option<&Environment>, p: &Interpreter) -> MResult<Vec<Value>> {
407  let mut row: Vec<Value> = Vec::new();
408  for col in &r.columns {
409    let result = table_column(col, env, p)?;
410    row.push(result);
411  }
412  Ok(row)
413}
414
415pub fn table_column(r: &TableColumn, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> { 
416  expression(&r.element, env, p)
417}
418
419// Matrix
420// ----------------------------------------------------------------------------
421
422#[cfg(feature = "matrix")]
423pub fn matrix(m: &Mat, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
424  let plan = p.plan();
425  let mut shape = vec![0, 0];
426  let mut col: Vec<Value> = Vec::new();
427  let mut kind = ValueKind::Empty;
428  #[cfg(feature = "matrix_horzcat")]
429  {
430    for row in &m.rows {
431      let result = matrix_row(row, env, p)?;
432      if shape == vec![0,0] {
433        shape = result.shape();
434        kind = result.kind();
435        col.push(result);
436      } else if shape[1] == result.shape()[1] {
437        col.push(result);
438      } else {
439        return Err(MechError2::new(
440            DimensionMismatch { dims: vec![shape[1], result.shape()[1]] },
441            None
442          ).with_compiler_loc()
443        );
444      }
445    }
446    if col.is_empty() {
447      return Ok(Value::MatrixValue(Matrix::from_vec(vec![], 0, 0)));
448    } else if col.len() == 1 {
449      return Ok(col[0].clone());
450    }
451  }
452  #[cfg(feature = "matrix_vertcat")]
453  {
454    let new_fxn = MatrixVertCat{}.compile(&col)?;
455    new_fxn.solve();
456    let out = new_fxn.out();
457    let mut plan_brrw = plan.borrow_mut();
458    plan_brrw.push(new_fxn);
459    return Ok(out);
460  }
461  return Err(MechError2::new(
462    FeatureNotEnabledError,
463    Some("matrix/vertcat feature not enabled".to_string())).with_compiler_loc()
464  );
465}
466
467#[cfg(feature = "matrix_horzcat")]
468pub fn matrix_row(r: &MatrixRow, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
469  let plan = p.plan();
470  let mut row: Vec<Value> = Vec::new();
471  let mut shape = vec![0, 0];
472  let mut kind = ValueKind::Empty;
473  for col in &r.columns {
474    let result = matrix_column(col, env, p)?;
475    if shape == vec![0,0] {
476      shape = result.shape();
477      kind = result.kind();
478      row.push(result);
479    } else if shape[0] == result.shape()[0] {
480      row.push(result);
481    } else {
482      return Err(MechError2::new(
483          DimensionMismatch { dims: vec![shape[0], result.shape()[0]] },
484          None
485        ).with_compiler_loc()
486      );
487    }
488  }
489  let new_fxn = MatrixHorzCat{}.compile(&row)?;
490  new_fxn.solve();
491  let out = new_fxn.out();
492  let mut plan_brrw = plan.borrow_mut();
493  plan_brrw.push(new_fxn);
494  Ok(out)
495}
496
497pub fn matrix_column(r: &MatrixColumn, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> { 
498  expression(&r.element, env, p)
499}