1use crate::ast::*;
2use crate::error::FluidError;
3use crate::lexer::Lexer;
4use crate::token::{Token, TokenType};
5
6pub struct Parser<'a> {
7 lexer: Lexer<'a>,
8 pub i: usize,
9 pub tokens: Vec<Token<'a>>,
10}
11
12impl<'a> Parser<'a> {
13 pub fn new(mut lexer: Lexer<'a>) -> Self {
14 let mut t = lexer.next();
15 let mut tokens = vec![t];
16 while t.typ != TokenType::Eof {
17 t = lexer.next();
18 tokens.push(t);
19 }
20 Self {
21 lexer,
22 i: 0,
23 tokens,
24 }
25 }
26 pub fn parse(&mut self) -> Result<Ast, FluidError> {
27 let mut a = Ast::default();
28 while self.i < self.tokens.len() {
29 if self.tokens[self.i].typ == TokenType::Eof {
30 break;
31 }
32 let curr = self.tokens[self.i];
33 match curr.typ {
34 TokenType::Eof => break,
35 TokenType::Word => match curr.word {
36 "i18n_type" => {
37 a.i18n_type = Some(true);
38 self.next_token()?;
39 self.next_token()?;
40 }
41 "class" => {
42 let c = self.consume_class()?;
43 a.classes.push(c);
44 }
45 "Function" => {
46 let f = self.consume_func()?;
47 a.functions.push(f);
48 }
49 "comment" => {
50 let c = self.consume_comment()?;
51 a.comments.push(c);
52 }
53 "decl" => {
54 let d = self.consume_decl()?;
55 a.decls.push(d);
56 }
57 "widget_class" => {
58 let w = self.consume_widget()?;
59 a.widget_classes.push(w);
60 }
61 _ => (),
62 },
63 _ => (),
64 }
65 self.next_token()?;
66 }
67 Ok(a)
68 }
69 fn next_token(&mut self) -> Result<Token, FluidError> {
70 self.i += 1;
71 if self.i >= self.tokens.len() {
72 let loc = if self.tokens.is_empty() {
73 crate::error::Location::default()
74 } else {
75 self.tokens[self.tokens.len() - 1].loc
76 };
77 return Err(FluidError::UnexpectedEof(loc));
78 }
79 Ok(self.tokens[self.i])
80 }
81
82 fn consume_func(&mut self) -> Result<Function, FluidError> {
83 let mut f = Function::default();
84 self.next_token()?;
85 f.name = self.consume_braced_string()?;
86 self.next_token()?; while self.tokens[self.i].typ != TokenType::Eof {
88 self.next_token()?;
89 if self.tokens[self.i].typ == TokenType::CloseBrace {
90 break;
91 }
92 match self.tokens[self.i].word {
93 "open" => f.props.open = Some(true),
94 "C" => f.props.c = Some(true),
95 "protected" => f.props.visibility = Some(Visibility::PROTECTED),
96 "private" => f.props.visibility = Some(Visibility::PRIVATE),
97 "comment" => {
98 self.next_token()?;
99 if self.tokens[self.i].typ == TokenType::OpenBrace {
100 f.props.comment = Some(self.consume_braced_string()?);
101 } else {
102 f.props.comment = Some(self.tokens[self.i].word.to_string());
103 }
104 }
105 "return_type" => {
106 self.next_token()?;
107 if self.tokens[self.i].typ == TokenType::OpenBrace {
108 f.props.return_type = Some(self.consume_braced_string()?);
109 } else {
110 f.props.return_type = Some(self.tokens[self.i].word.to_string());
111 }
112 }
113 _ => (),
114 }
115 }
116 self.next_token()?; if self.tokens[self.i].typ == TokenType::OpenBrace {
118 while self.tokens[self.i].typ != TokenType::CloseBrace {
119 self.next_token()?;
120 if self.tokens[self.i].word == "code" {
121 self.next_token()?;
122 f.code = Some(self.consume_code()?);
123 self.next_token()?;
124 }
125 if self.tokens[self.i].word.starts_with("Fl_")
126 || self.tokens[self.i].word == "MenuItem"
127 || self.tokens[self.i].word == "Submenu"
128 {
129 let w = self.consume_widget()?;
130 f.widgets.push(w);
131 self.next_token()?;
132 }
133 }
134 }
135 Ok(f)
136 }
137 fn consume_widget(&mut self) -> Result<Widget, FluidError> {
138 let mut w = Widget {
139 typ: self.tokens[self.i].word.to_string(),
140 ..Default::default()
141 };
142 self.next_token()?;
143 if self.tokens[self.i].typ == TokenType::OpenBrace {
144 self.next_token()?;
145 }
146 if !self.tokens[self.i].word.is_empty() {
147 w.name = self.tokens[self.i].word.to_string();
148 } else {
149 w.name = String::new();
150 }
151 while self.tokens[self.i].typ != TokenType::Eof {
152 self.next_token()?;
153 if self.tokens[self.i].typ == TokenType::CloseBrace {
154 break;
155 }
156 match self.tokens[self.i].word {
157 "open" => w.props.open = Some(true),
158 "hide" => w.props.hide = Some(true),
159 "deactivate" => w.props.deactivate = Some(true),
160 "divider" => w.props.divider = Some(true),
161 "resizable" => w.props.resizable = Some(true),
162 "visible" => w.props.visible = Some(true),
163 "hotspot" => w.props.hotspot = Some(true),
164 "modal" => w.props.modal = Some(true),
165 "non_modal" => w.props.non_modal = Some(true),
166 "noborder" => w.props.noborder = Some(true),
167 "xywh" => {
168 self.next_token()?;
169 w.props.xywh = self.consume_braced_string()?;
170 }
171 "size_range" => {
172 self.next_token()?;
173 w.props.size_range = Some(self.consume_braced_string()?);
174 }
175 "color" => {
176 self.next_token()?;
177 w.props.color =
178 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
179 FluidError::Parse(
180 self.tokens[self.i].word.to_string(),
181 self.tokens[self.i].loc,
182 )
183 })?);
184 }
185 "selection_color" => {
186 self.next_token()?;
187 w.props.selection_color =
188 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
189 FluidError::Parse(
190 self.tokens[self.i].word.to_string(),
191 self.tokens[self.i].loc,
192 )
193 })?);
194 }
195 "labelcolor" => {
196 self.next_token()?;
197 w.props.labelcolor =
198 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
199 FluidError::Parse(
200 self.tokens[self.i].word.to_string(),
201 self.tokens[self.i].loc,
202 )
203 })?);
204 }
205 "textcolor" => {
206 self.next_token()?;
207 w.props.textcolor =
208 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
209 FluidError::Parse(
210 self.tokens[self.i].word.to_string(),
211 self.tokens[self.i].loc,
212 )
213 })?);
214 }
215 "type" => {
216 self.next_token()?;
217 if self.tokens[self.i].typ == TokenType::OpenBrace {
218 w.props.typ = Some(self.consume_braced_string()?);
219 } else {
220 w.props.typ = Some(self.tokens[self.i].word.to_string());
221 }
222 }
223 "labeltype" => {
224 self.next_token()?;
225 w.props.labeltype = Some(self.tokens[self.i].word.to_string());
226 }
227 "labelfont" => {
228 self.next_token()?;
229 w.props.labelfont =
230 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
231 FluidError::Parse(
232 self.tokens[self.i].word.to_string(),
233 self.tokens[self.i].loc,
234 )
235 })?);
236 }
237 "textfont" => {
238 self.next_token()?;
239 w.props.textfont =
240 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
241 FluidError::Parse(
242 self.tokens[self.i].word.to_string(),
243 self.tokens[self.i].loc,
244 )
245 })?);
246 }
247 "labelsize" => {
248 self.next_token()?;
249 w.props.labelsize =
250 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
251 FluidError::Parse(
252 self.tokens[self.i].word.to_string(),
253 self.tokens[self.i].loc,
254 )
255 })?);
256 }
257 "textsize" => {
258 self.next_token()?;
259 w.props.textsize =
260 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
261 FluidError::Parse(
262 self.tokens[self.i].word.to_string(),
263 self.tokens[self.i].loc,
264 )
265 })?);
266 }
267 "box" => {
268 self.next_token()?;
269 w.props.r#box = Some(self.tokens[self.i].word.to_string());
270 }
271 "down_box" => {
272 self.next_token()?;
273 w.props.down_box = Some(self.tokens[self.i].word.to_string());
274 }
275 "align" => {
276 self.next_token()?;
277 w.props.align =
278 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
279 FluidError::Parse(
280 self.tokens[self.i].word.to_string(),
281 self.tokens[self.i].loc,
282 )
283 })?);
284 }
285 "when" => {
286 self.next_token()?;
287 w.props.when =
288 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
289 FluidError::Parse(
290 self.tokens[self.i].word.to_string(),
291 self.tokens[self.i].loc,
292 )
293 })?);
294 }
295 "shortcut" => {
296 self.next_token()?;
297 w.props.shortcut = Some(self.tokens[self.i].word.to_string());
298 }
299 "gap" => {
300 self.next_token()?;
301 if self.tokens[self.i].typ == TokenType::OpenBrace {
302 w.props.gap = Some(self.consume_braced_string()?);
303 } else {
304 w.props.gap = Some(self.tokens[self.i].word.to_string());
305 }
306 }
307 "minimum" => {
308 self.next_token()?;
309 w.props.minimum =
310 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
311 FluidError::Parse(
312 self.tokens[self.i].word.to_string(),
313 self.tokens[self.i].loc,
314 )
315 })?);
316 }
317 "maximum" => {
318 self.next_token()?;
319 w.props.maximum =
320 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
321 FluidError::Parse(
322 self.tokens[self.i].word.to_string(),
323 self.tokens[self.i].loc,
324 )
325 })?);
326 }
327 "step" => {
328 self.next_token()?;
329 w.props.step =
330 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
331 FluidError::Parse(
332 self.tokens[self.i].word.to_string(),
333 self.tokens[self.i].loc,
334 )
335 })?);
336 }
337 "slider_size" => {
338 self.next_token()?;
339 w.props.slider_size =
340 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
341 FluidError::Parse(
342 self.tokens[self.i].word.to_string(),
343 self.tokens[self.i].loc,
344 )
345 })?);
346 }
347 "size" => {
348 self.next_token()?;
349 w.props.size =
350 Some(self.tokens[self.i].word.to_string().parse().map_err(|_| {
351 FluidError::Parse(
352 self.tokens[self.i].word.to_string(),
353 self.tokens[self.i].loc,
354 )
355 })?);
356 }
357 "label" => {
358 self.next_token()?;
359 if self.tokens[self.i].typ == TokenType::OpenBrace {
360 w.props.label = Some(self.consume_braced_string()?);
361 } else {
362 w.props.label = Some(self.tokens[self.i].word.to_string());
363 }
364 }
365 "xclass" => {
366 self.next_token()?;
367 if self.tokens[self.i].typ == TokenType::OpenBrace {
368 w.props.xclass = Some(self.consume_braced_string()?);
369 } else {
370 w.props.xclass = Some(self.tokens[self.i].word.to_string());
371 }
372 }
373 "class" => {
374 self.next_token()?;
375 if self.tokens[self.i].typ == TokenType::OpenBrace {
376 w.props.class = Some(self.consume_braced_string()?);
377 } else {
378 w.props.class = Some(self.tokens[self.i].word.to_string());
379 }
380 }
381 "tooltip" => {
382 self.next_token()?;
383 if self.tokens[self.i].typ == TokenType::OpenBrace {
384 w.props.tooltip = Some(self.consume_braced_string()?);
385 } else {
386 w.props.tooltip = Some(self.tokens[self.i].word.to_string());
387 }
388 }
389 "image" => {
390 self.next_token()?;
391 if self.tokens[self.i].typ == TokenType::OpenBrace {
392 w.props.image = Some(self.consume_braced_string()?);
393 } else {
394 w.props.image = Some(self.tokens[self.i].word.to_string());
395 }
396 }
397 "deimage" => {
398 self.next_token()?;
399 if self.tokens[self.i].typ == TokenType::OpenBrace {
400 w.props.deimage = Some(self.consume_braced_string()?);
401 } else {
402 w.props.deimage = Some(self.tokens[self.i].word.to_string());
403 }
404 }
405 "value" => {
406 self.next_token()?;
407 if self.tokens[self.i].typ == TokenType::OpenBrace {
408 w.props.value = Some(self.consume_braced_string()?);
409 } else {
410 w.props.value = Some(self.tokens[self.i].word.to_string());
411 }
412 }
413 "set_size_tuples" => {
414 self.next_token()?;
415 w.props.size_tuple = Some(self.consume_braced_string()?);
416 }
417 "margins" => {
418 self.next_token()?;
419 w.props.margins = Some(self.consume_braced_string()?);
420 }
421 "dimensions" => {
422 self.next_token()?;
423 w.props.dimensions = Some(self.consume_braced_string()?);
424 }
425 "margin" => {
426 self.next_token()?;
427 w.props.margin = Some(self.consume_braced_string()?);
428 }
429 "fixed_size_tuples" => {
430 self.next_token()?;
431 w.props.size_tuple = Some(self.consume_braced_string()?);
432 }
433 "code0" => {
434 self.next_token()?;
435 w.props.code0 = Some(self.consume_braced_string()?);
436 }
437 "code1" => {
438 self.next_token()?;
439 w.props.code1 = Some(self.consume_braced_string()?);
440 }
441 "code2" => {
442 self.next_token()?;
443 w.props.code2 = Some(self.consume_braced_string()?);
444 }
445 "code3" => {
446 self.next_token()?;
447 w.props.code3 = Some(self.consume_braced_string()?);
448 }
449 "extra_code" => {
450 self.next_token()?;
451 w.props.extra_code = Some(self.consume_braced_string()?);
452 }
453 "callback" => {
454 self.next_token()?;
455 if self.tokens[self.i].typ == TokenType::OpenBrace {
456 w.props.callback = Some(self.consume_braced_string()?);
457 } else {
458 w.props.callback = Some(self.tokens[self.i].word.to_string());
459 }
460 }
461 "user_data" => {
462 self.next_token()?;
463 if self.tokens[self.i].typ == TokenType::OpenBrace {
464 w.props.user_data = Some(self.consume_braced_string()?);
465 } else {
466 w.props.user_data = Some(self.tokens[self.i].word.to_string());
467 }
468 }
469 "user_data_type" => {
470 self.next_token()?;
471 if self.tokens[self.i].typ == TokenType::OpenBrace {
472 w.props.user_data_type = Some(self.consume_braced_string()?);
473 } else {
474 w.props.user_data_type = Some(self.tokens[self.i].word.to_string());
475 }
476 }
477 "comment" => {
478 self.next_token()?;
479 if self.tokens[self.i].typ == TokenType::OpenBrace {
480 w.props.comment = Some(self.consume_braced_string()?);
481 } else {
482 w.props.comment = Some(self.tokens[self.i].word.to_string());
483 }
484 }
485 "parent_properties" => {
486 while self.tokens[self.i].typ != TokenType::CloseBrace {
487 self.next_token()?;
488 w.props.parent_properties = Some(self.consume_parent_props()?);
489 }
490 }
491 _ => (),
492 }
493 }
494 if self
495 .tokens
496 .get(self.i + 1)
497 .is_some_and(|t| t.typ == TokenType::OpenBrace)
498 {
499 self.next_token()?;
500 while self.tokens[self.i].typ != TokenType::CloseBrace {
501 self.next_token()?;
502 while self.tokens[self.i].word.starts_with("Fl_")
503 || self.tokens[self.i].word == "MenuItem"
504 || self.tokens[self.i].word == "Submenu"
505 {
506 let c = self.consume_widget()?;
507 w.children.push(c);
508 self.next_token()?;
509 }
510 }
511 }
512 Ok(w)
513 }
514 fn consume_class(&mut self) -> Result<Class, FluidError> {
515 let mut c = Class::default();
516 self.next_token()?;
517 if self.tokens[self.i].typ == TokenType::OpenBrace {
518 self.next_token()?;
519 self.next_token()?;
520 }
521 c.name = self.tokens[self.i].word.to_string();
522 self.next_token()?;
523 while self.tokens[self.i].typ != TokenType::CloseBrace {
525 self.next_token()?;
526 match self.tokens[self.i].word {
527 "open" => c.props.open = Some(true),
528 "protected" => c.props.visibility = Some(Visibility::PROTECTED),
529 "private" => c.props.visibility = Some(Visibility::PRIVATE),
530 "comment" => {
531 self.next_token()?;
532 if self.tokens[self.i].typ == TokenType::OpenBrace {
533 c.props.comment = Some(self.consume_braced_string()?);
534 } else {
535 c.props.comment = Some(self.tokens[self.i].word.to_string());
536 }
537 }
538 _ => (),
539 }
540 }
541 self.next_token()?;
542 if self.tokens[self.i].typ == TokenType::OpenBrace {
543 while self.tokens[self.i].typ != TokenType::CloseBrace {
544 self.next_token()?;
545 while self.tokens[self.i].word == "Function" {
546 let f = self.consume_func()?;
547 c.functions.push(f);
548 }
549 if self.tokens[self.i].word == "comment" {
550 self.next_token()?;
551 if self.tokens[self.i].typ == TokenType::OpenBrace {
552 c.props.comment = Some(self.consume_braced_string()?);
553 } else {
554 c.props.comment = Some(self.tokens[self.i].word.to_string());
555 }
556 }
557 }
558 }
559 Ok(c)
560 }
561 fn consume_comment(&mut self) -> Result<Comment, FluidError> {
562 let mut c = Comment::default();
563 self.next_token()?;
564 c.comment = self.consume_braced_string()?;
565 while self.tokens[self.i].typ != TokenType::Eof {
566 self.next_token()?;
567 if self.tokens[self.i].typ == TokenType::CloseBrace {
568 break;
569 }
570 match self.tokens[self.i].word {
571 "in_source" => c.props.in_source = Some(true),
572 "in_header" => c.props.in_header = Some(true),
573 _ => (),
574 }
575 }
576 Ok(c)
577 }
578 fn consume_decl(&mut self) -> Result<Decl, FluidError> {
579 let mut d = Decl::default();
580 self.next_token()?;
581 d.decl = self.consume_braced_string()?;
582 while self.tokens[self.i].typ != TokenType::Eof {
583 self.next_token()?;
584 if self.tokens[self.i].typ == TokenType::CloseBrace {
585 break;
586 }
587 match self.tokens[self.i].word {
588 "private" => d.props.visibility = Visibility::PRIVATE,
589 "public" => d.props.visibility = Visibility::PUBLIC,
590 "global" => d.props.global = Some(true),
591 "local" => d.props.local = Some(true),
592 _ => (),
593 }
594 }
595 Ok(d)
596 }
597 fn consume_code(&mut self) -> Result<String, FluidError> {
598 let s = self.consume_braced_string()?;
599 self.next_token()?;
601 self.next_token()?;
602 Ok(s)
603 }
604
605 fn consume_braced_string(&mut self) -> Result<String, FluidError> {
606 self.next_token()?;
607 let mut t = self.tokens[self.i];
608 let start = t.start;
609 let mut openbrace = 1;
610 while t.typ != TokenType::Eof {
611 self.next_token()?;
612 t = self.tokens[self.i];
613 if t.typ == TokenType::OpenBrace {
614 openbrace += 1;
615 }
616 if t.typ == TokenType::CloseBrace {
617 openbrace -= 1;
618 }
619 if openbrace == 0 {
620 break;
621 }
622 }
623 if t.typ == TokenType::Eof {
624 return Err(FluidError::UnexpectedEof(self.tokens[self.i].loc));
625 }
626 let end = self.tokens[self.i].end - 1;
627 Ok(self.lexer.s[start..end].to_string())
628 }
629 fn consume_parent_props(&mut self) -> Result<ParentProps, FluidError> {
630 let mut p = ParentProps::default();
631 while self.tokens[self.i].typ != TokenType::Eof {
632 self.next_token()?;
633 if self.tokens[self.i].typ == TokenType::CloseBrace {
634 break;
635 }
636 if self.tokens[self.i].word == "location" {
637 self.next_token()?;
638 p.location = Some(self.consume_braced_string()?);
639 }
640 }
641 Ok(p)
642 }
643}