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}