2022-06-18 21:56:31 -07:00
|
|
|
use super::*;
|
2019-11-21 10:14:10 -08:00
|
|
|
|
|
|
|
#[derive(Derivative)]
|
2021-06-08 01:01:27 -07:00
|
|
|
#[derivative(Debug, Clone, PartialEq = "feature_allow_slow_enum")]
|
2019-11-21 10:14:10 -08:00
|
|
|
pub(crate) enum Thunk<'src> {
|
|
|
|
Nullary {
|
2021-09-16 06:44:40 -07:00
|
|
|
name: Name<'src>,
|
2019-11-21 10:14:10 -08:00
|
|
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
|
|
|
function: fn(&FunctionContext) -> Result<String, String>,
|
|
|
|
},
|
|
|
|
Unary {
|
2021-09-16 06:44:40 -07:00
|
|
|
name: Name<'src>,
|
2019-11-21 10:14:10 -08:00
|
|
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
|
|
|
function: fn(&FunctionContext, &str) -> Result<String, String>,
|
2021-09-16 06:44:40 -07:00
|
|
|
arg: Box<Expression<'src>>,
|
2019-11-21 10:14:10 -08:00
|
|
|
},
|
2023-06-13 05:49:46 -07:00
|
|
|
UnaryOpt {
|
|
|
|
name: Name<'src>,
|
|
|
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
|
|
|
function: fn(&FunctionContext, &str, Option<&str>) -> Result<String, String>,
|
|
|
|
args: (Box<Expression<'src>>, Box<Option<Expression<'src>>>),
|
|
|
|
},
|
2019-11-21 10:14:10 -08:00
|
|
|
Binary {
|
2021-09-16 06:44:40 -07:00
|
|
|
name: Name<'src>,
|
2019-11-21 10:14:10 -08:00
|
|
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
|
|
|
function: fn(&FunctionContext, &str, &str) -> Result<String, String>,
|
2021-09-16 06:44:40 -07:00
|
|
|
args: [Box<Expression<'src>>; 2],
|
2019-11-21 10:14:10 -08:00
|
|
|
},
|
2021-10-14 17:00:58 -07:00
|
|
|
BinaryPlus {
|
|
|
|
name: Name<'src>,
|
|
|
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
|
|
|
function: fn(&FunctionContext, &str, &str, &[String]) -> Result<String, String>,
|
|
|
|
args: ([Box<Expression<'src>>; 2], Vec<Expression<'src>>),
|
|
|
|
},
|
2021-07-03 12:39:45 -07:00
|
|
|
Ternary {
|
2021-09-16 06:44:40 -07:00
|
|
|
name: Name<'src>,
|
2021-07-03 12:39:45 -07:00
|
|
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
|
|
|
function: fn(&FunctionContext, &str, &str, &str) -> Result<String, String>,
|
2021-09-16 06:44:40 -07:00
|
|
|
args: [Box<Expression<'src>>; 3],
|
2021-07-03 12:39:45 -07:00
|
|
|
},
|
2019-11-21 10:14:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> Thunk<'src> {
|
2021-11-17 00:07:48 -08:00
|
|
|
fn name(&self) -> &Name<'src> {
|
|
|
|
match self {
|
|
|
|
Self::Nullary { name, .. }
|
|
|
|
| Self::Unary { name, .. }
|
2023-06-13 05:49:46 -07:00
|
|
|
| Self::UnaryOpt { name, .. }
|
2021-11-17 00:07:48 -08:00
|
|
|
| Self::Binary { name, .. }
|
|
|
|
| Self::BinaryPlus { name, .. }
|
|
|
|
| Self::Ternary { name, .. } => name,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-21 10:14:10 -08:00
|
|
|
pub(crate) fn resolve(
|
|
|
|
name: Name<'src>,
|
|
|
|
mut arguments: Vec<Expression<'src>>,
|
2021-07-26 01:26:06 -07:00
|
|
|
) -> CompileResult<'src, Thunk<'src>> {
|
2023-10-16 20:07:09 -07:00
|
|
|
function::get(name.lexeme()).map_or(
|
2021-09-16 07:51:45 -07:00
|
|
|
Err(name.error(CompileErrorKind::UnknownFunction {
|
|
|
|
function: name.lexeme(),
|
|
|
|
})),
|
|
|
|
|function| match (function, arguments.len()) {
|
2022-12-15 16:53:21 -08:00
|
|
|
(Function::Nullary(function), 0) => Ok(Thunk::Nullary { function, name }),
|
2019-11-21 10:14:10 -08:00
|
|
|
(Function::Unary(function), 1) => Ok(Thunk::Unary {
|
2022-12-15 16:53:21 -08:00
|
|
|
function,
|
2024-05-14 20:07:41 -07:00
|
|
|
arg: arguments.pop().unwrap().into(),
|
2019-11-21 10:14:10 -08:00
|
|
|
name,
|
|
|
|
}),
|
2023-06-13 05:49:46 -07:00
|
|
|
(Function::UnaryOpt(function), 1..=2) => {
|
2024-05-14 20:07:41 -07:00
|
|
|
let a = arguments.remove(0).into();
|
2023-06-13 05:49:46 -07:00
|
|
|
let b = match arguments.pop() {
|
2024-05-14 20:07:41 -07:00
|
|
|
Some(value) => Some(value).into(),
|
|
|
|
None => None.into(),
|
2023-06-13 05:49:46 -07:00
|
|
|
};
|
|
|
|
Ok(Thunk::UnaryOpt {
|
|
|
|
function,
|
|
|
|
args: (a, b),
|
|
|
|
name,
|
|
|
|
})
|
|
|
|
}
|
2019-11-21 10:14:10 -08:00
|
|
|
(Function::Binary(function), 2) => {
|
2024-05-14 20:07:41 -07:00
|
|
|
let b = arguments.pop().unwrap().into();
|
|
|
|
let a = arguments.pop().unwrap().into();
|
2019-11-21 10:14:10 -08:00
|
|
|
Ok(Thunk::Binary {
|
2022-12-15 16:53:21 -08:00
|
|
|
function,
|
2019-11-21 10:14:10 -08:00
|
|
|
args: [a, b],
|
|
|
|
name,
|
|
|
|
})
|
2021-09-16 06:44:40 -07:00
|
|
|
}
|
2021-10-14 17:00:58 -07:00
|
|
|
(Function::BinaryPlus(function), 2..=usize::MAX) => {
|
|
|
|
let rest = arguments.drain(2..).collect();
|
2024-05-14 20:07:41 -07:00
|
|
|
let b = arguments.pop().unwrap().into();
|
|
|
|
let a = arguments.pop().unwrap().into();
|
2021-10-14 17:00:58 -07:00
|
|
|
Ok(Thunk::BinaryPlus {
|
2022-12-15 16:53:21 -08:00
|
|
|
function,
|
2021-10-14 17:00:58 -07:00
|
|
|
args: ([a, b], rest),
|
|
|
|
name,
|
|
|
|
})
|
|
|
|
}
|
2021-07-03 12:39:45 -07:00
|
|
|
(Function::Ternary(function), 3) => {
|
2024-05-14 20:07:41 -07:00
|
|
|
let c = arguments.pop().unwrap().into();
|
|
|
|
let b = arguments.pop().unwrap().into();
|
|
|
|
let a = arguments.pop().unwrap().into();
|
2021-07-03 12:39:45 -07:00
|
|
|
Ok(Thunk::Ternary {
|
2022-12-15 16:53:21 -08:00
|
|
|
function,
|
2021-07-03 12:39:45 -07:00
|
|
|
args: [a, b, c],
|
|
|
|
name,
|
|
|
|
})
|
2021-09-16 06:44:40 -07:00
|
|
|
}
|
2022-12-15 16:53:21 -08:00
|
|
|
(function, _) => Err(name.error(CompileErrorKind::FunctionArgumentCountMismatch {
|
2021-07-26 01:26:06 -07:00
|
|
|
function: name.lexeme(),
|
2021-09-16 06:44:40 -07:00
|
|
|
found: arguments.len(),
|
2021-07-26 01:26:06 -07:00
|
|
|
expected: function.argc(),
|
|
|
|
})),
|
2021-09-16 07:51:45 -07:00
|
|
|
},
|
|
|
|
)
|
2019-11-21 10:14:10 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Thunk<'_> {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
|
|
use Thunk::*;
|
|
|
|
match self {
|
|
|
|
Nullary { name, .. } => write!(f, "{}()", name.lexeme()),
|
2022-12-15 16:53:21 -08:00
|
|
|
Unary { name, arg, .. } => write!(f, "{}({arg})", name.lexeme()),
|
2023-06-13 05:49:46 -07:00
|
|
|
UnaryOpt {
|
|
|
|
name, args: (a, b), ..
|
|
|
|
} => {
|
|
|
|
if let Some(b) = b.as_ref() {
|
|
|
|
write!(f, "{}({a}, {b})", name.lexeme())
|
|
|
|
} else {
|
|
|
|
write!(f, "{}({a})", name.lexeme())
|
|
|
|
}
|
|
|
|
}
|
2019-11-21 10:14:10 -08:00
|
|
|
Binary {
|
|
|
|
name, args: [a, b], ..
|
2022-12-15 16:53:21 -08:00
|
|
|
} => write!(f, "{}({a}, {b})", name.lexeme()),
|
2021-10-14 17:00:58 -07:00
|
|
|
BinaryPlus {
|
|
|
|
name,
|
|
|
|
args: ([a, b], rest),
|
|
|
|
..
|
|
|
|
} => {
|
2022-12-15 16:53:21 -08:00
|
|
|
write!(f, "{}({a}, {b}", name.lexeme())?;
|
2021-10-14 17:00:58 -07:00
|
|
|
for arg in rest {
|
2022-12-15 16:53:21 -08:00
|
|
|
write!(f, ", {arg}")?;
|
2021-10-14 17:00:58 -07:00
|
|
|
}
|
|
|
|
write!(f, ")")
|
|
|
|
}
|
2021-07-03 12:39:45 -07:00
|
|
|
Ternary {
|
|
|
|
name,
|
|
|
|
args: [a, b, c],
|
|
|
|
..
|
2022-12-15 16:53:21 -08:00
|
|
|
} => write!(f, "{}({a}, {b}, {c})", name.lexeme()),
|
2019-11-21 10:14:10 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-17 00:07:48 -08:00
|
|
|
|
|
|
|
impl<'src> Serialize for Thunk<'src> {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
|
|
|
let mut seq = serializer.serialize_seq(None)?;
|
|
|
|
seq.serialize_element("call")?;
|
|
|
|
seq.serialize_element(self.name())?;
|
|
|
|
match self {
|
|
|
|
Self::Nullary { .. } => {}
|
|
|
|
Self::Unary { arg, .. } => seq.serialize_element(&arg)?,
|
2023-06-13 05:49:46 -07:00
|
|
|
Self::UnaryOpt {
|
|
|
|
args: (a, opt_b), ..
|
|
|
|
} => {
|
|
|
|
seq.serialize_element(a)?;
|
|
|
|
if let Some(b) = opt_b.as_ref() {
|
|
|
|
seq.serialize_element(b)?;
|
|
|
|
}
|
|
|
|
}
|
2021-11-17 00:07:48 -08:00
|
|
|
Self::Binary { args, .. } => {
|
|
|
|
for arg in args {
|
|
|
|
seq.serialize_element(arg)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Self::BinaryPlus { args, .. } => {
|
|
|
|
for arg in args.0.iter().map(Box::as_ref).chain(&args.1) {
|
|
|
|
seq.serialize_element(arg)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Self::Ternary { args, .. } => {
|
|
|
|
for arg in args {
|
|
|
|
seq.serialize_element(arg)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
seq.end()
|
|
|
|
}
|
|
|
|
}
|