myser 0.1.0

A lisp for no_std systems
Documentation
use nom::{
    AsChar,
    IResult,
    InputTakeAtPosition,
    branch::alt,
    bytes::complete as bytes,
    character::complete as character,
    combinator::{not,peek,map},
};

use crate::pool::{Pool, RcValue};

pub fn integer<'s, const N: usize>(pool: &'s Pool<'s, N>, input: &'s str) -> IResult<&'s str, RcValue<'s>> {
    let (input, result) = map(character::i64, |n| pool.new_integer(n))(input)?;
    let (input, _) = not(peek(bytes::tag(".")))(input)?;

    Ok((input, result))
}

pub fn number<'s, const N: usize>(pool: &'s Pool<'s, N>, input: &'s str) -> IResult<&'s str, RcValue<'s>> {
    map(nom::number::complete::double, |x| pool.new_number(x))(input)
}

pub fn cons_end<'s, const N: usize>(pool: &'s Pool<'s, N>, input: &'s str) -> IResult<&'s str, RcValue<'s>> {
    let (input, _) = character::space0(input)?;
    let (input, _) = bytes::tag(")")(input)?;
    Ok((input, pool.new_symbol("nil")))
}

pub fn cons_pair<'s, const N: usize>(pool: &'s Pool<'s, N>, input: &'s str) -> IResult<&'s str, RcValue<'s>> {
    let (input, _) = character::space0(input)?;
    let (input, _) = bytes::tag(".")(input)?;
    let (input, _) = character::space0(input)?;
    let (input, cdr) = parse(pool, input)?;
    let (input, _) = character::space0(input)?;
    let (input, _) = bytes::tag(")")(input)?;
    Ok((input, cdr))
}

pub fn cons_rest<'s, const N: usize>(pool: &'s Pool<'s, N>, input: &'s str) -> IResult<&'s str, RcValue<'s>> {
    alt((
        |input| cons_end(pool, input),
        |input| cons_pair(pool, input),
        |input| {
            let (input, _) = character::space0(input)?;
            let (input, car) = parse(pool, input)?;
            let (input, cdr) = cons_rest(pool, input)?;

            Ok((input, pool.new_cons(car, cdr)))
        }
    ))(input)
}

pub fn cons<'s, const N: usize>(pool: &'s Pool<'s, N>, input: &'s str) -> IResult<&'s str, RcValue<'s>> {
    let (input, _) = character::space0(input)?;
    let (input, _) = bytes::tag("(")(input)?;
    let (input, car) = parse(pool, input)?;
    let (input, cdr) = cons_rest(pool, input)?;

    Ok((input, pool.new_cons(car, cdr)))
}

pub fn symbol<'s, const N: usize>(pool: &'s Pool<'s, N>, input: &'s str) -> IResult<&'s str, RcValue<'s>> {
    let (input, _) = character::space0(input)?;
    let (input, symbol) = input.split_at_position(
        |c| !c.is_alphanum() && c != '+' && c != '-' && c != '*' && c != '/'
    )?;
    Ok((input, pool.new_symbol(symbol)))
}

pub fn parse<'s, const N: usize>(pool: &'s Pool<'s, N>, input: &'s str) -> IResult<&'s str, RcValue<'s>> {
    let (input, _) = character::space0(input)?;
    alt((
        |input| cons(pool, input),
        |input| integer(pool, input),
        |input| number(pool, input),
        |input| symbol(pool, input),
    ))(input)
}