Skip to main content

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