1use std::sync::Arc;
21
22use tatara_lisp::Span;
23
24use crate::error::{EvalError, Result};
25use crate::value::Value;
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29pub enum Arity {
30 Exact(usize),
31 AtLeast(usize),
32 Range(usize, usize),
33 Any,
34}
35
36impl Arity {
37 pub fn check(&self, got: usize) -> std::result::Result<(), String> {
39 match *self {
40 Self::Exact(n) if got == n => Ok(()),
41 Self::Exact(n) => Err(format!("expected exactly {n}, got {got}")),
42 Self::AtLeast(n) if got >= n => Ok(()),
43 Self::AtLeast(n) => Err(format!("expected at least {n}, got {got}")),
44 Self::Range(lo, hi) if got >= lo && got <= hi => Ok(()),
45 Self::Range(lo, hi) => Err(format!("expected {lo}..={hi}, got {got}")),
46 Self::Any => Ok(()),
47 }
48 }
49}
50
51pub trait NativeCallable<H>: Send + Sync + 'static {
61 fn call(&self, args: &[Value], host: &mut H, call_span: Span) -> Result<Value>;
62}
63
64impl<H, F> NativeCallable<H> for F
65where
66 F: Fn(&[Value], &mut H, Span) -> Result<Value> + Send + Sync + 'static,
67{
68 fn call(&self, args: &[Value], host: &mut H, call_span: Span) -> Result<Value> {
69 (self)(args, host, call_span)
70 }
71}
72
73pub trait HigherOrderCallable<H>: Send + Sync + 'static {
77 fn call(
78 &self,
79 args: &[Value],
80 host: &mut H,
81 caller: &Caller<H>,
82 call_span: Span,
83 ) -> Result<Value>;
84}
85
86impl<H, F> HigherOrderCallable<H> for F
87where
88 F: Fn(&[Value], &mut H, &Caller<H>, Span) -> Result<Value> + Send + Sync + 'static,
89{
90 fn call(
91 &self,
92 args: &[Value],
93 host: &mut H,
94 caller: &Caller<H>,
95 call_span: Span,
96 ) -> Result<Value> {
97 (self)(args, host, caller, call_span)
98 }
99}
100
101pub struct Caller<'a, H> {
111 pub(crate) registry: &'a FnRegistry<H>,
112 pub(crate) expander: &'a tatara_lisp::SpannedExpander,
113}
114
115impl<'a, H: 'static> Caller<'a, H> {
116 pub fn apply_value(
121 &self,
122 callee: &Value,
123 args: Vec<Value>,
124 host: &mut H,
125 call_span: Span,
126 ) -> Result<Value> {
127 crate::eval::apply_external(callee, args, call_span, self.registry, self.expander, host)
128 }
129
130 pub fn expander(&self) -> &tatara_lisp::SpannedExpander {
133 self.expander
134 }
135
136 pub fn call1(&self, f: &Value, x: Value, host: &mut H, span: Span) -> Result<Value> {
139 self.apply_value(f, vec![x], host, span)
140 }
141
142 pub fn call2(&self, f: &Value, a: Value, b: Value, host: &mut H, span: Span) -> Result<Value> {
144 self.apply_value(f, vec![a, b], host, span)
145 }
146}
147
148pub(crate) enum FnImpl<H> {
154 Native(Arc<dyn NativeCallable<H>>),
155 Higher(Arc<dyn HigherOrderCallable<H>>),
156}
157
158impl<H> Clone for FnImpl<H> {
159 fn clone(&self) -> Self {
160 match self {
161 Self::Native(f) => Self::Native(Arc::clone(f)),
162 Self::Higher(f) => Self::Higher(Arc::clone(f)),
163 }
164 }
165}
166
167pub(crate) struct FnRegistry<H> {
169 entries: Vec<FnEntry<H>>,
170}
171
172pub(crate) struct FnEntry<H> {
173 pub name: Arc<str>,
174 #[allow(dead_code)]
177 pub arity: Arity,
178 pub callable: FnImpl<H>,
179}
180
181impl<H> Default for FnRegistry<H> {
182 fn default() -> Self {
183 Self {
184 entries: Vec::new(),
185 }
186 }
187}
188
189impl<H> FnRegistry<H> {
190 pub(crate) fn new() -> Self {
191 Self::default()
192 }
193
194 pub(crate) fn insert(&mut self, entry: FnEntry<H>) {
195 if let Some(slot) = self.entries.iter_mut().find(|e| e.name == entry.name) {
197 *slot = entry;
198 } else {
199 self.entries.push(entry);
200 }
201 }
202
203 pub(crate) fn lookup(&self, name: &str) -> Option<&FnEntry<H>> {
204 self.entries.iter().find(|e| &*e.name == name)
205 }
206}
207
208pub trait FromValue: Sized {
214 fn from_value(v: &Value, at: Span) -> Result<Self>;
215}
216
217impl FromValue for Value {
218 fn from_value(v: &Value, _at: Span) -> Result<Self> {
219 Ok(v.clone())
220 }
221}
222
223impl FromValue for i64 {
224 fn from_value(v: &Value, at: Span) -> Result<Self> {
225 match v {
226 Value::Int(n) => Ok(*n),
227 other => Err(EvalError::type_mismatch("integer", other.type_name(), at)),
228 }
229 }
230}
231
232impl FromValue for f64 {
233 fn from_value(v: &Value, at: Span) -> Result<Self> {
234 match v {
235 Value::Int(n) => Ok(*n as f64),
236 Value::Float(n) => Ok(*n),
237 other => Err(EvalError::type_mismatch("number", other.type_name(), at)),
238 }
239 }
240}
241
242impl FromValue for bool {
243 fn from_value(v: &Value, at: Span) -> Result<Self> {
244 match v {
245 Value::Bool(b) => Ok(*b),
246 other => Err(EvalError::type_mismatch("bool", other.type_name(), at)),
247 }
248 }
249}
250
251impl FromValue for String {
252 fn from_value(v: &Value, at: Span) -> Result<Self> {
253 match v {
254 Value::Str(s) => Ok(s.to_string()),
255 other => Err(EvalError::type_mismatch("string", other.type_name(), at)),
256 }
257 }
258}
259
260impl FromValue for Arc<str> {
261 fn from_value(v: &Value, at: Span) -> Result<Self> {
262 match v {
263 Value::Str(s) => Ok(s.clone()),
264 Value::Symbol(s) => Ok(s.clone()),
265 Value::Keyword(s) => Ok(s.clone()),
266 other => Err(EvalError::type_mismatch(
267 "string/symbol",
268 other.type_name(),
269 at,
270 )),
271 }
272 }
273}
274
275impl FromValue for Vec<Value> {
276 fn from_value(v: &Value, at: Span) -> Result<Self> {
277 match v {
278 Value::Nil => Ok(Vec::new()),
279 Value::List(xs) => Ok(xs.as_ref().clone()),
280 other => Err(EvalError::type_mismatch("list", other.type_name(), at)),
281 }
282 }
283}
284
285impl<T: FromValue> FromValue for Option<T> {
286 fn from_value(v: &Value, at: Span) -> Result<Self> {
287 match v {
288 Value::Nil => Ok(None),
289 other => T::from_value(other, at).map(Some),
290 }
291 }
292}
293
294pub trait IntoValue {
299 fn into_value(self) -> Value;
300}
301
302impl IntoValue for Value {
303 fn into_value(self) -> Value {
304 self
305 }
306}
307
308impl IntoValue for () {
309 fn into_value(self) -> Value {
310 Value::Nil
311 }
312}
313
314impl IntoValue for bool {
315 fn into_value(self) -> Value {
316 Value::Bool(self)
317 }
318}
319
320impl IntoValue for i64 {
321 fn into_value(self) -> Value {
322 Value::Int(self)
323 }
324}
325
326impl IntoValue for f64 {
327 fn into_value(self) -> Value {
328 Value::Float(self)
329 }
330}
331
332impl IntoValue for String {
333 fn into_value(self) -> Value {
334 Value::Str(Arc::from(self))
335 }
336}
337
338impl IntoValue for &str {
339 fn into_value(self) -> Value {
340 Value::Str(Arc::from(self))
341 }
342}
343
344impl IntoValue for Arc<str> {
345 fn into_value(self) -> Value {
346 Value::Str(self)
347 }
348}
349
350impl<T: IntoValue> IntoValue for Option<T> {
351 fn into_value(self) -> Value {
352 match self {
353 None => Value::Nil,
354 Some(x) => x.into_value(),
355 }
356 }
357}
358
359impl<T: IntoValue> IntoValue for Vec<T> {
360 fn into_value(self) -> Value {
361 Value::list(self.into_iter().map(IntoValue::into_value))
362 }
363}
364
365#[cfg(test)]
366mod tests {
367 use super::*;
368
369 #[test]
370 fn arity_check() {
371 assert!(Arity::Exact(2).check(2).is_ok());
372 assert!(Arity::Exact(2).check(3).is_err());
373 assert!(Arity::AtLeast(1).check(5).is_ok());
374 assert!(Arity::AtLeast(1).check(0).is_err());
375 assert!(Arity::Range(1, 3).check(2).is_ok());
376 assert!(Arity::Range(1, 3).check(4).is_err());
377 assert!(Arity::Any.check(0).is_ok());
378 assert!(Arity::Any.check(1000).is_ok());
379 }
380
381 #[test]
382 fn from_value_round_trips_primitives() {
383 let sp = Span::synthetic();
384 assert_eq!(i64::from_value(&Value::Int(42), sp).unwrap(), 42);
385 assert_eq!(f64::from_value(&Value::Float(1.5), sp).unwrap(), 1.5);
386 assert!(bool::from_value(&Value::Bool(true), sp).unwrap());
387 assert_eq!(
388 String::from_value(&Value::Str(Arc::from("hi")), sp).unwrap(),
389 "hi"
390 );
391 }
392
393 #[test]
394 fn from_value_int_to_float_coerces() {
395 let sp = Span::synthetic();
396 assert_eq!(f64::from_value(&Value::Int(3), sp).unwrap(), 3.0);
397 }
398
399 #[test]
400 fn from_value_option_nil_is_none() {
401 let sp = Span::synthetic();
402 assert_eq!(
403 <Option<i64> as FromValue>::from_value(&Value::Nil, sp).unwrap(),
404 None
405 );
406 assert_eq!(
407 <Option<i64> as FromValue>::from_value(&Value::Int(7), sp).unwrap(),
408 Some(7)
409 );
410 }
411
412 #[test]
413 fn from_value_type_mismatch_reports_expected_kind() {
414 let sp = Span::synthetic();
415 let err = i64::from_value(&Value::Str(Arc::from("x")), sp).unwrap_err();
416 assert!(matches!(
417 err,
418 EvalError::TypeMismatch {
419 expected: "integer",
420 ..
421 }
422 ));
423 }
424
425 #[test]
426 fn into_value_round_trips() {
427 assert!(matches!(42i64.into_value(), Value::Int(42)));
428 assert!(matches!(true.into_value(), Value::Bool(true)));
429 assert!(matches!(().into_value(), Value::Nil));
430 match String::from("hello").into_value() {
431 Value::Str(s) => assert_eq!(&*s, "hello"),
432 other => panic!("{other:?}"),
433 }
434 }
435
436 #[test]
437 fn into_value_vec_produces_list() {
438 let v: Vec<i64> = vec![1, 2, 3];
439 match v.into_value() {
440 Value::List(xs) => {
441 assert_eq!(xs.len(), 3);
442 assert!(matches!(&xs[0], Value::Int(1)));
443 }
444 other => panic!("{other:?}"),
445 }
446 }
447}