1use super::*;
2
3#[derive_where(Debug, PartialEq)]
4#[derive(Clone)]
5pub enum Thunk<'src> {
6 Nullary {
7 name: Name<'src>,
8 #[derive_where(skip(Debug, EqHashOrd))]
9 function: fn(function::Context) -> FunctionResult,
10 },
11 Unary {
12 name: Name<'src>,
13 #[derive_where(skip(Debug, EqHashOrd))]
14 function: fn(function::Context, &str) -> FunctionResult,
15 arg: Box<Expression<'src>>,
16 },
17 UnaryOpt {
18 name: Name<'src>,
19 #[derive_where(skip(Debug, EqHashOrd))]
20 function: fn(function::Context, &str, Option<&str>) -> FunctionResult,
21 args: (Box<Expression<'src>>, Box<Option<Expression<'src>>>),
22 },
23 UnaryPlus {
24 name: Name<'src>,
25 #[derive_where(skip(Debug, EqHashOrd))]
26 function: fn(function::Context, &str, &[String]) -> FunctionResult,
27 args: (Box<Expression<'src>>, Vec<Expression<'src>>),
28 },
29 Binary {
30 name: Name<'src>,
31 #[derive_where(skip(Debug, EqHashOrd))]
32 function: fn(function::Context, &str, &str) -> FunctionResult,
33 args: [Box<Expression<'src>>; 2],
34 },
35 BinaryPlus {
36 name: Name<'src>,
37 #[derive_where(skip(Debug, EqHashOrd))]
38 function: fn(function::Context, &str, &str, &[String]) -> FunctionResult,
39 args: ([Box<Expression<'src>>; 2], Vec<Expression<'src>>),
40 },
41 Ternary {
42 name: Name<'src>,
43 #[derive_where(skip(Debug, EqHashOrd))]
44 function: fn(function::Context, &str, &str, &str) -> FunctionResult,
45 args: [Box<Expression<'src>>; 3],
46 },
47}
48
49impl<'src> Thunk<'src> {
50 pub fn name(&self) -> Name<'src> {
51 match self {
52 Self::Nullary { name, .. }
53 | Self::Unary { name, .. }
54 | Self::UnaryOpt { name, .. }
55 | Self::UnaryPlus { name, .. }
56 | Self::Binary { name, .. }
57 | Self::BinaryPlus { name, .. }
58 | Self::Ternary { name, .. } => *name,
59 }
60 }
61
62 pub fn resolve(
63 name: Name<'src>,
64 mut arguments: Vec<Expression<'src>>,
65 ) -> CompileResult<'src, Thunk<'src>> {
66 function::get(name.lexeme()).map_or(
67 Err(name.error(CompileErrorKind::UnknownFunction {
68 function: name.lexeme(),
69 })),
70 |function| match (function, arguments.len()) {
71 (Function::Nullary(function), 0) => Ok(Thunk::Nullary { function, name }),
72 (Function::Unary(function), 1) => Ok(Thunk::Unary {
73 function,
74 arg: arguments.pop().unwrap().into(),
75 name,
76 }),
77 (Function::UnaryOpt(function), 1..=2) => {
78 let a = arguments.remove(0).into();
79 let b = match arguments.pop() {
80 Some(value) => Some(value).into(),
81 None => None.into(),
82 };
83 Ok(Thunk::UnaryOpt {
84 function,
85 args: (a, b),
86 name,
87 })
88 }
89 (Function::UnaryPlus(function), 1..=usize::MAX) => {
90 let rest = arguments.drain(1..).collect();
91 let a = Box::new(arguments.pop().unwrap());
92 Ok(Thunk::UnaryPlus {
93 function,
94 args: (a, rest),
95 name,
96 })
97 }
98 (Function::Binary(function), 2) => {
99 let b = arguments.pop().unwrap().into();
100 let a = arguments.pop().unwrap().into();
101 Ok(Thunk::Binary {
102 function,
103 args: [a, b],
104 name,
105 })
106 }
107 (Function::BinaryPlus(function), 2..=usize::MAX) => {
108 let rest = arguments.drain(2..).collect();
109 let b = arguments.pop().unwrap().into();
110 let a = arguments.pop().unwrap().into();
111 Ok(Thunk::BinaryPlus {
112 function,
113 args: ([a, b], rest),
114 name,
115 })
116 }
117 (Function::Ternary(function), 3) => {
118 let c = arguments.pop().unwrap().into();
119 let b = arguments.pop().unwrap().into();
120 let a = arguments.pop().unwrap().into();
121 Ok(Thunk::Ternary {
122 function,
123 args: [a, b, c],
124 name,
125 })
126 }
127 (function, _) => Err(name.error(CompileErrorKind::FunctionArgumentCountMismatch {
128 function: name.lexeme(),
129 found: arguments.len(),
130 expected: function.argc(),
131 })),
132 },
133 )
134 }
135}
136
137impl Display for Thunk<'_> {
138 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
139 use Thunk::*;
140 match self {
141 Nullary { name, .. } => write!(f, "{}()", name.lexeme()),
142 Unary { name, arg, .. } => write!(f, "{}({arg})", name.lexeme()),
143 UnaryOpt {
144 name, args: (a, b), ..
145 } => {
146 if let Some(b) = b.as_ref() {
147 write!(f, "{}({a}, {b})", name.lexeme())
148 } else {
149 write!(f, "{}({a})", name.lexeme())
150 }
151 }
152 UnaryPlus {
153 name,
154 args: (a, rest),
155 ..
156 } => {
157 write!(f, "{}({a}", name.lexeme())?;
158 for arg in rest {
159 write!(f, ", {arg}")?;
160 }
161 write!(f, ")")
162 }
163 Binary {
164 name, args: [a, b], ..
165 } => write!(f, "{}({a}, {b})", name.lexeme()),
166 BinaryPlus {
167 name,
168 args: ([a, b], rest),
169 ..
170 } => {
171 write!(f, "{}({a}, {b}", name.lexeme())?;
172 for arg in rest {
173 write!(f, ", {arg}")?;
174 }
175 write!(f, ")")
176 }
177 Ternary {
178 name,
179 args: [a, b, c],
180 ..
181 } => write!(f, "{}({a}, {b}, {c})", name.lexeme()),
182 }
183 }
184}
185
186impl<'src> Serialize for Thunk<'src> {
187 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
188 where
189 S: Serializer,
190 {
191 let mut seq = serializer.serialize_seq(None)?;
192 seq.serialize_element("call")?;
193 seq.serialize_element(&self.name())?;
194 match self {
195 Self::Nullary { .. } => {}
196 Self::Unary { arg, .. } => seq.serialize_element(&arg)?,
197 Self::UnaryOpt {
198 args: (a, opt_b), ..
199 } => {
200 seq.serialize_element(a)?;
201 if let Some(b) = opt_b.as_ref() {
202 seq.serialize_element(b)?;
203 }
204 }
205 Self::UnaryPlus {
206 args: (a, rest), ..
207 } => {
208 seq.serialize_element(a)?;
209 for arg in rest {
210 seq.serialize_element(arg)?;
211 }
212 }
213 Self::Binary { args, .. } => {
214 for arg in args {
215 seq.serialize_element(arg)?;
216 }
217 }
218 Self::BinaryPlus { args, .. } => {
219 for arg in args.0.iter().map(Box::as_ref).chain(&args.1) {
220 seq.serialize_element(arg)?;
221 }
222 }
223 Self::Ternary { args, .. } => {
224 for arg in args {
225 seq.serialize_element(arg)?;
226 }
227 }
228 }
229 seq.end()
230 }
231}