diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/context.rs | 124 | ||||
| -rw-r--r-- | src/error.rs | 13 | ||||
| -rw-r--r-- | src/lib.rs | 110 | ||||
| -rw-r--r-- | src/parser.rs | 60 |
4 files changed, 199 insertions, 108 deletions
diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..78a7940 --- /dev/null +++ b/src/context.rs | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | use std::collections::HashMap; | ||
| 2 | |||
| 3 | use crate::{Identifier,IdentifierValue}; | ||
| 4 | |||
| 5 | pub type Context = HashMap<String,Value>; | ||
| 6 | |||
| 7 | pub trait MappedStructure { | ||
| 8 | fn get_value(&self, id: &Identifier) -> Option<Value>; | ||
| 9 | } | ||
| 10 | |||
| 11 | impl MappedStructure for Context { | ||
| 12 | fn get_value(&self, id: &Identifier) -> Option<Value> { | ||
| 13 | if id.len() == 0 { | ||
| 14 | return None; | ||
| 15 | } | ||
| 16 | let mut cur_val : Option<&Value> = if let IdentifierValue::Name(s) = &id[0] { | ||
| 17 | self.get(s) | ||
| 18 | } else { | ||
| 19 | return None; | ||
| 20 | }; | ||
| 21 | if cur_val.is_none() { | ||
| 22 | return None; | ||
| 23 | } | ||
| 24 | |||
| 25 | for idx in 1..id.len() { | ||
| 26 | if let IdentifierValue::Name(s) = &id[idx] && | ||
| 27 | let Some(Value::Dictionary(d)) = &cur_val { | ||
| 28 | cur_val.replace( if let Some(v) = d.get(s) { | ||
| 29 | v | ||
| 30 | } else { | ||
| 31 | return None; | ||
| 32 | }); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | return cur_val.cloned(); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | #[derive(Debug,Clone)] | ||
| 41 | pub enum Value { | ||
| 42 | Dictionary(Context), | ||
| 43 | List(Vec<Value>), | ||
| 44 | String(String), | ||
| 45 | Int(i64), | ||
| 46 | Float(f64), | ||
| 47 | Identifier(Identifier), | ||
| 48 | } | ||
| 49 | |||
| 50 | impl From<&str> for Value { | ||
| 51 | fn from(val: &str ) -> Value { | ||
| 52 | Value::String(val.into()) | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | impl From<String> for Value { | ||
| 57 | fn from(val: String) -> Value { | ||
| 58 | Value::String(val) | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | impl From<i64> for Value { | ||
| 63 | fn from(val: i64) -> Value { | ||
| 64 | Value::Int(val) | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | impl From<f64> for Value { | ||
| 69 | fn from(val: f64) -> Value { | ||
| 70 | Value::Float(val) | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | impl From<Vec<Value>> for Value { | ||
| 75 | fn from(val: Vec<Value>) -> Value { | ||
| 76 | Value::List(val) | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | impl From<&[Value]> for Value { | ||
| 81 | fn from(val: &[Value]) -> Value { | ||
| 82 | Value::List(Vec::from(val)) | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | impl From<Context> for Value { | ||
| 87 | fn from(val: Context) -> Value { | ||
| 88 | Value::Dictionary(val) | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | impl<const N: usize> From<[(String,Value); N]> for Value { | ||
| 93 | fn from(val: [(String,Value); N]) -> Value { | ||
| 94 | Value::Dictionary(HashMap::from(val)) | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | /* | ||
| 99 | impl MappedStructure for Value { | ||
| 100 | fn get_value(&self, id: &Identifier) -> Option<Value> { | ||
| 101 | if id.len() == 0 { | ||
| 102 | return Some(self); | ||
| 103 | } | ||
| 104 | match Value { | ||
| 105 | Value::Dictionary(dict) => { | ||
| 106 | } | ||
| 107 | } | ||
| 108 | let mut cur_val : Option<&Value> = Some(&self); | ||
| 109 | |||
| 110 | for idx in 0..id.len() { | ||
| 111 | if let IdentifierValue::Name(s) = &id[idx] && | ||
| 112 | let Some(Value::Dictionary(d)) = &cur_val { | ||
| 113 | cur_val.replace( if let Some(v) = d.get(s) { | ||
| 114 | v | ||
| 115 | } else { | ||
| 116 | return None; | ||
| 117 | }); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | return cur_val.cloned(); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | */ | ||
diff --git a/src/error.rs b/src/error.rs index a2b6d96..a2349ee 100644 --- a/src/error.rs +++ b/src/error.rs | |||
| @@ -11,15 +11,22 @@ pub struct CrimError { | |||
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | impl CrimError { | 13 | impl CrimError { |
| 14 | pub fn new( position: Position, what: String ) -> Self { | 14 | pub fn parse( position: Position, what: String ) -> Self { |
| 15 | CrimError { | 15 | Self { |
| 16 | position, | 16 | position, |
| 17 | what, | 17 | what, |
| 18 | } | 18 | } |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | pub fn other(what: String) -> Self { | ||
| 22 | Self { | ||
| 23 | position: Position::none(), | ||
| 24 | what, | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 21 | pub fn eos( context: &str ) -> Self { | 28 | pub fn eos( context: &str ) -> Self { |
| 22 | CrimError { | 29 | Self { |
| 23 | position: Position::none(), | 30 | position: Position::none(), |
| 24 | what: format!("Premature end of stream while looking for {}", context), | 31 | what: format!("Premature end of stream while looking for {}", context), |
| 25 | } | 32 | } |
| @@ -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 ), |
diff --git a/src/parser.rs b/src/parser.rs index 83144fb..be5492c 100644 --- a/src/parser.rs +++ b/src/parser.rs | |||
| @@ -76,7 +76,7 @@ impl<'a> SymbolHelper for Option<Symbol<'a>> { | |||
| 76 | _ => false | 76 | _ => false |
| 77 | }) | 77 | }) |
| 78 | } else { | 78 | } else { |
| 79 | Err(CrimError::new( | 79 | Err(CrimError::parse( |
| 80 | Position::none(), | 80 | Position::none(), |
| 81 | "Unexpeceted end of stream.".to_string() | 81 | "Unexpeceted end of stream.".to_string() |
| 82 | )) | 82 | )) |
| @@ -172,11 +172,11 @@ impl Parser { | |||
| 172 | 172 | ||
| 173 | fn lex_error<T>(&self, error: &Symbol) -> CrimResult<T> { | 173 | fn lex_error<T>(&self, error: &Symbol) -> CrimResult<T> { |
| 174 | if let SymbolType::Error{what} = error.symbol() { | 174 | if let SymbolType::Error{what} = error.symbol() { |
| 175 | Err(CrimError::new( *error.start(), | 175 | Err(CrimError::parse( *error.start(), |
| 176 | format!("What: {:?}", *what) | 176 | format!("What: {:?}", *what) |
| 177 | )) | 177 | )) |
| 178 | } else { | 178 | } else { |
| 179 | Err(CrimError::new( Position::none(), "Not an error?".into())) | 179 | Err(CrimError::parse( Position::none(), "Not an error?".into())) |
| 180 | } | 180 | } |
| 181 | } | 181 | } |
| 182 | 182 | ||
| @@ -214,7 +214,7 @@ impl Parser { | |||
| 214 | fn parse_tag_view(&self, ctx: &mut Context) -> CrimResult<View> { | 214 | fn parse_tag_view(&self, ctx: &mut Context) -> CrimResult<View> { |
| 215 | let tb = self.parse_open_tag( ctx )?; | 215 | let tb = self.parse_open_tag( ctx )?; |
| 216 | if !tb.is_name( &SymbolType::View ) { | 216 | if !tb.is_name( &SymbolType::View ) { |
| 217 | return Err(CrimError::new(tb.start_pos(), | 217 | return Err(CrimError::parse(tb.start_pos(), |
| 218 | "Unexpected tag type, only frament allowed at root".into() | 218 | "Unexpected tag type, only frament allowed at root".into() |
| 219 | )); | 219 | )); |
| 220 | } | 220 | } |
| @@ -260,7 +260,7 @@ impl Parser { | |||
| 260 | }); | 260 | }); |
| 261 | } else { | 261 | } else { |
| 262 | if !all_text { | 262 | if !all_text { |
| 263 | return Err(CrimError::new( | 263 | return Err(CrimError::parse( |
| 264 | *end.start(), | 264 | *end.start(), |
| 265 | "You cannot mix non-output and output tags in a view.".to_string() | 265 | "You cannot mix non-output and output tags in a view.".to_string() |
| 266 | )); | 266 | )); |
| @@ -269,7 +269,7 @@ impl Parser { | |||
| 269 | return tb.build_view(ctx,outputs); | 269 | return tb.build_view(ctx,outputs); |
| 270 | } else { | 270 | } else { |
| 271 | // They don't match, complain. | 271 | // They don't match, complain. |
| 272 | return Err(CrimError::new( | 272 | return Err(CrimError::parse( |
| 273 | *end.start(), | 273 | *end.start(), |
| 274 | "Mismatched open and closing tags.".to_string() | 274 | "Mismatched open and closing tags.".to_string() |
| 275 | )); | 275 | )); |
| @@ -279,7 +279,7 @@ impl Parser { | |||
| 279 | return self.lex_error( &ctx.cur().unwrap() ); | 279 | return self.lex_error( &ctx.cur().unwrap() ); |
| 280 | } | 280 | } |
| 281 | _ => { | 281 | _ => { |
| 282 | return Err(CrimError::new( | 282 | return Err(CrimError::parse( |
| 283 | *ctx.cur().unwrap().start(), | 283 | *ctx.cur().unwrap().start(), |
| 284 | format!("Unexpected tag in view root: {:?}", ctx.cur().unwrap().symbol()) | 284 | format!("Unexpected tag in view root: {:?}", ctx.cur().unwrap().symbol()) |
| 285 | )); | 285 | )); |
| @@ -302,7 +302,7 @@ impl Parser { | |||
| 302 | tb.set_name( name_sym ); | 302 | tb.set_name( name_sym ); |
| 303 | } | 303 | } |
| 304 | _ => { | 304 | _ => { |
| 305 | return Err(CrimError::new( | 305 | return Err(CrimError::parse( |
| 306 | *ctx.cur().unwrap().start(), | 306 | *ctx.cur().unwrap().start(), |
| 307 | "Unexpected symbol".to_string() | 307 | "Unexpected symbol".to_string() |
| 308 | )); | 308 | )); |
| @@ -318,13 +318,13 @@ impl Parser { | |||
| 318 | if let Some(end_sym) = ctx.cur() { | 318 | if let Some(end_sym) = ctx.cur() { |
| 319 | match end_sym.symbol() { | 319 | match end_sym.symbol() { |
| 320 | SymbolType::EndPoint => { | 320 | SymbolType::EndPoint => { |
| 321 | tb.set_type( TagType::BinaryOpen ); | 321 | tb.set_type( TagType::MultinaryOpen ); |
| 322 | } | 322 | } |
| 323 | SymbolType::EndFlat => { | 323 | SymbolType::EndFlat => { |
| 324 | tb.set_type( TagType::Unary ); | 324 | tb.set_type( TagType::Unary ); |
| 325 | } | 325 | } |
| 326 | _ => { | 326 | _ => { |
| 327 | return Err(CrimError::new( | 327 | return Err(CrimError::parse( |
| 328 | *end_sym.start(), | 328 | *end_sym.start(), |
| 329 | format!("Unexpected symbol {:?} looking for end of tag.", end_sym.symbol()) | 329 | format!("Unexpected symbol {:?} looking for end of tag.", end_sym.symbol()) |
| 330 | )); | 330 | )); |
| @@ -339,20 +339,20 @@ impl Parser { | |||
| 339 | 339 | ||
| 340 | fn parse_end_tag<'a>(&self, ctx: &mut Context<'a> ) -> CrimResult<Symbol<'a>> { | 340 | fn parse_end_tag<'a>(&self, ctx: &mut Context<'a> ) -> CrimResult<Symbol<'a>> { |
| 341 | if !ctx.cur().is("end tag",|s| *s == SymbolType::StartPoint )? { | 341 | if !ctx.cur().is("end tag",|s| *s == SymbolType::StartPoint )? { |
| 342 | return Err(CrimError::new( | 342 | return Err(CrimError::parse( |
| 343 | *ctx.cur().unwrap().start(), | 343 | *ctx.cur().unwrap().start(), |
| 344 | "Invalid end tag?".to_string() | 344 | "Invalid end tag?".to_string() |
| 345 | )); | 345 | )); |
| 346 | } | 346 | } |
| 347 | if !ctx.next().is_valid_tag_name()? { | 347 | if !ctx.next().is_valid_tag_name()? { |
| 348 | return Err(CrimError::new( | 348 | return Err(CrimError::parse( |
| 349 | *ctx.cur().unwrap().start(), | 349 | *ctx.cur().unwrap().start(), |
| 350 | "Invalid tag name".to_string() | 350 | "Invalid tag name".to_string() |
| 351 | )); | 351 | )); |
| 352 | } | 352 | } |
| 353 | let name = ctx.cur().unwrap(); | 353 | let name = ctx.cur().unwrap(); |
| 354 | if !ctx.next().is("end of end tag", |s| *s == SymbolType::EndFlat )? { | 354 | if !ctx.next().is("end of end tag", |s| *s == SymbolType::EndFlat )? { |
| 355 | return Err(CrimError::new( | 355 | return Err(CrimError::parse( |
| 356 | *ctx.cur().unwrap().start(), | 356 | *ctx.cur().unwrap().start(), |
| 357 | "Tag should be <| |] style end tag.".to_string(), | 357 | "Tag should be <| |] style end tag.".to_string(), |
| 358 | )); | 358 | )); |
| @@ -386,7 +386,7 @@ impl Parser { | |||
| 386 | return Ok(tb); | 386 | return Ok(tb); |
| 387 | } else { | 387 | } else { |
| 388 | // They don't match, complain. | 388 | // They don't match, complain. |
| 389 | return Err(CrimError::new( | 389 | return Err(CrimError::parse( |
| 390 | *end.start(), | 390 | *end.start(), |
| 391 | "Mismatched open and closing tags.".to_string() | 391 | "Mismatched open and closing tags.".to_string() |
| 392 | )); | 392 | )); |
| @@ -396,7 +396,7 @@ impl Parser { | |||
| 396 | return self.lex_error( &ctx.cur().unwrap() ); | 396 | return self.lex_error( &ctx.cur().unwrap() ); |
| 397 | } | 397 | } |
| 398 | _ => { | 398 | _ => { |
| 399 | return Err(CrimError::new( | 399 | return Err(CrimError::parse( |
| 400 | *ctx.cur().unwrap().start(), | 400 | *ctx.cur().unwrap().start(), |
| 401 | format!("Unexpected token: {:?}", ctx.cur().unwrap().symbol()), | 401 | format!("Unexpected token: {:?}", ctx.cur().unwrap().symbol()), |
| 402 | )); | 402 | )); |
| @@ -438,7 +438,7 @@ impl Parser { | |||
| 438 | id.push( IdentifierValue::Name(s.to_string()) ); | 438 | id.push( IdentifierValue::Name(s.to_string()) ); |
| 439 | } | 439 | } |
| 440 | } else { | 440 | } else { |
| 441 | return Err(CrimError::new( ctx.cur().unwrap().start().clone(), format!("Expeceted identifier, found {:?}", ctx.cur().unwrap().symbol() ) ) ); | 441 | return Err(CrimError::parse( ctx.cur().unwrap().start().clone(), format!("Expeceted identifier, found {:?}", ctx.cur().unwrap().symbol() ) ) ); |
| 442 | } | 442 | } |
| 443 | 443 | ||
| 444 | if !ctx.next().is("identifier seperator",|s| *s == SymbolType::Period )? { | 444 | if !ctx.next().is("identifier seperator",|s| *s == SymbolType::Period )? { |
| @@ -462,7 +462,7 @@ impl Parser { | |||
| 462 | let SymbolType::Literal(lv) = sym.symbol() { | 462 | let SymbolType::Literal(lv) = sym.symbol() { |
| 463 | tb.add_prop( s.to_string(), lv.to_string() ); | 463 | tb.add_prop( s.to_string(), lv.to_string() ); |
| 464 | } else { | 464 | } else { |
| 465 | return Err(CrimError::new(Position::none(),"Expected quoted literal string".to_string())); | 465 | return Err(CrimError::parse(Position::none(),"Expected quoted literal string".to_string())); |
| 466 | } | 466 | } |
| 467 | } else { | 467 | } else { |
| 468 | break; | 468 | break; |
| @@ -480,7 +480,8 @@ impl Parser { | |||
| 480 | enum TagType { | 480 | enum TagType { |
| 481 | Unknown, | 481 | Unknown, |
| 482 | Unary, | 482 | Unary, |
| 483 | BinaryOpen, | 483 | MultinaryOpen, |
| 484 | MultinaryMid, | ||
| 484 | } | 485 | } |
| 485 | 486 | ||
| 486 | struct TagBuilder<'a> { | 487 | struct TagBuilder<'a> { |
| @@ -523,7 +524,8 @@ impl<'a> TagBuilder<'a> { | |||
| 523 | } | 524 | } |
| 524 | 525 | ||
| 525 | pub fn can_have_children(&self) -> bool { | 526 | pub fn can_have_children(&self) -> bool { |
| 526 | if self.tag_type == TagType::BinaryOpen { | 527 | if self.tag_type == TagType::MultinaryOpen || |
| 528 | self.tag_type == TagType::MultinaryMid { | ||
| 527 | true | 529 | true |
| 528 | } else { | 530 | } else { |
| 529 | false | 531 | false |
| @@ -580,7 +582,7 @@ impl<'a> TagBuilder<'a> { | |||
| 580 | let name = if let ParamValue::Literal(s) = self.params.swap_remove(0) { | 582 | let name = if let ParamValue::Literal(s) = self.params.swap_remove(0) { |
| 581 | s.to_string() | 583 | s.to_string() |
| 582 | } else { | 584 | } else { |
| 583 | return Err(CrimError::new(Position::none(), "Expected string literal for view name.".to_string())); | 585 | return Err(CrimError::parse(Position::none(), "Expected string literal for view name.".to_string())); |
| 584 | }; | 586 | }; |
| 585 | Ok(View { | 587 | Ok(View { |
| 586 | name: name, | 588 | name: name, |
| @@ -590,10 +592,10 @@ impl<'a> TagBuilder<'a> { | |||
| 590 | layout: self.props.get("layout").cloned(), | 592 | layout: self.props.get("layout").cloned(), |
| 591 | }) | 593 | }) |
| 592 | } else { | 594 | } else { |
| 593 | Err(CrimError::new(self.start_pos, format!("Expected tag type view, found {:?}", sym.symbol()))) | 595 | Err(CrimError::parse(self.start_pos, format!("Expected tag type view, found {:?}", sym.symbol()))) |
| 594 | } | 596 | } |
| 595 | } else { | 597 | } else { |
| 596 | Err(CrimError::new(self.start_pos, "Broken Parser? No tag type found when building view.".to_string())) | 598 | Err(CrimError::parse(self.start_pos, "Broken Parser? No tag type found when building view.".to_string())) |
| 597 | } | 599 | } |
| 598 | } | 600 | } |
| 599 | 601 | ||
| @@ -603,17 +605,17 @@ impl<'a> TagBuilder<'a> { | |||
| 603 | let name = if let ParamValue::Literal(s) = self.params.swap_remove(0) { | 605 | let name = if let ParamValue::Literal(s) = self.params.swap_remove(0) { |
| 604 | s.to_string() | 606 | s.to_string() |
| 605 | } else { | 607 | } else { |
| 606 | return Err(CrimError::new(Position::none(), "Expected string literal for output name.".into())); | 608 | return Err(CrimError::parse(Position::none(), "Expected string literal for output name.".into())); |
| 607 | }; | 609 | }; |
| 608 | Ok(Output { | 610 | Ok(Output { |
| 609 | name: name, | 611 | name: name, |
| 610 | code: self.children, | 612 | code: self.children, |
| 611 | }) | 613 | }) |
| 612 | } else { | 614 | } else { |
| 613 | Err(CrimError::new(self.start_pos, format!("Expected tag type view, found {:?}", sym.symbol()))) | 615 | Err(CrimError::parse(self.start_pos, format!("Expected tag type view, found {:?}", sym.symbol()))) |
| 614 | } | 616 | } |
| 615 | } else { | 617 | } else { |
| 616 | Err(CrimError::new(self.start_pos, "Broken Parser? No tag type found when building view.".into())) | 618 | Err(CrimError::parse(self.start_pos, "Broken Parser? No tag type found when building view.".into())) |
| 617 | } | 619 | } |
| 618 | } | 620 | } |
| 619 | 621 | ||
| @@ -624,7 +626,7 @@ impl<'a> TagBuilder<'a> { | |||
| 624 | let id = if let ParamValue::Identifier(id) = self.params.swap_remove(0) { | 626 | let id = if let ParamValue::Identifier(id) = self.params.swap_remove(0) { |
| 625 | id | 627 | id |
| 626 | } else { | 628 | } else { |
| 627 | return Err(CrimError::new(Position::none(), "Identifier for loop variable name.".into())); | 629 | return Err(CrimError::parse(Position::none(), "Identifier for loop variable name.".into())); |
| 628 | }; | 630 | }; |
| 629 | Ok(Token::Loop(id, self.children)) | 631 | Ok(Token::Loop(id, self.children)) |
| 630 | } | 632 | } |
| @@ -632,16 +634,16 @@ impl<'a> TagBuilder<'a> { | |||
| 632 | let id = if let ParamValue::Identifier(id) = self.params.swap_remove(0) { | 634 | let id = if let ParamValue::Identifier(id) = self.params.swap_remove(0) { |
| 633 | id | 635 | id |
| 634 | } else { | 636 | } else { |
| 635 | return Err(CrimError::new(Position::none(), "Identifier for show variable name.".into())); | 637 | return Err(CrimError::parse(Position::none(), "Identifier for show variable name.".into())); |
| 636 | }; | 638 | }; |
| 637 | Ok(Token::Show(id, self.props)) | 639 | Ok(Token::Show(id, self.props)) |
| 638 | } | 640 | } |
| 639 | _ => { | 641 | _ => { |
| 640 | Err(CrimError::new( self.start_pos, "Bad tag type".into())) | 642 | Err(CrimError::parse( self.start_pos, "Bad tag type".into())) |
| 641 | } | 643 | } |
| 642 | } | 644 | } |
| 643 | } else { | 645 | } else { |
| 644 | Err(CrimError::new(self.start_pos, "Bad tag type".into())) | 646 | Err(CrimError::parse(self.start_pos, "Bad tag type".into())) |
| 645 | } | 647 | } |
| 646 | } | 648 | } |
| 647 | } | 649 | } |
