1use crate::lex::{StrPart, Token};
4use crate::path;
5use alloc::{boxed::Box, vec::Vec};
6
7pub type Error<S, T = S> = (Expect<S>, T);
9pub type TError<'t, S> = Error<S, Option<&'t Token<S>>>;
11
12type Path<T> = Vec<(path::Part<T>, path::Opt)>;
13
14#[derive(Debug)]
18pub enum Expect<S> {
19 Keyword(S),
21 Char(S),
23 Var,
25 ElseOrEnd,
27 CommaOrRBrace,
29 SemicolonOrRParen,
31 Term,
33 Key,
35 Ident,
37 Arg,
39 Str,
41 Nothing,
43}
44
45impl<'a> Expect<&'a str> {
46 pub fn as_str(&self) -> &'a str {
48 match self {
49 Self::Keyword(s) | Self::Char(s) => s,
50 Self::Var => "variable",
51 Self::ElseOrEnd => "else or end",
52 Self::CommaOrRBrace => "comma or right brace",
53 Self::SemicolonOrRParen => "semicolon or right parenthesis",
54 Self::Term => "term",
55 Self::Key => "key",
56 Self::Ident => "identifier",
57 Self::Arg => "argument",
58 Self::Str => "string",
59 Self::Nothing => "nothing",
60 }
61 }
62}
63
64pub type Result<'s, 't, T> = core::result::Result<T, TError<'t, &'s str>>;
66
67pub struct Parser<'s, 't> {
69 i: core::slice::Iter<'t, Token<&'s str>>,
70 e: Vec<TError<'t, &'s str>>,
71 fold: &'s [&'s str],
73}
74
75#[derive(Debug, Default)]
77pub enum Term<S> {
78 #[default]
80 Id,
81 Recurse,
83
84 Num(S),
86 Str(Option<S>, Vec<StrPart<S, Self>>),
91 Arr(Option<Box<Self>>),
93 Obj(Vec<(Self, Option<Self>)>),
95
96 Neg(Box<Self>),
98 Pipe(Box<Self>, Option<S>, Box<Self>),
100 BinOp(Box<Self>, Vec<(S, Self)>),
102
103 Label(S, Box<Self>),
105 Break(S),
107
108 Fold(S, Box<Self>, S, Vec<Self>),
110 TryCatch(Box<Self>, Option<Box<Self>>),
112 IfThenElse(Vec<(Self, Self)>, Option<Box<Self>>),
114
115 Def(Vec<Def<S, Self>>, Box<Self>),
117 Call(S, Vec<Self>),
119 Var(S),
121
122 Path(Box<Self>, Path<Self>),
124}
125
126impl<S> Term<S> {
127 pub(crate) fn str(s: S) -> Self {
128 Self::Str(None, [StrPart::Str(s)].into())
129 }
130}
131
132impl<'s, 't> Parser<'s, 't> {
133 #[must_use]
135 pub fn new(i: &'t [Token<&'s str>]) -> Self {
136 Self {
137 i: i.iter(),
138 e: Vec::new(),
139 fold: &["reduce", "foreach", "for"],
140 }
141 }
142
143 pub fn parse<T: Default, F>(mut self, f: F) -> core::result::Result<T, Vec<TError<'t, &'s str>>>
147 where
148 F: FnOnce(&mut Self) -> Result<'s, 't, T>,
149 {
150 let y = self.finish("", f);
151 if self.e.is_empty() {
152 Ok(y)
153 } else {
154 Err(self.e)
155 }
156 }
157
158 fn verify_last(&mut self, last: &'static str) -> Result<'s, 't, ()> {
160 match (self.i.as_slice(), last) {
161 ([], "") => Ok(()),
162 ([Token::Char(c)], last) if *c == last => Ok(()),
163 ([], _) => Err((Expect::Char(last), None))?,
164 ([next, ..], "") => Err((Expect::Nothing, Some(next)))?,
165 ([next, ..], _) => Err((Expect::Char(last), Some(next)))?,
166 }
167 }
168
169 fn with_tok<T>(&mut self, tokens: &'t [Token<&'s str>], f: impl FnOnce(&mut Self) -> T) -> T {
171 let i = core::mem::replace(&mut self.i, tokens.iter());
172 let y = f(self);
173 self.i = i;
174 y
175 }
176
177 fn finish<T: Default, F>(&mut self, last: &'static str, f: F) -> T
181 where
182 F: FnOnce(&mut Self) -> Result<'s, 't, T>,
183 {
184 f(self)
185 .and_then(|y| {
186 self.verify_last(last)?;
187 Ok(y)
188 })
189 .unwrap_or_else(|e| {
190 self.e.push(e);
191 T::default()
192 })
193 }
194
195 fn with<T: Default, F>(&mut self, tokens: &'t [Token<&'s str>], last: &'static str, f: F) -> T
196 where
197 F: FnOnce(&mut Self) -> Result<'s, 't, T>,
198 {
199 self.with_tok(tokens, |p| p.finish(last, f))
200 }
201
202 fn maybe<T>(&mut self, f: impl Fn(&mut Self) -> Option<T>) -> Option<T> {
204 let i = self.i.clone();
205 let y = f(self);
206 if y.is_none() {
208 self.i = i;
209 }
210 y
211 }
212
213 fn try_maybe<T, F>(&mut self, f: F) -> Result<'s, 't, Option<T>>
215 where
216 F: Fn(&mut Self) -> Result<'s, 't, Option<T>>,
217 {
218 let i = self.i.clone();
219 let y = f(self)?;
220 if y.is_none() {
222 self.i = i;
223 }
224 Ok(y)
225 }
226
227 fn obj_items<T, F>(&mut self, f: F) -> Result<'s, 't, Vec<T>>
229 where
230 F: Fn(&mut Self) -> Result<'s, 't, T>,
231 {
232 let mut y = Vec::from([f(self)?]);
233 let rbrace = |p: &mut Self| p.i.next().filter(|tk| matches!(tk, Token::Char("}")));
234 loop {
235 match self.i.next() {
236 Some(Token::Char("}")) => break,
237 Some(Token::Char(",")) if self.maybe(rbrace).is_some() => break,
238 Some(Token::Char(",")) => y.push(f(self)?),
239 next => Err((Expect::CommaOrRBrace, next))?,
240 }
241 }
242 Ok(y)
243 }
244
245 fn arg_items<T, F>(&mut self, f: F) -> Result<'s, 't, Vec<T>>
247 where
248 F: Fn(&mut Self) -> Result<'s, 't, T>,
249 {
250 let mut y = Vec::from([f(self)?]);
251 loop {
252 match self.i.next() {
253 Some(Token::Char(";")) => y.push(f(self)?),
254 Some(Token::Char(")")) => break,
255 next => Err((Expect::SemicolonOrRParen, next))?,
256 }
257 }
258 Ok(y)
259 }
260
261 fn args<T>(&mut self, f: fn(&mut Self) -> Result<'s, 't, T>) -> Vec<T> {
263 self.maybe(|p| match p.i.next() {
264 Some(Token::Block(full, tokens)) if full.starts_with('(') => {
265 Some(p.with(tokens, "", |p| p.arg_items(f)))
266 }
267 _ => None,
268 })
269 .unwrap_or_default()
270 }
271
272 fn op(&mut self, with_comma: bool) -> Option<&'s str> {
274 self.maybe(|p| match p.i.next() {
275 Some(Token::Op("|")) => None,
277 Some(Token::Op(o) | Token::Word(o @ ("and" | "or"))) => Some(*o),
278 Some(Token::Char(o @ ",")) if with_comma => Some(*o),
279 _ => None,
280 })
281 }
282
283 fn char0(&mut self, c: char) -> Option<&'s str> {
284 self.maybe(|p| match p.i.next() {
285 Some(Token::Char(s)) if s.chars().eq([c]) => Some(*s),
286 _ => None,
287 })
288 }
289
290 fn dot(&mut self) -> Option<&'s str> {
291 self.maybe(|p| match p.i.next() {
292 Some(Token::Char(c)) if *c != ".." => c.strip_prefix('.'),
293 _ => None,
294 })
295 }
296
297 fn terminated<T, F>(&mut self, f: F) -> Result<'s, 't, T>
298 where
299 F: FnOnce(&mut Self) -> Result<'s, 't, T>,
300 {
301 let y = f(self)?;
302 self.char1(";")?;
303 Ok(y)
304 }
305
306 fn char1(&mut self, c: &'static str) -> Result<'s, 't, &'s str> {
307 match self.i.next() {
308 Some(Token::Char(s)) if *s == c => Ok(*s),
309 next => Err((Expect::Char(c), next))?,
310 }
311 }
312
313 fn keyword(&mut self, kw: &'static str) -> Result<'s, 't, ()> {
314 match self.i.next() {
315 Some(Token::Word(w)) if *w == kw => Ok(()),
316 next => Err((Expect::Keyword(kw), next))?,
317 }
318 }
319
320 fn var(&mut self) -> Result<'s, 't, &'s str> {
321 match self.i.next() {
322 Some(Token::Word(x)) if x.starts_with('$') => Ok(*x),
323 next => Err((Expect::Var, next))?,
324 }
325 }
326
327 fn pipe(&mut self) -> Result<'s, 't, ()> {
328 match self.i.next() {
329 Some(Token::Op("|")) => Ok(()),
330 next => Err((Expect::Char("|"), next))?,
331 }
332 }
333
334 fn term_with_comma(&mut self, with_comma: bool) -> Result<'s, 't, Term<&'s str>> {
341 let head = self.atom()?;
342 let tail = core::iter::from_fn(|| self.op(with_comma).map(|op| Ok((op, self.atom()?))))
343 .collect::<Result<Vec<_>>>()?;
344
345 let tm = if tail.is_empty() {
346 head
347 } else {
348 Term::BinOp(Box::new(head), tail)
349 };
350
351 let pipe = self.try_maybe(|p| match p.i.next() {
352 Some(Token::Op("|")) => Ok(Some(None)),
353 Some(Token::Word("as")) => {
354 let x = p.var()?;
355 p.pipe()?;
356 Ok(Some(Some(x)))
357 }
358 _ => Ok(None),
359 })?;
360 Ok(match pipe {
361 None => tm,
362 Some(x) => Term::Pipe(Box::new(tm), x, Box::new(self.term_with_comma(with_comma)?)),
363 })
364 }
365
366 fn atom(&mut self) -> Result<'s, 't, Term<&'s str>> {
372 let tm = match self.i.next() {
373 Some(Token::Op("-")) => Term::Neg(Box::new(self.atom()?)),
374 Some(Token::Word("def")) => {
375 let head = self.def_tail()?;
376 let tail = self.defs()?;
377 let tm = self.term()?;
378 Term::Def(core::iter::once(head).chain(tail).collect(), Box::new(tm))
379 }
380 Some(Token::Word("if")) => {
381 let if_then = |p: &mut Self| -> Result<_> {
382 let if_ = p.term()?;
383 p.keyword("then")?;
384 Ok((if_, p.term()?))
385 };
386 let mut if_thens = Vec::from([if_then(self)?]);
387 let else_ = loop {
388 match self.i.next() {
389 Some(Token::Word("elif")) => if_thens.push(if_then(self)?),
390 Some(Token::Word("else")) => {
391 let else_ = self.term()?;
392 self.keyword("end")?;
393 break Some(else_);
394 }
395 Some(Token::Word("end")) => break None,
396 next => Err((Expect::ElseOrEnd, next))?,
397 }
398 };
399 Term::IfThenElse(if_thens, else_.map(Box::new))
400 }
401 Some(Token::Word("try")) => {
402 let try_ = self.atom()?;
403 let catch = self.try_maybe(|p| match p.i.next() {
404 Some(Token::Word("catch")) => Ok(Some(p.atom()?)),
405 _ => Ok(None),
406 })?;
407 Term::TryCatch(Box::new(try_), catch.map(Box::new))
408 }
409 Some(Token::Word("label")) => {
410 let x = self.var()?;
411 self.pipe()?;
412 let tm = self.term()?;
413 Term::Label(x, Box::new(tm))
414 }
415 Some(Token::Word("break")) => Term::Break(self.var()?),
416 Some(Token::Word(fold)) if self.fold.contains(fold) => {
417 let xs = self.atom()?;
418 self.keyword("as")?;
419 let x = self.var()?;
420 let args = self.args(Self::term);
421 Term::Fold(*fold, Box::new(xs), x, args)
422 }
423 Some(Token::Word(id)) if id.starts_with('$') => Term::Var(*id),
424 Some(Token::Word(id)) if id.starts_with('@') => {
425 let s = self.maybe(|p| match p.i.next() {
426 Some(Token::Str(_, parts)) => Some(p.str_parts(parts)),
427 _ => None,
428 });
429 match s {
430 None => Term::Call(*id, Vec::new()),
431 Some(parts) => Term::Str(Some(*id), parts),
432 }
433 }
434 Some(Token::Word(id)) => Term::Call(*id, self.args(Self::term)),
435 Some(Token::Char("..")) => Term::Recurse,
436 Some(Token::Char(c)) if c.starts_with('.') => {
437 let key = if c.len() > 1 {
438 Some(Term::str(&c[1..]))
439 } else {
440 self.maybe(|p| p.key().ok())
443 };
444
445 if let Some(key) = key {
446 let head = (path::Part::Index(key), self.opt());
447 let path = core::iter::once(head).chain(self.path()?).collect();
448 Term::Path(Box::new(Term::Id), path)
449 } else {
450 Term::Id
451 }
452 }
453 Some(Token::Num(n)) => Term::Num(*n),
454 Some(Token::Block(full, tokens)) => match &full[..1] {
455 "[" if matches!(tokens[..], [Token::Char("]")]) => Term::Arr(None),
456 "{" if matches!(tokens[..], [Token::Char("}")]) => Term::Obj(Vec::new()),
457 "[" => Term::Arr(Some(Box::new(self.with(tokens, "]", Self::term)))),
458 "{" => self.with(tokens, "", |p| p.obj_items(Self::obj_entry).map(Term::Obj)),
459 "(" => self.with(tokens, ")", Self::term),
460 _ => panic!(),
461 },
462 Some(Token::Str(_, parts)) => Term::Str(None, self.str_parts(parts)),
463 next => Err((Expect::Term, next))?,
464 };
465
466 let tm = match self.opt() {
467 path::Opt::Optional => Term::TryCatch(Box::new(tm), None),
468 path::Opt::Essential => tm,
469 };
470
471 let path = self.path()?;
472 Ok(if path.is_empty() {
473 tm
474 } else {
475 Term::Path(Box::new(tm), path)
476 })
477 }
478
479 pub fn term(&mut self) -> Result<'s, 't, Term<&'s str>> {
481 self.term_with_comma(true)
482 }
483
484 fn obj_entry(&mut self) -> Result<'s, 't, (Term<&'s str>, Option<Term<&'s str>>)> {
491 let i = self.i.clone();
492 let key = match self.i.next() {
493 Some(Token::Block(full, tokens)) if full.starts_with('(') => {
494 let k = self.with(tokens, ")", Self::term);
495 self.char1(":")?;
496 return Ok((k, Some(self.term_with_comma(false)?)));
497 }
498 Some(Token::Word(id)) if !id.starts_with(['$', '@']) && !id.contains("::") => {
499 Term::str(*id)
500 }
501 _ => {
502 self.i = i;
503 self.key()?
504 }
505 };
506 let v = self.char0(':').map(|_| self.term_with_comma(false));
507 Ok((key, v.transpose()?))
508 }
509
510 fn str_parts(
511 &mut self,
512 parts: &'t [StrPart<&'s str, Token<&'s str>>],
513 ) -> Vec<StrPart<&'s str, Term<&'s str>>> {
514 let parts = parts.iter().map(|part| match part {
515 StrPart::Str(s) => StrPart::Str(*s),
516 StrPart::Filter(Token::Block(full, tokens)) if full.starts_with('(') => {
517 StrPart::Filter(self.with(tokens, ")", Self::term))
518 }
519 StrPart::Filter(_) => unreachable!(),
520 StrPart::Char(c) => StrPart::Char(*c),
521 });
522 parts.collect()
523 }
524
525 fn path(&mut self) -> Result<'s, 't, Path<Term<&'s str>>> {
526 let mut path: Vec<_> = core::iter::from_fn(|| self.path_part_opt()).collect();
527 while let Some(key) = self.dot() {
528 let key = if key.is_empty() {
529 self.key()?
530 } else {
531 Term::str(key)
532 };
533 path.push((path::Part::Index(key), self.opt()));
534 path.extend(core::iter::from_fn(|| self.path_part_opt()));
535 }
536 Ok(path)
537 }
538
539 fn path_part(&mut self) -> Result<'s, 't, path::Part<Term<&'s str>>> {
541 use path::Part::{Index, Range};
542 let done = |p: &Self| matches!(p.i.as_slice(), [Token::Char("]")]);
543 Ok(if done(self) {
544 Range(None, None)
545 } else if self.char0(':').is_some() {
546 Range(None, Some(self.term()?))
547 } else {
548 let tm = self.term()?;
549 if self.char0(':').is_some() {
550 if done(self) {
551 Range(Some(tm), None)
552 } else {
553 Range(Some(tm), Some(self.term()?))
554 }
555 } else {
556 Index(tm)
557 }
558 })
559 }
560
561 fn path_part_opt(&mut self) -> Option<(path::Part<Term<&'s str>>, path::Opt)> {
562 let part = self.maybe(|p| match p.i.next() {
563 Some(Token::Block(full, tokens)) if full.starts_with('[') => {
564 Some(p.with(tokens, "]", Self::path_part))
565 }
566 _ => None,
567 })?;
568 Some((part, self.opt()))
569 }
570
571 fn key(&mut self) -> Result<'s, 't, Term<&'s str>> {
572 Ok(match self.i.next() {
573 Some(Token::Word(id)) if id.starts_with('$') => Term::Var(*id),
574 Some(Token::Word(id)) if id.starts_with('@') => match self.i.next() {
575 Some(Token::Str(_, parts)) => Term::Str(Some(*id), self.str_parts(parts)),
576 next => Err((Expect::Str, next))?,
577 },
578 Some(Token::Str(_, parts)) => Term::Str(None, self.str_parts(parts)),
579 next => Err((Expect::Key, next))?,
580 })
581 }
582
583 fn opt(&mut self) -> path::Opt {
584 let mut opt = path::Opt::Essential;
585 while self.char0('?').is_some() {
586 opt = path::Opt::Optional;
587 }
588 opt
589 }
590
591 pub fn defs(&mut self) -> Result<'s, 't, Defs<&'s str>> {
593 let head = |p: &mut Self| p.keyword("def").ok();
594 core::iter::from_fn(|| self.maybe(head).map(|_| self.def_tail())).collect()
595 }
596
597 fn def_tail(&mut self) -> Result<'s, 't, Def<&'s str, Term<&'s str>>> {
599 let name = match self.i.next() {
600 Some(Token::Word(w)) if !w.starts_with('$') && !w.contains("::") => w,
601 next => Err((Expect::Ident, next))?,
602 };
603 let args = self.args(|p| {
604 Ok(match p.i.next() {
605 Some(Token::Word(w)) if !w.contains("::") => *w,
606 next => Err((Expect::Arg, next))?,
607 })
608 });
609 self.char1(":")?;
610
611 let body = self.term()?;
612 self.char1(";")?;
613
614 Ok(Def { name, args, body })
615 }
616
617 fn bare_str(&mut self) -> Result<'s, 't, &'s str> {
618 match self.i.next() {
619 next @ Some(Token::Str(_, parts)) => match parts[..] {
620 [StrPart::Str(s)] => Ok(s),
621 _ => Err((Expect::Str, next))?,
622 },
623 next => Err((Expect::Str, next))?,
624 }
625 }
626
627 fn include(&mut self) -> Result<'s, 't, (&'s str, Option<&'s str>)> {
628 self.bare_str().map(|path| (path, None))
629 }
630
631 fn import(&mut self) -> Result<'s, 't, (&'s str, Option<&'s str>)> {
632 let path = self.bare_str()?;
633 self.keyword("as")?;
634 let name = match self.i.next() {
635 Some(Token::Word(w)) if !w.starts_with(['$', '@']) && !w.contains("::") => *w,
636 next => Err((Expect::Ident, next))?,
637 };
638 Ok((path, Some(name)))
639 }
640
641 pub fn module<B, F>(&mut self, f: F) -> Result<'s, 't, Module<&'s str, B>>
643 where
644 F: FnOnce(&mut Self) -> Result<'s, 't, B>,
645 {
646 let meta = self
647 .maybe(|p| match p.i.next() {
648 Some(Token::Word("module")) => Some(p.terminated(Self::term)),
649 _ => None,
650 })
651 .transpose()?;
652
653 let deps = core::iter::from_fn(|| {
654 self.maybe(|p| match p.i.next() {
655 Some(Token::Word("include")) => Some(p.terminated(Self::include)),
656 Some(Token::Word("import")) => Some(p.terminated(Self::import)),
657 _ => None,
658 })
659 })
660 .collect::<Result<_>>()?;
661
662 let body = f(self)?;
663
664 Ok(Module { meta, deps, body })
665 }
666}
667
668#[derive(Debug, Default)]
681pub struct Module<S, B> {
682 #[allow(dead_code)]
683 pub(crate) meta: Option<Term<S>>,
684 pub(crate) deps: Vec<(S, Option<S>)>,
685 pub(crate) body: B,
686}
687
688#[derive(Debug)]
699pub struct Def<S, F> {
700 pub(crate) name: S,
701 pub(crate) args: Vec<S>,
702 pub(crate) body: F,
704}
705
706pub(crate) type Defs<S> = Vec<Def<S, Term<S>>>;