mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
159 lines
5.3 KiB
Rust
159 lines
5.3 KiB
Rust
use std::sync::{Arc, RwLock};
|
|
use std::collections::BTreeMap;
|
|
pub use clojure_reader::edn::Edn;
|
|
|
|
|
|
//#[derive(Debug, Copy, Clone, Default, PartialEq)]
|
|
//pub struct Items<'a>(&'a [Item<'a>]);
|
|
//impl<'a> Items<'a> {
|
|
//fn iter (&'a self) -> ItemsIterator<'a> {
|
|
//ItemsIterator(0, self.0)
|
|
//}
|
|
//}
|
|
|
|
//pub struct ItemsIterator<'a>(usize, &'a [Item<'a>]);
|
|
//impl<'a> Iterator for ItemsIterator<'a> {
|
|
//type Item = &'a Item<'a>;
|
|
//fn next (&mut self) -> Option<Self::Item> {
|
|
//let item = self.1.get(self.0);
|
|
//self.0 += 1;
|
|
//item
|
|
//}
|
|
//}
|
|
|
|
/*
|
|
|
|
nice but doesn't work without compile time slice concat
|
|
(which i guess could be implemeted using an unsafe linked list?)
|
|
never done that one before im ny life, might try
|
|
|
|
use konst::slice_concat;
|
|
|
|
const fn read <'a> (
|
|
chars: impl Iterator<Item = char>
|
|
) -> Result<Range<'a>, ParseError> {
|
|
use Range::*;
|
|
let mut state = Range::Nil;
|
|
let mut tokens: &[Range<'a>] = &[];
|
|
while let Some(c) = chars.next() {
|
|
state = match state {
|
|
// must begin expression
|
|
Nil => match c {
|
|
' ' => Nil,
|
|
'(' => Exp(&[]),
|
|
':' => Sym(&[]),
|
|
'1'..'9' => Num(digit(c)),
|
|
'a'..'z' => Key(&[&[c]]),
|
|
_ => return Err(ParseError::Unexpected(c))
|
|
},
|
|
Num(b) => match c {
|
|
' ' => return Ok(Num(digit(c))),
|
|
'1'..'9' => Num(b*10+digit(c)),
|
|
_ => return Err(ParseError::Unexpected(c))
|
|
}
|
|
Sym([]) => match c {
|
|
'a'..'z' => Sym(&[c]),
|
|
_ => return Err(ParseError::Unexpected(c))
|
|
},
|
|
Sym([b @ ..]) => match c {
|
|
' ' => return Ok(Sym(&b)),
|
|
'a'..'z' | '0'..'9' | '-' => Sym(&[..b, c]),
|
|
_ => return Err(ParseError::Unexpected(c))
|
|
}
|
|
Key([[b @ ..]]) => match c {
|
|
' ' => return Ok(Key(&[&b])),
|
|
'/' => Key(&[&b, &[]]),
|
|
'a'..'z' | '0'..'9' | '-' => Key(&[&[..b, c], &[]]),
|
|
_ => return Err(ParseError::Unexpected(c))
|
|
}
|
|
Key([s @ .., []]) => match c {
|
|
'a'..'z' => Key(&[..s, &[c]]),
|
|
_ => return Err(ParseError::Unexpected(c))
|
|
}
|
|
Key([s @ .., [b @ ..]]) => match c {
|
|
'/' => Key([..s, &b, &[]]),
|
|
'a'..'z' | '0'..'9' | '-' => Key(&[..s, &[..b, c]]),
|
|
_ => return Err(ParseError::Unexpected(c))
|
|
}
|
|
// expression must begin with key or symbol
|
|
Exp([]) => match c {
|
|
' ' => Exp(&[]),
|
|
')' => return Err(ParseError::Empty),
|
|
':' => Exp(&[Sym(&[':'])]),
|
|
c => Exp(&[Key(&[&[c]])]),
|
|
},
|
|
|
|
// expression can't begin with number
|
|
Exp([Num(num)]) => return Err(ParseError::Unexpected(c)),
|
|
|
|
// symbol begins with : and lowercase a-z
|
|
Exp([Sym([':'])]) => match c {
|
|
'a'..'z' => Exp(&[Sym(&[':', c])]),
|
|
_ => return Err(ParseError::Unexpected(c)),
|
|
},
|
|
|
|
// any other char is part of symbol until space or )
|
|
Exp([Sym([':', b @ ..])]) => match c {
|
|
')' => { tokens = &[..tokens, Exp(&[Sym(&[":", ..b])])]; Nil },
|
|
' ' => Exp(&[Sym(&[':', ..b]), Nil]),
|
|
c => Exp(&[Sym(&[':', ..b, c])]),
|
|
},
|
|
|
|
// key begins with lowercase a-z
|
|
Exp([Key([])]) => match c {
|
|
'a'..'z' => Exp([Key([[c]])]),
|
|
_ => return Err(ParseError::Unexpected(c)),
|
|
},
|
|
|
|
// any other char is part of key until slash space or )
|
|
Exp([Key([[b @ ..]])]) => match c {
|
|
'/' => Exp(&[Key(&[[..b], []])]),
|
|
' ' => Exp(&[Key(&[[..b]]), Nil]),
|
|
')' => { tokens = &[..tokens, Exp(&[Sym(&[":", ..b])])]; Nil },
|
|
c => Exp(&[Key(&[[..b, c]])])
|
|
}
|
|
|
|
// slash adds new section to key
|
|
Exp([Key([b @ .., []])]) => match c {
|
|
'/' => Exp(&[Key(&[[..b], []])]),
|
|
' ' => Exp(&[Key(&[[..b]]), Nil]),
|
|
')' => { tokens = &[..tokens, Exp(&[Sym(&[":", ..b])])]; Nil },
|
|
c => Exp(&[Key(&[[..b, c]])])
|
|
}
|
|
|
|
}
|
|
}
|
|
Ok(state)
|
|
}
|
|
*/
|
|
|
|
|
|
/// EDN parsing helper.
|
|
#[macro_export] macro_rules! edn {
|
|
($edn:ident { $($pat:pat => $expr:expr),* $(,)? }) => {
|
|
match $edn { $($pat => $expr),* }
|
|
};
|
|
($edn:ident in $args:ident { $($pat:pat => $expr:expr),* $(,)? }) => {
|
|
for $edn in $args {
|
|
edn!($edn { $($pat => $expr),* })
|
|
}
|
|
};
|
|
}
|
|
|
|
pub trait FromEdn<C>: Sized {
|
|
const ID: &'static str;
|
|
fn from_edn (context: C, expr: &[Edn<'_>]) ->
|
|
std::result::Result<Self, Box<dyn std::error::Error>>;
|
|
}
|
|
|
|
/// Implements the [FromEdn] trait.
|
|
#[macro_export] macro_rules! from_edn {
|
|
($id:expr => |$context:tt:$Context:ty, $args:ident| -> $T:ty $body:block) => {
|
|
impl FromEdn<$Context> for $T {
|
|
const ID: &'static str = $id;
|
|
fn from_edn <'e> ($context: $Context, $args: &[Edn<'e>]) -> Usually<Self> {
|
|
$body
|
|
}
|
|
}
|
|
}
|
|
}
|