1use crate::*;
2use std::collections::HashMap;
3#[cfg(feature = "enum")]
4use std::collections::HashSet;
5
6pub 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(<rl, 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 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 _ => 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 _ => {
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 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 #[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 #[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!(), #[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!(), #[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 #[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 #[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 #[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}