diff options
Diffstat (limited to 'src/parser.rs')
| -rw-r--r-- | src/parser.rs | 297 |
1 files changed, 234 insertions, 63 deletions
diff --git a/src/parser.rs b/src/parser.rs index 6ba6cfe..b681fce 100644 --- a/src/parser.rs +++ b/src/parser.rs | |||
| @@ -221,11 +221,116 @@ impl Parser { | |||
| 221 | Ok(children) | 221 | Ok(children) |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | fn parse_tag(&self, ctx: &mut Context) -> CrimResult<TagBuilder> { | ||
| 225 | let start_sym = ctx.cur().unwrap(); | ||
| 226 | let mut tb = TagBuilder::new(&start_sym); | ||
| 227 | |||
| 228 | if ctx.next().is_some() { | ||
| 229 | match ctx.cur().unwrap().symbol() { | ||
| 230 | SymbolType::View | SymbolType::Show | SymbolType::Loop | | ||
| 231 | SymbolType::If | SymbolType::ElIf | SymbolType::Else | | ||
| 232 | SymbolType::Output => { | ||
| 233 | let name_sym = ctx.cur().unwrap(); | ||
| 234 | ctx.next(); | ||
| 235 | tb.set_name( name_sym ); | ||
| 236 | } | ||
| 237 | _ => { | ||
| 238 | return Err(CrimError::parse( | ||
| 239 | *ctx.cur().unwrap().start(), | ||
| 240 | "Unexpected symbol".to_string() | ||
| 241 | )); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | } else { | ||
| 245 | return Err(CrimError::eos("tag type")); | ||
| 246 | } | ||
| 247 | |||
| 248 | if tb.can_have_params() || tb.can_have_expr() { | ||
| 249 | self.parse_tag_params( ctx, &mut tb )?; | ||
| 250 | } | ||
| 251 | if tb.can_have_props() { | ||
| 252 | self.parse_tag_props( ctx, &mut tb )?; | ||
| 253 | } | ||
| 254 | |||
| 255 | if let Some(end_sym) = ctx.cur() { | ||
| 256 | match end_sym.symbol() { | ||
| 257 | SymbolType::EndPoint | SymbolType::EndFlat => { | ||
| 258 | tb.set_end( end_sym )?; | ||
| 259 | } | ||
| 260 | _ => { | ||
| 261 | return Err(CrimError::parse( | ||
| 262 | *end_sym.start(), | ||
| 263 | format!("Unexpected symbol {:?} looking for end of tag.", end_sym.symbol()) | ||
| 264 | )); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | ctx.next(); | ||
| 270 | |||
| 271 | Ok(tb) | ||
| 272 | } | ||
| 273 | |||
| 274 | fn parse_tag_set<'a>(&self, ctx: &mut Context; base: &mut TagBuilder) -> CrimResult<Token> { | ||
| 275 | if base.is_unary() { | ||
| 276 | return Ok(base.build()); | ||
| 277 | } | ||
| 278 | if !base.is_multinary_open() { | ||
| 279 | return Err(CrimError::broken("Found close/mid tag instead of opening")); | ||
| 280 | } | ||
| 281 | |||
| 282 | loop { | ||
| 283 | if ctx.cur().is_none() { | ||
| 284 | return Err(CrimError::eos(format!("close tag for {:?}", base.name()).as_str())); | ||
| 285 | } | ||
| 286 | match ctx.cur().unwrap().symbol() { | ||
| 287 | SymbolType::Text(s) => { | ||
| 288 | base.add_child(Token::Text(s.to_string())); | ||
| 289 | ctx.next(); | ||
| 290 | } | ||
| 291 | SymbolType::StartFlat | SymbolType::StartPoint => { | ||
| 292 | let mut tb = self.parse_tag( ctx )?; | ||
| 293 | |||
| 294 | match tb.tag_type() { | ||
| 295 | TagType::MultinaryOpen => { | ||
| 296 | base.add_child( parse_tag_set( ctx, tb )? ); | ||
| 297 | } | ||
| 298 | TagType::MultinaryMid => { | ||
| 299 | base.add_chain( parse_tag_set( ctx, tb )? ); | ||
| 300 | } | ||
| 301 | TagType::MultinaryClose => { | ||
| 302 | if (tb.is_name(SymbolToken::If) && | ||
| 303 | (base.is_name(SymbolToken::Elif) || | ||
| 304 | base.is_name(SymbolToken::Else))) || | ||
| 305 | tb.is_name(base.name().symbol()) { | ||
| 306 | |||
| 307 | } else { | ||
| 308 | return Err(CrimError::parse( | ||
| 309 | *tb.name().start(), | ||
| 310 | format!("Found {:?} looking for close of {:?}", tb.name().symbol(), base.name().symbol()) | ||
| 311 | )); | ||
| 312 | } | ||
| 313 | } | ||
| 314 | } | ||
| 315 | } | ||
| 316 | SymbolType::Error{..} => { | ||
| 317 | return self.lex_error( &ctx.cur().unwrap() ); | ||
| 318 | } | ||
| 319 | _ => { | ||
| 320 | return Err(CrimError::parse( | ||
| 321 | *ctx.cur().unwrap().start(), | ||
| 322 | format!("Unexpected token: {:?}", ctx.cur().unwrap().symbol()), | ||
| 323 | )); | ||
| 324 | } | ||
| 325 | } | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 224 | fn parse_tag_view(&self, ctx: &mut Context) -> CrimResult<View> { | 329 | fn parse_tag_view(&self, ctx: &mut Context) -> CrimResult<View> { |
| 225 | let tb = self.parse_open_tag( ctx )?; | 330 | let tb = self.parse_open_tag( ctx )?; |
| 226 | if !tb.is_name( &SymbolType::View ) { | 331 | if !tb.is_name( &SymbolType::View ) { |
| 227 | return Err(CrimError::parse(tb.start_pos(), | 332 | return Err(CrimError::parse(tb.start_pos(), |
| 228 | "Unexpected tag type, only frament allowed at root".into() | 333 | "Unexpected tag type, only view allowed at root".into() |
| 229 | )); | 334 | )); |
| 230 | } | 335 | } |
| 231 | 336 | ||
| @@ -246,7 +351,7 @@ impl Parser { | |||
| 246 | ctx.next(); | 351 | ctx.next(); |
| 247 | } | 352 | } |
| 248 | SymbolType::StartFlat => { | 353 | SymbolType::StartFlat => { |
| 249 | let subtb = self.parse_tag_body( ctx )?; | 354 | let subtb = self.parse_tag( ctx )?; |
| 250 | if subtb.is_name(&SymbolType::Output) { | 355 | if subtb.is_name(&SymbolType::Output) { |
| 251 | outputs.push(subtb.build_output()?); | 356 | outputs.push(subtb.build_output()?); |
| 252 | } else { | 357 | } else { |
| @@ -492,6 +597,7 @@ enum TagType { | |||
| 492 | Unary, | 597 | Unary, |
| 493 | MultinaryOpen, | 598 | MultinaryOpen, |
| 494 | MultinaryMid, | 599 | MultinaryMid, |
| 600 | MultinaryClose, | ||
| 495 | } | 601 | } |
| 496 | 602 | ||
| 497 | struct TagBuilder<'a> { | 603 | struct TagBuilder<'a> { |
| @@ -500,7 +606,8 @@ struct TagBuilder<'a> { | |||
| 500 | props: Properties, | 606 | props: Properties, |
| 501 | children: Vec<Token>, | 607 | children: Vec<Token>, |
| 502 | tag_type: TagType, | 608 | tag_type: TagType, |
| 503 | start_pos: Position, | 609 | start: Symbol<'a>, |
| 610 | chain: Vec<Token>, | ||
| 504 | } | 611 | } |
| 505 | 612 | ||
| 506 | #[derive(Debug)] | 613 | #[derive(Debug)] |
| @@ -509,30 +616,79 @@ enum ParamValue { | |||
| 509 | Identifier(Identifier), | 616 | Identifier(Identifier), |
| 510 | } | 617 | } |
| 511 | 618 | ||
| 619 | enum BuildResult { | ||
| 620 | View(View), | ||
| 621 | Output(Output), | ||
| 622 | Token(Token), | ||
| 623 | } | ||
| 624 | |||
| 512 | impl<'a> TagBuilder<'a> { | 625 | impl<'a> TagBuilder<'a> { |
| 513 | pub fn new(start: &Symbol) -> TagBuilder<'a> { | 626 | pub fn new(start: &Symbol<'a>) -> TagBuilder<'a> { |
| 514 | TagBuilder { | 627 | TagBuilder { |
| 515 | name: None, | 628 | name: None, |
| 516 | params: Vec::new(), | 629 | params: Vec::new(), |
| 517 | props: Properties::new(), | 630 | props: Properties::new(), |
| 518 | children: Vec::new(), | 631 | children: Vec::new(), |
| 519 | tag_type: TagType::Unknown, | 632 | tag_type: TagType::Unknown, |
| 520 | start_pos: *start.start(), | 633 | start: start.clone(), |
| 634 | chain: Vec::new(), | ||
| 635 | } | ||
| 636 | } | ||
| 637 | |||
| 638 | pub fn set_end(&mut self, end: &Symbol) -> CrimResult<()> { | ||
| 639 | if start.symbol() == SymbolType::StartFlat { | ||
| 640 | if end.symbol() == SymbolType::EndFlat { | ||
| 641 | self.tag_type = TagType::Unary; | ||
| 642 | } else if end.symbol() == SymbolType::EndPoint { | ||
| 643 | self.tag_type = TagType::MultinaryOpen; | ||
| 644 | } else { | ||
| 645 | return Err(CrimError::broken( *self.end.start(), "Invalid bracket token type.")); | ||
| 646 | } | ||
| 647 | } else if start.symbol() == SymbolType::StartPoint { | ||
| 648 | if end.symbol() == SymbolType::EndFlat { | ||
| 649 | self.tag_type = TagType::MultinaryClose; | ||
| 650 | } else if end.symbol() == SymbolType::EndPoint { | ||
| 651 | self.tag_type = TagType::MultinaryMid; | ||
| 652 | } else { | ||
| 653 | return Err(CrimError::broken( *self.end.start(), "Invalid bracket token type.")); | ||
| 654 | } | ||
| 655 | } else { | ||
| 656 | return Err(CrimError::broken( *self.start.start(), "Invalid bracket token type.")); | ||
| 521 | } | 657 | } |
| 522 | } | 658 | } |
| 523 | 659 | ||
| 524 | pub fn start_pos(&self) -> Position { | 660 | pub fn start_pos(&self) -> Position { |
| 525 | self.start_pos | 661 | self.start.start() |
| 526 | } | 662 | } |
| 527 | 663 | ||
| 528 | pub fn is_unary(&self) -> bool { | 664 | pub fn is_unary(&self) -> bool { |
| 529 | if self.tag_type == TagType::Unary { | 665 | self.tag_type == TagType::Unary |
| 530 | true | 666 | } |
| 531 | } else { | 667 | |
| 532 | false | 668 | pub fn is_multinary_open(&self) -> bool { |
| 669 | self.tag_type == TagType::MultinaryOpen | ||
| 670 | } | ||
| 671 | |||
| 672 | pub fn can_have_params(&self) -> bool { | ||
| 673 | match self.name.symbol() { | ||
| 674 | SymbolType::View | SymbolType::Output | SymbolType::Loop => true, | ||
| 675 | SymbolType::Show | SymbolType::If | SymbolType::ElIf | | ||
| 676 | SymbolType::Else => false, | ||
| 533 | } | 677 | } |
| 534 | } | 678 | } |
| 535 | 679 | ||
| 680 | pub fn can_have_expr(&self) -> bool { | ||
| 681 | match self.name.symbol() { | ||
| 682 | SymbolType::View | SymbolType::Output | SymbolType::Loop => false, | ||
| 683 | SymbolType::Show | SymbolType::If | SymbolType::ElIf | | ||
| 684 | SymbolType::Else => true, | ||
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | pub fn can_have_props(&self) -> bool { | ||
| 689 | true | ||
| 690 | } | ||
| 691 | |||
| 536 | pub fn can_have_children(&self) -> bool { | 692 | pub fn can_have_children(&self) -> bool { |
| 537 | if self.tag_type == TagType::MultinaryOpen || | 693 | if self.tag_type == TagType::MultinaryOpen || |
| 538 | self.tag_type == TagType::MultinaryMid { | 694 | self.tag_type == TagType::MultinaryMid { |
| @@ -586,75 +742,90 @@ impl<'a> TagBuilder<'a> { | |||
| 586 | self.tag_type | 742 | self.tag_type |
| 587 | } | 743 | } |
| 588 | 744 | ||
| 589 | pub fn build_view(mut self, ctx: &Context, outputs: Vec<Output>) -> CrimResult<View> { | 745 | pub fn build(mut self) -> CrimResult<BuildResult> { |
| 590 | if let Some(sym) = self.name { | ||
| 591 | if *sym.symbol() == SymbolType::View { | ||
| 592 | let name = if let ParamValue::Literal(s) = self.params.swap_remove(0) { | ||
| 593 | s.to_string() | ||
| 594 | } else { | ||
| 595 | return Err(CrimError::parse(Position::none(), "Expected string literal for view name.".to_string())); | ||
| 596 | }; | ||
| 597 | Ok(View { | ||
| 598 | name: name, | ||
| 599 | source: ctx.source(), | ||
| 600 | outputs: outputs, | ||
| 601 | //theme: Option<String> | ||
| 602 | layout: self.props.get("layout").cloned(), | ||
| 603 | }) | ||
| 604 | } else { | ||
| 605 | Err(CrimError::parse(self.start_pos, format!("Expected tag type view, found {:?}", sym.symbol()))) | ||
| 606 | } | ||
| 607 | } else { | ||
| 608 | Err(CrimError::parse(self.start_pos, "Broken Parser? No tag type found when building view.".to_string())) | ||
| 609 | } | ||
| 610 | } | ||
| 611 | |||
| 612 | pub fn build_output(mut self) -> CrimResult<Output> { | ||
| 613 | if let Some(sym) = self.name { | ||
| 614 | if *sym.symbol() == SymbolType::Output { | ||
| 615 | let name = if let ParamValue::Literal(s) = self.params.swap_remove(0) { | ||
| 616 | s.to_string() | ||
| 617 | } else { | ||
| 618 | return Err(CrimError::parse(Position::none(), "Expected string literal for output name.".into())); | ||
| 619 | }; | ||
| 620 | Ok(Output { | ||
| 621 | name: name, | ||
| 622 | code: self.children, | ||
| 623 | }) | ||
| 624 | } else { | ||
| 625 | Err(CrimError::parse(self.start_pos, format!("Expected tag type view, found {:?}", sym.symbol()))) | ||
| 626 | } | ||
| 627 | } else { | ||
| 628 | Err(CrimError::parse(self.start_pos, "Broken Parser? No tag type found when building view.".into())) | ||
| 629 | } | ||
| 630 | } | ||
| 631 | |||
| 632 | pub fn build(mut self) -> CrimResult<Token> { | ||
| 633 | if let Some(sym) = self.name { | 746 | if let Some(sym) = self.name { |
| 634 | match sym.symbol() { | 747 | match sym.symbol() { |
| 748 | SymbolType::View => { | ||
| 749 | let name = if let ParamValue::Literal(s) = self.params.swap_remove(0) { | ||
| 750 | s.to_string() | ||
| 751 | } else { | ||
| 752 | return Err(CrimError::parse(Position::none(), "Expected string literal for view name.".to_string())); | ||
| 753 | }; | ||
| 754 | Ok(BuildResult::View(View { | ||
| 755 | name: name, | ||
| 756 | source: ctx.source(), | ||
| 757 | outputs: outputs, | ||
| 758 | //theme: Option<String> | ||
| 759 | layout: self.props.get("layout").cloned(), | ||
| 760 | })) | ||
| 761 | } | ||
| 762 | SymbolType::Output => { | ||
| 763 | let name = if let ParamValue::Literal(s) = self.params.swap_remove(0) { | ||
| 764 | s.to_string() | ||
| 765 | } else { | ||
| 766 | return Err(CrimError::parse(Position::none(), "Expected string literal for output name.".into())); | ||
| 767 | }; | ||
| 768 | Ok(BuildResult::Output(Output { | ||
| 769 | name: name, | ||
| 770 | code: self.children, | ||
| 771 | })) | ||
| 772 | } | ||
| 635 | SymbolType::Loop => { | 773 | SymbolType::Loop => { |
| 636 | let id = if let ParamValue::Identifier(id) = self.params.swap_remove(0) { | 774 | let id = if let ParamValue::Identifier(id) |
| 775 | = self.params.swap_remove(0) { | ||
| 637 | id | 776 | id |
| 638 | } else { | 777 | } else { |
| 639 | return Err(CrimError::parse(Position::none(), "Identifier for loop variable name.".into())); | 778 | return Err(CrimError::parse( |
| 779 | Position::none(), | ||
| 780 | "Identifier for loop variable name.".into()) | ||
| 781 | ); | ||
| 640 | }; | 782 | }; |
| 641 | Ok(Token::Loop(id, self.children)) | 783 | Ok(BuildResult::Token(Token::Loop(id, self.children))) |
| 642 | } | 784 | } |
| 643 | SymbolType::Show => { | 785 | SymbolType::Show => { |
| 644 | let id = if let ParamValue::Identifier(id) = self.params.swap_remove(0) { | 786 | let id = if let ParamValue::Identifier(id) |
| 787 | = self.params.swap_remove(0) { | ||
| 645 | id | 788 | id |
| 646 | } else { | 789 | } else { |
| 647 | return Err(CrimError::parse(Position::none(), "Identifier for show variable name.".into())); | 790 | return Err(CrimError::parse( |
| 791 | Position::none(), | ||
| 792 | "Identifier for show variable name.".into()) | ||
| 793 | ); | ||
| 648 | }; | 794 | }; |
| 649 | Ok(Token::Show(id, self.props)) | 795 | Ok(BuildResult::Token(Token::Show(id, self.props))) |
| 650 | } | 796 | } |
| 651 | SymbolType::If => { | 797 | SymbolType::If => { |
| 652 | let id = if let ParamValue::Identifier(id) = self.params.swap_remove(0) { | 798 | let id = if let ParamValue::Identifier(id) |
| 799 | = self.params.swap_remove(0) { | ||
| 800 | id | ||
| 801 | } else { | ||
| 802 | return Err(CrimError::parse( | ||
| 803 | Position::none(), | ||
| 804 | "Identifier for if variable name.".into()) | ||
| 805 | ); | ||
| 806 | }; | ||
| 807 | if self.chain.len() == 1 && | ||
| 808 | let Token::If(id, mut children, chain) = self.chain[0] && | ||
| 809 | id.len() == 0 { | ||
| 810 | self.chain.clear(); | ||
| 811 | self.chain.append(children); | ||
| 812 | } | ||
| 813 | Ok(BuildResult::Token(Token::If(id, self.children, self.chain))) | ||
| 814 | } | ||
| 815 | SymbolType::ElIf => { | ||
| 816 | let id = if let ParamValue::Identifier(id) | ||
| 817 | = self.params.swap_remove(0) { | ||
| 653 | id | 818 | id |
| 654 | } else { | 819 | } else { |
| 655 | return Err(CrimError::parse(Position::none(), "Identifier for show variable name.".into())); | 820 | return Err(CrimError::parse( |
| 821 | Position::none(), | ||
| 822 | "Identifier for elif variable name.".into()) | ||
| 823 | ); | ||
| 656 | }; | 824 | }; |
| 657 | Ok(Token::If(id, self.children)) | 825 | Ok(BuildResult::Token(Token::If(Identifier::new(), self.children, self.chain))) |
| 826 | } | ||
| 827 | SymbolType::Else => { | ||
| 828 | Ok(BuildResult::Token(Token::If(Identifier::new(), self.children, self.chain))) | ||
| 658 | } | 829 | } |
| 659 | _ => { | 830 | _ => { |
| 660 | Err(CrimError::parse( self.start_pos, "Bad tag type".into())) | 831 | Err(CrimError::parse( self.start_pos, "Bad tag type".into())) |
