use crate::Error;
use crate::Result;
use gitdag::dag::Set;
use gitdag::git2::Oid;
use std::borrow::Cow;
use std::fmt;
#[derive(Clone)]
pub enum Expr {
Name(String),
Fn(Cow<'static, str>, Vec<Expr>),
Inlined(Set),
}
impl fmt::Debug for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expr::Name(s) => f.write_str(&s)?,
Expr::Fn(name, args) => {
if args.is_empty() {
f.write_str(name)?;
f.write_str("()")?;
} else {
let mut list = f.debug_tuple(&name);
for arg in args {
list.field(arg);
}
list.finish()?;
}
}
Expr::Inlined(set) => set.fmt(f)?,
}
Ok(())
}
}
impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<Self as fmt::Debug>::fmt(self, f)
}
}
impl Expr {
pub(crate) fn replace(&mut self, from: &str, to: &Expr) {
match self {
Expr::Name(s) => {
if &s[..] == from {
*self = to.clone();
}
}
Expr::Fn(name, args) => {
if name == "apply" && args.len() > 1 {
for arg in &mut args[1..] {
arg.replace(from, to);
}
} else {
for arg in args {
arg.replace(from, to);
}
}
}
Expr::Inlined(_) => (),
}
}
pub fn parse(s: &str) -> Result<Self> {
crate::parser::parse(s).map_err(|e| Error::ParseError(e.to_string()))
}
}
pub trait ParseToExpr {
fn parse_to_expr(self) -> Result<Expr>;
}
impl ParseToExpr for &str {
fn parse_to_expr(self) -> Result<Expr> {
Expr::parse(self)
}
}
impl ParseToExpr for Expr {
fn parse_to_expr(self) -> Result<Expr> {
Ok(self)
}
}
impl From<&str> for Expr {
fn from(s: &str) -> Expr {
Expr::Name(s.to_string())
}
}
impl From<Set> for Expr {
fn from(s: Set) -> Expr {
Expr::Inlined(s)
}
}
impl From<Oid> for Expr {
fn from(oid: Oid) -> Expr {
use crate::ext::OidExt;
Expr::Inlined(oid.to_vertex().into())
}
}
#[macro_export]
macro_rules! ast {
($v:literal) => { $crate::Expr::Name($v.to_string()) };
($fname:ident ( $($arg:tt $( ( $($subargs:tt)* ) )? ),* )) => {{
let args = vec![ $(ast!($arg $( ( $($subargs)* ) )?),)* ];
$crate::Expr::Fn(stringify!($fname).into(), args)
}};
{$v:expr} => { $crate::Expr::from($v) };
}