1use crate::allocator::{Allocator, NodePtr, SExp};
2use crate::cost::Cost;
3use crate::error::{EvalErr, Result};
4use crate::op_utils::{first, get_args, nilp, rest};
5use crate::reduction::{Reduction, Response};
6
7const FIRST_COST: Cost = 30;
8const IF_COST: Cost = 33;
9const CONS_COST: Cost = 50;
11const REST_COST: Cost = 30;
14const LISTP_COST: Cost = 19;
15const EQ_BASE_COST: Cost = 117;
16const EQ_COST_PER_BYTE: Cost = 1;
17
18pub fn op_if(a: &mut Allocator, input: NodePtr, _max_cost: Cost) -> Response {
19 let [cond, affirmative, negative] = get_args::<3>(a, input, "i")?;
20 let chosen_node = if nilp(a, cond) { negative } else { affirmative };
21 Ok(Reduction(IF_COST, chosen_node))
22}
23
24pub fn op_cons(a: &mut Allocator, input: NodePtr, _max_cost: Cost) -> Response {
25 let [n1, n2] = get_args::<2>(a, input, "c")?;
26 let r = a.new_pair(n1, n2)?;
27 Ok(Reduction(CONS_COST, r))
28}
29
30pub fn op_first(a: &mut Allocator, input: NodePtr, _max_cost: Cost) -> Response {
31 let [n] = get_args::<1>(a, input, "f")?;
32 Ok(Reduction(FIRST_COST, first(a, n)?))
33}
34
35pub fn op_rest(a: &mut Allocator, input: NodePtr, _max_cost: Cost) -> Response {
36 let [n] = get_args::<1>(a, input, "r")?;
37 Ok(Reduction(REST_COST, rest(a, n)?))
38}
39
40pub fn op_listp(a: &mut Allocator, input: NodePtr, _max_cost: Cost) -> Response {
41 let [n] = get_args::<1>(a, input, "l")?;
42 match a.sexp(n) {
43 SExp::Pair(_, _) => Ok(Reduction(LISTP_COST, a.one())),
44 _ => Ok(Reduction(LISTP_COST, a.nil())),
45 }
46}
47
48pub fn op_raise(a: &mut Allocator, input: NodePtr, _max_cost: Cost) -> Response {
49 let throw_value = if let Ok([value]) = get_args::<1>(a, input, "") {
54 match a.sexp(value) {
55 SExp::Atom => value,
56 _ => input,
57 }
58 } else {
59 input
60 };
61
62 Err(EvalErr::Raise(throw_value))
63}
64
65fn ensure_atom(a: &Allocator, n: NodePtr, op: &str) -> Result<()> {
66 if let SExp::Atom = a.sexp(n) {
67 Ok(())
68 } else {
69 Err(EvalErr::InvalidOpArg(n, format!("{op} used on list")))?
70 }
71}
72
73pub fn op_eq(a: &mut Allocator, input: NodePtr, _max_cost: Cost) -> Response {
74 let [s0, s1] = get_args::<2>(a, input, "=")?;
75 ensure_atom(a, s0, "=")?;
76 ensure_atom(a, s1, "=")?;
77 let eq = a.atom_eq(s0, s1);
78 let cost = EQ_BASE_COST + (a.atom_len(s0) as Cost + a.atom_len(s1) as Cost) * EQ_COST_PER_BYTE;
79 Ok(Reduction(cost, if eq { a.one() } else { a.nil() }))
80}