mech_interpreter/
expressions.rs

1use crate::*;
2use std::collections::HashMap;
3
4// Expressions
5// ----------------------------------------------------------------------------
6
7pub type Environment = HashMap<u64, Value>;
8
9pub fn expression(expr: &Expression, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
10  match &expr {
11    #[cfg(feature = "variables")]
12    Expression::Var(v) => var(v, env, p),
13    #[cfg(feature = "range")]
14    Expression::Range(rng) => range(&rng, env, p),
15    #[cfg(all(feature = "subscript_slice", feature = "access"))]
16    Expression::Slice(slc) => slice(&slc, env, p),
17    #[cfg(feature = "formulas")]
18    Expression::Formula(fctr) => factor(fctr, env, p),
19    Expression::Structure(strct) => structure(strct, env, p),
20    Expression::Literal(ltrl) => literal(&ltrl, p),
21    #[cfg(feature = "functions")]
22    Expression::FunctionCall(fxn_call) => function_call(fxn_call, p),
23    #[cfg(feature = "set_comprehensions")]
24    Expression::SetComprehension(set_comp) => set_comprehension(set_comp, p),
25    //Expression::FsmPipe(_) => todo!(),
26    x => Err(MechError2::new(
27      FeatureNotEnabledError,
28      None
29    ).with_compiler_loc().with_tokens(x.tokens())),
30  }
31}
32
33pub fn pattern_match_value(pattern: &Pattern, value: &Value, env: &mut Environment) -> MResult<()> {
34  match pattern {
35    Pattern::Wildcard => Ok(()),
36    Pattern::Expression(expr) => match expr {
37      Expression::Var(var) => {
38        let id = &var.name.hash();
39        match env.get(id) {
40          Some(existing) if existing == value => Ok(()),
41          Some(existing) => {
42            Err(MechError2::new(
43                PatternMatchError {
44                    var: var.name.to_string(),
45                    expected: existing.to_string(),
46                    found: value.to_string(),
47                },
48                None
49            ).with_compiler_loc())
50          }
51          None => {
52            env.insert(id.clone(), value.clone());
53            Ok(())
54          }
55        }
56      },
57      _ => todo!("Unsupported expression in pattern"),
58    },
59    #[cfg(feature = "tuple")]
60    Pattern::Tuple(pat_tuple) => {
61      match value {
62        Value::Tuple(values) => {
63          let values_brrw = values.borrow();
64          if pat_tuple.0.len() != values_brrw.elements.len() {
65            return Err(MechError2::new(
66              ArityMismatchError{
67                expected: pat_tuple.0.len(),
68                found: values_brrw.elements.len(),
69              },
70              None
71            ).with_compiler_loc());
72          }
73          for (pttrn, val) in pat_tuple.0.iter().zip(values_brrw.elements.iter()) {
74            pattern_match_value(pttrn, val, env)?;
75          }
76          Ok(())
77        }
78        _ => Err(MechError2::new(
79          PatternExpectedTupleError{
80            found: value.kind(),
81          },
82          None
83        ).with_compiler_loc()),
84      }
85    },
86    Pattern::TupleStruct(pat_struct) => {
87      todo!("Implement tuple struct pattern matching")
88    },
89    _ => {
90      Err(MechError2::new(
91        FeatureNotEnabledError,
92        None
93      ).with_compiler_loc())
94    } 
95  }
96}
97
98#[cfg(feature = "set_comprehensions")]
99pub fn set_comprehension(set_comp: &SetComprehension,p: &Interpreter) -> MResult<Value> {
100  let mut envs: Vec<Environment> = vec![HashMap::new()];
101  let comprehension_id = hash_str(&format!("{:?}", set_comp));
102  let mut new_p = p.clone();
103  new_p.id = comprehension_id;
104  new_p.clear_plan();
105  // Process each qualifier in order
106  for qual in &set_comp.qualifiers {
107    envs = match qual {
108      ComprehensionQualifier::Generator((pttrn, expr)) => {
109        let mut new_envs = Vec::new();
110        for env in &envs {
111          // Evaluate the generator expression
112          let collection = expression(expr, Some(env), &new_p)?;
113          match collection {
114            Value::Set(mset) => {
115              let set_brrw = mset.borrow();
116
117              for elmnt in set_brrw.set.iter() {
118                let mut new_env = env.clone();
119
120                // Try to match the element with the pattern
121                if pattern_match_value(pttrn, elmnt, &mut new_env).is_ok() {
122                  new_envs.push(new_env);
123                }
124                // If match fails, skip this element
125              }
126            }
127            Value::MutableReference(ref_set) => {
128              let ref_set_brrw = ref_set.borrow();
129              match &*ref_set_brrw {
130                Value::Set(mset) => {
131                  let set_brrw = mset.borrow();
132
133                  for elmnt in set_brrw.set.iter() {
134                    let mut new_env = env.clone();
135
136                    // Try to match the element with the pattern
137                    if pattern_match_value(pttrn, elmnt, &mut new_env).is_ok() {
138                      new_envs.push(new_env);
139                    }
140                    // If match fails, skip this element
141                  }
142                }
143                x => return Err(MechError2::new(
144                  SetComprehensionGeneratorError{
145                    found: x.kind(),
146                  },
147                  None
148                ).with_compiler_loc()),
149              }
150            }
151            x => return Err(MechError2::new(
152              SetComprehensionGeneratorError{
153                found: x.kind(),
154              },
155              None
156            ).with_compiler_loc()),
157          }
158        }
159        new_envs
160      }
161      ComprehensionQualifier::Filter(expr) => {
162        // Keep only environments where the filter evaluates to true
163        envs
164          .into_iter()
165          .filter(|env| {
166            let result = expression(expr, Some(env), &new_p);
167            match result {
168              Ok(Value::Bool(v)) => v.borrow().clone(),
169              Ok(x) => {
170                false
171              }
172              Err(_) => false,
173            }
174          })
175          .collect()
176      }
177      ComprehensionQualifier::Let(var_def) => {
178        envs.into_iter()
179            .map(|mut env| -> MResult<_> {
180                let val = expression(&var_def.expression, Some(&env), &new_p)?;
181                env.insert(var_def.var.name.hash(), val);
182                Ok(env)
183            })
184            .collect::<MResult<Vec<_>>>()?
185      }
186    };
187  }
188  // Step 3: evaluate the LHS expression in each environment
189  let mut result_set = IndexSet::new();
190  for env in envs {
191    let val = expression(&set_comp.expression, Some(&env), &new_p)?;
192    if !result_set.contains(&val) {
193      result_set.insert(val);
194    }
195  }
196  Ok(Value::Set(Ref::new(MechSet::from_set(result_set))))
197}
198
199
200#[cfg(feature = "range")]
201pub fn range(rng: &RangeExpression, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
202  let plan = p.plan();
203  let start = factor(&rng.start, env, p)?;
204  let terminal = factor(&rng.terminal, env, p)?;
205  let new_fxn = match &rng.operator {
206    #[cfg(feature = "range_exclusive")]
207    RangeOp::Exclusive => RangeExclusive{}.compile(&vec![start,terminal])?,
208    #[cfg(feature = "range_inclusive")]
209    RangeOp::Inclusive => RangeInclusive{}.compile(&vec![start,terminal])?,
210    x => unreachable!(),
211  };
212  let mut plan_brrw = plan.borrow_mut();
213  plan_brrw.push(new_fxn);
214  let step = plan_brrw.last().unwrap();
215  step.solve();
216  let res = step.out();
217  Ok(res)
218}
219
220#[cfg(all(feature = "subscript_slice", feature = "access"))]
221pub fn slice(slc: &Slice, env: Option<&Environment>,p: &Interpreter) -> MResult<Value> {
222  let id = slc.name.hash();
223  let val: Value = if let Some(env) = env {
224    if let Some(val) = env.get(&id) {
225      val.clone()
226    } else {
227      // fallback to global symbols
228      match p.symbols().borrow().get(id) {
229        Some(val) => Value::MutableReference(val.clone()),
230        None => {
231          return Err(MechError2::new(
232            UndefinedVariableError { id },
233            None,
234          )
235          .with_compiler_loc()
236          .with_tokens(slc.tokens()))
237        }
238      }
239    }
240  } else {
241    match p.symbols().borrow().get(id) {
242      Some(val) => Value::MutableReference(val.clone()),
243      None => {
244        return Err(MechError2::new(
245          UndefinedVariableError { id },
246          None,
247        )
248        .with_compiler_loc()
249        .with_tokens(slc.tokens()))
250      }
251    }
252  };
253  let mut v = val;
254  for s in &slc.subscript {
255    v = subscript(s, &v, env, p)?;
256  }
257  Ok(v)
258}
259
260#[cfg(feature = "subscript_formula")]
261pub fn subscript_formula(sbscrpt: &Subscript, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
262  match sbscrpt {
263    Subscript::Formula(fctr) => {
264      factor(fctr, env, p)
265    }
266    _ => unreachable!()
267  }
268}
269
270#[cfg(feature = "subscript_formula")]
271pub fn subscript_formula_ix(sbscrpt: &Subscript, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
272  match sbscrpt {
273    Subscript::Formula(fctr) => {
274      let result = factor(fctr, env, p)?;
275      result.as_index()
276    }
277    _ => unreachable!()
278  }
279}
280
281#[cfg(feature = "subscript_range")]
282pub fn subscript_range(sbscrpt: &Subscript, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
283  match sbscrpt {
284    Subscript::Range(rng) => {
285      let result = range(rng, env, p)?;
286      match result.as_vecusize() {
287        Ok(v) => Ok(v.to_value()),
288        Err(_) => Err(MechError2::new(
289            InvalidIndexKindError { kind: result.kind() },
290            None
291          ).with_compiler_loc().with_tokens(rng.tokens())
292        ),
293      }
294    }
295    _ => unreachable!()
296  }
297}
298
299#[cfg(all(feature = "subscript", feature = "access"))]
300pub fn subscript(sbscrpt: &Subscript, val: &Value, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
301  let plan = p.plan();
302  match sbscrpt {
303    #[cfg(feature = "table")]
304    Subscript::Dot(x) => {
305      let key = x.hash();
306      let fxn_input: Vec<Value> = vec![val.clone(), Value::Id(key)];
307      let new_fxn = AccessColumn{}.compile(&fxn_input)?;
308      new_fxn.solve();
309      let res = new_fxn.out();
310      plan.borrow_mut().push(new_fxn);
311      return Ok(res);
312    },
313    Subscript::DotInt(x) => {
314      let mut fxn_input = vec![val.clone()];
315      let result = real(&x.clone());
316      fxn_input.push(result.as_index()?);
317      match val.deref_kind() {
318        #[cfg(feature = "matrix")]
319        ValueKind::Matrix(..) => {
320          let new_fxn = MatrixAccessScalar{}.compile(&fxn_input)?;
321          new_fxn.solve();
322          let res = new_fxn.out();
323          plan.borrow_mut().push(new_fxn);
324          return Ok(res);
325        },
326        #[cfg(feature = "tuple")]
327        ValueKind::Tuple(..) => {
328          let new_fxn = TupleAccess{}.compile(&fxn_input)?;
329          new_fxn.solve();
330          let res = new_fxn.out();
331          plan.borrow_mut().push(new_fxn);
332          return Ok(res);
333        },
334        /*ValueKind::Record(_) => {
335          let new_fxn = RecordAccessScalar{}.compile(&fxn_input)?;
336          new_fxn.solve();
337          let res = new_fxn.out();
338          plan.borrow_mut().push(new_fxn);
339          return Ok(res);
340        },*/
341        _ => todo!("Implement access for dot int"),
342      }
343    },
344    #[cfg(feature = "swizzle")]
345    Subscript::Swizzle(x) => {
346      let mut keys = x.iter().map(|x| Value::Id(x.hash())).collect::<Vec<Value>>();
347      let mut fxn_input: Vec<Value> = vec![val.clone()];
348      fxn_input.append(&mut keys);
349      let new_fxn = AccessSwizzle{}.compile(&fxn_input)?;
350      new_fxn.solve();
351      let res = new_fxn.out();
352      plan.borrow_mut().push(new_fxn);
353      return Ok(res);
354    },
355    Subscript::Brace(subs) => {
356      let mut fxn_input = vec![val.clone()];
357      match &subs[..] {
358        #[cfg(feature = "subscript_formula")]
359        [Subscript::Formula(ix)] => {
360          let result = subscript_formula(&subs[0], env, p)?;
361          let shape = result.shape();
362          fxn_input.push(result);
363          match shape[..] {
364            [1, 1] => plan.borrow_mut().push(AccessScalar{}.compile(&fxn_input)?),
365            #[cfg(feature = "subscript_range")]
366            [n,1] => plan.borrow_mut().push(AccessRange{}.compile(&fxn_input)?),
367            #[cfg(feature = "subscript_range")]
368            [1,n] => plan.borrow_mut().push(AccessRange{}.compile(&fxn_input)?),
369            _ => todo!(),
370          }
371        },
372        #[cfg(feature = "subscript_range")]
373        [Subscript::Range(ix)] => {
374          let result = subscript_range(&subs[0], env, p)?;
375          fxn_input.push(result);
376          plan.borrow_mut().push(AccessRange{}.compile(&fxn_input)?);
377        },
378        /*[Subscript::All] => {
379          fxn_input.push(Value::IndexAll);
380          #[cfg(feature = "matrix")]
381          plan.borrow_mut().push(MapAccessAll{}.compile(&fxn_input)?);
382        },*/
383        _ => {
384          todo!("Implement brace subscript")
385        }
386      }
387      let plan_brrw = plan.borrow();
388      let mut new_fxn = &plan_brrw.last().unwrap();
389      new_fxn.solve();
390      let res = new_fxn.out();
391      return Ok(res);
392    }
393    #[cfg(feature = "subscript_slice")]
394    Subscript::Bracket(subs) => {
395      let mut fxn_input = vec![val.clone()];
396      match &subs[..] {
397        #[cfg(feature = "subscript_formula")]
398        [Subscript::Formula(ix)] => {
399          let result = subscript_formula_ix(&subs[0], env, p)?;
400          let shape = result.shape();
401          fxn_input.push(result);
402          match shape[..] {
403            [1,1] => plan.borrow_mut().push(AccessScalar{}.compile(&fxn_input)?),
404            #[cfg(feature = "subscript_range")]
405            [1,n] => plan.borrow_mut().push(AccessRange{}.compile(&fxn_input)?),
406            #[cfg(feature = "subscript_range")]
407            [n,1] => plan.borrow_mut().push(AccessRange{}.compile(&fxn_input)?),
408            _ => todo!(),
409          }
410        },
411        #[cfg(feature = "subscript_range")]
412        [Subscript::Range(ix)] => {
413          let result = subscript_range(&subs[0], env, p)?;
414          fxn_input.push(result);
415          plan.borrow_mut().push(AccessRange{}.compile(&fxn_input)?);
416        },
417        [Subscript::All] => {
418          fxn_input.push(Value::IndexAll);
419          #[cfg(feature = "matrix")]
420          plan.borrow_mut().push(MatrixAccessAll{}.compile(&fxn_input)?);
421        },
422        [Subscript::All,Subscript::All] => todo!(),
423        #[cfg(feature = "subscript_formula")]
424        [Subscript::Formula(ix1),Subscript::Formula(ix2)] => {
425          let result = subscript_formula_ix(&subs[0], env, p)?;
426          let shape1 = result.shape();
427          fxn_input.push(result);
428          let result = subscript_formula_ix(&subs[1], env, p)?;
429          let shape2 = result.shape();
430          fxn_input.push(result);
431          match ((shape1[0],shape1[1]),(shape2[0],shape2[1])) {
432            #[cfg(feature = "matrix")]
433            ((1,1),(1,1)) => plan.borrow_mut().push(MatrixAccessScalarScalar{}.compile(&fxn_input)?),
434            #[cfg(feature = "matrix")]
435            ((1,1),(m,1)) => plan.borrow_mut().push(MatrixAccessScalarRange{}.compile(&fxn_input)?),
436            #[cfg(feature = "matrix")]
437            ((n,1),(1,1)) => plan.borrow_mut().push(MatrixAccessRangeScalar{}.compile(&fxn_input)?),
438            #[cfg(feature = "matrix")]
439            ((n,1),(m,1)) => plan.borrow_mut().push(MatrixAccessRangeRange{}.compile(&fxn_input)?),
440            _ => unreachable!(),
441          }
442        },
443        #[cfg(feature = "subscript_range")]
444        [Subscript::Range(ix1),Subscript::Range(ix2)] => {
445          let result = subscript_range(&subs[0], env, p)?;
446          fxn_input.push(result);
447          let result = subscript_range(&subs[1], env, p)?;
448          fxn_input.push(result);
449          #[cfg(feature = "matrix")]
450          plan.borrow_mut().push(MatrixAccessRangeRange{}.compile(&fxn_input)?);
451        },
452        #[cfg(all(feature = "subscript_range", feature = "subscript_formula"))]
453        [Subscript::All,Subscript::Formula(ix2)] => {
454          fxn_input.push(Value::IndexAll);
455          let result = subscript_formula_ix(&subs[1], env, p)?;
456          let shape = result.shape();
457          fxn_input.push(result);
458          match &shape[..] {
459            #[cfg(feature = "matrix")]
460            [1,1] => plan.borrow_mut().push(MatrixAccessAllScalar{}.compile(&fxn_input)?),
461            #[cfg(feature = "matrix")]
462            [1,n] => plan.borrow_mut().push(MatrixAccessAllRange{}.compile(&fxn_input)?),
463            #[cfg(feature = "matrix")]
464            [n,1] => plan.borrow_mut().push(MatrixAccessAllRange{}.compile(&fxn_input)?),
465            _ => todo!(),
466          }
467        },
468        #[cfg(all(feature = "subscript_range", feature = "subscript_formula"))]
469        [Subscript::Formula(ix1),Subscript::All] => {
470          let result = subscript_formula_ix(&subs[0], env, p)?;
471          let shape = result.shape();
472          fxn_input.push(result);
473          fxn_input.push(Value::IndexAll);
474          match &shape[..] {
475            #[cfg(feature = "matrix")]
476            [1,1] => plan.borrow_mut().push(MatrixAccessScalarAll{}.compile(&fxn_input)?),
477            #[cfg(feature = "matrix")]
478            [1,n] => plan.borrow_mut().push(MatrixAccessRangeAll{}.compile(&fxn_input)?),
479            #[cfg(feature = "matrix")]
480            [n,1] => plan.borrow_mut().push(MatrixAccessRangeAll{}.compile(&fxn_input)?),
481            _ => todo!(),
482          }
483        },
484        #[cfg(all(feature = "subscript_range", feature = "subscript_formula"))]
485        [Subscript::Range(ix1),Subscript::Formula(ix2)] => {
486          let result = subscript_range(&subs[0], env, p)?;
487          fxn_input.push(result);
488          let result = subscript_formula_ix(&subs[1], env, p)?;
489          let shape = result.shape();
490          fxn_input.push(result);
491          match &shape[..] {
492            #[cfg(feature = "matrix")]
493            [1,1] => plan.borrow_mut().push(MatrixAccessRangeScalar{}.compile(&fxn_input)?),
494            #[cfg(feature = "matrix")]
495            [1,n] => plan.borrow_mut().push(MatrixAccessRangeRange{}.compile(&fxn_input)?),
496            #[cfg(feature = "matrix")]
497            [n,1] => plan.borrow_mut().push(MatrixAccessRangeRange{}.compile(&fxn_input)?),
498            _ => todo!(),
499          }
500        },
501        #[cfg(all(feature = "subscript_range", feature = "subscript_formula"))]
502        [Subscript::Formula(ix1),Subscript::Range(ix2)] => {
503          let result = subscript_formula_ix(&subs[0], env, p)?;
504          let shape = result.shape();
505          fxn_input.push(result);
506          let result = subscript_range(&subs[1], env, p)?;
507          fxn_input.push(result);
508          match &shape[..] {
509            #[cfg(feature = "matrix")]
510            [1,1] => plan.borrow_mut().push(MatrixAccessScalarRange{}.compile(&fxn_input)?),
511            #[cfg(feature = "matrix")]
512            [1,n] => plan.borrow_mut().push(MatrixAccessRangeRange{}.compile(&fxn_input)?),
513            #[cfg(feature = "matrix")]
514            [n,1] => plan.borrow_mut().push(MatrixAccessRangeRange{}.compile(&fxn_input)?),
515            _ => todo!(),
516          }
517        },
518        #[cfg(feature = "subscript_range")]
519        [Subscript::All,Subscript::Range(ix2)] => {
520          fxn_input.push(Value::IndexAll);
521          let result = subscript_range(&subs[1], env, p)?;
522          fxn_input.push(result);
523          #[cfg(feature = "matrix")]
524          plan.borrow_mut().push(MatrixAccessAllRange{}.compile(&fxn_input)?);
525        },
526        #[cfg(feature = "subscript_range")]
527        [Subscript::Range(ix1),Subscript::All] => {
528          let result = subscript_range(&subs[0], env, p)?;
529          fxn_input.push(result);
530          fxn_input.push(Value::IndexAll);
531          #[cfg(feature = "matrix")]
532          plan.borrow_mut().push(MatrixAccessRangeAll{}.compile(&fxn_input)?);
533        },
534        _ => unreachable!(),
535      };
536      let plan_brrw = plan.borrow();
537      let mut new_fxn = &plan_brrw.last().unwrap();
538      new_fxn.solve();
539      let res = new_fxn.out();
540      return Ok(res);
541    },
542    _ => unreachable!(),
543  }
544}
545
546#[cfg(feature = "symbol_table")]
547pub fn var(v: &Var, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
548  let state_brrw = p.state.borrow();
549  let symbols_brrw = state_brrw.symbol_table.borrow();
550  let id = v.name.hash();
551  match env {
552    Some(env) => {
553      match env.get(&id) {
554        Some(value) => {
555          return Ok(value.clone())
556        }
557        None => {
558          match symbols_brrw.get(id) {
559            Some(value) => {
560              return Ok(Value::MutableReference(value.clone()))
561            }
562            None => {
563              return Err(MechError2::new(
564                  UndefinedVariableError { id },
565                  None
566                ).with_compiler_loc().with_tokens(v.tokens())
567              )
568            }
569          }
570        }
571      }
572    }
573    None => {
574      match symbols_brrw.get(id) {
575        Some(value) => {
576          return Ok(Value::MutableReference(value.clone()))
577        }
578        None => {
579          return Err(MechError2::new(
580              UndefinedVariableError { id },
581              None
582            ).with_compiler_loc().with_tokens(v.tokens())
583          )
584        }
585      }
586    }
587  }
588}
589
590#[cfg(feature = "formulas")]
591pub fn factor(fctr: &Factor, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
592  match fctr {
593    Factor::Term(trm) => {
594      let result = term(trm, env, p)?;
595      Ok(result)
596    },
597    Factor::Parenthetical(paren) => factor(&*paren, env, p),
598    Factor::Expression(expr) => expression(expr, env, p),
599    #[cfg(feature = "math_neg")]
600    Factor::Negate(neg) => {
601      let value = factor(neg, env, p)?;
602      let new_fxn = MathNegate{}.compile(&vec![value])?;
603      new_fxn.solve();
604      let out = new_fxn.out();
605      p.state.borrow_mut().add_plan_step(new_fxn);
606      Ok(out)
607    },
608    #[cfg(feature = "logic_not")]
609    Factor::Not(neg) => {
610      let value = factor(neg, env, p)?;
611      let new_fxn = LogicNot{}.compile(&vec![value])?;
612      new_fxn.solve();
613      let out = new_fxn.out();
614      p.state.borrow_mut().add_plan_step(new_fxn);
615      Ok(out)
616    },
617    #[cfg(feature = "matrix_transpose")]
618    Factor::Transpose(fctr) => {
619      use mech_matrix::MatrixTranspose;
620      let value = factor(fctr, env, p)?;
621      let new_fxn = MatrixTranspose{}.compile(&vec![value])?;
622      new_fxn.solve();
623      let out = new_fxn.out();
624      p.state.borrow_mut().add_plan_step(new_fxn);
625      Ok(out)
626    }
627    _ => todo!(),
628  }
629}
630
631#[cfg(feature = "formulas")]
632pub fn term(trm: &Term, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
633  let plan = p.plan();
634  let mut lhs = factor(&trm.lhs, env, p)?;
635  let mut term_plan: Vec<Box<dyn MechFunction>> = vec![];
636  for (op,rhs) in &trm.rhs {
637    let rhs = factor(&rhs, env, p)?;
638    let new_fxn: Box<dyn MechFunction> = match op {
639      // Math
640      #[cfg(feature = "math_add")]
641      FormulaOperator::AddSub(AddSubOp::Add) => MathAdd{}.compile(&vec![lhs,rhs])?,
642      #[cfg(feature = "math_sub")]
643      FormulaOperator::AddSub(AddSubOp::Sub) => MathSub{}.compile(&vec![lhs,rhs])?,
644      #[cfg(feature = "math_mul")]
645      FormulaOperator::MulDiv(MulDivOp::Mul) => MathMul{}.compile(&vec![lhs,rhs])?,
646      #[cfg(feature = "math_div")]
647      FormulaOperator::MulDiv(MulDivOp::Div) => MathDiv{}.compile(&vec![lhs,rhs])?,
648      #[cfg(feature = "math_mod")]
649      FormulaOperator::MulDiv(MulDivOp::Mod) => MathMod{}.compile(&vec![lhs,rhs])?,
650      #[cfg(feature = "math_pow")]
651      FormulaOperator::Power(PowerOp::Pow) => MathPow{}.compile(&vec![lhs,rhs])?,
652
653      // Matrix
654      #[cfg(feature = "matrix_matmul")]
655      FormulaOperator::Vec(VecOp::MatMul) => {
656        use mech_matrix::MatrixMatMul;
657        MatrixMatMul{}.compile(&vec![lhs,rhs])?
658      }
659      #[cfg(feature = "matrix_solve")]
660      FormulaOperator::Vec(VecOp::Solve) => MatrixSolve{}.compile(&vec![lhs,rhs])?,
661      #[cfg(feature = "matrix_cross")]
662      FormulaOperator::Vec(VecOp::Cross) => todo!(),
663      #[cfg(feature = "matrix_dot")]
664      FormulaOperator::Vec(VecOp::Dot) => MatrixDot{}.compile(&vec![lhs,rhs])?,
665
666      // Compare
667      #[cfg(feature = "compare_eq")]
668      FormulaOperator::Comparison(ComparisonOp::Equal) => CompareEqual{}.compile(&vec![lhs,rhs])?,
669      #[cfg(feature = "compare_seq")]
670      FormulaOperator::Comparison(ComparisonOp::StrictEqual) => todo!(), //CompareStrictEqual{}.compile(&vec![lhs,rhs])?,
671      #[cfg(feature = "compare_neq")]
672      FormulaOperator::Comparison(ComparisonOp::NotEqual) => CompareNotEqual{}.compile(&vec![lhs,rhs])?,
673      #[cfg(feature = "compare_sneq")]
674      FormulaOperator::Comparison(ComparisonOp::StrictNotEqual) => todo!(), //CompareStrictNotEqual{}.compile(&vec![lhs,rhs])?,
675      #[cfg(feature = "compare_lte")]
676      FormulaOperator::Comparison(ComparisonOp::LessThanEqual) => CompareLessThanEqual{}.compile(&vec![lhs,rhs])?,
677      #[cfg(feature = "compare_gte")]
678      FormulaOperator::Comparison(ComparisonOp::GreaterThanEqual) => CompareGreaterThanEqual{}.compile(&vec![lhs,rhs])?,
679      #[cfg(feature = "compare_lt")]
680      FormulaOperator::Comparison(ComparisonOp::LessThan) => CompareLessThan{}.compile(&vec![lhs,rhs])?,
681      #[cfg(feature = "compare_gt")]
682      FormulaOperator::Comparison(ComparisonOp::GreaterThan) => CompareGreaterThan{}.compile(&vec![lhs,rhs])?,
683
684      // Logic
685      #[cfg(feature = "logic_and")]
686      FormulaOperator::Logic(LogicOp::And) => LogicAnd{}.compile(&vec![lhs,rhs])?,
687      #[cfg(feature = "logic_or")]
688      FormulaOperator::Logic(LogicOp::Or)  => LogicOr{}.compile(&vec![lhs,rhs])?,
689      #[cfg(feature = "logic_not")]
690      FormulaOperator::Logic(LogicOp::Not) => LogicNot{}.compile(&vec![lhs,rhs])?,
691      #[cfg(feature = "logic_xor")]
692      FormulaOperator::Logic(LogicOp::Xor) => LogicXor{}.compile(&vec![lhs,rhs])?,
693      
694      // Table
695      #[cfg(feature = "table_inner_join")]
696      FormulaOperator::Table(TableOp::InnerJoin) => todo!(),
697      #[cfg(feature = "table_left_outer_join")]
698      FormulaOperator::Table(TableOp::LeftOuterJoin) => todo!(),
699      #[cfg(feature = "table_right_outer_join")]
700      FormulaOperator::Table(TableOp::RightOuterJoin) => todo!(),
701      #[cfg(feature = "table_full_outer_join")]
702      FormulaOperator::Table(TableOp::FullOuterJoin) => todo!(),
703      #[cfg(feature = "table_left_semi_join")]
704      FormulaOperator::Table(TableOp::LeftSemiJoin) => todo!(),
705      #[cfg(feature = "table_left_anti_join")]
706      FormulaOperator::Table(TableOp::LeftAntiJoin) => todo!(),
707
708      // Set
709      #[cfg(feature = "set_union")]
710      FormulaOperator::Set(SetOp::Union) => SetUnion{}.compile(&vec![lhs,rhs])?,
711      #[cfg(feature = "set_intersection")]
712      FormulaOperator::Set(SetOp::Intersection) => SetIntersection{}.compile(&vec![lhs,rhs])?,
713      #[cfg(feature = "set_difference")]
714      FormulaOperator::Set(SetOp::Difference) => SetDifference{}.compile(&vec![lhs,rhs])?,
715      #[cfg(feature = "set_symmetric_difference")]
716      FormulaOperator::Set(SetOp::SymmetricDifference) => SetSymmetricDifference{}.compile(&vec![lhs,rhs])?,
717      #[cfg(feature = "set_complement")]
718      FormulaOperator::Set(SetOp::Complement) => todo!(),
719      #[cfg(feature = "set_subset")]
720      FormulaOperator::Set(SetOp::Subset) => SetSubset{}.compile(&vec![lhs,rhs])?,
721      #[cfg(feature = "set_superset")]
722      FormulaOperator::Set(SetOp::Superset) => SetSuperset{}.compile(&vec![lhs,rhs])?,
723      #[cfg(feature = "set_proper_subset")]
724      FormulaOperator::Set(SetOp::ProperSubset) => SetProperSubset{}.compile(&vec![lhs,rhs])?,
725      #[cfg(feature = "set_proper_superset")]
726      FormulaOperator::Set(SetOp::ProperSuperset) => SetProperSuperset{}.compile(&vec![lhs,rhs])?,
727      #[cfg(feature = "set_element_of")]
728      FormulaOperator::Set(SetOp::ElementOf) => SetElementOf{}.compile(&vec![lhs,rhs])?,
729      #[cfg(feature = "set_not_element_of")]
730      FormulaOperator::Set(SetOp::NotElementOf) => SetNotElementOf{}.compile(&vec![lhs,rhs])?,
731      x => return Err(MechError2::new(
732          UnhandledFormulaOperatorError { operator: x.clone() },
733          None
734        ).with_compiler_loc().with_tokens(trm.tokens())
735      ),
736    };
737    new_fxn.solve();
738    let res = new_fxn.out();
739    term_plan.push(new_fxn);
740    lhs = res;
741  }
742  let mut plan_brrw = plan.borrow_mut();
743  plan_brrw.append(&mut term_plan);
744  return Ok(lhs);
745}
746
747#[derive(Debug, Clone)]
748pub struct UnhandledFormulaOperatorError {
749  pub operator: FormulaOperator,
750}
751impl MechErrorKind2 for UnhandledFormulaOperatorError {
752  fn name(&self) -> &str { "UnhandledFormulaOperator" }
753  fn message(&self) -> String {
754    format!("Unhandled formula operator: {:#?}", self.operator)
755  }
756}
757
758#[derive(Debug, Clone)]
759pub struct UndefinedVariableError {
760  pub id: u64, 
761}
762impl MechErrorKind2 for UndefinedVariableError {
763  fn name(&self) -> &str { "UndefinedVariable" }
764
765  fn message(&self) -> String {
766    format!("Undefined variable: {}", self.id)
767  }
768}
769#[derive(Debug, Clone)]
770pub struct InvalidIndexKindError {
771  kind: ValueKind,
772}
773impl MechErrorKind2 for InvalidIndexKindError {
774  fn name(&self) -> &str {
775    "InvalidIndexKind"
776  }
777  fn message(&self) -> String {
778    "Invalid index kind".to_string()
779  }
780}
781
782#[derive(Debug, Clone)]
783pub struct SetComprehensionGeneratorError{
784  found: ValueKind,
785}
786
787impl MechErrorKind2 for SetComprehensionGeneratorError {
788  fn name(&self) -> &str {
789    "SetComprehensionGenerator"
790  }
791  fn message(&self) -> String {
792    format!("Set comprehension generator must produce a set, found kind: {:?}", self.found)
793  }
794}
795
796#[derive(Debug, Clone)]
797pub struct PatternExpectedTupleError{
798  found: ValueKind,
799}
800impl MechErrorKind2 for PatternExpectedTupleError {
801  fn name(&self) -> &str {
802    "PatternExpectedTuple"
803  }
804  fn message(&self) -> String {
805    format!("Pattern expected a tuple, found kind: {:?}", self.found)
806  }
807}
808
809#[derive(Debug, Clone)]
810pub struct ArityMismatchError {
811  expected: usize,
812  found: usize,
813}
814impl MechErrorKind2 for ArityMismatchError {
815  fn name(&self) -> &str {
816    "ArityMismatch"
817  }
818  fn message(&self) -> String {
819    format!("Arity mismatch: expected {}, found {}", self.expected, self.found)
820  }
821}
822
823#[derive(Debug, Clone)]
824pub struct PatternMatchError {
825  pub var: String,
826  pub expected: String,
827  pub found: String,
828}
829
830impl MechErrorKind2 for PatternMatchError {
831  fn name(&self) -> &str {
832    "PatternMatchError"
833  }
834  fn message(&self) -> String {
835    format!(
836      "Pattern match error for variable '{}': expected value {}, found value {}",
837      self.var, self.expected, self.found
838    )
839  }
840}