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