~jojo/microcrisp

39ef00ca178cce7550a7e2c18ab2343f699961e1 — JoJo 8 months ago 659df76
reorder defs
1 files changed, 74 insertions(+), 74 deletions(-)

M src/lib.rs
M src/lib.rs => src/lib.rs +74 -74
@@ 8,46 8,6 @@ const SYMBOL_CHARS: &str = "\0abcdefghijklmnopqrstuvxyz+-*?0123456789";
const SYMBOL_MAX_LEN: usize =
    1 + (u128::MAX / (SYMBOL_CHARS.len() - 10) as u128).ilog(SYMBOL_CHARS.len() as u128) as usize;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Symbol(u128);

impl Symbol {
    pub fn pack_str(s: &str) -> Option<Self> {
        Self::pack(s.as_bytes())
    }

    pub fn pack(s: &[u8]) -> Option<Self> {
        if s.is_empty() || s.len() > SYMBOL_MAX_LEN || s[0].is_ascii_digit() || s[0] == 0 {
            None
        } else {
            let mut acc = SYMBOL_CHARS.find(s[0] as char)? as u128;
            let mut multiplier = (SYMBOL_CHARS.len() - 10) as u128;
            for &c in &s[1..] {
                if c == 0 {
                    return None;
                }
                acc += multiplier * SYMBOL_CHARS.find(c as char)? as u128;
                multiplier *= SYMBOL_CHARS.len() as u128;
            }
            Some(Symbol(acc))
        }
    }

    pub fn unpack_str(self) -> String {
        let mut cs = [0u8; SYMBOL_MAX_LEN + 1];
        let mut acc = self.0;
        let divisor = (SYMBOL_CHARS.len() - 10) as u128;
        cs[0] = SYMBOL_CHARS.as_bytes()[(acc % divisor) as usize];
        acc /= divisor;
        let divisor = SYMBOL_CHARS.len() as u128;
        for c in &mut cs[1..] {
            *c = SYMBOL_CHARS.as_bytes()[(acc % divisor) as usize];
            acc /= divisor;
        }
        std::ffi::CStr::from_bytes_until_nul(&cs).unwrap().to_str().unwrap().to_owned()
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Lisp {
    Int(i64),


@@ 57,40 17,8 @@ pub enum Lisp {
    String(String),
}

impl Lisp {
    pub fn as_list(&self) -> Option<&[Lisp]> {
        match self {
            Lisp::List(xs) => Some(xs),
            _ => None,
        }
    }

    pub fn as_int(&self) -> Option<i64> {
        match *self {
            Lisp::Int(x) => Some(x),
            _ => None,
        }
    }

    pub fn as_string(&self) -> Option<&str> {
        match self {
            Lisp::String(s) => Some(s),
            _ => None,
        }
    }
}

impl fmt::Display for Lisp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            Lisp::Int(x) => x.fmt(f),
            Lisp::Float(x) => x.fmt(f),
            _ => todo!(),
        }
    }
}

type PResult<T, E> = Result<(usize, T), (usize, E)>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Symbol(u128);

pub fn parse(src: &[u8]) -> Result<Lisp, String> {
    fn context(src: &[u8], i: usize) -> (Cow<str>, Cow<str>) {


@@ 112,6 40,8 @@ pub fn parse(src: &[u8]) -> Result<Lisp, String> {
    }
}

type PResult<T, E> = Result<(usize, T), (usize, E)>;

fn parse_(src: &[u8]) -> PResult<Lisp, &'static str> {
    let mut i = 0;
    i += consume_whitespace(&src[i..]);


@@ 236,6 166,76 @@ fn map_ok<T, U, E>(r: PResult<T, E>, f: impl FnOnce(T) -> U) -> PResult<U, E> {
    r.map(|(n, x)| (n, f(x)))
}

impl Symbol {
    pub fn pack_str(s: &str) -> Option<Self> {
        Self::pack(s.as_bytes())
    }

    pub fn pack(s: &[u8]) -> Option<Self> {
        if s.is_empty() || s.len() > SYMBOL_MAX_LEN || s[0].is_ascii_digit() || s[0] == 0 {
            None
        } else {
            let mut acc = SYMBOL_CHARS.find(s[0] as char)? as u128;
            let mut multiplier = (SYMBOL_CHARS.len() - 10) as u128;
            for &c in &s[1..] {
                if c == 0 {
                    return None;
                }
                acc += multiplier * SYMBOL_CHARS.find(c as char)? as u128;
                multiplier *= SYMBOL_CHARS.len() as u128;
            }
            Some(Symbol(acc))
        }
    }

    pub fn unpack_str(self) -> String {
        let mut cs = [0u8; SYMBOL_MAX_LEN + 1];
        let mut acc = self.0;
        let divisor = (SYMBOL_CHARS.len() - 10) as u128;
        cs[0] = SYMBOL_CHARS.as_bytes()[(acc % divisor) as usize];
        acc /= divisor;
        let divisor = SYMBOL_CHARS.len() as u128;
        for c in &mut cs[1..] {
            *c = SYMBOL_CHARS.as_bytes()[(acc % divisor) as usize];
            acc /= divisor;
        }
        std::ffi::CStr::from_bytes_until_nul(&cs).unwrap().to_str().unwrap().to_owned()
    }
}

impl Lisp {
    pub fn as_list(&self) -> Option<&[Lisp]> {
        match self {
            Lisp::List(xs) => Some(xs),
            _ => None,
        }
    }

    pub fn as_int(&self) -> Option<i64> {
        match *self {
            Lisp::Int(x) => Some(x),
            _ => None,
        }
    }

    pub fn as_string(&self) -> Option<&str> {
        match self {
            Lisp::String(s) => Some(s),
            _ => None,
        }
    }
}

impl fmt::Display for Lisp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            Lisp::Int(x) => x.fmt(f),
            Lisp::Float(x) => x.fmt(f),
            _ => todo!(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;