pub_just/
thunk.rs

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}