use std::fmt::Display;
use std::hash::Hash;
use std::str::FromStr;
use gen_utils::error::{Error, ParseError, ParseType};
use gen_utils::parser::trim;
use nom::branch::alt;
use nom::bytes::complete::{take_while, take_while_m_n};
use nom::character::complete::{alphanumeric1, char, multispace0};
use nom::combinator::{map, recognize};
use nom::multi::{many1, separated_list0};
use nom::sequence::{pair, preceded, separated_pair};
use nom::{bytes::complete::tag, sequence::delimited, IResult};
use super::Function;
#[derive(Debug, Clone, PartialEq)]
pub enum Bind {
Normal(Vec<Ident>),
Fn(Function),
For(For),
}
impl Bind {
pub fn ident(&self) -> String {
match self {
Bind::Normal(n) => Ident::fmt_idents(n),
Bind::For(f) => f.ident(),
Bind::Fn(function) => function.ident().to_string(),
}
}
pub fn is(&self, s: &str) -> bool {
match self {
Bind::Normal(n) => n[0].name == s,
Bind::For(f) => f.iter_ident[0].name == s,
Bind::Fn(function) => function.name == s,
}
}
pub fn get_for(&self) -> Option<&For> {
match self {
Bind::For(f) => Some(f),
_ => None,
}
}
pub fn get_normal(&self) -> Option<&Vec<Ident>> {
match self {
Bind::Normal(n) => Some(&n),
_ => None,
}
}
pub fn parse_style(s: &str) -> Result<Self, Error> {
let s = s.trim();
if s.starts_with('$') {
let s = s.trim_matches(|c| c == '$');
return Ok(Bind::Normal(Ident::parse_idents(s)?));
}
return Err(ParseError::template(&format!("parse style bind: {} failed", s)).into());
}
pub fn parse_template(s: &str) -> Result<Self, Error> {
s.trim().parse::<Bind>()
}
}
impl Display for Bind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Bind::Normal(n) => f.write_str(&n.iter().map(|i| i.to_string()).collect::<String>()),
Bind::For(for_bind) => for_bind.fmt(f),
Bind::Fn(function) => function.fmt(f),
}
}
}
impl FromStr for Bind {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.parse::<For>() {
Ok(f) => {
return Ok(Bind::For(f));
}
Err(_) => {
if let Ok(fn_bind) = Function::parse(s, false) {
return Ok(Bind::Fn(fn_bind));
}
if let Ok(normal) = Ident::parse_idents(s) {
return Ok(Bind::Normal(normal));
}
return Err(ParseError::template(&format!("parse bind: {} failed", s)).into());
}
}
}
}
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub struct For {
pub iter_ident: Vec<Ident>,
pub index: Option<String>,
pub item: ForItem,
}
impl For {
pub const SUGAR_SIGN: &'static str = "for_sugar_sign";
pub fn ident(&self) -> String {
self.iter_ident
.first()
.expect("iter_ident is empty")
.name
.to_string()
}
pub fn is_use_index(&self, s: &str) -> bool {
s.contains(&self.fmt_index())
}
pub fn is_use_item(&self, s: &str) -> bool {
match &self.item {
ForItem::Ident(i) => s.contains(i),
ForItem::Tuple(vec) => vec.iter().any(|item| item.is_use(s)),
_ => false,
}
}
pub fn iter_ident_as_fn(&self) -> String {
self.iter_ident
.iter()
.map(|i| i.name.to_string())
.collect::<Vec<String>>()
.join("_")
}
pub fn fmt_iter_ident(&self) -> String {
self.iter_ident
.iter()
.map(|i| i.to_string())
.collect::<String>()
}
pub fn fmt_item_clone_tk(&self) -> String {
self.item.item_clone()
}
pub fn fmt_enumerate(&self) -> String {
format!("({}, {})", self.fmt_index(), self.fmt_item())
}
pub fn fmt_index(&self) -> String {
self.index
.as_ref()
.unwrap_or(&"index".to_string())
.to_string()
}
pub fn fmt_item(&self) -> String {
self.item.to_string()
}
pub fn parser(input: &str) -> IResult<&str, Self> {
fn index_item(input: &str) -> IResult<&str, (Option<String>, ForItem)> {
let has_index = input.starts_with("(");
let (input, item) = ForItem::parser(input)?;
let (index, item) = if has_index {
match &item {
ForItem::Tuple(vec) => {
match vec.len() {
0 | 1 => (None, item),
_ => {
let index = Some(vec[0].to_string());
let item = ForItem::Tuple(vec[1..].to_vec());
(index, item)
}
}
}
_ => (None, item),
}
} else {
(None, item)
};
Ok((input, (index, item)))
}
let (input, ((index, item), idents)) =
separated_pair(trim(index_item), trim(tag("in")), trim(many1(Ident::parse)))(input)?;
if !input.is_empty() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Tag,
)));
}
return Ok((
input,
Self {
iter_ident: idents
.iter()
.map(|(ident, split)| Ident {
name: ident.to_string(),
split: *split,
})
.collect(),
index,
item,
},
));
}
}
impl FromStr for For {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
For::parser(s)
.map_err(|e| {
let mut err = ParseError::new(s, ParseType::DSLBind);
let _ = err.set_other(e.to_string().as_str());
err.into()
})
.map(|(_, f)| f)
}
}
impl Display for For {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"({index}, {item}) in {iter_ident}",
index = self.index.as_ref().unwrap_or(&"index".to_string()),
item = self.item,
iter_ident = self
.iter_ident
.iter()
.map(|i| i.to_string())
.collect::<String>()
)
}
}
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub enum ForItem {
Tuple(Vec<ForItem>),
Ident(String),
More,
None,
}
impl Default for ForItem {
fn default() -> Self {
ForItem::Ident("item".to_string())
}
}
impl Display for ForItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ForItem::Tuple(items) => match items.len() {
0 => f.write_str("()"),
1 => items[0].fmt(f),
_ => f.write_fmt(format_args!(
"({})",
items
.iter()
.map(|item| { item.to_string() })
.collect::<Vec<_>>()
.join(", ")
)),
},
ForItem::Ident(ident) => write!(f, "{}", ident),
ForItem::None => write!(f, "_"),
ForItem::More => write!(f, ".."),
}
}
}
impl ForItem {
pub fn is_use(&self, s: &str) -> bool {
match self {
ForItem::Ident(i) => s.contains(i),
ForItem::Tuple(vec) => vec.iter().any(|item| item.is_use(s)),
_ => false,
}
}
pub fn item_clone(&self) -> String {
match self {
ForItem::Tuple(vec) => vec.iter().fold(String::new(), |mut tk, item| {
tk.push_str(&item.item_clone());
tk
}),
ForItem::Ident(i) => {
format!("let {} = {}.clone();", i, i)
}
ForItem::More => "..".to_string(),
ForItem::None => "_".to_string(),
}
}
pub fn parser(input: &str) -> IResult<&str, ForItem> {
fn ident(input: &str) -> IResult<&str, String> {
let is_ident_char = |c: char| c.is_alphanumeric() || c == '_';
map(take_while(is_ident_char), |s: &str| s.to_string())(input)
}
fn more(input: &str) -> IResult<&str, ForItem> {
map(tag(".."), |_| ForItem::More)(input)
}
fn none(input: &str) -> IResult<&str, ForItem> {
map(tag("_"), |_| ForItem::None)(input)
}
fn for_ident(input: &str) -> IResult<&str, ForItem> {
map(ident, ForItem::Ident)(input)
}
fn for_tuple(input: &str) -> IResult<&str, ForItem> {
let inner = separated_list0(
preceded(multispace0, char(',')),
preceded(multispace0, for_item),
);
let parser = delimited(char('('), inner, char(')'));
map(parser, ForItem::Tuple)(input)
}
fn for_item(input: &str) -> IResult<&str, ForItem> {
alt((for_tuple, none, more, for_ident))(input)
}
for_item(input)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
pub enum IdentSplit {
None,
Dot,
Holder,
}
impl IdentSplit {
pub fn is_none(&self) -> bool {
matches!(self, IdentSplit::None)
}
pub fn is_dot(&self) -> bool {
matches!(self, IdentSplit::Dot)
}
pub fn is_holder(&self) -> bool {
matches!(self, IdentSplit::Holder)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Ident {
pub name: String,
pub split: IdentSplit,
}
impl Ident {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
split: IdentSplit::None,
}
}
pub fn dot(name: &str) -> Self {
Self {
name: name.to_string(),
split: IdentSplit::Dot,
}
}
pub fn holder(name: &str) -> Self {
Self {
name: name.to_string(),
split: IdentSplit::Holder,
}
}
pub fn parse_idents(input: &str) -> Result<Vec<Self>, Error> {
let (remain, idents) = many1(Self::parse)(input).map_err(|e| Error::from(e.to_string()))?;
if remain.is_empty() {
return Ok(idents
.iter()
.map(|(ident, split)| Ident {
name: ident.to_string(),
split: *split,
})
.collect());
} else {
return Err(ParseError::template(&format!(
"parse idents: {} failed, still remain: {}",
input, remain
))
.into());
}
}
pub fn parser(input: &str) -> Result<Self, Error> {
let (remain, (ident, split)) =
Self::parse(input).map_err(|e| Error::from(e.to_string()))?;
if remain.is_empty() {
return Ok(Ident {
name: ident.to_string(),
split,
});
} else {
return Err(ParseError::template(&format!(
"parse ident: {} failed, still remain: {}",
input, remain
))
.into());
}
}
pub fn ident(&self) -> String {
self.name.to_string()
}
fn parse(s: &str) -> IResult<&str, (&str, IdentSplit)> {
fn dot(s: &str) -> IResult<&str, (&str, IdentSplit)> {
let (remain, ident) = preceded(tag("."), normal)(s)?;
Ok((remain, (ident, IdentSplit::Dot)))
}
fn holder(s: &str) -> IResult<&str, (&str, IdentSplit)> {
let (remain, ident) = delimited(tag("["), normal, tag("]"))(s)?;
Ok((remain, (ident, IdentSplit::Holder)))
}
fn normal(s: &str) -> IResult<&str, &str> {
recognize(pair(
alphanumeric1,
take_while_m_n(0, usize::MAX, |c: char| c == '_' || c.is_alphanumeric()),
))(s)
}
fn ident(s: &str) -> IResult<&str, (&str, IdentSplit)> {
let (remain, ident) = recognize(pair(
alphanumeric1,
take_while_m_n(0, usize::MAX, |c: char| c == '_' || c.is_alphanumeric()),
))(s)?;
Ok((remain, (ident, IdentSplit::None)))
}
alt((dot, holder, ident))(s)
}
pub fn fmt_idents(idents: &Vec<Ident>) -> String {
idents.iter().map(|i| i.to_string()).collect::<String>()
}
}
impl FromStr for Ident {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parser(s)
}
}
impl Display for Ident {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.split {
IdentSplit::None => write!(f, "{}", self.name),
IdentSplit::Dot => write!(f, ".{}", self.name),
IdentSplit::Holder => write!(f, "[{}]", self.name),
}
}
}