diff options
| author | Mike Buland <mike@xagasoft.com> | 2026-06-13 00:21:12 -0700 |
|---|---|---|
| committer | Mike Buland <mike@xagasoft.com> | 2026-06-13 00:21:12 -0700 |
| commit | 6188fa4c32160846908e4ff7654c4ff7bc177797 (patch) | |
| tree | dcd14f050f579809ac5c05116759c2e764ac9448 | |
| parent | 3c9a65f0a576397024c76bcc33950796ec3297ec (diff) | |
| download | crimtag-6188fa4c32160846908e4ff7654c4ff7bc177797.tar.gz crimtag-6188fa4c32160846908e4ff7654c4ff7bc177797.tar.bz2 crimtag-6188fa4c32160846908e4ff7654c4ff7bc177797.tar.xz crimtag-6188fa4c32160846908e4ff7654c4ff7bc177797.zip | |
Adding root access in identifiers.
There's an issue, it doesn't compile yet.
| -rw-r--r-- | src/context.rs | 38 | ||||
| -rw-r--r-- | src/lexer.rs | 5 | ||||
| -rw-r--r-- | src/lib.rs | 18 | ||||
| -rw-r--r-- | src/parser.rs | 6 |
4 files changed, 56 insertions, 11 deletions
diff --git a/src/context.rs b/src/context.rs index e4cd5c2..7484a1f 100644 --- a/src/context.rs +++ b/src/context.rs | |||
| @@ -5,11 +5,12 @@ use crate::{Identifier,IdentifierValue}; | |||
| 5 | pub type Context = HashMap<String,Value>; | 5 | pub type Context = HashMap<String,Value>; |
| 6 | 6 | ||
| 7 | pub trait MappedStructure { | 7 | pub trait MappedStructure { |
| 8 | fn get_value(&self, id: &Identifier) -> Option<Value>; | 8 | fn get_value(&self, id: &[IdentifierValue]) -> Option<Value>; |
| 9 | |||
| 9 | } | 10 | } |
| 10 | 11 | ||
| 11 | impl MappedStructure for Context { | 12 | impl MappedStructure for Context { |
| 12 | fn get_value(&self, id: &Identifier) -> Option<Value> { | 13 | fn get_value(&self, id: &[IdentifierValue]) -> Option<Value> { |
| 13 | if id.len() == 0 { | 14 | if id.len() == 0 { |
| 14 | return None; | 15 | return None; |
| 15 | } | 16 | } |
| @@ -37,6 +38,39 @@ impl MappedStructure for Context { | |||
| 37 | } | 38 | } |
| 38 | } | 39 | } |
| 39 | 40 | ||
| 41 | pub struct StatefulContext<'a, T: MappedStructure> { | ||
| 42 | root: &'a T, | ||
| 43 | current: &'a T, | ||
| 44 | } | ||
| 45 | |||
| 46 | impl<'a, T: MappedStructure> StatefulContext<'a, T> { | ||
| 47 | pub fn root( root: &'a T ) -> Self { | ||
| 48 | Self { | ||
| 49 | root, current: root, | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | pub fn local(&self, current: &'a T ) -> Self { | ||
| 54 | Self { | ||
| 55 | root: self.root, | ||
| 56 | current | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | impl<'a, T: MappedStructure> MappedStructure for StatefulContext<'a,T> { | ||
| 62 | fn get_value(&self, id: &[IdentifierValue]) -> Option<Value> { | ||
| 63 | if id.is_empty() { | ||
| 64 | return None; | ||
| 65 | } | ||
| 66 | if id[0] == IdentifierValue::Root { | ||
| 67 | self.root.get_value( &id[1..] ) | ||
| 68 | } else { | ||
| 69 | self.current.get_value( id ) | ||
| 70 | } | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 40 | #[derive(Debug,Clone)] | 74 | #[derive(Debug,Clone)] |
| 41 | pub enum Value { | 75 | pub enum Value { |
| 42 | Dictionary(Context), | 76 | Dictionary(Context), |
diff --git a/src/lexer.rs b/src/lexer.rs index afff5a8..4e95854 100644 --- a/src/lexer.rs +++ b/src/lexer.rs | |||
| @@ -25,6 +25,7 @@ pub enum SymbolType<'a> { | |||
| 25 | ElIf, | 25 | ElIf, |
| 26 | Else, | 26 | Else, |
| 27 | 27 | ||
| 28 | Sharp, | ||
| 28 | Equals, | 29 | Equals, |
| 29 | Period, | 30 | Period, |
| 30 | Token(&'a str), | 31 | Token(&'a str), |
| @@ -224,6 +225,10 @@ impl<'a> Lexer<'a> { | |||
| 224 | Some('"') => { | 225 | Some('"') => { |
| 225 | return self.parse_literal_str(); | 226 | return self.parse_literal_str(); |
| 226 | } | 227 | } |
| 228 | Some('#') => { | ||
| 229 | self.next(); | ||
| 230 | return Some(Symbol::new(SymbolType::Sharp, self.pos, self.pos)); | ||
| 231 | } | ||
| 227 | Some('=') => { | 232 | Some('=') => { |
| 228 | self.next(); | 233 | self.next(); |
| 229 | return Some(Symbol::new(SymbolType::Equals, self.pos, self.pos)); | 234 | return Some(Symbol::new(SymbolType::Equals, self.pos, self.pos)); |
| @@ -11,7 +11,7 @@ mod context; | |||
| 11 | 11 | ||
| 12 | pub use error::{CrimError,CrimResult}; | 12 | pub use error::{CrimError,CrimResult}; |
| 13 | pub use position::*; | 13 | pub use position::*; |
| 14 | pub use context::{Context,Value,MappedStructure}; | 14 | pub use context::{Context,Value,MappedStructure,StatefulContext}; |
| 15 | 15 | ||
| 16 | #[derive(Debug)] | 16 | #[derive(Debug)] |
| 17 | pub struct Crimtag { | 17 | pub struct Crimtag { |
| @@ -41,11 +41,12 @@ struct View { | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | impl View { | 43 | impl View { |
| 44 | fn process(&self, input: &impl MappedStructure) -> CrimResult<Context> { | 44 | fn process<T: MappedStructure>(&self, input: &T) -> CrimResult<Context> { |
| 45 | let mut out_vars = Context::new(); | 45 | let mut out_vars = Context::new(); |
| 46 | for output in &self.outputs { | 46 | for output in &self.outputs { |
| 47 | let mut buf = String::new(); | 47 | let mut buf = String::new(); |
| 48 | exec( input, &output.code, &mut buf )?; | 48 | let sc = StatefulContext::root( input ); |
| 49 | exec( &sc, &output.code, &mut buf )?; | ||
| 49 | out_vars.insert( output.name.clone(), Value::String(buf) ); | 50 | out_vars.insert( output.name.clone(), Value::String(buf) ); |
| 50 | } | 51 | } |
| 51 | Ok(out_vars) | 52 | Ok(out_vars) |
| @@ -68,8 +69,9 @@ enum Token { | |||
| 68 | Text(String), | 69 | Text(String), |
| 69 | } | 70 | } |
| 70 | 71 | ||
| 71 | #[derive(Debug,Clone)] | 72 | #[derive(Debug,Clone,PartialEq)] |
| 72 | pub enum IdentifierValue { | 73 | pub enum IdentifierValue { |
| 74 | Root, | ||
| 73 | Name(String), | 75 | Name(String), |
| 74 | Index(usize), | 76 | Index(usize), |
| 75 | } | 77 | } |
| @@ -161,7 +163,7 @@ impl Crimtag { | |||
| 161 | } | 163 | } |
| 162 | } | 164 | } |
| 163 | 165 | ||
| 164 | pub fn render_partial(&self, view: &str, input: &impl MappedStructure ) -> CrimResult<Context> { | 166 | pub fn render_partial<T: MappedStructure>(&self, view: &str, input: &T ) -> CrimResult<Context> { |
| 165 | if let Some(view) = self.views.get(view) { | 167 | if let Some(view) = self.views.get(view) { |
| 166 | return view.process( input ) | 168 | return view.process( input ) |
| 167 | } else { | 169 | } else { |
| @@ -169,7 +171,7 @@ impl Crimtag { | |||
| 169 | } | 171 | } |
| 170 | } | 172 | } |
| 171 | 173 | ||
| 172 | pub fn render(&self, view: &str, input: &impl MappedStructure ) -> CrimResult<String> { | 174 | pub fn render<T: MappedStructure>(&self, view: &str, input: &T ) -> CrimResult<String> { |
| 173 | if let Some(view) = self.views.get( view ) { | 175 | if let Some(view) = self.views.get( view ) { |
| 174 | //println!("::Token tree::\n{:?}", view ); | 176 | //println!("::Token tree::\n{:?}", view ); |
| 175 | let mut output = view.process( input )?; | 177 | let mut output = view.process( input )?; |
| @@ -191,7 +193,7 @@ impl Crimtag { | |||
| 191 | } | 193 | } |
| 192 | } | 194 | } |
| 193 | 195 | ||
| 194 | fn exec(input: &impl MappedStructure, tokens: &Vec<Token>, buf: &mut String) -> CrimResult<()> { | 196 | fn exec<T: MappedStructure>(input: &StatefulContext<T>, tokens: &Vec<Token>, buf: &mut String) -> CrimResult<()> { |
| 195 | for token in tokens { | 197 | for token in tokens { |
| 196 | match token { | 198 | match token { |
| 197 | Token::Loop(ident,code) => { | 199 | Token::Loop(ident,code) => { |
| @@ -199,7 +201,7 @@ fn exec(input: &impl MappedStructure, tokens: &Vec<Token>, buf: &mut String) -> | |||
| 199 | let Value::List(list) = value { | 201 | let Value::List(list) = value { |
| 200 | for rec in &list { | 202 | for rec in &list { |
| 201 | if let Value::Dictionary(d) = rec { | 203 | if let Value::Dictionary(d) = rec { |
| 202 | exec( d, code, buf )? | 204 | exec( &input.local(d), code, buf )? |
| 203 | } | 205 | } |
| 204 | } | 206 | } |
| 205 | } | 207 | } |
diff --git a/src/parser.rs b/src/parser.rs index fff00b1..d1fe4d7 100644 --- a/src/parser.rs +++ b/src/parser.rs | |||
| @@ -360,7 +360,7 @@ impl Parser { | |||
| 360 | tb.add_param( ParamValue::Literal(s.to_string()) ); | 360 | tb.add_param( ParamValue::Literal(s.to_string()) ); |
| 361 | ctx.next(); | 361 | ctx.next(); |
| 362 | } | 362 | } |
| 363 | SymbolType::Token(_) => { | 363 | SymbolType::Token(_) | SymbolType::Sharp => { |
| 364 | if ctx.peek().is("tag data", |s| *s == SymbolType::Equals)? { | 364 | if ctx.peek().is("tag data", |s| *s == SymbolType::Equals)? { |
| 365 | break; | 365 | break; |
| 366 | } | 366 | } |
| @@ -377,6 +377,10 @@ impl Parser { | |||
| 377 | fn parse_identifier(&self, ctx: &mut Context ) -> CrimResult<ParamValue> { | 377 | fn parse_identifier(&self, ctx: &mut Context ) -> CrimResult<ParamValue> { |
| 378 | let mut id = Identifier::new(); | 378 | let mut id = Identifier::new(); |
| 379 | 379 | ||
| 380 | if ctx.cur().is("identifier",|s| matches!( s, SymbolType::Sharp))? { | ||
| 381 | id.push( IdentifierValue::Root ); | ||
| 382 | ctx.next(); | ||
| 383 | } | ||
| 380 | loop { | 384 | loop { |
| 381 | if ctx.cur().is("identifier",|s| matches!( s, SymbolType::Token(_) ))? { | 385 | if ctx.cur().is("identifier",|s| matches!( s, SymbolType::Token(_) ))? { |
| 382 | if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() { | 386 | if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() { |
