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