summaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2026-06-11 11:35:24 -0700
committerMike Buland <mike@xagasoft.com>2026-06-11 11:35:24 -0700
commitcffacc4dc4a46b525250772e87fd69a2f1c64dc2 (patch)
tree37ef3b84667668540bdb2bc64576f7eee9bc9c3c /src/lib.rs
parent92dbff3cda66a2a677f0c2306bb8508c64884445 (diff)
downloadcrimtag-cffacc4dc4a46b525250772e87fd69a2f1c64dc2.tar.gz
crimtag-cffacc4dc4a46b525250772e87fd69a2f1c64dc2.tar.bz2
crimtag-cffacc4dc4a46b525250772e87fd69a2f1c64dc2.tar.xz
crimtag-cffacc4dc4a46b525250772e87fd69a2f1c64dc2.zip
Split things out, made things easier to use.
CrimError now has several constructors for different cases, so it's easier to use, using constructors is normalized now. Value has a load of From implementations now so it's much, much, much easier to use in practice.
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs110
1 files changed, 34 insertions, 76 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 9b838f3..b0bc688 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -7,9 +7,11 @@ mod lexer;
7mod parser; 7mod parser;
8mod position; 8mod position;
9mod error; 9mod error;
10mod context;
10 11
11pub use error::{CrimError,CrimResult}; 12pub use error::{CrimError,CrimResult};
12pub use position::*; 13pub use position::*;
14pub use context::{Context,Value,MappedStructure};
13 15
14#[derive(Debug)] 16#[derive(Debug)]
15pub struct Crimtag { 17pub struct Crimtag {
@@ -39,7 +41,7 @@ struct View {
39} 41}
40 42
41impl View { 43impl View {
42 fn process(&self, input: &impl MappedStructure) -> Result<Context, CrimError> { 44 fn process(&self, input: &impl MappedStructure) -> CrimResult<Context> {
43 let mut out_vars = Context::new(); 45 let mut out_vars = Context::new();
44 for output in &self.outputs { 46 for output in &self.outputs {
45 let mut buf = String::new(); 47 let mut buf = String::new();
@@ -69,56 +71,12 @@ enum Token {
69} 71}
70 72
71#[derive(Debug,Clone)] 73#[derive(Debug,Clone)]
72pub enum Value {
73 Dictionary(Context),
74 List(Vec<Value>),
75 String(String),
76 Int(i64),
77 Float(f64),
78 Identifier(Identifier),
79}
80
81#[derive(Debug,Clone)]
82pub enum IdentifierValue { 74pub enum IdentifierValue {
83 Name(String), 75 Name(String),
84 Index(usize), 76 Index(usize),
85} 77}
86 78
87pub type Identifier = Vec<IdentifierValue>; 79pub type Identifier = Vec<IdentifierValue>;
88pub type Context = HashMap<String,Value>;
89
90pub trait MappedStructure {
91 fn get_value(&self, id: &Identifier) -> Option<Value>;
92}
93
94impl MappedStructure for Context {
95 fn get_value(&self, id: &Identifier) -> Option<Value> {
96 if id.len() == 0 {
97 return None;
98 }
99 let mut cur_val : Option<&Value> = if let IdentifierValue::Name(s) = &id[0] {
100 self.get(s)
101 } else {
102 return None;
103 };
104 if cur_val.is_none() {
105 return None;
106 }
107
108 for idx in 1..id.len() {
109 if let IdentifierValue::Name(s) = &id[idx] &&
110 let Some(Value::Dictionary(d)) = &cur_val {
111 cur_val.replace( if let Some(v) = d.get(s) {
112 v
113 } else {
114 return None;
115 });
116 }
117 }
118
119 return cur_val.cloned();
120 }
121}
122 80
123impl Crimtag { 81impl Crimtag {
124 pub fn new() -> Self { 82 pub fn new() -> Self {
@@ -169,13 +127,13 @@ impl Crimtag {
169 Ok(()) 127 Ok(())
170 } 128 }
171 129
172 pub fn load_static(&mut self, data: &str) -> Result<(),CrimError> { 130 pub fn load_static(&mut self, data: &str) -> CrimResult<()> {
173 let source_id = self.id_source( &ViewSource::Static ); 131 let source_id = self.id_source( &ViewSource::Static );
174 let p = parser::Parser::new(); 132 let p = parser::Parser::new();
175 self.register_views( p.parse( &data, source_id )? ) 133 self.register_views( p.parse( &data, source_id )? )
176 } 134 }
177 135
178 pub fn load_external(&mut self, key: &str, data: &str) -> Result<(),CrimError> { 136 pub fn load_external(&mut self, key: &str, data: &str) -> CrimResult<()> {
179 let source_id = self.id_source( 137 let source_id = self.id_source(
180 &ViewSource::External{ key: key.to_string()} 138 &ViewSource::External{ key: key.to_string()}
181 ); 139 );
@@ -186,7 +144,7 @@ impl Crimtag {
186 ) 144 )
187 } 145 }
188 146
189 fn register_views(&mut self, views: Vec<View>) -> Result<(),CrimError> { 147 fn register_views(&mut self, views: Vec<View>) -> CrimResult<()> {
190 for view in views { 148 for view in views {
191 self.views.insert( view.name.clone(), view ); 149 self.views.insert( view.name.clone(), view );
192 } 150 }
@@ -205,15 +163,15 @@ impl Crimtag {
205 } 163 }
206 } 164 }
207 165
208 pub fn render_partial(&self, view: &str, input: &impl MappedStructure ) -> Result<Context,CrimError> { 166 pub fn render_partial(&self, view: &str, input: &impl MappedStructure ) -> CrimResult<Context> {
209 if let Some(view) = self.views.get(view) { 167 if let Some(view) = self.views.get(view) {
210 return view.process( input ) 168 return view.process( input )
211 } else { 169 } else {
212 return Err(CrimError::new(Position::none(),"No such view found".into())); 170 return Err(CrimError::other("No such view found".into()));
213 } 171 }
214 } 172 }
215 173
216 pub fn render(&self, view: &str, input: &impl MappedStructure ) -> Result<String,CrimError> { 174 pub fn render(&self, view: &str, input: &impl MappedStructure ) -> CrimResult<String> {
217 if let Some(view) = self.views.get( view ) { 175 if let Some(view) = self.views.get( view ) {
218 let mut output = view.process( input )?; 176 let mut output = view.process( input )?;
219 if let Some(l) = &view.layout { 177 if let Some(l) = &view.layout {
@@ -224,17 +182,17 @@ impl Crimtag {
224 182
225 Ok(s) 183 Ok(s)
226 } else { 184 } else {
227 Err(CrimError::new(Position::none(), "No content found in root layout.".into())) 185 Err(CrimError::other("No content found in root layout.".into()))
228 } 186 }
229 } 187 }
230 188
231 } else { 189 } else {
232 Err(CrimError::new(Position::none(),"No such view found".into())) 190 Err(CrimError::other("No such view found".into()))
233 } 191 }
234 } 192 }
235} 193}
236 194
237fn exec(input: &impl MappedStructure, tokens: &Vec<Token>, buf: &mut String) -> Result<(),CrimError> { 195fn exec(input: &impl MappedStructure, tokens: &Vec<Token>, buf: &mut String) -> CrimResult<()> {
238 for token in tokens { 196 for token in tokens {
239 match token { 197 match token {
240 Token::Loop(ident,code) => { 198 Token::Loop(ident,code) => {
@@ -363,28 +321,28 @@ Now with explicit outputs:
363 } 321 }
364 322
365 let ctx = Context::from([ 323 let ctx = Context::from([
366 ("people".to_string(), crate::Value::List(vec![ 324 ("people".to_string(), vec![
367 crate::Value::Dictionary(Context::from([ 325 [
368 ("first_name".to_string(), Value::String("Joe".to_string())), 326 ("first_name".into(), "Joe".into()),
369 ("last_name".to_string(), Value::String("Smith".to_string())), 327 ("last_name".into(), "Smith".into()),
370 ("title".to_string(), Value::String("CEO".to_string())), 328 ("title".into(), "CEO".into()),
371 ])), 329 ].into(),
372 crate::Value::Dictionary(Context::from([ 330 [
373 ("first_name".to_string(), Value::String("Chris".to_string())), 331 ("first_name".into(), "Chris".into()),
374 ("last_name".to_string(), Value::String("Perkens".to_string())), 332 ("last_name".into(), "Perkens".into()),
375 ("title".to_string(), Value::String("Baconeer".to_string())), 333 ("title".into(), "Baconeer".into()),
376 ])), 334 ].into(),
377 crate::Value::Dictionary(Context::from([ 335 [
378 ("first_name".to_string(), Value::String("Will".to_string())), 336 ("first_name".into(), "Will".into()),
379 ("last_name".to_string(), Value::String("Power".to_string())), 337 ("last_name".into(), "Power".into()),
380 ("title".to_string(), Value::String("CFO".to_string())), 338 ("title".into(), "CFO".into()),
381 ])), 339 ].into(),
382 crate::Value::Dictionary(Context::from([ 340 [
383 ("first_name".to_string(), Value::String("Justin".to_string())), 341 ("first_name".into(), "Justin".into()),
384 ("last_name".to_string(), Value::String("Time".to_string())), 342 ("last_name".into(), "Time".into()),
385 ("title".to_string(), Value::String("CIO".to_string())), 343 ("title".into(), "CIO".into()),
386 ])), 344 ].into(),
387 ])), 345 ].into()),
388 ]); 346 ]);
389 match ct.render("index", &ctx) { 347 match ct.render("index", &ctx) {
390 Ok(s) => println!("View result: {}", s ), 348 Ok(s) => println!("View result: {}", s ),