diff options
| author | Mike Buland <mike@xagasoft.com> | 2026-06-09 10:16:19 -0700 |
|---|---|---|
| committer | Mike Buland <mike@xagasoft.com> | 2026-06-09 10:16:19 -0700 |
| commit | f724cea337965419618d7d587015c9593a67834d (patch) | |
| tree | 4dfde406f727f27f0ec77738506e5061ff648d07 /src/parser.rs | |
| parent | 9c5da7c258a49d911b20629be6b4ef426d4f431e (diff) | |
| download | crimtag-f724cea337965419618d7d587015c9593a67834d.tar.gz crimtag-f724cea337965419618d7d587015c9593a67834d.tar.bz2 crimtag-f724cea337965419618d7d587015c9593a67834d.tar.xz crimtag-f724cea337965419618d7d587015c9593a67834d.zip | |
Removed root, view, and output AST tokens.
They are built as their final objects during parsing now. It's no more
complex and we have no useless tokens now.
Diffstat (limited to 'src/parser.rs')
| -rw-r--r-- | src/parser.rs | 122 |
1 files changed, 73 insertions, 49 deletions
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 | } |
