use delegate_attr::delegate;
use serde::{Deserialize, Serialize};
pub type Atom = crate::crulst::CrulzAtom;
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum GroupType {
Strict,
Loose,
Dissolving,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum ASTNode {
NullNode,
Constant(bool, Atom),
Argument {
indirection: usize,
index: Option<usize>,
},
Grouped(GroupType, Vec<ASTNode>),
CmdEval(Vec<ASTNode>, CmdEvalArgs),
}
use ASTNode::*;
pub type VAN = Vec<ASTNode>;
impl std::default::Default for ASTNode {
#[inline(always)]
fn default() -> Self {
NullNode
}
}
impl ASTNode {
#[inline(always)]
pub(crate) fn is_space(&self) -> bool {
match self {
NullNode | Constant(false, _) => true,
_ => false,
}
}
#[inline(always)]
pub(crate) fn as_constant(&self) -> Option<&Atom> {
match self {
Constant(_, ref x) => Some(x),
_ => None,
}
}
pub(crate) fn conv_to_constant(&self) -> Option<Atom> {
match self {
ASTNode::Constant(_, x) => Some(x.clone()),
ASTNode::Grouped(gt, x) if *gt != GroupType::Strict => {
let mut impc = x.iter().map(ASTNode::conv_to_constant);
if x.len() == 1 {
impc.next().unwrap()
} else {
impc.try_fold(String::new(), |acc, i| i.as_ref().map(|j| acc + j))
.map(<_>::into)
}
}
_ => None,
}
}
}
pub trait LiftAST {
type LiftT: LiftAST;
fn lift_ast(self) -> Self::LiftT;
}
impl LiftAST for ASTNode {
type LiftT = VAN;
#[inline(always)]
fn lift_ast(self) -> Self::LiftT {
vec![self]
}
}
impl LiftAST for VAN {
type LiftT = ASTNode;
#[inline(always)]
fn lift_ast(self) -> Self::LiftT {
ASTNode::Grouped(GroupType::Dissolving, self)
}
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct CmdEvalArgs(pub VAN);
impl std::iter::IntoIterator for CmdEvalArgs {
type Item = ASTNode;
type IntoIter = std::vec::IntoIter<ASTNode>;
#[inline(always)]
fn into_iter(self) -> std::vec::IntoIter<ASTNode> {
self.0.into_iter()
}
}
impl std::iter::FromIterator<ASTNode> for CmdEvalArgs {
#[inline(always)]
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = ASTNode>,
{
CmdEvalArgs(Vec::from_iter(iter))
}
}
impl CmdEvalArgs {
pub fn from_wsdelim(args: VAN) -> Self {
use crate::mangle_ast::MangleAST;
use itertools::Itertools;
args.into_iter()
.group_by(ASTNode::is_space)
.into_iter()
.filter(|x| !x.0)
.map(|x| x.1.collect::<VAN>().lift_ast().simplify())
.collect()
}
}
#[delegate(self.0)]
impl CmdEvalArgs {
pub fn iter(&self) -> std::slice::Iter<ASTNode> { }
pub fn iter_mut(&mut self) -> std::slice::IterMut<ASTNode> { }
pub fn len(&self) -> usize { }
pub fn is_empty(&self) -> bool { }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_args2unspaced() {
use ASTNode::*;
assert_eq!(
CmdEvalArgs::from_wsdelim(vec![
Constant(true, "a".into()),
Constant(false, "a".into()),
Constant(true, "a".into()),
Constant(true, "a".into()),
Constant(false, "a".into())
]),
CmdEvalArgs(vec![
Constant(true, "a".into()),
Constant(true, "aa".into())
])
);
}
}