2019-11-21 10:14:10 -08:00
|
|
|
use crate::common::*;
|
|
|
|
|
|
|
|
#[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 {
|
2020-02-10 20:07:06 -08:00
|
|
|
name: Name<'src>,
|
2019-11-21 10:14:10 -08:00
|
|
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
|
|
|
function: fn(&FunctionContext) -> Result<String, String>,
|
|
|
|
},
|
|
|
|
Unary {
|
2020-02-10 20:07:06 -08:00
|
|
|
name: Name<'src>,
|
2019-11-21 10:14:10 -08:00
|
|
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
|
|
|
function: fn(&FunctionContext, &str) -> Result<String, String>,
|
2020-02-10 20:07:06 -08:00
|
|
|
arg: Box<Expression<'src>>,
|
2019-11-21 10:14:10 -08:00
|
|
|
},
|
|
|
|
Binary {
|
2020-02-10 20:07:06 -08: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>,
|
2020-02-10 20:07:06 -08:00
|
|
|
args: [Box<Expression<'src>>; 2],
|
2019-11-21 10:14:10 -08:00
|
|
|
},
|
2021-07-03 12:39:45 -07:00
|
|
|
Ternary {
|
|
|
|
name: Name<'src>,
|
|
|
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
|
|
|
function: fn(&FunctionContext, &str, &str, &str) -> Result<String, String>,
|
|
|
|
args: [Box<Expression<'src>>; 3],
|
|
|
|
},
|
2019-11-21 10:14:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> Thunk<'src> {
|
|
|
|
pub(crate) fn resolve(
|
|
|
|
name: Name<'src>,
|
|
|
|
mut arguments: Vec<Expression<'src>>,
|
|
|
|
) -> CompilationResult<'src, Thunk<'src>> {
|
|
|
|
if let Some(function) = crate::function::TABLE.get(&name.lexeme()) {
|
|
|
|
match (function, arguments.len()) {
|
|
|
|
(Function::Nullary(function), 0) => Ok(Thunk::Nullary {
|
|
|
|
function: *function,
|
|
|
|
name,
|
|
|
|
}),
|
|
|
|
(Function::Unary(function), 1) => Ok(Thunk::Unary {
|
|
|
|
function: *function,
|
|
|
|
arg: Box::new(arguments.pop().unwrap()),
|
|
|
|
name,
|
|
|
|
}),
|
|
|
|
(Function::Binary(function), 2) => {
|
|
|
|
let b = Box::new(arguments.pop().unwrap());
|
|
|
|
let a = Box::new(arguments.pop().unwrap());
|
|
|
|
Ok(Thunk::Binary {
|
|
|
|
function: *function,
|
|
|
|
args: [a, b],
|
|
|
|
name,
|
|
|
|
})
|
2020-02-10 20:07:06 -08:00
|
|
|
},
|
2021-07-03 12:39:45 -07:00
|
|
|
(Function::Ternary(function), 3) => {
|
|
|
|
let c = Box::new(arguments.pop().unwrap());
|
|
|
|
let b = Box::new(arguments.pop().unwrap());
|
|
|
|
let a = Box::new(arguments.pop().unwrap());
|
|
|
|
Ok(Thunk::Ternary {
|
|
|
|
function: *function,
|
|
|
|
args: [a, b, c],
|
|
|
|
name,
|
|
|
|
})
|
|
|
|
},
|
2019-11-21 10:14:10 -08:00
|
|
|
_ => Err(
|
|
|
|
name.error(CompilationErrorKind::FunctionArgumentCountMismatch {
|
|
|
|
function: name.lexeme(),
|
2020-02-10 20:07:06 -08:00
|
|
|
found: arguments.len(),
|
2019-11-21 10:14:10 -08:00
|
|
|
expected: function.argc(),
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(name.error(CompilationErrorKind::UnknownFunction {
|
|
|
|
function: name.lexeme(),
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Thunk<'_> {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
|
|
use Thunk::*;
|
|
|
|
match self {
|
|
|
|
Nullary { name, .. } => write!(f, "{}()", name.lexeme()),
|
|
|
|
Unary { name, arg, .. } => write!(f, "{}({})", name.lexeme(), arg),
|
|
|
|
Binary {
|
|
|
|
name, args: [a, b], ..
|
|
|
|
} => write!(f, "{}({}, {})", name.lexeme(), a, b),
|
2021-07-03 12:39:45 -07:00
|
|
|
Ternary {
|
|
|
|
name,
|
|
|
|
args: [a, b, c],
|
|
|
|
..
|
|
|
|
} => write!(f, "{}({}, {}, {})", name.lexeme(), a, b, c),
|
2019-11-21 10:14:10 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|