i_slint_compiler/parser/
type.rs

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
6use super::document::parse_qualified_name;
7use super::prelude::*;
8
9#[cfg_attr(test, parser_test)]
10/// ```test,Type
11/// string
12/// [ int ]
13/// {a: string, b: int}
14/// ```
15pub fn parse_type(p: &mut impl Parser) {
16    let mut p = p.start_node(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/// ```
34pub fn parse_type_object(p: &mut impl Parser) {
35    let mut p = p.start_node(SyntaxKind::ObjectType);
36    if !p.expect(SyntaxKind::LBrace) {
37        return;
38    }
39    while p.nth(0).kind() != SyntaxKind::RBrace {
40        let mut p = p.start_node(SyntaxKind::ObjectTypeMember);
41        p.expect(SyntaxKind::Identifier);
42        p.expect(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(SyntaxKind::Comma) {
50            break;
51        }
52    }
53    p.expect(SyntaxKind::RBrace);
54}
55
56#[cfg_attr(test, parser_test)]
57/// ```test,ArrayType
58/// [int]
59/// [[int]]
60/// [{a: string, b: [string]}]
61/// ```
62pub fn parse_type_array(p: &mut impl Parser) {
63    let mut p = p.start_node(SyntaxKind::ArrayType);
64    p.expect(SyntaxKind::LBracket);
65    parse_type(&mut *p);
66    p.expect(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/// ```
76pub 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 = p.start_node_at(checkpoint, SyntaxKind::StructDeclaration);
79    p.consume(); // "struct"
80    {
81        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
82        p.expect(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/// ```
100pub 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 = p.start_node_at(checkpoint, SyntaxKind::EnumDeclaration);
103    p.consume(); // "enum"
104    {
105        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
106        p.expect(SyntaxKind::Identifier);
107    }
108
109    if !p.expect(SyntaxKind::LBrace) {
110        return false;
111    }
112    while p.nth(0).kind() != SyntaxKind::RBrace {
113        {
114            let mut p = p.start_node(SyntaxKind::EnumValue);
115            p.expect(SyntaxKind::Identifier);
116        }
117        if !p.test(SyntaxKind::Comma) {
118            break;
119        }
120    }
121    p.expect(SyntaxKind::RBrace);
122    true
123}
124
125/// ```test,AtRustAttr
126/// @rustattr(derive([()]), just some token({()}) ()..)
127/// @rustattr()
128/// ```
129pub 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}