Skip to main content

mech_interpreter/
statements.rs

1use crate::*;
2use paste::paste;
3
4#[cfg(feature = "variable_define")]
5use crate::stdlib::define::*;
6
7// Statements
8// ----------------------------------------------------------------------------
9
10pub fn statement(stmt: &Statement, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
11  match stmt {
12    #[cfg(feature = "tuple")]
13    Statement::TupleDestructure(tpl_dstrct) => tuple_destructure(&tpl_dstrct, p),
14    #[cfg(feature = "variable_define")]
15    Statement::VariableDefine(var_def) => variable_define(&var_def, p),
16    #[cfg(feature = "variable_assign")]
17    Statement::VariableAssign(var_assgn) => variable_assign(&var_assgn, env, p),
18    #[cfg(feature = "kind_define")]
19    Statement::KindDefine(knd_def) => kind_define(&knd_def, p),
20    #[cfg(feature = "enum")]
21    Statement::EnumDefine(enm_def) => {
22      enum_define(&enm_def, p)?;
23      Ok(Value::Empty)
24    }
25    #[cfg(feature = "math")]
26    Statement::OpAssign(op_assgn) => op_assign(&op_assgn, env, p),
27    #[cfg(feature = "state_machines")]
28    Statement::FsmDeclare(fsm_decl) => fsm_declare(fsm_decl, env, p),
29    //Statement::SplitTable => todo!(),
30    //Statement::FlattenTable => todo!(),
31    x => return Err(MechError::new(
32        FeatureNotEnabledError,
33        None
34      ).with_compiler_loc().with_tokens(x.tokens())
35    ),
36  }
37}
38
39#[cfg(feature = "tuple")]
40pub fn tuple_destructure(tpl_dstrct: &TupleDestructure, p: &Interpreter) -> MResult<Value> {
41  let source = expression(&tpl_dstrct.expression, None, p)?;
42  let tpl = match &source {
43    Value::Tuple(tpl) => tpl,
44    Value::MutableReference(r) => {
45      let r_brrw = r.borrow();
46      &match &*r_brrw {
47        Value::Tuple(tpl) => tpl.clone(),
48        _ => return Err(MechError::new(
49          DestructureExpectedTupleError{ value: source.kind() },
50          None
51        ).with_compiler_loc().with_tokens(tpl_dstrct.expression.tokens())),
52      }
53    },
54    _ => return Err(MechError::new(
55      DestructureExpectedTupleError{ value: source.kind() },
56      None
57    ).with_compiler_loc().with_tokens(tpl_dstrct.expression.tokens())),
58  };
59  let symbols = p.symbols();
60  let mut symbols_brrw = symbols.borrow_mut();
61  for (i, var) in tpl_dstrct.vars.iter().enumerate() {
62    let id = var.hash();
63    if symbols_brrw.contains(id) {
64      return Err(MechError::new(
65        VariableAlreadyDefinedError { id },
66        None
67      ).with_compiler_loc().with_tokens(var.tokens()));
68    }
69    if let Some(element) = tpl.borrow().get(i) {
70      symbols_brrw.insert(id, element.clone(), true);
71      symbols_brrw.dictionary.borrow_mut().insert(id, var.name.to_string());
72    } else {
73      return Err(MechError::new(
74        TupleDestructureTooManyVarsError{ value: source.kind() },
75        None
76      ).with_compiler_loc().with_tokens(var.tokens()));
77    }
78  }
79  Ok(source)
80}
81
82#[cfg(feature = "math")]
83pub fn op_assign(op_assgn: &OpAssign, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
84  let mut source = expression(&op_assgn.expression, env, p)?;
85  let slc = &op_assgn.target;
86  let id = slc.name.hash();
87  let sink = { 
88    let mut state_brrw = p.state.borrow_mut();
89    match state_brrw.get_mutable_symbol(id) {
90      Some(val) => val.borrow().clone(),
91      None => {
92        match state_brrw.contains_symbol(id) {
93          true => return Err(MechError::new(
94            NotMutableError { id },
95            Some("(!)> Mutable variables are defined with the `~` operator. *e.g.*: {{~x := 123}}".to_string()),
96          ).with_compiler_loc().with_tokens(slc.name.tokens())),
97          false => return Err(MechError::new(
98            UndefinedVariableError { id },
99            Some("(!)> Variables are defined with the `:=` operator. *e.g.*: {{x := 123}}".to_string()),
100          ).with_compiler_loc().with_tokens(slc.name.tokens())),
101        }
102      }
103    }
104  };
105  match &slc.subscript {
106    Some(sbscrpt) => {
107      // todo: this only works for the first subscript, it needs to work for multiple subscripts
108      for s in sbscrpt {
109        let fxn = match op_assgn.op {
110          #[cfg(feature = "math_add_assign")]
111          OpAssignOp::Add => add_assign(&s, &sink, &source, env, p)?,
112          #[cfg(feature = "math_sub_assign")]
113          OpAssignOp::Sub => sub_assign(&s, &sink, &source, env, p)?,
114          #[cfg(feature = "math_div_assign")]
115          OpAssignOp::Div => div_assign(&s, &sink, &source, env, p)?,
116          #[cfg(feature = "math_mul_assign")]
117          OpAssignOp::Mul => mul_assign(&s, &sink, &source, env, p)?,
118          _ => todo!(),
119        };
120        return Ok(fxn);
121      }
122    }
123    None => {
124      let args = vec![sink,source];
125      let fxn: Box<dyn MechFunction> = match op_assgn.op {
126        #[cfg(feature = "math_add_assign")]
127        OpAssignOp::Add => AddAssignValue{}.compile(&args)?,
128        #[cfg(feature = "math_sub_assign")]
129        OpAssignOp::Sub => SubAssignValue{}.compile(&args)?,
130        #[cfg(feature = "math_div_assign")]
131        OpAssignOp::Div => DivAssignValue{}.compile(&args)?,
132        #[cfg(feature = "math_mul_assign")]
133        OpAssignOp::Mul => MulAssignValue{}.compile(&args)?,
134        _ => todo!(),
135      };
136      fxn.solve();
137      let res = fxn.out();
138      p.state.borrow_mut().add_plan_step(fxn);
139      return Ok(res);
140    }
141  }
142  unreachable!(); // subscript should have thrown an error if we can't access an element
143}
144
145#[cfg(feature = "variable_assign")]
146pub fn variable_assign(var_assgn: &VariableAssign, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
147  let mut source = expression(&var_assgn.expression, env, p)?;
148  let slc = &var_assgn.target;
149  let id = slc.name.hash();
150  let sink = {
151    let symbols = p.symbols();
152    let symbols_brrw = symbols.borrow();
153    match symbols_brrw.get_mutable(id) {
154      Some(val) => val.borrow().clone(),
155      None => {
156        if !symbols_brrw.contains(id) {
157          return Err(MechError::new(
158            UndefinedVariableError { id },
159            Some("(!)> Variables are defined with the `:=` operator. *e.g.*: {{x := 123}}".to_string()),
160          ).with_compiler_loc().with_tokens(slc.name.tokens()));
161        } else { 
162          return Err(MechError::new(
163            NotMutableError { id },
164            Some("(!)> Mutable variables are defined with the `~` operator. *e.g.*: {{~x := 123}}".to_string()),
165          ).with_compiler_loc().with_tokens(slc.name.tokens()));
166        }
167      }
168    }
169  };
170  match &slc.subscript {
171    Some(sbscrpt) => {
172      #[cfg(feature = "subscript")]
173      for s in sbscrpt {
174        let s_result = subscript_ref(&s, &sink, &source, env, p)?;
175        return Ok(s_result);
176      }
177    }
178    #[cfg(feature = "assign")]
179    None => {
180      let args = vec![sink,source];
181      let fxn = AssignValue{}.compile(&args)?;
182      fxn.solve();
183      let res = fxn.out();
184      p.state.borrow_mut().add_plan_step(fxn);
185      return Ok(res);
186    }
187    _ => return Err(MechError::new(
188      FeatureNotEnabledError,
189      None
190    ).with_compiler_loc().with_tokens(var_assgn.target.tokens())),
191  }
192  unreachable!(); // subscript should have thrown an error if we can't access an element
193}
194
195#[cfg(feature = "enum")]
196pub fn enum_define(enm_def: &EnumDefine, p: &Interpreter) -> MResult<()> {
197  let id = enm_def.name.hash();
198  let mut variants: Vec<(u64, Option<Value>)> = Vec::new();
199  {
200    let mut state_brrw = p.state.borrow_mut();
201    for v in &enm_def.variants {
202      let payload = match &v.value {
203        Some(kind_annotation_node) => {
204          let knd = kind_annotation(&kind_annotation_node.kind, p)?;
205          let vk = knd.to_value_kind(&mut state_brrw.kinds)?;
206          Some(Value::Kind(vk))
207        }
208        None => None,
209      };
210      variants.push((v.name.hash(), payload));
211    }
212  }
213  let state = &p.state;
214  let mut state_brrw = state.borrow_mut();
215  let dictionary = state_brrw.dictionary.clone();
216  {
217    let mut dictionary_brrw = dictionary.borrow_mut();
218    dictionary_brrw.insert(enm_def.name.hash(), enm_def.name.to_string());
219    for variant in &enm_def.variants {
220      dictionary_brrw.insert(variant.name.hash(), variant.name.to_string());
221    }
222  }
223  let enm = MechEnum{id, variants, names: dictionary};
224  let val = Value::Enum(Ref::new(enm.clone()));
225  state_brrw.enums.insert(id, enm.clone());
226  state_brrw.kinds.insert(id, val.kind());
227  Ok(())
228}
229
230#[cfg(feature = "kind_define")]
231pub fn kind_define(knd_def: &KindDefine, p: &Interpreter) -> MResult<Value> {
232  let id = knd_def.name.hash();
233  let kind = kind_annotation(&knd_def.kind.kind, p)?;
234  let value_kind = kind.to_value_kind(&p.state.borrow().kinds)?;
235  let functions = p.functions();
236  let mut kinds = &mut p.state.borrow_mut().kinds;
237  kinds.insert(id, value_kind.clone());
238  Ok(Value::Kind(value_kind))
239}
240
241#[cfg(all(feature = "enum", feature = "atom"))]
242fn value_matches_enum_variant(value: &Value, enum_id: u64, state: &ProgramState) -> bool {
243  let my_enum = match state.enums.get(&enum_id) {
244    Some(enm) => enm,
245    None => return false,
246  };
247  match value {
248    Value::Atom(atom_variant) => {
249      let variant_id = atom_variant.borrow().id();
250      my_enum.variants.iter().any(|(known_variant, payload_kind)| *known_variant == variant_id && payload_kind.is_none())
251    }
252    #[cfg(feature = "tuple")]
253    Value::Tuple(tuple_val) => {
254      let tuple_brrw = tuple_val.borrow();
255      if tuple_brrw.elements.len() != 2 {
256        return false;
257      }
258      let variant_atom = match tuple_brrw.elements[0].as_ref() {
259        Value::Atom(atom) => atom.borrow(),
260        _ => return false,
261      };
262      let variant_id = variant_atom.id();
263      let payload = tuple_brrw.elements[1].as_ref();
264      let (_, declared_payload_kind) = match my_enum.variants.iter().find(|(known_variant, _)| *known_variant == variant_id) {
265        Some(v) => v,
266        None => return false,
267      };
268      match declared_payload_kind {
269        Some(Value::Kind(expected_kind)) => match expected_kind {
270          ValueKind::Enum(inner_enum_id, _) => value_matches_enum_variant(payload, *inner_enum_id, state),
271          _ => {
272            payload.kind() == expected_kind.clone() ||
273            ConvertKind{}.compile(&vec![payload.clone(), Value::Kind(expected_kind.clone())]).is_ok()
274          }
275        },
276        _ => false,
277      }
278    }
279    _ => false,
280  }
281}
282
283#[cfg(feature = "variable_define")]
284pub fn variable_define(var_def: &VariableDefine, p: &Interpreter) -> MResult<Value> {
285  let var_id = var_def.var.name.hash();
286  let var_name = var_def.var.name.to_string();
287  {
288    let symbols = p.symbols();
289    if symbols.borrow().contains(var_id) {
290      return Err(MechError::new(
291        VariableAlreadyDefinedError { id: var_id },
292        None
293      ).with_compiler_loc().with_tokens(var_def.var.name.tokens()));
294    }
295  }
296  let mut result = expression(&var_def.expression, None, p)?;
297  #[cfg(all(feature = "kind_annotation", feature = "convert"))]
298  if let Some(knd_anntn) =  &var_def.var.kind {
299    let knd = kind_annotation(&knd_anntn.kind,p)?;
300    let mut state_brrw = &mut p.state.borrow_mut();
301    let target_knd = knd.to_value_kind(&mut state_brrw.kinds)?;
302    // Do kind checking
303    match (&result, &target_knd) {
304      // Atom is a variant of an enum
305      #[cfg(all(feature = "atom", feature = "enum"))]
306      (Value::Atom(atom_variant), ValueKind::Enum(enum_id, target_enum_variant_name)) => {
307        let atom_name = atom_variant.borrow().name();
308        if !value_matches_enum_variant(&result, *enum_id, &*state_brrw) {
309          return Err(MechError::new(
310            UnableToConvertAtomToEnumVariantError { atom_name: atom_name.clone(), target_enum_variant_name: target_enum_variant_name.clone() },
311            None
312          ).with_compiler_loc().with_tokens(var_def.expression.tokens()));
313        }
314      }
315      #[cfg(all(feature = "tuple", feature = "atom", feature = "enum"))]
316      (Value::Tuple(tuple_val), ValueKind::Enum(enum_id, target_enum_variant_name)) => {
317        let atom_name = format!("{:?}", tuple_val);
318        if !value_matches_enum_variant(&result, *enum_id, &*state_brrw) {
319          return Err(MechError::new(
320            UnableToConvertAtomToEnumVariantError { atom_name, target_enum_variant_name: target_enum_variant_name.clone() },
321            None
322          ).with_compiler_loc().with_tokens(var_def.expression.tokens()));
323        }
324      }
325      // Atoms can't convert into anything else.
326      #[cfg(feature = "atom")]
327      (Value::Atom(given_variant_id), target_kind) => {
328        return Err(MechError::new(
329          UnableToConvertAtomError { atom_id: given_variant_id.borrow().0.0},
330          None
331        ).with_compiler_loc().with_tokens(var_def.expression.tokens()));
332      }
333      #[cfg(feature = "record")]
334      (Value::Record(rec), ref target_kind @ ValueKind::Record(target_rec_knd)) => {
335        let rec_brrw = rec.borrow();
336        let rec_knd = rec_brrw.kind();
337        if &rec_knd != *target_kind {
338          return Err(MechError::new(
339            UnableToConvertRecordError { source_record_kind: rec_knd.clone(), target_record_kind: (*target_kind).clone() },
340            None
341          ).with_compiler_loc().with_tokens(var_def.expression.tokens()));
342        }
343      }
344      #[cfg(feature = "matrix")]
345      (Value::MutableReference(v), ValueKind::Matrix(target_matrix_knd,_)) => {
346        let value = v.borrow().clone();
347        if value.is_matrix() {
348          let convert_fxn = ConvertMatToMat{}.compile(&vec![result.clone(), Value::Kind(target_knd.clone())])?;
349          convert_fxn.solve();
350          let converted_result = convert_fxn.out();
351          state_brrw.add_plan_step(convert_fxn);
352          result = converted_result;
353        } else {
354          let value_kind = value.kind();
355          if value_kind.deref_kind() != target_matrix_knd.as_ref().clone() && value_kind != *target_matrix_knd.clone() {
356            let convert_fxn = ConvertKind{}.compile(&vec![result.clone(), Value::Kind(target_matrix_knd.as_ref().clone())])?;
357            convert_fxn.solve();
358            let converted_result = convert_fxn.out();
359            state_brrw.add_plan_step(convert_fxn);
360            result = converted_result;
361          };
362          let convert_fxn = ConvertScalarToMat{}.compile(&vec![result.clone(), Value::Kind(target_knd.clone())])?;
363          convert_fxn.solve();
364          let converted_result = convert_fxn.out();
365          state_brrw.add_plan_step(convert_fxn);
366          result = converted_result;          
367        }
368      }
369      #[cfg(feature = "matrix")]
370      (value, ValueKind::Matrix(target_matrix_knd,_)) => {
371        if value.is_matrix() {
372          let convert_fxn = ConvertMatToMat{}.compile(&vec![result.clone(), Value::Kind(target_knd.clone())])?;
373          convert_fxn.solve();
374          let converted_result = convert_fxn.out();
375          state_brrw.add_plan_step(convert_fxn);
376          result = converted_result;
377        } else {
378          let value_kind = value.kind();
379          if value_kind.deref_kind() != target_matrix_knd.as_ref().clone() && value_kind != *target_matrix_knd.clone() {
380            let convert_fxn = ConvertKind{}.compile(&vec![result.clone(), Value::Kind(target_matrix_knd.as_ref().clone())])?;
381            convert_fxn.solve();
382            let converted_result = convert_fxn.out();
383            state_brrw.add_plan_step(convert_fxn);
384            result = converted_result;
385          };
386          let convert_fxn = ConvertScalarToMat{}.compile(&vec![result.clone(), Value::Kind(target_knd.clone())])?;
387          convert_fxn.solve();
388          let converted_result = convert_fxn.out();
389          state_brrw.add_plan_step(convert_fxn);
390          result = converted_result;
391        }
392      }
393      // Kind isn't checked
394      x => {
395        let convert_fxn = ConvertKind{}.compile(&vec![result.clone(), Value::Kind(target_knd)])?;
396        convert_fxn.solve();
397        let converted_result = convert_fxn.out();
398        state_brrw.add_plan_step(convert_fxn);
399        result = converted_result;
400      },
401    };
402    let detached_result = detach_variable_value(&result);
403    // Save symbol to interpreter
404    let val_ref = state_brrw.save_symbol(var_id, var_name.clone(), detached_result.clone(), var_def.mutable);
405    // Add variable define step to plan
406    let var_def_fxn = VarDefine{}.compile(&vec![detached_result.clone(), Value::String(Ref::new(var_name.clone())), Value::Bool(Ref::new(var_def.mutable))])?;
407    state_brrw.add_plan_step(var_def_fxn);
408    return Ok(detached_result);
409  } 
410  let mut state_brrw = p.state.borrow_mut();
411  let detached_result = detach_variable_value(&result);
412  // Save symbol to interpreter
413  let val_ref = state_brrw.save_symbol(var_id,var_name.clone(),detached_result.clone(),var_def.mutable);
414  // Add variable define step to plan
415  let var_def_fxn = VarDefine{}.compile(&vec![detached_result.clone(), Value::String(Ref::new(var_name.clone())), Value::Bool(Ref::new(var_def.mutable))])?;
416  state_brrw.add_plan_step(var_def_fxn);
417  return Ok(detached_result);
418}
419
420#[cfg(feature = "state_machines")]
421pub fn fsm_declare(fsm_decl: &FsmDeclare, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
422  let result = crate::state_machines::execute_fsm_pipe(&fsm_decl.pipe, env, p)?;
423  let id = fsm_decl.fsm.name.hash();
424  let name = fsm_decl.fsm.name.to_string();
425  #[cfg(feature = "symbol_table")]
426  {
427    let symbols = p.symbols();
428    let mut symbols_brrw = symbols.borrow_mut();
429    symbols_brrw.insert(id, detach_variable_value(&result), false);
430    symbols_brrw.dictionary.borrow_mut().insert(id, name);
431  }
432  Ok(result)
433}
434
435fn detach_variable_value(value: &Value) -> Value {
436  match value {
437    Value::MutableReference(reference) => detach_variable_value(&reference.borrow()),
438    _ => value.clone(),
439  }
440}
441
442macro_rules! op_assign {
443  ($fxn_name:ident, $op:tt) => {
444    paste!{
445      pub fn $fxn_name(sbscrpt: &Subscript, sink: &Value, source: &Value, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
446        let plan = p.plan();
447        match sbscrpt {
448          Subscript::Dot(x) => {
449            todo!()
450          },
451          Subscript::DotInt(x) => {
452            todo!()
453          },
454          Subscript::Swizzle(x) => {
455            todo!()
456          },
457          Subscript::Bracket(subs) => {
458            let mut fxn_input = vec![sink.clone()];
459            match &subs[..] {
460              [Subscript::Formula(ix)] => {
461                fxn_input.push(source.clone());
462                let ixes = subscript_formula_ix(&subs[0], env, p)?;
463                let shape = ixes.shape();
464                fxn_input.push(ixes);
465                match shape[..] {
466                  [1,1] => plan.borrow_mut().push(MatrixAssignScalar{}.compile(&fxn_input)?),
467                  [1,n] => plan.borrow_mut().push([<$op AssignRange>]{}.compile(&fxn_input)?),
468                  [n,1] => plan.borrow_mut().push([<$op AssignRange>]{}.compile(&fxn_input)?),
469                  _ => todo!(),
470                }
471              },
472              [Subscript::Formula(ix1),Subscript::All] => {
473                fxn_input.push(source.clone());
474                let ix = subscript_formula_ix(&subs[0], env, p)?;
475                let shape = ix.shape();
476                fxn_input.push(ix);
477                fxn_input.push(Value::IndexAll);
478                match shape[..] {
479                  [1,1] => plan.borrow_mut().push(MatrixAssignScalarAll{}.compile(&fxn_input)?),
480                  [1,n] => plan.borrow_mut().push([<$op AssignRangeAll>]{}.compile(&fxn_input)?),
481                  [n,1] => plan.borrow_mut().push([<$op AssignRangeAll>]{}.compile(&fxn_input)?),
482                  _ => todo!(),
483                }
484              },
485              [Subscript::Range(ix)] => {
486                fxn_input.push(source.clone());
487                let ixes = subscript_range(&subs[0], env, p)?;
488                fxn_input.push(ixes);
489                plan.borrow_mut().push([<$op AssignRange>]{}.compile(&fxn_input)?);
490              },
491              [Subscript::Range(ix), Subscript::All] => {
492                fxn_input.push(source.clone());
493                let ixes = subscript_range(&subs[0], env, p)?;
494                fxn_input.push(ixes);
495                fxn_input.push(Value::IndexAll);
496                plan.borrow_mut().push([<$op AssignRangeAll>]{}.compile(&fxn_input)?);
497              },
498              x => todo!("{:?}", x),
499            };
500            let plan_brrw = plan.borrow();
501            let mut new_fxn = &plan_brrw.last().unwrap();
502            new_fxn.solve();
503            let res = new_fxn.out();
504            return Ok(res);
505          },
506          Subscript::Brace(x) => todo!(),
507          x => todo!("{:?}", x),
508        }
509      }
510    }}}
511
512#[cfg(feature = "math_add_assign")]
513op_assign!(add_assign, Add);
514#[cfg(feature = "math_sub_assign")]
515op_assign!(sub_assign, Sub);
516#[cfg(feature = "math_div_assign")]
517op_assign!(mul_assign, Mul);
518#[cfg(feature = "math_mul_assign")]
519op_assign!(div_assign, Div);
520//#[cfg(feature = "math_pow")]
521//op_assign!(pow_assign, Pow);
522
523#[cfg(all(feature = "subscript", feature = "assign"))]
524pub fn subscript_ref(sbscrpt: &Subscript, sink: &Value, source: &Value, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
525  let plan = p.plan();
526  let symbols = p.symbols();
527  let functions = p.functions();
528  match sbscrpt {
529    Subscript::Dot(x) => {
530      let key = x.hash();
531      let fxn_input: Vec<Value> = vec![sink.clone(), source.clone(), Value::Id(key)];
532      let new_fxn = AssignColumn{}.compile(&fxn_input)?;
533      new_fxn.solve();
534      let res = new_fxn.out();
535      plan.borrow_mut().push(new_fxn);
536      return Ok(res);
537    },
538    #[cfg(feature = "tuple")]
539    Subscript::DotInt(x) => {
540      let ix = real(x, p)?.as_index()?;
541      let mut fxn_input: Vec<Value> = vec![sink.clone(), source.clone(), ix.clone()];
542      let new_fxn = TupleAssignScalar{}.compile(&fxn_input)?;
543      new_fxn.solve();
544      let res = new_fxn.out();
545      plan.borrow_mut().push(new_fxn);
546      return Ok(res);
547    },
548    Subscript::Swizzle(x) => {
549      unreachable!()
550    },
551    Subscript::Bracket(subs) => {
552      let mut fxn_input = vec![sink.clone()];
553      match &subs[..] {
554        #[cfg(feature = "subscript_formula")]
555        [Subscript::Formula(ix)] => {
556          fxn_input.push(source.clone());
557          let ixes = subscript_formula_ix(&subs[0], env, p)?;
558          let shape = ixes.shape();
559          fxn_input.push(ixes);
560          match shape[..] {
561            #[cfg(feature = "matrix")]
562            [1,1] => plan.borrow_mut().push(MatrixAssignScalar{}.compile(&fxn_input)?),
563            #[cfg(all(feature = "matrix", feature = "subscript_range", feature = "assign"))]
564            [1,n] => plan.borrow_mut().push(MatrixAssignRange{}.compile(&fxn_input)?),
565            #[cfg(all(feature = "matrix", feature = "subscript_range", feature = "assign"))]
566            [n,1] => plan.borrow_mut().push(MatrixAssignRange{}.compile(&fxn_input)?),
567            _ => todo!(),
568          }
569        },
570        #[cfg(all(feature = "matrix", feature = "subscript_range"))]
571        [Subscript::Range(ix)] => {
572          fxn_input.push(source.clone());
573          let ixes = subscript_range(&subs[0], env, p)?;
574          fxn_input.push(ixes);
575          plan.borrow_mut().push(MatrixAssignRange{}.compile(&fxn_input)?);
576        },
577        #[cfg(all(feature = "matrix", feature = "subscript_range"))]
578        [Subscript::All] => {
579          fxn_input.push(source.clone());
580          fxn_input.push(Value::IndexAll);
581          plan.borrow_mut().push(MatrixAssignAll{}.compile(&fxn_input)?);
582        },
583        [Subscript::All,Subscript::All] => todo!(),
584        #[cfg(feature = "subscript_formula")]
585        [Subscript::Formula(ix1),Subscript::Formula(ix2)] => {
586          fxn_input.push(source.clone());
587          let result1 = subscript_formula_ix(&subs[0], env, p)?;
588          let result2 = subscript_formula_ix(&subs[1], env, p)?;
589          let shape1 = result1.shape();
590          let shape2 = result2.shape();
591          fxn_input.push(result1);
592          fxn_input.push(result2);
593          match ((shape1[0],shape1[1]),(shape2[0],shape2[1])) {
594            #[cfg(feature = "matrix")]
595            ((1,1),(1,1)) => plan.borrow_mut().push(MatrixAssignScalarScalar{}.compile(&fxn_input)?),
596            #[cfg(all(feature = "matrix", feature = "subscript_range"))]
597            ((1,1),(m,1)) => plan.borrow_mut().push(MatrixAssignScalarRange{}.compile(&fxn_input)?),
598            #[cfg(all(feature = "matrix", feature = "subscript_range"))]
599            ((n,1),(1,1)) => plan.borrow_mut().push(MatrixAssignRangeScalar{}.compile(&fxn_input)?),
600            #[cfg(all(feature = "matrix", feature = "subscript_range"))]
601            ((n,1),(m,1)) => plan.borrow_mut().push(MatrixAssignRangeRange{}.compile(&fxn_input)?),
602            _ => unreachable!(),
603          }          
604        },
605        #[cfg(all(feature = "matrix", feature = "subscript_range"))]
606        [Subscript::Range(ix1),Subscript::Range(ix2)] => {
607          fxn_input.push(source.clone());
608          let result = subscript_range(&subs[0], env, p)?;
609          fxn_input.push(result);
610          let result = subscript_range(&subs[1], env, p)?;
611          fxn_input.push(result);
612          plan.borrow_mut().push(MatrixAssignRangeRange{}.compile(&fxn_input)?);
613        },
614        #[cfg(all(feature = "matrix", feature = "subscript_formula"))]
615        [Subscript::All,Subscript::Formula(ix2)] => {
616          fxn_input.push(source.clone());
617          fxn_input.push(Value::IndexAll);
618          let ix = subscript_formula_ix(&subs[1], env, p)?;
619          let shape = ix.shape();
620          fxn_input.push(ix);
621          match shape[..] {
622            #[cfg(feature = "matrix")]
623            [1,1] => plan.borrow_mut().push(MatrixAssignAllScalar{}.compile(&fxn_input)?),
624            #[cfg(feature = "matrix")]
625            [1,n] => plan.borrow_mut().push(MatrixAssignAllRange{}.compile(&fxn_input)?),
626            #[cfg(feature = "matrix")]
627            [n,1] => plan.borrow_mut().push(MatrixAssignAllRange{}.compile(&fxn_input)?),
628            _ => todo!(),
629          }
630        }
631        #[cfg(feature = "subscript_formula")]
632        [Subscript::Formula(ix1),Subscript::All] => {
633          fxn_input.push(source.clone());
634          let ix = subscript_formula_ix(&subs[0], env, p)?;
635          let shape = ix.shape();
636          fxn_input.push(ix);
637          fxn_input.push(Value::IndexAll);
638          match shape[..] {
639            #[cfg(feature = "matrix")]
640            [1,1] => plan.borrow_mut().push(MatrixAssignScalarAll{}.compile(&fxn_input)?),
641            #[cfg(all(feature = "matrix", feature = "subscript_range"))]
642            [1,n] => plan.borrow_mut().push(MatrixAssignRangeAll{}.compile(&fxn_input)?),
643            #[cfg(all(feature = "matrix", feature = "subscript_range"))]
644            [n,1] => plan.borrow_mut().push(MatrixAssignRangeAll{}.compile(&fxn_input)?),
645            _ => todo!(),
646          }
647        },
648        #[cfg(all(feature = "subscript_formula", feature = "subscript_range"))]
649        [Subscript::Range(ix1),Subscript::Formula(ix2)] => {
650          fxn_input.push(source.clone());
651          let result = subscript_range(&subs[0], env, p)?;
652          fxn_input.push(result);
653          let result = subscript_formula_ix(&subs[1], env, p)?;
654          let shape = result.shape();
655          fxn_input.push(result);
656          match &shape[..] {
657            #[cfg(feature = "matrix")]
658            [1,1] => plan.borrow_mut().push(MatrixAssignRangeScalar{}.compile(&fxn_input)?),
659            #[cfg(feature = "matrix")]
660            [1,n] => plan.borrow_mut().push(MatrixAssignRangeRange{}.compile(&fxn_input)?),
661            #[cfg(feature = "matrix")]
662            [n,1] => plan.borrow_mut().push(MatrixAssignRangeRange{}.compile(&fxn_input)?),
663            _ => todo!(),
664          }
665        },
666        #[cfg(all(feature = "subscript_formula", feature = "subscript_range"))]
667        [Subscript::Formula(ix1),Subscript::Range(ix2)] => {
668          fxn_input.push(source.clone());
669          let result = subscript_formula_ix(&subs[0], env, p)?;
670          let shape = result.shape();
671          fxn_input.push(result);
672          let result = subscript_range(&subs[1], env, p)?;
673          fxn_input.push(result);
674          match &shape[..] {
675            #[cfg(feature = "matrix")]
676            [1,1] => plan.borrow_mut().push(MatrixAssignScalarRange{}.compile(&fxn_input)?),
677            #[cfg(feature = "matrix")]
678            [1,n] => plan.borrow_mut().push(MatrixAssignRangeRange{}.compile(&fxn_input)?),
679            #[cfg(feature = "matrix")]
680            [n,1] => plan.borrow_mut().push(MatrixAssignRangeRange{}.compile(&fxn_input)?),
681            _ => todo!(),
682          }
683        },
684        #[cfg(all(feature = "matrix", feature = "subscript_range"))]
685        [Subscript::All,Subscript::Range(ix2)] => {
686          fxn_input.push(source.clone());
687          fxn_input.push(Value::IndexAll);
688          let result = subscript_range(&subs[1], env, p)?;
689          fxn_input.push(result);
690          plan.borrow_mut().push(MatrixAssignAllRange{}.compile(&fxn_input)?);
691        },
692        #[cfg(all(feature = "matrix", feature = "subscript_range"))]
693        [Subscript::Range(ix1),Subscript::All] => {
694          fxn_input.push(source.clone());
695          let result = subscript_range(&subs[0], env, p)?;
696          fxn_input.push(result);
697          fxn_input.push(Value::IndexAll);
698          plan.borrow_mut().push(MatrixAssignRangeAll{}.compile(&fxn_input)?);
699        },
700        _ => unreachable!(),
701      };
702      let plan_brrw = plan.borrow();
703      let mut new_fxn = &plan_brrw.last().unwrap();
704      new_fxn.solve();
705      let res = new_fxn.out();
706      return Ok(res);
707    },
708    Subscript::Brace(subs) => {
709      let mut fxn_input = vec![sink.clone()];
710      match &subs[..] {
711        #[cfg(feature = "subscript_formula")]
712        [Subscript::Formula(ix)] => {
713          fxn_input.push(source.clone());
714          let ixes = subscript_formula(&subs[0], env, p)?;
715          let shape = ixes.shape();
716          fxn_input.push(ixes);
717          match shape[..] {
718            #[cfg(feature = "map")]
719            [1,1] => plan.borrow_mut().push(MapAssignScalar{}.compile(&fxn_input)?),
720            //#[cfg(all(feature = "matrix", feature = "subscript_range", feature = "assign"))]
721            //[1,n] => plan.borrow_mut().push(MatrixAssignRange{}.compile(&fxn_input)?),
722            //#[cfg(all(feature = "matrix", feature = "subscript_range", feature = "assign"))]
723            //[n,1] => plan.borrow_mut().push(MatrixAssignRange{}.compile(&fxn_input)?),
724            _ => todo!(),
725          }
726        },
727        #[cfg(all(feature = "matrix", feature = "subscript_range"))]
728        [Subscript::Range(ix)] => {
729          todo!();
730          //fxn_input.push(source.clone());
731          //let ixes = subscript_range(&subs[0], env, p)?;
732          //fxn_input.push(ixes);
733          //plan.borrow_mut().push(MatrixAssignRange{}.compile(&fxn_input)?);
734        },
735        #[cfg(all(feature = "matrix", feature = "subscript_range"))]
736        [Subscript::All] => {
737          todo!();
738          //fxn_input.push(source.clone());
739          //fxn_input.push(Value::IndexAll);
740          //plan.borrow_mut().push(MatrixAssignAll{}.compile(&fxn_input)?);
741        },
742        _ => unreachable!(),
743      };
744      let plan_brrw = plan.borrow();
745      let mut new_fxn = &plan_brrw.last().unwrap();
746      new_fxn.solve();
747      let res = new_fxn.out();
748      return Ok(res);      
749    }
750    _ => unreachable!(),
751  }
752}
753
754#[derive(Debug, Clone)]
755pub struct UnableToConvertAtomToEnumVariantError {
756  pub atom_name: String,
757  pub target_enum_variant_name: String,
758}
759impl MechErrorKind for UnableToConvertAtomToEnumVariantError {
760  fn name(&self) -> &str {
761    "UnableToConvertAtomToEnumVariant"
762  }
763  fn message(&self) -> String {
764    format!("Unable to convert atom variant `{} to enum <{}>", self.atom_name, self.target_enum_variant_name)
765  }
766}
767
768#[derive(Debug, Clone)]
769pub struct UnableToConvertAtomError {
770  pub atom_id: u64,
771}
772impl MechErrorKind for UnableToConvertAtomError {
773  fn name(&self) -> &str {
774    "UnableToConvertAtom"
775  }
776  fn message(&self) -> String {
777    format!("Unable to atom  {}", self.atom_id)
778  }
779}
780
781#[derive(Debug, Clone)]
782pub struct VariableAlreadyDefinedError {
783  pub id: u64,
784}
785impl MechErrorKind for VariableAlreadyDefinedError {
786  fn name(&self) -> &str { "VariableAlreadyDefined" }
787  fn message(&self) -> String {
788    format!("Variable already defined: {}", self.id)
789  }
790}
791
792#[derive(Debug, Clone)]
793pub struct UndefinedVariableError {
794  pub id: u64,
795}
796impl MechErrorKind for UndefinedVariableError {
797  fn name(&self) -> &str { "UndefinedVariable" }
798
799  fn message(&self) -> String {
800    format!("Undefined variable: {}", self.id)
801  }
802}
803
804#[derive(Debug, Clone)]
805pub struct NotMutableError {
806  pub id: u64,
807}
808impl MechErrorKind for NotMutableError {
809  fn name(&self) -> &str { "NotMutable" }
810  fn message(&self) -> String {
811    format!("Variable is not mutable: {}", self.id)
812  }
813}
814
815#[cfg(feature = "record")]
816#[derive(Debug, Clone)]
817pub struct UnableToConvertRecordError {
818  pub source_record_kind: ValueKind,
819  pub target_record_kind: ValueKind,
820}
821#[cfg(feature = "record")]
822impl MechErrorKind for UnableToConvertRecordError {
823  fn name(&self) -> &str {
824    "UnableToConvertRecord"
825  }
826  fn message(&self) -> String {
827    format!("Unable to convert record of kind `{:?}` to record of kind `{:?}`", self.source_record_kind, self.target_record_kind)
828  }
829}
830