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