use super::expressions::parse_expression; use super::prelude::*; use super::statements::parse_statement; #[cfg_attr(test, parser_test)] /// ```test,Document /// Type := Base { } /// Type := Base { SubElement { } } /// component Comp := Base {} Type := Base {} /// ``` pub fn parse_document(p: &mut impl Parser) -> bool { let mut p = p.start_node(SyntaxKind::Document); loop { if p.peek().as_str() == "component" && p.nth(1) != SyntaxKind::ColonEqual { p.expect(SyntaxKind::Identifier); } if !parse_component(&mut *p) { return false; } if p.nth(0) == SyntaxKind::Eof { return true; } } } #[cfg_attr(test, parser_test)] /// ```test,Component /// Type := Base { } /// Type := Base { prop: value; } /// Type := Base { SubElement { } } /// ``` pub fn parse_component(p: &mut impl Parser) -> bool { let mut p = p.start_node(SyntaxKind::Component); if !(p.expect(SyntaxKind::Identifier) && p.expect(SyntaxKind::ColonEqual)) { return false; } if !parse_element(&mut *p) { return false; } true } #[cfg_attr(test, parser_test)] /// ```test,Element /// Item { } /// Item { property: value; SubElement { } } /// ``` pub fn parse_element(p: &mut impl Parser) -> bool { let mut p = p.start_node(SyntaxKind::Element); if !(parse_qualified_name(&mut *p) && p.expect(SyntaxKind::LBrace)) { return false; } parse_element_content(&mut *p); p.expect(SyntaxKind::RBrace) } #[cfg_attr(test, parser_test)] /// ```test /// property1: value; property2: value; /// sub := Sub { } /// for xx in model: Sub {} /// if (condition) : Sub {} /// clicked => {} /// signal foobar; /// property width; /// animate someProp { } /// ``` fn parse_element_content(p: &mut impl Parser) { loop { match p.nth(0) { SyntaxKind::RBrace => return, SyntaxKind::Eof => return, SyntaxKind::Identifier => match p.nth(1) { SyntaxKind::Colon => parse_property_binding(&mut *p), SyntaxKind::ColonEqual | SyntaxKind::LBrace => parse_sub_element(&mut *p), SyntaxKind::FatArrow => parse_signal_connection(&mut *p), SyntaxKind::Identifier if p.peek().as_str() == "for" => { parse_repeated_element(&mut *p); } SyntaxKind::Identifier if p.peek().as_str() == "signal" => { parse_signal_declaration(&mut *p); } SyntaxKind::Identifier if p.peek().as_str() == "animate" => { parse_property_animation(&mut *p); } SyntaxKind::LAngle if p.peek().as_str() == "property" => { parse_property_declaration(&mut *p); } SyntaxKind::LParent if p.peek().as_str() == "if" => { parse_if_element(&mut *p); } _ => { p.consume(); p.error("FIXME"); } }, _ => { p.consume(); p.error("FIXME"); } } } } #[cfg_attr(test, parser_test)] /// ```test,SubElement /// Bar {} /// foo := Bar {} /// Bar { x : y ; } /// ``` /// Must consume at least one token fn parse_sub_element(p: &mut impl Parser) { let mut p = p.start_node(SyntaxKind::SubElement); if p.nth(1) == SyntaxKind::ColonEqual { assert!(p.expect(SyntaxKind::Identifier)); p.expect(SyntaxKind::ColonEqual); } parse_element(&mut *p); } #[cfg_attr(test, parser_test)] /// ```test,RepeatedElement /// for xx in mm: Elem { } /// for [idx] in mm: Elem { } /// for xx [idx] in foo.bar: Elem { } /// ``` /// Must consume at least one token fn parse_repeated_element(p: &mut impl Parser) { debug_assert_eq!(p.peek().as_str(), "for"); let mut p = p.start_node(SyntaxKind::RepeatedElement); p.consume(); // "for" if p.nth(0) == SyntaxKind::Identifier { let mut p = p.start_node(SyntaxKind::DeclaredIdentifier); p.expect(SyntaxKind::Identifier); } if p.nth(0) == SyntaxKind::LBracket { let mut p = p.start_node(SyntaxKind::RepeatedIndex); p.expect(SyntaxKind::LBracket); p.expect(SyntaxKind::Identifier); p.expect(SyntaxKind::RBracket); } if p.peek().as_str() != "in" { p.error("Invalid 'for' syntax: there should be a 'in' token"); return; } p.consume(); // "in" parse_expression(&mut *p); p.expect(SyntaxKind::Colon); parse_element(&mut *p); } /// ```test,ConditionalElement /// if (condition) : Elem { } /// if (foo ? bar : xx) : Elem { foo:bar; Elem {}} /// ``` /// Must consume at least one token fn parse_if_element(p: &mut impl Parser) { debug_assert_eq!(p.peek().as_str(), "if"); let mut p = p.start_node(SyntaxKind::ConditionalElement); p.consume(); // "if" if !p.expect(SyntaxKind::LParent) { return; } parse_expression(&mut *p); if !p.expect(SyntaxKind::RParent) || !p.expect(SyntaxKind::Colon) { return; } parse_element(&mut *p); } #[cfg_attr(test, parser_test)] /// ```test,QualifiedName /// Rectangle /// MyModule.Rectangle /// Deeply.Nested.MyModule.Rectangle /// ``` pub fn parse_qualified_name(p: &mut impl Parser) -> bool { let mut p = p.start_node(SyntaxKind::QualifiedName); if !p.expect(SyntaxKind::Identifier) { return false; } loop { if p.nth(0) != SyntaxKind::Dot { break; } p.consume(); p.expect(SyntaxKind::Identifier); } return true; } #[cfg_attr(test, parser_test)] /// ```test,Binding /// foo: bar; /// foo: {} /// ``` fn parse_property_binding(p: &mut impl Parser) { let mut p = p.start_node(SyntaxKind::Binding); p.consume(); p.expect(SyntaxKind::Colon); parse_binding_expression(&mut *p); } #[cfg_attr(test, parser_test)] /// ```test,BindingExpression /// { } /// expression ; /// {expression } /// {object: 42}; /// ``` fn parse_binding_expression(p: &mut impl Parser) { let mut p = p.start_node(SyntaxKind::BindingExpression); if p.nth(0) == SyntaxKind::LBrace && p.nth(2) != SyntaxKind::Colon { parse_code_block(&mut *p); p.test(SyntaxKind::Semicolon); } else { parse_expression(&mut *p); p.expect(SyntaxKind::Semicolon); } } #[cfg_attr(test, parser_test)] /// ```test,CodeBlock /// { } /// { expression } /// { expression ; expression } /// { expression ; expression ; } /// { ;;;; } /// ``` fn parse_code_block(p: &mut impl Parser) { let mut p = p.start_node(SyntaxKind::CodeBlock); p.expect(SyntaxKind::LBrace); // Or assert? while p.nth(0) != SyntaxKind::RBrace { parse_statement(&mut *p); if !p.test(SyntaxKind::Semicolon) { break; } } p.expect(SyntaxKind::RBrace); } #[cfg_attr(test, parser_test)] /// ```test,SignalConnection /// clicked => {} /// ``` fn parse_signal_connection(p: &mut impl Parser) { let mut p = p.start_node(SyntaxKind::SignalConnection); p.consume(); // the identifier p.expect(SyntaxKind::FatArrow); parse_code_block(&mut *p); } #[cfg_attr(test, parser_test)] /// ```test,SignalDeclaration /// signal foobar; /// ``` /// Must consume at least one token fn parse_signal_declaration(p: &mut impl Parser) { debug_assert_eq!(p.peek().as_str(), "signal"); let mut p = p.start_node(SyntaxKind::SignalDeclaration); p.consume(); // "signal" { let mut p = p.start_node(SyntaxKind::DeclaredIdentifier); p.expect(SyntaxKind::Identifier); } p.expect(SyntaxKind::Semicolon); } #[cfg_attr(test, parser_test)] /// ```test,PropertyDeclaration /// property foobar; /// property text: "Something"; /// ``` fn parse_property_declaration(p: &mut impl Parser) { debug_assert_eq!(p.peek().as_str(), "property"); let mut p = p.start_node(SyntaxKind::PropertyDeclaration); p.consume(); // property p.expect(SyntaxKind::LAngle); parse_qualified_name(&mut *p); p.expect(SyntaxKind::RAngle); { let mut p = p.start_node(SyntaxKind::DeclaredIdentifier); p.expect(SyntaxKind::Identifier); } if p.nth(0) == SyntaxKind::Colon { p.consume(); parse_binding_expression(&mut *p); } else { p.expect(SyntaxKind::Semicolon); } } #[cfg_attr(test, parser_test)] /// ```test,PropertyAnimation /// animate x { duration: 1000; } /// ``` fn parse_property_animation(p: &mut impl Parser) { debug_assert_eq!(p.peek().as_str(), "animate"); let mut p = p.start_node(SyntaxKind::PropertyAnimation); p.consume(); // animate { let mut p = p.start_node(SyntaxKind::DeclaredIdentifier); p.expect(SyntaxKind::Identifier); } p.expect(SyntaxKind::LBrace); loop { match p.nth(0) { SyntaxKind::RBrace => { p.consume(); return; } SyntaxKind::Eof => return, SyntaxKind::Identifier => match p.nth(1) { SyntaxKind::Colon => parse_property_binding(&mut *p), _ => { p.consume(); p.error("Only bindings are allowed in animations"); } }, _ => { p.consume(); p.error("Only bindings are allowed in animations"); } } } }