From 1553b785cbc75bfc47066096b81d0066017a91ad Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 30 Jun 2026 13:21:38 -0700 Subject: Added LookAhead, fixed up the proc-macro. LookAhead should make the rest of the parser and lexer stuff way easier, probably spin that out into it's own lib later on. --- Cargo.lock | 5 +++ Cargo.toml | 4 +-- crimtag/src/context.rs | 71 ++++++++++++++++++++++++++++++++---------- derive/Cargo.toml | 4 +++ derive/src/lib.rs | 30 +++++++++--------- derive/tests/basic.rs | 9 ++++++ lookahead/Cargo.toml | 6 ++++ lookahead/src/lib.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 179 insertions(+), 34 deletions(-) create mode 100644 lookahead/Cargo.toml create mode 100644 lookahead/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 842949d..062b9ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,4 +11,9 @@ name = "derive" version = "0.1.0" dependencies = [ "crimtag", + "lookahead", ] + +[[package]] +name = "lookahead" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index a20cdc3..dc6bbe8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] -members = ["derive","crimtag"] -default-members = ["derive","crimtag"] +members = ["derive","crimtag", "lookahead"] +default-members = ["lookahead", "derive","crimtag"] resolver = "3" [workspace.dependencies] diff --git a/crimtag/src/context.rs b/crimtag/src/context.rs index 6f8e04f..15448ee 100644 --- a/crimtag/src/context.rs +++ b/crimtag/src/context.rs @@ -107,24 +107,63 @@ pub enum MappedValue<'a> { impl<'a> fmt::Debug for MappedValue<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - MappedValue::<'a>::Struct(_) => write!(f, "MappedValue"), - MappedValue::<'a>::List(_) => write!(f, "MappedList"), - MappedValue::<'a>::Str(v) => write!(f, "{:?}", v), - MappedValue::<'a>::String(v) => write!(f, "{:?}", v), - MappedValue::<'a>::Int8(v) => write!(f, "{:?}", v), - MappedValue::<'a>::Int16(v) => write!(f, "{:?}", v), - MappedValue::<'a>::Int32(v) => write!(f, "{:?}", v), - MappedValue::<'a>::Int64(v) => write!(f, "{:?}", v), - MappedValue::<'a>::UInt8(v) => write!(f, "{:?}", v), - MappedValue::<'a>::UInt16(v) => write!(f, "{:?}", v), - MappedValue::<'a>::UInt32(v) => write!(f, "{:?}", v), - MappedValue::<'a>::UInt64(v) => write!(f, "{:?}", v), - MappedValue::<'a>::Float32(v) => write!(f, "{:?}", v), - MappedValue::<'a>::Float64(v) => write!(f, "{:?}", v), - MappedValue::<'a>::Bool(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Struct(_) => write!(f, "MappedValue"), + MappedValue::<'a>::List(_) => write!(f, "MappedList"), + MappedValue::<'a>::Str(v) => write!(f, "{:?}", v), + MappedValue::<'a>::String(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Int8(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Int16(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Int32(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Int64(v) => write!(f, "{:?}", v), + MappedValue::<'a>::UInt8(v) => write!(f, "{:?}", v), + MappedValue::<'a>::UInt16(v) => write!(f, "{:?}", v), + MappedValue::<'a>::UInt32(v) => write!(f, "{:?}", v), + MappedValue::<'a>::UInt64(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Float32(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Float64(v) => write!(f, "{:?}", v), + MappedValue::<'a>::Bool(v) => write!(f, "{:?}", v), } + } +} + +macro_rules! basic_mapped_value_from { + ( $x:ident, $y:ident ) => { + impl<'a> From<&$x> for MappedValue<'a> { + fn from(val: &$x) -> MappedValue<'a> { + MappedValue::$y(*val) + } + } + }; +} + +basic_mapped_value_from!(i8, Int8); +basic_mapped_value_from!(i16, Int16); +basic_mapped_value_from!(i32, Int32); +basic_mapped_value_from!(i64, Int64); +basic_mapped_value_from!(u8, UInt8); +basic_mapped_value_from!(u16, UInt16); +basic_mapped_value_from!(u32, UInt32); +basic_mapped_value_from!(u64, UInt64); +basic_mapped_value_from!(f32, Float32); +basic_mapped_value_from!(f64, Float64); +basic_mapped_value_from!(bool, Bool); + +impl<'a> From<&'a String> for MappedValue<'a> { + fn from(val: &'a String ) -> MappedValue<'a> { + MappedValue::String(val) + } +} + +impl<'a, T: MappedStructure<'a>> From<&'a Vec> for MappedValue<'a> { + fn from(val: &'a Vec ) -> MappedValue<'a> { + MappedValue::List(val) + } +} + +impl<'a,T: MappedStructure<'a>> From<&'a T> for MappedValue<'a> { + fn from(val: &'a T ) -> MappedValue<'a> { + MappedValue::Struct(val) } - } pub struct StatefulContext<'a> { diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 65f3a75..bb5ddf3 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -6,5 +6,9 @@ edition = "2024" [lib] proc-macro = true +[dependencies] +lookahead = {path="../lookahead"} + [dev-dependencies] crimtag = { path = "../crimtag"} + diff --git a/derive/src/lib.rs b/derive/src/lib.rs index f9c9180..bb299d0 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -1,9 +1,11 @@ extern crate proc_macro; use proc_macro::{TokenStream,TokenTree,Ident,Delimiter}; +use lookahead::LookAhead; + #[proc_macro_derive(CrimtagMappable)] pub fn derive_crimtag_mappable(s: TokenStream) -> TokenStream { - let mut i = s.into_iter(); + let mut i = LookAhead::<2,_,_>::new(s.into_iter()); while let Some(t) = i.next() { if let TokenTree::Ident(ident) = t && ident.to_string() == "struct" { @@ -18,7 +20,7 @@ pub fn derive_crimtag_mappable(s: TokenStream) -> TokenStream { // TODO: Expand this to include the generic parameters and the where? at // least the parameters. - println!("struct name: {:?}", name); + //println!("struct name: {:?}", name); let mut newfunc = format!( r#"impl<'a> crimtag::MappedStructure<'a> for {} {{ @@ -34,24 +36,20 @@ r#"impl<'a> crimtag::MappedStructure<'a> for {} {{ if let TokenTree::Group(g) = &n && g.delimiter() == Delimiter::Brace { // Operate on the struct members. - let mut gi = g.stream().into_iter(); - let mut cur = 0usize; - let mut tok = [gi.next(), gi.next()]; + let mut gi = LookAhead::<2,_,_>::new(g.stream().into_iter()); loop { - if let Some(TokenTree::Punct(ch)) = &tok[(cur+1)%2] && + if let Some(TokenTree::Punct(ch)) = gi.peek(1) && ch.as_char() == ':' && - let Some(TokenTree::Ident(id)) = &tok[cur] { - println!("!!!!!!!!!! -> {}", id); + let Some(TokenTree::Ident(id)) = gi.peek(0) { + //println!("!!!!!!!!!! -> {}", id); newfunc.push_str(&format!( -r#" "{}" => Some(self.{}.into()), +r#" "{}" => Some((&self.{}).into()), "#, id, id)); } - println!(" - {:?} {:?}", tok[cur], tok[(cur+1)%2] ); + //println!(" -> {:?} ", gi.peek(0)); + //println!(" {:?}", gi.peek(1) ); // Update next. - if let Some(ni) = gi.next() { - tok[cur].replace( ni ); - cur = (cur+1)%2; - } else { + if gi.next().is_none() { break; } } @@ -63,13 +61,13 @@ r#" _ => None, } } }"#); - +/* println!(); println!(); println!("{}", newfunc); println!(); println!(); - +*/ newfunc.parse().unwrap() } diff --git a/derive/tests/basic.rs b/derive/tests/basic.rs index 18fc366..a636faa 100644 --- a/derive/tests/basic.rs +++ b/derive/tests/basic.rs @@ -1,11 +1,20 @@ use derive::*; use crimtag::*; +#[derive(CrimtagMappable)] +pub struct SubTest { + name: String, + byline: String, + amount: i64, +} + #[derive(CrimtagMappable)] pub struct Test { number: i32, something: f64, inner_thing: String, + sub: SubTest, + stuff: Vec, } diff --git a/lookahead/Cargo.toml b/lookahead/Cargo.toml new file mode 100644 index 0000000..d79f913 --- /dev/null +++ b/lookahead/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "lookahead" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/lookahead/src/lib.rs b/lookahead/src/lib.rs new file mode 100644 index 0000000..08bf20e --- /dev/null +++ b/lookahead/src/lib.rs @@ -0,0 +1,84 @@ +pub struct LookAhead +where + U: Iterator + Sized +{ + iter: U, + data: [Option;C], + cur: usize, + fill: usize, +} + +impl LookAhead +where + U: Iterator + Sized +{ + pub fn new(iter: U) -> Self { + Self { + iter, + data: [const {None};C], + cur: 0, + fill: 0, + } + } + + pub fn peek(&mut self, offset: usize) -> Option<&T> { + assert!(offset std::iter::Iterator for LookAhead +where + U: Iterator + Sized +{ + type Item=T; + + fn next(&mut self) -> Option { + if self.fill == 0 { + self.iter.next() + } else { + let old = self.cur; + self.cur = (self.cur+1)%C; + self.fill -= 1; + self.data[old].take() + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn basic() { + let data = [1, 2, 3, 4, 5, 6, 7, 8]; + let mut i = LookAhead::<3,_,_>::new(data.iter()); + assert_eq!(i.next(), Some(&1)); + assert_eq!(i.peek(1), Some(&&3)); + assert_eq!(i.peek(0), Some(&&2)); + assert_eq!(i.next(), Some(&2)); + assert_eq!(i.peek(0), Some(&&3)); + assert_eq!(i.next(), Some(&3)); + assert_eq!(i.next(), Some(&4)); + assert_eq!(i.next(), Some(&5)); + assert_eq!(i.peek(0), Some(&&6)); + assert_eq!(i.peek(1), Some(&&7)); + assert_eq!(i.peek(2), Some(&&8)); + assert_eq!(i.next(), Some(&6)); + assert_eq!(i.peek(2), None); + assert_eq!(i.next(), Some(&7)); + assert_eq!(i.peek(2), None); + assert_eq!(i.next(), Some(&8)); + assert_eq!(i.next(), None); + } +} -- cgit v1.2.3