Skip to main content

wdl_format/
token.rs

1//! Tokens used during formatting.
2
3mod post;
4mod pre;
5
6use std::fmt::Display;
7use std::rc::Rc;
8
9pub use post::*;
10pub use pre::*;
11
12use crate::Config;
13
14/// Tokens that are streamable.
15pub trait Token: Eq + PartialEq {
16    /// Returns a displayable version of the token.
17    fn display<'a>(&'a self, config: &'a Config) -> impl Display + 'a;
18}
19
20/// A stream of tokens. Tokens in this case are either [`PreToken`]s or
21/// [`PostToken`]s. Note that, unless you are working on formatting
22/// specifically, you should never need to work with [`PostToken`]s.
23#[derive(Debug, Clone)]
24pub struct TokenStream<T: Token>(Vec<T>);
25
26impl<T: Token> Default for TokenStream<T> {
27    fn default() -> Self {
28        Self(Default::default())
29    }
30}
31
32impl<T: Token> TokenStream<T> {
33    /// Pushes a token into the stream.
34    pub fn push(&mut self, token: T) {
35        self.0.push(token);
36    }
37
38    /// Removes any number of `token`s at the end of the stream.
39    pub fn trim_end(&mut self, token: &T) {
40        while Some(token) == self.0.last() {
41            let _ = self.0.pop();
42        }
43    }
44
45    /// Removes any number of `token`s at the end of the stream.
46    pub fn trim_while<F: Fn(&T) -> bool>(&mut self, predicate: F) {
47        while let Some(token) = self.0.last() {
48            if !predicate(token) {
49                break;
50            }
51
52            let _ = self.0.pop();
53        }
54    }
55
56    /// Returns whether the stream is empty.
57    pub fn is_empty(&self) -> bool {
58        self.0.is_empty()
59    }
60
61    /// Returns an iterator over the tokens in the stream.
62    pub fn iter(&self) -> std::slice::Iter<'_, T> {
63        self.0.iter()
64    }
65
66    /// Clears the stream.
67    pub fn clear(&mut self) {
68        self.0.clear();
69    }
70
71    /// Extends the stream with the tokens from another stream.
72    pub fn extend(&mut self, other: Self) {
73        self.0.extend(other.0);
74    }
75}
76
77impl<T: Token> IntoIterator for TokenStream<T> {
78    type IntoIter = std::vec::IntoIter<Self::Item>;
79    type Item = T;
80
81    fn into_iter(self) -> Self::IntoIter {
82        self.0.into_iter()
83    }
84}
85
86/// The kind of comment.
87#[derive(Clone, Debug, Eq, PartialEq)]
88pub enum Comment {
89    /// A comment on its own line.
90    Preceding(Rc<String>),
91    /// A comment on the same line as the code preceding it.
92    Inline(Rc<String>),
93}
94
95/// Trivia.
96#[derive(Clone, Debug, Eq, PartialEq)]
97pub enum Trivia {
98    /// A blank line. This may be ignored by the postprocessor.
99    BlankLine,
100    /// A comment.
101    Comment(Comment),
102}
103
104/// The policy for [`Trivia::BlankLine`] line spacing.
105///
106/// Blank lines before comments and between comments are always permitted.
107#[derive(Eq, PartialEq, Default, Debug, Clone, Copy)]
108pub enum TriviaBlankLineSpacingPolicy {
109    /// Blank lines are allowed before and between comments, but not after.
110    ///
111    /// e.g. a comment, then a blank line, then code, followed by another blank
112    /// line, would have the trailing blank (between the comment and the code)
113    /// removed but any blank line before the comment would be preserved.
114    RemoveTrailingBlanks,
115    /// Blank lines are always allowed.
116    #[default]
117    Always,
118}