i_slint_compiler/parser/
document.rs1use super::element::{parse_element, parse_element_content};
5use super::prelude::*;
6use super::r#type::{parse_enum_declaration, parse_rustattr, parse_struct_declaration};
7
8#[cfg_attr(test, parser_test)]
9pub fn parse_document(p: &mut impl Parser) -> bool {
21 let mut p = p.start_node(SyntaxKind::Document);
22
23 loop {
24 if p.test(SyntaxKind::Eof) {
25 return true;
26 }
27
28 if p.peek().kind() == SyntaxKind::Semicolon {
29 p.error("Extra semicolon. Remove this semicolon");
30 p.consume();
31 continue;
32 }
33
34 match p.peek().as_str() {
35 "export" => {
36 if !parse_export(&mut *p, None) {
37 break;
38 }
39 }
40 "import" => {
41 if !parse_import_specifier(&mut *p) {
42 break;
43 }
44 }
45 "struct" => {
46 if !parse_struct_declaration(&mut *p, None) {
47 break;
48 }
49 }
50 "enum" => {
51 if !parse_enum_declaration(&mut *p, None) {
52 break;
53 }
54 }
55 "@" if p.nth(1).as_str() == "rust-attr" => {
56 let checkpoint = p.checkpoint();
57 if !parse_rustattr(&mut *p) {
58 break;
59 }
60 let is_export = p.nth(0).as_str() == "export";
61 let i = if is_export { 1 } else { 0 };
62 if !matches!(p.nth(i).as_str(), "enum" | "struct") {
63 p.error("Expected enum or struct after @rust-attr");
64 continue;
65 }
66 let r = if is_export {
67 parse_export(&mut *p, Some(checkpoint))
68 } else if p.nth(0).as_str() == "struct" {
69 parse_struct_declaration(&mut *p, Some(checkpoint))
70 } else if p.nth(0).as_str() == "enum" {
71 parse_enum_declaration(&mut *p, Some(checkpoint))
72 } else {
73 false
74 };
75 if !r {
76 break;
77 }
78 }
79 _ => {
80 if !parse_component(&mut *p) {
81 break;
82 }
83 }
84 }
85 }
86 while !p.test(SyntaxKind::Eof) {
88 p.consume()
89 }
90 false
91}
92
93#[cfg_attr(test, parser_test)]
94pub fn parse_component(p: &mut impl Parser) -> bool {
104 let simple_component = p.nth(1).kind() == SyntaxKind::ColonEqual;
105 let is_global = !simple_component && p.peek().as_str() == "global";
106 let is_new_component = !simple_component && p.peek().as_str() == "component";
107 if !is_global && !simple_component && !is_new_component {
108 p.error(
109 "Parse error: expected a top-level item such as a component, a struct, or a global",
110 );
111 return false;
112 }
113 let mut p = p.start_node(SyntaxKind::Component);
114 if is_global || is_new_component {
115 p.consume();
116 }
117 if !p.start_node(SyntaxKind::DeclaredIdentifier).expect(SyntaxKind::Identifier) {
118 drop(p.start_node(SyntaxKind::Element));
119 return false;
120 }
121 if is_global {
122 if p.peek().kind() == SyntaxKind::ColonEqual {
123 p.warning("':=' to declare a global is deprecated. Remove the ':='");
124 p.consume();
125 }
126 } else if !is_new_component {
127 if p.peek().kind() == SyntaxKind::ColonEqual {
128 p.warning("':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info");
129 }
130 if !p.expect(SyntaxKind::ColonEqual) {
131 drop(p.start_node(SyntaxKind::Element));
132 return false;
133 }
134 } else if p.peek().as_str() == "inherits" {
135 p.consume();
136 } else if p.peek().kind() == SyntaxKind::LBrace {
137 let mut p = p.start_node(SyntaxKind::Element);
138 p.consume();
139 parse_element_content(&mut *p);
140 return p.expect(SyntaxKind::RBrace);
141 } else {
142 p.error("Expected '{' or keyword 'inherits'");
143 drop(p.start_node(SyntaxKind::Element));
144 return false;
145 }
146
147 if is_global && p.peek().kind() == SyntaxKind::LBrace {
148 let mut p = p.start_node(SyntaxKind::Element);
149 p.consume();
150 parse_element_content(&mut *p);
151 return p.expect(SyntaxKind::RBrace);
152 }
153
154 parse_element(&mut *p)
155}
156
157#[cfg_attr(test, parser_test)]
158pub fn parse_qualified_name(p: &mut impl Parser) -> bool {
164 let mut p = p.start_node(SyntaxKind::QualifiedName);
165 if !p.expect(SyntaxKind::Identifier) {
166 return false;
167 }
168
169 loop {
170 if p.nth(0).kind() != SyntaxKind::Dot {
171 break;
172 }
173 p.consume();
174 p.expect(SyntaxKind::Identifier);
175 }
176
177 true
178}
179
180#[cfg_attr(test, parser_test)]
181fn parse_export<P: Parser>(p: &mut P, checkpoint: Option<P::Checkpoint>) -> bool {
193 debug_assert_eq!(p.peek().as_str(), "export");
194 let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::ExportsList);
195
196 p.expect(SyntaxKind::Identifier); if p.test(SyntaxKind::LBrace) {
198 loop {
199 if p.test(SyntaxKind::RBrace) {
200 break;
201 }
202 parse_export_specifier(&mut *p);
203 match p.nth(0).kind() {
204 SyntaxKind::RBrace => {
205 p.consume();
206 break;
207 }
208 SyntaxKind::Eof => {
209 p.error("Expected comma");
210 return false;
211 }
212 SyntaxKind::Comma => {
213 p.consume();
214 }
215 _ => {
216 p.consume();
217 p.error("Expected comma");
218 return false;
219 }
220 }
221 }
222 if p.peek().as_str() == "from" {
223 let mut p = p.start_node(SyntaxKind::ExportModule);
224 p.consume(); p.expect(SyntaxKind::StringLiteral);
226 p.expect(SyntaxKind::Semicolon);
227 }
228 true
229 } else if p.peek().as_str() == "struct" {
230 parse_struct_declaration(&mut *p, checkpoint)
231 } else if p.peek().as_str() == "enum" {
232 parse_enum_declaration(&mut *p, checkpoint)
233 } else if p.peek().kind == SyntaxKind::Star {
234 let mut p = p.start_node(SyntaxKind::ExportModule);
235 p.consume(); if p.peek().as_str() != "from" {
237 p.error("Expected from keyword for export statement");
238 return false;
239 }
240 p.consume();
241 let peek = p.peek();
242 if peek.kind != SyntaxKind::StringLiteral
243 || !peek.as_str().starts_with('"')
244 || !peek.as_str().ends_with('"')
245 {
246 p.error("Expected plain string literal");
247 return false;
248 }
249 p.consume();
250 p.expect(SyntaxKind::Semicolon)
251 } else {
252 parse_component(&mut *p)
253 }
254}
255
256#[cfg_attr(test, parser_test)]
257fn parse_export_specifier(p: &mut impl Parser) -> bool {
262 let mut p = p.start_node(SyntaxKind::ExportSpecifier);
263 {
264 let mut p = p.start_node(SyntaxKind::ExportIdentifier);
265 if !p.expect(SyntaxKind::Identifier) {
266 return false;
267 }
268 }
269 if p.peek().as_str() == "as" {
270 p.consume();
271 let mut p = p.start_node(SyntaxKind::ExportName);
272 if !p.expect(SyntaxKind::Identifier) {
273 return false;
274 }
275 }
276
277 true
278}
279
280#[cfg_attr(test, parser_test)]
281fn parse_import_specifier(p: &mut impl Parser) -> bool {
286 debug_assert_eq!(p.peek().as_str(), "import");
287 let mut p = p.start_node(SyntaxKind::ImportSpecifier);
288 p.expect(SyntaxKind::Identifier); if p.peek().kind != SyntaxKind::StringLiteral {
290 if !parse_import_identifier_list(&mut *p) {
291 return false;
292 }
293 if p.peek().as_str() != "from" {
294 p.error("Expected from keyword for import statement");
295 return false;
296 }
297 if !p.expect(SyntaxKind::Identifier) {
298 return false;
299 }
300 }
301 let peek = p.peek();
302 if peek.kind != SyntaxKind::StringLiteral
303 || !peek.as_str().starts_with('"')
304 || !peek.as_str().ends_with('"')
305 {
306 p.error("Expected plain string literal");
307 return false;
308 }
309 p.consume();
310 p.expect(SyntaxKind::Semicolon)
311}
312
313#[cfg_attr(test, parser_test)]
314fn parse_import_identifier_list(p: &mut impl Parser) -> bool {
324 let mut p = p.start_node(SyntaxKind::ImportIdentifierList);
325 if !p.expect(SyntaxKind::LBrace) {
326 return false;
327 }
328 loop {
329 if p.test(SyntaxKind::RBrace) {
330 return true;
331 }
332 parse_import_identifier(&mut *p);
333 if !p.test(SyntaxKind::Comma) && p.nth(0).kind() != SyntaxKind::RBrace {
334 p.error("Expected comma or brace");
335 return false;
336 }
337 }
338}
339
340#[cfg_attr(test, parser_test)]
341fn parse_import_identifier(p: &mut impl Parser) -> bool {
346 let mut p = p.start_node(SyntaxKind::ImportIdentifier);
347 {
348 let mut p = p.start_node(SyntaxKind::ExternalName);
349 if !p.expect(SyntaxKind::Identifier) {
350 return false;
351 }
352 }
353 if p.nth(0).kind() == SyntaxKind::Identifier && p.peek().as_str() == "as" {
354 p.consume();
355 let mut p = p.start_node(SyntaxKind::InternalName);
356 if !p.expect(SyntaxKind::Identifier) {
357 return false;
358 }
359 }
360 true
361}