| 1 | use crate::{spanned::Spans, utils::Peekable2, Error}; |
| 2 | |
| 3 | use proc_macro2::{ |
| 4 | token_stream::IntoIter, Delimiter, Group, Ident, Punct, Span, TokenStream as TokenStream2, |
| 5 | TokenTree as TokenTree2, |
| 6 | }; |
| 7 | |
| 8 | use std::{cmp::PartialEq, ops::Range}; |
| 9 | |
| 10 | pub type ParseStream<'a> = &'a mut ParseBuffer; |
| 11 | |
| 12 | pub struct ParseBuffer { |
| 13 | iter: Peekable2<IntoIter>, |
| 14 | } |
| 15 | |
| 16 | impl ParseBuffer { |
| 17 | pub fn new(ts: TokenStream2) -> Self { |
| 18 | let iter = Peekable2::new(ts); |
| 19 | Self { iter } |
| 20 | } |
| 21 | |
| 22 | pub fn is_empty(&mut self) -> bool { |
| 23 | self.iter.is_empty() |
| 24 | } |
| 25 | |
| 26 | pub fn peek(&mut self) -> Option<&TokenTree2> { |
| 27 | self.iter.peek() |
| 28 | } |
| 29 | pub fn peek2(&mut self) -> Option<&TokenTree2> { |
| 30 | self.iter.peek2() |
| 31 | } |
| 32 | |
| 33 | pub fn parse_punct(&mut self, c: char) -> Result<Punct, crate::Error> { |
| 34 | match self.next() { |
| 35 | Some(TokenTree2::Punct(x)) if x.as_char() == c => Ok(x), |
| 36 | Some(x) => Err(Error::new(x.span(), &format!("Expected a ' {}' token" , c))), |
| 37 | None => Err(Error::new( |
| 38 | Span::mixed_site(), |
| 39 | &format!("Expected a ' {}' token" , c), |
| 40 | )), |
| 41 | } |
| 42 | } |
| 43 | pub fn parse_opt_punct(&mut self, c: char) -> Result<Option<Punct>, crate::Error> { |
| 44 | match self.next() { |
| 45 | Some(TokenTree2::Punct(x)) if x.as_char() == c => Ok(Some(x)), |
| 46 | Some(x) => Err(Error::new(x.span(), &format!("Expected a ' {}' token" , c))), |
| 47 | None => Ok(None), |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | pub fn parse_ident(&mut self) -> Result<Ident, crate::Error> { |
| 52 | match self.next() { |
| 53 | Some(TokenTree2::Ident(x)) => Ok(x), |
| 54 | Some(x) => Err(Error::new(x.span(), "Expected an identifier" )), |
| 55 | None => Err(Error::new(Span::mixed_site(), "Expected an identifier" )), |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | pub fn parse_paren(&mut self) -> Result<Parentheses, crate::Error> { |
| 60 | match self.next() { |
| 61 | Some(TokenTree2::Group(group)) if group.delimiter() == Delimiter::Parenthesis => { |
| 62 | Ok(Parentheses { |
| 63 | paren_span: group.span(), |
| 64 | contents: group.stream(), |
| 65 | }) |
| 66 | } |
| 67 | Some(x) => Err(Error::new( |
| 68 | x.span(), |
| 69 | &format!("Expected parentheses: found {}" , x), |
| 70 | )), |
| 71 | None => Err(Error::new( |
| 72 | Span::mixed_site(), |
| 73 | "Expected parentheses, found nothing" , |
| 74 | )), |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | pub fn parse_unwrap_paren<F, T>(&mut self, f: F) -> Result<T, crate::Error> |
| 79 | where |
| 80 | F: FnOnce(ParseStream<'_>) -> Result<T, crate::Error>, |
| 81 | { |
| 82 | if matches!(self.peek(), Some(TokenTree2::Group(x)) if x.delimiter() == Delimiter::Parenthesis ) |
| 83 | { |
| 84 | if let Some(TokenTree2::Group(group)) = self.next() { |
| 85 | ParseBuffer::new(group.stream()).parse_unwrap_tt(f) |
| 86 | } else { |
| 87 | unreachable!("But I peeked for a Parenthesis delimited TokenTree::Group!!" ) |
| 88 | } |
| 89 | } else { |
| 90 | f(self) |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | pub fn parse_unwrap_group<F, T>(&mut self, f: F) -> Result<T, crate::Error> |
| 95 | where |
| 96 | F: FnOnce(ParseStream<'_>) -> Result<T, crate::Error>, |
| 97 | { |
| 98 | if let Some(TokenTree2::Group(group)) = self.next() { |
| 99 | ParseBuffer::new(group.stream()).parse_unwrap_tt(f) |
| 100 | } else { |
| 101 | f(self) |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | pub fn parse_token_stream_and_span(&mut self) -> (TokenStream2, Spans) { |
| 106 | let mut start = match self.peek() { |
| 107 | Some(x) => x.span(), |
| 108 | None => Span::call_site(), |
| 109 | }; |
| 110 | |
| 111 | let mut end = start; |
| 112 | |
| 113 | let ts = self |
| 114 | .inspect(|tt| { |
| 115 | end = tt.span(); |
| 116 | if let Some(next) = start.join(end) { |
| 117 | start = next; |
| 118 | } |
| 119 | }) |
| 120 | .collect::<TokenStream2>(); |
| 121 | |
| 122 | (ts, Spans { start, end }) |
| 123 | } |
| 124 | |
| 125 | /// Unwraps a none-delimited token tree to parse a type, |
| 126 | /// if the first token is not a none-delimited token tree it parses the type in |
| 127 | /// the passed in ParseStream. |
| 128 | pub fn parse_unwrap_tt<F, T>(&mut self, f: F) -> Result<T, crate::Error> |
| 129 | where |
| 130 | F: FnOnce(ParseStream<'_>) -> Result<T, crate::Error>, |
| 131 | { |
| 132 | if matches!(self.peek(), Some(TokenTree2::Group(x)) if x.delimiter() == Delimiter::None ) { |
| 133 | if let Some(TokenTree2::Group(group)) = self.next() { |
| 134 | ParseBuffer::new(group.stream()).parse_unwrap_tt(f) |
| 135 | } else { |
| 136 | unreachable!("But I peeked for a None delimited TokenTree::Group!!" ) |
| 137 | } |
| 138 | } else { |
| 139 | f(self) |
| 140 | } |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | impl Iterator for ParseBuffer { |
| 145 | type Item = TokenTree2; |
| 146 | |
| 147 | fn next(&mut self) -> Option<TokenTree2> { |
| 148 | self.iter.next() |
| 149 | } |
| 150 | |
| 151 | fn size_hint(&self) -> (usize, Option<usize>) { |
| 152 | self.iter.size_hint() |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | /////////////////////////////////////////////////////////////////////////////// |
| 157 | |
| 158 | pub struct Parentheses { |
| 159 | #[allow (dead_code)] |
| 160 | pub paren_span: Span, |
| 161 | pub contents: TokenStream2, |
| 162 | } |
| 163 | |
| 164 | /////////////////////////////////////////////////////////////////////////////// |
| 165 | |
| 166 | pub struct LitStr { |
| 167 | value: String, |
| 168 | pub rawness: StrRawness, |
| 169 | pub inside_lit: Range<usize>, |
| 170 | pub span: Span, |
| 171 | } |
| 172 | |
| 173 | impl LitStr { |
| 174 | pub fn value(&self) -> &str { |
| 175 | &self.value[self.inside_lit.clone()] |
| 176 | } |
| 177 | pub(crate) fn parse_from_literal(literal: &proc_macro2::Literal) -> Result<Self, Error> { |
| 178 | let mut value = literal.to_string(); |
| 179 | // Ignoring the quote characters |
| 180 | let mut range = 1..value.len() - 1; |
| 181 | let span = literal.span(); |
| 182 | |
| 183 | let is_raw = if let Some(suffix) = value.strip_prefix('r' ) { |
| 184 | let hashes = suffix.bytes().take_while(|x| *x == b'#' ).count(); |
| 185 | |
| 186 | if value.as_bytes()[1 + hashes] != b'"' { |
| 187 | return Err(Error::new( |
| 188 | span, |
| 189 | &format!("Expected a string literal, found: {}" , literal), |
| 190 | )); |
| 191 | } |
| 192 | |
| 193 | // Ignoring the r and hashes |
| 194 | range.start += 1 + hashes; |
| 195 | range.end -= hashes; |
| 196 | Some(hashes as u32) |
| 197 | } else { |
| 198 | let mut matches = value.match_indices(r#"\u"# ).peekable(); |
| 199 | if matches.peek().is_some() { |
| 200 | let mut prev_end = 0; |
| 201 | let mut new = String::with_capacity(value.len()); |
| 202 | |
| 203 | for (pos, _) in matches { |
| 204 | new.push_str(&value[prev_end..pos]); |
| 205 | |
| 206 | let past_open = pos + 3; |
| 207 | |
| 208 | let off_close = value[pos..].find('}' ).unwrap(); |
| 209 | |
| 210 | let c = &value[past_open..pos + off_close]; |
| 211 | let c = u32::from_str_radix(c, 16).unwrap(); |
| 212 | let c = std::char::from_u32(c).unwrap(); |
| 213 | |
| 214 | // if matches!(c, '\\' | '"') { |
| 215 | // new.push('\\'); |
| 216 | // } |
| 217 | new.push(c); |
| 218 | |
| 219 | prev_end = pos + off_close + 1; |
| 220 | } |
| 221 | new.push_str(&value[prev_end..]); |
| 222 | value = new; |
| 223 | } |
| 224 | |
| 225 | range = 1..value.len() - 1; |
| 226 | |
| 227 | None |
| 228 | }; |
| 229 | |
| 230 | Ok(Self { |
| 231 | value, |
| 232 | rawness: StrRawness { is_raw, span }, |
| 233 | inside_lit: range, |
| 234 | span, |
| 235 | }) |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | #[derive (Debug, Copy, Clone)] |
| 240 | pub struct StrRawness { |
| 241 | is_raw: Option<u32>, |
| 242 | span: Span, |
| 243 | } |
| 244 | |
| 245 | impl PartialEq for StrRawness { |
| 246 | fn eq(&self, other: &Self) -> bool { |
| 247 | self.is_raw == other.is_raw |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | impl StrRawness { |
| 252 | #[cfg (test)] |
| 253 | pub fn dummy() -> Self { |
| 254 | Self { |
| 255 | is_raw: Some(4), |
| 256 | span: Span::mixed_site(), |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | pub fn span(&self) -> Span { |
| 261 | self.span |
| 262 | } |
| 263 | |
| 264 | /// Tokenizes a slice of the parsed string literal. |
| 265 | pub fn tokenize_sub(&self, str: &str) -> TokenStream2 { |
| 266 | let mut buffer = String::new(); |
| 267 | match self.is_raw { |
| 268 | Some(hashes) => { |
| 269 | let hashes = hashes as usize; |
| 270 | buffer.reserve(3 + hashes + str.len() + hashes); |
| 271 | buffer.push('r' ); |
| 272 | let hashes = (0..hashes).map(|_| '#' ); |
| 273 | buffer.extend(hashes.clone()); |
| 274 | buffer.push('"' ); |
| 275 | buffer.push_str(str); |
| 276 | buffer.push('"' ); |
| 277 | buffer.extend(hashes); |
| 278 | } |
| 279 | None => { |
| 280 | buffer.reserve(2 + str.len()); |
| 281 | buffer.push('"' ); |
| 282 | buffer.push_str(str); |
| 283 | buffer.push('"' ); |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | buffer |
| 288 | .parse::<TokenStream2>() |
| 289 | .unwrap() |
| 290 | .set_span_recursive(self.span) |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | /////////////////////////////////////////////////////////////////////////////// |
| 295 | |
| 296 | pub trait TokenTreeExt: Sized { |
| 297 | fn as_token_tree(&self) -> &TokenTree2; |
| 298 | fn into_token_tree(self) -> TokenTree2; |
| 299 | |
| 300 | fn is_punct(&self, c: char) -> bool { |
| 301 | matches!(self.as_token_tree(), TokenTree2::Punct(p) if p.as_char() == c) |
| 302 | } |
| 303 | |
| 304 | #[allow (dead_code)] |
| 305 | fn is_paren(&self) -> bool { |
| 306 | matches!( |
| 307 | self.as_token_tree(), |
| 308 | TokenTree2::Group(g) if g.delimiter() == Delimiter::Parenthesis |
| 309 | ) |
| 310 | } |
| 311 | |
| 312 | #[allow (dead_code)] |
| 313 | fn is_ident(&self, ident: &str) -> bool { |
| 314 | matches!(self.as_token_tree(), TokenTree2::Ident(x) if x == ident) |
| 315 | } |
| 316 | |
| 317 | fn set_span_recursive(self, span: Span) -> TokenTree2 { |
| 318 | let mut tt = self.into_token_tree(); |
| 319 | |
| 320 | tt.set_span(span); |
| 321 | if let TokenTree2::Group(group) = tt { |
| 322 | let delim = group.delimiter(); |
| 323 | let stream = group.stream().set_span_recursive(span); |
| 324 | tt = TokenTree2::Group(Group::new(delim, stream)); |
| 325 | } |
| 326 | tt.set_span(span); |
| 327 | tt |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | impl TokenTreeExt for TokenTree2 { |
| 332 | fn as_token_tree(&self) -> &TokenTree2 { |
| 333 | self |
| 334 | } |
| 335 | |
| 336 | fn into_token_tree(self) -> TokenTree2 { |
| 337 | self |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | /////////////////////////////////////////////////////////////////////////////// |
| 342 | |
| 343 | pub trait TokenStream2Ext: Sized { |
| 344 | fn into_token_stream(self) -> TokenStream2; |
| 345 | |
| 346 | fn set_span_recursive(self, span: Span) -> TokenStream2 { |
| 347 | self.into_token_stream() |
| 348 | .into_iter() |
| 349 | .map(|tt: TokenTree| tt.set_span_recursive(span)) |
| 350 | .collect() |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | impl TokenStream2Ext for TokenStream2 { |
| 355 | fn into_token_stream(self) -> TokenStream2 { |
| 356 | self |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | /////////////////////////////////////////////////////////////////////////////// |
| 361 | |
| 362 | pub trait MyParse: Sized { |
| 363 | fn parse(input: ParseStream<'_>) -> Result<Self, crate::Error>; |
| 364 | |
| 365 | fn parse_token_stream_1(input: proc_macro::TokenStream) -> Result<Self, crate::Error> { |
| 366 | Self::parse(&mut ParseBuffer::new(ts:TokenStream2::from(input))) |
| 367 | } |
| 368 | |
| 369 | #[allow (dead_code)] |
| 370 | fn parse_token_stream_2(input: TokenStream2) -> Result<Self, crate::Error> { |
| 371 | Self::parse(&mut ParseBuffer::new(ts:input)) |
| 372 | } |
| 373 | } |
| 374 | |
| 375 | /////////////////////////////////////////////////////////////////////////////// |
| 376 | |