#[allow(clippy::missing_docs_in_private_items)]
pub mod parsers {
mod begin;
mod dateformat;
mod r#else;
mod end;
mod excerpt;
mod r#for;
mod ifdefined;
mod import;
mod insert;
mod timetoread;
pub use begin::BeginParser as Begin;
pub use dateformat::DateFormatParser as DateFormat;
pub use end::EndParser as End;
pub use excerpt::ExcerptParser as Excerpt;
pub use ifdefined::IfDefinedParser as IfDefined;
pub use import::ImportParser as Import;
pub use insert::InsertParser as Insert;
pub use r#else::ElseParser as Else;
pub use r#for::ForParser as For;
pub use timetoread::TimeToReadParser as TimeToRead;
#[macro_use]
mod r#if;
if_parsers![
ifeq, IfEq, ==;
ifne, IfNe, !=;
ifgt, IfGt, >;
ifge, IfGe, >=;
iflt, IfLt, <;
ifle, IfLe, <;
];
}
use crate::error::ProcessError;
use crate::parse::{ParseError, RawFunction};
use crate::process::Scope;
use crate::TracebackError;
use humphrey_json::Value;
use std::fmt::Debug;
pub trait FunctionParser: Send + Sync {
fn name(&self) -> &'static str;
fn parse(&self, raw: RawFunction) -> Result<Box<dyn Function>, ParseError>;
fn can_parse(&self, raw: &RawFunction) -> bool {
raw.name == self.name()
}
}
pub trait Function: Debug + Send + Sync {
fn name(&self) -> &'static str;
fn execute(&self, scope: &mut Scope) -> Result<(), TracebackError<ProcessError>>;
}
#[derive(Debug, Clone)]
enum Input {
Variable(String),
String(String),
Integer(i32),
}
impl Input {
fn evaluate_variable(&self, scope: &mut Scope) -> Option<Self> {
match self {
Input::Variable(name) => match scope.get_variable(name) {
Some(Value::String(s)) => Some(Input::String(s)),
Some(Value::Number(i)) => Some(Input::Integer(i as i32)),
_ => None,
},
x => Some(x.clone()),
}
}
}
impl PartialEq for Input {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Variable(l0), Self::Variable(r0)) => l0 == r0,
(Self::String(l0), Self::String(r0)) => l0 == r0,
(Self::Integer(l0), Self::Integer(r0)) => l0 == r0,
_ => false,
}
}
}
impl PartialOrd for Input {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match (self, other) {
(Self::Variable(_), Self::Variable(_)) => None,
(Self::String(_), Self::String(_)) => None,
(Self::Integer(i), Self::Integer(j)) => i.partial_cmp(j),
_ => None,
}
}
}
impl ToString for Input {
fn to_string(&self) -> String {
match self {
Input::Variable(v) => v.clone(),
Input::String(s) => s.clone(),
Input::Integer(i) => i.to_string(),
}
}
}
macro_rules! count {
() => { 0_usize };
($head:tt $($tail:tt)*) => { 1_usize + count!($($tail)*) };
}
macro_rules! define_functions {
($($name:expr,)*) => {
const FUNCTION_COUNT: usize = count!($($name)*);
::lazy_static::lazy_static! {
static ref FUNCTION_PARSERS: [Box<dyn $crate::functions::FunctionParser>; FUNCTION_COUNT] = [
$(Box::new($name)),*
];
}
}
}
#[macro_export]
macro_rules! quiet_assert {
($cond:expr) => {
match $cond {
true => Ok(()),
false => Err($crate::parse::ParseError::AssertionError(
stringify!($cond).to_string(),
)),
}
};
}
#[inline]
pub fn is_ident(s: &str) -> bool {
crate::FUNCTION_PARSERS.iter().any(|f| f.name() == s)
}