1 //! Types for the intermediate representation of the macro input. This parsed
2 //! representation allows the functions in `gen.rs` to work more easily.
3 
4 use proc_macro2::{Span, TokenStream};
5 use std::collections::HashMap;
6 
7 
8 /// Input for the `write!` and `writeln!` macro.
9 #[derive(Debug)]
10 pub(crate) struct WriteInput {
11     pub(crate) target: Expr,
12     pub(crate) format_str: FormatStr,
13     pub(crate) args: FormatArgs,
14 }
15 
16 /// Our own `expr` type. We use this instead of `syn` to avoid `syn`
17 /// alltogether. We don't need to introspect the expression, we just need to
18 /// skip over them and the emit them again.
19 #[derive(Debug)]
20 pub(crate) struct Expr {
21     pub(crate) span: Span,
22     pub(crate) tokens: TokenStream,
23 }
24 
25 /// A parsed format string.
26 #[derive(Debug)]
27 pub(crate) struct FormatStr {
28     pub(crate) fragments: Vec<FormatStrFragment>,
29 }
30 
31 impl FormatStr {
32     /// Adds `\n` to the end of the formatting string.
add_newline(&mut self)33     pub(crate) fn add_newline(&mut self) {
34         match self.fragments.last_mut() {
35             // If the last fragment is an `fmt` one, we can easily add the
36             // newline to its last part (which is guaranteed to exist).
37             Some(FormatStrFragment::Fmt { fmt_str_parts, .. }) => {
38                 fmt_str_parts.last_mut()
39                     .expect("bug: fmt_str_parts empty")
40                     .push('\n');
41             }
42 
43             // Otherwise (style closing tag is last fragment), we have to add a
44             // new `Fmt` fragment.
45             _ => {
46                 self.fragments.push(FormatStrFragment::Fmt {
47                     fmt_str_parts: vec!["\n".into()],
48                     args: vec![],
49                 });
50             }
51         }
52     }
53 }
54 
55 /// One fragment of the format string.
56 #[derive(Debug)]
57 pub(crate) enum FormatStrFragment {
58     /// A format string without style tags, but potentially with arguments.
59     ///
60     /// `fmt_str_parts` always has exactly one element more than `args`.
61     Fmt {
62         /// The format string as parts between the arguments.
63         fmt_str_parts: Vec<String>,
64 
65         /// Information about argument that are referenced.
66         args: Vec<ArgRef>,
67     },
68 
69     /// A `{$...}` style start tag.
70     StyleStart(Style),
71 
72     /// A `{/$}` style end tag.
73     StyleEnd,
74 }
75 
76 #[derive(Debug)]
77 pub(crate) struct ArgRef {
78     pub(crate) kind: ArgRefKind,
79     pub(crate) format_spec: FormatSpec,
80 }
81 
82 /// How a format argument is referred to.
83 #[derive(Debug)]
84 pub(crate) enum ArgRefKind {
85     /// `{}`
86     Next,
87     /// `{2}`
88     Position(usize),
89     /// `{peter}`
90     Name(String),
91 }
92 
93 #[derive(Debug, Clone)]
94 #[cfg_attr(test, derive(PartialEq))]
95 pub(crate) struct FormatSpec {
96     pub(crate) fill: Option<char>,
97     pub(crate) align: Option<Align>,
98     pub(crate) sign: Option<Sign>,
99     pub(crate) alternate: bool,
100     pub(crate) zero: bool,
101     pub(crate) width: Option<Width>,
102     pub(crate) precision: Option<Precision>,
103     pub(crate) ty: Option<char>,
104 }
105 
106 #[cfg(test)]
107 impl Default for FormatSpec {
default() -> Self108     fn default() -> Self {
109         Self {
110             fill: None,
111             align: None,
112             sign: None,
113             alternate: false,
114             zero: false,
115             width: None,
116             precision: None,
117             ty: None,
118         }
119     }
120 }
121 
122 #[derive(Debug, Clone, Copy)]
123 #[cfg_attr(test, derive(PartialEq))]
124 pub(crate) enum Align {
125     Left,
126     Center,
127     Right,
128 }
129 
130 #[derive(Debug, Clone, Copy)]
131 #[cfg_attr(test, derive(PartialEq))]
132 pub(crate) enum Sign {
133     Plus,
134     Minus,
135 }
136 
137 #[derive(Debug, Clone)]
138 #[cfg_attr(test, derive(PartialEq))]
139 pub(crate) enum Width {
140     Constant(usize),
141     Name(String),
142     Position(usize),
143 }
144 
145 #[derive(Debug, Clone)]
146 #[cfg_attr(test, derive(PartialEq))]
147 pub(crate) enum Precision {
148     Constant(usize),
149     Name(String),
150     Position(usize),
151     /// `.*`
152     Bundled,
153 }
154 
155 /// Parsed formatting arguments.
156 #[derive(Debug)]
157 pub(crate) struct FormatArgs {
158     /// All argument expressions in order, including the named ones (without the
159     /// `name =` part).
160     pub(crate) exprs: Vec<Expr>,
161 
162     /// Mapping from named argument name to index in `self.exprs`.
163     pub(crate) name_indices: HashMap<String, usize>,
164 }
165 
166 #[derive(Debug, Clone, Copy)]
167 pub(crate) enum Color {
168     Black,
169     Blue,
170     Green,
171     Red,
172     Cyan,
173     Magenta,
174     Yellow,
175     White,
176     //Ansi256(u8), // TODO: add
177     Rgb(u8, u8, u8),
178 }
179 
180 #[derive(Debug, Default, Clone, Copy)]
181 pub(crate) struct Style {
182     pub(crate) fg: Option<Color>,
183     pub(crate) bg: Option<Color>,
184     pub(crate) bold: Option<bool>,
185     pub(crate) intense: Option<bool>,
186     pub(crate) underline: Option<bool>,
187     pub(crate) italic: Option<bool>,
188     pub(crate) dimmed: Option<bool>,
189     pub(crate) reset: Option<bool>,
190 }
191 
192 impl Style {
193     /// Like `Option::or`: all style values set in `self` are kept, all unset
194     /// ones are overwritten with the values from `style_b`.
or(&self, style_b: Self) -> Self195     pub(crate) fn or(&self, style_b: Self) -> Self {
196         Self {
197             fg: self.fg.or(style_b.fg),
198             bg: self.bg.or(style_b.bg),
199             bold: self.bold.or(style_b.bold),
200             intense: self.intense.or(style_b.intense),
201             underline: self.underline.or(style_b.underline),
202             italic: self.italic.or(style_b.italic),
203             dimmed: self.dimmed.or(style_b.dimmed),
204             reset: self.reset.or(style_b.reset),
205         }
206     }
207 }
208