1use crate::load::{self, lex, parse};
4use crate::{ops, Bind as Arg, Filter};
5use alloc::collections::{BTreeMap, BTreeSet};
6use alloc::{boxed::Box, string::String, vec::Vec};
7
8type NativeId = usize;
9type ModId = usize;
10type VarId = usize;
11type VarSkip = usize;
12type Arity = usize;
13
14#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
16pub struct TermId(pub(crate) usize);
17
18#[derive(Clone, Debug)]
20pub struct Lut<F> {
21 pub(crate) terms: Vec<Term>,
23 pub(crate) funs: Vec<F>,
24}
25
26impl<F> Default for Lut<F> {
27 fn default() -> Self {
28 Lut {
29 terms: Vec::new(),
30 funs: Vec::new(),
31 }
32 }
33}
34
35impl<F> Default for Filter<F> {
36 fn default() -> Self {
37 Self(TermId(0), Lut::new([Term::Id].into()))
38 }
39}
40
41impl<F> Lut<F> {
42 fn new(terms: Vec<Term>) -> Self {
43 let funs = Vec::new();
44 Self { terms, funs }
45 }
46
47 fn map_funs<F2>(self, f: impl Fn(F) -> F2) -> Lut<F2> {
48 Lut {
49 funs: self.funs.into_iter().map(f).collect(),
50 terms: self.terms,
51 }
52 }
53
54 fn insert_term(&mut self, t: Term) -> TermId {
55 let tid = self.terms.len();
56 self.terms.push(t);
57 TermId(tid)
58 }
59}
60
61#[derive(Clone, Debug)]
62pub(crate) enum Tailrec {
63 Throw,
64 Catch,
65}
66
67#[derive(Clone, Debug)]
68pub(crate) enum Term<T = TermId> {
69 Id,
71 ToString,
72
73 Int(isize),
74 Num(String),
75 Str(String),
76 Arr(T),
78 ObjEmpty,
80 ObjSingle(T, T),
82
83 Var(VarId),
85 CallDef(TermId, Box<[Arg<T>]>, VarSkip, Option<Tailrec>),
87 Native(NativeId, Box<[Arg<T>]>),
88
89 Label(T),
91 Neg(T),
93 Pipe(T, Option<Pattern<T>>, T),
96 Comma(T, T),
98 Assign(T, T),
100 Update(T, T),
102 UpdateMath(T, ops::Math, T),
104 UpdateAlt(T, T),
106 Logic(T, bool, T),
108 Math(T, ops::Math, T),
110 Cmp(T, ops::Cmp, T),
112 Alt(T, T),
114 TryCatch(T, T),
116 Ite(T, T, T),
118 Fold(T, Pattern<T>, T, T, Fold<T>),
140 Path(T, crate::path::Path<T>),
141}
142
143#[derive(Clone, Debug)]
144pub(crate) enum Fold<T> {
145 Reduce,
146 Foreach(Option<T>),
147}
148
149impl<T> Default for Term<T> {
150 fn default() -> Self {
151 Self::Id
152 }
153}
154
155#[derive(Clone, Debug)]
156pub(crate) enum Pattern<F> {
157 Var,
158 Idx(Vec<(F, Self)>),
159}
160
161pub type Error<S> = (S, Undefined);
163
164pub type Errors<S, P> = load::Errors<S, P, Vec<Error<S>>>;
166
167#[derive(Debug)]
169#[non_exhaustive]
170pub enum Undefined {
171 Mod,
173 Var,
175 Label,
177 Filter(Arity),
179}
180
181impl Undefined {
182 pub fn as_str(&self) -> &'static str {
184 match self {
185 Self::Var => "variable",
186 Self::Mod => "module",
187 Self::Label => "label",
188 Self::Filter(_arity) => "filter",
189 }
190 }
191}
192
193pub struct Compiler<S, F> {
197 lut: Lut<(Sig<S>, F)>,
198
199 mod_map: Vec<Vec<(Sig<S>, Def)>>,
201
202 imported_mods: Vec<(ModId, S)>,
203 included_mods: Vec<ModId>,
204
205 global_vars: Vec<S>,
206 imported_vars: Vec<(S, ModId)>,
207
208 locals: Locals<S>,
209
210 tailrecs: BTreeSet<TermId>,
212
213 errs: Vec<Error<S>>,
214}
215
216impl<S: Default, F> Default for Compiler<S, F> {
218 fn default() -> Self {
219 Self {
220 lut: Lut::default(),
221 mod_map: Vec::new(),
222 imported_mods: Vec::new(),
223 included_mods: Vec::new(),
224 global_vars: Vec::new(),
225 imported_vars: Vec::new(),
226 tailrecs: BTreeSet::new(),
227 locals: Locals::default(),
228 errs: Vec::new(),
229 }
230 }
231}
232
233#[derive(Clone, Debug)]
234struct Sig<S, A = Arg> {
235 name: S,
236 args: Box<[A]>,
239}
240
241fn bind_from<T>(s: &str, x: T) -> Arg<T> {
242 if s.starts_with('$') {
243 Arg::Var(x)
244 } else {
245 Arg::Fun(x)
246 }
247}
248
249fn binds<T, U: Copy>(binds: &[Arg<T>], args: &[U]) -> Box<[Arg<U>]> {
250 assert!(binds.len() == args.len());
251 let args = binds.iter().zip(args);
252 args.map(|(bind, id)| bind.as_ref().map(|_| *id)).collect()
253}
254
255#[derive(Clone, Debug)]
256struct Def {
257 id: TermId,
258 rec: bool,
260 tailrec: bool,
262}
263
264impl<S: Eq, A> Sig<S, A> {
265 fn matches(&self, name: S, args: &[TermId]) -> bool {
266 name == self.name && args.len() == self.args.len()
267 }
268}
269
270impl Def {
271 fn call(&self, args: Box<[Arg<TermId>]>, vars: usize) -> Term {
272 Term::CallDef(self.id, args, vars, Some(Tailrec::Catch))
276 }
277}
278
279struct MapVecLen<S> {
281 bound: MapVec<S, usize>,
282 total: usize,
283}
284
285impl<S> Default for MapVecLen<S> {
286 fn default() -> Self {
287 Self {
288 bound: MapVec::default(),
289 total: 0,
290 }
291 }
292}
293
294impl<S: Ord> MapVecLen<S> {
295 fn push(&mut self, name: S) {
296 self.total += 1;
297 self.bound.push(name, self.total)
298 }
299
300 fn pop(&mut self, name: &S) {
301 assert_eq!(self.bound.pop(name), Some(self.total));
302 self.total -= 1;
303 }
304
305 fn is_empty(&self) -> bool {
306 self.bound.is_empty() && self.total == 0
307 }
308}
309
310enum Fun<S> {
311 Arg,
312 Parent(Box<[Arg<S>]>, Def),
313 Sibling(Box<[Arg<S>]>, Def, Tr),
315}
316
317#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
319pub(crate) enum Bind<V, L = V, F = V> {
320 Var(V),
322 Label(L),
324 Fun(F),
326}
327
328struct Locals<S> {
329 funs: MapVec<(S, Arity), (Fun<S>, usize)>,
331 vars: MapVecLen<Bind<S>>,
332 parents: Tr,
333}
334
335impl<S> Default for Locals<S> {
336 fn default() -> Self {
337 Self {
338 funs: MapVec::default(),
339 vars: MapVecLen::default(),
340 parents: Tr::default(),
341 }
342 }
343}
344
345struct MapVec<K, V>(BTreeMap<K, Vec<V>>);
346
347impl<K, V> Default for MapVec<K, V> {
348 fn default() -> Self {
349 Self(BTreeMap::new())
350 }
351}
352
353impl<K: Ord, V> MapVec<K, V> {
354 fn push(&mut self, k: K, v: V) {
355 self.0.entry(k).or_default().push(v)
356 }
357
358 fn pop(&mut self, k: &K) -> Option<V> {
359 let vs = self.0.get_mut(k)?;
360 let v = vs.pop()?;
361 if vs.is_empty() {
362 self.0.remove(k);
363 }
364 Some(v)
365 }
366
367 fn get_last(&self, k: &K) -> Option<&V> {
368 self.0.get(k)?.last()
369 }
370
371 fn get_last_mut(&mut self, k: &K) -> Option<&mut V> {
372 self.0.get_mut(k)?.last_mut()
373 }
374
375 fn is_empty(&self) -> bool {
376 self.0.is_empty()
377 }
378}
379
380impl<S: Copy + Ord> Locals<S> {
381 fn push_sibling(&mut self, name: S, args: Box<[Arg<S>]>, def: Def) {
382 let tr = self.parents.clone();
383 self.funs.push(
384 (name, args.len()),
385 (Fun::Sibling(args, def, tr), self.vars.total),
386 );
387 }
388
389 fn pop_sibling(&mut self, name: S, arity: Arity) -> (Box<[Arg<S>]>, Def, Tr) {
390 let (y, vars) = match self.funs.pop(&(name, arity)) {
391 Some((Fun::Sibling(args, def, tr), vars)) => ((args, def, tr), vars),
392 _ => panic!(),
393 };
394 assert_eq!(self.vars.total, vars);
395 y
396 }
397
398 fn push_parent(&mut self, name: S, args: Box<[Arg<S>]>, def: Def) {
399 self.parents.insert(def.id);
400
401 let vars = self.vars.total;
402
403 for arg in args.iter() {
404 match arg {
405 Arg::Var(v) => self.vars.push(Bind::Var(*v)),
406 Arg::Fun(f) => self.push_arg(*f),
407 }
408 }
409
410 self.funs
411 .push((name, args.len()), (Fun::Parent(args, def), vars));
412 }
413
414 fn pop_parent(&mut self, name: S, arity: Arity) -> Def {
415 let (args, def, vars) = match self.funs.pop(&(name, arity)) {
416 Some((Fun::Parent(args, def), vars)) => (args, def, vars),
417 _ => panic!(),
418 };
419 for arg in args.iter().rev() {
420 match arg {
421 Arg::Var(v) => self.vars.pop(&Bind::Var(*v)),
422 Arg::Fun(f) => self.pop_arg(*f),
423 }
424 }
425 assert_eq!(self.vars.total, vars);
426 assert!(self.parents.remove(&def.id));
427 def
428 }
429
430 fn push_arg(&mut self, name: S) {
431 self.vars.push(Bind::Fun(name));
432 self.funs.push((name, 0), (Fun::Arg, self.vars.total));
433 }
434
435 fn pop_arg(&mut self, name: S) {
436 let vars = match self.funs.pop(&(name, 0)) {
437 Some((Fun::Arg, vars)) => vars,
438 _ => panic!(),
439 };
440 assert_eq!(self.vars.total, vars);
441 self.vars.pop(&Bind::Fun(name));
442 }
443
444 fn call(&mut self, name: S, args: &[TermId], tr: &Tr) -> Option<Term> {
445 Some(match self.funs.get_last_mut(&(name, args.len()))? {
446 (Fun::Arg, vars) => Term::Var(self.vars.total - *vars),
447 (Fun::Sibling(args_, def, tr_), vars) => {
448 tr_.retain(|id| tr.contains(id));
452 def.call(binds(args_, args), self.vars.total - *vars)
453 }
454 (Fun::Parent(args_, def), vars) => {
455 def.rec = true;
457 if !tr.contains(&def.id) {
461 def.tailrec = false;
462 }
463 let call = Some(Tailrec::Throw);
464 Term::CallDef(def.id, binds(args_, args), self.vars.total - *vars, call)
465 }
466 })
467 }
468
469 fn is_empty(&self) -> bool {
470 self.funs.is_empty() && self.vars.is_empty() && self.parents.is_empty()
471 }
472}
473
474type Tr = BTreeSet<TermId>;
477
478impl<'s, F> Compiler<&'s str, F> {
479 pub fn with_funs(mut self, funs: impl IntoIterator<Item = (&'s str, Box<[Arg]>, F)>) -> Self {
481 self.lut.funs = funs
482 .into_iter()
483 .map(|(name, args, f)| (Sig { name, args }, f))
484 .collect();
485 self
486 }
487
488 pub fn with_global_vars(self, global_vars: impl IntoIterator<Item = &'s str>) -> Self {
493 Self {
494 global_vars: global_vars.into_iter().collect(),
495 ..self
496 }
497 }
498
499 pub fn compile<P>(
501 mut self,
502 mods: load::Modules<&'s str, P>,
503 ) -> Result<Filter<F>, Errors<&'s str, P>> {
504 self.imported_vars = mods
505 .iter()
506 .enumerate()
507 .flat_map(|(mid, (_file, m))| m.vars.iter().map(move |(_path, x, _meta)| (*x, mid)))
508 .collect();
509
510 let mut errs = Vec::new();
511 for (file, m) in mods {
512 self.module(m);
513 if !self.errs.is_empty() {
514 errs.push((file, core::mem::take(&mut self.errs)));
515 }
516 assert!(self.locals.is_empty());
517 }
518
519 for t in self.lut.terms.iter_mut() {
528 match t {
529 Term::CallDef(id, .., tr) if !self.tailrecs.contains(id) => *tr = None,
530 _ => (),
531 }
532 }
533
534 if errs.is_empty() {
541 let (main_sig, main_def) = self.mod_map.last().unwrap().last().unwrap();
543 assert!(main_sig.matches("main", &[]));
544 assert!(!main_def.rec && main_def.tailrec);
545 Ok(Filter(main_def.id, self.lut.map_funs(|(_sig, f)| f)))
547 } else {
548 Err(errs)
549 }
550 }
551
552 fn with_label<T>(&mut self, label: &'s str, f: impl FnOnce(&mut Self) -> T) -> T {
553 self.locals.vars.push(Bind::Label(label));
554 let y = f(self);
555 self.locals.vars.pop(&Bind::Label(label));
556 y
557 }
558
559 fn with_vars<T>(&mut self, vars: &[&'s str], f: impl FnOnce(&mut Self) -> T) -> T {
560 vars.iter()
561 .for_each(|v| self.locals.vars.push(Bind::Var(v)));
562 let y = f(self);
563 vars.iter()
564 .rev()
565 .for_each(|v| self.locals.vars.pop(&Bind::Var(v)));
566 y
567 }
568
569 fn module(&mut self, m: load::Module<&'s str>) {
570 self.imported_mods.clear();
571 self.included_mods.clear();
572 for (mid, as_) in m.mods {
573 match as_ {
574 None => self.included_mods.push(mid),
575 Some(as_) => self.imported_mods.push((mid, as_)),
576 }
577 }
578
579 m.body.iter().for_each(|def| self.def_pre(def));
580 let defs = m.body.into_iter().rev().map(|def| self.def_post(def));
581 let mut defs: Vec<_> = defs.collect();
582 defs.reverse();
583 self.mod_map.push(defs)
584 }
585
586 fn def_pre(&mut self, d: &parse::Def<&'s str>) {
591 let tid = self.lut.insert_term(Term::Id);
592 let args = d.args.iter().map(|a| bind_from(a, *a)).collect();
593 let def = Def {
596 id: tid,
597 rec: false,
598 tailrec: true,
599 };
600 self.locals.push_sibling(d.name, args, def)
603 }
604
605 fn def_post(&mut self, d: parse::Def<&'s str>) -> (Sig<&'s str, Arg>, Def) {
607 let (args, def, mut tr) = self.locals.pop_sibling(d.name, d.args.len());
608 let tid = def.id;
609 self.locals.push_parent(d.name, args, def);
610 assert!(tr.insert(tid));
612 self.lut.terms[tid.0] = self.term(d.body, &tr);
613 let def = self.locals.pop_parent(d.name, d.args.len());
614 if def.rec && def.tailrec {
617 self.tailrecs.insert(def.id);
618 }
619 let sig = Sig {
620 name: d.name,
621 args: d.args.iter().map(|a| bind_from(a, ())).collect(),
622 };
623 (sig, def)
624 }
625
626 fn term(&mut self, t: parse::Term<&'s str>, tr: &Tr) -> Term {
627 use parse::Term::*;
628 match t {
629 Id => Term::Id,
630 Recurse => self.term(Call("!recurse", Vec::new()), &Tr::new()),
631 Arr(t) => Term::Arr(self.iterm(t.map_or_else(|| Call("!empty", Vec::new()), |t| *t))),
632 Neg(t) => Term::Neg(self.iterm(*t)),
633 Pipe(l, None, r) => Term::Pipe(self.iterm(*l), None, self.iterm_tr(*r, tr)),
634 Pipe(l, Some(pat), r) => {
635 let vars: Vec<_> = pat.vars().copied().collect();
636 let r = self.with_vars(&vars, |c| c.iterm_tr(*r, tr));
637 Term::Pipe(self.iterm(*l), Some(self.pattern(pat)), r)
638 }
639 Label(x, t) => Term::Label(self.with_label(x, |c| c.iterm(*t))),
640 Break(x) => self.break_(x),
641 IfThenElse(if_thens, else_) => {
642 let else_ = else_.map_or(Term::Id, |else_| self.term(*else_, tr));
643 if_thens.into_iter().rev().fold(else_, |acc, (if_, then_)| {
644 Term::Ite(
645 self.iterm(if_),
646 self.iterm_tr(then_, tr),
647 self.lut.insert_term(acc),
648 )
649 })
650 }
651 Var(x) => self.var(x),
652 Call(name, args) => {
653 let args: Box<[_]> = args.into_iter().map(|t| self.iterm(t)).collect();
654 if let Some((module, name)) = name.split_once("::") {
655 self.call_mod(module, name, &args)
656 } else {
657 self.call(name, &args, tr)
658 }
659 }
660 Def(defs, t) => {
661 defs.iter().for_each(|def| self.def_pre(def));
662 let t = self.term(*t, tr);
663 defs.into_iter().rev().for_each(|def| {
669 self.def_post(def);
670 });
671 t
672 }
673 Num(n) => n.parse().map_or_else(|_| Term::Num(n.into()), Term::Int),
674 TryCatch(try_, catch) => {
677 let catch = match catch {
678 None => Break(""),
679 Some(c) => BinOp(c, parse::BinaryOp::Comma, Break("").into()),
680 };
681 let tc = self.with_label("", |c| Term::TryCatch(c.iterm(*try_), c.iterm(catch)));
682 Term::Label(self.lut.insert_term(tc))
683 }
684 Fold(name, xs, pat, args) => {
685 use self::Fold::{Foreach, Reduce};
686 let arity = args.len();
687 let mut args = args.into_iter();
688 let (init, update) = match (args.next(), args.next()) {
689 (Some(init), Some(update)) => (init, update),
690 _ => return self.fail(name, Undefined::Filter(arity)),
691 };
692 let vars: Vec<_> = pat.vars().copied().collect();
693 let xs = self.iterm(*xs);
694 let pat = self.pattern(pat);
695 let init = self.iterm(init);
696 let update = self.with_vars(&vars, |c| c.iterm(update));
697
698 match (name, args.next(), args.next()) {
699 ("reduce", None, None) => Term::Fold(xs, pat, init, update, Reduce),
700 ("foreach", proj, None) => {
701 let proj = proj.map(|p| self.with_vars(&vars, |c| c.iterm_tr(p, tr)));
702 Term::Fold(xs, pat, init, update, Foreach(proj))
703 }
704 _ => self.fail(name, Undefined::Filter(arity)),
705 }
706 }
707 BinOp(l, op, r) => {
708 use parse::BinaryOp::*;
709 let (l, r) = match op {
710 Comma => (self.iterm_tr(*l, tr), self.iterm_tr(*r, tr)),
711 Alt => (self.iterm(*l), self.iterm_tr(*r, tr)),
712 _ => (self.iterm(*l), self.iterm(*r)),
713 };
714 match op {
715 Comma => Term::Comma(l, r),
716 Math(op) => Term::Math(l, op, r),
717 Assign => Term::Assign(l, r),
718 Update => Term::Update(l, r),
719 UpdateMath(op) => Term::UpdateMath(l, op, r),
720 Cmp(op) => Term::Cmp(l, op, r),
721 Or => Term::Logic(l, true, r),
722 And => Term::Logic(l, false, r),
723 Alt => Term::Alt(l, r),
724 UpdateAlt => Term::UpdateAlt(l, r),
725 }
726 }
727 Path(t, path) => {
728 let t = self.iterm(*t);
729 let path = path.0.into_iter();
730 let path = path.map(|(p, opt)| (p.map(|f| self.iterm(f)), opt));
731 Term::Path(t, crate::path::Path(path.collect()))
732 }
733 Str(fmt, parts) => {
734 use lex::StrPart;
735 let fmt = match fmt {
736 Some(fmt) => self.iterm(Call(fmt, Vec::new())),
737 None => self.lut.insert_term(Term::ToString),
738 };
739 let parts = parts.into_iter().map(|part| match part {
740 StrPart::Str(s) => Term::Str(s.into()),
741 StrPart::Char(c) => Term::Str(c.into()),
742 StrPart::Term(f) => Term::Pipe(self.iterm(f), None, fmt),
743 });
744 let parts = parts.collect();
745 self.sum_or(|| Term::Str(String::new()), parts)
746 }
747 Obj(o) => {
748 let kvs = o.into_iter().map(|(k, v)| self.obj_entry(k, v)).collect();
749 self.sum_or(|| Term::ObjEmpty, kvs)
750 }
751 }
752 }
753
754 fn iterm(&mut self, t: parse::Term<&'s str>) -> TermId {
758 self.iterm_tr(t, &Tr::new())
761 }
762
763 fn iterm_tr(&mut self, t: parse::Term<&'s str>, tr: &Tr) -> TermId {
764 let t = self.term(t, tr);
765 self.lut.insert_term(t)
766 }
767
768 fn pattern(&mut self, p: parse::Pattern<&'s str>) -> Pattern<TermId> {
769 match p {
770 parse::Pattern::Var(_) => Pattern::Var,
771 parse::Pattern::Arr(a) => {
772 let iter = a
773 .into_iter()
774 .enumerate()
775 .map(|(i, p)| (self.lut.insert_term(Term::Int(i as isize)), self.pattern(p)));
776 Pattern::Idx(iter.collect())
777 }
778 parse::Pattern::Obj(o) => {
779 let iter = o.into_iter().map(|(k, p)| (self.iterm(k), self.pattern(p)));
780 Pattern::Idx(iter.collect())
781 }
782 }
783 }
784
785 fn fail(&mut self, name: &'s str, undef: Undefined) -> Term {
786 self.errs.push((name, undef));
787 Term::default()
788 }
789
790 fn call_mod_id(&self, mid: ModId, name: &'s str, args: &[TermId]) -> Option<Term> {
791 let mut sig_defs = self.mod_map[mid].iter().rev();
792 let (sig, def) = sig_defs.find(|(sig, _)| sig.matches(name, args))?;
793 Some(def.call(binds(&sig.args, args), self.locals.vars.total))
794 }
795
796 fn call_mod(&mut self, module: &'s str, name: &'s str, args: &[TermId]) -> Term {
798 let mut imported_mods = self.imported_mods.iter().rev();
799 let mid = match imported_mods.find(|(_mid, module_)| module == *module_) {
800 Some((mid, _module)) => mid,
801 None => return self.fail(module, Undefined::Mod),
802 };
803 if let Some(call) = self.call_mod_id(*mid, name, args) {
804 return call;
805 }
806 self.fail(name, Undefined::Filter(args.len()))
807 }
808
809 fn call(&mut self, name: &'s str, args: &[TermId], tr: &Tr) -> Term {
811 if let Some(t) = self.locals.call(name, args, tr) {
812 return t;
813 }
814 for mid in self.included_mods.iter().rev() {
815 if let Some(call) = self.call_mod_id(*mid, name, args) {
816 return call;
817 }
818 }
819 for (nid, (sig, _f)) in self.lut.funs.iter().enumerate() {
820 if sig.matches(name, args) {
821 return Term::Native(nid, binds(&sig.args, args));
822 }
823 }
824
825 self.fail(name, Undefined::Filter(args.len()))
826 }
827
828 fn var(&mut self, x: &'s str) -> Term {
829 let mut i = self.locals.vars.total;
830
831 if let Some(v) = self.locals.vars.bound.get_last(&Bind::Var(x)) {
832 return Term::Var(i - v);
833 }
834 for (x_, mid) in self.imported_vars.iter().rev() {
835 if x == *x_ && *mid == self.mod_map.len() {
836 return Term::Var(i);
837 } else {
838 i += 1;
839 }
840 }
841 for x_ in self.global_vars.iter().rev() {
842 if x == *x_ {
843 return Term::Var(i);
844 } else {
845 i += 1;
846 }
847 }
848 self.fail(x, Undefined::Var)
849 }
850
851 fn break_(&mut self, x: &'s str) -> Term {
852 if let Some(l) = self.locals.vars.bound.get_last(&Bind::Label(x)) {
853 return Term::Var(self.locals.vars.total - l);
854 }
855 self.fail(x, Undefined::Label)
856 }
857
858 fn obj_entry(&mut self, k: parse::Term<&'s str>, v: Option<parse::Term<&'s str>>) -> Term {
859 let (k, v) = match (k, v) {
860 (parse::Term::Var(x), None) => (
861 self.lut.insert_term(Term::Str(x[1..].into())),
862 self.iterm(parse::Term::Var(x)),
863 ),
864 (k, None) => {
865 use crate::path::{Part, Path};
866 let k = self.iterm(k);
867 let path = Path::from(Part::Index(k));
868 let path = Term::Path(self.lut.insert_term(Term::Id), path);
869 (k, self.lut.insert_term(path))
870 }
871 (k, Some(v)) => (self.iterm(k), self.iterm(v)),
872 };
873 Term::ObjSingle(k, v)
874 }
875
876 fn sum_or(&mut self, f: impl FnOnce() -> Term, terms: Vec<Term>) -> Term {
877 use ops::Math::Add;
878 let mut iter = terms.into_iter().rev();
879 let last = iter.next().unwrap_or_else(f);
880 iter.fold(last, |acc, x| {
881 Term::Math(self.lut.insert_term(x), Add, self.lut.insert_term(acc))
882 })
883 }
884}