| 1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
| 2 | // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 |
| 3 | |
| 4 | //! Module containing the parsing functions for type names |
| 5 | |
| 6 | use super::document::parse_qualified_name; |
| 7 | use super::prelude::*; |
| 8 | |
| 9 | #[cfg_attr (test, parser_test)] |
| 10 | /// ```test,Type |
| 11 | /// string |
| 12 | /// [ int ] |
| 13 | /// {a: string, b: int} |
| 14 | /// ``` |
| 15 | pub fn parse_type(p: &mut impl Parser) { |
| 16 | let mut p: Node<'_, impl Parser> = p.start_node(kind:SyntaxKind::Type); |
| 17 | match p.nth(0).kind() { |
| 18 | SyntaxKind::LBrace => parse_type_object(&mut *p), |
| 19 | SyntaxKind::LBracket => parse_type_array(&mut *p), |
| 20 | _ => { |
| 21 | parse_qualified_name(&mut *p); |
| 22 | } |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | #[cfg_attr (test, parser_test)] |
| 27 | /// ```test,ObjectType |
| 28 | /// {a: string, b: int} |
| 29 | /// {} |
| 30 | /// {a: string} |
| 31 | /// {a: string,} |
| 32 | /// {a: { foo: string, bar: int, }, q: {} } |
| 33 | /// ``` |
| 34 | pub fn parse_type_object(p: &mut impl Parser) { |
| 35 | let mut p: Node<'_, impl Parser> = p.start_node(kind:SyntaxKind::ObjectType); |
| 36 | if !p.expect(kind:SyntaxKind::LBrace) { |
| 37 | return; |
| 38 | } |
| 39 | while p.nth(0).kind() != SyntaxKind::RBrace { |
| 40 | let mut p: Node<'_, impl Parser> = p.start_node(kind:SyntaxKind::ObjectTypeMember); |
| 41 | p.expect(kind:SyntaxKind::Identifier); |
| 42 | p.expect(kind:SyntaxKind::Colon); |
| 43 | parse_type(&mut *p); |
| 44 | if p.peek().kind() == SyntaxKind::Semicolon { |
| 45 | p.error("Expected ','. Use ',' instead of ';' to separate fields in a struct" ); |
| 46 | p.consume(); |
| 47 | continue; |
| 48 | } |
| 49 | if !p.test(kind:SyntaxKind::Comma) { |
| 50 | break; |
| 51 | } |
| 52 | } |
| 53 | p.expect(kind:SyntaxKind::RBrace); |
| 54 | } |
| 55 | |
| 56 | #[cfg_attr (test, parser_test)] |
| 57 | /// ```test,ArrayType |
| 58 | /// [int] |
| 59 | /// [[int]] |
| 60 | /// [{a: string, b: [string]}] |
| 61 | /// ``` |
| 62 | pub fn parse_type_array(p: &mut impl Parser) { |
| 63 | let mut p: Node<'_, impl Parser> = p.start_node(kind:SyntaxKind::ArrayType); |
| 64 | p.expect(kind:SyntaxKind::LBracket); |
| 65 | parse_type(&mut *p); |
| 66 | p.expect(kind:SyntaxKind::RBracket); |
| 67 | } |
| 68 | |
| 69 | #[cfg_attr (test, parser_test)] |
| 70 | /// ```test,StructDeclaration |
| 71 | /// struct Foo := { foo: bar, xxx: { aaa: bbb, } } |
| 72 | /// struct Bar := {} |
| 73 | /// struct Foo { foo: bar, xxx: { aaa: bbb, } } |
| 74 | /// struct Bar {} |
| 75 | /// ``` |
| 76 | pub fn parse_struct_declaration<P: Parser>(p: &mut P, checkpoint: Option<P::Checkpoint>) -> bool { |
| 77 | debug_assert_eq!(p.peek().as_str(), "struct" ); |
| 78 | let mut p: Node<'_, P> = p.start_node_at(checkpoint, kind:SyntaxKind::StructDeclaration); |
| 79 | p.consume(); // "struct" |
| 80 | { |
| 81 | let mut p: Node<'_, P> = p.start_node(kind:SyntaxKind::DeclaredIdentifier); |
| 82 | p.expect(kind:SyntaxKind::Identifier); |
| 83 | } |
| 84 | |
| 85 | if p.peek().kind() == SyntaxKind::ColonEqual { |
| 86 | p.warning("':=' to declare a struct is deprecated. Remove the ':='" ); |
| 87 | p.consume(); |
| 88 | } |
| 89 | |
| 90 | parse_type_object(&mut *p); |
| 91 | true |
| 92 | } |
| 93 | |
| 94 | #[cfg_attr (test, parser_test)] |
| 95 | /// ```test,EnumDeclaration |
| 96 | /// enum Foo {} |
| 97 | /// enum Foo { el1 } |
| 98 | /// enum Foo { el1, xxx, yyy } |
| 99 | /// ``` |
| 100 | pub fn parse_enum_declaration<P: Parser>(p: &mut P, checkpoint: Option<P::Checkpoint>) -> bool { |
| 101 | debug_assert_eq!(p.peek().as_str(), "enum" ); |
| 102 | let mut p: Node<'_, P> = p.start_node_at(checkpoint, kind:SyntaxKind::EnumDeclaration); |
| 103 | p.consume(); // "enum" |
| 104 | { |
| 105 | let mut p: Node<'_, P> = p.start_node(kind:SyntaxKind::DeclaredIdentifier); |
| 106 | p.expect(kind:SyntaxKind::Identifier); |
| 107 | } |
| 108 | |
| 109 | if !p.expect(kind:SyntaxKind::LBrace) { |
| 110 | return false; |
| 111 | } |
| 112 | while p.nth(0).kind() != SyntaxKind::RBrace { |
| 113 | { |
| 114 | let mut p: Node<'_, P> = p.start_node(kind:SyntaxKind::EnumValue); |
| 115 | p.expect(kind:SyntaxKind::Identifier); |
| 116 | } |
| 117 | if !p.test(kind:SyntaxKind::Comma) { |
| 118 | break; |
| 119 | } |
| 120 | } |
| 121 | p.expect(kind:SyntaxKind::RBrace); |
| 122 | true |
| 123 | } |
| 124 | |
| 125 | /// ```test,AtRustAttr |
| 126 | /// @rustattr(derive([()]), just some token({()}) ()..) |
| 127 | /// @rustattr() |
| 128 | /// ``` |
| 129 | pub fn parse_rustattr(p: &mut impl Parser) -> bool { |
| 130 | debug_assert_eq!(p.peek().as_str(), "@" ); |
| 131 | p.consume(); // "@" |
| 132 | if p.peek().as_str() != "rust-attr" { |
| 133 | p.expect(SyntaxKind::AtRustAttr); |
| 134 | } |
| 135 | p.consume(); // "rust-attr" |
| 136 | p.expect(SyntaxKind::LParent); |
| 137 | { |
| 138 | let mut p = p.start_node(SyntaxKind::AtRustAttr); |
| 139 | let mut level = 1; |
| 140 | loop { |
| 141 | match p.peek().kind() { |
| 142 | SyntaxKind::LParent => level += 1, |
| 143 | SyntaxKind::RParent => { |
| 144 | level -= 1; |
| 145 | if level == 0 { |
| 146 | break; |
| 147 | } |
| 148 | } |
| 149 | SyntaxKind::Eof => { |
| 150 | p.error("unmatched parentheses in @rust-attr" ); |
| 151 | return false; |
| 152 | } |
| 153 | _ => {} |
| 154 | } |
| 155 | p.consume() |
| 156 | } |
| 157 | } |
| 158 | p.expect(SyntaxKind::RParent) |
| 159 | } |
| 160 | |