wdl_format/
token.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! Tokens used during formatting.

mod post;
mod pre;

use std::fmt::Display;

pub use post::*;
pub use pre::*;

use crate::Config;

/// Tokens that are streamable.
pub trait Token: Eq + PartialEq {
    /// Returns a displayable version of the token.
    fn display<'a>(&'a self, config: &'a Config) -> impl Display + 'a;
}

/// A stream of tokens. Tokens in this case are either [`PreToken`]s or
/// [`PostToken`]s. Note that, unless you are working on formatting
/// specifically, you should never need to work with [`PostToken`]s.
#[derive(Debug)]

pub struct TokenStream<T: Token>(Vec<T>);

impl<T: Token> Default for TokenStream<T> {
    fn default() -> Self {
        Self(Default::default())
    }
}

impl<T: Token> TokenStream<T> {
    /// Pushes a token into the stream.
    pub fn push(&mut self, token: T) {
        self.0.push(token);
    }

    /// Removes any number of `token`s at the end of the stream.
    pub fn trim_end(&mut self, token: &T) {
        while Some(token) == self.0.last() {
            let _ = self.0.pop();
        }
    }

    /// Removes any number of `token`s at the end of the stream.
    pub fn trim_while<F: Fn(&T) -> bool>(&mut self, predicate: F) {
        while let Some(token) = self.0.last() {
            if !predicate(token) {
                break;
            }

            let _ = self.0.pop();
        }
    }
}

impl<T: Token> IntoIterator for TokenStream<T> {
    type IntoIter = std::vec::IntoIter<Self::Item>;
    type Item = T;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

/// The kind of comment.
#[derive(Debug, Eq, PartialEq)]
pub enum Comment {
    /// A comment on its own line.
    Preceding(String),
    /// A comment on the same line as the code preceding it.
    Inline(String),
}

/// Trivia.
#[derive(Debug, Eq, PartialEq)]
pub enum Trivia {
    /// A blank line. This may be ignored by the postprocessor.
    BlankLine,
    /// A comment.
    Comment(Comment),
}

/// Whether optional blank lines are allowed in the current context.
#[derive(Eq, PartialEq, Default, Debug, Clone, Copy)]
pub enum LineSpacingPolicy {
    /// Blank lines are allowed before comments.
    BeforeComments,
    /// Blank lines are always allowed.
    #[default]
    Always,
}