snix_eval/value/
builtin.rs1use crate::vm::generators::Generator;
7
8use super::Value;
9
10use std::{
11 fmt::{Debug, Display},
12 rc::Rc,
13};
14
15pub trait BuiltinGen: Fn(Vec<Value>) -> Generator {}
23impl<F: Fn(Vec<Value>) -> Generator> BuiltinGen for F {}
24
25#[derive(Clone)]
26pub struct BuiltinRepr {
27 name: &'static str,
28 documentation: Option<&'static str>,
30 arg_count: usize,
31
32 func: Rc<dyn BuiltinGen>,
33
34 partials: Vec<Value>,
36}
37
38pub enum BuiltinResult {
39 Partial(Builtin),
42
43 Called(&'static str, Generator),
45}
46
47#[derive(Clone)]
60pub struct Builtin(Box<BuiltinRepr>);
61
62impl From<BuiltinRepr> for Builtin {
63 fn from(value: BuiltinRepr) -> Self {
64 Builtin(Box::new(value))
65 }
66}
67
68impl Builtin {
69 pub fn new<F: BuiltinGen + 'static>(
70 name: &'static str,
71 documentation: Option<&'static str>,
72 arg_count: usize,
73 func: F,
74 ) -> Self {
75 BuiltinRepr {
76 name,
77 documentation,
78 arg_count,
79 func: Rc::new(func),
80 partials: vec![],
81 }
82 .into()
83 }
84
85 pub fn name(&self) -> &'static str {
86 self.0.name
87 }
88
89 pub fn documentation(&self) -> Option<&'static str> {
90 self.0.documentation
91 }
92
93 pub fn apply_arg(&mut self, arg: Value) {
97 self.0.partials.push(arg);
98
99 debug_assert!(
100 self.0.partials.len() <= self.0.arg_count,
101 "Snix bug: pushed too many arguments to builtin"
102 );
103 }
104
105 pub fn call(self) -> BuiltinResult {
108 if self.0.partials.len() == self.0.arg_count {
109 BuiltinResult::Called(self.0.name, (self.0.func)(self.0.partials))
110 } else {
111 BuiltinResult::Partial(self)
112 }
113 }
114}
115
116impl Debug for Builtin {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 write!(f, "builtin[{}]", self.0.name)
119 }
120}
121
122impl Display for Builtin {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 if !self.0.partials.is_empty() {
125 f.write_str("<PRIMOP-APP>")
126 } else {
127 f.write_str("<PRIMOP>")
128 }
129 }
130}
131
132impl PartialEq for Builtin {
134 fn eq(&self, other: &Self) -> bool {
135 self.0.name == other.0.name
136 }
137}