1use super::lex::{StrPart, Tok, Token};
4use super::path::{self, Path};
5use super::{ops, prec_climb};
6use alloc::{boxed::Box, vec::Vec};
7use core::fmt::{self, Debug};
8
9pub type Error<S, T = S> = (Expect<S>, T);
11pub type TError<'t, S> = Error<S, Option<&'t Token<S>>>;
13
14#[derive(Debug)]
18#[non_exhaustive]
19pub enum Expect<S> {
20 Just(S),
23 Var,
25 Pattern,
27 ElseOrEnd,
29 CommaOrRBrack,
31 CommaOrRBrace,
33 SemicolonOrRParen,
35 Term,
37 Key,
39 Ident,
41 Arg,
43 Str,
45 Nothing,
47}
48
49impl<'a> Expect<&'a str> {
50 pub fn as_str(&self) -> &'a str {
52 match self {
53 Self::Just(s) => s,
54 Self::Var => "variable",
55 Self::Pattern => "pattern",
56 Self::ElseOrEnd => "else or end",
57 Self::CommaOrRBrack => "comma or right bracket",
58 Self::CommaOrRBrace => "comma or right brace",
59 Self::SemicolonOrRParen => "semicolon or right parenthesis",
60 Self::Term => "term",
61 Self::Key => "key",
62 Self::Ident => "identifier",
63 Self::Arg => "argument",
64 Self::Str => "string",
65 Self::Nothing => "nothing",
66 }
67 }
68}
69
70pub type Result<'s, 't, T> = core::result::Result<T, TError<'t, &'s str>>;
72
73pub struct Parser<'s, 't> {
75 i: core::slice::Iter<'t, Token<&'s str>>,
76 e: Vec<TError<'t, &'s str>>,
77}
78
79#[derive(Debug, Default)]
81pub enum Term<S> {
82 #[default]
84 Id,
85 Recurse,
87
88 Num(S),
90 Str(Option<S>, Vec<StrPart<S, Self>>),
95 Arr(Option<Box<Self>>),
97 Obj(Vec<(Self, Option<Self>)>),
99
100 Neg(Box<Self>),
102 Pipe(Box<Self>, Option<Pattern<S>>, Box<Self>),
104
105 BinOp(Box<Self>, BinaryOp, Box<Self>),
107
108 Label(S, Box<Self>),
110 Break(S),
112
113 Fold(S, Box<Self>, Pattern<S>, Vec<Self>),
115 TryCatch(Box<Self>, Option<Box<Self>>),
117 IfThenElse(Vec<(Self, Self)>, Option<Box<Self>>),
119
120 Def(Vec<Def<S, Self>>, Box<Self>),
122 Call(S, Vec<Self>),
124 Var(S),
126
127 Path(Box<Self>, Path<Self>),
129}
130
131#[derive(Debug)]
133pub enum Pattern<S> {
134 Var(S),
136 Arr(Vec<Self>),
138 Obj(Vec<(Term<S>, Self)>),
140}
141
142#[derive(Debug)]
144pub enum BinaryOp {
145 Comma,
147 Alt,
149 Or,
151 And,
153 Math(ops::Math),
155 Cmp(ops::Cmp),
157 Assign,
159 Update,
161 UpdateMath(ops::Math),
164 UpdateAlt,
166}
167
168impl<S> Term<S> {
169 #[cfg(feature = "std")]
170 pub(crate) fn as_str(&self) -> Option<&S> {
171 if let Term::Str(None, s) = self {
172 if let [StrPart::Str(s)] = &s[..] {
173 return Some(s);
174 }
175 }
176 None
177 }
178
179 pub(crate) fn from_str(s: S) -> Self {
180 Self::Str(None, [StrPart::Str(s)].into())
181 }
182
183 pub(crate) fn empty() -> Self {
185 let path = (path::Part::Range(None, None), path::Opt::Essential);
187 let obj = Term::Obj(Vec::new());
189 Term::Path(obj.into(), Path(Vec::from([path])))
191 }
192}
193
194impl<S> Pattern<S> {
195 pub(crate) fn vars(&self) -> Box<dyn Iterator<Item = &S> + '_> {
196 match self {
197 Pattern::Var(x) => Box::new(core::iter::once(x)),
198 Pattern::Arr(a) => Box::new(a.iter().flat_map(|p| p.vars())),
199 Pattern::Obj(o) => Box::new(o.iter().flat_map(|(_k, p)| p.vars())),
200 }
201 }
202}
203
204impl<'s, 't> Parser<'s, 't> {
205 #[must_use]
207 pub fn new(i: &'t [Token<&'s str>]) -> Self {
208 Self {
209 i: i.iter(),
210 e: Vec::new(),
211 }
212 }
213
214 pub fn parse<T: Default, F>(mut self, f: F) -> core::result::Result<T, Vec<TError<'t, &'s str>>>
218 where
219 F: FnOnce(&mut Self) -> Result<'s, 't, T>,
220 {
221 let y = self.finish("", f);
222 if self.e.is_empty() {
223 Ok(y)
224 } else {
225 Err(self.e)
226 }
227 }
228
229 fn verify_last(&mut self, last: &'static str) -> Result<'s, 't, ()> {
231 match (self.i.as_slice(), last) {
232 ([], "") => Ok(()),
233 ([Token(c, _)], last) if *c == last => Ok(()),
234 ([], _) => Err((Expect::Just(last), None)),
235 ([next, ..], "") => Err((Expect::Nothing, Some(next))),
236 ([next, ..], _) => Err((Expect::Just(last), Some(next))),
237 }
238 }
239
240 fn with_tok<T>(&mut self, tokens: &'t [Token<&'s str>], f: impl FnOnce(&mut Self) -> T) -> T {
242 let i = core::mem::replace(&mut self.i, tokens.iter());
243 let y = f(self);
244 self.i = i;
245 y
246 }
247
248 fn finish<T: Default, F>(&mut self, last: &'static str, f: F) -> T
252 where
253 F: FnOnce(&mut Self) -> Result<'s, 't, T>,
254 {
255 f(self)
256 .and_then(|y| {
257 self.verify_last(last)?;
258 Ok(y)
259 })
260 .unwrap_or_else(|e| {
261 self.e.push(e);
262 T::default()
263 })
264 }
265
266 fn with<T: Default, F>(&mut self, tokens: &'t [Token<&'s str>], last: &'static str, f: F) -> T
267 where
268 F: FnOnce(&mut Self) -> Result<'s, 't, T>,
269 {
270 self.with_tok(tokens, |p| p.finish(last, f))
271 }
272
273 fn maybe<T>(&mut self, f: impl Fn(&mut Self) -> Option<T>) -> Option<T> {
275 let i = self.i.clone();
276 let y = f(self);
277 if y.is_none() {
279 self.i = i;
280 }
281 y
282 }
283
284 fn try_maybe<T, F>(&mut self, f: F) -> Result<'s, 't, Option<T>>
286 where
287 F: Fn(&mut Self) -> Result<'s, 't, Option<T>>,
288 {
289 let i = self.i.clone();
290 let y = f(self)?;
291 if y.is_none() {
293 self.i = i;
294 }
295 Ok(y)
296 }
297
298 fn many1<T>(
299 &mut self,
300 f: impl Fn(&mut Self) -> Result<'s, 't, T>,
301 sep: &'s str,
302 allow_trailing_sep: bool,
303 last: &'s str,
304 expect: Expect<&'s str>,
305 ) -> Result<'s, 't, Vec<T>> {
306 let mut y = Vec::from([f(self)?]);
307 let get_last = |p: &mut Self| p.i.next().filter(|Token(s, _)| *s == last);
308 let next_last = |p: &mut Self| allow_trailing_sep && p.maybe(get_last).is_some();
309 loop {
310 match self.i.next() {
311 Some(Token(s, _)) if *s == last => break,
312 Some(Token(s, _)) if *s == sep && next_last(self) => break,
313 Some(Token(s, _)) if *s == sep => y.push(f(self)?),
314 next => return Err((expect, next)),
315 }
316 }
317 Ok(y)
318 }
319
320 fn obj_items<T, F>(&mut self, f: F) -> Result<'s, 't, Vec<T>>
322 where
323 F: Fn(&mut Self) -> Result<'s, 't, T>,
324 {
325 self.many1(f, ",", true, "}", Expect::CommaOrRBrace)
326 }
327
328 fn args<T>(&mut self, f: fn(&mut Self) -> Result<'s, 't, T>) -> Vec<T> {
330 self.maybe(|p| match p.i.next() {
331 Some(Token(full, Tok::Block(tokens))) if full.starts_with('(') => {
332 Some(p.with(tokens, "", |p| {
333 p.many1(f, ";", false, ")", Expect::SemicolonOrRParen)
334 }))
335 }
336 _ => None,
337 })
338 .unwrap_or_default()
339 }
340
341 fn op(&mut self, with_comma: bool) -> Option<BinaryOp> {
343 use ops::{Cmp, Math};
344 self.maybe(|p| match p.i.next() {
345 Some(Token(s, _)) => Some(match *s {
346 "," if with_comma => BinaryOp::Comma,
347 "+" => BinaryOp::Math(Math::Add),
348 "-" => BinaryOp::Math(Math::Sub),
349 "*" => BinaryOp::Math(Math::Mul),
350 "/" => BinaryOp::Math(Math::Div),
351 "%" => BinaryOp::Math(Math::Rem),
352 "=" => BinaryOp::Assign,
353 "|=" => BinaryOp::Update,
354 "+=" => BinaryOp::UpdateMath(Math::Add),
355 "-=" => BinaryOp::UpdateMath(Math::Sub),
356 "*=" => BinaryOp::UpdateMath(Math::Mul),
357 "/=" => BinaryOp::UpdateMath(Math::Div),
358 "%=" => BinaryOp::UpdateMath(Math::Rem),
359 "<" => BinaryOp::Cmp(Cmp::Lt),
360 ">" => BinaryOp::Cmp(Cmp::Gt),
361 "<=" => BinaryOp::Cmp(Cmp::Le),
362 ">=" => BinaryOp::Cmp(Cmp::Ge),
363 "==" => BinaryOp::Cmp(Cmp::Eq),
364 "!=" => BinaryOp::Cmp(Cmp::Ne),
365 "//" => BinaryOp::Alt,
366 "//=" => BinaryOp::UpdateAlt,
367 "or" => BinaryOp::Or,
368 "and" => BinaryOp::And,
369 _ => return None,
370 }),
371 None => None,
372 })
373 }
374
375 fn char0(&mut self, c: char) -> Option<&'s str> {
377 self.maybe(|p| match p.i.next() {
378 Some(Token(s, _)) if s.chars().eq([c]) => Some(*s),
379 _ => None,
380 })
381 }
382
383 fn dot(&mut self) -> Option<&'s str> {
389 self.maybe(|p| match p.i.next() {
390 Some(Token(c, _)) if *c != ".." => c.strip_prefix('.'),
391 _ => None,
392 })
393 }
394
395 fn terminated<T, F>(&mut self, f: F) -> Result<'s, 't, T>
396 where
397 F: FnOnce(&mut Self) -> Result<'s, 't, T>,
398 {
399 let y = f(self)?;
400 self.just(";")?;
401 Ok(y)
402 }
403
404 fn just(&mut self, c: &'static str) -> Result<'s, 't, &'s str> {
405 match self.i.next() {
406 Some(Token(s, _)) if *s == c => Ok(*s),
407 next => Err((Expect::Just(c), next)),
408 }
409 }
410
411 fn var(&mut self) -> Result<'s, 't, &'s str> {
412 match self.i.next() {
413 Some(Token(x, Tok::Var)) => Ok(*x),
414 next => Err((Expect::Var, next)),
415 }
416 }
417
418 fn pattern(&mut self) -> Result<'s, 't, Pattern<&'s str>> {
419 match self.i.next() {
420 Some(Token(x, Tok::Var)) => Ok(Pattern::Var(*x)),
421 next @ Some(Token(full, Tok::Block(tokens))) => match &full[..1] {
422 "[" => Ok(Pattern::Arr(self.with(tokens, "", |p| {
423 p.many1(Self::pattern, ",", false, "]", Expect::CommaOrRBrack)
424 }))),
425 "{" => Ok(Pattern::Obj(
426 self.with(tokens, "", |p| p.obj_items(Self::pat_obj_entry)),
427 )),
428 _ => Err((Expect::Pattern, next)),
429 },
430 next => Err((Expect::Pattern, next)),
431 }
432 }
433
434 fn term_with_comma(&mut self, with_comma: bool) -> Result<'s, 't, Term<&'s str>> {
441 let head = self.atom()?;
442 let tail = core::iter::from_fn(|| self.op(with_comma).map(|op| Ok((op, self.atom()?))))
443 .collect::<Result<Vec<_>>>()?;
444 let tm = prec_climb::climb(head, tail);
445
446 let pipe = self.try_maybe(|p| match p.i.next() {
447 Some(Token("|", _)) => Ok(Some(None)),
448 Some(Token("as", _)) => {
449 let x = p.pattern()?;
450 p.just("|")?;
451 Ok(Some(Some(x)))
452 }
453 _ => Ok(None),
454 })?;
455 Ok(match pipe {
456 None => tm,
457 Some(x) => Term::Pipe(Box::new(tm), x, Box::new(self.term_with_comma(with_comma)?)),
458 })
459 }
460
461 fn atom(&mut self) -> Result<'s, 't, Term<&'s str>> {
467 let tm = match self.i.next() {
468 Some(Token("-", _)) => Term::Neg(Box::new(self.atom()?)),
469 Some(Token("def", _)) => {
470 let head = self.def_tail()?;
471 let tail = self.defs()?;
472 let tm = self.term()?;
473 Term::Def(core::iter::once(head).chain(tail).collect(), Box::new(tm))
474 }
475 Some(Token("if", _)) => {
476 let if_then = |p: &mut Self| -> Result<_> {
477 let if_ = p.term()?;
478 p.just("then")?;
479 Ok((if_, p.term()?))
480 };
481 let mut if_thens = Vec::from([if_then(self)?]);
482 let else_ = loop {
483 match self.i.next() {
484 Some(Token("elif", _)) => if_thens.push(if_then(self)?),
485 Some(Token("else", _)) => {
486 let else_ = self.term()?;
487 self.just("end")?;
488 break Some(else_);
489 }
490 Some(Token("end", _)) => break None,
491 next => return Err((Expect::ElseOrEnd, next)),
492 }
493 };
494 Term::IfThenElse(if_thens, else_.map(Box::new))
495 }
496 Some(Token("try", _)) => {
497 let try_ = self.atom()?;
498 let catch = self.try_maybe(|p| match p.i.next() {
499 Some(Token("catch", _)) => Ok(Some(p.atom()?)),
500 _ => Ok(None),
501 })?;
502 Term::TryCatch(Box::new(try_), catch.map(Box::new))
503 }
504 Some(Token("label", _)) => {
505 let x = self.var()?;
506 self.just("|")?;
507 let tm = self.term()?;
508 Term::Label(x, Box::new(tm))
509 }
510 Some(Token("break", _)) => Term::Break(self.var()?),
511 Some(Token(fold @ ("reduce" | "foreach"), _)) => {
512 let xs = self.atom()?;
513 self.just("as")?;
514 let x = self.pattern()?;
515 let args = self.args(Self::term);
516 Term::Fold(*fold, Box::new(xs), x, args)
517 }
518 Some(Token(id, Tok::Var)) => Term::Var(*id),
519 Some(Token(id, Tok::Fmt)) => {
520 let s = self.maybe(|p| match p.i.next() {
521 Some(Token(_, Tok::Str(parts))) => Some(p.str_parts(parts)),
522 _ => None,
523 });
524 match s {
525 None => Term::Call(*id, self.args(Self::term)),
526 Some(parts) => Term::Str(Some(*id), parts),
527 }
528 }
529 Some(Token(id, Tok::Word)) => Term::Call(*id, self.args(Self::term)),
530 Some(Token("..", _)) => Term::Recurse,
531 Some(Token(c, Tok::Sym)) if c.starts_with('.') => {
532 let key = if c.len() > 1 {
533 Some(Term::from_str(&c[1..]))
534 } else {
535 self.maybe(|p| p.str_key().ok())
538 };
539
540 if let Some(key) = key {
541 let head = (path::Part::Index(key), self.opt());
542 let path = core::iter::once(head).chain(self.path()?.0).collect();
543 Term::Path(Box::new(Term::Id), Path(path))
544 } else {
545 Term::Id
546 }
547 }
548 Some(Token(n, Tok::Num)) => Term::Num(*n),
549 Some(Token(full, Tok::Block(tokens))) => match &full[..1] {
550 "[" if matches!(tokens[..], [Token("]", _)]) => Term::Arr(None),
551 "{" if matches!(tokens[..], [Token("}", _)]) => Term::Obj(Vec::new()),
552 "[" => Term::Arr(Some(Box::new(self.with(tokens, "]", Self::term)))),
553 "{" => self.with(tokens, "", |p| p.obj_items(Self::obj_entry).map(Term::Obj)),
554 "(" => self.with(tokens, ")", Self::term),
555 _ => panic!(),
556 },
557 Some(Token(_, Tok::Str(parts))) => Term::Str(None, self.str_parts(parts)),
558 next => return Err((Expect::Term, next)),
559 };
560
561 let tm = match self.opt() {
562 path::Opt::Optional => Term::TryCatch(Box::new(tm), None),
563 path::Opt::Essential => tm,
564 };
565
566 let path = self.path()?;
567 Ok(if path.0.is_empty() {
568 tm
569 } else {
570 Term::Path(Box::new(tm), path)
571 })
572 }
573
574 pub fn term(&mut self) -> Result<'s, 't, Term<&'s str>> {
576 self.term_with_comma(true)
577 }
578
579 fn pat_obj_entry(&mut self) -> Result<'s, 't, (Term<&'s str>, Pattern<&'s str>)> {
588 let i = self.i.clone();
589 let key = match self.i.next() {
590 Some(Token(x, Tok::Var)) => return Ok((Term::from_str(&x[1..]), Pattern::Var(x))),
591 Some(Token(full, Tok::Block(tokens))) if full.starts_with('(') => {
592 self.with(tokens, ")", Self::term)
593 }
594 Some(Token(id, Tok::Word)) if !id.contains("::") => Term::from_str(*id),
595 _ => {
596 self.i = i;
597 self.str_key()?
598 }
599 };
600 self.just(":")?;
601 Ok((key, self.pattern()?))
602 }
603
604 fn obj_entry(&mut self) -> Result<'s, 't, (Term<&'s str>, Option<Term<&'s str>>)> {
611 let i = self.i.clone();
612 let key = match self.i.next() {
613 Some(Token(full, Tok::Block(tokens))) if full.starts_with('(') => {
614 let k = self.with(tokens, ")", Self::term);
615 self.just(":")?;
616 return Ok((k, Some(self.term_with_comma(false)?)));
617 }
618 Some(Token(id, Tok::Var)) => Term::Var(*id),
619 Some(Token(id, Tok::Word)) if !id.contains("::") => Term::from_str(*id),
620 _ => {
621 self.i = i;
622 self.str_key()?
623 }
624 };
625 let v = self.char0(':').map(|_| self.term_with_comma(false));
626 Ok((key, v.transpose()?))
627 }
628
629 fn str_parts(
630 &mut self,
631 parts: &'t [StrPart<&'s str, Token<&'s str>>],
632 ) -> Vec<StrPart<&'s str, Term<&'s str>>> {
633 let parts = parts.iter().map(|part| match part {
634 StrPart::Str(s) => StrPart::Str(*s),
635 StrPart::Term(Token(full, Tok::Block(tokens))) if full.starts_with('(') => {
636 StrPart::Term(self.with(tokens, ")", Self::term))
637 }
638 StrPart::Term(_) => unreachable!(),
639 StrPart::Char(c) => StrPart::Char(*c),
640 });
641 parts.collect()
642 }
643
644 fn path(&mut self) -> Result<'s, 't, Path<Term<&'s str>>> {
645 let mut path: Vec<_> = core::iter::from_fn(|| self.path_part_opt()).collect();
646 while let Some(key) = self.dot() {
647 let key = if key.is_empty() {
648 self.str_key()?
649 } else {
650 Term::from_str(key)
651 };
652 path.push((path::Part::Index(key), self.opt()));
653 path.extend(core::iter::from_fn(|| self.path_part_opt()));
654 }
655 Ok(Path(path))
656 }
657
658 fn path_part(&mut self) -> Result<'s, 't, path::Part<Term<&'s str>>> {
660 use path::Part::{Index, Range};
661 let done = |p: &Self| matches!(p.i.as_slice(), [Token("]", _)]);
662 Ok(if done(self) {
663 Range(None, None)
664 } else if self.char0(':').is_some() {
665 Range(None, Some(self.term()?))
666 } else {
667 let tm = self.term()?;
668 if self.char0(':').is_some() {
669 if done(self) {
670 Range(Some(tm), None)
671 } else {
672 Range(Some(tm), Some(self.term()?))
673 }
674 } else {
675 Index(tm)
676 }
677 })
678 }
679
680 fn path_part_opt(&mut self) -> Option<(path::Part<Term<&'s str>>, path::Opt)> {
681 let part = self.maybe(|p| match p.i.next() {
682 Some(Token(full, Tok::Block(tokens))) if full.starts_with('[') => {
683 Some(p.with(tokens, "]", Self::path_part))
684 }
685 _ => None,
686 })?;
687 Some((part, self.opt()))
688 }
689
690 fn str_key(&mut self) -> Result<'s, 't, Term<&'s str>> {
691 match self.i.next() {
692 Some(Token(id, Tok::Fmt)) => match self.i.next() {
693 Some(Token(_, Tok::Str(parts))) => Ok(Term::Str(Some(*id), self.str_parts(parts))),
694 next => Err((Expect::Str, next)),
695 },
696 Some(Token(_, Tok::Str(parts))) => Ok(Term::Str(None, self.str_parts(parts))),
697 next => Err((Expect::Key, next)),
698 }
699 }
700
701 fn opt(&mut self) -> path::Opt {
702 let mut opt = path::Opt::Essential;
703 while self.char0('?').is_some() {
704 opt = path::Opt::Optional;
705 }
706 opt
707 }
708
709 pub fn defs(&mut self) -> Result<'s, 't, Vec<Def<&'s str>>> {
711 let head = |p: &mut Self| p.just("def").ok();
712 core::iter::from_fn(|| self.maybe(head).map(|_| self.def_tail())).collect()
713 }
714
715 fn def_tail(&mut self) -> Result<'s, 't, Def<&'s str, Term<&'s str>>> {
717 let name = match self.i.next() {
718 Some(Token(w, Tok::Word | Tok::Fmt)) if !w.contains("::") => w,
719 next => return Err((Expect::Ident, next)),
720 };
721 let args = self.args(|p| match p.i.next() {
722 Some(Token(w, Tok::Word | Tok::Var)) if !w.contains("::") => Ok(*w),
723 next => Err((Expect::Arg, next)),
724 });
725 self.just(":")?;
726
727 let body = self.term()?;
728 self.just(";")?;
729
730 Ok(Def { name, args, body })
731 }
732
733 fn bare_str(&mut self) -> Result<'s, 't, &'s str> {
734 match self.i.next() {
735 next @ Some(Token(_, Tok::Str(parts))) => match parts[..] {
736 [StrPart::Str(s)] => Ok(s),
737 _ => Err((Expect::Str, next)),
738 },
739 next => Err((Expect::Str, next)),
740 }
741 }
742
743 fn dep(&mut self, import: bool) -> Result<'s, 't, Dep<&'s str>> {
745 let path = self.bare_str()?;
746 let name = import.then(|| {
747 self.just("as")?;
748 match self.i.next() {
749 Some(Token(v, Tok::Word | Tok::Var)) => Ok(*v),
750 next => Err((Expect::Ident, next)),
751 }
752 });
753 let name = name.transpose()?;
754 let meta = !matches!(self.i.as_slice(), [Token(";", _), ..]);
755 let meta = meta.then(|| self.term()).transpose()?;
756 Ok((path, name, meta))
757 }
758
759 pub(crate) fn module<B, F>(&mut self, f: F) -> Result<'s, 't, Module<&'s str, B>>
761 where
762 F: FnOnce(&mut Self) -> Result<'s, 't, B>,
763 {
764 let meta = self
765 .maybe(|p| match p.i.next() {
766 Some(Token("module", _)) => Some(p.terminated(Self::term)),
767 _ => None,
768 })
769 .transpose()?;
770
771 let deps = core::iter::from_fn(|| {
772 self.maybe(|p| match p.i.next() {
773 Some(Token("include", _)) => Some(p.terminated(|p| p.dep(false))),
774 Some(Token("import", _)) => Some(p.terminated(|p| p.dep(true))),
775 _ => None,
776 })
777 })
778 .collect::<Result<_>>()?;
779
780 let body = f(self)?;
781
782 Ok(Module { meta, deps, body })
783 }
784}
785
786type Dep<S> = (S, Option<S>, Option<Term<S>>);
787
788#[derive(Debug, Default)]
801pub(crate) struct Module<S, B> {
802 pub meta: Option<Term<S>>,
803 pub deps: Vec<Dep<S>>,
804 pub body: B,
805}
806
807pub struct Def<S, F = Term<S>> {
819 pub name: S,
821 pub args: Vec<S>,
823 pub body: F,
825}
826
827impl<S: Debug, F: Debug> Debug for Def<S, F> {
829 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
830 write!(f, "({:?}, {:?}, {:?})", self.name, self.args, self.body)
831 }
832}
833
834impl<S, F> Def<S, F> {
835 pub(crate) fn new(name: S, args: Vec<S>, body: F) -> Self {
836 Self { name, args, body }
837 }
838}
839
840impl prec_climb::Op for BinaryOp {
841 fn precedence(&self) -> usize {
842 use ops::{Cmp, Math};
843 match self {
844 Self::Comma => 1,
845 Self::Assign | Self::Update | Self::UpdateMath(_) | Self::UpdateAlt => 2,
846 Self::Alt => 3,
847 Self::Or => Self::Alt.precedence() + 1,
848 Self::And => Self::Or.precedence() + 1,
849 Self::Cmp(Cmp::Eq | Cmp::Ne) => Self::And.precedence() + 1,
850 Self::Cmp(Cmp::Lt | Cmp::Gt | Cmp::Le | Cmp::Ge) => Self::And.precedence() + 2,
851 Self::Math(Math::Add | Math::Sub) => Self::And.precedence() + 3,
852 Self::Math(Math::Mul | Math::Div) => Self::Math(Math::Add).precedence() + 1,
853 Self::Math(Math::Rem) => Self::Math(Math::Mul).precedence() + 1,
854 }
855 }
856
857 fn associativity(&self) -> prec_climb::Associativity {
858 use prec_climb::Associativity;
859 match self {
860 Self::Assign | Self::Update | Self::UpdateMath(_) | Self::UpdateAlt => {
861 Associativity::Right
862 }
863 _ => Associativity::Left,
864 }
865 }
866}
867
868impl<S> prec_climb::Expr<BinaryOp> for Term<S> {
869 fn from_op(lhs: Self, op: BinaryOp, rhs: Self) -> Self {
870 Self::BinOp(Box::new(lhs), op, Box::new(rhs))
871 }
872}