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 {
22 let mut p = p.start_node(SyntaxKind::Document);
23
24 loop {
25 if p.test(SyntaxKind::Eof) {
26 return true;
27 }
28
29 if p.peek().kind() == SyntaxKind::Semicolon {
30 p.error("Extra semicolon. Remove this semicolon");
31 p.consume();
32 continue;
33 }
34
35 match p.peek().as_str() {
36 "export" => {
37 if !parse_export(&mut *p, None) {
38 break;
39 }
40 }
41 "import" => {
42 if !parse_import_specifier(&mut *p) {
43 break;
44 }
45 }
46 "struct" => {
47 if !parse_struct_declaration(&mut *p, None) {
48 break;
49 }
50 }
51 "enum" => {
52 if !parse_enum_declaration(&mut *p, None) {
53 break;
54 }
55 }
56 "@" if p.nth(1).as_str() == "rust-attr" => {
57 let checkpoint = p.checkpoint();
58 if !parse_rustattr(&mut *p) {
59 break;
60 }
61 while p.peek().as_str() == "@" && p.nth(1).as_str() == "rust-attr" {
62 parse_rustattr(&mut *p);
63 }
64 let is_export = p.peek().as_str() == "export";
65 let i = if is_export { 1 } else { 0 };
66 if !matches!(p.nth(i).as_str(), "enum" | "struct") {
67 p.error("Expected enum or struct after @rust-attr");
68 continue;
69 }
70 let r = if is_export {
71 parse_export(&mut *p, Some(checkpoint))
72 } else if p.peek().as_str() == "struct" {
73 parse_struct_declaration(&mut *p, Some(checkpoint))
74 } else if p.peek().as_str() == "enum" {
75 parse_enum_declaration(&mut *p, Some(checkpoint))
76 } else {
77 false
78 };
79 if !r {
80 break;
81 }
82 }
83 _ => {
84 if !parse_component(&mut *p) {
85 break;
86 }
87 }
88 }
89 }
90 while !p.test(SyntaxKind::Eof) {
92 p.consume()
93 }
94 false
95}
96
97#[cfg_attr(test, parser_test)]
98pub fn parse_component(p: &mut impl Parser) -> bool {
109 let simple_component = p.nth(1).kind() == SyntaxKind::ColonEqual;
110 let is_global = !simple_component && p.peek().as_str() == "global";
111 let is_interface = !simple_component && p.peek().as_str() == "interface";
112 let is_new_component = !simple_component && p.peek().as_str() == "component";
113 if !is_global && !simple_component && !is_new_component && !is_interface {
114 p.error(
115 "Parse error: expected a top-level item such as a component, a struct, or a global",
116 );
117 return false;
118 }
119 let mut p = p.start_node(SyntaxKind::Component);
120 if is_global || is_new_component || is_interface {
121 p.consume();
122 }
123 if !p.start_node(SyntaxKind::DeclaredIdentifier).expect(SyntaxKind::Identifier) {
124 drop(p.start_node(SyntaxKind::Element));
125 return false;
126 }
127 if is_global {
128 if p.peek().kind() == SyntaxKind::ColonEqual {
129 p.warning("':=' to declare a global is deprecated. Remove the ':='");
130 p.consume();
131 }
132 } else if is_interface {
133 if p.peek().kind() == SyntaxKind::ColonEqual {
134 p.error("':=' to declare an interface is not supported. Remove the ':='");
135 p.consume();
136 }
137 if p.peek().as_str() == "inherits" {
138 p.error("Interface inheritance is not supported");
139 drop(p.start_node(SyntaxKind::Element));
140 return false;
141 }
142 } else if !is_new_component {
143 if p.peek().kind() == SyntaxKind::ColonEqual {
144 p.warning("':=' to declare a component is deprecated. The new syntax declare components with 'component MyComponent {'. Read the documentation for more info");
145 }
146 if !p.expect(SyntaxKind::ColonEqual) {
147 drop(p.start_node(SyntaxKind::Element));
148 return false;
149 }
150 } else if p.peek().as_str() == "inherits" {
151 p.consume();
152 } else if p.peek().kind() == SyntaxKind::LBrace {
153 let mut p = p.start_node(SyntaxKind::Element);
154 p.consume();
155 parse_element_content(&mut *p);
156 return p.expect(SyntaxKind::RBrace);
157 } else {
158 p.error("Expected '{' or keyword 'inherits'");
159 drop(p.start_node(SyntaxKind::Element));
160 return false;
161 }
162
163 if (is_global || is_interface) && p.peek().kind() == SyntaxKind::LBrace {
164 let mut p = p.start_node(SyntaxKind::Element);
165 p.consume();
166 parse_element_content(&mut *p);
167 return p.expect(SyntaxKind::RBrace);
168 }
169
170 parse_element(&mut *p)
171}
172
173#[cfg_attr(test, parser_test)]
174pub fn parse_qualified_name(p: &mut impl Parser) -> bool {
180 let mut p = p.start_node(SyntaxKind::QualifiedName);
181 if !p.expect(SyntaxKind::Identifier) {
182 return false;
183 }
184
185 loop {
186 if p.nth(0).kind() != SyntaxKind::Dot {
187 break;
188 }
189 p.consume();
190 p.expect(SyntaxKind::Identifier);
191 }
192
193 true
194}
195
196#[cfg_attr(test, parser_test)]
197fn parse_export<P: Parser>(p: &mut P, checkpoint: Option<P::Checkpoint>) -> bool {
209 debug_assert_eq!(p.peek().as_str(), "export");
210 let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::ExportsList);
211
212 p.expect(SyntaxKind::Identifier); if p.test(SyntaxKind::LBrace) {
214 loop {
215 if p.test(SyntaxKind::RBrace) {
216 break;
217 }
218 parse_export_specifier(&mut *p);
219 match p.nth(0).kind() {
220 SyntaxKind::RBrace => {
221 p.consume();
222 break;
223 }
224 SyntaxKind::Eof => {
225 p.error("Expected comma");
226 return false;
227 }
228 SyntaxKind::Comma => {
229 p.consume();
230 }
231 _ => {
232 p.consume();
233 p.error("Expected comma");
234 return false;
235 }
236 }
237 }
238 if p.peek().as_str() == "from" {
239 let mut p = p.start_node(SyntaxKind::ExportModule);
240 p.consume(); p.expect(SyntaxKind::StringLiteral);
242 p.expect(SyntaxKind::Semicolon);
243 }
244 true
245 } else if p.peek().as_str() == "struct" {
246 parse_struct_declaration(&mut *p, checkpoint)
247 } else if p.peek().as_str() == "enum" {
248 parse_enum_declaration(&mut *p, checkpoint)
249 } else if p.peek().kind == SyntaxKind::Star {
250 let mut p = p.start_node(SyntaxKind::ExportModule);
251 p.consume(); if p.peek().as_str() != "from" {
253 p.error("Expected from keyword for export statement");
254 return false;
255 }
256 p.consume();
257 let peek = p.peek();
258 if peek.kind != SyntaxKind::StringLiteral
259 || !peek.as_str().starts_with('"')
260 || !peek.as_str().ends_with('"')
261 {
262 p.error("Expected plain string literal");
263 return false;
264 }
265 p.consume();
266 p.expect(SyntaxKind::Semicolon)
267 } else {
268 parse_component(&mut *p)
269 }
270}
271
272#[cfg_attr(test, parser_test)]
273fn parse_export_specifier(p: &mut impl Parser) -> bool {
278 let mut p = p.start_node(SyntaxKind::ExportSpecifier);
279 {
280 let mut p = p.start_node(SyntaxKind::ExportIdentifier);
281 if !p.expect(SyntaxKind::Identifier) {
282 return false;
283 }
284 }
285 if p.peek().as_str() == "as" {
286 p.consume();
287 let mut p = p.start_node(SyntaxKind::ExportName);
288 if !p.expect(SyntaxKind::Identifier) {
289 return false;
290 }
291 }
292
293 true
294}
295
296#[cfg_attr(test, parser_test)]
297fn parse_import_specifier(p: &mut impl Parser) -> bool {
302 debug_assert_eq!(p.peek().as_str(), "import");
303 let mut p = p.start_node(SyntaxKind::ImportSpecifier);
304 p.expect(SyntaxKind::Identifier); if p.peek().kind != SyntaxKind::StringLiteral {
306 if !parse_import_identifier_list(&mut *p) {
307 return false;
308 }
309 if p.peek().as_str() != "from" {
310 p.error("Expected from keyword for import statement");
311 return false;
312 }
313 if !p.expect(SyntaxKind::Identifier) {
314 return false;
315 }
316 }
317 let peek = p.peek();
318 if peek.kind != SyntaxKind::StringLiteral
319 || !peek.as_str().starts_with('"')
320 || !peek.as_str().ends_with('"')
321 {
322 p.error("Expected plain string literal");
323 return false;
324 }
325 p.consume();
326 p.expect(SyntaxKind::Semicolon)
327}
328
329#[cfg_attr(test, parser_test)]
330fn parse_import_identifier_list(p: &mut impl Parser) -> bool {
340 let mut p = p.start_node(SyntaxKind::ImportIdentifierList);
341 if !p.expect(SyntaxKind::LBrace) {
342 return false;
343 }
344 loop {
345 if p.test(SyntaxKind::RBrace) {
346 return true;
347 }
348 parse_import_identifier(&mut *p);
349 if !p.test(SyntaxKind::Comma) && p.nth(0).kind() != SyntaxKind::RBrace {
350 p.error("Expected comma or brace");
351 return false;
352 }
353 }
354}
355
356#[cfg_attr(test, parser_test)]
357fn parse_import_identifier(p: &mut impl Parser) -> bool {
362 let mut p = p.start_node(SyntaxKind::ImportIdentifier);
363 {
364 let mut p = p.start_node(SyntaxKind::ExternalName);
365 if !p.expect(SyntaxKind::Identifier) {
366 return false;
367 }
368 }
369 if p.nth(0).kind() == SyntaxKind::Identifier && p.peek().as_str() == "as" {
370 p.consume();
371 let mut p = p.start_node(SyntaxKind::InternalName);
372 if !p.expect(SyntaxKind::Identifier) {
373 return false;
374 }
375 }
376 true
377}