1use crate::error::SeqError;
2use crate::ir::{
3 BinOp, CompParam, ComponentDef, DeferredDecl, DeferredKind, FnParam, ImportDecl, LengthVal,
4 MatchPat, SeqApp, SeqArg, SeqExpr, SeqExprKind, SeqFile, SeqFn, SeqMatchArm, SeqNode, SeqStmt,
5 SeqValue, SeqWindow, StateDecl, StyleDecl, ThemeName, UnOp, Visibility,
6};
7
8pub fn parse(file: &str, src: &str) -> Result<SeqApp, SeqError> {
9 let seq = parse_seq_file(file, src)?;
10 let mut app = seq
11 .app
12 .ok_or_else(|| SeqError::new(file, 1, 1, "brak bloku `app Nazwa { }`"))?;
13 app.components = seq.components;
14 app.imports = seq.imports;
15 Ok(app)
16}
17
18pub fn parse_seq_file(file: &str, src: &str) -> Result<SeqFile, SeqError> {
19 let mut p = Parser::new(file, src);
20 p.parse_seq_file()
21}
22
23const MAX_NESTING_DEPTH: usize = 256;
24
25fn is_single_value_expr(kind: &SeqExprKind) -> bool {
26 matches!(
27 kind,
28 SeqExprKind::Int(_)
29 | SeqExprKind::Float(_)
30 | SeqExprKind::Str(_)
31 | SeqExprKind::Bool(_)
32 | SeqExprKind::Var(_)
33 | SeqExprKind::Field { .. }
34 | SeqExprKind::Unary { .. }
35 | SeqExprKind::Call { .. }
36 | SeqExprKind::Array(_)
37 )
38}
39
40struct Parser<'a> {
41 file: &'a str,
42 chars: Vec<char>,
43 pos: usize,
44 line: usize,
45 col: usize,
46 depth: usize,
47}
48
49impl<'a> Parser<'a> {
50 fn new(file: &'a str, src: &str) -> Self {
51 Self {
52 file,
53 chars: src.chars().collect(),
54 pos: 0,
55 line: 1,
56 col: 1,
57 depth: 0,
58 }
59 }
60
61 fn err(&self, line: usize, col: usize, message: impl Into<String>) -> SeqError {
62 SeqError::new(self.file, line, col, message)
63 }
64
65 fn peek(&self) -> Option<char> {
66 self.chars.get(self.pos).copied()
67 }
68
69 fn bump(&mut self) -> Option<char> {
70 let c = self.chars.get(self.pos).copied()?;
71 self.pos += 1;
72 if c == '\n' {
73 self.line += 1;
74 self.col = 1;
75 } else {
76 self.col += 1;
77 }
78 Some(c)
79 }
80
81 fn skip_trivia(&mut self) {
82 loop {
83 match self.peek() {
84 Some(c) if c == ' ' || c == '\t' || c == '\r' || c == '\n' => {
85 self.bump();
86 }
87 Some('/') if self.chars.get(self.pos + 1) == Some(&'/') => {
88 while !matches!(self.peek(), None | Some('\n')) {
89 self.bump();
90 }
91 }
92 _ => break,
93 }
94 }
95 }
96
97 fn loc(&mut self) -> (usize, usize) {
98 self.skip_trivia();
99 (self.line, self.col)
100 }
101
102 fn eat(&mut self, c: char) -> bool {
103 self.skip_trivia();
104 if self.peek() == Some(c) {
105 self.bump();
106 true
107 } else {
108 false
109 }
110 }
111
112 fn expect(&mut self, c: char, what: &str) -> Result<(), SeqError> {
113 let (line, col) = self.loc();
114 if self.peek() == Some(c) {
115 self.bump();
116 Ok(())
117 } else {
118 Err(self.err(line, col, format!("oczekiwano {what}")))
119 }
120 }
121
122 fn ident(&mut self) -> Result<(String, usize, usize), SeqError> {
123 let (line, col) = self.loc();
124 let start = self.pos;
125 match self.peek() {
126 Some(c) if c.is_ascii_alphabetic() || c == '_' => {
127 self.bump();
128 }
129 _ => return Err(self.err(line, col, "oczekiwano identyfikatora")),
130 }
131 while matches!(self.peek(), Some(c) if c.is_ascii_alphanumeric() || c == '_') {
132 self.bump();
133 }
134 Ok((self.chars[start..self.pos].iter().collect(), line, col))
135 }
136
137 fn number(&mut self) -> Result<(f32, usize, usize), SeqError> {
138 let (line, col) = self.loc();
139 let start = self.pos;
140 if self.peek() == Some('-') {
141 self.bump();
142 }
143 let mut digits = 0;
144 while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
145 self.bump();
146 digits += 1;
147 }
148 if self.peek() == Some('.') {
149 self.bump();
150 while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
151 self.bump();
152 digits += 1;
153 }
154 }
155 if digits == 0 {
156 return Err(self.err(line, col, "oczekiwano liczby"));
157 }
158 let text: String = self.chars[start..self.pos].iter().collect();
159 text.parse::<f32>()
160 .map(|v| (v, line, col))
161 .map_err(|_| self.err(line, col, format!("bad number '{text}'")))
162 }
163
164 fn string(&mut self) -> Result<(String, usize, usize), SeqError> {
165 let (line, col) = self.loc();
166 if self.peek() != Some('"') {
167 return Err(self.err(line, col, "expected string in quotation marks"));
168 }
169 self.bump();
170 let mut out = String::new();
171 loop {
172 match self.bump() {
173 None => return Err(self.err(line, col, "unclosed string")),
174 Some('"') => break,
175 Some('\\') => match self.bump() {
176 Some('"') => out.push('"'),
177 Some('\\') => out.push('\\'),
178 Some('n') => out.push('\n'),
179 Some('t') => out.push('\t'),
180 Some(c) => {
181 return Err(self.err(self.line, self.col, format!("bad escape '\\{c}'")));
182 }
183 None => return Err(self.err(line, col, "unclosed string")),
184 },
185 Some(c) => out.push(c),
186 }
187 }
188 Ok((out, line, col))
189 }
190
191 fn color(&mut self) -> Result<(String, usize, usize), SeqError> {
192 let (line, col) = self.loc();
193 debug_assert_eq!(self.peek(), Some('#'));
194 self.bump();
195 let start = self.pos;
196 while matches!(self.peek(), Some(c) if c.is_ascii_hexdigit()) {
197 self.bump();
198 }
199 let hex: String = self.chars[start..self.pos].iter().collect();
200 if hex.len() != 6 && hex.len() != 8 {
201 return Err(self.err(line, col, "kolor to #RRGGBB lub #RRGGBBAA"));
202 }
203 Ok((hex, line, col))
204 }
205
206 fn parse_seq_file(&mut self) -> Result<SeqFile, SeqError> {
207 let mut app: Option<SeqApp> = None;
208 let mut components: Vec<ComponentDef> = Vec::new();
209 let mut imports: Vec<ImportDecl> = Vec::new();
210 loop {
211 self.skip_trivia();
212 if self.peek().is_none() {
213 break;
214 }
215 let (kw, line, col) = self.ident()?;
216 match kw.as_str() {
217 "app" => {
218 if app.is_some() {
219 return Err(self.err(line, col, "drugi blok `app` (dozwolony jeden)"));
220 }
221 app = Some(self.app_rest(line, col)?);
222 }
223 "import" => {
224 let (path, _, _) = self.string()?;
225 imports.push(ImportDecl { path, line });
226 }
227 "pub" => {
228 let (kw2, l2, c2) = self.ident()?;
229 if kw2 != "component" {
230 return Err(self.err(l2, c2, "`pub` tylko przed `component`"));
231 }
232 components.push(self.component_rest(line, Visibility::Pub)?);
233 }
234 "component" => {
235 components.push(self.component_rest(line, Visibility::Priv)?);
236 }
237 _ => {
238 return Err(self.err(line, col, "oczekiwano `app`, `component` albo `import`"));
239 }
240 }
241 }
242 if app.is_none() && components.is_empty() && imports.is_empty() {
243 return Err(self.err(
244 1,
245 1,
246 "pusty plik: oczekiwano `app`, `component` albo `import`",
247 ));
248 }
249 Ok(SeqFile {
250 imports,
251 components,
252 app,
253 })
254 }
255
256 fn app_rest(&mut self, line: usize, col: usize) -> Result<SeqApp, SeqError> {
257 let (name, _, _) = self.ident()?;
258 let _ = name;
259 self.expect('{', "'{' po `app Nazwa`")?;
260 let mut app = SeqApp {
261 title: String::new(),
262 size: (0.0, 0.0),
263 theme: ThemeName::Dark,
264 windows: Vec::new(),
265 deferred: Vec::new(),
266 styles: Vec::new(),
267 components: Vec::new(),
268 states: Vec::new(),
269 fns: Vec::new(),
270 imports: Vec::new(),
271 app_line: line,
272 has_title: false,
273 has_size: false,
274 };
275 loop {
276 self.skip_trivia();
277 if self.peek() == Some('}') {
278 self.bump();
279 break;
280 }
281 if self.peek().is_none() {
282 return Err(self.err(self.line, self.col, "unclosed `app` block"));
283 }
284 self.app_item(&mut app)?;
285 }
286 if !app.has_title {
287 return Err(self.err(line, col, "app wymaga `title: \"...\"`"));
288 }
289 if !app.has_size {
290 return Err(self.err(line, col, "app wymaga `size: (W, H)`"));
291 }
292 if app.windows.is_empty() {
293 return Err(self.err(line, col, "app wymaga min. 1 bloku `window`"));
294 }
295 Ok(app)
296 }
297
298 fn component_rest(
299 &mut self,
300 line: usize,
301 visibility: Visibility,
302 ) -> Result<ComponentDef, SeqError> {
303 let (name, _, _) = self.ident()?;
304 self.expect('(', "'(' po nazwie component")?;
305 let mut params = Vec::new();
306 loop {
307 self.skip_trivia();
308 if self.eat(')') {
309 break;
310 }
311 let (pname, pline, _) = self.ident()?;
312 self.expect(':', "':' po nazwie parametru")?;
313 let (pty, _, _) = self.ident()?;
314 params.push(CompParam {
315 name: pname,
316 line: pline,
317 ty: pty,
318 });
319 if !self.eat(',') {
320 self.expect(')', "')' po parametrach `component`")?;
321 break;
322 }
323 }
324 self.expect('{', "'{' after `component` header")?;
325 let mut body = Vec::new();
326 loop {
327 self.skip_trivia();
328 if self.peek() == Some('}') {
329 self.bump();
330 break;
331 }
332 if self.peek().is_none() {
333 return Err(self.err(self.line, self.col, "unclosed `component` block"));
334 }
335 body.push(self.node()?);
336 }
337 if body.is_empty() {
338 return Err(self.err(line, 1, "component requires at least 1 node"));
339 }
340 Ok(ComponentDef {
341 name,
342 line,
343 params,
344 body,
345 visibility,
346 file: self.file.to_string(),
347 })
348 }
349
350 fn app_item(&mut self, app: &mut SeqApp) -> Result<(), SeqError> {
351 let (kw, line, col) = self.ident()?;
352 match kw.as_str() {
353 "title" => {
354 self.expect(':', "':' po `title`")?;
355 let (s, _, _) = self.string()?;
356 app.title = s;
357 app.has_title = true;
358 }
359 "size" => {
360 self.expect(':', "':' po `size`")?;
361 app.size = self.size_tuple()?;
362 app.has_size = true;
363 }
364 "theme" => {
365 self.expect(':', "':' po `theme`")?;
366 app.theme = self.theme_name()?;
367 }
368 "window" => {
369 let w = self.window(line)?;
370 app.windows.push(w);
371 }
372 "prop" => {
373 let (name, _, _) = self.ident()?;
374 self.expect(':', "':' po nazwie prop")?;
375 let (ty, _, _) = self.ident()?;
376 app.deferred.push(DeferredDecl {
377 kind: DeferredKind::Prop,
378 name,
379 line,
380 sig: vec![ty],
381 });
382 }
383 "on" => {
384 let (name, _, _) = self.ident()?;
385 self.expect('(', "'(' po nazwie on")?;
386 let mut sig = Vec::new();
387 loop {
388 self.skip_trivia();
389 if self.eat(')') {
390 break;
391 }
392 let (_, _, _) = self.ident()?;
393 self.expect(':', "':' po nazwie parametru")?;
394 let (ty, _, _) = self.ident()?;
395 sig.push(ty);
396 if !self.eat(',') {
397 self.expect(')', "')' po parametrach `on`")?;
398 break;
399 }
400 }
401 app.deferred.push(DeferredDecl {
402 kind: DeferredKind::On,
403 name,
404 line,
405 sig,
406 });
407 }
408 "state" => {
409 let (name, _, _) = self.ident()?;
410 self.expect(':', "':' po nazwie state")?;
411 let ty = self.fn_type()?;
412 self.expect('=', "'=' po typie state")?;
413 let init = self.state_literal()?;
414 self.eat(';');
415 app.states.push(StateDecl {
416 name,
417 line,
418 ty,
419 init,
420 });
421 }
422 "fn" => {
423 let f = self.fn_decl(line)?;
424 app.fns.push(f);
425 }
426 "style" => {
427 let (name, _, _) = self.ident()?;
428 self.expect(':', "':' po nazwie stylu")?;
429 let (target, _, _) = self.ident()?;
430 let mut base = None;
431 let (save_pos, save_line, save_col) = (self.pos, self.line, self.col);
432 if let Ok((w, _, _)) = self.ident() {
433 if w == "extends" {
434 let (b, _, _) = self.ident()?;
435 base = Some(b);
436 } else {
437 (self.pos, self.line, self.col) = (save_pos, save_line, save_col);
438 }
439 } else {
440 (self.pos, self.line, self.col) = (save_pos, save_line, save_col);
441 }
442 self.expect('{', "'{' po `style Nazwa: Typ`")?;
443 let args = self.style_args()?;
444 self.expect('}', "'}' po polach stylu")?;
445 app.styles.push(StyleDecl {
446 name,
447 line,
448 target,
449 base,
450 args,
451 });
452 }
453 "component" => {
454 return Err(self.err(line, col, "blok component poza `app` (definiuj obok `app`)"));
455 }
456 "import" => {
457 return Err(self.err(
458 line,
459 col,
460 "`import` tylko na poziomie pliku (poza blokiem `app`)",
461 ));
462 }
463 "pub" => {
464 return Err(self.err(
465 line,
466 col,
467 "`pub` tylko przed `component` (poza blokiem `app`)",
468 ));
469 }
470 _ => {
471 return Err(self.err(
472 line,
473 col,
474 format!(
475 "nieznany element app '{kw}' (title/size/theme/window/prop/on/state/fn/style)"
476 ),
477 ));
478 }
479 }
480 Ok(())
481 }
482
483 fn state_literal(&mut self) -> Result<SeqExpr, SeqError> {
484 self.skip_trivia();
485 let (line, col) = (self.line, self.col);
486 match self.peek() {
487 Some('"') => {
488 let (s, _, _) = self.string()?;
489 Ok(SeqExpr {
490 line,
491 kind: SeqExprKind::Str(s),
492 })
493 }
494 Some(c) if c == '-' || c.is_ascii_digit() => {
495 let (n, int, _, _) = self.number_expr()?;
496 Ok(SeqExpr {
497 line,
498 kind: if int {
499 SeqExprKind::Int(n as i64)
500 } else {
501 SeqExprKind::Float(n)
502 },
503 })
504 }
505 _ => {
506 let (id, _, _) = self.ident()?;
507 match id.as_str() {
508 "true" => Ok(SeqExpr {
509 line,
510 kind: SeqExprKind::Bool(true),
511 }),
512 "false" => Ok(SeqExpr {
513 line,
514 kind: SeqExprKind::Bool(false),
515 }),
516 "None" => Ok(SeqExpr {
517 line,
518 kind: SeqExprKind::Var("None".to_string()),
519 }),
520 other => Err(self.err(
521 line,
522 col,
523 format!(
524 "state '{other}': initial value is literal (number/string/true/false)"
525 ),
526 )),
527 }
528 }
529 }
530 }
531
532 fn fn_decl(&mut self, line: usize) -> Result<SeqFn, SeqError> {
533 let (name, _, _) = self.ident()?;
534 self.expect('(', "'(' po nazwie funkcji")?;
535 let mut params = Vec::new();
536 loop {
537 self.skip_trivia();
538 if self.eat(')') {
539 break;
540 }
541 let mut mutable = false;
542 let (first, first_line, _) = self.ident()?;
543 let pname;
544 let pline;
545 if first == "mut" {
546 mutable = true;
547 let (n, l, _) = self.ident()?;
548 pname = n;
549 pline = l;
550 } else {
551 pname = first;
552 pline = first_line;
553 }
554 self.expect(':', "':' po nazwie parametru funkcji")?;
555 let ty = self.fn_type()?;
556 params.push(FnParam {
557 name: pname,
558 mutable,
559 line: pline,
560 ty,
561 });
562 if !self.eat(',') {
563 self.expect(')', "')' po parametrach funkcji")?;
564 break;
565 }
566 }
567 let mut ret = None;
568 if self.eat_arrow() {
569 ret = Some(self.fn_type()?);
570 }
571 let body = self.fn_block("funkcji")?;
572 Ok(SeqFn {
573 name,
574 line,
575 params,
576 ret,
577 body,
578 })
579 }
580
581 fn fn_type(&mut self) -> Result<String, SeqError> {
582 self.skip_trivia();
583 if self.peek() == Some('O') {
584 let save = (self.pos, self.line, self.col);
585 if let Ok((id, _, _)) = self.ident()
586 && id == "Option"
587 {
588 self.skip_trivia();
589 if self.eat('<') {
590 let inner = self.fn_type()?;
591 self.skip_trivia();
592 self.expect('>', "'>' po typie Option")?;
593 return Ok(format!("Option<{}>", inner));
594 }
595 } else {
596 (self.pos, self.line, self.col) = save;
597 }
598 (self.pos, self.line, self.col) = save;
599 }
600 if self.eat('(') {
601 let mut parts = vec![self.fn_type()?];
602 while self.eat(',') {
603 parts.push(self.fn_type()?);
604 }
605 self.expect(')', "')' po typie krotki")?;
606 Ok(format!("({})", parts.join(",")))
607 } else {
608 let (id, _, _) = self.ident()?;
609 Ok(id)
610 }
611 }
612
613 fn eat_arrow(&mut self) -> bool {
614 let save = (self.pos, self.line, self.col);
615 self.skip_trivia();
616 if self.peek() == Some('-') && self.chars.get(self.pos + 1) == Some(&'>') {
617 self.bump();
618 self.bump();
619 true
620 } else {
621 (self.pos, self.line, self.col) = save;
622 false
623 }
624 }
625
626 fn fn_block(&mut self, what: &str) -> Result<Vec<SeqStmt>, SeqError> {
627 self.depth += 1;
628 if self.depth > MAX_NESTING_DEPTH {
629 self.depth -= 1;
630 return Err(self.err(
631 self.line,
632 self.col,
633 format!("nesting too deep (limit {MAX_NESTING_DEPTH} levels)"),
634 ));
635 }
636 let result = self.fn_block_inner(what);
637 self.depth -= 1;
638 result
639 }
640
641 fn fn_block_inner(&mut self, what: &str) -> Result<Vec<SeqStmt>, SeqError> {
642 self.expect('{', format!("'{{' w ciele {what}").as_str())?;
643 let mut out = Vec::new();
644 loop {
645 self.skip_trivia();
646 if self.peek() == Some('}') {
647 self.bump();
648 break;
649 }
650 if self.peek().is_none() {
651 return Err(self.err(self.line, self.col, format!("unclosed block {what}")));
652 }
653 let stmt = self.fn_stmt()?;
654 if let Some(stmt) = stmt {
655 out.push(stmt);
656 }
657 }
658 Ok(out)
659 }
660
661 fn fn_stmt(&mut self) -> Result<Option<SeqStmt>, SeqError> {
662 self.skip_trivia();
663 if self.eat(';') {
664 return Ok(None);
665 }
666 let (kw, line, col) = self.ident()?;
667 match kw.as_str() {
668 "let" | "mut" => {
669 let (name, _, _) = self.ident()?;
670 self.expect('=', "'=' po nazwie zmiennej")?;
671 let value = self.fn_expr()?;
672 self.expect(';', "';' po `let`/`mut`")?;
673 Ok(Some(SeqStmt::Let {
674 name,
675 mutable: kw == "mut",
676 value,
677 line,
678 }))
679 }
680 "if" => Ok(Some(self.if_rest(line)?)),
681 "for" => {
682 let (var, _, _) = self.ident()?;
683 let (in_kw, l2, c2) = self.ident()?;
684 if in_kw != "in" {
685 return Err(self.err(l2, c2, "'in' after loop variable `for x in rows`"));
686 }
687 let (source, _, _) = self.ident()?;
688 let body = self.fn_block("for loop")?;
689 Ok(Some(SeqStmt::For {
690 var,
691 source,
692 body,
693 line,
694 }))
695 }
696 "match" => self.match_rest(line),
697 "return" => {
698 self.skip_trivia();
699 let value = if self.peek() == Some(';') {
700 None
701 } else {
702 Some(self.fn_expr()?)
703 };
704 self.expect(';', "';' po `return`")?;
705 Ok(Some(SeqStmt::Return { value, line }))
706 }
707 _ => {
708 if self.eat_eq() {
709 let value = self.fn_expr()?;
710 self.expect(';', "';' po przypisaniu")?;
711 return Ok(Some(SeqStmt::Assign {
712 name: kw,
713 value,
714 line,
715 }));
716 }
717 let base = SeqExpr {
718 line,
719 kind: SeqExprKind::Var(kw),
720 };
721 let expr = self.fn_postfix(base)?;
722 if matches!(expr.kind, SeqExprKind::Var(_) | SeqExprKind::Field { .. }) {
723 return Err(self.err(
724 line,
725 col,
726 "an expression as a statement is a function call (e.g. `connect();`)",
727 ));
728 }
729 self.expect(';', "';' po instrukcji")?;
730 Ok(Some(SeqStmt::Expr(expr)))
731 }
732 }
733 }
734
735 fn if_rest(&mut self, line: usize) -> Result<SeqStmt, SeqError> {
736 self.expect('(', "'(' po `if`")?;
737 let cond = self.fn_expr()?;
738 self.expect(')', "')' po warunku `if`")?;
739 let then = self.fn_block("branch `if`")?;
740 let mut elifs = Vec::new();
741 let mut els = None;
742 loop {
743 if !self.peek_keyword("else") {
744 break;
745 }
746 let _ = self.ident();
747 if self.peek_keyword("if") {
748 let _ = self.ident();
749 self.expect('(', "'(' po `else if`")?;
750 let cond = self.fn_expr()?;
751 self.expect(')', "')' po warunku `else if`")?;
752 let body = self.fn_block("branch `else if`")?;
753 elifs.push((cond, body));
754 } else {
755 els = Some(self.fn_block("branch `else`")?);
756 break;
757 }
758 }
759 Ok(SeqStmt::If {
760 cond,
761 then,
762 elifs,
763 els,
764 line,
765 })
766 }
767
768 fn match_rest(&mut self, line: usize) -> Result<Option<SeqStmt>, SeqError> {
769 let value = self.fn_expr()?;
770 self.expect('{', "'{' after `match`")?;
771 let mut arms = Vec::new();
772 loop {
773 self.skip_trivia();
774 if self.peek() == Some('}') {
775 self.bump();
776 break;
777 }
778 if self.peek().is_none() {
779 return Err(self.err(self.line, self.col, "unclosed `match` block"));
780 }
781 let (aline, acol) = (self.line, self.col);
782 let pattern = match self.peek() {
783 Some('"') => MatchPat::Str(self.string()?.0),
784 Some(c) if c == '-' || c.is_ascii_digit() => {
785 let (n, int, _, _) = self.number_expr()?;
786 if !int {
787 return Err(self.err(aline, acol, "match pattern is integer"));
788 }
789 #[allow(clippy::cast_possible_truncation)]
790 MatchPat::Int(n as i64)
791 }
792 _ => {
793 let (id, _, _) = self.ident()?;
794 match id.as_str() {
795 "true" => MatchPat::Bool(true),
796 "false" => MatchPat::Bool(false),
797 "_" => MatchPat::Wildcard,
798 other => {
799 return Err(self.err(
800 aline,
801 acol,
802 format!(
803 "wzorzec match to \"tekst\"/liczba/true/false/_, nie '{other}'"
804 ),
805 ));
806 }
807 }
808 }
809 };
810 self.expect('=', "'=' we wzorcu match (`wzorzec => { ... }`)")?;
811 self.expect('>', "'>' we wzorcu match (`wzorzec => { ... }`)")?;
812 let body = self.fn_block("branch `match`")?;
813 arms.push(SeqMatchArm {
814 pattern,
815 body,
816 line: aline,
817 });
818 self.eat(',');
819 }
820 Ok(Some(SeqStmt::Match { value, arms, line }))
821 }
822
823 fn eat_eq(&mut self) -> bool {
824 let save = (self.pos, self.line, self.col);
825 self.skip_trivia();
826 if self.peek() == Some('=') && self.chars.get(self.pos + 1) != Some(&'=') {
827 self.bump();
828 true
829 } else {
830 (self.pos, self.line, self.col) = save;
831 false
832 }
833 }
834
835 fn peek_keyword(&mut self, kw: &str) -> bool {
836 let save = (self.pos, self.line, self.col);
837 let ok = matches!(self.ident(), Ok((w, _, _)) if w == kw);
838 (self.pos, self.line, self.col) = save;
839 ok
840 }
841
842 fn number_expr(&mut self) -> Result<(f64, bool, usize, usize), SeqError> {
843 let (line, col) = self.loc();
844 let start = self.pos;
845 if self.peek() == Some('-') {
846 self.bump();
847 }
848 let mut digits = 0;
849 while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
850 self.bump();
851 digits += 1;
852 }
853 let mut int = true;
854 if self.peek() == Some('.') {
855 int = false;
856 self.bump();
857 while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
858 self.bump();
859 digits += 1;
860 }
861 }
862 if digits == 0 {
863 return Err(self.err(line, col, "oczekiwano liczby"));
864 }
865 let text: String = self.chars[start..self.pos].iter().collect();
866 text.parse::<f64>()
867 .map(|v| (v, int, line, col))
868 .map_err(|_| self.err(line, col, format!("bad number '{text}'")))
869 }
870
871 fn peek_paren_trivia(&mut self) -> bool {
872 self.skip_trivia();
873 self.peek() == Some('(')
874 }
875
876 fn fn_or(&mut self) -> Result<SeqExpr, SeqError> {
877 let mut lhs = self.fn_and()?;
878 loop {
879 if !self.eat_op("||") {
880 break;
881 }
882 let line = self.line;
883 let rhs = self.fn_and()?;
884 lhs = SeqExpr {
885 line,
886 kind: SeqExprKind::Binary {
887 op: BinOp::Or,
888 lhs: Box::new(lhs),
889 rhs: Box::new(rhs),
890 },
891 };
892 }
893 Ok(lhs)
894 }
895
896 fn fn_and(&mut self) -> Result<SeqExpr, SeqError> {
897 let mut lhs = self.fn_eq()?;
898 loop {
899 if !self.eat_op("&&") {
900 break;
901 }
902 let line = self.line;
903 let rhs = self.fn_eq()?;
904 lhs = SeqExpr {
905 line,
906 kind: SeqExprKind::Binary {
907 op: BinOp::And,
908 lhs: Box::new(lhs),
909 rhs: Box::new(rhs),
910 },
911 };
912 }
913 Ok(lhs)
914 }
915
916 fn fn_eq(&mut self) -> Result<SeqExpr, SeqError> {
917 let mut lhs = self.fn_cmp()?;
918 loop {
919 let op = if self.eat_op("==") {
920 BinOp::Eq
921 } else if self.eat_op("!=") {
922 BinOp::Ne
923 } else {
924 break;
925 };
926 let line = self.line;
927 let rhs = self.fn_cmp()?;
928 lhs = SeqExpr {
929 line,
930 kind: SeqExprKind::Binary {
931 op,
932 lhs: Box::new(lhs),
933 rhs: Box::new(rhs),
934 },
935 };
936 }
937 Ok(lhs)
938 }
939
940 fn fn_cmp(&mut self) -> Result<SeqExpr, SeqError> {
941 let mut lhs = self.fn_add()?;
942 loop {
943 let op = if self.eat_op("<=") {
944 BinOp::Le
945 } else if self.eat_op(">=") {
946 BinOp::Ge
947 } else if self.eat_op("<") {
948 BinOp::Lt
949 } else if self.eat_op(">") {
950 BinOp::Gt
951 } else {
952 break;
953 };
954 let line = self.line;
955 let rhs = self.fn_add()?;
956 lhs = SeqExpr {
957 line,
958 kind: SeqExprKind::Binary {
959 op,
960 lhs: Box::new(lhs),
961 rhs: Box::new(rhs),
962 },
963 };
964 }
965 Ok(lhs)
966 }
967
968 fn fn_add(&mut self) -> Result<SeqExpr, SeqError> {
969 let mut lhs = self.fn_mul()?;
970 loop {
971 let op = if self.eat_op("+") {
972 BinOp::Add
973 } else if self.eat_op("-") {
974 BinOp::Sub
975 } else {
976 break;
977 };
978 let line = self.line;
979 let rhs = self.fn_mul()?;
980 lhs = SeqExpr {
981 line,
982 kind: SeqExprKind::Binary {
983 op,
984 lhs: Box::new(lhs),
985 rhs: Box::new(rhs),
986 },
987 };
988 }
989 Ok(lhs)
990 }
991
992 fn fn_mul(&mut self) -> Result<SeqExpr, SeqError> {
993 let mut lhs = self.fn_unary()?;
994 loop {
995 let op = if self.eat_op("*") {
996 BinOp::Mul
997 } else if self.eat_op("/") {
998 BinOp::Div
999 } else if self.eat_op("%") {
1000 BinOp::Rem
1001 } else {
1002 break;
1003 };
1004 let line = self.line;
1005 let rhs = self.fn_unary()?;
1006 lhs = SeqExpr {
1007 line,
1008 kind: SeqExprKind::Binary {
1009 op,
1010 lhs: Box::new(lhs),
1011 rhs: Box::new(rhs),
1012 },
1013 };
1014 }
1015 Ok(lhs)
1016 }
1017
1018 fn fn_unary(&mut self) -> Result<SeqExpr, SeqError> {
1019 self.skip_trivia();
1020 let (line, _) = (self.line, self.col);
1021 if self.eat_op("!") {
1022 let expr = self.fn_unary()?;
1023 return Ok(SeqExpr {
1024 line,
1025 kind: SeqExprKind::Unary {
1026 op: UnOp::Not,
1027 expr: Box::new(expr),
1028 },
1029 });
1030 }
1031 if self.eat_op("-") {
1032 let expr = self.fn_unary()?;
1033 return Ok(SeqExpr {
1034 line,
1035 kind: SeqExprKind::Unary {
1036 op: UnOp::Neg,
1037 expr: Box::new(expr),
1038 },
1039 });
1040 }
1041 let primary = self.fn_primary()?;
1042 self.fn_postfix(primary)
1043 }
1044
1045 fn fn_postfix(&mut self, mut base: SeqExpr) -> Result<SeqExpr, SeqError> {
1046 loop {
1047 if self.eat('.') {
1048 self.skip_trivia();
1049 let (name, nline) = if matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
1050 let nline = self.line;
1051 let start = self.pos;
1052 while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
1053 self.bump();
1054 }
1055 (
1056 self.chars[start..self.pos].iter().collect::<String>(),
1057 nline,
1058 )
1059 } else {
1060 let (name, line, _) = self.ident()?;
1061 (name, line)
1062 };
1063 if self.peek_paren_trivia() {
1064 self.expect('(', "'(' po metodzie")?;
1065 let args = self.fn_call_args()?;
1066 let mut all = vec![base];
1067 all.extend(args);
1068 base = SeqExpr {
1069 line: nline,
1070 kind: SeqExprKind::Call { name, args: all },
1071 };
1072 } else {
1073 let SeqExprKind::Var(var) = base.kind else {
1074 return Err(self.err(
1075 nline,
1076 self.col,
1077 "field only on loop variable (e.g. `x.id`)",
1078 ));
1079 };
1080 base = SeqExpr {
1081 line: nline,
1082 kind: SeqExprKind::Field {
1083 base: var,
1084 field: name,
1085 },
1086 };
1087 }
1088 } else if self.peek_paren_trivia() {
1089 self.skip_trivia();
1090 let line = self.line;
1091 self.expect('(', "'(' po nazwie funkcji")?;
1092 let args = self.fn_call_args()?;
1093 let SeqExprKind::Var(name) = base.kind else {
1094 return Err(self.err(line, self.col, "you can call a function by name"));
1095 };
1096 base = SeqExpr {
1097 line,
1098 kind: SeqExprKind::Call { name, args },
1099 };
1100 } else {
1101 break;
1102 }
1103 }
1104 Ok(base)
1105 }
1106
1107 fn fn_call_args(&mut self) -> Result<Vec<SeqExpr>, SeqError> {
1108 let mut args = Vec::new();
1109 self.skip_trivia();
1110 if self.eat(')') {
1111 return Ok(args);
1112 }
1113 args.push(self.fn_expr()?);
1114 loop {
1115 if !self.eat(',') {
1116 break;
1117 }
1118 self.skip_trivia();
1119 if self.eat(')') {
1120 return Ok(args);
1121 }
1122 args.push(self.fn_expr()?);
1123 }
1124 self.expect(')', "')' after call arguments")?;
1125 Ok(args)
1126 }
1127
1128 fn fn_primary(&mut self) -> Result<SeqExpr, SeqError> {
1129 self.depth += 1;
1130 if self.depth > MAX_NESTING_DEPTH {
1131 self.depth -= 1;
1132 return Err(self.err(
1133 self.line,
1134 self.col,
1135 format!("nesting too deep (limit {MAX_NESTING_DEPTH} levels)"),
1136 ));
1137 }
1138 let result = self.fn_primary_inner();
1139 self.depth -= 1;
1140 result
1141 }
1142
1143 fn fn_primary_inner(&mut self) -> Result<SeqExpr, SeqError> {
1144 self.skip_trivia();
1145 let (line, col) = (self.line, self.col);
1146 match self.peek() {
1147 Some('"') => {
1148 let (s, _, _) = self.string()?;
1149 Ok(SeqExpr {
1150 line,
1151 kind: SeqExprKind::Str(s),
1152 })
1153 }
1154 Some(c) if c.is_ascii_digit() => {
1155 let (n, int, _, _) = self.number_expr()?;
1156 Ok(SeqExpr {
1157 line,
1158 kind: if int {
1159 #[allow(clippy::cast_possible_truncation)]
1160 SeqExprKind::Int(n as i64)
1161 } else {
1162 SeqExprKind::Float(n)
1163 },
1164 })
1165 }
1166 Some('(') => {
1167 self.bump();
1168 let first = self.fn_expr()?;
1169 self.skip_trivia();
1170 if self.eat(',') {
1171 let mut items = vec![first];
1172 loop {
1173 self.skip_trivia();
1174 if self.eat(')') {
1175 break;
1176 }
1177 items.push(self.fn_expr()?);
1178 if !self.eat(',') {
1179 self.expect(')', "')' po krotce `(a, b)`")?;
1180 break;
1181 }
1182 }
1183 Ok(SeqExpr {
1184 line,
1185 kind: SeqExprKind::Tuple(items),
1186 })
1187 } else {
1188 self.expect(')', "')' after the expression in brackets")?;
1189 Ok(first)
1190 }
1191 }
1192 Some('[') => {
1193 self.bump();
1194 let mut items = Vec::new();
1195 self.skip_trivia();
1196 if !self.eat(']') {
1197 loop {
1198 items.push(self.fn_expr()?);
1199 self.skip_trivia();
1200 if self.eat(']') {
1201 break;
1202 }
1203 self.expect(',', "',' or ']' in list `[a, b]`")?;
1204 self.skip_trivia();
1205 if self.eat(']') {
1206 break;
1207 }
1208 }
1209 }
1210 Ok(SeqExpr {
1211 line,
1212 kind: SeqExprKind::Array(items),
1213 })
1214 }
1215 Some('_') => Err(self.err(line, col, "`_` only as `match` pattern")),
1216 _ => {
1217 let (id, _, _) = self.ident()?;
1218 Ok(SeqExpr {
1219 line,
1220 kind: match id.as_str() {
1221 "true" => SeqExprKind::Bool(true),
1222 "false" => SeqExprKind::Bool(false),
1223 _ => SeqExprKind::Var(id),
1224 },
1225 })
1226 }
1227 }
1228 }
1229
1230 fn eat_op(&mut self, s: &str) -> bool {
1231 self.skip_trivia();
1232 for (i, c) in s.chars().enumerate() {
1233 if self.chars.get(self.pos + i) != Some(&c) {
1234 return false;
1235 }
1236 }
1237 for _ in s.chars() {
1238 self.bump();
1239 }
1240 true
1241 }
1242
1243 fn fn_expr(&mut self) -> Result<SeqExpr, SeqError> {
1244 self.fn_ternary()
1245 }
1246
1247 fn fn_ternary(&mut self) -> Result<SeqExpr, SeqError> {
1248 let cond = self.fn_or()?;
1249 if !self.eat_op("?") {
1250 return Ok(cond);
1251 }
1252 let line = self.line;
1253 let then = self.fn_expr()?;
1254 self.expect(':', "':' in conditional expression `condition ? a : b`")?;
1255 let els = self.fn_ternary()?;
1256 Ok(SeqExpr {
1257 line,
1258 kind: SeqExprKind::Ternary {
1259 cond: Box::new(cond),
1260 then: Box::new(then),
1261 els: Box::new(els),
1262 },
1263 })
1264 }
1265
1266 fn theme_name(&mut self) -> Result<ThemeName, SeqError> {
1267 let (line, col) = self.loc();
1268 match self.peek() {
1269 Some('"') => {
1270 let (s, _, _) = self.string()?;
1271 match s.as_str() {
1272 "dark" => Ok(ThemeName::Dark),
1273 "light" => Ok(ThemeName::Light),
1274 _ => Ok(ThemeName::File(s)),
1275 }
1276 }
1277 _ => {
1278 let (id, _, _) = self.ident()?;
1279 match id.as_str() {
1280 "dark" => Ok(ThemeName::Dark),
1281 "light" => Ok(ThemeName::Light),
1282 _ => Err(self.err(line, col, "theme to dark/light albo \"plik-tokens.json\"")),
1283 }
1284 }
1285 }
1286 }
1287
1288 fn size_tuple(&mut self) -> Result<(f32, f32), SeqError> {
1289 self.expect('(', "'(' przed rozmiarem")?;
1290 let (w, _, _) = self.number()?;
1291 self.expect(',', "',' between W and H")?;
1292 let (h, _, _) = self.number()?;
1293 self.expect(')', "')' po rozmiarze")?;
1294 if !(w.is_finite() && h.is_finite() && w > 0.0 && h > 0.0) {
1295 let (l, c) = (self.line, self.col);
1296 return Err(self.err(l, c, "size must be positive and finite"));
1297 }
1298 Ok((w, h))
1299 }
1300
1301 fn style_args(&mut self) -> Result<Vec<SeqArg>, SeqError> {
1302 let mut args = Vec::new();
1303 loop {
1304 self.skip_trivia();
1305 if self.peek() == Some('}') {
1306 break;
1307 }
1308 if self.peek().is_none() {
1309 return Err(self.err(self.line, self.col, "unclosed `style` block"));
1310 }
1311 let (name, line, _) = self.ident()?;
1312 self.expect(':', format!("':' po polu stylu '{name}'").as_str())?;
1313 let value = self.value()?;
1314 args.push(SeqArg { name, line, value });
1315
1316 self.eat(',');
1317 }
1318 Ok(args)
1319 }
1320
1321 fn window(&mut self, line: usize) -> Result<SeqWindow, SeqError> {
1322 let (name, _, _) = self.ident()?;
1323 let mut size = None;
1324 if self.eat('(') {
1325 let (kw, l, c) = self.ident()?;
1326 if kw != "size" {
1327 return Err(self.err(l, c, "w nawiasie window dozwolone tylko `size: (W, H)`"));
1328 }
1329 self.expect(':', "':' po `size`")?;
1330 size = Some(self.size_tuple()?);
1331 self.expect(')', "')' po `window Nazwa (...)`")?;
1332 }
1333 self.expect('{', "'{' after `window` header")?;
1334 let mut nodes = Vec::new();
1335 loop {
1336 self.skip_trivia();
1337 if self.peek() == Some('}') {
1338 self.bump();
1339 break;
1340 }
1341 if self.peek().is_none() {
1342 return Err(self.err(self.line, self.col, "unclosed `window` block"));
1343 }
1344 nodes.push(self.node()?);
1345 }
1346 Ok(SeqWindow {
1347 name,
1348 line,
1349 size,
1350 nodes,
1351 })
1352 }
1353
1354 fn node(&mut self) -> Result<SeqNode, SeqError> {
1355 self.depth += 1;
1356 if self.depth > MAX_NESTING_DEPTH {
1357 self.depth -= 1;
1358 return Err(self.err(
1359 self.line,
1360 self.col,
1361 format!("nesting too deep (limit {MAX_NESTING_DEPTH} levels)"),
1362 ));
1363 }
1364 let result = self.node_inner();
1365 self.depth -= 1;
1366 result
1367 }
1368
1369 fn node_inner(&mut self) -> Result<SeqNode, SeqError> {
1370 let (kind, line, _) = self.ident()?;
1371 let mut label = None;
1372 let mut args = Vec::new();
1373
1374 if self.eat('(') {
1375 self.skip_trivia();
1376 if self.peek() == Some('"') {
1377 let (s, _, _) = self.string()?;
1378 label = Some(s);
1379 self.skip_trivia();
1380 if self.eat(',') {
1381 self.skip_trivia();
1382 if self.peek() != Some(')') {
1383 args = self.named_args()?;
1384 }
1385 }
1386 } else if self.peek() != Some(')') {
1387 args = self.named_args()?;
1388 }
1389 self.expect(')', "')' po atrybutach")?;
1390 }
1391 let mut children = Vec::new();
1392 if self.eat('{') {
1393 loop {
1394 self.skip_trivia();
1395 if self.peek() == Some('}') {
1396 self.bump();
1397 break;
1398 }
1399 if self.peek().is_none() {
1400 return Err(self.err(self.line, self.col, "unclosed children block `{ }`"));
1401 }
1402 children.push(self.node()?);
1403 }
1404 }
1405 Ok(SeqNode {
1406 kind,
1407 line,
1408 label,
1409 args,
1410 children,
1411 })
1412 }
1413
1414 fn named_args(&mut self) -> Result<Vec<SeqArg>, SeqError> {
1415 let mut args = Vec::new();
1416 loop {
1417 let (name, line, _) = self.ident()?;
1418 self.expect(':', format!("':' po atrybucie '{name}'").as_str())?;
1419 let value = self.value()?;
1420 args.push(SeqArg { name, line, value });
1421 if !self.eat(',') {
1422 break;
1423 }
1424 self.skip_trivia();
1425 if self.peek() == Some(')') {
1426 break;
1427 }
1428 }
1429 Ok(args)
1430 }
1431
1432 fn peek_paren(&self) -> bool {
1433 let mut i = self.pos;
1434 while let Some(&c) = self.chars.get(i) {
1435 if c == ' ' || c == '\t' || c == '\r' || c == '\n' {
1436 i += 1;
1437 } else {
1438 return c == '(';
1439 }
1440 }
1441 false
1442 }
1443
1444 fn value(&mut self) -> Result<SeqValue, SeqError> {
1445 self.depth += 1;
1446 if self.depth > MAX_NESTING_DEPTH {
1447 self.depth -= 1;
1448 return Err(self.err(
1449 self.line,
1450 self.col,
1451 format!("nesting too deep (limit {MAX_NESTING_DEPTH} levels)"),
1452 ));
1453 }
1454 let result = self.value_inner();
1455 self.depth -= 1;
1456 result.map(SeqValue::fold_exprs)
1457 }
1458
1459 fn value_inner(&mut self) -> Result<SeqValue, SeqError> {
1460 self.skip_trivia();
1461 match self.peek() {
1462 Some('#') => {
1463 let (hex, _, _) = self.color()?;
1464 return Ok(SeqValue::Color(hex));
1465 }
1466 Some('{') => return self.callback(),
1467 _ => {}
1468 }
1469 let save = (self.pos, self.line, self.col);
1470 let starts_paren = self.peek() == Some('(');
1471 if let Ok(expr) = self.fn_expr()
1472 && self.value_end()
1473 {
1474 let expr = if starts_paren && is_single_value_expr(&expr.kind) {
1475 SeqExpr {
1476 line: expr.line,
1477 kind: SeqExprKind::Tuple(vec![expr]),
1478 }
1479 } else {
1480 expr
1481 };
1482 return Ok(SeqValue::Expr(expr));
1483 }
1484 (self.pos, self.line, self.col) = save;
1485 self.value_literal()
1486 }
1487
1488 fn value_end(&mut self) -> bool {
1489 self.skip_trivia();
1490 matches!(
1491 self.peek(),
1492 None | Some(',') | Some(')') | Some(']') | Some('}')
1493 )
1494 }
1495
1496 fn value_literal(&mut self) -> Result<SeqValue, SeqError> {
1497 self.skip_trivia();
1498 Ok(match self.peek() {
1499 Some('"') => {
1500 let (s, _, _) = self.string()?;
1501 SeqValue::Str(s)
1502 }
1503 Some(c) if c == '-' || c.is_ascii_digit() => {
1504 let (n, _, _) = self.number()?;
1505 SeqValue::Num(n)
1506 }
1507 Some('#') => {
1508 let (hex, _, _) = self.color()?;
1509 SeqValue::Color(hex)
1510 }
1511 Some('{') => return self.callback(),
1512 Some('(') => {
1513 self.bump();
1514 let mut items = vec![self.value()?];
1515 while self.eat(',') {
1516 self.skip_trivia();
1517 if self.peek() == Some(')') {
1518 break;
1519 }
1520 items.push(self.value()?);
1521 }
1522 self.expect(')', "')' po krotce `(a, b)`")?;
1523 SeqValue::Tuple(items)
1524 }
1525 Some('[') => {
1526 self.bump();
1527 let mut items = vec![self.value()?];
1528 while self.eat(',') {
1529 self.skip_trivia();
1530 if self.peek() == Some(']') {
1531 break;
1532 }
1533 items.push(self.value()?);
1534 }
1535 self.expect(']', "']' after list `[a, b]`")?;
1536 SeqValue::Array(items)
1537 }
1538 _ => {
1539 let (id, _, _) = self.ident()?;
1540 match id.as_str() {
1541 "true" => SeqValue::Bool(true),
1542 "false" => SeqValue::Bool(false),
1543 "fit" => SeqValue::Length(LengthVal::Fit),
1544
1545 "fill" if self.peek_paren() => {
1546 return self.length_paren(LengthVal::Fill, "fill(waga)");
1547 }
1548 "px" if self.peek_paren() => {
1549 return self.length_paren(LengthVal::Px, "px(liczba)");
1550 }
1551 "percent" if self.peek_paren() => {
1552 return self.length_paren(LengthVal::Percent, "percent(liczba)");
1553 }
1554 "dynamic" => {
1555 self.expect('(', "'(' po `dynamic`")?;
1556 let (name, _, _) = self.ident()?;
1557 self.expect(')', "')' po `dynamic(nazwa)`")?;
1558 SeqValue::Dynamic(name)
1559 }
1560 "theme" => {
1561 self.expect('.', "'.' po `theme` (theme.pole)")?;
1562 let (field, _, _) = self.ident()?;
1563 SeqValue::Theme(field)
1564 }
1565 "env" => {
1566 self.expect('.', "'.' po `env` (env.nazwa)")?;
1567 let (field, _, _) = self.ident()?;
1568 SeqValue::Env(field)
1569 }
1570 "item" => {
1571 self.expect('.', "'.' po `item` (item.pole)")?;
1572 let (field, _, _) = self.ident()?;
1573 SeqValue::ItemField(field)
1574 }
1575 _ => SeqValue::Ident(id),
1576 }
1577 }
1578 })
1579 }
1580
1581 fn length_paren(&mut self, f: fn(f32) -> LengthVal, what: &str) -> Result<SeqValue, SeqError> {
1582 self.expect('(', format!("'(' — {what}").as_str())?;
1583 let (n, _, _) = self.number()?;
1584 self.expect(')', format!("')' — {what}").as_str())?;
1585 Ok(SeqValue::Length(f(n)))
1586 }
1587
1588 fn callback(&mut self) -> Result<SeqValue, SeqError> {
1589 debug_assert_eq!(self.peek(), Some('{'));
1590 self.bump();
1591 self.skip_trivia();
1592 let (action, _, _) = self.ident()?;
1593 self.expect('(', "'(' po nazwie callbacku")?;
1594 let mut args = Vec::new();
1595 self.skip_trivia();
1596 if self.peek() != Some(')') {
1597 args.push(self.value()?);
1598 while self.eat(',') {
1599 self.skip_trivia();
1600 if self.peek() == Some(')') {
1601 break;
1602 }
1603 args.push(self.value()?);
1604 }
1605 }
1606 self.expect(')', "')' po argumencie callbacku")?;
1607 self.skip_trivia();
1608 if self.peek() == Some('}') {
1609 self.bump();
1610 } else {
1611 let (l, c) = (self.line, self.col);
1612 return Err(self.err(l, c, "'}' po callbacku `{ akcja() }`"));
1613 }
1614 Ok(SeqValue::Callback { action, args })
1615 }
1616}