Skip to main content

mech_interpreter/
expressions.rs

1use crate::*;
2use std::collections::HashMap;
3#[cfg(feature = "enum")]
4use std::collections::HashSet;
5
6// Expressions
7// ----------------------------------------------------------------------------
8
9pub type Environment = HashMap<u64, Value>;
10
11pub fn expression(expr: &Expression, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
12    match &expr {
13        #[cfg(feature = "variables")]
14        Expression::Var(v) => var(v, env, p),
15        #[cfg(feature = "range")]
16        Expression::Range(rng) => range(&rng, env, p),
17        #[cfg(all(feature = "subscript_slice", feature = "access"))]
18        Expression::Slice(slc) => slice(&slc, env, p),
19        #[cfg(feature = "formulas")]
20        Expression::Formula(fctr) => factor(fctr, env, p),
21        Expression::Structure(strct) => structure(strct, env, p),
22        Expression::Literal(ltrl) => literal(&ltrl, p),
23        #[cfg(feature = "functions")]
24        Expression::FunctionCall(fxn_call) => function_call(fxn_call, env, p),
25        #[cfg(feature = "set_comprehensions")]
26        Expression::SetComprehension(set_comp) => set_comprehension(set_comp, p),
27        #[cfg(feature = "matrix_comprehensions")]
28        Expression::MatrixComprehension(matrix_comp) => matrix_comprehension(matrix_comp, p),
29        Expression::Match(match_expr) => match_expression(match_expr, env, p),
30        #[cfg(feature = "state_machines")]
31        Expression::FsmPipe(fsm_pipe) => crate::state_machines::execute_fsm_pipe(fsm_pipe, env, p),
32        x => Err(MechError::new(FeatureNotEnabledError, None)
33            .with_compiler_loc()
34            .with_tokens(x.tokens())),
35    }
36}
37
38#[cfg(any(feature = "set_comprehensions", feature = "matrix_comprehensions"))]
39pub fn pattern_match_value(pattern: &Pattern, value: &Value, env: &mut Environment) -> MResult<()> {
40    match pattern {
41        Pattern::Wildcard => Ok(()),
42        Pattern::Expression(expr) => match expr {
43            Expression::Var(var) => {
44                let id = &var.name.hash();
45                match env.get(id) {
46                    Some(existing) if existing == value => Ok(()),
47                    Some(existing) => Err(MechError::new(
48                        PatternMatchError {
49                            var: var.name.to_string(),
50                            expected: existing.to_string(),
51                            found: value.to_string(),
52                        },
53                        None,
54                    )
55                    .with_compiler_loc()),
56                    None => {
57                        env.insert(id.clone(), value.clone());
58                        Ok(())
59                    }
60                }
61            }
62            _ => todo!("Unsupported expression in pattern"),
63        },
64        #[cfg(feature = "tuple")]
65        Pattern::Tuple(pat_tuple) => match value {
66            Value::Tuple(values) => {
67                let values_brrw = values.borrow();
68                if pat_tuple.0.len() != values_brrw.elements.len() {
69                    return Err(MechError::new(
70                        ArityMismatchError {
71                            expected: pat_tuple.0.len(),
72                            found: values_brrw.elements.len(),
73                        },
74                        None,
75                    )
76                    .with_compiler_loc());
77                }
78                for (pttrn, val) in pat_tuple.0.iter().zip(values_brrw.elements.iter()) {
79                    pattern_match_value(pttrn, val, env)?;
80                }
81                Ok(())
82            }
83            _ => Err(MechError::new(
84                PatternExpectedTupleError {
85                    found: value.kind(),
86                },
87                None,
88            )
89            .with_compiler_loc()),
90        },
91        Pattern::TupleStruct(pat_struct) => {
92            todo!("Implement tuple struct pattern matching")
93        }
94        _ => Err(MechError::new(FeatureNotEnabledError, None).with_compiler_loc()),
95    }
96}
97
98#[cfg(any(feature = "set_comprehensions", feature = "matrix_comprehensions"))]
99fn comprehension_environments(
100    qualifiers: &[ComprehensionQualifier],
101    comprehension_id: u64,
102    p: &Interpreter,
103) -> MResult<(Vec<Environment>, Interpreter)> {
104    let mut envs: Vec<Environment> = vec![HashMap::new()];
105    let mut new_p = p.clone();
106    new_p.id = comprehension_id;
107    new_p.clear_plan();
108    for qual in qualifiers {
109        envs = match qual {
110            ComprehensionQualifier::Generator((pttrn, expr)) => {
111                let mut new_envs = Vec::new();
112                for env in &envs {
113                    let collection = expression(expr, Some(env), &new_p)?;
114                    for elmnt in comprehension_generator_values(&collection)? {
115                        let mut new_env = env.clone();
116                        if pattern_match_value(pttrn, &elmnt, &mut new_env).is_ok() {
117                            new_envs.push(new_env);
118                        }
119                    }
120                }
121                new_envs
122            }
123            ComprehensionQualifier::Filter(expr) => envs
124                .into_iter()
125                .filter(|env| {
126                    let result = expression(expr, Some(env), &new_p);
127                    match result {
128                        Ok(Value::Bool(v)) => v.borrow().clone(),
129                        Ok(_) => false,
130                        Err(_) => false,
131                    }
132                })
133                .collect(),
134            ComprehensionQualifier::Let(var_def) => envs
135                .into_iter()
136                .map(|mut env| -> MResult<_> {
137                    let val = expression(&var_def.expression, Some(&env), &new_p)?;
138                    env.insert(var_def.var.name.hash(), val);
139                    Ok(env)
140                })
141                .collect::<MResult<Vec<_>>>()?,
142        };
143    }
144    Ok((envs, new_p))
145}
146
147#[cfg(any(feature = "set_comprehensions", feature = "matrix_comprehensions"))]
148fn comprehension_generator_values(collection: &Value) -> MResult<Vec<Value>> {
149    match collection {
150        #[cfg(feature = "set")]
151        Value::Set(mset) => Ok(mset.borrow().set.iter().cloned().collect()),
152        #[cfg(feature = "matrix")]
153        Value::MatrixIndex(matrix) => Ok(matrix
154            .as_vec()
155            .into_iter()
156            .map(|value| Value::Index(Ref::new(value)))
157            .collect()),
158        #[cfg(all(feature = "matrix", feature = "bool"))]
159        Value::MatrixBool(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
160        #[cfg(all(feature = "matrix", feature = "u8"))]
161        Value::MatrixU8(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
162        #[cfg(all(feature = "matrix", feature = "u16"))]
163        Value::MatrixU16(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
164        #[cfg(all(feature = "matrix", feature = "u32"))]
165        Value::MatrixU32(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
166        #[cfg(all(feature = "matrix", feature = "u64"))]
167        Value::MatrixU64(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
168        #[cfg(all(feature = "matrix", feature = "u128"))]
169        Value::MatrixU128(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
170        #[cfg(all(feature = "matrix", feature = "i8"))]
171        Value::MatrixI8(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
172        #[cfg(all(feature = "matrix", feature = "i16"))]
173        Value::MatrixI16(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
174        #[cfg(all(feature = "matrix", feature = "i32"))]
175        Value::MatrixI32(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
176        #[cfg(all(feature = "matrix", feature = "i64"))]
177        Value::MatrixI64(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
178        #[cfg(all(feature = "matrix", feature = "i128"))]
179        Value::MatrixI128(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
180        #[cfg(all(feature = "matrix", feature = "f32"))]
181        Value::MatrixF32(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
182        #[cfg(all(feature = "matrix", feature = "f64"))]
183        Value::MatrixF64(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
184        #[cfg(all(feature = "matrix", feature = "string"))]
185        Value::MatrixString(matrix) => Ok(matrix.as_vec().into_iter().map(Value::from).collect()),
186        #[cfg(all(feature = "matrix", feature = "rational"))]
187        Value::MatrixR64(matrix) => Ok(matrix
188            .as_vec()
189            .into_iter()
190            .map(|value| value.to_value())
191            .collect()),
192        #[cfg(all(feature = "matrix", feature = "complex"))]
193        Value::MatrixC64(matrix) => Ok(matrix
194            .as_vec()
195            .into_iter()
196            .map(|value| value.to_value())
197            .collect()),
198        #[cfg(feature = "matrix")]
199        Value::MatrixValue(matrix) => Ok(matrix.as_vec()),
200        Value::MutableReference(reference) => comprehension_generator_values(&reference.borrow()),
201        x => Err(
202            MechError::new(ComprehensionGeneratorError { found: x.kind() }, None)
203                .with_compiler_loc(),
204        ),
205    }
206}
207
208#[cfg(any(feature = "set_comprehensions", feature = "matrix_comprehensions"))]
209fn detach_comprehension_value(value: &Value) -> Value {
210    match value {
211        Value::MutableReference(reference) => reference.borrow().clone(),
212        _ => value.clone(),
213    }
214}
215
216#[cfg(feature = "set_comprehensions")]
217#[derive(Debug)]
218pub struct ValueSetComprehension {
219    pub arguments: Vec<Value>,
220    pub out: Ref<MechSet>,
221}
222#[cfg(all(feature = "set_comprehensions", feature = "functions"))]
223impl MechFunctionImpl for ValueSetComprehension {
224    fn solve(&self) {
225        let args = self
226            .arguments
227            .iter()
228            .map(detach_comprehension_value)
229            .collect::<Vec<Value>>();
230        *self.out.borrow_mut() = MechSet::from_vec(args);
231    }
232    fn out(&self) -> Value {
233        Value::Set(self.out.clone())
234    }
235    fn to_string(&self) -> String {
236        format!("{:#?}", self)
237    }
238}
239#[cfg(all(feature = "set_comprehensions", feature = "functions"))]
240impl MechFunctionFactory for ValueSetComprehension {
241    fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
242        match args {
243            FunctionArgs::Nullary(out) => {
244                let out: Ref<MechSet> = unsafe { out.as_unchecked().clone() };
245                Ok(Box::new(ValueSetComprehension {
246                    arguments: Vec::new(),
247                    out,
248                }))
249            }
250            _ => Err(MechError::new(
251                IncorrectNumberOfArguments {
252                    expected: 0,
253                    found: args.len(),
254                },
255                None,
256            )
257            .with_compiler_loc()),
258        }
259    }
260}
261#[cfg(all(feature = "set_comprehensions", feature = "compiler"))]
262impl MechFunctionCompiler for ValueSetComprehension {
263    fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
264        compile_nullop!(
265            "set/comprehension",
266            self.out,
267            ctx,
268            FeatureFlag::Builtin(FeatureKind::SetComprehensions)
269        );
270    }
271}
272#[cfg(all(feature = "set_comprehensions", feature = "functions"))]
273register_descriptor! {
274  FunctionDescriptor {
275    name: "set/comprehension",
276    ptr: ValueSetComprehension::new,
277  }
278}
279#[cfg(feature = "set_comprehensions")]
280pub struct SetComprehensionDefine {}
281#[cfg(all(feature = "set_comprehensions", feature = "functions"))]
282impl NativeFunctionCompiler for SetComprehensionDefine {
283    fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
284        Ok(Box::new(ValueSetComprehension {
285            arguments: arguments.clone(),
286            out: Ref::new(MechSet::from_vec(arguments.clone())),
287        }))
288    }
289}
290#[cfg(all(feature = "set_comprehensions", feature = "functions"))]
291register_descriptor! {
292  FunctionCompilerDescriptor {
293    name: "set/comprehension",
294    ptr: &SetComprehensionDefine{},
295  }
296}
297
298#[cfg(feature = "matrix_comprehensions")]
299#[derive(Debug)]
300pub struct ValueMatrixComprehension {
301    pub arguments: Vec<Value>,
302    pub out: Ref<Value>,
303}
304#[cfg(all(feature = "matrix_comprehensions", feature = "functions"))]
305impl MechFunctionImpl for ValueMatrixComprehension {
306    fn solve(&self) {
307        let args = self
308            .arguments
309            .iter()
310            .map(detach_comprehension_value)
311            .collect::<Vec<Value>>();
312        let out = if args.is_empty() {
313            Value::MatrixValue(Matrix::from_vec(vec![], 0, 0))
314        } else {
315            let fxn = MatrixHorzCat {}
316                .compile(&args)
317                .expect("matrix/comprehension input kinds changed to incompatible values");
318            fxn.solve();
319            fxn.out()
320        };
321        *self.out.borrow_mut() = out;
322    }
323    fn out(&self) -> Value {
324        self.out.borrow().clone()
325    }
326    fn to_string(&self) -> String {
327        format!("{:#?}", self)
328    }
329}
330#[cfg(all(feature = "matrix_comprehensions", feature = "functions"))]
331impl MechFunctionFactory for ValueMatrixComprehension {
332    fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
333        match args {
334            FunctionArgs::Nullary(out) => Ok(Box::new(ValueMatrixComprehension {
335                arguments: Vec::new(),
336                out: Ref::new(out),
337            })),
338            _ => Err(MechError::new(
339                IncorrectNumberOfArguments {
340                    expected: 0,
341                    found: args.len(),
342                },
343                None,
344            )
345            .with_compiler_loc()),
346        }
347    }
348}
349#[cfg(all(feature = "matrix_comprehensions", feature = "compiler"))]
350impl MechFunctionCompiler for ValueMatrixComprehension {
351    fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
352        compile_nullop!(
353            "matrix/comprehension",
354            self.out,
355            ctx,
356            FeatureFlag::Builtin(FeatureKind::MatrixComprehensions)
357        );
358    }
359}
360#[cfg(all(feature = "matrix_comprehensions", feature = "functions"))]
361register_descriptor! {
362  FunctionDescriptor {
363    name: "matrix/comprehension",
364    ptr: ValueMatrixComprehension::new,
365  }
366}
367#[cfg(feature = "matrix_comprehensions")]
368pub struct MatrixComprehensionDefine {}
369#[cfg(all(feature = "matrix_comprehensions", feature = "functions"))]
370impl NativeFunctionCompiler for MatrixComprehensionDefine {
371    fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
372        let out = if arguments.is_empty() {
373            Value::MatrixValue(Matrix::from_vec(vec![], 0, 0))
374        } else {
375            let fxn = MatrixHorzCat {}.compile(arguments)?;
376            fxn.solve();
377            fxn.out()
378        };
379        Ok(Box::new(ValueMatrixComprehension {
380            arguments: arguments.clone(),
381            out: Ref::new(out),
382        }))
383    }
384}
385#[cfg(all(feature = "matrix_comprehensions", feature = "functions"))]
386register_descriptor! {
387  FunctionCompilerDescriptor {
388    name: "matrix/comprehension",
389    ptr: &MatrixComprehensionDefine{},
390  }
391}
392
393#[cfg(feature = "set_comprehensions")]
394pub fn set_comprehension(set_comp: &SetComprehension, p: &Interpreter) -> MResult<Value> {
395    let comprehension_id = hash_str(&format!("{:?}", set_comp));
396    let (envs, new_p) = comprehension_environments(&set_comp.qualifiers, comprehension_id, p)?;
397    let mut values = Vec::new();
398    for env in envs {
399        let val = expression(&set_comp.expression, Some(&env), &new_p)?;
400        values.push(val);
401    }
402    let functions = p.functions();
403    let set_define_id = hash_str("set/comprehension");
404    let set_define = {
405        functions
406            .borrow()
407            .function_compilers
408            .get(&set_define_id)
409            .copied()
410    };
411    match set_define {
412        Some(compiler) => execute_native_function_compiler(compiler, &values, p),
413        None => Err(MechError::new(
414            MissingFunctionError {
415                function_id: set_define_id,
416            },
417            None,
418        )
419        .with_compiler_loc()),
420    }
421}
422
423#[cfg(feature = "matrix_comprehensions")]
424pub fn matrix_comprehension(matrix_comp: &MatrixComprehension, p: &Interpreter) -> MResult<Value> {
425    let comprehension_id = hash_str(&format!("{:?}", matrix_comp));
426    let (envs, new_p) = comprehension_environments(&matrix_comp.qualifiers, comprehension_id, p)?;
427    let mut values = Vec::new();
428    for env in envs {
429        values.push(expression(&matrix_comp.expression, Some(&env), &new_p)?);
430    }
431    let functions = p.functions();
432    let horzcat_id = hash_str("matrix/comprehension");
433    let horzcat = {
434        functions
435            .borrow()
436            .function_compilers
437            .get(&horzcat_id)
438            .copied()
439    };
440    match horzcat {
441        Some(compiler) => execute_native_function_compiler(compiler, &values, p),
442        None => Err(MechError::new(
443            MissingFunctionError {
444                function_id: horzcat_id,
445            },
446            None,
447        )
448        .with_compiler_loc()),
449    }
450}
451
452#[cfg(feature = "range")]
453pub fn range(rng: &RangeExpression, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
454    let plan = p.plan();
455    let start = factor(&rng.start, env, p)?;
456    let terminal = factor(&rng.terminal, env, p)?;
457    let new_fxn = match &rng.increment {
458        Some((_, inc)) => {
459            let step = factor(inc, env, p)?;
460            match &rng.operator {
461                #[cfg(feature = "range_exclusive")]
462                RangeOp::Exclusive => {
463                    RangeIncrementExclusive {}.compile(&vec![start, step, terminal])?
464                }
465                #[cfg(feature = "range_inclusive")]
466                RangeOp::Inclusive => {
467                    RangeIncrementInclusive {}.compile(&vec![start, step, terminal])?
468                }
469                x => unreachable!(),
470            }
471        }
472        None => match &rng.operator {
473            #[cfg(feature = "range_exclusive")]
474            RangeOp::Exclusive => RangeExclusive {}.compile(&vec![start, terminal])?,
475            #[cfg(feature = "range_inclusive")]
476            RangeOp::Inclusive => RangeInclusive {}.compile(&vec![start, terminal])?,
477            x => unreachable!(),
478        },
479    };
480    let mut plan_brrw = plan.borrow_mut();
481    plan_brrw.push(new_fxn);
482    let step = plan_brrw.last().unwrap();
483    step.solve();
484    let res = step.out();
485    Ok(res)
486}
487
488#[cfg(all(feature = "subscript_slice", feature = "access"))]
489pub fn slice(slc: &Slice, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
490    let id = slc.name.hash();
491    let val: Value = if let Some(env) = env {
492        if let Some(val) = env.get(&id) {
493            val.clone()
494        } else {
495            // fallback to global symbols
496            match p.symbols().borrow().get(id) {
497                Some(val) => Value::MutableReference(val.clone()),
498                None => {
499                    return Err(MechError::new(UndefinedVariableError { id }, None)
500                        .with_compiler_loc()
501                        .with_tokens(slc.tokens()));
502                }
503            }
504        }
505    } else {
506        match p.symbols().borrow().get(id) {
507            Some(val) => Value::MutableReference(val.clone()),
508            None => {
509                return Err(MechError::new(UndefinedVariableError { id }, None)
510                    .with_compiler_loc()
511                    .with_tokens(slc.tokens()));
512            }
513        }
514    };
515    let mut v = val;
516    for s in &slc.subscript {
517        v = subscript(s, &v, env, p)?;
518    }
519    Ok(v)
520}
521
522#[cfg(feature = "subscript_formula")]
523pub fn subscript_formula(
524    sbscrpt: &Subscript,
525    env: Option<&Environment>,
526    p: &Interpreter,
527) -> MResult<Value> {
528    match sbscrpt {
529        Subscript::Formula(fctr) => factor(fctr, env, p),
530        _ => unreachable!(),
531    }
532}
533
534#[cfg(feature = "subscript_formula")]
535pub fn subscript_formula_ix(
536    sbscrpt: &Subscript,
537    env: Option<&Environment>,
538    p: &Interpreter,
539) -> MResult<Value> {
540    match sbscrpt {
541        Subscript::Formula(fctr) => {
542            let result = factor(fctr, env, p)?;
543            result.as_index()
544        }
545        _ => unreachable!(),
546    }
547}
548
549#[cfg(feature = "subscript_range")]
550pub fn subscript_range(
551    sbscrpt: &Subscript,
552    env: Option<&Environment>,
553    p: &Interpreter,
554) -> MResult<Value> {
555    match sbscrpt {
556        Subscript::Range(rng) => {
557            let result = range(rng, env, p)?;
558            match result.as_vecusize() {
559                Ok(v) => Ok(v.to_value()),
560                Err(_) => Err(MechError::new(
561                    InvalidIndexKindError {
562                        kind: result.kind(),
563                    },
564                    None,
565                )
566                .with_compiler_loc()
567                .with_tokens(rng.tokens())),
568            }
569        }
570        _ => unreachable!(),
571    }
572}
573
574#[cfg(all(feature = "subscript", feature = "access"))]
575pub fn subscript(
576    sbscrpt: &Subscript,
577    val: &Value,
578    env: Option<&Environment>,
579    p: &Interpreter,
580) -> MResult<Value> {
581    let plan = p.plan();
582    match sbscrpt {
583        #[cfg(feature = "table")]
584        Subscript::Dot(x) => {
585            let key = x.hash();
586            let fxn_input: Vec<Value> = vec![val.clone(), Value::Id(key)];
587            let new_fxn = AccessColumn {}.compile(&fxn_input)?;
588            new_fxn.solve();
589            let res = new_fxn.out();
590            plan.borrow_mut().push(new_fxn);
591            return Ok(res);
592        }
593        Subscript::DotInt(x) => {
594            let mut fxn_input = vec![val.clone()];
595            let result = real(&x.clone(), p)?;
596            fxn_input.push(result.as_index()?);
597            match val.deref_kind() {
598                #[cfg(feature = "matrix")]
599                ValueKind::Matrix(..) => {
600                    let new_fxn = MatrixAccessScalar {}.compile(&fxn_input)?;
601                    new_fxn.solve();
602                    let res = new_fxn.out();
603                    plan.borrow_mut().push(new_fxn);
604                    return Ok(res);
605                }
606                #[cfg(feature = "tuple")]
607                ValueKind::Tuple(..) => {
608                    let new_fxn = TupleAccess {}.compile(&fxn_input)?;
609                    new_fxn.solve();
610                    let res = new_fxn.out();
611                    plan.borrow_mut().push(new_fxn);
612                    return Ok(res);
613                }
614                /*ValueKind::Record(_) => {
615                  let new_fxn = RecordAccessScalar{}.compile(&fxn_input)?;
616                  new_fxn.solve();
617                  let res = new_fxn.out();
618                  plan.borrow_mut().push(new_fxn);
619                  return Ok(res);
620                },*/
621                _ => todo!("Implement access for dot int"),
622            }
623        }
624        #[cfg(feature = "swizzle")]
625        Subscript::Swizzle(x) => {
626            let mut keys = x
627                .iter()
628                .map(|x| Value::Id(x.hash()))
629                .collect::<Vec<Value>>();
630            let mut fxn_input: Vec<Value> = vec![val.clone()];
631            fxn_input.append(&mut keys);
632            let new_fxn = AccessSwizzle {}.compile(&fxn_input)?;
633            new_fxn.solve();
634            let res = new_fxn.out();
635            plan.borrow_mut().push(new_fxn);
636            return Ok(res);
637        }
638        Subscript::Brace(subs) => {
639            let mut fxn_input = vec![val.clone()];
640            match &subs[..] {
641                #[cfg(feature = "subscript_formula")]
642                [Subscript::Formula(ix)] => {
643                    let result = subscript_formula(&subs[0], env, p)?;
644                    let shape = result.shape();
645                    fxn_input.push(result);
646                    match shape[..] {
647                        [1, 1] => plan.borrow_mut().push(AccessScalar {}.compile(&fxn_input)?),
648                        #[cfg(feature = "subscript_range")]
649                        [n, 1] => plan.borrow_mut().push(AccessRange {}.compile(&fxn_input)?),
650                        #[cfg(feature = "subscript_range")]
651                        [1, n] => plan.borrow_mut().push(AccessRange {}.compile(&fxn_input)?),
652                        _ => todo!(),
653                    }
654                }
655                #[cfg(feature = "subscript_range")]
656                [Subscript::Range(ix)] => {
657                    let result = subscript_range(&subs[0], env, p)?;
658                    fxn_input.push(result);
659                    plan.borrow_mut().push(AccessRange {}.compile(&fxn_input)?);
660                }
661                /*[Subscript::All] => {
662                  fxn_input.push(Value::IndexAll);
663                  #[cfg(feature = "matrix")]
664                  plan.borrow_mut().push(MapAccessAll{}.compile(&fxn_input)?);
665                },*/
666                _ => {
667                    todo!("Implement brace subscript")
668                }
669            }
670            let plan_brrw = plan.borrow();
671            let mut new_fxn = &plan_brrw.last().unwrap();
672            new_fxn.solve();
673            let res = new_fxn.out();
674            return Ok(res);
675        }
676        #[cfg(feature = "subscript_slice")]
677        Subscript::Bracket(subs) => {
678            let mut fxn_input = vec![val.clone()];
679            match &subs[..] {
680                #[cfg(feature = "subscript_formula")]
681                [Subscript::Formula(ix)] => {
682                    let result = subscript_formula_ix(&subs[0], env, p)?;
683                    let shape = result.shape();
684                    fxn_input.push(result);
685                    match shape[..] {
686                        [1, 1] => plan.borrow_mut().push(AccessScalar {}.compile(&fxn_input)?),
687                        #[cfg(feature = "subscript_range")]
688                        [1, n] => plan.borrow_mut().push(AccessRange {}.compile(&fxn_input)?),
689                        #[cfg(feature = "subscript_range")]
690                        [n, 1] => plan.borrow_mut().push(AccessRange {}.compile(&fxn_input)?),
691                        _ => todo!(),
692                    }
693                }
694                #[cfg(feature = "subscript_range")]
695                [Subscript::Range(ix)] => {
696                    let result = subscript_range(&subs[0], env, p)?;
697                    fxn_input.push(result);
698                    plan.borrow_mut().push(AccessRange {}.compile(&fxn_input)?);
699                }
700                [Subscript::All] => {
701                    fxn_input.push(Value::IndexAll);
702                    #[cfg(feature = "matrix")]
703                    plan.borrow_mut()
704                        .push(MatrixAccessAll {}.compile(&fxn_input)?);
705                }
706                [Subscript::All, Subscript::All] => todo!(),
707                #[cfg(feature = "subscript_formula")]
708                [Subscript::Formula(ix1), Subscript::Formula(ix2)] => {
709                    let result = subscript_formula_ix(&subs[0], env, p)?;
710                    let shape1 = result.shape();
711                    fxn_input.push(result);
712                    let result = subscript_formula_ix(&subs[1], env, p)?;
713                    let shape2 = result.shape();
714                    fxn_input.push(result);
715                    match ((shape1[0], shape1[1]), (shape2[0], shape2[1])) {
716                        #[cfg(feature = "matrix")]
717                        ((1, 1), (1, 1)) => plan
718                            .borrow_mut()
719                            .push(MatrixAccessScalarScalar {}.compile(&fxn_input)?),
720                        #[cfg(feature = "matrix")]
721                        ((1, 1), (m, 1)) => plan
722                            .borrow_mut()
723                            .push(MatrixAccessScalarRange {}.compile(&fxn_input)?),
724                        #[cfg(feature = "matrix")]
725                        ((n, 1), (1, 1)) => plan
726                            .borrow_mut()
727                            .push(MatrixAccessRangeScalar {}.compile(&fxn_input)?),
728                        #[cfg(feature = "matrix")]
729                        ((n, 1), (m, 1)) => plan
730                            .borrow_mut()
731                            .push(MatrixAccessRangeRange {}.compile(&fxn_input)?),
732                        _ => unreachable!(),
733                    }
734                }
735                #[cfg(feature = "subscript_range")]
736                [Subscript::Range(ix1), Subscript::Range(ix2)] => {
737                    let result = subscript_range(&subs[0], env, p)?;
738                    fxn_input.push(result);
739                    let result = subscript_range(&subs[1], env, p)?;
740                    fxn_input.push(result);
741                    #[cfg(feature = "matrix")]
742                    plan.borrow_mut()
743                        .push(MatrixAccessRangeRange {}.compile(&fxn_input)?);
744                }
745                #[cfg(all(feature = "subscript_range", feature = "subscript_formula"))]
746                [Subscript::All, Subscript::Formula(ix2)] => {
747                    fxn_input.push(Value::IndexAll);
748                    let result = subscript_formula_ix(&subs[1], env, p)?;
749                    let shape = result.shape();
750                    fxn_input.push(result);
751                    match &shape[..] {
752                        #[cfg(feature = "matrix")]
753                        [1, 1] => plan
754                            .borrow_mut()
755                            .push(MatrixAccessAllScalar {}.compile(&fxn_input)?),
756                        #[cfg(feature = "matrix")]
757                        [1, n] => plan
758                            .borrow_mut()
759                            .push(MatrixAccessAllRange {}.compile(&fxn_input)?),
760                        #[cfg(feature = "matrix")]
761                        [n, 1] => plan
762                            .borrow_mut()
763                            .push(MatrixAccessAllRange {}.compile(&fxn_input)?),
764                        _ => todo!(),
765                    }
766                }
767                #[cfg(all(feature = "subscript_range", feature = "subscript_formula"))]
768                [Subscript::Formula(ix1), Subscript::All] => {
769                    let result = subscript_formula_ix(&subs[0], env, p)?;
770                    let shape = result.shape();
771                    fxn_input.push(result);
772                    fxn_input.push(Value::IndexAll);
773                    match &shape[..] {
774                        #[cfg(feature = "matrix")]
775                        [1, 1] => plan
776                            .borrow_mut()
777                            .push(MatrixAccessScalarAll {}.compile(&fxn_input)?),
778                        #[cfg(feature = "matrix")]
779                        [1, n] => plan
780                            .borrow_mut()
781                            .push(MatrixAccessRangeAll {}.compile(&fxn_input)?),
782                        #[cfg(feature = "matrix")]
783                        [n, 1] => plan
784                            .borrow_mut()
785                            .push(MatrixAccessRangeAll {}.compile(&fxn_input)?),
786                        _ => todo!(),
787                    }
788                }
789                #[cfg(all(feature = "subscript_range", feature = "subscript_formula"))]
790                [Subscript::Range(ix1), Subscript::Formula(ix2)] => {
791                    let result = subscript_range(&subs[0], env, p)?;
792                    fxn_input.push(result);
793                    let result = subscript_formula_ix(&subs[1], env, p)?;
794                    let shape = result.shape();
795                    fxn_input.push(result);
796                    match &shape[..] {
797                        #[cfg(feature = "matrix")]
798                        [1, 1] => plan
799                            .borrow_mut()
800                            .push(MatrixAccessRangeScalar {}.compile(&fxn_input)?),
801                        #[cfg(feature = "matrix")]
802                        [1, n] => plan
803                            .borrow_mut()
804                            .push(MatrixAccessRangeRange {}.compile(&fxn_input)?),
805                        #[cfg(feature = "matrix")]
806                        [n, 1] => plan
807                            .borrow_mut()
808                            .push(MatrixAccessRangeRange {}.compile(&fxn_input)?),
809                        _ => todo!(),
810                    }
811                }
812                #[cfg(all(feature = "subscript_range", feature = "subscript_formula"))]
813                [Subscript::Formula(ix1), Subscript::Range(ix2)] => {
814                    let result = subscript_formula_ix(&subs[0], env, p)?;
815                    let shape = result.shape();
816                    fxn_input.push(result);
817                    let result = subscript_range(&subs[1], env, p)?;
818                    fxn_input.push(result);
819                    match &shape[..] {
820                        #[cfg(feature = "matrix")]
821                        [1, 1] => plan
822                            .borrow_mut()
823                            .push(MatrixAccessScalarRange {}.compile(&fxn_input)?),
824                        #[cfg(feature = "matrix")]
825                        [1, n] => plan
826                            .borrow_mut()
827                            .push(MatrixAccessRangeRange {}.compile(&fxn_input)?),
828                        #[cfg(feature = "matrix")]
829                        [n, 1] => plan
830                            .borrow_mut()
831                            .push(MatrixAccessRangeRange {}.compile(&fxn_input)?),
832                        _ => todo!(),
833                    }
834                }
835                #[cfg(feature = "subscript_range")]
836                [Subscript::All, Subscript::Range(ix2)] => {
837                    fxn_input.push(Value::IndexAll);
838                    let result = subscript_range(&subs[1], env, p)?;
839                    fxn_input.push(result);
840                    #[cfg(feature = "matrix")]
841                    plan.borrow_mut()
842                        .push(MatrixAccessAllRange {}.compile(&fxn_input)?);
843                }
844                #[cfg(feature = "subscript_range")]
845                [Subscript::Range(ix1), Subscript::All] => {
846                    let result = subscript_range(&subs[0], env, p)?;
847                    fxn_input.push(result);
848                    fxn_input.push(Value::IndexAll);
849                    #[cfg(feature = "matrix")]
850                    plan.borrow_mut()
851                        .push(MatrixAccessRangeAll {}.compile(&fxn_input)?);
852                }
853                _ => unreachable!(),
854            };
855            let plan_brrw = plan.borrow();
856            let mut new_fxn = &plan_brrw.last().unwrap();
857            new_fxn.solve();
858            let res = new_fxn.out();
859            return Ok(res);
860        }
861        _ => unreachable!(),
862    }
863}
864
865#[cfg(feature = "symbol_table")]
866pub fn var(v: &Var, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
867    let maybe_cast_to_kind = |value: Value| -> MResult<Value> {
868        match &v.kind {
869            Some(kind_anntn) => {
870                let target_kind = {
871                    let state_brrw = p.state.borrow();
872                    kind_annotation(&kind_anntn.kind, p)?.to_value_kind(&state_brrw.kinds)?
873                };
874                let convert_fxn = ConvertKind {}.compile(&vec![value, Value::Kind(target_kind)])?;
875                convert_fxn.solve();
876                let out = convert_fxn.out();
877                p.state.borrow_mut().add_plan_step(convert_fxn);
878                Ok(out)
879            }
880            None => Ok(value),
881        }
882    };
883
884    let id = v.name.hash();
885    match env {
886        Some(env) => match env.get(&id) {
887            Some(value) => maybe_cast_to_kind(value.clone()),
888            None => {
889                let state_brrw = p.state.borrow();
890                let symbols_brrw = state_brrw.symbol_table.borrow();
891                let symbol_value = symbols_brrw.get(id);
892                drop(symbols_brrw);
893                drop(state_brrw);
894                match symbol_value {
895                    Some(value) => maybe_cast_to_kind(Value::MutableReference(value)),
896                    None => Err(MechError::new(UndefinedVariableError { id }, None)
897                        .with_compiler_loc()
898                        .with_tokens(v.tokens())),
899                }
900            }
901        },
902        None => {
903            let state_brrw = p.state.borrow();
904            let symbols_brrw = state_brrw.symbol_table.borrow();
905            let symbol_value = symbols_brrw.get(id);
906            drop(symbols_brrw);
907            drop(state_brrw);
908            match symbol_value {
909                Some(value) => maybe_cast_to_kind(Value::MutableReference(value)),
910                None => Err(MechError::new(UndefinedVariableError { id }, None)
911                    .with_compiler_loc()
912                    .with_tokens(v.tokens())),
913            }
914        }
915    }
916}
917
918pub fn match_expression(
919    match_expr: &MatchExpression,
920    env: Option<&Environment>,
921    p: &Interpreter,
922) -> MResult<Value> {
923    let source = expression(&match_expr.source, env, p)?;
924    let detached_source = match &source {
925        Value::MutableReference(reference) => reference.borrow().clone(),
926        _ => source.clone(),
927    };
928    if !match_expr
929        .arms
930        .iter()
931        .any(|arm| matches!(arm.pattern, Pattern::Wildcard))
932    {
933        #[cfg(feature = "enum")]
934        if let Some((enum_name, missing_patterns)) =
935            infer_missing_enum_match_patterns(match_expr, &detached_source, p)
936        {
937            return Err(MechError::new(
938                MatchNonExhaustiveVariantsError {
939                    enum_name,
940                    missing_patterns,
941                },
942                None,
943            )
944            .with_compiler_loc()
945            .with_tokens(match_expr.source.tokens()));
946        }
947        return Err(MechError::new(MatchNonExhaustiveError, None)
948            .with_compiler_loc()
949            .with_tokens(match_expr.source.tokens()));
950    }
951    let mut base_env = env.cloned().unwrap_or_default();
952    if let Expression::Var(var) = &match_expr.source {
953        base_env.insert(var.name.hash(), detached_source.clone());
954    }
955    if value_contains_empty(&detached_source) {
956        if let Some(arm) = match_expr
957            .arms
958            .iter()
959            .find(|arm| matches!(arm.pattern, Pattern::Wildcard))
960        {
961            let passed_guard = match &arm.guard {
962                Some(guard) => guard_expression_true(guard, &base_env, p)?,
963                None => true,
964            };
965            if passed_guard {
966                return expression(&arm.expression, Some(&base_env), p);
967            }
968        }
969    }
970
971    for (arm_ix, arm) in match_expr.arms.iter().enumerate() {
972        let mut guard_env = base_env.clone();
973        let matched = match &arm.pattern {
974            Pattern::Wildcard => true,
975            _ => crate::patterns::pattern_matches_value_with_semantics(
976                &arm.pattern,
977                &detached_source,
978                &mut guard_env,
979                p,
980                crate::patterns::PatternMatchSemantics::OptionGuard,
981            )?,
982        };
983        let passed_guard = match &arm.guard {
984            Some(guard) => guard_expression_true(guard, &guard_env, p)?,
985            None => true,
986        };
987        if matched && passed_guard {
988            let output = expression(&arm.expression, Some(&guard_env), p)?;
989            match_validate_arm_kinds(
990                match_expr,
991                arm_ix,
992                &output.kind(),
993                &detached_source,
994                &base_env,
995                p,
996            )?;
997            return Ok(output);
998        }
999    }
1000
1001    Err(MechError::new(MatchNoArmMatchedError, None)
1002        .with_compiler_loc()
1003        .with_tokens(match_expr.source.tokens()))
1004}
1005
1006#[cfg(feature = "enum")]
1007fn infer_missing_enum_match_patterns(
1008    match_expr: &MatchExpression,
1009    source: &Value,
1010    p: &Interpreter,
1011) -> Option<(String, Vec<String>)> {
1012    let source_tag = match source {
1013        Value::Atom(atom) => Some(atom.borrow().id()),
1014        #[cfg(feature = "tuple")]
1015        Value::Tuple(tuple_val) => {
1016            let tuple_brrw = tuple_val.borrow();
1017            match tuple_brrw.elements.first() {
1018                Some(tag) => match tag.as_ref() {
1019                    Value::Atom(atom) => Some(atom.borrow().id()),
1020                    _ => None,
1021                },
1022                None => None,
1023            }
1024        }
1025        _ => None,
1026    }?;
1027
1028    let mut arm_tags: HashSet<u64> = HashSet::new();
1029    for arm in &match_expr.arms {
1030        match &arm.pattern {
1031            Pattern::Expression(Expression::Literal(Literal::Atom(atom))) => {
1032                arm_tags.insert(atom.name.hash());
1033            }
1034            #[cfg(feature = "atom")]
1035            Pattern::TupleStruct(pattern_tuple_struct) => {
1036                arm_tags.insert(pattern_tuple_struct.name.hash());
1037            }
1038            _ => {}
1039        }
1040    }
1041    if arm_tags.is_empty() {
1042        return None;
1043    }
1044
1045    let state_brrw = p.state.borrow();
1046    let candidates: Vec<&MechEnum> = state_brrw
1047        .enums
1048        .values()
1049        .filter(|enm| {
1050            let variant_ids: HashSet<u64> = enm.variants.iter().map(|(id, _)| *id).collect();
1051            variant_ids.contains(&source_tag) && arm_tags.is_subset(&variant_ids)
1052        })
1053        .collect();
1054    if candidates.len() != 1 {
1055        return None;
1056    }
1057    let enum_def = candidates[0];
1058    let variant_ids: HashSet<u64> = enum_def.variants.iter().map(|(id, _)| *id).collect();
1059    let missing_ids: Vec<u64> = variant_ids.difference(&arm_tags).copied().collect();
1060    if missing_ids.is_empty() {
1061        return None;
1062    }
1063    let names_brrw = enum_def.names.borrow();
1064    let missing_patterns = enum_def
1065        .variants
1066        .iter()
1067        .filter(|(id, _)| missing_ids.contains(id))
1068        .map(|(id, payload_kind)| {
1069            let variant_name = names_brrw
1070                .get(id)
1071                .cloned()
1072                .unwrap_or_else(|| id.to_string());
1073            if payload_kind.is_some() {
1074                format!(":{}(...)", variant_name)
1075            } else {
1076                format!(":{}", variant_name)
1077            }
1078        })
1079        .collect::<Vec<String>>();
1080    Some((enum_def.name(), missing_patterns))
1081}
1082
1083fn match_validate_arm_kinds(
1084    match_expr: &MatchExpression,
1085    matched_arm_ix: usize,
1086    matched_kind: &ValueKind,
1087    source: &Value,
1088    base_env: &Environment,
1089    p: &Interpreter,
1090) -> MResult<()> {
1091    for (ix, arm) in match_expr.arms.iter().enumerate() {
1092        if ix == matched_arm_ix {
1093            continue;
1094        }
1095        if matches!(arm.pattern, Pattern::Wildcard) {
1096            continue;
1097        }
1098        let mut arm_env = base_env.clone();
1099        let applicable = match arm.pattern {
1100            Pattern::Wildcard => true,
1101            _ => crate::patterns::pattern_matches_value_with_semantics(
1102                &arm.pattern,
1103                source,
1104                &mut arm_env,
1105                p,
1106                crate::patterns::PatternMatchSemantics::OptionGuard,
1107            )?,
1108        };
1109        let passed_guard = match &arm.guard {
1110            Some(guard) => guard_expression_true(guard, &arm_env, p)?,
1111            None => true,
1112        };
1113        if !(applicable && passed_guard) {
1114            continue;
1115        }
1116        let arm_value = expression(&arm.expression, Some(&arm_env), p)?;
1117        let arm_kind = arm_value.kind();
1118        if arm_kind != *matched_kind {
1119            return Err(MechError::new(
1120                MatchArmKindMismatchError {
1121                    expected: matched_kind.clone(),
1122                    found: arm_kind,
1123                },
1124                None,
1125            )
1126            .with_compiler_loc()
1127            .with_tokens(arm.expression.tokens()));
1128        }
1129    }
1130    Ok(())
1131}
1132
1133fn guard_expression_true(guard: &Expression, env: &Environment, p: &Interpreter) -> MResult<bool> {
1134    let guard_result = expression(guard, Some(env), p)?;
1135    #[cfg(feature = "bool")]
1136    if let Value::Bool(flag) = guard_result {
1137        return Ok(*flag.borrow());
1138    }
1139    Ok(false)
1140}
1141
1142fn value_contains_empty(value: &Value) -> bool {
1143    match value {
1144        Value::Empty | Value::EmptyKind(_) => true,
1145        #[cfg(feature = "tuple")]
1146        Value::Tuple(tuple) => tuple
1147            .borrow()
1148            .elements
1149            .iter()
1150            .any(|value| value_contains_empty(value.as_ref())),
1151        Value::Typed(value, _) => value_contains_empty(value),
1152        Value::MutableReference(reference) => value_contains_empty(&reference.borrow()),
1153        _ => false,
1154    }
1155}
1156
1157#[cfg(feature = "formulas")]
1158pub fn factor(fctr: &Factor, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
1159    match fctr {
1160        Factor::Term(trm) => {
1161            let result = term(trm, env, p)?;
1162            Ok(result)
1163        }
1164        Factor::Parenthetical(paren) => factor(&*paren, env, p),
1165        Factor::Expression(expr) => expression(expr, env, p),
1166        #[cfg(feature = "math_neg")]
1167        Factor::Negate(neg) => {
1168            let value = factor(neg, env, p)?;
1169            let new_fxn = MathNegate {}.compile(&vec![value])?;
1170            new_fxn.solve();
1171            let out = new_fxn.out();
1172            p.state.borrow_mut().add_plan_step(new_fxn);
1173            Ok(out)
1174        }
1175        #[cfg(feature = "logic_not")]
1176        Factor::Not(neg) => {
1177            let value = factor(neg, env, p)?;
1178            let new_fxn = LogicNot {}.compile(&vec![value])?;
1179            new_fxn.solve();
1180            let out = new_fxn.out();
1181            p.state.borrow_mut().add_plan_step(new_fxn);
1182            Ok(out)
1183        }
1184        #[cfg(feature = "matrix_transpose")]
1185        Factor::Transpose(fctr) => {
1186            use mech_matrix::MatrixTranspose;
1187            let value = factor(fctr, env, p)?;
1188            let new_fxn = MatrixTranspose {}.compile(&vec![value])?;
1189            new_fxn.solve();
1190            let out = new_fxn.out();
1191            p.state.borrow_mut().add_plan_step(new_fxn);
1192            Ok(out)
1193        }
1194        _ => todo!(),
1195    }
1196}
1197
1198#[cfg(feature = "formulas")]
1199pub fn term(trm: &Term, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
1200    let plan = p.plan();
1201    let mut lhs = factor(&trm.lhs, env, p)?;
1202    let mut term_plan: Vec<Box<dyn MechFunction>> = vec![];
1203    for (op, rhs) in &trm.rhs {
1204        let rhs = factor(&rhs, env, p)?;
1205        let new_fxn: Box<dyn MechFunction> = match op {
1206            // Math
1207            FormulaOperator::AddSub(AddSubOp::Add) => match (&lhs, &rhs) {
1208                #[cfg(feature = "string_concat")]
1209                (_, value) | (value, _) if value.is_string() => {
1210                    StringConcat {}.compile(&vec![lhs, rhs])?
1211                }
1212                #[cfg(feature = "math_add")]
1213                _ => MathAdd {}.compile(&vec![lhs, rhs])?,
1214            },
1215            #[cfg(feature = "math_sub")]
1216            FormulaOperator::AddSub(AddSubOp::Sub) => MathSub {}.compile(&vec![lhs, rhs])?,
1217            #[cfg(feature = "math_mul")]
1218            FormulaOperator::MulDiv(MulDivOp::Mul) => MathMul {}.compile(&vec![lhs, rhs])?,
1219            #[cfg(feature = "math_div")]
1220            FormulaOperator::MulDiv(MulDivOp::Div) => MathDiv {}.compile(&vec![lhs, rhs])?,
1221            #[cfg(feature = "math_mod")]
1222            FormulaOperator::MulDiv(MulDivOp::Mod) => MathMod {}.compile(&vec![lhs, rhs])?,
1223            #[cfg(feature = "math_pow")]
1224            FormulaOperator::Power(PowerOp::Pow) => MathPow {}.compile(&vec![lhs, rhs])?,
1225
1226            // Matrix
1227            #[cfg(feature = "matrix_matmul")]
1228            FormulaOperator::Vec(VecOp::MatMul) => {
1229                use mech_matrix::MatrixMatMul;
1230                MatrixMatMul {}.compile(&vec![lhs, rhs])?
1231            }
1232            #[cfg(feature = "matrix_solve")]
1233            FormulaOperator::Vec(VecOp::Solve) => MatrixSolve {}.compile(&vec![lhs, rhs])?,
1234            #[cfg(feature = "matrix_cross")]
1235            FormulaOperator::Vec(VecOp::Cross) => todo!(),
1236            #[cfg(feature = "matrix_dot")]
1237            FormulaOperator::Vec(VecOp::Dot) => MatrixDot {}.compile(&vec![lhs, rhs])?,
1238
1239            // Compare
1240            #[cfg(feature = "compare_eq")]
1241            FormulaOperator::Comparison(ComparisonOp::Equal) => {
1242                CompareEqual {}.compile(&vec![lhs, rhs])?
1243            }
1244            #[cfg(feature = "compare_seq")]
1245            FormulaOperator::Comparison(ComparisonOp::StrictEqual) => todo!(), //CompareStrictEqual{}.compile(&vec![lhs,rhs])?,
1246            #[cfg(feature = "compare_neq")]
1247            FormulaOperator::Comparison(ComparisonOp::NotEqual) => {
1248                CompareNotEqual {}.compile(&vec![lhs, rhs])?
1249            }
1250            #[cfg(feature = "compare_sneq")]
1251            FormulaOperator::Comparison(ComparisonOp::StrictNotEqual) => todo!(), //CompareStrictNotEqual{}.compile(&vec![lhs,rhs])?,
1252            #[cfg(feature = "compare_lte")]
1253            FormulaOperator::Comparison(ComparisonOp::LessThanEqual) => {
1254                CompareLessThanEqual {}.compile(&vec![lhs, rhs])?
1255            }
1256            #[cfg(feature = "compare_gte")]
1257            FormulaOperator::Comparison(ComparisonOp::GreaterThanEqual) => {
1258                CompareGreaterThanEqual {}.compile(&vec![lhs, rhs])?
1259            }
1260            #[cfg(feature = "compare_lt")]
1261            FormulaOperator::Comparison(ComparisonOp::LessThan) => {
1262                CompareLessThan {}.compile(&vec![lhs, rhs])?
1263            }
1264            #[cfg(feature = "compare_gt")]
1265            FormulaOperator::Comparison(ComparisonOp::GreaterThan) => {
1266                CompareGreaterThan {}.compile(&vec![lhs, rhs])?
1267            }
1268
1269            // Logic
1270            #[cfg(feature = "logic_and")]
1271            FormulaOperator::Logic(LogicOp::And) => LogicAnd {}.compile(&vec![lhs, rhs])?,
1272            #[cfg(feature = "logic_or")]
1273            FormulaOperator::Logic(LogicOp::Or) => LogicOr {}.compile(&vec![lhs, rhs])?,
1274            #[cfg(feature = "logic_not")]
1275            FormulaOperator::Logic(LogicOp::Not) => LogicNot {}.compile(&vec![lhs, rhs])?,
1276            #[cfg(feature = "logic_xor")]
1277            FormulaOperator::Logic(LogicOp::Xor) => LogicXor {}.compile(&vec![lhs, rhs])?,
1278
1279            // Table
1280            #[cfg(feature = "table")]
1281            FormulaOperator::Table(TableOp::InnerJoin) => {
1282                TableInnerJoin {}.compile(&vec![lhs, rhs])?
1283            }
1284            #[cfg(feature = "table")]
1285            FormulaOperator::Table(TableOp::LeftOuterJoin) => {
1286                TableLeftOuterJoin {}.compile(&vec![lhs, rhs])?
1287            }
1288            #[cfg(feature = "table")]
1289            FormulaOperator::Table(TableOp::RightOuterJoin) => {
1290                TableRightOuterJoin {}.compile(&vec![lhs, rhs])?
1291            }
1292            #[cfg(feature = "table")]
1293            FormulaOperator::Table(TableOp::FullOuterJoin) => {
1294                TableFullOuterJoin {}.compile(&vec![lhs, rhs])?
1295            }
1296            #[cfg(feature = "table")]
1297            FormulaOperator::Table(TableOp::LeftSemiJoin) => {
1298                TableLeftSemiJoin {}.compile(&vec![lhs, rhs])?
1299            }
1300            #[cfg(feature = "table")]
1301            FormulaOperator::Table(TableOp::LeftAntiJoin) => {
1302                TableLeftAntiJoin {}.compile(&vec![lhs, rhs])?
1303            }
1304
1305            // Set
1306            #[cfg(feature = "set_union")]
1307            FormulaOperator::Set(SetOp::Union) => SetUnion {}.compile(&vec![lhs, rhs])?,
1308            #[cfg(feature = "set_intersection")]
1309            FormulaOperator::Set(SetOp::Intersection) => {
1310                SetIntersection {}.compile(&vec![lhs, rhs])?
1311            }
1312            #[cfg(feature = "set_difference")]
1313            FormulaOperator::Set(SetOp::Difference) => SetDifference {}.compile(&vec![lhs, rhs])?,
1314            #[cfg(feature = "set_symmetric_difference")]
1315            FormulaOperator::Set(SetOp::SymmetricDifference) => {
1316                SetSymmetricDifference {}.compile(&vec![lhs, rhs])?
1317            }
1318            #[cfg(feature = "set_complement")]
1319            FormulaOperator::Set(SetOp::Complement) => todo!(),
1320            #[cfg(feature = "set_subset")]
1321            FormulaOperator::Set(SetOp::Subset) => SetSubset {}.compile(&vec![lhs, rhs])?,
1322            #[cfg(feature = "set_superset")]
1323            FormulaOperator::Set(SetOp::Superset) => SetSuperset {}.compile(&vec![lhs, rhs])?,
1324            #[cfg(feature = "set_proper_subset")]
1325            FormulaOperator::Set(SetOp::ProperSubset) => {
1326                SetProperSubset {}.compile(&vec![lhs, rhs])?
1327            }
1328            #[cfg(feature = "set_proper_superset")]
1329            FormulaOperator::Set(SetOp::ProperSuperset) => {
1330                SetProperSuperset {}.compile(&vec![lhs, rhs])?
1331            }
1332            #[cfg(feature = "set_element_of")]
1333            FormulaOperator::Set(SetOp::ElementOf) => {
1334                #[cfg(feature = "kind_annotation")]
1335                if let Value::Kind(kind) = &rhs {
1336                    lhs = Value::Bool(Ref::new(value_in_kind(&lhs, kind, p)));
1337                    continue;
1338                }
1339                SetElementOf {}.compile(&vec![lhs, rhs])?
1340            }
1341            #[cfg(feature = "set_not_element_of")]
1342            FormulaOperator::Set(SetOp::NotElementOf) => {
1343                #[cfg(feature = "kind_annotation")]
1344                if let Value::Kind(kind) = &rhs {
1345                    lhs = Value::Bool(Ref::new(!value_in_kind(&lhs, kind, p)));
1346                    continue;
1347                }
1348                SetNotElementOf {}.compile(&vec![lhs, rhs])?
1349            }
1350            x => {
1351                return Err(MechError::new(
1352                    UnhandledFormulaOperatorError {
1353                        operator: x.clone(),
1354                    },
1355                    None,
1356                )
1357                .with_compiler_loc()
1358                .with_tokens(trm.tokens()));
1359            }
1360        };
1361        new_fxn.solve();
1362        let res = new_fxn.out();
1363        term_plan.push(new_fxn);
1364        lhs = res;
1365    }
1366    let mut plan_brrw = plan.borrow_mut();
1367    plan_brrw.append(&mut term_plan);
1368    return Ok(lhs);
1369}
1370
1371#[cfg(all(feature = "kind_annotation", feature = "enum", feature = "atom"))]
1372fn enum_value_matches_kind(value: &Value, enum_id: u64, state: &ProgramState) -> bool {
1373    let enum_def = match state.enums.get(&enum_id) {
1374        Some(enm) => enm,
1375        None => return false,
1376    };
1377    match value {
1378        Value::Atom(atom) => {
1379            let variant_id = atom.borrow().id();
1380            enum_def
1381                .variants
1382                .iter()
1383                .any(|(known_variant, payload_kind)| *known_variant == variant_id && payload_kind.is_none())
1384        }
1385        #[cfg(feature = "tuple")]
1386        Value::Tuple(tuple_val) => {
1387            let tuple_brrw = tuple_val.borrow();
1388            if tuple_brrw.elements.len() != 2 {
1389                return false;
1390            }
1391            let tag = match tuple_brrw.elements[0].as_ref() {
1392                Value::Atom(atom) => atom.borrow().id(),
1393                _ => return false,
1394            };
1395            let payload = tuple_brrw.elements[1].as_ref();
1396            let (_, declared_payload_kind) = match enum_def
1397                .variants
1398                .iter()
1399                .find(|(known_variant, _)| *known_variant == tag)
1400            {
1401                Some(entry) => entry,
1402                None => return false,
1403            };
1404            match declared_payload_kind {
1405                Some(Value::Kind(expected_kind)) => match expected_kind {
1406                    ValueKind::Enum(inner_enum_id, _) => {
1407                        enum_value_matches_kind(payload, *inner_enum_id, state)
1408                    }
1409                    _ => payload.kind() == expected_kind.clone() || payload.convert_to(expected_kind).is_some(),
1410                },
1411                _ => false,
1412            }
1413        }
1414        _ => false,
1415    }
1416}
1417
1418#[cfg(feature = "kind_annotation")]
1419fn value_in_kind(value: &Value, kind: &ValueKind, p: &Interpreter) -> bool {
1420    let detached = detach_value(value);
1421    #[cfg(all(feature = "enum", feature = "atom"))]
1422    if let ValueKind::Enum(enum_id, _) = kind {
1423        let state_brrw = p.state.borrow();
1424        return enum_value_matches_kind(&detached, *enum_id, &state_brrw);
1425    }
1426    detached.convert_to(kind).is_some()
1427}
1428
1429#[derive(Debug, Clone)]
1430pub struct UnhandledFormulaOperatorError {
1431    pub operator: FormulaOperator,
1432}
1433impl MechErrorKind for UnhandledFormulaOperatorError {
1434    fn name(&self) -> &str {
1435        "UnhandledFormulaOperator"
1436    }
1437    fn message(&self) -> String {
1438        format!("Unhandled formula operator: {:#?}", self.operator)
1439    }
1440}
1441
1442#[derive(Debug, Clone)]
1443pub struct UndefinedVariableError {
1444    pub id: u64,
1445}
1446impl MechErrorKind for UndefinedVariableError {
1447    fn name(&self) -> &str {
1448        "UndefinedVariable"
1449    }
1450
1451    fn message(&self) -> String {
1452        format!("Undefined variable: {}", self.id)
1453    }
1454}
1455#[derive(Debug, Clone)]
1456pub struct InvalidIndexKindError {
1457    kind: ValueKind,
1458}
1459impl MechErrorKind for InvalidIndexKindError {
1460    fn name(&self) -> &str {
1461        "InvalidIndexKind"
1462    }
1463    fn message(&self) -> String {
1464        "Invalid index kind".to_string()
1465    }
1466}
1467
1468#[derive(Debug, Clone)]
1469pub struct ComprehensionGeneratorError {
1470    found: ValueKind,
1471}
1472
1473impl MechErrorKind for ComprehensionGeneratorError {
1474    fn name(&self) -> &str {
1475        "ComprehensionGenerator"
1476    }
1477    fn message(&self) -> String {
1478        format!(
1479            "Comprehension generator must produce a set or matrix, found kind: {:?}",
1480            self.found
1481        )
1482    }
1483}
1484
1485#[derive(Debug, Clone)]
1486pub struct PatternExpectedTupleError {
1487    found: ValueKind,
1488}
1489impl MechErrorKind for PatternExpectedTupleError {
1490    fn name(&self) -> &str {
1491        "PatternExpectedTuple"
1492    }
1493    fn message(&self) -> String {
1494        format!("Pattern expected a tuple, found kind: {:?}", self.found)
1495    }
1496}
1497
1498#[derive(Debug, Clone)]
1499pub struct ArityMismatchError {
1500    expected: usize,
1501    found: usize,
1502}
1503impl MechErrorKind for ArityMismatchError {
1504    fn name(&self) -> &str {
1505        "ArityMismatch"
1506    }
1507    fn message(&self) -> String {
1508        format!(
1509            "Arity mismatch: expected {}, found {}",
1510            self.expected, self.found
1511        )
1512    }
1513}
1514
1515#[derive(Debug, Clone)]
1516pub struct PatternMatchError {
1517    pub var: String,
1518    pub expected: String,
1519    pub found: String,
1520}
1521
1522#[derive(Debug, Clone)]
1523pub struct MatchNoArmMatchedError;
1524impl MechErrorKind for MatchNoArmMatchedError {
1525    fn name(&self) -> &str {
1526        "MatchNoArmMatched"
1527    }
1528    fn message(&self) -> String {
1529        format!("No match arm matched the provided value.")
1530    }
1531}
1532
1533#[derive(Debug, Clone)]
1534pub struct MatchArmKindMismatchError {
1535    expected: ValueKind,
1536    found: ValueKind,
1537}
1538impl MechErrorKind for MatchArmKindMismatchError {
1539    fn name(&self) -> &str {
1540        "MatchArmKindMismatch"
1541    }
1542    fn message(&self) -> String {
1543        format!(
1544            "Match arm kind mismatch: expected {:?}, found {:?}",
1545            self.expected, self.found
1546        )
1547    }
1548}
1549
1550#[derive(Debug, Clone)]
1551pub struct MatchNonExhaustiveError;
1552impl MechErrorKind for MatchNonExhaustiveError {
1553    fn name(&self) -> &str {
1554        "MatchNonExhaustive"
1555    }
1556    fn message(&self) -> String {
1557        "Match expression must include a wildcard (`*`) arm.".to_string()
1558    }
1559}
1560
1561#[derive(Debug, Clone)]
1562pub struct MatchNonExhaustiveVariantsError {
1563    pub enum_name: String,
1564    pub missing_patterns: Vec<String>,
1565}
1566impl MechErrorKind for MatchNonExhaustiveVariantsError {
1567    fn name(&self) -> &str {
1568        "MatchNonExhaustive"
1569    }
1570    fn message(&self) -> String {
1571        format!(
1572            "Match over enum '{}' is non-exhaustive. Missing patterns: {}. Add the missing patterns or add a wildcard (`*`) arm.",
1573            self.enum_name,
1574            self.missing_patterns.join(", ")
1575        )
1576    }
1577}
1578
1579impl MechErrorKind for PatternMatchError {
1580    fn name(&self) -> &str {
1581        "PatternMatchError"
1582    }
1583    fn message(&self) -> String {
1584        format!(
1585            "Pattern match error for variable '{}': expected value {}, found value {}",
1586            self.var, self.expected, self.found
1587        )
1588    }
1589}