ravenrs_sheet/calc/eval/
lambda.rs1use super::MAX_LAMBDA_CALLS;
2use super::array::{broadcast_len, single};
3use super::{Array, CellError, Ev, Evaluator, Expr, Lambda, MAX_CELLS, Value, err};
4use std::sync::Arc;
5
6impl<'h> Evaluator<'h> {
7 pub fn apply_lambda(&mut self, l: &Lambda, args: &[Expr]) -> Ev {
8 let positions_ok = args.len() == l.params.len() || (args.is_empty() && l.params.len() == 1);
13 if !positions_ok {
14 return err(CellError::Value);
15 }
16 let mut bound = Vec::with_capacity(l.params.len());
17 for (i, p) in l.params.iter().enumerate() {
18 let v = match args.get(i) {
19 Some(Expr::Missing) | None => Ev::V(Value::Empty),
20 Some(e) => self.eval(e),
21 };
22 bound.push((p.clone(), v));
23 }
24 self.call_lambda_values(l, bound)
25 }
26
27 pub(super) fn call_lambda_values(&mut self, l: &Lambda, bound: Vec<(String, Ev)>) -> Ev {
28 if self.calls >= MAX_LAMBDA_CALLS {
29 return err(CellError::Num);
30 }
31 self.fuel = match self.fuel.checked_sub(1) {
35 Some(f) => f,
36 None => return err(CellError::Calc),
37 };
38 self.calls += 1;
39 let saved = std::mem::replace(&mut self.env, l.env.clone());
40 self.env.extend(bound);
41 let r = self.eval(&l.body);
42 self.env = saved;
43 self.calls -= 1;
44 r
45 }
46
47 pub(super) fn let_(&mut self, args: &[Expr]) -> Ev {
48 if args.len() < 3 || args.len().is_multiple_of(2) {
49 return err(CellError::Value);
50 }
51 let base = self.env.len();
52 for pair in args[..args.len() - 1].chunks(2) {
53 let [Expr::Name(n), v] = pair else {
54 self.env.truncate(base);
55 return err(CellError::Value);
56 };
57 let val = self.eval(v);
58 self.env.push((n.clone(), val));
59 }
60 let r = match args.last() {
61 Some(body) => self.eval(body),
62 None => err(CellError::Value),
63 };
64 self.env.truncate(base);
65 r
66 }
67
68 fn lambda_arg(&mut self, e: Option<&Expr>, arity: usize) -> Option<Arc<Lambda>> {
71 if let Some(f) = e.and_then(|x| self.function_by_name(x)) {
72 let params: Vec<String> = (0..arity).map(|i| format!("_xleta.{i}")).collect();
73 let body = Expr::Call(f, params.iter().map(|p| Expr::Name(p.clone())).collect());
74 return Some(Arc::new(Lambda { params, body, env: Vec::new() }));
75 }
76 match e.map(|x| self.eval(x)) {
77 Some(Ev::L(l)) => Some(l),
78 _ => None,
79 }
80 }
81
82 pub(super) fn higher_order(&mut self, name: &str, args: &[Expr]) -> Ev {
83 let as_array = |v: Value| -> Arc<Array> {
84 match v {
85 Value::Array(a) => a,
86 other => Arc::new(Array::scalar(other)),
87 }
88 };
89 match name {
90 "MAP" => {
91 if args.len() < 2 {
92 return err(CellError::Value);
93 }
94 let Some(l) = self.lambda_arg(args.last(), args.len() - 1) else { return err(CellError::Value) };
95 let arrays: Vec<Arc<Array>> = args[..args.len() - 1].iter().map(|a| as_array(self.value(a))).collect();
96 let rows = arrays.iter().map(|a| a.rows).max().unwrap_or(1);
97 let cols = arrays.iter().map(|a| a.cols).max().unwrap_or(1);
98 let Some(n) = broadcast_len(rows, cols) else { return err(CellError::Num) };
99 if l.params.len() != arrays.len() {
101 return err(CellError::Value);
102 }
103 let mut out = Vec::with_capacity(n);
104 for r in 0..rows {
105 for c in 0..cols {
106 let bound = l.params.iter().zip(arrays.iter()).map(|(p, a)| (p.clone(), Ev::V(a.get_broadcast(r, c)))).collect();
107 let v = self.call_lambda_values(&l, bound);
108 let Some(one) = single(self.deref(v)) else { return err(CellError::Calc) };
109 out.push(one);
110 }
111 }
112 Ev::V(Array::new(rows, cols, out).map(Value::from).unwrap_or(Value::Error(CellError::Calc)))
113 }
114 "REDUCE" | "SCAN" => {
115 if args.len() != 3 {
116 return err(CellError::Value);
117 }
118 let mut acc = self.value(&args[0]);
119 let arr = as_array(self.value(&args[1]));
120 let Some(l) = self.lambda_arg(args.get(2), 2) else { return err(CellError::Value) };
121 if l.params.len() != 2 {
122 return err(CellError::Value);
123 }
124 let mut scan = Vec::with_capacity(arr.data.len());
125 for v in arr.data.iter() {
126 let bound = vec![(l.params[0].clone(), Ev::V(acc.clone())), (l.params[1].clone(), Ev::V(v.clone()))];
127 let r = self.call_lambda_values(&l, bound);
128 acc = self.deref(r);
129 if name == "SCAN" {
130 let Some(one) = single(acc.clone()) else { return err(CellError::Calc) };
131 scan.push(one);
132 }
133 }
134 if name == "SCAN" {
135 Ev::V(Array::new(arr.rows, arr.cols, scan).map(Value::from).unwrap_or(Value::Error(CellError::Calc)))
136 } else {
137 Ev::V(acc)
138 }
139 }
140 "BYROW" | "BYCOL" => {
141 if args.len() != 2 {
142 return err(CellError::Value);
143 }
144 let arr = as_array(self.value(&args[0]));
145 let Some(l) = self.lambda_arg(args.get(1), 1) else { return err(CellError::Value) };
146 let Some(p) = l.params.first().cloned() else { return err(CellError::Value) };
147 if l.params.len() != 1 {
148 return err(CellError::Value);
149 }
150 let by_row = name == "BYROW";
151 let n = if by_row { arr.rows } else { arr.cols };
152 let mut out = Vec::with_capacity(n);
153 for i in 0..n {
154 let slice: Vec<Value> = if by_row {
155 (0..arr.cols).map(|c| arr.get(i, c).cloned().unwrap_or_default()).collect()
156 } else {
157 (0..arr.rows).map(|r| arr.get(r, i).cloned().unwrap_or_default()).collect()
158 };
159 let a = if by_row { Array::row(slice) } else { Array::column(slice) };
160 let r = self.call_lambda_values(&l, vec![(p.clone(), Ev::V(a.into()))]);
161 let Some(one) = single(self.deref(r)) else { return err(CellError::Calc) };
162 out.push(one);
163 }
164 let a = if by_row { Array::column(out) } else { Array::row(out) };
165 Ev::V(a.into())
166 }
167 "MAKEARRAY" => {
168 if args.len() != 3 {
169 return err(CellError::Value);
170 }
171 let (rows, cols) = match (self.arg_num(args, 0, 0.0), self.arg_num(args, 1, 0.0)) {
172 (Ok(r), Ok(c)) => (r.trunc(), c.trunc()),
173 (Err(e), _) | (_, Err(e)) => return err(e),
174 };
175 if rows < 1.0 || cols < 1.0 || rows * cols > MAX_CELLS as f64 {
176 return err(CellError::Value);
177 }
178 let Some(l) = self.lambda_arg(args.get(2), 2) else { return err(CellError::Value) };
179 if l.params.len() != 2 {
180 return err(CellError::Value);
181 }
182 let (rows, cols) = (rows as usize, cols as usize);
183 let mut out = Vec::with_capacity(rows * cols);
184 for r in 0..rows {
185 for c in 0..cols {
186 let bound = vec![
187 (l.params[0].clone(), Ev::V(Value::number(r as f64 + 1.0))),
188 (l.params[1].clone(), Ev::V(Value::number(c as f64 + 1.0))),
189 ];
190 let v = self.call_lambda_values(&l, bound);
191 let Some(one) = single(self.deref(v)) else { return err(CellError::Calc) };
192 out.push(one);
193 }
194 }
195 Ev::V(Array::new(rows, cols, out).map(Value::from).unwrap_or(Value::Error(CellError::Calc)))
196 }
197 _ => err(CellError::Name),
198 }
199 }
200}