diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lexer.rs | 4 | ||||
| -rw-r--r-- | src/lib.rs | 98 | ||||
| -rw-r--r-- | src/parser.rs | 122 |
3 files changed, 103 insertions, 121 deletions
diff --git a/src/lexer.rs b/src/lexer.rs index c7249b7..0724df2 100644 --- a/src/lexer.rs +++ b/src/lexer.rs | |||
| @@ -5,12 +5,12 @@ use std::fmt; | |||
| 5 | 5 | ||
| 6 | use crate::Position; | 6 | use crate::Position; |
| 7 | 7 | ||
| 8 | #[derive(Debug,Copy,Clone,PartialEq)] | 8 | #[derive(Debug,Copy,Clone,PartialEq,Eq)] |
| 9 | pub enum ErrorType { | 9 | pub enum ErrorType { |
| 10 | UnexpectedChar(char), | 10 | UnexpectedChar(char), |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | #[derive(Debug,Copy,Clone,PartialEq)] | 13 | #[derive(Debug,Copy,Clone,PartialEq,Eq)] |
| 14 | pub enum SymbolType<'a> { | 14 | pub enum SymbolType<'a> { |
| 15 | StartFlat, | 15 | StartFlat, |
| 16 | StartPoint, | 16 | StartPoint, |
| @@ -30,6 +30,7 @@ pub enum ViewSource { | |||
| 30 | 30 | ||
| 31 | #[derive(Debug)] | 31 | #[derive(Debug)] |
| 32 | struct View { | 32 | struct View { |
| 33 | name: String, | ||
| 33 | source: usize, | 34 | source: usize, |
| 34 | outputs: Vec<Output>, | 35 | outputs: Vec<Output>, |
| 35 | // theme: Option<String> | 36 | // theme: Option<String> |
| @@ -40,11 +41,9 @@ impl View { | |||
| 40 | fn process(&self, input: &Value) -> Result<Value, ParseError> { | 41 | fn process(&self, input: &Value) -> Result<Value, ParseError> { |
| 41 | let mut out_vars = HashMap::new(); | 42 | let mut out_vars = HashMap::new(); |
| 42 | for output in &self.outputs { | 43 | for output in &self.outputs { |
| 43 | if let Token::Output(_,/*_,*/tokens) = &output.ast_root { | 44 | let mut buf = String::new(); |
| 44 | let mut buf = String::new(); | 45 | exec( input, &output.code, &mut buf )?; |
| 45 | exec( input, tokens, &mut buf )?; | 46 | out_vars.insert( output.name.clone(), Value::String(buf) ); |
| 46 | out_vars.insert( output.name.clone(), Value::String(buf) ); | ||
| 47 | } | ||
| 48 | } | 47 | } |
| 49 | Ok(Value::Dictionary(out_vars)) | 48 | Ok(Value::Dictionary(out_vars)) |
| 50 | } | 49 | } |
| @@ -53,16 +52,13 @@ impl View { | |||
| 53 | #[derive(Debug)] | 52 | #[derive(Debug)] |
| 54 | struct Output { | 53 | struct Output { |
| 55 | name: String, | 54 | name: String, |
| 56 | ast_root: Token, | 55 | code: Vec<Token>, |
| 57 | } | 56 | } |
| 58 | 57 | ||
| 59 | type Properties = HashMap<String, String>; | 58 | type Properties = HashMap<String, String>; |
| 60 | 59 | ||
| 61 | #[derive(Debug)] | 60 | #[derive(Debug)] |
| 62 | enum Token { | 61 | enum Token { |
| 63 | Root(Vec<Token>), | ||
| 64 | View(String,Properties,Vec<Token>), | ||
| 65 | Output(String,/*Properties,*/ Vec<Token>), | ||
| 66 | Show(String,Properties), | 62 | Show(String,Properties), |
| 67 | Text(String), | 63 | Text(String), |
| 68 | } | 64 | } |
| @@ -109,78 +105,44 @@ impl Crimtag { | |||
| 109 | } else { | 105 | } else { |
| 110 | SystemTime::now() | 106 | SystemTime::now() |
| 111 | }; | 107 | }; |
| 112 | 108 | let source_id = self.id_source( | |
| 109 | &ViewSource::File { | ||
| 110 | path: path.to_path_buf(), | ||
| 111 | loaded: time, | ||
| 112 | } | ||
| 113 | ); | ||
| 113 | let p = parser::Parser::new(); | 114 | let p = parser::Parser::new(); |
| 114 | self.register_views( | 115 | self.register_views( |
| 115 | p.parse( &String::from_utf8( std::fs::read( path )? )? )?, | 116 | p.parse( |
| 116 | ViewSource::File { | 117 | &String::from_utf8( std::fs::read( path )? )?, |
| 117 | path: path.to_path_buf(), | 118 | source_id |
| 118 | loaded: time, | 119 | )?, |
| 119 | })?; | 120 | )?; |
| 120 | Ok(()) | 121 | Ok(()) |
| 121 | } | 122 | } |
| 122 | 123 | ||
| 123 | pub fn load_static(&mut self, data: &str) -> Result<(),ParseError> { | 124 | pub fn load_static(&mut self, data: &str) -> Result<(),ParseError> { |
| 125 | let source_id = self.id_source( &ViewSource::Static ); | ||
| 124 | let p = parser::Parser::new(); | 126 | let p = parser::Parser::new(); |
| 125 | self.register_views( p.parse( &data )?, ViewSource::Static ) | 127 | self.register_views( p.parse( &data, source_id )? ) |
| 126 | } | 128 | } |
| 127 | 129 | ||
| 128 | pub fn load_external(&mut self, key: &str, data: &str) -> Result<(),ParseError> { | 130 | pub fn load_external(&mut self, key: &str, data: &str) -> Result<(),ParseError> { |
| 129 | let p = parser::Parser::new(); | 131 | let source_id = self.id_source( |
| 132 | &ViewSource::External{ key: key.to_string()} | ||
| 133 | ); | ||
| 134 | |||
| 135 | let p = parser::Parser::new(); | ||
| 130 | self.register_views( | 136 | self.register_views( |
| 131 | p.parse( &data )?, | 137 | p.parse( &data, source_id )?, |
| 132 | ViewSource::External{ key: key.to_string()} | ||
| 133 | ) | 138 | ) |
| 134 | } | 139 | } |
| 135 | 140 | ||
| 136 | fn register_views(&mut self, token: Token, source: ViewSource) -> Result<(),ParseError> { | 141 | fn register_views(&mut self, views: Vec<View>) -> Result<(),ParseError> { |
| 137 | let source_id = self.id_source( &source ); | 142 | for view in views { |
| 138 | if let Token::Root(views) = token { | 143 | self.views.insert( view.name.clone(), view ); |
| 139 | for token in views { | ||
| 140 | if let Token::View(name,props,output_tokens) = token { | ||
| 141 | let mut outputs = Vec::new(); | ||
| 142 | for ot in output_tokens { | ||
| 143 | let output_name = if let Token::Output(on,..) = &ot { | ||
| 144 | on.clone() | ||
| 145 | } else { | ||
| 146 | return Err(ParseError::new( | ||
| 147 | Position::new(0,0), | ||
| 148 | "Broken parser? Item in view is not an output." | ||
| 149 | )); | ||
| 150 | }; | ||
| 151 | outputs.push( | ||
| 152 | Output { | ||
| 153 | name: output_name, | ||
| 154 | ast_root: ot, | ||
| 155 | } | ||
| 156 | ); | ||
| 157 | } | ||
| 158 | |||
| 159 | let layout = if let Some(l) = props.get("layout") { | ||
| 160 | Some(l.clone()) | ||
| 161 | } else { | ||
| 162 | None | ||
| 163 | }; | ||
| 164 | |||
| 165 | self.views.insert( name, View { | ||
| 166 | source: source_id, | ||
| 167 | outputs: outputs, | ||
| 168 | layout: layout, | ||
| 169 | }); | ||
| 170 | } else { | ||
| 171 | return Err(ParseError::new( | ||
| 172 | Position::new(0,0), | ||
| 173 | "Broken parser? Item in root is not a view." | ||
| 174 | )); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | Ok(()) | ||
| 178 | } else { | ||
| 179 | Err(ParseError::new( | ||
| 180 | Position::new(0,0), | ||
| 181 | "Broken parser? Root is not a root token." | ||
| 182 | )) | ||
| 183 | } | 144 | } |
| 145 | Ok(()) | ||
| 184 | } | 146 | } |
| 185 | 147 | ||
| 186 | pub fn get_view_source(&self, view: &str) -> Option<ViewSource> { | 148 | pub fn get_view_source(&self, view: &str) -> Option<ViewSource> { |
| @@ -228,10 +190,6 @@ impl Crimtag { | |||
| 228 | fn exec(input: &Value, tokens: &Vec<Token>, buf: &mut String) -> Result<(),ParseError> { | 190 | fn exec(input: &Value, tokens: &Vec<Token>, buf: &mut String) -> Result<(),ParseError> { |
| 229 | for token in tokens { | 191 | for token in tokens { |
| 230 | match token { | 192 | match token { |
| 231 | Token::Root(..) | Token::View(..) | Token::Output(..) => { | ||
| 232 | println!("Too high!?"); | ||
| 233 | // Error? | ||
| 234 | } | ||
| 235 | Token::Show(s,p) => { | 193 | Token::Show(s,p) => { |
| 236 | let format = if let Some(s) = p.get("format") { | 194 | let format = if let Some(s) = p.get("format") { |
| 237 | s | 195 | s |
diff --git a/src/parser.rs b/src/parser.rs index c7a8abe..297230c 100644 --- a/src/parser.rs +++ b/src/parser.rs | |||
| @@ -40,16 +40,18 @@ struct Context<'a> { | |||
| 40 | cur: [Option<Symbol<'a>>;2], | 40 | cur: [Option<Symbol<'a>>;2], |
| 41 | icur: usize, | 41 | icur: usize, |
| 42 | ll: Lexer<'a>, | 42 | ll: Lexer<'a>, |
| 43 | source: usize, | ||
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | impl<'a> Context<'a> { | 46 | impl<'a> Context<'a> { |
| 46 | pub fn new( mut ll: Lexer<'a> ) -> Self { | 47 | pub fn new( mut ll: Lexer<'a>, source: usize ) -> Self { |
| 47 | let cur = [ll.next(), ll.next()]; | 48 | let cur = [ll.next(), ll.next()]; |
| 48 | //println!(" - cur: {:?}, peek: {:?}", cur[0], cur[1] ); | 49 | //println!(" - cur: {:?}, peek: {:?}", cur[0], cur[1] ); |
| 49 | Self { | 50 | Self { |
| 50 | cur, | 51 | cur, |
| 51 | icur: 0, | 52 | icur: 0, |
| 52 | ll | 53 | ll, |
| 54 | source, | ||
| 53 | } | 55 | } |
| 54 | } | 56 | } |
| 55 | 57 | ||
| @@ -75,6 +77,10 @@ impl<'a> Context<'a> { | |||
| 75 | Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol())) | 77 | Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol())) |
| 76 | } | 78 | } |
| 77 | } | 79 | } |
| 80 | |||
| 81 | pub fn source(&self) -> usize { | ||
| 82 | self.source | ||
| 83 | } | ||
| 78 | } | 84 | } |
| 79 | 85 | ||
| 80 | trait SymbolHelper { | 86 | trait SymbolHelper { |
| @@ -195,7 +201,7 @@ impl Parser { | |||
| 195 | } | 201 | } |
| 196 | } | 202 | } |
| 197 | 203 | ||
| 198 | fn lex_error(&self, error: &Symbol) -> ParseResult<Token> { | 204 | fn lex_error<T>(&self, error: &Symbol) -> ParseResult<T> { |
| 199 | if let SymbolType::Error{what} = error.symbol() { | 205 | if let SymbolType::Error{what} = error.symbol() { |
| 200 | Err(ParseError { | 206 | Err(ParseError { |
| 201 | position: error.start().clone(), | 207 | position: error.start().clone(), |
| @@ -209,15 +215,15 @@ impl Parser { | |||
| 209 | } | 215 | } |
| 210 | } | 216 | } |
| 211 | 217 | ||
| 212 | pub fn parse(&self, src: &str ) -> ParseResult<Token> { | 218 | pub fn parse(&self, src: &str, source: usize ) -> ParseResult<Vec<View>> { |
| 213 | let ll = Lexer::new( src ); | 219 | let ll = Lexer::new( src ); |
| 214 | let mut ctx = Context::new( ll ); | 220 | let mut ctx = Context::new( ll, source ); |
| 215 | 221 | ||
| 216 | // Parse the root of the file, the input context | 222 | // Parse the root of the file, the input context |
| 217 | self.p_input( &mut ctx ) | 223 | self.p_input( &mut ctx ) |
| 218 | } | 224 | } |
| 219 | 225 | ||
| 220 | fn p_input(&self, ctx: &mut Context ) -> ParseResult<Token> { | 226 | fn p_input(&self, ctx: &mut Context ) -> ParseResult<Vec<View>> { |
| 221 | let mut children = Vec::new(); | 227 | let mut children = Vec::new(); |
| 222 | loop { | 228 | loop { |
| 223 | if ctx.cur().is_none() { | 229 | if ctx.cur().is_none() { |
| @@ -229,7 +235,7 @@ impl Parser { | |||
| 229 | children.push( self.parse_tag_view( ctx )? ); | 235 | children.push( self.parse_tag_view( ctx )? ); |
| 230 | } | 236 | } |
| 231 | SymbolType::Error{..} => { | 237 | SymbolType::Error{..} => { |
| 232 | return self.lex_error( &ctx.cur().unwrap() ); | 238 | self.lex_error( &ctx.cur().unwrap() )?; |
| 233 | } | 239 | } |
| 234 | _ => { | 240 | _ => { |
| 235 | 241 | ||
| @@ -237,11 +243,11 @@ impl Parser { | |||
| 237 | } | 243 | } |
| 238 | ctx.next(); | 244 | ctx.next(); |
| 239 | } | 245 | } |
| 240 | Ok(Token::Root(children)) | 246 | Ok(children) |
| 241 | } | 247 | } |
| 242 | 248 | ||
| 243 | fn parse_tag_view(&self, ctx: &mut Context) -> ParseResult<Token> { | 249 | fn parse_tag_view(&self, ctx: &mut Context) -> ParseResult<View> { |
| 244 | let mut tb = self.parse_open_tag( ctx )?; | 250 | let tb = self.parse_open_tag( ctx )?; |
| 245 | if !tb.is_name( &SymbolType::View ) { | 251 | if !tb.is_name( &SymbolType::View ) { |
| 246 | return Err(ParseError{ | 252 | return Err(ParseError{ |
| 247 | position: tb.start_pos(), | 253 | position: tb.start_pos(), |
| @@ -250,9 +256,10 @@ impl Parser { | |||
| 250 | } | 256 | } |
| 251 | 257 | ||
| 252 | if tb.is_unary() { | 258 | if tb.is_unary() { |
| 253 | return tb.build(); | 259 | return tb.build_view(ctx, Vec::new()); |
| 254 | } | 260 | } |
| 255 | let mut children = Vec::new(); | 261 | let mut children = Vec::new(); |
| 262 | let mut outputs = Vec::new(); | ||
| 256 | 263 | ||
| 257 | //println!("--parse-tag-view-- tag parsed, next token: {:?}", ctx.cur() ); | 264 | //println!("--parse-tag-view-- tag parsed, next token: {:?}", ctx.cur() ); |
| 258 | loop { | 265 | loop { |
| @@ -265,47 +272,37 @@ impl Parser { | |||
| 265 | ctx.next(); | 272 | ctx.next(); |
| 266 | } | 273 | } |
| 267 | SymbolType::StartFlat => { | 274 | SymbolType::StartFlat => { |
| 268 | //child.is_name(SymbolType::Output) | 275 | let subtb = self.parse_tag_body( ctx )?; |
| 269 | children.push( self.parse_tag_body( ctx )? ); | 276 | if subtb.is_name(&SymbolType::Output) { |
| 277 | outputs.push(subtb.build_output(ctx)?); | ||
| 278 | } else { | ||
| 279 | children.push(subtb.build()?); | ||
| 280 | } | ||
| 270 | } | 281 | } |
| 271 | SymbolType::StartPoint => { | 282 | SymbolType::StartPoint => { |
| 272 | let end = self.parse_end_tag( ctx )?; | 283 | let end = self.parse_end_tag( ctx )?; |
| 273 | //println!("End tag: {:?}, open tag: {:?}", end, tb.name() ); | 284 | //println!("End tag: {:?}, open tag: {:?}", end, tb.name() ); |
| 274 | if tb.is_name(end.symbol()) { | 285 | if tb.is_name(end.symbol()) { |
| 275 | // They match, time to decide what we're doing. | 286 | // They match, time to decide what we're doing. |
| 276 | let any_outputs = children.iter().any( | 287 | let any_outputs = outputs.len() > 0; |
| 277 | |t| matches!(t, Token::Output(..)) | 288 | let all_text = children.iter().all( |
| 289 | |t| matches!(t, Token::Text(..)) | ||
| 278 | ); | 290 | ); |
| 279 | if children.iter().all(|t| matches!(t, Token::Text(..)) || matches!(t, Token::Output(..))) { | 291 | if !any_outputs { |
| 280 | // Everything is either text or output | 292 | // Create an implicit output called "content" |
| 281 | if !any_outputs { | 293 | outputs.push(Output{ |
| 282 | // Special case, if it's only text then we create an implicit output. | 294 | name: "content".to_string(), |
| 283 | tb.add_child(Token::Output("content".to_string(), /*Properties::new(),*/ children )); | 295 | code: children, |
| 284 | } | 296 | }); |
| 285 | else { | ||
| 286 | // Standard case, outputs are included, text is | ||
| 287 | // skipped. | ||
| 288 | for token in children { | ||
| 289 | if matches!(token, Token::Output(..)) { | ||
| 290 | tb.add_child( token ); | ||
| 291 | } | ||
| 292 | } | ||
| 293 | } | ||
| 294 | } else { | 297 | } else { |
| 295 | // We have another mix, now check to see if there | 298 | if !all_text { |
| 296 | // are any outptus, if so this is an error. | ||
| 297 | if any_outputs { | ||
| 298 | return Err(ParseError{ | 299 | return Err(ParseError{ |
| 299 | position: *end.start(), | 300 | position: *end.start(), |
| 300 | what: "You cannot mix non-output and output tags in a view.".to_string() | 301 | what: "You cannot mix non-output and output tags in a view.".to_string() |
| 301 | }); | 302 | }); |
| 302 | } else { | ||
| 303 | // No outputs at all, we create an implict output | ||
| 304 | tb.add_child(Token::Output("content".to_string(), /*Properties::new(), */children )); | ||
| 305 | } | 303 | } |
| 306 | } | 304 | } |
| 307 | 305 | return tb.build_view(ctx,outputs); | |
| 308 | return tb.build(); | ||
| 309 | } else { | 306 | } else { |
| 310 | // They don't match, complain. | 307 | // They don't match, complain. |
| 311 | return Err(ParseError{ | 308 | return Err(ParseError{ |
| @@ -392,10 +389,10 @@ impl Parser { | |||
| 392 | Ok(name) | 389 | Ok(name) |
| 393 | } | 390 | } |
| 394 | 391 | ||
| 395 | fn parse_tag_body(&self, ctx: &mut Context ) -> ParseResult<Token> { | 392 | fn parse_tag_body<'a>(&self, ctx: &mut Context<'a> ) -> ParseResult<TagBuilder<'a>> { |
| 396 | let mut tb = self.parse_open_tag( ctx )?; | 393 | let mut tb = self.parse_open_tag( ctx )?; |
| 397 | if tb.is_unary() { | 394 | if tb.is_unary() { |
| 398 | return tb.build(); | 395 | return Ok(tb); |
| 399 | } | 396 | } |
| 400 | 397 | ||
| 401 | loop { | 398 | loop { |
| @@ -408,13 +405,13 @@ impl Parser { | |||
| 408 | ctx.next(); | 405 | ctx.next(); |
| 409 | } | 406 | } |
| 410 | SymbolType::StartFlat => { | 407 | SymbolType::StartFlat => { |
| 411 | tb.add_child( self.parse_tag_body( ctx )? ); | 408 | tb.add_child( self.parse_tag_body( ctx )?.build()? ); |
| 412 | } | 409 | } |
| 413 | SymbolType::StartPoint => { | 410 | SymbolType::StartPoint => { |
| 414 | let end = self.parse_end_tag( ctx )?; | 411 | let end = self.parse_end_tag( ctx )?; |
| 415 | if tb.is_name(end.symbol()) { | 412 | if tb.is_name(end.symbol()) { |
| 416 | // They match, end. | 413 | // They match, end. |
| 417 | return tb.build(); | 414 | return Ok(tb); |
| 418 | } else { | 415 | } else { |
| 419 | // They don't match, complain. | 416 | // They don't match, complain. |
| 420 | return Err(ParseError{ | 417 | return Err(ParseError{ |
| @@ -424,7 +421,7 @@ impl Parser { | |||
| 424 | } | 421 | } |
| 425 | } | 422 | } |
| 426 | SymbolType::Error{..} => { | 423 | SymbolType::Error{..} => { |
| 427 | self.lex_error( &ctx.cur().unwrap() )?; | 424 | return self.lex_error( &ctx.cur().unwrap() ); |
| 428 | } | 425 | } |
| 429 | _ => { | 426 | _ => { |
| 430 | 427 | ||
| @@ -565,15 +562,42 @@ impl<'a> TagBuilder<'a> { | |||
| 565 | self.tag_type | 562 | self.tag_type |
| 566 | } | 563 | } |
| 567 | 564 | ||
| 565 | pub fn build_view(mut self, ctx: &Context, outputs: Vec<Output>) -> ParseResult<View> { | ||
| 566 | if let Some(sym) = self.name { | ||
| 567 | if *sym.symbol() == SymbolType::View { | ||
| 568 | Ok(View { | ||
| 569 | name: self.params.swap_remove(0), | ||
| 570 | source: ctx.source(), | ||
| 571 | outputs: outputs, | ||
| 572 | //theme: Option<String> | ||
| 573 | layout: self.props.get("layout").cloned(), | ||
| 574 | }) | ||
| 575 | } else { | ||
| 576 | Err(ParseError::new(self.start_pos, &format!("Expected tag type view, found {:?}", sym.symbol()))) | ||
| 577 | } | ||
| 578 | } else { | ||
| 579 | Err(ParseError::new(self.start_pos, "Broken Parser? No tag type found when building view.")) | ||
| 580 | } | ||
| 581 | } | ||
| 582 | |||
| 583 | pub fn build_output(mut self, ctx: &Context) -> ParseResult<Output> { | ||
| 584 | if let Some(sym) = self.name { | ||
| 585 | if *sym.symbol() == SymbolType::Output { | ||
| 586 | Ok(Output { | ||
| 587 | name: self.params.swap_remove(0), | ||
| 588 | code: self.children, | ||
| 589 | }) | ||
| 590 | } else { | ||
| 591 | Err(ParseError::new(self.start_pos, &format!("Expected tag type view, found {:?}", sym.symbol()))) | ||
| 592 | } | ||
| 593 | } else { | ||
| 594 | Err(ParseError::new(self.start_pos, "Broken Parser? No tag type found when building view.")) | ||
| 595 | } | ||
| 596 | } | ||
| 597 | |||
| 568 | pub fn build(mut self) -> ParseResult<Token> { | 598 | pub fn build(mut self) -> ParseResult<Token> { |
| 569 | if let Some(sym) = self.name { | 599 | if let Some(sym) = self.name { |
| 570 | match sym.symbol() { | 600 | match sym.symbol() { |
| 571 | SymbolType::View => { | ||
| 572 | Ok(Token::View(self.params.swap_remove(0), self.props, self.children)) | ||
| 573 | } | ||
| 574 | SymbolType::Output => { | ||
| 575 | Ok(Token::Output(self.params.swap_remove(0), /*self.props,*/ self.children)) | ||
| 576 | } | ||
| 577 | SymbolType::Show => { | 601 | SymbolType::Show => { |
| 578 | Ok(Token::Show(self.params.swap_remove(0), self.props)) | 602 | Ok(Token::Show(self.params.swap_remove(0), self.props)) |
| 579 | } | 603 | } |
