David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 1 | //! Parsing interface for parsing a token stream into a syntax tree node. |
| 2 | |
| 3 | use std::cell::Cell; |
| 4 | use std::fmt::Display; |
| 5 | use std::marker::PhantomData; |
| 6 | use std::mem; |
| 7 | use std::ops::Deref; |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 8 | use std::rc::Rc; |
| 9 | |
| 10 | use proc_macro2::{Ident, Span}; |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 11 | |
David Tolnay | 6d67c74 | 2018-08-24 20:42:39 -0400 | [diff] [blame] | 12 | use buffer::Cursor; |
David Tolnay | b625418 | 2018-08-25 08:44:54 -0400 | [diff] [blame] | 13 | use error; |
David Tolnay | 577d033 | 2018-08-25 21:45:24 -0400 | [diff] [blame] | 14 | use punctuated::Punctuated; |
David Tolnay | 4fb7123 | 2018-08-25 23:14:50 -0400 | [diff] [blame] | 15 | use token::Token; |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 16 | |
David Tolnay | b625418 | 2018-08-25 08:44:54 -0400 | [diff] [blame] | 17 | pub use error::{Error, Result}; |
| 18 | pub use lookahead::{Lookahead1, Peek}; |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 19 | |
| 20 | /// Parsing interface implemented by all types that can be parsed in a default |
| 21 | /// way from a token stream. |
| 22 | pub trait Parse: Sized { |
| 23 | fn parse(input: ParseStream) -> Result<Self>; |
| 24 | } |
| 25 | |
| 26 | /// Input to a Syn parser function. |
| 27 | pub type ParseStream<'a> = &'a ParseBuffer<'a>; |
| 28 | |
| 29 | /// Cursor position within a buffered token stream. |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 30 | pub struct ParseBuffer<'a> { |
| 31 | scope: Span, |
| 32 | cell: Cell<Cursor<'static>>, |
| 33 | marker: PhantomData<Cursor<'a>>, |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 34 | unexpected: Rc<Cell<Option<Span>>>, |
| 35 | } |
| 36 | |
| 37 | impl<'a> Drop for ParseBuffer<'a> { |
| 38 | fn drop(&mut self) { |
| 39 | if !self.is_empty() && self.unexpected.get().is_none() { |
| 40 | self.unexpected.set(Some(self.cursor().span())); |
| 41 | } |
| 42 | } |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | // Not public API. |
| 46 | #[doc(hidden)] |
| 47 | #[derive(Copy, Clone)] |
| 48 | pub struct StepCursor<'c, 'a> { |
| 49 | scope: Span, |
| 50 | cursor: Cursor<'c>, |
| 51 | marker: PhantomData<fn(Cursor<'c>) -> Cursor<'a>>, |
| 52 | } |
| 53 | |
| 54 | impl<'c, 'a> Deref for StepCursor<'c, 'a> { |
| 55 | type Target = Cursor<'c>; |
| 56 | |
| 57 | fn deref(&self) -> &Self::Target { |
| 58 | &self.cursor |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | impl<'c, 'a> StepCursor<'c, 'a> { |
| 63 | // Not public API. |
| 64 | #[doc(hidden)] |
| 65 | pub fn advance(self, other: Cursor<'c>) -> Cursor<'a> { |
| 66 | unsafe { mem::transmute::<Cursor<'c>, Cursor<'a>>(other) } |
| 67 | } |
| 68 | |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 69 | pub fn error<T: Display>(self, message: T) -> Error { |
| 70 | error::new_at(self.scope, self.cursor, message) |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | impl<'a> ParseBuffer<'a> { |
| 75 | // Not public API. |
| 76 | #[doc(hidden)] |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 77 | pub fn new(scope: Span, cursor: Cursor<'a>, unexpected: Rc<Cell<Option<Span>>>) -> Self { |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 78 | let extend = unsafe { mem::transmute::<Cursor<'a>, Cursor<'static>>(cursor) }; |
| 79 | ParseBuffer { |
| 80 | scope: scope, |
| 81 | cell: Cell::new(extend), |
| 82 | marker: PhantomData, |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 83 | unexpected: unexpected, |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 84 | } |
| 85 | } |
| 86 | |
| 87 | pub fn cursor(&self) -> Cursor<'a> { |
| 88 | self.cell.get() |
| 89 | } |
| 90 | |
| 91 | pub fn is_empty(&self) -> bool { |
| 92 | self.cursor().eof() |
| 93 | } |
| 94 | |
| 95 | pub fn lookahead1(&self) -> Lookahead1<'a> { |
| 96 | Lookahead1::new(self.scope, self.cursor()) |
| 97 | } |
| 98 | |
| 99 | pub fn parse<T: Parse>(&self) -> Result<T> { |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 100 | self.check_unexpected()?; |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 101 | T::parse(self) |
| 102 | } |
| 103 | |
David Tolnay | 3a515a0 | 2018-08-25 21:08:27 -0400 | [diff] [blame] | 104 | pub fn call<T>(&self, function: fn(ParseStream) -> Result<T>) -> Result<T> { |
| 105 | function(self) |
| 106 | } |
| 107 | |
David Tolnay | b77c8b6 | 2018-08-25 16:39:41 -0400 | [diff] [blame] | 108 | pub fn peek<T: Peek>(&self, token: T) -> bool { |
| 109 | self.lookahead1().peek(token) |
| 110 | } |
| 111 | |
David Tolnay | 4fb7123 | 2018-08-25 23:14:50 -0400 | [diff] [blame] | 112 | pub fn peek2<T: Peek>(&self, token: T) -> bool { |
| 113 | if self.is_empty() { |
| 114 | return false; |
| 115 | } |
| 116 | let ahead = self.fork(); |
David Tolnay | a7d69fc | 2018-08-26 13:30:24 -0400 | [diff] [blame] | 117 | ahead |
| 118 | .step_cursor(|cursor| Ok(cursor.token_tree().unwrap())) |
| 119 | .unwrap(); |
David Tolnay | 4fb7123 | 2018-08-25 23:14:50 -0400 | [diff] [blame] | 120 | ahead.peek(token) |
| 121 | } |
| 122 | |
| 123 | pub fn peek3<T: Peek>(&self, token: T) -> bool { |
| 124 | if self.is_empty() { |
| 125 | return false; |
| 126 | } |
| 127 | let ahead = self.fork(); |
David Tolnay | a7d69fc | 2018-08-26 13:30:24 -0400 | [diff] [blame] | 128 | ahead |
| 129 | .step_cursor(|cursor| Ok(cursor.token_tree().unwrap())) |
| 130 | .unwrap(); |
| 131 | ahead |
| 132 | .step_cursor(|cursor| Ok(cursor.token_tree().unwrap())) |
| 133 | .unwrap(); |
David Tolnay | 4fb7123 | 2018-08-25 23:14:50 -0400 | [diff] [blame] | 134 | ahead.peek(token) |
| 135 | } |
| 136 | |
David Tolnay | 577d033 | 2018-08-25 21:45:24 -0400 | [diff] [blame] | 137 | pub fn parse_terminated<T, P: Parse>( |
| 138 | &self, |
| 139 | parser: fn(ParseStream) -> Result<T>, |
| 140 | ) -> Result<Punctuated<T, P>> { |
David Tolnay | ecf0fbc | 2018-08-30 18:28:33 -0700 | [diff] [blame^] | 141 | Punctuated::parse_terminated(self, parser) |
David Tolnay | 577d033 | 2018-08-25 21:45:24 -0400 | [diff] [blame] | 142 | } |
| 143 | |
David Tolnay | b77c8b6 | 2018-08-25 16:39:41 -0400 | [diff] [blame] | 144 | pub fn fork(&self) -> Self { |
David Tolnay | 6456a9d | 2018-08-26 08:11:18 -0400 | [diff] [blame] | 145 | ParseBuffer { |
| 146 | scope: self.scope, |
| 147 | cell: self.cell.clone(), |
| 148 | marker: PhantomData, |
| 149 | // Not the parent's unexpected. Nothing cares whether the clone |
| 150 | // parses all the way. |
| 151 | unexpected: Rc::new(Cell::new(None)), |
| 152 | } |
David Tolnay | b77c8b6 | 2018-08-25 16:39:41 -0400 | [diff] [blame] | 153 | } |
| 154 | |
David Tolnay | 4fb7123 | 2018-08-25 23:14:50 -0400 | [diff] [blame] | 155 | pub fn error<T: Display>(&self, message: T) -> Error { |
| 156 | error::new_at(self.scope, self.cursor(), message) |
| 157 | } |
| 158 | |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 159 | // Not public API. |
| 160 | #[doc(hidden)] |
| 161 | pub fn step_cursor<F, R>(&self, function: F) -> Result<R> |
| 162 | where |
| 163 | F: for<'c> FnOnce(StepCursor<'c, 'a>) -> Result<(R, Cursor<'c>)>, |
| 164 | { |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 165 | self.check_unexpected()?; |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 166 | match function(StepCursor { |
| 167 | scope: self.scope, |
| 168 | cursor: self.cell.get(), |
| 169 | marker: PhantomData, |
| 170 | }) { |
| 171 | Ok((ret, cursor)) => { |
| 172 | self.cell.set(cursor); |
| 173 | Ok(ret) |
| 174 | } |
| 175 | Err(err) => Err(err), |
| 176 | } |
| 177 | } |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 178 | |
| 179 | // Not public API. |
| 180 | #[doc(hidden)] |
| 181 | pub fn get_unexpected(&self) -> Rc<Cell<Option<Span>>> { |
| 182 | self.unexpected.clone() |
| 183 | } |
| 184 | |
| 185 | // Not public API. |
| 186 | #[doc(hidden)] |
| 187 | pub fn check_unexpected(&self) -> Result<()> { |
| 188 | match self.unexpected.get() { |
| 189 | Some(span) => Err(Error::new(span, "unexpected token")), |
| 190 | None => Ok(()), |
| 191 | } |
| 192 | } |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | impl Parse for Ident { |
| 196 | fn parse(input: ParseStream) -> Result<Self> { |
| 197 | input.step_cursor(|cursor| { |
| 198 | if let Some((ident, rest)) = cursor.ident() { |
David Tolnay | c4fdb1a | 2018-08-24 21:11:07 -0400 | [diff] [blame] | 199 | match ident.to_string().as_str() { |
| 200 | "_" |
| 201 | // Based on https://doc.rust-lang.org/grammar.html#keywords |
| 202 | // and https://github.com/rust-lang/rfcs/blob/master/text/2421-unreservations-2018.md |
| 203 | | "abstract" | "as" | "become" | "box" | "break" | "const" |
| 204 | | "continue" | "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" |
| 205 | | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" |
| 206 | | "mod" | "move" | "mut" | "override" | "priv" | "proc" | "pub" |
| 207 | | "ref" | "return" | "Self" | "self" | "static" | "struct" |
| 208 | | "super" | "trait" | "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" |
| 209 | | "virtual" | "where" | "while" | "yield" => {} |
| 210 | _ => return Ok((ident, rest)), |
| 211 | } |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 212 | } |
David Tolnay | c4fdb1a | 2018-08-24 21:11:07 -0400 | [diff] [blame] | 213 | Err(cursor.error("expected identifier")) |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 214 | }) |
| 215 | } |
| 216 | } |
| 217 | |
David Tolnay | a7d69fc | 2018-08-26 13:30:24 -0400 | [diff] [blame] | 218 | impl<T: Parse> Parse for Box<T> { |
| 219 | fn parse(input: ParseStream) -> Result<Self> { |
| 220 | input.parse().map(Box::new) |
| 221 | } |
| 222 | } |
| 223 | |
David Tolnay | 4fb7123 | 2018-08-25 23:14:50 -0400 | [diff] [blame] | 224 | impl<T: Parse + Token> Parse for Option<T> { |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 225 | fn parse(input: ParseStream) -> Result<Self> { |
David Tolnay | 4fb7123 | 2018-08-25 23:14:50 -0400 | [diff] [blame] | 226 | if T::peek(&input.lookahead1()) { |
| 227 | Ok(Some(input.parse()?)) |
| 228 | } else { |
| 229 | Ok(None) |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 230 | } |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 231 | } |
| 232 | } |