summaryrefslogtreecommitdiff
path: root/src/parser.rs
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2026-06-11 15:20:49 -0700
committerMike Buland <mike@xagasoft.com>2026-06-11 15:20:49 -0700
commit9083d5843f5a39fafacde81242b817021f9cb818 (patch)
treee65371f368f151a30e10631149fdd970de615e60 /src/parser.rs
parentc9889f7c6622def3b6badde2738c3e912b48144f (diff)
downloadcrimtag-9083d5843f5a39fafacde81242b817021f9cb818.tar.gz
crimtag-9083d5843f5a39fafacde81242b817021f9cb818.tar.bz2
crimtag-9083d5843f5a39fafacde81242b817021f9cb818.tar.xz
crimtag-9083d5843f5a39fafacde81242b817021f9cb818.zip
Halfway there. About half the code is going away.
I'm learning better how to take advantage of features of rust to simplify the code a lot. It's actually really cool.
Diffstat (limited to 'src/parser.rs')
-rw-r--r--src/parser.rs297
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
497struct TagBuilder<'a> { 603struct 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
619enum BuildResult {
620 View(View),
621 Output(Output),
622 Token(Token),
623}
624
512impl<'a> TagBuilder<'a> { 625impl<'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()))