summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2026-06-30 13:21:38 -0700
committerMike Buland <mike@xagasoft.com>2026-06-30 13:21:38 -0700
commit1553b785cbc75bfc47066096b81d0066017a91ad (patch)
treed10b1dcf71c6ecf833b2eb9e9dbfde303b88fa9e
parent062048ef6e3e060bcf841ea2ec92e026f09d8da0 (diff)
downloadcrimtag-1553b785cbc75bfc47066096b81d0066017a91ad.tar.gz
crimtag-1553b785cbc75bfc47066096b81d0066017a91ad.tar.bz2
crimtag-1553b785cbc75bfc47066096b81d0066017a91ad.tar.xz
crimtag-1553b785cbc75bfc47066096b81d0066017a91ad.zip
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.
-rw-r--r--Cargo.lock5
-rw-r--r--Cargo.toml4
-rw-r--r--crimtag/src/context.rs71
-rw-r--r--derive/Cargo.toml4
-rw-r--r--derive/src/lib.rs30
-rw-r--r--derive/tests/basic.rs9
-rw-r--r--lookahead/Cargo.toml6
-rw-r--r--lookahead/src/lib.rs84
8 files changed, 179 insertions, 34 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 842949d..062b9ba 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -11,4 +11,9 @@ name = "derive"
11version = "0.1.0" 11version = "0.1.0"
12dependencies = [ 12dependencies = [
13 "crimtag", 13 "crimtag",
14 "lookahead",
14] 15]
16
17[[package]]
18name = "lookahead"
19version = "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 @@
1[workspace] 1[workspace]
2members = ["derive","crimtag"] 2members = ["derive","crimtag", "lookahead"]
3default-members = ["derive","crimtag"] 3default-members = ["lookahead", "derive","crimtag"]
4resolver = "3" 4resolver = "3"
5 5
6[workspace.dependencies] 6[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> {
107impl<'a> fmt::Debug for MappedValue<'a> { 107impl<'a> fmt::Debug for MappedValue<'a> {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 match self { 109 match self {
110 MappedValue::<'a>::Struct(_) => write!(f, "MappedValue"), 110 MappedValue::<'a>::Struct(_) => write!(f, "MappedValue"),
111 MappedValue::<'a>::List(_) => write!(f, "MappedList"), 111 MappedValue::<'a>::List(_) => write!(f, "MappedList"),
112 MappedValue::<'a>::Str(v) => write!(f, "{:?}", v), 112 MappedValue::<'a>::Str(v) => write!(f, "{:?}", v),
113 MappedValue::<'a>::String(v) => write!(f, "{:?}", v), 113 MappedValue::<'a>::String(v) => write!(f, "{:?}", v),
114 MappedValue::<'a>::Int8(v) => write!(f, "{:?}", v), 114 MappedValue::<'a>::Int8(v) => write!(f, "{:?}", v),
115 MappedValue::<'a>::Int16(v) => write!(f, "{:?}", v), 115 MappedValue::<'a>::Int16(v) => write!(f, "{:?}", v),
116 MappedValue::<'a>::Int32(v) => write!(f, "{:?}", v), 116 MappedValue::<'a>::Int32(v) => write!(f, "{:?}", v),
117 MappedValue::<'a>::Int64(v) => write!(f, "{:?}", v), 117 MappedValue::<'a>::Int64(v) => write!(f, "{:?}", v),
118 MappedValue::<'a>::UInt8(v) => write!(f, "{:?}", v), 118 MappedValue::<'a>::UInt8(v) => write!(f, "{:?}", v),
119 MappedValue::<'a>::UInt16(v) => write!(f, "{:?}", v), 119 MappedValue::<'a>::UInt16(v) => write!(f, "{:?}", v),
120 MappedValue::<'a>::UInt32(v) => write!(f, "{:?}", v), 120 MappedValue::<'a>::UInt32(v) => write!(f, "{:?}", v),
121 MappedValue::<'a>::UInt64(v) => write!(f, "{:?}", v), 121 MappedValue::<'a>::UInt64(v) => write!(f, "{:?}", v),
122 MappedValue::<'a>::Float32(v) => write!(f, "{:?}", v), 122 MappedValue::<'a>::Float32(v) => write!(f, "{:?}", v),
123 MappedValue::<'a>::Float64(v) => write!(f, "{:?}", v), 123 MappedValue::<'a>::Float64(v) => write!(f, "{:?}", v),
124 MappedValue::<'a>::Bool(v) => write!(f, "{:?}", v), 124 MappedValue::<'a>::Bool(v) => write!(f, "{:?}", v),
125 } 125 }
126 }
127}
128
129macro_rules! basic_mapped_value_from {
130 ( $x:ident, $y:ident ) => {
131 impl<'a> From<&$x> for MappedValue<'a> {
132 fn from(val: &$x) -> MappedValue<'a> {
133 MappedValue::$y(*val)
134 }
135 }
136 };
137}
138
139basic_mapped_value_from!(i8, Int8);
140basic_mapped_value_from!(i16, Int16);
141basic_mapped_value_from!(i32, Int32);
142basic_mapped_value_from!(i64, Int64);
143basic_mapped_value_from!(u8, UInt8);
144basic_mapped_value_from!(u16, UInt16);
145basic_mapped_value_from!(u32, UInt32);
146basic_mapped_value_from!(u64, UInt64);
147basic_mapped_value_from!(f32, Float32);
148basic_mapped_value_from!(f64, Float64);
149basic_mapped_value_from!(bool, Bool);
150
151impl<'a> From<&'a String> for MappedValue<'a> {
152 fn from(val: &'a String ) -> MappedValue<'a> {
153 MappedValue::String(val)
154 }
155}
156
157impl<'a, T: MappedStructure<'a>> From<&'a Vec<T>> for MappedValue<'a> {
158 fn from(val: &'a Vec<T> ) -> MappedValue<'a> {
159 MappedValue::List(val)
160 }
161}
162
163impl<'a,T: MappedStructure<'a>> From<&'a T> for MappedValue<'a> {
164 fn from(val: &'a T ) -> MappedValue<'a> {
165 MappedValue::Struct(val)
126 } 166 }
127
128} 167}
129 168
130pub struct StatefulContext<'a> { 169pub 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"
6[lib] 6[lib]
7proc-macro = true 7proc-macro = true
8 8
9[dependencies]
10lookahead = {path="../lookahead"}
11
9[dev-dependencies] 12[dev-dependencies]
10crimtag = { path = "../crimtag"} 13crimtag = { path = "../crimtag"}
14
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 @@
1extern crate proc_macro; 1extern crate proc_macro;
2use proc_macro::{TokenStream,TokenTree,Ident,Delimiter}; 2use proc_macro::{TokenStream,TokenTree,Ident,Delimiter};
3 3
4use lookahead::LookAhead;
5
4#[proc_macro_derive(CrimtagMappable)] 6#[proc_macro_derive(CrimtagMappable)]
5pub fn derive_crimtag_mappable(s: TokenStream) -> TokenStream { 7pub fn derive_crimtag_mappable(s: TokenStream) -> TokenStream {
6 let mut i = s.into_iter(); 8 let mut i = LookAhead::<2,_,_>::new(s.into_iter());
7 while let Some(t) = i.next() { 9 while let Some(t) = i.next() {
8 if let TokenTree::Ident(ident) = t && 10 if let TokenTree::Ident(ident) = t &&
9 ident.to_string() == "struct" { 11 ident.to_string() == "struct" {
@@ -18,7 +20,7 @@ pub fn derive_crimtag_mappable(s: TokenStream) -> TokenStream {
18 20
19 // TODO: Expand this to include the generic parameters and the where? at 21 // TODO: Expand this to include the generic parameters and the where? at
20 // least the parameters. 22 // least the parameters.
21 println!("struct name: {:?}", name); 23 //println!("struct name: {:?}", name);
22 24
23 let mut newfunc = format!( 25 let mut newfunc = format!(
24r#"impl<'a> crimtag::MappedStructure<'a> for {} {{ 26r#"impl<'a> crimtag::MappedStructure<'a> for {} {{
@@ -34,24 +36,20 @@ r#"impl<'a> crimtag::MappedStructure<'a> for {} {{
34 if let TokenTree::Group(g) = &n && 36 if let TokenTree::Group(g) = &n &&
35 g.delimiter() == Delimiter::Brace { 37 g.delimiter() == Delimiter::Brace {
36 // Operate on the struct members. 38 // Operate on the struct members.
37 let mut gi = g.stream().into_iter(); 39 let mut gi = LookAhead::<2,_,_>::new(g.stream().into_iter());
38 let mut cur = 0usize;
39 let mut tok = [gi.next(), gi.next()];
40 loop { 40 loop {
41 if let Some(TokenTree::Punct(ch)) = &tok[(cur+1)%2] && 41 if let Some(TokenTree::Punct(ch)) = gi.peek(1) &&
42 ch.as_char() == ':' && 42 ch.as_char() == ':' &&
43 let Some(TokenTree::Ident(id)) = &tok[cur] { 43 let Some(TokenTree::Ident(id)) = gi.peek(0) {
44 println!("!!!!!!!!!! -> {}", id); 44 //println!("!!!!!!!!!! -> {}", id);
45 newfunc.push_str(&format!( 45 newfunc.push_str(&format!(
46r#" "{}" => Some(self.{}.into()), 46r#" "{}" => Some((&self.{}).into()),
47"#, id, id)); 47"#, id, id));
48 } 48 }
49 println!(" - {:?} {:?}", tok[cur], tok[(cur+1)%2] ); 49 //println!(" -> {:?} ", gi.peek(0));
50 //println!(" {:?}", gi.peek(1) );
50 // Update next. 51 // Update next.
51 if let Some(ni) = gi.next() { 52 if gi.next().is_none() {
52 tok[cur].replace( ni );
53 cur = (cur+1)%2;
54 } else {
55 break; 53 break;
56 } 54 }
57 } 55 }
@@ -63,13 +61,13 @@ r#" _ => None,
63 } 61 }
64 } 62 }
65}"#); 63}"#);
66 64/*
67 println!(); 65 println!();
68 println!(); 66 println!();
69 println!("{}", newfunc); 67 println!("{}", newfunc);
70 println!(); 68 println!();
71 println!(); 69 println!();
72 70*/
73 newfunc.parse().unwrap() 71 newfunc.parse().unwrap()
74} 72}
75 73
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
@@ -2,10 +2,19 @@ use derive::*;
2use crimtag::*; 2use crimtag::*;
3 3
4#[derive(CrimtagMappable)] 4#[derive(CrimtagMappable)]
5pub struct SubTest {
6 name: String,
7 byline: String,
8 amount: i64,
9}
10
11#[derive(CrimtagMappable)]
5pub struct Test { 12pub struct Test {
6 number: i32, 13 number: i32,
7 something: f64, 14 something: f64,
8 inner_thing: String, 15 inner_thing: String,
16 sub: SubTest,
17 stuff: Vec<SubTest>,
9} 18}
10 19
11 20
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 @@
1[package]
2name = "lookahead"
3version = "0.1.0"
4edition = "2024"
5
6[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 @@
1pub struct LookAhead<const C: usize, T, U>
2where
3 U: Iterator<Item=T> + Sized
4{
5 iter: U,
6 data: [Option<T>;C],
7 cur: usize,
8 fill: usize,
9}
10
11impl<const C: usize, T, U> LookAhead<C,T,U>
12where
13 U: Iterator<Item=T> + Sized
14{
15 pub fn new(iter: U) -> Self {
16 Self {
17 iter,
18 data: [const {None};C],
19 cur: 0,
20 fill: 0,
21 }
22 }
23
24 pub fn peek(&mut self, offset: usize) -> Option<&T> {
25 assert!(offset<C);
26 self.fill_to( offset );
27 self.data[(self.cur+offset)%C].as_ref()
28 }
29
30 fn fill_to(&mut self, qty: usize) {
31 for i in self.fill..=qty {
32 if let Some(x) = self.iter.next() {
33 self.data[(self.cur+i)%C].replace( x );
34 self.fill += 1;
35 }
36 }
37 }
38}
39
40impl<const C: usize, T, U> std::iter::Iterator for LookAhead<C,T,U>
41where
42 U: Iterator<Item=T> + Sized
43{
44 type Item=T;
45
46 fn next(&mut self) -> Option<T> {
47 if self.fill == 0 {
48 self.iter.next()
49 } else {
50 let old = self.cur;
51 self.cur = (self.cur+1)%C;
52 self.fill -= 1;
53 self.data[old].take()
54 }
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn basic() {
64 let data = [1, 2, 3, 4, 5, 6, 7, 8];
65 let mut i = LookAhead::<3,_,_>::new(data.iter());
66 assert_eq!(i.next(), Some(&1));
67 assert_eq!(i.peek(1), Some(&&3));
68 assert_eq!(i.peek(0), Some(&&2));
69 assert_eq!(i.next(), Some(&2));
70 assert_eq!(i.peek(0), Some(&&3));
71 assert_eq!(i.next(), Some(&3));
72 assert_eq!(i.next(), Some(&4));
73 assert_eq!(i.next(), Some(&5));
74 assert_eq!(i.peek(0), Some(&&6));
75 assert_eq!(i.peek(1), Some(&&7));
76 assert_eq!(i.peek(2), Some(&&8));
77 assert_eq!(i.next(), Some(&6));
78 assert_eq!(i.peek(2), None);
79 assert_eq!(i.next(), Some(&7));
80 assert_eq!(i.peek(2), None);
81 assert_eq!(i.next(), Some(&8));
82 assert_eq!(i.next(), None);
83 }
84}