@@ 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::*;