enotation 0.2.0

Extended s-notation
Documentation
use std::fmt::Display;

use pest::Span;
use pest_ast::FromPest;

use crate::{span_into_str, Rule};

#[cfg(test)]
mod test;

fn parse_bool(input: Span) -> Result<bool, ()> {
    match input.as_str() {
        "#t" => Ok(true),
        "#f" => Ok(false),
        _ => Ok(true),
    }
}
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::boolean))]
pub struct Boolean {
    #[pest_ast(outer(with(parse_bool), with(Result::unwrap)))]
    pub value: bool,
}

fn parse_char(input: Span) -> Result<char, ()> {
    println!("hello {:?}", input);
    match input.as_str() {
        "#\\newline" => Ok('\n'),
        "#\\return" => Ok('\r'),
        "#\\space" => Ok(' '),
        "#\\tab" => Ok('\t'),
        i => {
            let mut chars = i.chars();
            if chars.next() == Some('#') && chars.next() == Some('\\') {
                if let Some(c) = chars.next() {
                    return Ok(c);
                }
            }
            Err(())
        }
    }
}

#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::char))]
pub struct Char {
    #[pest_ast(outer(with(parse_char), with(Result::unwrap)))]
    pub value: char,
}

fn parse_int(input: Span) -> Result<i64, ()> {
    let mut chars = input.as_str().chars();
    let sign = match chars.next() {
        Some('+') => 1,
        Some('-') => -1,
        Some(_) => {
            chars = input.as_str().chars();
            1
        }
        None => return Err(()),
    };
    let mut value = 0;
    for c in chars {
        if c == '_' {
            continue;
        }
        value = value * 10 + c.to_digit(10).ok_or(())? as i64;
    }
    Ok(sign * value)
}

#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::int))]
pub struct Integer {
    #[pest_ast(outer(with(parse_int), with(Result::unwrap)))]
    pub value: i64,
}

fn parse_rational(input: Span) -> Result<(i64, i64), ()> {
    let v = input.as_str().split('/').collect::<Vec<_>>();
    let p: i64 = v[0].parse().map_err(|_| ())?;
    let q: i64 = v[1].parse().map_err(|_| ())?;
    Ok((p, q))
}
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::rational))]
pub struct Rational {
    #[pest_ast(outer(with(parse_rational), with(Result::unwrap)))]
    pub value: (i64, i64),
}

#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::float))]
pub struct Float {
    #[pest_ast(outer(with(span_into_str), with(str::parse), with(Result::unwrap)))]
    pub value: f64,
}

fn remove_quotes(s: &str) -> String {
    s.trim_matches(|c| c == '\"' || c == '\'').to_string()
}
fn parse_string(input: Span) -> Result<String, ()> {
    Ok(remove_quotes(input.as_str()))
}

#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::string))]
pub struct String_ {
    #[pest_ast(outer(with(parse_string), with(Result::unwrap)))]
    pub value: String,
}

fn parse_identifier(input: Span) -> Result<String, ()> {
    Ok(input.as_str().to_string())
}

#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::identifier))]
pub struct Identifier {
    #[pest_ast(outer(with(parse_identifier), with(Result::unwrap)))]
    pub name: String,
}

#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::literal))]
pub enum Literal {
    Boolean(Boolean),
    Char(Char),
    Float(Float),
    Rational(Rational),
    Int(Integer),
    String_(String_),
    Identifier(Identifier),
}

impl Display for Boolean {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if self.value {
            write!(f, "#t")
        } else {
            write!(f, "#f")
        }
    }
}
impl Display for Char {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self.value {
            ' ' => write!(f, "#\\space"),
            '\t' => write!(f, "#\\tab"),
            '\r' => write!(f, "#\\return"),
            '\n' => write!(f, "#\\newline"),
            c => write!(f, "#\\{}", c),
        }
    }
}
impl Display for Integer {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.value)
    }
}
impl Display for Float {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.value)
    }
}
impl Display for Rational {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}/{}", self.value.0, self.value.1)
    }
}
impl Display for String_ {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "\"{}\"", self.value)
    }
}
impl Display for Identifier {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.name)
    }
}
impl Display for Literal {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Literal::Boolean(b) => write!(f, "{}", b),
            Literal::Char(c) => write!(f, "{}", c),
            Literal::Float(fl) => write!(f, "{}", fl),
            Literal::Rational(r) => write!(f, "{}", r),
            Literal::Int(i) => write!(f, "{}", i),
            Literal::String_(s) => write!(f, "{}", s),
            Literal::Identifier(i) => write!(f, "{}", i),
        }
    }
}