sexprs-parser 0.0.5

sexprs is a minimal lisp dialect to evaluate written in Rust.
Documentation
use std::borrow::Cow;
pub mod errors;
pub use errors::{Caller, Error, Result};
pub mod macros;
pub mod test;

pub mod source;
use std::str::FromStr;

use sexprs_data_structures::{Cell, Value};
use sexprs_util::unexpected;
use pest::iterators::{Pair, Pairs};
use pest::Parser;
use pest_derive::Parser;
pub use source::{Source, Span, SpanPosition};
pub const GRAMMAR: &'static str = include_str!("./grammar.pest");

#[derive(Parser, Debug, Clone)]
#[grammar = "src/grammar.pest"]
pub struct MinilispSource;
pub fn parse_source<'a>(input: &'a str) -> Result<'a, Value<'a>> {
    let source_info = Source {
        source: Cow::from(input),
        filename: None,
    };
    let mut pairs = MinilispSource::parse(Rule::file, input).map_err(|e| {
        Error::new(
            e.variant.message().to_string(),
            Some(Span::from_error(e, source_info.clone())),
        )
    })?;
    let file = pairs.next().unwrap();
    let nodes = (|pair: Pair<'a, Rule>| -> Option<Value<'a>> {
        Some(pair_to_value(
            pair.clone()
                .into_inner()
                .next()?
                .into_inner()
                .next()?,
        ))
    })(file)
    .unwrap_or_default();
    Ok(nodes)
}

pub fn map_pairs_to_list<'a>(pairs: Pairs<'a, Rule>) -> Value<'a> {
    pairs.map(|pair| pair_to_value(pair)).collect()
}
pub fn pair_to_value<'a>(pair: Pair<'a, Rule>) -> Value<'a> {
    match pair.as_rule() {
        Rule::float =>
            Value::float(f64::from_str(pair.as_span().as_str()).expect("float")),
        Rule::integer =>
            Value::integer(i64::from_str(pair.as_span().as_str()).expect("integer")),
        Rule::string => Value::string(Cow::from(pair.as_span().as_str())),
        Rule::symbol => Value::symbol(Cow::from(pair.as_span().as_str())),
        Rule::quoted_symbol => {
            let mut pairs = pair.clone().into_inner();
            pairs.next().expect("quote");
            let symbol = pairs.next().expect("symbol");
            Value::quoted_symbol(symbol.as_span().as_str())
        },
        Rule::t => Value::T,
        Rule::unsigned => Value::unsigned_integer(
            u32::from_str(pair.as_span().as_str()).expect("unsigned integer"),
        ),
        Rule::value => pair_to_value(pair.clone().into_inner().next().expect("value")),
        Rule::sexpr => {
            let mut items = Cell::nil();
            let mut pairs = pair.clone().into_inner();
            let mut quoted = false;
            loop {
                if let Some(pair) = pairs.peek() {
                    if pair.as_rule() == Rule::close_paren {
                        break;
                    }
                }
                let pair = pairs.next().expect("quote, open_paren or item");
                match pair.as_rule() {
                    Rule::quote => {
                        quoted = true;
                    },
                    Rule::open_paren => continue,
                    Rule::close_paren => continue,
                    _ => {
                        items.push_value(pair_to_value(pair));
                        continue;
                    },
                }
            }
            pairs.next().expect("close_paren");
            let value = Value::from_iter(items.into_iter());
            if quoted {
                value.quote()
            } else {
                value
            }
        },
        Rule::nil => Value::nil(),
        _ => unexpected!(pair),
    }
}