1use crate::buffer::Cursor; 2use crate::error::{self, Error}; 3use crate::sealed::lookahead::Sealed; 4use crate::span::IntoSpans; 5use crate::token::Token; 6use proc_macro2::{Delimiter, Span}; 7use std::cell::RefCell; 8 9/// Support for checking the next token in a stream to decide how to parse. 10/// 11/// An important advantage over [`ParseStream::peek`] is that here we 12/// automatically construct an appropriate error message based on the token 13/// alternatives that get peeked. If you are producing your own error message, 14/// go ahead and use `ParseStream::peek` instead. 15/// 16/// Use [`ParseStream::lookahead1`] to construct this object. 17/// 18/// [`ParseStream::peek`]: crate::parse::ParseBuffer::peek 19/// [`ParseStream::lookahead1`]: crate::parse::ParseBuffer::lookahead1 20/// 21/// Consuming tokens from the source stream after constructing a lookahead 22/// object does not also advance the lookahead object. 23/// 24/// # Example 25/// 26/// ``` 27/// use syn::{ConstParam, Ident, Lifetime, LifetimeParam, Result, Token, TypeParam}; 28/// use syn::parse::{Parse, ParseStream}; 29/// 30/// // A generic parameter, a single one of the comma-separated elements inside 31/// // angle brackets in: 32/// // 33/// // fn f<T: Clone, 'a, 'b: 'a, const N: usize>() { ... } 34/// // 35/// // On invalid input, lookahead gives us a reasonable error message. 36/// // 37/// // error: expected one of: identifier, lifetime, `const` 38/// // | 39/// // 5 | fn f<!Sized>() {} 40/// // | ^ 41/// enum GenericParam { 42/// Type(TypeParam), 43/// Lifetime(LifetimeParam), 44/// Const(ConstParam), 45/// } 46/// 47/// impl Parse for GenericParam { 48/// fn parse(input: ParseStream) -> Result<Self> { 49/// let lookahead = input.lookahead1(); 50/// if lookahead.peek(Ident) { 51/// input.parse().map(GenericParam::Type) 52/// } else if lookahead.peek(Lifetime) { 53/// input.parse().map(GenericParam::Lifetime) 54/// } else if lookahead.peek(Token![const]) { 55/// input.parse().map(GenericParam::Const) 56/// } else { 57/// Err(lookahead.error()) 58/// } 59/// } 60/// } 61/// ``` 62pub struct Lookahead1<'a> { 63 scope: Span, 64 cursor: Cursor<'a>, 65 comparisons: RefCell<Vec<&'static str>>, 66} 67 68pub(crate) fn new(scope: Span, cursor: Cursor) -> Lookahead1 { 69 Lookahead1 { 70 scope, 71 cursor, 72 comparisons: RefCell::new(Vec::new()), 73 } 74} 75 76fn peek_impl( 77 lookahead: &Lookahead1, 78 peek: fn(Cursor) -> bool, 79 display: fn() -> &'static str, 80) -> bool { 81 if peek(lookahead.cursor) { 82 return true; 83 } 84 lookahead.comparisons.borrow_mut().push(display()); 85 false 86} 87 88impl<'a> Lookahead1<'a> { 89 /// Looks at the next token in the parse stream to determine whether it 90 /// matches the requested type of token. 91 /// 92 /// # Syntax 93 /// 94 /// Note that this method does not use turbofish syntax. Pass the peek type 95 /// inside of parentheses. 96 /// 97 /// - `input.peek(Token![struct])` 98 /// - `input.peek(Token![==])` 99 /// - `input.peek(Ident)` *(does not accept keywords)* 100 /// - `input.peek(Ident::peek_any)` 101 /// - `input.peek(Lifetime)` 102 /// - `input.peek(token::Brace)` 103 pub fn peek<T: Peek>(&self, token: T) -> bool { 104 let _ = token; 105 peek_impl(self, T::Token::peek, T::Token::display) 106 } 107 108 /// Triggers an error at the current position of the parse stream. 109 /// 110 /// The error message will identify all of the expected token types that 111 /// have been peeked against this lookahead instance. 112 pub fn error(self) -> Error { 113 let comparisons = self.comparisons.borrow(); 114 match comparisons.len() { 115 0 => { 116 if self.cursor.eof() { 117 Error::new(self.scope, "unexpected end of input") 118 } else { 119 Error::new(self.cursor.span(), "unexpected token") 120 } 121 } 122 1 => { 123 let message = format!("expected {}", comparisons[0]); 124 error::new_at(self.scope, self.cursor, message) 125 } 126 2 => { 127 let message = format!("expected {} or {}", comparisons[0], comparisons[1]); 128 error::new_at(self.scope, self.cursor, message) 129 } 130 _ => { 131 let join = comparisons.join(", "); 132 let message = format!("expected one of: {}", join); 133 error::new_at(self.scope, self.cursor, message) 134 } 135 } 136 } 137} 138 139/// Types that can be parsed by looking at just one token. 140/// 141/// Use [`ParseStream::peek`] to peek one of these types in a parse stream 142/// without consuming it from the stream. 143/// 144/// This trait is sealed and cannot be implemented for types outside of Syn. 145/// 146/// [`ParseStream::peek`]: crate::parse::ParseBuffer::peek 147pub trait Peek: Sealed { 148 // Not public API. 149 #[doc(hidden)] 150 type Token: Token; 151} 152 153impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Peek for F { 154 type Token = T; 155} 156 157pub enum TokenMarker {} 158 159impl<S> IntoSpans<S> for TokenMarker { 160 fn into_spans(self) -> S { 161 match self {} 162 } 163} 164 165pub(crate) fn is_delimiter(cursor: Cursor, delimiter: Delimiter) -> bool { 166 cursor.group(delimiter).is_some() 167} 168 169impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Sealed for F {} 170