1use hyperon_atom::*;
5use hyperon_atom::matcher::*;
6use hyperon_space::*;
7use crate::metta::*;
8use crate::metta::types::*;
9use crate::metta::runner::stdlib::core::IfEqualOp;
10use hyperon_common::collections::CowArray;
11
12use std::fmt::{Debug, Display, Formatter};
13use std::convert::TryFrom;
14use std::rc::Rc;
15use std::fmt::Write;
16use std::cell::RefCell;
17use itertools::Itertools;
18use hyperon_atom::gnd::number::Number;
19
20macro_rules! match_atom {
21 ($atom:tt ~ $pattern:tt => $succ:tt , _ => $error:tt) => {
22 match_atom!{ $atom ~ $pattern if true => $succ , _ => $error }
23 };
24 ($atom:tt ~ $pattern:tt if $cond:expr => $succ:tt , _ => $error:tt) => {
25 match atom_as_slice(&$atom) {
26 #[allow(unused_variables)]
27 Some($pattern) if $cond => {
28 match atom_into_array($atom) {
29 Some($pattern) => $succ,
30 _ => panic!("Unexpected state"),
31 }
32 }
33 _ => $error,
34 }
35 };
36}
37
38macro_rules! call_native {
39 ($func:ident, $atom:expr) => {
40 call_native_atom($func, stringify!($func), $atom)
41 }
42}
43
44type ReturnHandler = fn(Rc<RefCell<Stack>>, Atom, Bindings) -> Option<(Stack, Bindings)>;
52
53#[derive(Debug, Clone)]
54#[cfg_attr(test, derive(PartialEq))]
55struct Stack {
56 prev: Option<Rc<RefCell<Self>>>,
62 atom: Atom,
63 ret: ReturnHandler,
64 finished: bool,
66 vars: Variables,
67 depth: usize,
68}
69
70fn no_handler(_stack: Rc<RefCell<Stack>>, _atom: Atom, _bindings: Bindings) -> Option<(Stack, Bindings)> {
71 panic!("Unexpected state");
72}
73
74impl Stack {
75 fn from_prev_with_vars(prev: Option<Rc<RefCell<Self>>>, atom: Atom, vars: Variables, ret: ReturnHandler) -> Self {
76 let depth = prev.as_ref().map_or(1, |prev| prev.borrow().depth + 1);
77 Self{ prev, atom, ret, finished: false, vars, depth }
78 }
79
80 fn from_prev_keep_vars(prev: Option<Rc<RefCell<Self>>>, atom: Atom, ret: ReturnHandler) -> Self {
81 let vars = Self::vars_copy(&prev);
82 let depth = prev.as_ref().map_or(1, |prev| prev.borrow().depth + 1);
83 Self{ prev, atom, ret, finished: false, vars, depth }
84 }
85
86 fn finished(prev: Option<Rc<RefCell<Self>>>, atom: Atom) -> Self {
87 let depth = prev.as_ref().map_or(1, |prev| prev.borrow().depth + 1);
88 Self{ prev, atom, ret: no_handler, finished: true, vars: Variables::new(), depth }
89 }
90
91 fn depth(&self) -> usize {
92 self.depth
93 }
94
95 fn fold<T, F: FnMut(T, &Stack) -> T>(&self, mut val: T, mut app: F) -> T {
97 val = app(val, self);
98 match &self.prev {
99 None => val,
100 Some(prev) => prev.borrow().fold(val, app),
101 }
102 }
103
104 fn vars_copy(prev: &Option<Rc<RefCell<Self>>>) -> Variables {
105 match prev {
106 Some(prev) => prev.borrow().vars.clone(),
107 None => Variables::new(),
108 }
109 }
110
111 fn add_vars_it<'a, I: 'a + Iterator<Item=&'a VariableAtom>>(prev: &Option<Rc<RefCell<Self>>>, vars: I) -> Variables {
112 match prev {
113 Some(prev) => {
114 let mut next = prev.borrow().vars.clone();
115 next.insert_all(vars);
116 next
117 },
118 None => vars.cloned().collect(),
119 }
120 }
121}
122
123impl Display for Stack {
124 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
125 fn print_level(buffer: &mut String, level: usize, last: bool, stack: &Stack) -> std::fmt::Result {
126 let prefix = if last { "=> " } else { " " };
127 let ret = if stack.finished { "return " } else { "" };
128 write!(buffer, "{}{:05} {}{} {}\n", prefix, level, ret, stack.atom, stack.vars)
129 }
130
131 let buffer = &mut String::new();
132 let last_level = self.depth();
133 let res = print_level(buffer, last_level, true, self);
134 self.prev.as_ref().map_or(res, |prev| {
135 prev.borrow().fold((res, last_level - 1), |(res, level), top| {
136 (res.and_then(|_| print_level(buffer, level, false, top)), level - 1)
137 }).0
138 })
139 .and_then(|_| write!(f, "{}", buffer))
140 }
141}
142
143#[derive(Debug)]
144#[cfg_attr(test, derive(PartialEq))]
145struct InterpretedAtom(Stack, Bindings);
146
147impl Display for InterpretedAtom {
148 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
149 if self.1.is_empty() {
150 write!(f, "{}", self.0)
151 } else {
152 write!(f, "{}\n{}", self.1, self.0)
153 }
154 }
155}
156
157#[derive(Debug)]
158struct InterpreterContext {
159 space: DynSpace,
160}
161
162impl InterpreterContext {
163 fn new(space: DynSpace) -> Self {
164 Self{ space }
165 }
166}
167
168#[derive(Debug)]
173pub struct InterpreterState {
174 plan: Vec<InterpretedAtom>,
176 finished: Vec<Atom>,
178 context: InterpreterContext,
180 max_stack_depth: usize,
182}
183
184fn atom_as_slice(atom: &Atom) -> Option<&[Atom]> {
185 <&[Atom]>::try_from(atom).ok()
186}
187
188fn atom_as_slice_mut(atom: &mut Atom) -> Option<&mut [Atom]> {
189 <&mut [Atom]>::try_from(atom).ok()
190}
191
192fn atom_into_array<const N: usize>(atom: Atom) -> Option<[Atom; N]> {
193 <[Atom; N]>::try_from(atom).ok()
194}
195
196impl InterpreterState {
197
198 pub(crate) fn new_finished(space: DynSpace, results: Vec<Atom>) -> Self {
200 Self {
201 plan: vec![],
202 finished: results,
203 context: InterpreterContext::new(space),
204 max_stack_depth: 0,
205 }
206 }
207
208 pub fn has_next(&self) -> bool {
210 !self.plan.is_empty()
211 }
212
213 pub fn into_result(self) -> Result<Vec<Atom>, String> {
216 if self.has_next() {
217 Err("Evaluation is not finished".into())
218 } else {
219 Ok(self.finished)
220 }
221 }
222
223 fn pop(&mut self) -> Option<InterpretedAtom> {
224 self.plan.pop()
225 }
226
227 fn push(&mut self, atom: InterpretedAtom) {
228 if atom.0.prev.is_none() && atom.0.finished {
229 let InterpretedAtom(stack, bindings) = atom;
230 let atom = apply_bindings_to_atom_move(stack.atom, &bindings);
231 self.finished.push(atom);
232 } else {
233 self.plan.push(atom);
234 }
235 }
236
237 pub fn set_max_stack_depth(&mut self, depth: usize) {
238 self.max_stack_depth = depth;
239 }
240}
241
242impl std::fmt::Display for InterpreterState {
243 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
244 write!(f, "{:?}\n", self.plan)
245 }
246}
247
248pub fn interpret_init(space: DynSpace, expr: &Atom) -> InterpreterState {
255 let context = InterpreterContext::new(space);
256 InterpreterState {
257 plan: vec![InterpretedAtom(atom_to_stack(expr.clone(), None), Bindings::new())],
258 finished: vec![],
259 context,
260 max_stack_depth: 0,
261 }
262}
263
264pub fn interpret_step(mut state: InterpreterState) -> InterpreterState {
270 let interpreted_atom = state.pop().unwrap();
271 log::debug!("interpret_step:\n{}", interpreted_atom);
272 let InterpretedAtom(stack, bindings) = interpreted_atom;
273 for result in interpret_stack(&state.context, stack, bindings, state.max_stack_depth) {
274 state.push(result);
275 }
276 state
277}
278
279pub fn interpret(space: DynSpace, expr: &Atom) -> Result<Vec<Atom>, String> {
286 let mut state = interpret_init(space, expr);
287 while state.has_next() {
288 state = interpret_step(state);
289 }
290 state.into_result()
291}
292
293fn is_embedded_op(atom: &Atom) -> bool {
294 let expr = atom_as_slice(&atom);
295 match expr {
296 Some([op, ..]) => *op == EVAL_SYMBOL
297 || *op == EVALC_SYMBOL
298 || *op == CHAIN_SYMBOL
299 || *op == UNIFY_SYMBOL
300 || *op == CONS_ATOM_SYMBOL
301 || *op == DECONS_ATOM_SYMBOL
302 || *op == FUNCTION_SYMBOL
303 || *op == COLLAPSE_BIND_SYMBOL
304 || *op == SUPERPOSE_BIND_SYMBOL
305 || *op == METTA_SYMBOL
306 || *op == CONTEXT_SPACE_SYMBOL
307 || *op == CALL_NATIVE_SYMBOL,
308 _ => false,
309 }
310}
311
312fn is_op(atom: &Atom, op: &Atom) -> bool {
313 let expr = atom_as_slice(&atom);
314 match expr {
315 Some([opp, ..]) => opp == op,
316 _ => false,
317 }
318}
319
320fn is_function_op(atom: &Atom) -> bool {
321 is_op(atom, &FUNCTION_SYMBOL)
322}
323
324#[derive(Debug, Clone)]
325#[cfg_attr(test, derive(PartialEq))]
326struct Variables(im::HashSet<VariableAtom>);
327
328impl Variables {
329 fn new() -> Self {
330 Self(im::HashSet::new())
331 }
332 fn insert(&mut self, var: VariableAtom) -> Option<VariableAtom> {
333 self.0.insert(var)
334 }
335 fn insert_all<'a, I: 'a + Iterator<Item=&'a VariableAtom>>(&mut self, it: I) {
336 it.for_each(|var| { self.insert(var.clone()); });
337 }
338 fn iter(&self) -> impl Iterator<Item=&'_ VariableAtom> {
339 self.0.iter()
340 }
341}
342fn vars_from_atom(atom: &Atom) -> impl Iterator<Item=&VariableAtom> {
343 atom.iter().filter_type::<&VariableAtom>()
344}
345
346impl FromIterator<VariableAtom> for Variables {
347 fn from_iter<I: IntoIterator<Item=VariableAtom>>(iter: I) -> Self {
348 Self(im::HashSet::from_iter(iter))
349 }
350}
351
352impl VariableSet for Variables {
353 type Iter<'a> = im::hashset::Iter<'a, hyperon_atom::VariableAtom> where Self: 'a;
354
355 fn contains(&self, var: &VariableAtom) -> bool {
356 self.0.contains(var)
357 }
358 fn iter(&self) -> Self::Iter<'_> {
359 self.0.iter()
360 }
361}
362
363impl Display for Variables {
364 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
365 write!(f, "[")
366 .and_then(|_| self.iter().take(1).fold(Ok(()),
367 |res, atom| res.and_then(|_| write!(f, "{}", atom))))
368 .and_then(|_| self.iter().skip(1).fold(Ok(()),
369 |res, atom| res.and_then(|_| write!(f, " {}", atom))))
370 .and_then(|_| write!(f, "]"))
371 }
372}
373
374fn interpret_stack(context: &InterpreterContext, stack: Stack, mut bindings: Bindings, max_stack_depth: usize) -> Vec<InterpretedAtom> {
375 if stack.finished {
376 if stack.prev.is_none() {
378 return vec![InterpretedAtom(stack, bindings)];
379 }
380 let Stack{ prev, mut atom, .. } = stack;
381 let prev = match prev {
382 Some(prev) => prev,
383 None => panic!("Unexpected state"),
384 };
385 {
386 let outer_vars = &prev.borrow().vars;
387 bindings.apply_and_retain(&mut atom, |v| outer_vars.contains(v));
388 }
389 let ret = prev.borrow().ret;
390 ret(prev, atom, bindings)
391 .map_or(vec![], |(stack, bindings)| vec![InterpretedAtom(stack, bindings)])
392 } else if max_stack_depth > 0 && stack.depth >= max_stack_depth
393 && atom_as_slice(&stack.atom).map_or(false, |expr| expr[0] == METTA_SYMBOL)
394 {
395 let Stack{ prev, atom, .. } = stack;
412 let stack = Stack::finished(prev, error_atom(atom, STACK_OVERFLOW_SYMBOL));
413 vec![InterpretedAtom(stack, bindings)]
414 } else {
415 let expr = atom_as_slice(&stack.atom);
416 let result = match expr {
417 Some([op, ..]) if *op == EVAL_SYMBOL => {
418 eval(context, stack, bindings)
419 },
420 Some([op, ..]) if *op == EVALC_SYMBOL => {
421 evalc(context, stack, bindings)
422 },
423 Some([op, ..]) if *op == CHAIN_SYMBOL => {
424 chain(stack, bindings)
425 },
426 Some([op, ..]) if *op == FUNCTION_SYMBOL => {
427 panic!("Unexpected state")
428 },
429 Some([op, ..]) if *op == COLLAPSE_BIND_SYMBOL => {
430 collapse_bind(stack, bindings)
431 },
432 Some([op, ..]) if *op == UNIFY_SYMBOL => {
433 unify(stack, bindings)
434 },
435 Some([op, ..]) if *op == DECONS_ATOM_SYMBOL => {
436 decons_atom(stack, bindings)
437 },
438 Some([op, ..]) if *op == CONS_ATOM_SYMBOL => {
439 cons_atom(stack, bindings)
440 },
441 Some([op, ..]) if *op == SUPERPOSE_BIND_SYMBOL => {
442 superpose_bind(stack, bindings)
443 },
444 Some([op, ..]) if *op == METTA_SYMBOL => {
445 metta_sym(stack, bindings)
446 },
447 Some([op, ..]) if *op == CONTEXT_SPACE_SYMBOL => {
448 context_space(context, stack, bindings)
449 },
450 Some([op, ..]) if *op == CALL_NATIVE_SYMBOL => {
451 call_native_symbol(stack, bindings)
452 },
453 _ => {
454 let stack = Stack::finished(stack.prev, stack.atom);
455 vec![InterpretedAtom(stack, bindings)]
456 },
457 };
458 result
459 }
460}
461
462fn return_not_reducible() -> Atom {
463 NOT_REDUCIBLE_SYMBOL
464}
465
466fn error_msg(atom: Atom, err: String) -> Atom {
467 error_atom(atom, Atom::sym(err))
468}
469
470fn error_atom(atom: Atom, err: Atom) -> Atom {
471 Atom::expr([ERROR_SYMBOL, atom, err])
472}
473
474fn finished_result(atom: Atom, bindings: Bindings, prev: Option<Rc<RefCell<Stack>>>) -> Vec<InterpretedAtom> {
475 vec![InterpretedAtom(Stack::finished(prev, atom), bindings)]
476}
477
478fn evalc(_context: &InterpreterContext, stack: Stack, bindings: Bindings) -> Vec<InterpretedAtom> {
479 let Stack{ prev, atom: eval, vars, .. } = stack;
480 let (to_eval, space) = match_atom!{
481 eval ~ [_op, to_eval, space]
482 if space.as_gnd::<DynSpace>().is_some() => (to_eval, space),
483 _ => {
484 let error = format!("expected: ({} <atom> <space>), found: {}", EVALC_SYMBOL, eval);
485 return finished_result(error_msg(eval, error), bindings, prev);
486 }
487 };
488 let space = space.as_gnd::<DynSpace>().unwrap();
489 eval_impl(to_eval, &space, bindings, prev, vars)
490}
491
492fn eval(context: &InterpreterContext, stack: Stack, bindings: Bindings) -> Vec<InterpretedAtom> {
493 let Stack{ prev, atom: eval, vars, .. } = stack;
494 let to_eval = match_atom!{
495 eval ~ [_op, to_eval] => to_eval,
496 _ => {
497 let error = format!("expected: ({} <atom>), found: {}", EVAL_SYMBOL, eval);
498 return finished_result(error_msg(eval, error), bindings, prev);
499 }
500 };
501 eval_impl(to_eval, &context.space, bindings, prev, vars)
502}
503
504fn eval_impl(to_eval: Atom, space: &DynSpace, bindings: Bindings, prev: Option<Rc<RefCell<Stack>>>, vars: Variables) -> Vec<InterpretedAtom> {
505 let to_eval = apply_bindings_to_atom_move(to_eval, &bindings);
506 log::debug!("eval: to_eval: {}", to_eval);
507 match atom_as_slice(&to_eval) {
508 Some([Atom::Grounded(op), args @ ..]) => {
509 match op.as_grounded().as_execute() {
510 None => query(space, prev, to_eval, bindings, vars),
511 Some(executable) => {
512 let exec_res = executable.execute_bindings(args);
513 match exec_res {
514 Ok(results) => {
515 let call_stack = call_to_stack(to_eval, vars, prev.clone());
516 let results: Vec<InterpretedAtom> = results.into_iter()
517 .flat_map(|(atom, b)| {
518 let c = move |b| (apply_bindings_to_atom_move(atom.clone(), &b), b);
519 match b {
520 None => BindingsSet::from(bindings.clone()).into_iter().map(c),
521 Some(b) => b.merge(&bindings).into_iter().map(c),
522 }
523 })
524 .map(|(res, b)| eval_result(prev.clone(), res, &call_stack, b))
525 .collect();
526 log::debug!("eval: execution results: {:?}", results);
527 if results.is_empty() {
528 finished_result(EMPTY_SYMBOL, bindings, prev)
537 } else {
538 results
539 }
540 },
541 Err(ExecError::Runtime(err)) =>
542 finished_result(error_msg(to_eval, err), bindings, prev),
543 Err(ExecError::NoReduce) =>
544 finished_result(return_not_reducible(), bindings, prev),
547 Err(ExecError::IncorrectArgument) =>
548 finished_result(return_not_reducible(), bindings, prev),
549 }
550 },
551 }
552 },
553 _ if is_embedded_op(&to_eval) =>
554 vec![InterpretedAtom(atom_to_stack(to_eval, prev), bindings)],
555 _ => query(space, prev, to_eval, bindings, vars),
556 }
557}
558
559fn eval_result(prev: Option<Rc<RefCell<Stack>>>, res: Atom, call_stack: &Rc<RefCell<Stack>>, mut bindings: Bindings) -> InterpretedAtom {
560 let stack = if is_function_op(&res) {
561 let mut stack = function_to_stack(res, Some(call_stack.clone()));
562 let call_stack = call_stack.borrow();
563 bindings.apply_and_retain(&mut stack.atom, |v| call_stack.vars.contains(v));
574 stack
575 } else {
576 Stack::finished(prev, res)
577 };
578 InterpretedAtom(stack, bindings)
579}
580
581fn call_to_stack(call: Atom, mut vars: Variables, prev: Option<Rc<RefCell<Stack>>>) -> Rc<RefCell<Stack>> {
582 vars.insert_all(vars_from_atom(&call));
583 let stack = Stack::from_prev_with_vars(prev, call, vars, call_ret);
584 Rc::new(RefCell::new(stack))
585}
586
587#[cfg(not(feature = "variable_operation"))]
588fn is_variable_op(atom: &Atom) -> bool {
589 match atom {
590 Atom::Expression(expr) => is_variable_op_expr(expr),
591 _ => false,
592 }
593}
594
595#[cfg(not(feature = "variable_operation"))]
596fn is_variable_op_expr(expr: &ExpressionAtom) -> bool {
597 match expr.children().get(0) {
598 Some(Atom::Variable(_)) => true,
599 Some(Atom::Expression(expr)) => is_variable_op_expr(expr),
600 _ => false,
601 }
602}
603
604fn query(space: &DynSpace, prev: Option<Rc<RefCell<Stack>>>, to_eval: Atom, bindings: Bindings, vars: Variables) -> Vec<InterpretedAtom> {
605 #[cfg(not(feature = "variable_operation"))]
606 if is_variable_op(&to_eval) {
607 return finished_result(return_not_reducible(), bindings, prev)
611 }
612 let var_x = &VariableAtom::new("X").make_unique();
613 let query = Atom::expr([EQUAL_SYMBOL, to_eval.clone(), Atom::Variable(var_x.clone())]);
614 let results = space.borrow().query(&query);
615 log::debug!("interpreter::query: query: {}", query);
616 log::debug!("interpreter::query: results.len(): {}, bindings.len(): {}, results: {} bindings: {}",
617 results.len(), bindings.len(), results, bindings);
618 let call_stack = call_to_stack(to_eval, vars, prev.clone());
619 let result = |res, bindings| eval_result(prev.clone(), res, &call_stack, bindings);
620 let results: Vec<InterpretedAtom> = results.into_iter().flat_map(|b| {
621 log::debug!("interpreter::query: b: {}", b);
622 b.merge(&bindings).into_iter()
623 }).filter_map(move |b| {
624 b.resolve(&var_x).map_or(None, |res| {
625 if b.has_loops() {
626 None
627 } else {
628 Some(result(res, b))
629 }
630 })
631 })
632 .collect();
633 if results.is_empty() {
634 finished_result(return_not_reducible(), bindings, prev)
635 } else {
636 results
637 }
638}
639
640fn atom_to_stack(atom: Atom, prev: Option<Rc<RefCell<Stack>>>) -> Stack {
641 let expr = atom_as_slice(&atom);
642 let result = match expr {
643 Some([op, ..]) if *op == CHAIN_SYMBOL =>
644 chain_to_stack(atom, prev),
645 Some([op, ..]) if *op == FUNCTION_SYMBOL =>
646 function_to_stack(atom, prev),
647 Some([op, ..]) if *op == EVAL_SYMBOL =>
648 Stack::from_prev_keep_vars(prev, atom, no_handler),
649 Some([op, ..]) if *op == UNIFY_SYMBOL =>
650 unify_to_stack(atom, prev),
651 _ =>
652 Stack::from_prev_keep_vars(prev, atom, no_handler),
653 };
654 result
655}
656
657fn chain_to_stack(mut atom: Atom, prev: Option<Rc<RefCell<Stack>>>) -> Stack {
658 let mut nested = Atom::sym("%Nested%");
659 let (nested_arg, templ_arg) = match atom_as_slice_mut(&mut atom) {
660 Some([_op, nested, Atom::Variable(_var), templ]) => (nested, templ),
661 _ => {
662 let error: String = format!("expected: ({} <nested> (: <var> Variable) <templ>), found: {}", CHAIN_SYMBOL, atom);
663 return Stack::finished(prev, error_msg(atom, error));
664 },
665 };
666 std::mem::swap(nested_arg, &mut nested);
667 let nested_vars: im::HashSet<&VariableAtom> = vars_from_atom(&nested).collect();
668 let templ_vars: im::HashSet<&VariableAtom> = vars_from_atom(templ_arg).collect();
669 let both_vars = nested_vars.intersection(templ_vars).into_iter();
670 let vars = Stack::add_vars_it(&prev, both_vars);
671 let cur = Stack::from_prev_with_vars(prev, atom, vars, chain_ret);
672 atom_to_stack(nested, Some(Rc::new(RefCell::new(cur))))
673}
674
675fn chain_ret(stack: Rc<RefCell<Stack>>, atom: Atom, bindings: Bindings) -> Option<(Stack, Bindings)> {
676 let mut stack = (*stack.borrow()).clone();
677 let nested = atom;
678 let Stack{ atom: chain, .. } = &mut stack;
679 let arg = match atom_as_slice_mut(chain) {
680 Some([_op, nested, Atom::Variable(_var), _templ]) => nested,
681 _ => panic!("Unexpected state"),
682 };
683 *arg = nested;
684 Some((stack, bindings))
685}
686
687fn chain(stack: Stack, bindings: Bindings) -> Vec<InterpretedAtom> {
688 let Stack{ prev, atom: chain, vars, .. } = stack;
689 let (nested, var, templ) = match_atom!{
690 chain ~ [_op, nested, Atom::Variable(var), templ] => (nested, var, templ),
691 _ => {
692 panic!("Unexpected state")
693 }
694 };
695 let b = Bindings::new().add_var_binding(var, nested).unwrap();
696 let templ = apply_bindings_to_atom_move(templ, &b);
697 let stack = atom_to_stack(templ, prev);
698 if let Some(prev) = stack.prev.as_ref() {
699 prev.borrow_mut().vars.insert_all(vars.iter());
700 }
701 vec![InterpretedAtom(stack, bindings)]
702}
703
704fn function_to_stack(mut atom: Atom, prev: Option<Rc<RefCell<Stack>>>) -> Stack {
705 let mut nested = Atom::sym("%Nested%");
706 let nested_arg = match atom_as_slice_mut(&mut atom) {
707 Some([_op, nested @ Atom::Expression(_)]) => nested,
708 _ => {
709 let error: String = format!("expected: ({} (: <body> Expression)), found: {}", FUNCTION_SYMBOL, atom);
710 return Stack::finished(prev, error_msg(atom, error));
711 },
712 };
713 std::mem::swap(nested_arg, &mut nested);
714 let cur = Stack::from_prev_keep_vars(prev, atom, function_ret);
715 atom_to_stack(nested, Some(Rc::new(RefCell::new(cur))))
716}
717
718fn call_ret(stack: Rc<RefCell<Stack>>, atom: Atom, bindings: Bindings) -> Option<(Stack, Bindings)> {
719 let stack = Stack::finished(stack.borrow().prev.clone(), atom);
720 Some((stack, bindings))
721}
722
723fn function_ret(stack: Rc<RefCell<Stack>>, atom: Atom, bindings: Bindings) -> Option<(Stack, Bindings)> {
724 match_atom!{
725 atom ~ [op, result] if *op == RETURN_SYMBOL => {
726 let stack = Stack::finished(stack.borrow().prev.clone(), result);
727 Some((stack, bindings))
728 },
729 _ => {
730 if is_embedded_op(&atom) {
731 Some((atom_to_stack(atom, Some(stack)), bindings))
732 } else {
733 let prev = stack.borrow().prev.clone();
734 let err = if let Some(ref prev) = prev {
735 error_atom(prev.borrow().atom.clone(), NO_RETURN_SYMBOL)
736 } else {
737 error_atom(atom, NO_RETURN_SYMBOL)
738 };
739 let stack = Stack::finished(prev, err);
740 Some((stack, bindings))
741 }
742 }
743 }
744}
745
746fn collapse_bind(stack: Stack, bindings: Bindings) -> Vec<InterpretedAtom> {
747 let Stack{ prev, atom: collapse, vars, .. } = stack;
748
749 let mut nested = Atom::Expression(ExpressionAtom::new(CowArray::Allocated(Vec::new())));
750 let collapse = match collapse {
751 Atom::Expression(mut expr) => {
752 let children = expr.children_mut();
753 std::mem::swap(&mut nested, &mut children[1]);
754 children.push(Atom::value(bindings.clone()));
755 Atom::Expression(expr)
756 },
757 _ => panic!("Unexpected state"),
758 };
759
760 let prev = Stack::from_prev_with_vars(prev, collapse, vars, collapse_bind_ret);
761 let prev = Rc::new(RefCell::new(prev));
762 let cur = atom_to_stack(nested, Some(prev.clone()));
763 let dummy = Stack::finished(Some(prev), EMPTY_SYMBOL);
764 vec![InterpretedAtom(dummy, bindings.clone()), InterpretedAtom(cur, bindings)]
765}
766
767fn collapse_bind_ret(stack: Rc<RefCell<Stack>>, atom: Atom, bindings: Bindings) -> Option<(Stack, Bindings)> {
768 let nested = atom;
769 if nested != EMPTY_SYMBOL {
770 let stack_ref = &mut *stack.borrow_mut();
771 let Stack{ atom: collapse, .. } = stack_ref;
772 match atom_as_slice_mut(collapse) {
773 Some([_op, Atom::Expression(ref mut finished), _bindings]) => {
774 finished.children_mut().push(atom_bindings_into_atom(nested, bindings));
775 },
776 _ => panic!("Unexpected state"),
777 };
778 }
779
780 match Rc::into_inner(stack).map(RefCell::into_inner) {
782 Some(stack) => {
783 let Stack{ prev, atom: collapse, .. } = stack;
784 let (result, bindings) = match atom_into_array(collapse) {
785 Some([_op, result, bindings]) => (result, atom_into_bindings(bindings)),
786 None => panic!("Unexpected state"),
787 };
788 Some((Stack::finished(prev, result), bindings))
789 },
790 None => None,
791 }
792}
793
794fn atom_bindings_into_atom(atom: Atom, bindings: Bindings) -> Atom {
795 Atom::expr([atom, Atom::value(bindings)])
796}
797
798fn unify_to_stack(mut atom: Atom, prev: Option<Rc<RefCell<Stack>>>) -> Stack {
799 let () = match atom_as_slice_mut(&mut atom) {
800 Some([_op, _a, _b, _then, _else]) => (),
801 _ => {
802 let error: String = format!("expected: ({} <atom> <pattern> <then> <else>), found: {}", UNIFY_SYMBOL, atom);
803 return Stack::finished(prev, error_msg(atom, error));
804 },
805 };
806 Stack::from_prev_with_vars(prev, atom, Variables::new(), no_handler)
807}
808
809fn unify(stack: Stack, bindings: Bindings) -> Vec<InterpretedAtom> {
810 let Stack{ prev, atom: unify, .. } = stack;
811 let (atom, pattern, then, else_) = match_atom!{
812 unify ~ [_op, atom, pattern, then, else_] => (atom, pattern, then, else_),
813 _ => {
814 let error: String = format!("expected: ({} <atom> <pattern> <then> <else>), found: {}", UNIFY_SYMBOL, unify);
815 return finished_result(error_msg(unify, error), bindings, prev);
816 }
817 };
818
819 let matches: Vec<Bindings> = match_atoms(&atom, &pattern).collect();
820 let result = |bindings| {
821 let then = apply_bindings_to_atom_move(then.clone(), &bindings);
822 let stack = Stack::finished(prev.clone(), then);
823 InterpretedAtom(stack, bindings)
824 };
825 let bindings_ref = &bindings;
826 let matches: Vec<InterpretedAtom> = matches.into_iter().flat_map(move |b| {
827 b.merge(bindings_ref).into_iter().filter_map(move |b| {
828 if b.has_loops() {
829 None
830 } else {
831 Some(result(b))
832 }
833 })
834 })
835 .collect();
836 if matches.is_empty() {
837 finished_result(else_, bindings, prev)
838 } else {
839 matches
840 }
841}
842
843fn decons_atom(stack: Stack, bindings: Bindings) -> Vec<InterpretedAtom> {
844 let Stack{ prev, atom: decons, .. } = stack;
845 let expr = match_atom!{
846 decons ~ [_op, Atom::Expression(expr)] if expr.children().len() > 0 => expr,
847 _ => {
848 let error: String = format!("expected: ({} (: <expr> Expression)), found: {}", DECONS_ATOM_SYMBOL, decons);
849 return finished_result(error_msg(decons, error), bindings, prev);
850 }
851 };
852 let mut children = expr.into_children();
853 let head = children.remove(0);
854 let tail = children;
855 finished_result(Atom::expr([head, Atom::expr(tail)]), bindings, prev)
856}
857
858fn cons_atom(stack: Stack, bindings: Bindings) -> Vec<InterpretedAtom> {
859 let Stack{ prev, atom: cons, .. } = stack;
860 let (head, tail) = match_atom!{
861 cons ~ [_op, head, Atom::Expression(tail)] => (head, tail),
862 _ => {
863 let error: String = format!("expected: ({} <head> (: <tail> Expression)), found: {}", CONS_ATOM_SYMBOL, cons);
864 return finished_result(error_msg(cons, error), bindings, prev);
865 }
866 };
867 let mut children = vec![head];
868 children.extend(tail.into_children());
869 finished_result(Atom::expr(children), bindings, prev)
870}
871
872fn atom_into_atom_bindings(pair: Atom) -> (Atom, Bindings) {
873 match_atom!{
874 pair ~ [atom, bindings] => (atom, atom_into_bindings(bindings)),
875 _ => {
876 panic!("(Atom Bindings) pair is expected, {} was received", pair)
877 }
878 }
879}
880
881fn atom_into_bindings(bindings: Atom) -> Bindings {
882 match bindings.as_gnd::<Bindings>() {
883 Some(bindings) => {
884 bindings.clone()
888 },
889 _ => panic!("Unexpected state: second item cannot be converted to Bindings"),
890 }
891}
892
893fn superpose_bind(stack: Stack, bindings: Bindings) -> Vec<InterpretedAtom> {
894 let Stack{ prev, atom: superpose, .. } = stack;
895 let collapsed = match_atom!{
896 superpose ~ [_op, Atom::Expression(collapsed)] => collapsed,
897 _ => {
898 let error: String = format!("expected: ({} (: <collapsed> Expression)), found: {}", SUPERPOSE_BIND_SYMBOL, superpose);
899 return finished_result(error_msg(superpose, error), bindings, prev);
900 }
901 };
902 collapsed.into_children().into_iter()
903 .map(atom_into_atom_bindings)
904 .flat_map(|(atom, b)| {
905 let result = |atom, bindings| {
906 let stack = Stack::finished(prev.clone(), atom);
907 InterpretedAtom(stack, bindings)
908 };
909 b.merge(&bindings).into_iter().filter_map(move |b| {
910 if b.has_loops() {
911 None
912 } else {
913 Some(result(atom.clone(), b))
914 }
915 })
916 })
917 .collect()
918}
919
920type NativeFunc = fn(Atom, Bindings) -> MettaResult;
921
922fn call_native_symbol(stack: Stack, bindings: Bindings) -> Vec<InterpretedAtom> {
923 let Stack{ prev, atom: call, vars, .. } = stack;
924 let (name, func, args) = match_atom!{
925 call ~ [_op, name, func, args]
926 if func.as_gnd::<NativeFunc>().is_some() => (name, func, args),
927 _ => {
928 let error = format!("expected: ({} func args), found: {}", CALL_NATIVE_SYMBOL, call);
929 return finished_result(error_msg(call, error), bindings, prev);
930 }
931 };
932
933 let call_stack = Some(call_to_stack(Atom::expr([name, args.clone()]), vars, prev));
934 let func = func.as_gnd::<NativeFunc>().expect("Unexpected state");
935 func(args, bindings)
936 .map(|(atom, bindings)| InterpretedAtom(atom_to_stack(atom, call_stack.clone()), bindings))
937 .collect()
938}
939
940fn metta_sym(stack: Stack, bindings: Bindings) -> Vec<InterpretedAtom> {
941 let Stack{ prev, atom: metta, .. } = stack;
942 let (atom, typ, space) = match_atom!{
943 metta ~ [_op, atom, typ, space]
944 if space.as_gnd::<DynSpace>().is_some() => (atom, typ, space),
945 _ => {
946 let error = format!("expected: ({} atom type space), found: {}", METTA_SYMBOL, metta);
947 return finished_result(error_msg(metta, error), bindings, prev);
948 }
949 };
950
951 vec![InterpretedAtom(atom_to_stack(call_native!(metta_impl, Atom::expr([atom, typ, space])), prev), bindings)]
952}
953
954fn context_space(context: &InterpreterContext, stack: Stack, bindings: Bindings) -> Vec<InterpretedAtom> {
955 let space = context.space.clone();
956 let Stack{ prev, atom: ctx_space, .. } = stack;
957 let _ = match_atom!{
958 ctx_space ~ [_op] => (),
959 _ => {
960 let error = format!("expected: ({}), found: {}", CONTEXT_SPACE_SYMBOL, ctx_space);
961 return finished_result(error_msg(ctx_space, error), bindings, prev);
962 }
963 };
964 finished_result(Atom::gnd(space), bindings, prev)
965}
966
967type MettaResult = Box<dyn Iterator<Item=(Atom, Bindings)>>;
968
969#[inline]
970fn once<'a, T: 'a>(data: T) -> Box<dyn Iterator<Item=T> + 'a> {
971 Box::new(std::iter::once(data))
972}
973
974#[inline]
975fn empty<'a, T: 'a>() -> Box<dyn Iterator<Item=T> + 'a> {
976 Box::new(std::iter::empty())
977}
978
979#[inline]
980fn call_native_atom(func: NativeFunc, name: &str, args: Atom) -> Atom {
981 function_atom(Atom::expr([CALL_NATIVE_SYMBOL, Atom::sym(name), Atom::value(func), args]))
982}
983
984#[inline]
985fn return_atom(atom: Atom) -> Atom {
986 Atom::expr([RETURN_SYMBOL, atom])
987}
988
989#[inline]
990fn function_atom(atom: Atom) -> Atom {
991 Atom::expr([FUNCTION_SYMBOL, atom])
992}
993
994fn metta_impl(args: Atom, bindings: Bindings) -> MettaResult {
995 let (atom, typ, space) = match_atom!{
996 args ~ [atom, typ, space]
997 if space.as_gnd::<DynSpace>().is_some() => (atom, typ, space),
998 _ => {
999 let error = format!("expected args: (atom type space), found: {}", args);
1000 return once((return_atom(error_msg(call_native!(metta_impl, args), error)), bindings));
1001 }
1002 };
1003
1004 match &atom {
1005 _ if typ == ATOM_TYPE_ATOM => once((return_atom(atom), bindings)),
1006 Atom::Variable(_) => once((return_atom(atom), bindings)),
1007 Atom::Symbol(_) if typ == ATOM_TYPE_SYMBOL => once((return_atom(atom), bindings)),
1008 Atom::Symbol(_) => type_cast(space, atom, typ, bindings),
1009 Atom::Grounded(_) if typ == ATOM_TYPE_GROUNDED => once((return_atom(atom), bindings)),
1010 Atom::Grounded(_) => type_cast(space, atom, typ, bindings),
1011 Atom::Expression(_) if typ == ATOM_TYPE_EXPRESSION => once((return_atom(atom), bindings)),
1012 Atom::Expression(e) if e.is_evaluated() => once((return_atom(atom), bindings)),
1013 Atom::Expression(_) => {
1014 let var = Atom::Variable(VariableAtom::new("x").make_unique());
1015 let res = Atom::Variable(VariableAtom::new("res").make_unique());
1016 once((Atom::expr([CHAIN_SYMBOL, Atom::expr([COLLAPSE_BIND_SYMBOL, call_native!(interpret_expression, Atom::expr([atom.clone(), typ, space]))]), var.clone(),
1017 Atom::expr([CHAIN_SYMBOL, call_native!(check_alternatives, Atom::expr([atom, var])), res.clone(),
1018 return_atom(res)
1019 ])
1020 ]), bindings))
1021 }
1022 }
1023}
1024
1025fn get_meta_type(atom: &Atom) -> Atom {
1026 match atom {
1027 Atom::Variable(_) => ATOM_TYPE_VARIABLE,
1028 Atom::Symbol(_) => ATOM_TYPE_SYMBOL,
1029 Atom::Expression(_) => ATOM_TYPE_EXPRESSION,
1030 Atom::Grounded(_) => ATOM_TYPE_GROUNDED,
1031 }
1032}
1033
1034fn type_cast(space: Atom, atom: Atom, expected_type: Atom, bindings: Bindings) -> MettaResult {
1035 let space = space.as_gnd::<DynSpace>().unwrap();
1036 let types = get_atom_types(space, &atom);
1037
1038 let mut errors = Vec::with_capacity(types.len());
1039 for actual_type in types.into_iter().filter(AtomType::is_valid).map(AtomType::into_atom) {
1040 let res = match_types(&expected_type, &actual_type, bindings.clone());
1041 match res {
1042 Ok(it) => return Box::new(it.map(move |b| (return_atom(atom.clone()), b))),
1043 Err(_) => errors.push(actual_type),
1044 }
1045 }
1046
1047 Box::new(errors.into_iter().map(move |actual_type| {
1048 let err = error_atom(atom.clone(), Atom::expr([BAD_TYPE_SYMBOL, expected_type.clone(), actual_type]));
1049 (return_atom(err), bindings.clone())
1050 }))
1051}
1052
1053fn match_types(type1: &Atom, type2: &Atom, bindings: Bindings) -> Result<MatchResultIter, MatchResultIter> {
1054 if *type1 == ATOM_TYPE_UNDEFINED
1055 || *type2 == ATOM_TYPE_UNDEFINED
1056 || *type1 == ATOM_TYPE_ATOM
1057 || *type2 == ATOM_TYPE_ATOM {
1058 Ok(once(bindings))
1059 } else {
1060 let bindings_copy = bindings.clone();
1061 let mut result = match_atoms(type1, type2)
1062 .flat_map(move |b| b.merge(&bindings).into_iter())
1063 .peekable();
1064 if result.peek().is_none() {
1065 log::trace!("match_types: no match: {} !~ {}", type1, type2);
1066 Err(once(bindings_copy))
1067 } else {
1068 if log::log_enabled!(log::Level::Trace) {
1069 let result: Vec<Bindings> = result.collect();
1070 log::trace!("match_types: match: {} ~ {}, bindings {:?}", type1, type2, result);
1071 Ok(Box::new(result.into_iter()))
1072 } else {
1073 Ok(Box::new(result))
1074 }
1075 }
1076 }
1077}
1078
1079fn check_alternatives(args: Atom, bindings: Bindings) -> MettaResult {
1080 let (original, expr) = match_atom!{
1081 args ~ [original, Atom::Expression(expr)] => (original, expr),
1082 _ => {
1083 let error = format!("expected args: ((: expr Expression)), found: {}", args);
1084 return once((return_atom(error_msg(call_native!(check_alternatives, args), error)), bindings));
1085 }
1086 };
1087 let results = expr.into_children().into_iter()
1088 .map(atom_into_atom_bindings);
1089 let mut succ = results.clone()
1090 .filter(|(atom, _bindings)| !atom_is_error(&atom))
1091 .map(move |(mut atom, bindings)| {
1092 if original == atom {
1093 match &mut atom {
1094 Atom::Expression(e) => e.set_evaluated(),
1095 _ => {},
1096 };
1097 }
1098 (return_atom(atom), bindings)
1099 })
1100 .peekable();
1101 let err = results
1102 .filter(|(atom, _bindings)| atom_is_error(&atom))
1103 .map(|(atom, bindings)| (return_atom(atom), bindings));
1104 match succ.peek() {
1105 Some(_) => Box::new(succ),
1106 None => Box::new(err),
1107 }
1108}
1109
1110fn interpret_expression(args: Atom, bindings: Bindings) -> MettaResult {
1111 let (expr, expr_typ, space) = match_atom!{
1112 args ~ [expr, expr_typ, space]
1113 if space.as_gnd::<DynSpace>().is_some() => (expr, expr_typ, space),
1114 _ => {
1115 let error = format!("expected args: (atom type space), found: {}", args);
1116 return once((return_atom(error_msg(call_native!(interpret_expression, args), error)), bindings));
1117 }
1118 };
1119 match atom_as_slice(&expr) {
1120 Some([op, _args @ ..]) => {
1121 let space_ref = space.as_gnd::<DynSpace>().unwrap();
1122 let actual_types = get_atom_types(space_ref, op);
1123
1124 let only_error_types = actual_types.iter().all(AtomType::is_error);
1125 if only_error_types {
1126 log::debug!("interpret_expression: op type check: expr: {}, op types: [{}]", expr, actual_types.iter().format(", "));
1127 return Box::new(actual_types.into_iter().map(move |t| (return_atom(t.into_error_unchecked()), bindings.clone())))
1128 }
1129
1130 let mut func_types = actual_types.iter()
1131 .filter(|t| t.is_valid() && t.is_function())
1132 .map(AtomType::as_atom)
1133 .peekable();
1134 let func = if func_types.peek().is_some() {
1135 let ret_typ = expr_typ.clone();
1136 let type_check_results = func_types.flat_map(|typ| check_if_function_type_is_applicable(&expr, typ, &ret_typ, space_ref, bindings.clone()));
1137 let mut errors = Vec::new();
1138 for res in type_check_results {
1139 log::debug!("interpret_expression: function type check: expr: {} type: {:?}", expr, res);
1140 match res {
1141 (Ok((op_type, mut ret_type)), bindings) => {
1142 if ret_type == ATOM_TYPE_EXPRESSION {
1152 ret_type = ATOM_TYPE_UNDEFINED;
1153 }
1154 let reduced = Atom::Variable(VariableAtom::new("reduced").make_unique());
1155 let result = Atom::Variable(VariableAtom::new("result").make_unique());
1156 return once((Atom::expr([CHAIN_SYMBOL, call_native!(interpret_function, Atom::expr([expr.clone(), op_type, expr_typ.clone(), space.clone()])), reduced.clone(),
1157 Atom::expr([CHAIN_SYMBOL, call_native!(metta_call, Atom::expr([reduced, ret_type, space.clone()])), result.clone(),
1158 return_atom(result)
1159 ])
1160 ]), bindings));
1161 },
1162 (Err(err), bindings) => errors.push((err, bindings)),
1163 }
1164 }
1165 Box::new(errors.into_iter()
1166 .map(move |(err, bindings)| (return_atom(err), bindings)))
1167 } else {
1168 empty()
1169 };
1170
1171 let has_tuple_type = actual_types.iter().any(|t| (t.is_valid() && !t.is_function()) || t.as_atom() == &ATOM_TYPE_UNDEFINED);
1172 let tuple = if has_tuple_type {
1173 let reduced = Atom::Variable(VariableAtom::new("reduced").make_unique());
1174 let result = Atom::Variable(VariableAtom::new("result").make_unique());
1175 once((
1176 Atom::expr([CHAIN_SYMBOL, call_native!(interpret_tuple, Atom::expr([expr.clone(), space.clone()])), reduced.clone(),
1177 Atom::expr([CHAIN_SYMBOL, call_native!(metta_call, Atom::expr([reduced, expr_typ.clone(), space.clone()])), result.clone(),
1178 return_atom(result)
1179 ])
1180 ]), bindings.clone()))
1181 } else {
1182 empty()
1183 };
1184
1185 Box::new(tuple.chain(func))
1186 },
1187 _ => type_cast(space, expr, expr_typ, bindings),
1188 }
1189}
1190
1191fn interpret_tuple(args: Atom, bindings: Bindings) -> MettaResult {
1192 let (expr, space) = match_atom!{
1193 args ~ [Atom::Expression(expr), space]
1194 if space.as_gnd::<DynSpace>().is_some() => (expr, space),
1195 _ => {
1196 let error = format!("expected args: ((: expr Expression) space), found: {}", args);
1197 return once((return_atom(error_msg(call_native!(interpret_tuple, args), error)), bindings));
1198 }
1199 };
1200 if expr.children().is_empty() {
1201 once((return_atom(Atom::Expression(expr)), bindings))
1202 } else {
1203 let mut tuple = expr.into_children();
1204 let head = tuple.remove(0);
1205 let tail = tuple;
1206 let rhead = Atom::Variable(VariableAtom::new("rhead").make_unique());
1207 let rtail = Atom::Variable(VariableAtom::new("rtail").make_unique());
1208 let result = Atom::Variable(VariableAtom::new("result").make_unique());
1209 once((
1210 Atom::expr([CHAIN_SYMBOL, Atom::expr([METTA_SYMBOL, head, ATOM_TYPE_UNDEFINED, space.clone()]), rhead.clone(),
1211 call_native!(return_on_error, Atom::expr([rhead.clone(),
1212 Atom::expr([CHAIN_SYMBOL, call_native!(interpret_tuple, Atom::expr([Atom::expr(tail), space.clone()])), rtail.clone(),
1213 call_native!(return_on_error, Atom::expr([rtail.clone(),
1214 Atom::expr([CHAIN_SYMBOL, Atom::expr([CONS_ATOM_SYMBOL, rhead, rtail]), result.clone(),
1215 return_atom(result)
1216 ])
1217 ]))
1218 ])
1219 ]))
1220 ]), bindings))
1221 }
1222}
1223
1224fn interpret_function(args: Atom, bindings: Bindings) -> MettaResult {
1225 let (atom, op_type, ret_type, space) = match_atom!{
1226 args ~ [Atom::Expression(atom), Atom::Expression(op_type), ret_type, space]
1227 if space.as_gnd::<DynSpace>().is_some() &&
1228 op_type.children().get(0) == Some(&ARROW_SYMBOL) => (atom, op_type, ret_type, space),
1229 _ => {
1230 let error = format!("expected args: ((: atom Expression) (: op_type Expression) ret_type space), found: {}", args);
1231 return once((return_atom(error_msg(call_native!(interpret_function, args), error)), bindings));
1232 }
1233 };
1234 let mut call = atom.clone().into_children();
1235 let head = call.remove(0);
1236 let args = call;
1237 let mut arg_types: Vec<Atom> = op_type.children().into();
1238 arg_types.remove(0);
1239 let arg_types = Atom::expr(arg_types);
1240 let rop = Atom::Variable(VariableAtom::new("rop").make_unique());
1241 let rargs = Atom::Variable(VariableAtom::new("rargs").make_unique());
1242 let result = Atom::Variable(VariableAtom::new("result").make_unique());
1243 let unpacked_args = Atom::Variable(VariableAtom::new("unpacked_args").make_unique());
1244 let call_interpret_args = call_native!(interpret_args, Atom::expr([Atom::Expression(atom), Atom::expr(args), arg_types, ret_type, space.clone()]));
1245 once((
1246 Atom::expr([CHAIN_SYMBOL, Atom::expr([METTA_SYMBOL, head, Atom::Expression(op_type), space.clone()]), rop.clone(),
1247 call_native!(return_on_error, Atom::expr([rop.clone(),
1248 Atom::expr([CHAIN_SYMBOL, call_interpret_args.clone(), rargs.clone(),
1249 Atom::expr([UNIFY_SYMBOL, Atom::expr([Atom::sym("Ok"), unpacked_args.clone()]), rargs.clone(),
1250 Atom::expr([CHAIN_SYMBOL, Atom::expr([CONS_ATOM_SYMBOL, rop, unpacked_args]), result.clone(),
1251 return_atom(result)
1252 ]),
1253 return_atom(rargs)
1254 ])
1255 ])
1256 ]))
1257 ]), bindings))
1258}
1259
1260fn check_if_function_type_is_applicable<'a>(expr: &'a Atom, op_type: &'a Atom, expected_type: &'a Atom, space: &'a DynSpace, bindings: Bindings) -> Box<dyn Iterator<Item=(Result<(Atom, Atom), Atom>, Bindings)> + 'a> {
1261 log::trace!("check_if_function_type_is_applicable: function type check: expr: {}, op_type: {}, expected_type: {}", expr, op_type, expected_type);
1262 let arg_types: &ExpressionAtom = (op_type).try_into().unwrap();
1263 let arg_types = arg_types.children();
1264 let actual_args: &ExpressionAtom = (expr).try_into().unwrap();
1265 let actual_args = actual_args.children();
1266 if (arg_types.len() - 2) != (actual_args.len() - 1) {
1267 return once((Err(error_atom(expr.clone(), INCORRECT_NUMBER_OF_ARGUMENTS_SYMBOL)), bindings));
1268 }
1269 let mut actual_args = actual_args.iter();
1270 actual_args.next();
1271 let mut arg_types = arg_types.iter();
1272 assert_eq!(arg_types.next().unwrap(), &ARROW_SYMBOL);
1273 check_if_function_type_is_applicable_(expr, op_type,
1274 actual_args, arg_types, expected_type, space, bindings)
1275}
1276
1277fn is_meta_type(atom: &Atom) -> bool {
1278 if *atom == ATOM_TYPE_ATOM
1279 || *atom == ATOM_TYPE_SYMBOL
1280 || *atom == ATOM_TYPE_VARIABLE
1281 || *atom == ATOM_TYPE_EXPRESSION
1282 || *atom == ATOM_TYPE_GROUNDED {
1283 true
1284 } else {
1285 false
1286 }
1287}
1288
1289fn match_meta_types(actual: &Atom, expected: &Atom) -> bool {
1290 if *expected == ATOM_TYPE_ATOM {
1291 true
1292 } else {
1293 actual == expected
1294 }
1295}
1296
1297fn check_if_function_type_is_applicable_<'a>(expr: &'a Atom, op_type: &'a Atom,
1298 mut actual_args: std::slice::Iter<'a, Atom>, mut arg_types: std::slice::Iter<'a, Atom>,
1299 expected_type: &'a Atom, space: &'a DynSpace, bindings: Bindings) -> Box<dyn Iterator<Item=(Result<(Atom, Atom), Atom>, Bindings)> + 'a> {
1300 match actual_args.next() {
1301 None => {
1302 let ret_type = arg_types.next().unwrap();
1303 log::trace!("check_if_function_type_is_applicable_: function type check: expr: {}, ret_type: {}, expected_type: {}", expr, ret_type, expected_type);
1304 match match_types(ret_type, expected_type, bindings) {
1313 Ok(matches) => Box::new(matches.map(move |bindings| (Ok((op_type.clone(), ret_type.clone())), bindings))),
1314 Err(nomatch) => Box::new(nomatch.map(move |bindings| (Err(Atom::expr([ERROR_SYMBOL, expr.clone(), Atom::expr([BAD_TYPE_SYMBOL, expected_type.clone(), ret_type.clone()])])), bindings))),
1315 }
1316 },
1317 Some(actual_arg) => {
1318 let formal_arg_type = arg_types.next().unwrap();
1319 if is_meta_type(formal_arg_type) && match_meta_types(&get_meta_type(actual_arg), formal_arg_type) {
1320 check_if_function_type_is_applicable_(expr, op_type, actual_args, arg_types, expected_type, space, bindings)
1321 } else {
1322 let actual_arg_types = get_atom_types(space, actual_arg)
1323 .into_iter()
1324 .inspect(move |typ| log::trace!("check_if_function_type_is_applicable_: function type check: expr: {}, actual_arg: {}, actual_type: {}", expr, actual_arg, typ));
1325 let iter = actual_arg_types.flat_map(move |actual_arg_type| -> Box<dyn Iterator<Item=(Result<(Atom, Atom), Atom>, Bindings)> + '_> {
1326 match actual_arg_type.into_atom_or_error() {
1327 Ok(actual_arg_type) => {
1328 match match_types(formal_arg_type, &actual_arg_type, bindings.clone()) {
1329 Ok(matches) => {
1330 let actual_args = actual_args.clone();
1331 let arg_types = arg_types.clone();
1332 Box::new(matches.flat_map(move |bindings| check_if_function_type_is_applicable_(expr, op_type, actual_args.clone(), arg_types.clone(), expected_type, space, bindings)))
1333 },
1334 Err(nomatch) => {
1335 let arg_id = TryInto::<&ExpressionAtom>::try_into(expr).unwrap().children().len() - arg_types.len();
1336 Box::new(nomatch.map(move |bindings| {
1337 let formal_arg_type = apply_bindings_to_atom_move(formal_arg_type.clone(), &bindings);
1338 (Err(Atom::expr([ERROR_SYMBOL, expr.clone(), Atom::expr([BAD_ARG_TYPE_SYMBOL, Atom::gnd(Number::Integer(arg_id as i64)), formal_arg_type, actual_arg_type.clone()])])), bindings)
1339 }))
1340 },
1341 }
1342 },
1343 Err(error) => once((Err(error), bindings.clone())),
1344 }
1345 });
1346 Box::new(iter)
1347 }
1348 },
1349 }
1350}
1351
1352fn interpret_args(args_: Atom, bindings: Bindings) -> MettaResult {
1353 let (atom, args, arg_types, ret_type, space) = match_atom!{
1354 args_ ~ [atom, Atom::Expression(args), Atom::Expression(arg_types), ret_type, space]
1355 if space.as_gnd::<DynSpace>().is_some() => (atom, args, arg_types, ret_type, space),
1356 _ => {
1357 let error = format!("expected args: (atom (: args Expression) (: arg_types Expression) ret_type space), found: {}", args_);
1358 return once((return_atom(error_msg(call_native!(interpret_args, args_), error)), bindings));
1359 }
1360 };
1361 let mut types = arg_types.into_children();
1362 if types.is_empty() {
1363 return once((return_atom(error_atom(atom, INCORRECT_NUMBER_OF_ARGUMENTS_SYMBOL)), bindings));
1364 }
1365 let types_head = types.remove(0);
1366 let types_tail = types;
1367 if args.children().is_empty() {
1368 once((return_atom(Atom::expr([Atom::sym("Ok"), Atom::Expression(args.clone())])), bindings))
1369 } else {
1370 let mut args = args.into_children();
1371 let args_head = args.remove(0);
1372 let args_tail = args;
1373 let rhead = Atom::Variable(VariableAtom::new("rhead").make_unique());
1374 let rtail = Atom::Variable(VariableAtom::new("rtail").make_unique());
1375 let result = Atom::Variable(VariableAtom::new("result").make_unique());
1376 let tail = Atom::Variable(VariableAtom::new("tail").make_unique());
1377 let call_self = call_native!(interpret_args, Atom::expr([atom, Atom::expr(args_tail), Atom::expr(types_tail), ret_type, space.clone()]));
1378 let recursion = Atom::expr([CHAIN_SYMBOL, call_self.clone(), rtail.clone(),
1379 Atom::expr([UNIFY_SYMBOL, Atom::expr([Atom::sym("Ok"), tail.clone()]), rtail.clone(),
1380 Atom::expr([CHAIN_SYMBOL, Atom::expr([CONS_ATOM_SYMBOL, rhead.clone(), tail]), result.clone(),
1381 return_atom(Atom::expr([Atom::sym("Ok"), result]))
1382 ]),
1383 return_atom(rtail)
1384 ])
1385 ]);
1386 once((
1387 Atom::expr([CHAIN_SYMBOL, Atom::expr([METTA_SYMBOL, args_head.clone(), types_head, space.clone()]), rhead.clone(),
1388 Atom::expr([EVAL_SYMBOL, Atom::expr([Atom::gnd(IfEqualOp{}), rhead.clone(), args_head,
1389 recursion.clone(),
1390 call_native!(return_on_error, Atom::expr([rhead,
1391 recursion
1392 ]))
1393 ])])
1394 ]), bindings))
1395 }
1396}
1397
1398fn return_on_error(args: Atom, bindings: Bindings) -> MettaResult {
1399 let (atom, then) = match_atom!{
1400 args ~ [atom, then] => (atom, then),
1401 _ => {
1402 let error = format!("expected args: (atom then), found: {}", args);
1403 return once((return_atom(error_msg(call_native!(return_on_error, args), error)), bindings));
1404 }
1405 };
1406 if EMPTY_SYMBOL == atom {
1407 once((return_atom(return_atom(EMPTY_SYMBOL)), bindings))
1408 } else if atom_is_error(&atom) {
1409 once((return_atom(return_atom(atom)), bindings))
1410 } else {
1411 once((return_atom(then), bindings))
1412 }
1413}
1414
1415fn metta_call(args: Atom, bindings: Bindings) -> MettaResult {
1416 let (atom, typ, space) = match_atom!{
1417 args ~ [atom, typ, space]
1418 if space.as_gnd::<DynSpace>().is_some() => (atom, typ, space),
1419 _ => {
1420 let error = format!("expected args: (atom type space), found: {}", args);
1421 return once((return_atom(error_msg(call_native!(metta_call, args), error)), bindings));
1422 }
1423 };
1424 if atom_is_error(&atom) {
1425 once((return_atom(atom), bindings))
1426 } else {
1427 let result = Atom::Variable(VariableAtom::new("result").make_unique());
1428 let ret = Atom::Variable(VariableAtom::new("ret").make_unique());
1429 once((
1430 Atom::expr([CHAIN_SYMBOL, Atom::expr([EVALC_SYMBOL, atom.clone(), space.clone()]), result.clone(),
1440 Atom::expr([CHAIN_SYMBOL, call_native!(metta_call_return, Atom::expr([atom, result, typ, space])), ret.clone(),
1441 return_atom(ret)
1442 ])
1443 ]), bindings))
1444 }
1445}
1446
1447fn metta_call_return(args: Atom, bindings: Bindings) -> MettaResult {
1448 let (atom, result, typ, space) = match_atom!{
1449 args ~ [atom, result, typ, space]
1450 if space.as_gnd::<DynSpace>().is_some() => (atom, result, typ, space),
1451 _ => {
1452 let error = format!("expected args: (atom result type space), found: {}", args);
1453 return once((return_atom(error_msg(call_native!(metta_call_return, args), error)), bindings));
1454 }
1455 };
1456 if NOT_REDUCIBLE_SYMBOL == result {
1457 once((return_atom(atom), bindings))
1458 } else if EMPTY_SYMBOL == result {
1459 once((return_atom(EMPTY_SYMBOL), bindings))
1460 } else if atom_is_error(&result) {
1461 once((return_atom(result), bindings))
1462 } else {
1463 let ret = Atom::Variable(VariableAtom::new("ret").make_unique());
1464 once((
1465 Atom::expr([CHAIN_SYMBOL, Atom::expr([METTA_SYMBOL, result, typ, space]), ret.clone(),
1466 return_atom(ret)
1467 ]), bindings))
1468 }
1469}
1470
1471#[cfg(test)]
1472mod tests {
1473 use super::*;
1474 use crate::metta::text::metta_atom;
1475 use crate::space::grounding::metta_space;
1476 use hyperon_common::assert_eq_no_order;
1477 use hyperon_macros::metta;
1478
1479 #[test]
1480 fn interpret_atom_evaluate_incorrect_args() {
1481 assert_eq!(call_interpret(space(""), &metta_atom("(eval)")),
1482 vec![expr!("Error" ("eval") "expected: (eval <atom>), found: (eval)")]);
1483 assert_eq!(call_interpret(space(""), &metta_atom("(eval a b)")),
1484 vec![expr!("Error" ("eval" "a" "b") "expected: (eval <atom>), found: (eval a b)")]);
1485 }
1486
1487 #[test]
1488 fn interpret_atom_evaluate_atom() {
1489 let result = call_interpret(space("(= a b)"), &metta_atom("(eval a)"));
1490 assert_eq!(result, vec![metta_atom("b")]);
1491 }
1492
1493 #[test]
1494 fn interpret_atom_evaluate_atom_no_definition() {
1495 let result = call_interpret(space(""), &metta_atom("(eval a)"));
1496 assert_eq!(result, vec![metta_atom("NotReducible")]);
1497 }
1498
1499 #[test]
1500 fn interpret_atom_evaluate_empty_expression() {
1501 let result = call_interpret(space(""), &metta_atom("(eval ())"));
1502 assert_eq!(result, vec![metta_atom("NotReducible")]);
1503 }
1504
1505 #[test]
1506 fn interpret_atom_evaluate_grounded_value() {
1507 let result = call_interpret(space(""), &expr!("eval" {6}));
1508 assert_eq!(result, vec![metta_atom("NotReducible")]);
1509 }
1510
1511
1512 #[test]
1513 fn interpret_atom_evaluate_pure_expression() {
1514 let space = space("(= (foo $a B) $a)");
1515 let result = call_interpret(space, &metta_atom("(eval (foo A $b))"));
1516 assert_eq!(result, vec![metta_atom("A")]);
1517 }
1518
1519 #[test]
1520 fn interpret_atom_evaluate_pure_expression_non_determinism() {
1521 let space = space("
1522 (= color red)
1523 (= color green)
1524 (= color blue)
1525 ");
1526 let result = call_interpret(space, &metta_atom("(eval color)"));
1527 assert_eq_no_order!(result, vec![
1528 metta_atom("red"),
1529 metta_atom("green"),
1530 metta_atom("blue"),
1531 ]);
1532 }
1533
1534 #[test]
1535 fn interpret_atom_evaluate_pure_expression_no_definition() {
1536 let result = call_interpret(space(""), &metta_atom("(eval (foo A))"));
1537 assert_eq!(result, vec![metta_atom("NotReducible")]);
1538 }
1539
1540 #[test]
1541 fn interpret_atom_evaluate_pure_expression_variable_in_space() {
1542 let space = space("$t (= (foo $a B) $a)");
1543 let result = call_interpret(space, &metta_atom("(eval (foo A $b))"));
1544 assert_eq!(result, vec![metta_atom("A")]);
1545 }
1546
1547 #[test]
1548 fn interpret_atom_evaluate_pure_expression_variable_name_conflict() {
1549 let space = space("(= (foo ($W)) True)");
1550 let result = call_interpret(space, &metta_atom("(eval (foo $W))"));
1551 assert_eq!(result[0], sym!("True"));
1552 }
1553
1554 #[test]
1555 fn interpret_atom_evaluate_grounded_expression() {
1556 let result = call_interpret(space(""), &expr!("eval" ({MulXUndefinedType(7)} {6})));
1557 assert_eq!(result, vec![expr!({42})]);
1558 }
1559
1560 #[test]
1561 fn interpret_atom_evaluate_grounded_expression_empty() {
1562 let result = call_interpret(space(""), &expr!("eval" ({ReturnNothing()} {6})));
1563 assert_eq!(result, vec![EMPTY_SYMBOL]);
1564 }
1565
1566 #[test]
1567 fn interpret_atom_evaluate_grounded_expression_noreduce() {
1568 let result = call_interpret(space(""), &expr!("eval" ({NonReducible()} {6})));
1569 assert_eq!(result, vec![NOT_REDUCIBLE_SYMBOL]);
1570 }
1571
1572 #[test]
1573 fn interpret_atom_evaluate_grounded_expression_incorrect_argument() {
1574 let result = call_interpret(space(""), &expr!("eval" ({IncorrectArgument()} {6.5})));
1575 assert_eq!(result, vec![NOT_REDUCIBLE_SYMBOL]);
1576 }
1577
1578 #[test]
1579 fn interpret_atom_evaluate_grounded_expression_error() {
1580 let result = call_interpret(space(""), &expr!("eval" ({ThrowError()} {"Test error"})));
1581 assert_eq!(result, vec![expr!("Error" ({ThrowError()} {"Test error"}) "Test error")]);
1582 }
1583
1584 #[test]
1585 fn interpret_atom_evaluate_variable_operation() {
1586 let space = space("(= (foo $a B) $a)");
1587 let result = call_interpret(space, &metta_atom("(eval ($a A $b))"));
1588 #[cfg(feature = "variable_operation")]
1589 assert_eq!(result, vec![metta_atom("A")]);
1590 #[cfg(not(feature = "variable_operation"))]
1591 assert_eq!(result, vec![NOT_REDUCIBLE_SYMBOL]);
1592 }
1593
1594 #[test]
1595 fn interpret_atom_evaluate_variable_via_call_direct_equality() {
1596 let space = space("
1597 (= (bar) (function (return ())))
1598 (= (foo $b) (function
1599 (chain (eval (bar)) $_
1600 (unify $b value
1601 (return ())
1602 (return (Error () \"Unexpected error\")) ))))");
1603 let result = call_interpret(space,
1604 &metta_atom("(chain (eval (foo $a)) $_ $a)"));
1605 assert_eq!(result[0], sym!("value"));
1606 }
1607
1608 #[test]
1609 fn interpret_atom_evaluate_variable_via_call_struct_equality() {
1610 let formal_arg_struct = space("
1611 (= (bar) (function (return ())))
1612 (= (foo ($b)) (function
1613 (chain (eval (bar)) $_
1614 (unify $b value
1615 (return ())
1616 (return (Error () \"Unexpected error\")) ))))");
1617 let result = call_interpret(formal_arg_struct,
1618 &metta_atom("(chain (eval (foo $a)) $_ $a)"));
1619 assert_eq!(result[0], expr!(("value")));
1620
1621 let actual_arg_struct = space("
1622 (= (bar) (function (return ())))
1623 (= (foo $b) (function
1624 (chain (eval (bar)) $_
1625 (unify $b (value)
1626 (return ())
1627 (return (Error () \"Unexpected error\")) ))))");
1628 let result = call_interpret(actual_arg_struct,
1629 &metta_atom("(chain (eval (foo ($a))) $_ $a)"));
1630 assert_eq!(result[0], sym!("value"));
1631 }
1632
1633 #[test]
1634 fn interpret_atom_evaluate_variable_operation_nested() {
1635 let space = space("(= ((baz $a) $b) ($a $b))");
1636 let result = call_interpret(space, &metta_atom("(eval (($a A) B))"));
1637 #[cfg(feature = "variable_operation")]
1638 assert_eq!(result, vec![metta_atom("(A B)")]);
1639 #[cfg(not(feature = "variable_operation"))]
1640 assert_eq!(result, vec![NOT_REDUCIBLE_SYMBOL]);
1641 }
1642
1643 #[test]
1644 fn interpret_atom_evaluate_non_executable_grounded_atom_on_a_first_position() {
1645 let space = space("(= ($x > $y) (> $x $y))");
1646
1647 let result = call_interpret(space, &expr!("eval" ({1} ">" {2})));
1648 assert_eq!(result, vec![expr!(">" {1} {2})]);
1649 }
1650
1651
1652 #[test]
1653 fn interpret_atom_chain_incorrect_args() {
1654 assert_eq!(call_interpret(space(""), &metta_atom("(chain n $v t o)")),
1655 vec![expr!("Error" ("chain" "n" v "t" "o") "expected: (chain <nested> (: <var> Variable) <templ>), found: (chain n $v t o)")]);
1656 assert_eq!(call_interpret(space(""), &metta_atom("(chain n v t)")),
1657 vec![expr!("Error" ("chain" "n" "v" "t") "expected: (chain <nested> (: <var> Variable) <templ>), found: (chain n v t)")]);
1658 assert_eq!(call_interpret(space(""), &metta_atom("(chain n $v)")),
1659 vec![expr!("Error" ("chain" "n" v) "expected: (chain <nested> (: <var> Variable) <templ>), found: (chain n $v)")]);
1660 }
1661
1662 #[test]
1663 fn interpret_atom_chain_atom() {
1664 let result = call_interpret(space(""), &expr!("chain" ("A" () {6} y) x ("bar" x)));
1665 assert_eq!(result, vec![expr!("bar" ("A" () {6} y))]);
1666 }
1667
1668
1669 #[test]
1670 fn interpret_atom_chain_evaluation() {
1671 let space = space("(= (foo $a B) $a)");
1672 let result = call_interpret(space, &metta_atom("(chain (eval (foo A $b)) $x (bar $x))"));
1673 assert_eq!(result, vec![metta_atom("(bar A)")]);
1674 }
1675
1676 #[test]
1677 fn interpret_atom_chain_nested_evaluation() {
1678 let space = space("(= (foo $a B) $a)");
1679 let result = call_interpret(space, &metta_atom("(chain (chain (eval (foo A $b)) $x (bar $x)) $y (baz $y))"));
1680 assert_eq!(result, vec![metta_atom("(baz (bar A))")]);
1681 }
1682
1683 #[test]
1684 fn interpret_atom_chain_nested_value() {
1685 let result = call_interpret(space(""), &metta_atom("(chain (chain A $x (bar $x)) $y (baz $y))"));
1686 assert_eq!(result, vec![metta_atom("(baz (bar A))")]);
1687 }
1688
1689 #[test]
1690 fn interpret_atom_chain_expression_non_determinism() {
1691 let space = space("
1692 (= (color) red)
1693 (= (color) green)
1694 (= (color) blue)
1695 ");
1696 let result = call_interpret(space, &metta_atom("(chain (eval (color)) $x (bar $x))"));
1697 assert_eq_no_order!(result, vec![
1698 metta_atom("(bar red)"),
1699 metta_atom("(bar green)"),
1700 metta_atom("(bar blue))"),
1701 ]);
1702 }
1703
1704 #[test]
1705 fn interpret_atom_chain_return() {
1706 let result = call_interpret(space(""), &metta_atom("(chain Empty $x (bar $x))"));
1707 assert_eq!(result, vec![metta_atom("(bar Empty)")]);
1708 }
1709
1710 #[test]
1711 fn interpret_atom_chain_keep_var_from_evaluated_part() {
1712 let result = call_interpret(space("(= (even 4) True)"), &metta_atom("(chain (eval (even $x)) $res (= (is-even $x) $res))"));
1713 assert_eq!(result, vec![metta_atom("(= (is-even 4) True)")]);
1714 }
1715
1716
1717 #[test]
1718 fn interpret_atom_unify_incorrect_args() {
1719 assert_eq!(call_interpret(space(""), &metta_atom("(unify a p t e o)")),
1720 vec![expr!("Error" ("unify" "a" "p" "t" "e" "o") "expected: (unify <atom> <pattern> <then> <else>), found: (unify a p t e o)")]);
1721 assert_eq!(call_interpret(space(""), &metta_atom("(unify a p t)")),
1722 vec![expr!("Error" ("unify" "a" "p" "t") "expected: (unify <atom> <pattern> <then> <else>), found: (unify a p t)")]);
1723 }
1724
1725 #[test]
1726 fn interpret_atom_unify_then() {
1727 let result = call_interpret(space(""), &metta_atom("(unify (A $b) ($a B) ($a $b) Empty)"));
1728 assert_eq!(result, vec![metta_atom("(A B)")]);
1729 }
1730
1731 #[test]
1732 fn interpret_atom_unify_else() {
1733 let result = call_interpret(space(""), &metta_atom("(unify (A $b C) ($a B D) ($a $b) Empty)"));
1734 assert_eq!(result, vec![EMPTY_SYMBOL]);
1735 }
1736
1737
1738 #[test]
1739 fn interpret_atom_decons_atom_incorrect_args() {
1740 assert_eq!(call_interpret(space(""), &metta_atom("(decons-atom a)")),
1741 vec![expr!("Error" ("decons-atom" "a") "expected: (decons-atom (: <expr> Expression)), found: (decons-atom a)")]);
1742 assert_eq!(call_interpret(space(""), &metta_atom("(decons-atom (a) (b))")),
1743 vec![expr!("Error" ("decons-atom" ("a") ("b")) "expected: (decons-atom (: <expr> Expression)), found: (decons-atom (a) (b))")]);
1744 assert_eq!(call_interpret(space(""), &metta_atom("(decons-atom)")),
1745 vec![expr!("Error" ("decons-atom") "expected: (decons-atom (: <expr> Expression)), found: (decons-atom)")]);
1746 }
1747
1748 #[test]
1749 fn interpret_atom_decons_atom_empty() {
1750 let result = call_interpret(space(""), &metta_atom("(decons-atom ())"));
1751 assert_eq!(result, vec![expr!("Error" ("decons-atom" ()) "expected: (decons-atom (: <expr> Expression)), found: (decons-atom ())")]);
1752 }
1753
1754 #[test]
1755 fn interpret_atom_decons_atom_single() {
1756 let result = call_interpret(space(""), &metta_atom("(decons-atom (a))"));
1757 assert_eq!(result, vec![metta_atom("(a ())")]);
1758 }
1759
1760 #[test]
1761 fn interpret_atom_decons_atom_list() {
1762 let result = call_interpret(space(""), &metta_atom("(decons-atom (a b c))"));
1763 assert_eq!(result, vec![metta_atom("(a (b c))")]);
1764 }
1765
1766
1767 #[test]
1768 fn interpret_atom_cons_atom_incorrect_args() {
1769 assert_eq!(call_interpret(space(""), &metta_atom("(cons-atom a (e) o)")),
1770 vec![expr!("Error" ("cons-atom" "a" ("e") "o") "expected: (cons-atom <head> (: <tail> Expression)), found: (cons-atom a (e) o)")]);
1771 assert_eq!(call_interpret(space(""), &metta_atom("(cons-atom a e)")),
1772 vec![expr!("Error" ("cons-atom" "a" "e") "expected: (cons-atom <head> (: <tail> Expression)), found: (cons-atom a e)")]);
1773 assert_eq!(call_interpret(space(""), &metta_atom("(cons-atom a)")),
1774 vec![expr!("Error" ("cons-atom" "a") "expected: (cons-atom <head> (: <tail> Expression)), found: (cons-atom a)")]);
1775 }
1776
1777 #[test]
1778 fn interpret_atom_cons_atom_empty() {
1779 let result = call_interpret(space(""), &metta_atom("(cons-atom a ())"));
1780 assert_eq!(result, vec![metta_atom("(a)")]);
1781 }
1782
1783 #[test]
1784 fn interpret_atom_cons_atom_single() {
1785 let result = call_interpret(space(""), &metta_atom("(cons-atom a (b))"));
1786 assert_eq!(result, vec![metta_atom("(a b)")]);
1787 }
1788
1789 #[test]
1790 fn interpret_atom_cons_atom_list() {
1791 let result = call_interpret(space(""), &metta_atom("(cons-atom a (b c))"));
1792 assert_eq!(result, vec![metta_atom("(a b c)")]);
1793 }
1794
1795
1796 #[test]
1797 fn test_superpose_bind() {
1798 let vars: Variables = [ "a", "b", "c" ].into_iter().map(VariableAtom::new).collect();
1799 let atom = Atom::expr([Atom::sym("superpose-bind"),
1800 Atom::expr([atom_bindings_into_atom(expr!("foo" a b), bind!{ a: expr!("A"), c: expr!("C") })])]);
1801 let stack = Stack{ prev: None, atom, ret: no_handler, finished: false, vars: vars.clone(), depth: 1 };
1802
1803 let result = superpose_bind(stack, bind!{ b: expr!("B"), d: expr!("D") });
1804
1805 assert_eq!(result, vec![InterpretedAtom(
1806 Stack{ prev: None, atom: expr!("foo" a b), ret: no_handler, finished: true, vars: Variables::new(), depth: 1 },
1807 bind!{ a: expr!("A"), b: expr!("B"), c: expr!("C"), d: expr!("D") }
1808 )]);
1809 }
1810
1811 #[test]
1812 fn interpret_function_error_on_no_return() {
1813 let result = call_interpret(space(""), &metta_atom("(function (SomeValue))"));
1814 assert_eq!(result, vec![metta_atom("(Error (SomeValue) NoReturn)")]);
1815
1816 let result = call_interpret(space("
1817 (= (foo) (function (SomeValue)))
1818 "), &metta_atom("(eval (foo))"));
1819 assert_eq!(result, vec![metta_atom("(Error (foo) NoReturn)")]);
1820 }
1821
1822 #[test]
1823 fn metta_turing_machine() {
1824 let space = space("
1825 (= (tm $rule $state $tape)
1826 (function (eval (tm-body $rule $state $tape))) )
1827
1828 (= (tm-body $rule $state $tape)
1829 (unify $state HALT
1830 (return $tape)
1831 (chain (eval (read $tape)) $char
1832 (chain (eval ($rule $state $char)) $res
1833 (unify $res ($next-state $next-char $dir)
1834 (chain (eval (move $tape $next-char $dir)) $next-tape
1835 (eval (tm-body $rule $next-state $next-tape)) )
1836 (return (Error (tm-body $rule $state $tape) \"Incorrect state\")) )))))
1837
1838 (= (read ($head $hole $tail)) $hole)
1839
1840 (= (move ($head $hole $tail) $char N) ($head $char $tail))
1841 (= (move ($head $hole $tail) $char L) (function
1842 (chain (cons-atom $char $head) $next-head
1843 (chain (decons-atom $tail) $list
1844 (unify $list ($next-hole $next-tail)
1845 (return ($next-head $next-hole $next-tail))
1846 (return ($next-head 0 ())) )))))
1847 (= (move ($head $hole $tail) $char R) (function
1848 (chain (cons-atom $char $tail) $next-tail
1849 (chain (decons-atom $head) $list
1850 (unify $list ($next-hole $next-head)
1851 (return ($next-head $next-hole $next-tail))
1852 (return (() 0 $next-tail)) )))))
1853
1854 (= (busy-beaver A 0) (B 1 R))
1855 (= (busy-beaver A 1) (C 1 L))
1856
1857 (= (busy-beaver B 0) (A 1 L))
1858 (= (busy-beaver B 1) (B 1 R))
1859
1860 (= (busy-beaver C 0) (B 1 L))
1861 (= (busy-beaver C 1) (HALT 1 N))
1862
1863 ");
1864 let result = interpret(space, &metta_atom("(eval (tm busy-beaver A (() 0 ())))"));
1865 assert_eq!(result, Ok(vec![metta_atom("((1 1) 1 (1 1 1))")]));
1866 }
1867
1868 #[test]
1869 fn interpret_minimal_metta_smoketest() {
1870 let space = space("
1871 (= (foo $a B) $a)
1872 (= (fu $x) (function (chain (eval (foo $x B)) $r (return $r))))
1873 (= (color) red)
1874 (= (color) green)
1875 (= (color) blue)
1876 ");
1877 let result = interpret(space.clone(), &metta_atom("(chain (chain A $x $x) $y $y)"));
1878 assert_eq!(result, Ok(vec![metta_atom("A")]));
1879 let result = interpret(space.clone(), &metta_atom("(chain (chain (eval (foo A $b)) $x (bar $x)) $y (baz $y))"));
1880 assert_eq!(result, Ok(vec![metta_atom("(baz (bar A))")]));
1881 let result = interpret(space.clone(), &metta_atom("(chain (chain (eval (fu A)) $x (bar $x)) $y (baz $y))"));
1882 assert_eq!(result, Ok(vec![metta_atom("(baz (bar A))")]));
1883 let result = interpret(space.clone(), &metta_atom("(unify (A $b) ($a B) ($a $b) Empty)"));
1884 assert_eq!(result, Ok(vec![metta_atom("(A B)")]));
1885 let result = interpret(space.clone(), &metta_atom("(decons-atom (a b c))"));
1886 assert_eq!(result, Ok(vec![metta_atom("(a (b c))")]));
1887 let result = interpret(space.clone(), &metta_atom("(cons-atom a (b c))"));
1888 assert_eq!(result, Ok(vec![metta_atom("(a b c)")]));
1889 let result = interpret(space.clone(), &metta_atom("(chain (collapse-bind (eval (color))) $collapsed (superpose-bind $collapsed))")).unwrap();
1890 assert_eq_no_order!(result, vec![metta_atom("red"), metta_atom("green"), metta_atom("blue")]);
1891 let result = interpret(space.clone(), &metta_atom("((P $a B) $a)"));
1892 assert_eq!(result, Ok(vec![metta_atom("((P $a B) $a)")]));
1893 let result = interpret(space.clone(), &metta_atom("(collapse-bind (eval (color)))")).unwrap();
1894 assert_eq!(result.len(), 1);
1895 assert_eq_no_order!(atom_as_slice(&result[0]).unwrap(), [
1896 atom_bindings_into_atom(expr!("red"), bind!{}),
1897 atom_bindings_into_atom(expr!("green"), bind!{}),
1898 atom_bindings_into_atom(expr!("blue"), bind!{})
1899 ]);
1900 }
1901
1902 fn space(text: &str) -> DynSpace {
1903 metta_space(text)
1904 }
1905
1906 fn call_interpret(space: DynSpace, atom: &Atom) -> Vec<Atom> {
1907 let _ = env_logger::builder().is_test(true).try_init();
1908 let result = interpret(space, atom);
1909 assert!(result.is_ok());
1910 result.unwrap()
1911 }
1912
1913 #[derive(PartialEq, Clone, Debug)]
1914 struct ThrowError();
1915
1916 impl Grounded for ThrowError {
1917 fn type_(&self) -> Atom {
1918 expr!("->" "&str" "Error")
1919 }
1920 fn as_execute(&self) -> Option<&dyn CustomExecute> {
1921 Some(self)
1922 }
1923 }
1924
1925 impl CustomExecute for ThrowError {
1926 fn execute(&self, args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
1927 Err((*args[0].as_gnd::<&str>().unwrap()).into())
1928 }
1929 }
1930
1931 impl Display for ThrowError {
1932 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1933 write!(f, "throw-error")
1934 }
1935 }
1936
1937 #[derive(PartialEq, Clone, Debug)]
1938 struct NonReducible();
1939
1940 impl Grounded for NonReducible {
1941 fn type_(&self) -> Atom {
1942 expr!("->" "u32" "u32")
1943 }
1944 fn as_execute(&self) -> Option<&dyn CustomExecute> {
1945 Some(self)
1946 }
1947 }
1948
1949 impl CustomExecute for NonReducible {
1950 fn execute(&self, _args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
1951 Err(ExecError::NoReduce)
1952 }
1953 }
1954
1955 impl Display for NonReducible {
1956 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1957 write!(f, "non-reducible")
1958 }
1959 }
1960
1961 #[derive(PartialEq, Clone, Debug)]
1962 struct IncorrectArgument();
1963
1964 impl Grounded for IncorrectArgument {
1965 fn type_(&self) -> Atom {
1966 expr!("->" "u32" "u32")
1967 }
1968 fn as_execute(&self) -> Option<&dyn CustomExecute> {
1969 Some(self)
1970 }
1971 }
1972
1973 impl CustomExecute for IncorrectArgument {
1974 fn execute(&self, _args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
1975 Err(ExecError::IncorrectArgument)
1976 }
1977 }
1978
1979 impl Display for IncorrectArgument {
1980 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1981 write!(f, "incorrect-argument")
1982 }
1983 }
1984
1985 #[derive(PartialEq, Clone, Debug)]
1986 struct MulXUndefinedType(i32);
1987
1988 impl Grounded for MulXUndefinedType {
1989 fn type_(&self) -> Atom {
1990 ATOM_TYPE_UNDEFINED
1991 }
1992 fn as_execute(&self) -> Option<&dyn CustomExecute> {
1993 Some(self)
1994 }
1995 }
1996
1997 impl CustomExecute for MulXUndefinedType {
1998 fn execute(&self, args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
1999 Ok(vec![Atom::value(self.0 * args.get(0).unwrap().as_gnd::<i32>().unwrap())])
2000 }
2001 }
2002
2003 impl Display for MulXUndefinedType {
2004 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2005 write!(f, "x{}", self.0)
2006 }
2007 }
2008
2009 #[derive(PartialEq, Clone, Debug)]
2010 struct ReturnNothing();
2011
2012 impl Grounded for ReturnNothing {
2013 fn type_(&self) -> Atom {
2014 ATOM_TYPE_UNDEFINED
2015 }
2016 fn as_execute(&self) -> Option<&dyn CustomExecute> {
2017 Some(self)
2018 }
2019 }
2020
2021 impl CustomExecute for ReturnNothing {
2022 fn execute(&self, _args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
2023 Ok(vec![])
2024 }
2025 }
2026
2027 impl Display for ReturnNothing {
2028 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2029 write!(f, "return-nothing")
2030 }
2031 }
2032
2033 #[test]
2034 fn interpret_duplicated_types() {
2035 let space = space("
2036 (: foo (-> A A))
2037 (: foo (-> A A))
2038 (: foo (-> Atom A))
2039 (: a A)
2040 (= (foo $x) a)
2041 ");
2042 let result = interpret(space.clone(), &Atom::expr([METTA_SYMBOL, expr!("foo" "a"), ATOM_TYPE_UNDEFINED, Atom::gnd(space)]));
2043 assert_eq!(result, Ok(vec![metta_atom("a")]));
2044 }
2045
2046 #[test]
2047 fn run_metta_using_context() {
2048 let outer = space("");
2049 let nested = space("
2050 (= (foo $x) $x)
2051 ");
2052 let result = interpret(outer, &Atom::expr([METTA_SYMBOL, expr!("foo" "a"), ATOM_TYPE_UNDEFINED, Atom::gnd(nested)]));
2053 assert_eq!(result, Ok(vec![metta_atom("a")]));
2054 }
2055
2056 #[test]
2057 fn interpret_stop_evaluation() {
2058 let space = space("
2059 (= (bar) X)
2060 (= (foo) (bar))
2061
2062 (: q (-> Atom Atom))
2063 (= (q $a) $a)
2064 (= (e $a) $a)
2065 ");
2066 let result = interpret(space.clone(), &Atom::expr([METTA_SYMBOL, expr!("q" ("foo")), ATOM_TYPE_UNDEFINED, Atom::gnd(space.clone())]));
2067 assert_eq!(result, Ok(vec![Atom::expr([Atom::sym("foo")])]));
2068 let result = interpret(space.clone(), &Atom::expr([METTA_SYMBOL, expr!("e" ("q" ("foo"))), ATOM_TYPE_UNDEFINED, Atom::gnd(space)]));
2069 assert_eq!(result, Ok(vec![Atom::sym("X")]));
2070 }
2071
2072 #[test]
2073 fn interpret_context_space() {
2074 let space = space("");
2075
2076 let result = interpret(space.clone(), &Atom::expr([CONTEXT_SPACE_SYMBOL]));
2077 assert_eq!(result, Ok(vec![Atom::gnd(space)]));
2078 }
2079
2080 #[test]
2081 fn interpret_variable_substitution() {
2082 let space = space("
2083 (: unify (-> Atom Atom Atom Atom %Undefined%))
2084 (= (foo) (bar))
2085 (= (bar) a)
2086 ");
2087 let result = interpret(space.clone(),
2088 &Atom::expr([METTA_SYMBOL,
2089 Atom::expr([UNIFY_SYMBOL, Atom::gnd(space.clone()), Atom::expr([EQUAL_SYMBOL, Atom::expr([Atom::sym("foo")]), Atom::var("x")]), Atom::var("x"), EMPTY_SYMBOL]),
2090 ATOM_TYPE_UNDEFINED,
2091 Atom::gnd(space)]));
2092
2093 assert_eq!(result, Ok(vec![metta_atom("a")]));
2094 }
2095
2096 #[test]
2097 fn interpret_variable_substitution_after_superpose() {
2098 let space = space("
2099 (= (foo a) xa)
2100 (= (foo b) xb)
2101 ");
2102 let result = interpret(space.clone(), &metta_atom("
2103 (chain (collapse-bind (eval (foo $a))) $collapsed
2104 (chain (superpose-bind $collapsed) $x
2105 ($x $a)))
2106 ")).unwrap();
2107 assert_eq_no_order!(result, vec![metta_atom("(xa a)"), metta_atom("(xb b)")]);
2108 }
2109
2110 #[derive(PartialEq, Clone, Debug)]
2111 struct EvalCounter(Rc<RefCell<i64>>);
2112
2113 impl Grounded for EvalCounter {
2114 fn type_(&self) -> Atom {
2115 expr!("->" ("->"))
2116 }
2117 fn as_execute(&self) -> Option<&dyn CustomExecute> {
2118 Some(self)
2119 }
2120 }
2121
2122 impl CustomExecute for EvalCounter {
2123 fn execute(&self, _args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
2124 *self.0.borrow_mut() += 1;
2125 Err(ExecError::NoReduce)
2126 }
2127 }
2128
2129 impl Display for EvalCounter {
2130 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2131 write!(f, "increment-self")
2132 }
2133 }
2134
2135 #[test]
2136 fn interpret_evaluate_once() {
2137 let counter = EvalCounter(Rc::new(RefCell::new(0)));
2138 let space = space("
2139 (= (one $x) (two $x))
2140 (= (two $x) ok)
2141 ");
2142 let result = interpret(space.clone(), &Atom::expr([METTA_SYMBOL, expr!("one" ({counter.clone()})), ATOM_TYPE_UNDEFINED, Atom::gnd(space.clone())]));
2143 assert_eq!(result, Ok(vec![Atom::sym("ok")]));
2144 assert_eq!(*counter.0.borrow(), 1);
2145 }
2146
2147 #[test]
2148 fn type_check_returned_value() {
2149 let space = space("
2150 (: foo (-> Number))
2151 (= (foo) 1)
2152 (: bar (-> Bool))
2153 (= (bar) (foo))
2154 ");
2155 let result = interpret(space.clone(), &metta!((metta (bar) %Undefined% {space.clone()})));
2156 assert_eq!(result, Ok(vec![metta!((Error (foo) (BadType Bool Number)))]));
2157 }
2158
2159 #[test]
2160 fn test_incorrect_number_of_arguments_issue_1037() {
2161 let space = space("
2162 (: a A)
2163 (: b B)
2164 (: foo (-> A B))
2165 ");
2166
2167 let result = interpret(space.clone(), &metta!((metta (foo b c) %Undefined% {space.clone()})));
2168 assert_eq!(result, Ok(vec![metta!((Error (foo b c) IncorrectNumberOfArguments))]));
2169 }
2170}