boxworks/lang/
cst.rs

1//! Box language concrete syntax tree (CST).
2//!
3//! This module contains two representations of the Box CST.
4//!
5//! The type [`Tree`] is an **explicit representation** of a CST.
6//! It consists of Rust vectors of function calls ([`FuncCall`]).
7//! These calls contain Rust vectors of arguments ([`Arg`]).
8//! Some of these arguments may, in turn, contain nested trees if the argument
9//!     is a list type.
10//!
11//! The explicit representation is easy to use, but is inefficient
12//!     and makes using the CST a costly abstraction.
13//! The alternative representation is an **iterator representation**,
14//!     based on two traits [`TreeIter`] and [`ArgsIter`].
15//! With this representation, instead of materializing the CST at once
16//!     with a type like a [`Tree`], calling code instead iterates
17//!     over the tree.
18//!
19
20use super::lexer::ClosingParen;
21use super::Error;
22
23use super::lexer;
24use super::Str;
25use std::borrow::Cow;
26use std::collections::VecDeque;
27use std::fmt::Write;
28
29/// Iterator representation of a CST.
30pub trait TreeIter<'a>: Iterator<Item = TreeItem<'a, Self::ArgsIter>> {
31    /// Args iterator associated to this iterator.
32    type ArgsIter: ArgsIter<'a, TreeIter = Self>;
33
34    /// Return the remaining source to be parsed.
35    fn remaining_source(&self) -> Str<'a>;
36}
37
38/// Item returned by [`TreeIter`].
39pub enum TreeItem<'a, A> {
40    /// A function call, like `text("Hello", font=3)`.
41    FuncCall {
42        /// Name of the function
43        func_name: Str<'a>,
44        /// Iterator over the arguments of the function.
45        args: A,
46    },
47    /// A comment, like `# this is a comment`.
48    Comment {
49        /// Value of the comment.
50        value: &'a str,
51    },
52}
53
54/// Iterator over the arguments of a function.
55pub trait ArgsIter<'a>: Iterator<Item = ArgsItem<'a, Self::TreeIter>> {
56    /// Tree iterator associated to this iterator.
57    type TreeIter: TreeIter<'a, ArgsIter = Self>;
58}
59
60/// Item returned by [`ArgsIter`].
61pub enum ArgsItem<'a, F> {
62    /// A non-list argument, like `3pt` or `font=5`.
63    Regular {
64        /// Key of the argument, if present.
65        ///
66        /// This is populated for keyword arguments like `font=5`.
67        /// Positional arguments like `3pt` will have a value of `None` here.
68        key: Option<Str<'a>>,
69        /// Value of the argument.
70        value: Value<'a>,
71        /// Source of the value in the source code.
72        value_source: Str<'a>,
73    },
74    /// A list argument.
75    List {
76        /// Key of the argument, if present.
77        ///
78        /// This is populated for keyword arguments like `font=5`.
79        /// Positional arguments like `3pt` will have a value of `None` here.
80        key: Option<Str<'a>>,
81        /// Opening square brace.
82        square_open: Str<'a>,
83        /// Iterator over the items in this list.
84        ///
85        /// This will satisfy the [`TreeIter`] trait.
86        tree: F,
87    },
88    /// A comment.
89    Comment {
90        /// Value of the comment.
91        value: &'a str,
92    },
93}
94
95/// Pretty print a Box CST.
96pub fn pretty_print<'a, W: std::fmt::Write>(
97    w: &mut W,
98    tree: impl TreeIter<'a>,
99) -> std::fmt::Result {
100    pretty_print_impl(w, tree, 0)?;
101    Ok(())
102}
103
104#[derive(Default)]
105struct ArgsPrinter<'a> {
106    indent: usize,
107    multiline: bool,
108    buf: Vec<(Option<Str<'a>>, Value<'a>)>,
109}
110
111impl<'a> ArgsPrinter<'a> {
112    fn activate_multiline<W: std::fmt::Write>(&mut self, w: &mut W) -> std::fmt::Result {
113        self.multiline = true;
114        for (key, value) in &self.buf {
115            self.print_multiline(w, key, value)?;
116        }
117        self.buf.clear();
118        Ok(())
119    }
120    fn print<W: std::fmt::Write>(
121        &mut self,
122        w: &mut W,
123        key: Option<Str<'a>>,
124        value: Value<'a>,
125    ) -> std::fmt::Result {
126        if self.buf.len() >= 4 {
127            self.activate_multiline(w)?;
128        }
129        if self.multiline {
130            self.print_multiline(w, &key, &value)?;
131        } else {
132            self.buf.push((key, value));
133        }
134        Ok(())
135    }
136    fn print_multiline<W: std::fmt::Write>(
137        &self,
138        w: &mut W,
139        key: &Option<Str<'a>>,
140        value: &Value<'a>,
141    ) -> std::fmt::Result {
142        let indent = Indent(self.indent);
143        write!(w, "\n{indent}  ")?;
144        if let Some(key) = key {
145            write!(w, "{key}=")?;
146        }
147        write!(w, "{},", value)?;
148        Ok(())
149    }
150    fn flush<W: std::fmt::Write>(&mut self, w: &mut W) -> std::fmt::Result {
151        let mut remaining_args = self.buf.len();
152        for (keyword, arg) in &self.buf {
153            if let Some(keyword) = keyword {
154                write!(w, "{keyword}=")?;
155            }
156            write!(w, "{}", arg)?;
157            remaining_args = remaining_args.saturating_sub(1);
158            if remaining_args > 0 {
159                write!(w, ", ")?;
160            }
161        }
162        let indent = Indent(self.indent);
163        if self.multiline {
164            write!(w, "\n{indent}")?;
165        }
166        self.buf.clear();
167        self.multiline = false;
168        Ok(())
169    }
170}
171
172struct Indent(usize);
173
174impl std::fmt::Display for Indent {
175    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176        for _ in 0..self.0 {
177            f.write_char(' ')?;
178        }
179        Ok(())
180    }
181}
182
183fn pretty_print_impl<'a, W: std::fmt::Write, T: TreeIter<'a>>(
184    w: &mut W,
185    tree: T,
186    depth: usize,
187) -> std::fmt::Result {
188    let indent = Indent(depth);
189    let mut ap: ArgsPrinter = ArgsPrinter {
190        indent: depth,
191        ..Default::default()
192    };
193    // If this is not the root tree, print the opening brace.
194    if depth.checked_sub(2).is_some() {
195        write!(w, "[")?;
196    }
197    let mut has_items = false;
198    for (i, item) in tree.enumerate() {
199        if i == 0 {
200            has_items = true;
201            if depth.checked_sub(2).is_some() {
202                writeln!(w)?;
203            }
204        }
205        match item {
206            TreeItem::FuncCall { func_name, args } => {
207                write!(w, "{indent}{func_name}(")?;
208                for item in args {
209                    match item {
210                        ArgsItem::Comment { value } => {
211                            ap.activate_multiline(w)?;
212                            write!(w, "\n{indent}  #{value}")?;
213                        }
214                        ArgsItem::Regular {
215                            key,
216                            value,
217                            value_source: _,
218                        } => {
219                            ap.print(w, key, value)?;
220                        }
221                        ArgsItem::List {
222                            key,
223                            square_open: _,
224                            tree,
225                        } => {
226                            ap.activate_multiline(w)?;
227                            //
228                            write!(w, "\n{indent}  ")?;
229                            if let Some(key) = key {
230                                write!(w, "{key}=")?;
231                            }
232                            pretty_print_impl(w, tree, depth + 4)?;
233                        }
234                    }
235                }
236                ap.flush(w)?;
237                writeln!(w, ")")?;
238            }
239            TreeItem::Comment { value } => {
240                writeln!(w, "{indent}#{value}")?;
241            }
242        };
243    }
244    // If this is not the root tree, print the closing brace.
245    if let Some(prev_depth) = depth.checked_sub(2) {
246        if has_items {
247            write!(w, "{}],", Indent(prev_depth))?;
248        } else {
249            write!(w, "],")?;
250        }
251    }
252    Ok(())
253}
254
255/// Explicit representation of a CST.
256#[derive(Debug, Default, PartialEq, Clone)]
257pub struct Tree<'a> {
258    pub calls: Vec<FuncCall<'a>>,
259    pub trailing_comments: Vec<&'a str>,
260}
261
262impl<'a> Tree<'a> {
263    /// Built a CST from a tree iterator.
264    pub fn build(tree: impl TreeIter<'a>) -> Self {
265        Self::build_impl(tree)
266    }
267
268    fn build_impl<I: TreeIter<'a>>(tree: I) -> Self {
269        let mut comments = vec![];
270        let take_comments = |comments: &mut Vec<&'a str>| {
271            let mut v = vec![];
272            std::mem::swap(&mut v, comments);
273            v
274        };
275        let calls = tree
276            .filter_map(|item| match item {
277                TreeItem::FuncCall { func_name, args } => {
278                    let func_comments = take_comments(&mut comments);
279                    let args: Vec<Arg<'a>> = args
280                        .filter_map(|item| match item {
281                            ArgsItem::Regular {
282                                key,
283                                value,
284                                value_source,
285                            } => Some(Arg {
286                                comments: take_comments(&mut comments),
287                                key,
288                                value,
289                                value_source,
290                            }),
291                            ArgsItem::List {
292                                key,
293                                square_open: _,
294                                tree,
295                            } => {
296                                let value_source = tree.remaining_source();
297                                let inner_tree = Tree::build_impl(tree);
298                                Some(Arg {
299                                    comments: take_comments(&mut comments),
300                                    key,
301                                    value: Value::List(inner_tree),
302                                    value_source,
303                                })
304                            }
305                            ArgsItem::Comment { value } => {
306                                comments.push(value);
307                                None
308                            }
309                        })
310                        .collect();
311                    Some(FuncCall {
312                        comments: func_comments,
313                        func_name,
314                        args,
315                        trailing_comments: take_comments(&mut comments),
316                    })
317                }
318                TreeItem::Comment { value } => {
319                    comments.push(value);
320                    None
321                }
322            })
323            .collect();
324        Self {
325            calls,
326            trailing_comments: comments,
327        }
328    }
329
330    pub fn iter<'b>(&'b self) -> impl TreeIter<'a> + 'b {
331        let mut iter = ExplicitIter { tree_stack: vec![] };
332        iter.push_tree(self);
333        iter
334    }
335}
336
337impl<'a> std::fmt::Display for Tree<'a> {
338    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
339        pretty_print(f, self.iter())
340    }
341}
342
343/// Iterator over an explicit CST.
344struct ExplicitIter<'a, 'b> {
345    tree_stack: Vec<TreeStackElem<'a, 'b>>,
346}
347
348enum TreeStackElem<'a, 'b> {
349    FuncCall(&'b FuncCall<'a>),
350    Comments(&'b [&'a str]),
351}
352
353/// Iterator over an explicit CST.
354struct ExplicitArgsIter<'a, 'b> {
355    args_stack: Vec<ArgsStackElem<'a, 'b>>,
356}
357
358enum ArgsStackElem<'a, 'b> {
359    Arg(&'b Arg<'a>),
360    Comments(&'b [&'a str]),
361}
362
363impl<'a, 'b> ExplicitIter<'a, 'b> {
364    fn push_tree(&mut self, t: &'b Tree<'a>) {
365        self.tree_stack
366            .push(TreeStackElem::Comments(&t.trailing_comments));
367        for call in t.calls.iter().rev() {
368            self.push_func_call(call);
369        }
370    }
371    fn push_func_call(&mut self, call: &'b FuncCall<'a>) {
372        self.tree_stack.push(TreeStackElem::FuncCall(call));
373        self.tree_stack
374            .push(TreeStackElem::Comments(&call.comments));
375    }
376}
377
378impl<'a, 'b> ExplicitArgsIter<'a, 'b> {
379    fn push_args(&mut self, call: &'b FuncCall<'a>) {
380        self.args_stack
381            .push(ArgsStackElem::Comments(&call.trailing_comments));
382        for a in call.args.iter().rev() {
383            self.args_stack.push(ArgsStackElem::Arg(a));
384            self.args_stack.push(ArgsStackElem::Comments(&a.comments));
385        }
386    }
387}
388
389impl<'a, 'b> TreeIter<'a> for ExplicitIter<'a, 'b> {
390    type ArgsIter = ExplicitArgsIter<'a, 'b>;
391
392    fn remaining_source(&self) -> Str<'a> {
393        "".into()
394    }
395}
396
397impl<'a, 'b> Iterator for ExplicitIter<'a, 'b> {
398    type Item = TreeItem<'a, ExplicitArgsIter<'a, 'b>>;
399
400    fn next(&mut self) -> Option<Self::Item> {
401        loop {
402            match self.tree_stack.pop()? {
403                TreeStackElem::FuncCall(func_call) => {
404                    let mut iter = ExplicitArgsIter { args_stack: vec![] };
405                    iter.push_args(func_call);
406                    return Some(TreeItem::FuncCall {
407                        func_name: func_call.func_name.clone(),
408                        args: iter,
409                    });
410                }
411                TreeStackElem::Comments(items) => {
412                    if let Some((head, tail)) = items.split_first() {
413                        self.tree_stack.push(TreeStackElem::Comments(tail));
414                        return Some(TreeItem::Comment { value: head });
415                    }
416                }
417            }
418        }
419    }
420}
421
422impl<'a, 'b> ArgsIter<'a> for ExplicitArgsIter<'a, 'b> {
423    type TreeIter = ExplicitIter<'a, 'b>;
424}
425
426impl<'a, 'b> Iterator for ExplicitArgsIter<'a, 'b> {
427    type Item = ArgsItem<'a, ExplicitIter<'a, 'b>>;
428
429    fn next(&mut self) -> Option<Self::Item> {
430        loop {
431            match self.args_stack.pop()? {
432                ArgsStackElem::Arg(arg) => {
433                    return match arg.value.try_clone_value() {
434                        Ok(v) => Some(ArgsItem::Regular {
435                            key: arg.key.clone(),
436                            value: v,
437                            value_source: arg.value_source.clone(),
438                        }),
439                        Err(tree) => {
440                            let mut iter = ExplicitIter { tree_stack: vec![] };
441                            iter.push_tree(tree);
442                            Some(ArgsItem::List {
443                                key: arg.key.clone(),
444                                square_open: "".into(),
445                                tree: iter,
446                            })
447                        }
448                    };
449                }
450                ArgsStackElem::Comments(items) => {
451                    if let Some((head, tail)) = items.split_first() {
452                        self.args_stack.push(ArgsStackElem::Comments(tail));
453                        return Some(ArgsItem::Comment { value: head });
454                    }
455                }
456            }
457        }
458    }
459}
460
461/// Parse Box language source code into a CST.
462pub fn parse<'a>(source: &'a str, errs: super::ErrorAccumulator<'a>) -> impl TreeIter<'a> {
463    let lexer = lexer::Lexer::new(source, errs.clone());
464    parse_using_lexer(lexer, errs)
465}
466
467/// Parse into a CST using an explicitly provided lexer.
468///
469/// In general it's easier to use the [`parse`] function.
470pub fn parse_using_lexer<'a>(
471    lexer: lexer::Lexer<'a>,
472    errs: super::ErrorAccumulator<'a>,
473) -> impl TreeIter<'a> {
474    ParseTreeIter {
475        next_tree: None,
476        c: ParseIterCommon {
477            comments: Default::default(),
478            next_token: None,
479            lexer,
480            errs,
481        },
482    }
483}
484
485struct ParseTreeIter<'a> {
486    next_tree: Option<(Str<'a>, lexer::Lexer<'a>)>,
487    c: ParseIterCommon<'a>,
488}
489
490struct ParseArgsIter<'a> {
491    next_arg: Option<ArgsItem<'a, ParseTreeIter<'a>>>,
492    c: ParseIterCommon<'a>,
493}
494
495struct ParseIterCommon<'a> {
496    comments: VecDeque<&'a str>,
497    next_token: Option<lexer::Token<'a>>,
498    lexer: lexer::Lexer<'a>,
499    errs: super::ErrorAccumulator<'a>,
500}
501
502impl<'a> ParseIterCommon<'a> {
503    fn refill(&mut self) {
504        if self.next_token.is_some() {
505            return;
506        }
507        for token in self.lexer.by_ref() {
508            match token.value {
509                lexer::TokenValue::Comment => {
510                    self.comments.push_back(token.source.str());
511                }
512                lexer::TokenValue::SquareClose | lexer::TokenValue::RoundClose => {
513                    self.errs.add(super::Error::UnmatchedClosingBracket {
514                        close: token.source,
515                    });
516                }
517                _ => {
518                    self.next_token = Some(token);
519                    break;
520                }
521            }
522        }
523    }
524
525    fn parse_optional<F: Fn(&lexer::Token<'a>) -> bool>(&mut self, f: F) {
526        self.refill();
527        if let Some(token) = &self.next_token {
528            if f(token) {
529                self.next_token = None;
530            }
531        }
532    }
533
534    fn parse_required<T, F: FnMut(lexer::Token<'a>) -> Option<T>>(
535        &mut self,
536        mut f: F,
537        want: &'static str,
538    ) -> Option<T> {
539        loop {
540            self.refill();
541            let token = self.next_token.take()?;
542            enum Skipped {
543                Parens(Option<ClosingParen>),
544                Other,
545            }
546            let skipped = match token.value {
547                lexer::TokenValue::SquareOpen { closing }
548                | lexer::TokenValue::RoundOpen { closing } => Skipped::Parens(closing),
549                _ => Skipped::Other,
550            };
551            let token_source = token.source.clone();
552            if let Some(t) = f(token) {
553                return Some(t);
554            }
555            let skipped = match skipped {
556                Skipped::Parens(closing) => {
557                    let inner = self.lexer.split_nested(closing);
558                    let mut s = inner.remaining_source();
559                    include_parens(&mut s);
560                    s
561                }
562                Skipped::Other => token_source.clone(),
563            };
564            self.errs.add(Error::UnexpectedToken {
565                want,
566                got: token_source,
567                skipped,
568            });
569        }
570    }
571}
572
573fn include_parens(s: &mut Str) {
574    // We include the '[' before...
575    if let Some(i) = s.start.checked_sub(1) {
576        if (s.value.as_bytes()[i] as u32) == ('[' as u32)
577            || (s.value.as_bytes()[i] as u32) == ('(' as u32)
578        {
579            s.start = i;
580        }
581    }
582    // ...and the ']' after
583    if s.value[s.end..].starts_with(']') || s.value[s.end..].starts_with(')') {
584        s.end += 1;
585    }
586}
587
588impl<'a> TreeIter<'a> for ParseTreeIter<'a> {
589    type ArgsIter = ParseArgsIter<'a>;
590    fn remaining_source(&self) -> Str<'a> {
591        let mut s = self.c.lexer.remaining_source();
592        include_parens(&mut s);
593        s
594    }
595}
596
597impl<'a> Iterator for ParseTreeIter<'a> {
598    type Item = TreeItem<'a, ParseArgsIter<'a>>;
599
600    fn next(&mut self) -> Option<Self::Item> {
601        if let Some(comment) = self.c.comments.pop_front() {
602            return Some(TreeItem::Comment { value: comment });
603        }
604        if let Some((func_name, lexer)) = self.next_tree.take() {
605            return Some(TreeItem::FuncCall {
606                func_name,
607                args: ParseArgsIter {
608                    next_arg: None,
609                    c: ParseIterCommon {
610                        comments: Default::default(),
611                        next_token: None,
612                        lexer,
613                        errs: self.c.errs.clone(),
614                    },
615                },
616            });
617        }
618
619        // parse function name
620        let func_name_or = self.c.parse_required(
621            |token| match token.value {
622                lexer::TokenValue::Keyword => Some(token.source),
623                _ => None,
624            },
625            "a function name",
626        );
627        let func_name = match func_name_or {
628            Some(func_name) => func_name,
629            None => {
630                if self.c.comments.is_empty() {
631                    return None;
632                }
633                return self.next();
634            }
635        };
636        // parse (
637        let closing_or = self.c.parse_required(
638            |token| match token.value {
639                lexer::TokenValue::RoundOpen { closing } => Some(closing),
640                _ => None,
641            },
642            "opening parenthesis",
643        );
644        let closing = match closing_or {
645            Some(closing) => closing,
646            None => {
647                self.c.errs.add(Error::MissingArgsForFunction {
648                    function_name: func_name,
649                });
650                return self.next();
651            }
652        };
653        let inner = self.c.lexer.split_nested(closing);
654        self.next_tree = Some((func_name, inner));
655        self.next()
656    }
657}
658
659impl<'a> ArgsIter<'a> for ParseArgsIter<'a> {
660    type TreeIter = ParseTreeIter<'a>;
661}
662
663impl<'a> Iterator for ParseArgsIter<'a> {
664    type Item = ArgsItem<'a, ParseTreeIter<'a>>;
665
666    fn next(&mut self) -> Option<Self::Item> {
667        if let Some(comment) = self.c.comments.pop_front() {
668            return Some(ArgsItem::Comment { value: comment });
669        }
670        if let Some(next) = self.next_arg.take() {
671            return Some(next);
672        }
673
674        enum ArgStart<'a> {
675            Value(lexer::Token<'a>),
676            Keyword(Str<'a>),
677        }
678        let start = self.c.parse_required(
679            |token| {
680                use lexer::TokenValue;
681                match token.value {
682                    TokenValue::String(_)
683                    | TokenValue::Integer(_)
684                    | TokenValue::Scaled(_)
685                    | TokenValue::InfiniteGlue(_, _)
686                    | TokenValue::SquareOpen { .. } => Some(ArgStart::Value(token)),
687                    lexer::TokenValue::Keyword => Some(ArgStart::Keyword(token.source)),
688                    _ => None,
689                }
690            },
691            "a function argument",
692        );
693        let Some(start) = start else {
694            if self.c.comments.is_empty() {
695                return None;
696            }
697            return self.next();
698        };
699        let (key, value) = match start {
700            ArgStart::Keyword(key) => {
701                self.c.parse_required(
702                    |token| match token.value {
703                        lexer::TokenValue::Equal => Some(()),
704                        _ => None,
705                    },
706                    "an equals",
707                );
708                let value = self.c.parse_required(
709                    |token| {
710                        use lexer::TokenValue;
711                        match token.value {
712                            TokenValue::String(_)
713                            | TokenValue::Integer(_)
714                            | TokenValue::Scaled(_)
715                            | TokenValue::InfiniteGlue(_, _)
716                            | TokenValue::SquareOpen { .. } => Some(token),
717                            _ => None,
718                        }
719                    },
720                    "value of a keyword argument",
721                );
722                let Some(value) = value else {
723                    self.c
724                        .errs
725                        .add(Error::IncompleteKeywordArg { keyword: key });
726                    return self.next();
727                };
728                (Some(key), value)
729            }
730            ArgStart::Value(value) => (None, value),
731        };
732        let mut c = None;
733        let value_v = match value.value {
734            lexer::TokenValue::String(s) => Value::String(s),
735            lexer::TokenValue::Integer(n) => Value::Integer(n),
736            lexer::TokenValue::Scaled(n) => Value::Scaled(n),
737            lexer::TokenValue::InfiniteGlue(s, o) => Value::InfiniteGlue(s, o),
738            lexer::TokenValue::SquareOpen { closing } => {
739                c = closing;
740                Value::List(Default::default())
741            }
742            _ => unreachable!(),
743        };
744        self.next_arg = Some(match value_v {
745            Value::List(_) => {
746                let lexer = self.c.lexer.split_nested(c);
747                ArgsItem::List {
748                    key,
749                    square_open: value.source,
750                    tree: ParseTreeIter {
751                        next_tree: None,
752                        c: ParseIterCommon {
753                            comments: Default::default(),
754                            next_token: None,
755                            lexer,
756                            errs: self.c.errs.clone(),
757                        },
758                    },
759                }
760            }
761            value_v => ArgsItem::Regular {
762                key,
763                value: value_v,
764                value_source: value.source,
765            },
766        });
767        // Consume an optional ',' after the value.
768        self.c
769            .parse_optional(|token| matches!(token.value, lexer::TokenValue::Comma));
770        self.next()
771    }
772}
773
774/// An argument to a function.
775#[derive(Debug, Clone)]
776pub struct Arg<'a> {
777    /// Comments preceding the argument.
778    pub comments: Vec<&'a str>,
779    /// For positional arguments the key is [`None`];
780    /// for keyword arguments the key is the name provided.
781    pub key: Option<Str<'a>>,
782    pub value: Value<'a>,
783    pub value_source: Str<'a>,
784}
785
786impl<'a> PartialEq for Arg<'a> {
787    fn eq(&self, other: &Self) -> bool {
788        let eq = self.comments == other.comments && self.value == other.value;
789        // We only compare sources if they are both provided.
790        if self.value_source.is_empty() || other.value_source.is_empty() {
791            eq
792        } else {
793            eq && self.value_source == other.value_source
794        }
795    }
796}
797
798/// The value of an argument to a function.
799#[derive(Debug, PartialEq, Clone)]
800pub enum Value<'a> {
801    Integer(i32),
802    Scaled(common::Scaled),
803    InfiniteGlue(common::Scaled, common::GlueOrder),
804    String(Cow<'a, str>),
805    List(Tree<'a>),
806}
807
808impl<'a> Value<'a> {
809    /// Attempts to clone the value.
810    ///
811    /// This method is intended for fast code, and will accordingly not clone a tree.
812    /// If the value is a tree, it returns the tree in the error payload.
813    pub fn try_clone_value(&self) -> Result<Self, &Tree<'a>> {
814        use Value::*;
815        let ok = match self {
816            Integer(i) => Integer(*i),
817            Scaled(scaled) => Scaled(*scaled),
818            InfiniteGlue(scaled, glue_order) => InfiniteGlue(*scaled, *glue_order),
819            // TODO: the string clone here is pretty bad.
820            // May be better to have a cheap clonable string.
821            String(cow) => String(cow.clone()),
822            List(tree) => return Err(tree),
823        };
824        Ok(ok)
825    }
826    pub fn description(&self) -> &'static str {
827        use Value::*;
828        match self {
829            Integer(_) => "an integer",
830            Scaled(_) => "a number",
831            InfiniteGlue(_, _) => "an infinite glue component",
832            String(_) => "a string",
833            List(_) => "a list",
834        }
835    }
836}
837
838impl<'a> std::fmt::Display for Value<'a> {
839    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
840        use Value::*;
841        match self {
842            Integer(i) => write!(f, "{i}"),
843            Scaled(scaled) => write!(f, "{scaled}"),
844            InfiniteGlue(scaled, glue_order) => {
845                write!(f, "{}{glue_order}", scaled.display_no_units())
846            }
847            String(str) => {
848                write!(f, r#"""#)?;
849                for c in str.chars() {
850                    write!(f, "{}", c.escape_debug())?;
851                }
852                write!(f, r#"""#)
853            }
854            List(tree) => write!(f, "{tree}"),
855        }
856    }
857}
858
859/// A function call.
860#[derive(Debug, PartialEq, Clone)]
861pub struct FuncCall<'a> {
862    /// Comments before the function call.
863    pub comments: Vec<&'a str>,
864    /// Name of the function.
865    pub func_name: Str<'a>,
866    /// Arguments to the function.
867    pub args: Vec<Arg<'a>>,
868    /// Comments between the last argument and the closing parenthesis.
869    pub trailing_comments: Vec<&'a str>,
870}
871
872impl<'a> FuncCall<'a> {
873    pub fn iter<'b>(&'b self) -> impl TreeIter<'a> + 'b {
874        let mut iter = ExplicitIter { tree_stack: vec![] };
875        iter.push_func_call(self);
876        iter
877    }
878}
879
880impl<'a> std::fmt::Display for FuncCall<'a> {
881    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
882        pretty_print(f, self.iter())
883    }
884}
885
886#[cfg(test)]
887mod tests {
888
889    use super::super::error::ErrorAccumulator;
890    use super::*;
891
892    fn run_parse_test(input: &str, want: Vec<FuncCall>) {
893        let want = Tree {
894            calls: want,
895            trailing_comments: vec![],
896        };
897        let errs: ErrorAccumulator = Default::default();
898        let got = Tree::build(parse(input, errs.clone()));
899        assert_eq!(got, want);
900        assert_eq!(Ok(()), errs.check());
901    }
902
903    fn run_convert_test(input: Vec<FuncCall>) {
904        let tree = Tree {
905            calls: input,
906            trailing_comments: vec![],
907        };
908        let got = Tree::build(tree.iter());
909        assert_eq!(got, tree);
910    }
911
912    macro_rules! cst_tests {
913        ( $( (
914            $name: ident,
915            $input: expr,
916            $want: expr,
917        ), )+ ) => {
918            $(
919                mod $name {
920                    use super::*;
921                    #[test]
922                    fn parse_test() {
923                        let input = $input;
924                        let want = $want;
925                        run_parse_test(&input, want);
926                    }
927                    #[test]
928                    fn convert_test() {
929                        let input = $want;
930                        run_convert_test(input);
931                    }
932                }
933            )+
934        };
935    }
936
937    cst_tests!(
938        (
939            basic_case,
940            "a(b=[c()])",
941            vec![FuncCall {
942                comments: vec![],
943                func_name: "a".into(),
944                args: vec![Arg {
945                    comments: vec![],
946                    key: Some("b".into()),
947                    value: Value::List(Tree {
948                        calls: vec![FuncCall {
949                            comments: vec![],
950                            func_name: "c".into(),
951                            args: vec![],
952                            trailing_comments: vec![],
953                        }],
954                        trailing_comments: vec![],
955                    }),
956                    value_source: "[c()]".into(),
957                },],
958                trailing_comments: vec![],
959            }],
960        ),
961        (
962            comma_after_list,
963            "a(b=[],)",
964            vec![FuncCall {
965                comments: vec![],
966                func_name: "a".into(),
967                args: vec![Arg {
968                    comments: vec![],
969                    key: Some("b".into()),
970                    value: Value::List(Default::default()),
971                    value_source: "[]".into(),
972                },],
973                trailing_comments: vec![],
974            }],
975        ),
976        (
977            comment_in_empty_list,
978            "a(b=[#X\n])",
979            vec![FuncCall {
980                comments: vec![],
981                func_name: "a".into(),
982                args: vec![Arg {
983                    comments: vec![],
984                    key: Some("b".into()),
985                    value: Value::List(Tree {
986                        calls: vec![],
987                        trailing_comments: vec!["X"]
988                    }),
989                    value_source: "[#X\n]".into(),
990                },],
991                trailing_comments: vec![],
992            }],
993        ),
994    );
995
996    fn run_comments_test(
997        input: &str,
998        func_comments: Vec<&'static str>,
999        arg_1_comments: Vec<&'static str>,
1000        arg_2_comments: Vec<&'static str>,
1001        trailing_comments: Vec<&'static str>,
1002    ) {
1003        let want = vec![FuncCall {
1004            comments: func_comments,
1005            func_name: "f".into(),
1006            args: vec![
1007                Arg {
1008                    comments: arg_1_comments,
1009                    key: None,
1010                    value: Value::Integer(3),
1011                    value_source: "3".into(),
1012                },
1013                Arg {
1014                    comments: arg_2_comments,
1015                    key: Some("key".into()),
1016                    value: Value::Integer(4),
1017                    value_source: "4".into(),
1018                },
1019            ],
1020            trailing_comments,
1021        }];
1022        run_parse_test(input, want.clone());
1023        run_convert_test(want);
1024    }
1025
1026    macro_rules! comment_tests {
1027        ( $( (
1028            $name: ident,
1029            $input: expr,
1030            $(
1031                func_comments: $func_comments: expr,
1032            )?
1033            $(
1034                arg_1_comments: $arg_1_comments: expr,
1035            )?
1036            $(
1037                arg_2_comments: $arg_2_comments: expr,
1038            )?
1039            $(
1040                trailing_comments: $trailing_comments: expr,
1041            )?
1042        ), )+ ) => {
1043            $(
1044                #[test]
1045                #[allow(unused_assignments, unused_mut)]
1046                fn $name() {
1047                    let input = $input;
1048                    let mut func_comments = vec![];
1049                    $(
1050                        func_comments = $func_comments;
1051                    )?
1052                    let mut arg_1_comments = vec![];
1053                    $(
1054                        arg_1_comments = $arg_1_comments;
1055                    )?
1056                    let mut arg_2_comments = vec![];
1057                    $(
1058                        arg_2_comments = $arg_2_comments;
1059                    )?
1060                    let mut trailing_comments = vec![];
1061                    $(
1062                        trailing_comments = $trailing_comments;
1063                    )?
1064                    run_comments_test(&input, func_comments, arg_1_comments, arg_2_comments, trailing_comments);
1065                }
1066            )+
1067        };
1068    }
1069
1070    comment_tests!(
1071        (
1072            comment_0,
1073            "f(3,key=4,)",
1074        ),
1075        (
1076            comment_1,
1077            "#X\nf(3,key=4,)",
1078            func_comments: vec!["X"],
1079        ),
1080        (
1081            comment_2,
1082            "f#X\n(3,key=4,)",
1083            func_comments: vec!["X"],
1084        ),
1085        (
1086            comment_3,
1087            "f(#X\n3,key=4,)",
1088            arg_1_comments: vec!["X"],
1089        ),
1090        (
1091            comment_4,
1092            "f(3#X\n,key=4,)",
1093            arg_1_comments: vec!["X"],
1094        ),
1095        (
1096            comment_5,
1097            "f(3,#X\nkey=4,)",
1098            arg_2_comments: vec!["X"],
1099        ),
1100        (
1101            comment_6,
1102            "f(3,key#X\n=4,)",
1103            arg_2_comments: vec!["X"],
1104        ),
1105        (
1106            comment_7,
1107            "f(3,key=#X\n4,)",
1108            arg_2_comments: vec!["X"],
1109        ),
1110        (
1111            comment_8,
1112            "f(3,key=4#X\n,)",
1113            arg_2_comments: vec!["X"],
1114        ),
1115        (
1116            comment_9,
1117            "f(3,key=4,#X\n)",
1118            trailing_comments: vec!["X"],
1119        ),
1120        (
1121            comment_10,
1122            "f(3,key=4#X\n)",
1123            arg_2_comments: vec!["X"],
1124        ),
1125        // TODO: f([#X\n],)
1126        // TODO: f([],#X\n)
1127        // TODO: f([]#X\n,)
1128    );
1129}