diff options
Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 110 |
1 files changed, 34 insertions, 76 deletions
| @@ -7,9 +7,11 @@ mod lexer; | |||
| 7 | mod parser; | 7 | mod parser; |
| 8 | mod position; | 8 | mod position; |
| 9 | mod error; | 9 | mod error; |
| 10 | mod context; | ||
| 10 | 11 | ||
| 11 | pub use error::{CrimError,CrimResult}; | 12 | pub use error::{CrimError,CrimResult}; |
| 12 | pub use position::*; | 13 | pub use position::*; |
| 14 | pub use context::{Context,Value,MappedStructure}; | ||
| 13 | 15 | ||
| 14 | #[derive(Debug)] | 16 | #[derive(Debug)] |
| 15 | pub struct Crimtag { | 17 | pub struct Crimtag { |
| @@ -39,7 +41,7 @@ struct View { | |||
| 39 | } | 41 | } |
| 40 | 42 | ||
| 41 | impl View { | 43 | impl 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)] |
| 72 | pub 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)] | ||
| 82 | pub enum IdentifierValue { | 74 | pub enum IdentifierValue { |
| 83 | Name(String), | 75 | Name(String), |
| 84 | Index(usize), | 76 | Index(usize), |
| 85 | } | 77 | } |
| 86 | 78 | ||
| 87 | pub type Identifier = Vec<IdentifierValue>; | 79 | pub type Identifier = Vec<IdentifierValue>; |
| 88 | pub type Context = HashMap<String,Value>; | ||
| 89 | |||
| 90 | pub trait MappedStructure { | ||
| 91 | fn get_value(&self, id: &Identifier) -> Option<Value>; | ||
| 92 | } | ||
| 93 | |||
| 94 | impl 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 | ||
| 123 | impl Crimtag { | 81 | impl 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 | ||
| 237 | fn exec(input: &impl MappedStructure, tokens: &Vec<Token>, buf: &mut String) -> Result<(),CrimError> { | 195 | fn 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 ), |
