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 | b77c8b6 | 2018-08-25 16:39:41 -0400 | [diff] [blame] | 15 | use synom::PResult; |
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 | |
David Tolnay | a8e2903 | 2018-08-25 17:14:31 -0400 | [diff] [blame] | 45 | impl<'a> Clone for ParseBuffer<'a> { |
| 46 | fn clone(&self) -> Self { |
| 47 | ParseBuffer { |
| 48 | scope: self.scope, |
| 49 | cell: self.cell.clone(), |
| 50 | marker: PhantomData, |
| 51 | // Not the parent's unexpected. Nothing cares whether the clone |
| 52 | // parses all the way. |
| 53 | unexpected: Rc::new(Cell::new(None)), |
| 54 | } |
| 55 | } |
| 56 | } |
| 57 | |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 58 | // Not public API. |
| 59 | #[doc(hidden)] |
| 60 | #[derive(Copy, Clone)] |
| 61 | pub struct StepCursor<'c, 'a> { |
| 62 | scope: Span, |
| 63 | cursor: Cursor<'c>, |
| 64 | marker: PhantomData<fn(Cursor<'c>) -> Cursor<'a>>, |
| 65 | } |
| 66 | |
| 67 | impl<'c, 'a> Deref for StepCursor<'c, 'a> { |
| 68 | type Target = Cursor<'c>; |
| 69 | |
| 70 | fn deref(&self) -> &Self::Target { |
| 71 | &self.cursor |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | impl<'c, 'a> StepCursor<'c, 'a> { |
| 76 | // Not public API. |
| 77 | #[doc(hidden)] |
| 78 | pub fn advance(self, other: Cursor<'c>) -> Cursor<'a> { |
| 79 | unsafe { mem::transmute::<Cursor<'c>, Cursor<'a>>(other) } |
| 80 | } |
| 81 | |
| 82 | // Not public API. |
| 83 | #[doc(hidden)] |
| 84 | pub fn error<T: Display>(self, message: T) -> Error { |
| 85 | error::new_at(self.scope, self.cursor, message) |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | impl<'a> ParseBuffer<'a> { |
| 90 | // Not public API. |
| 91 | #[doc(hidden)] |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 92 | 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] | 93 | let extend = unsafe { mem::transmute::<Cursor<'a>, Cursor<'static>>(cursor) }; |
| 94 | ParseBuffer { |
| 95 | scope: scope, |
| 96 | cell: Cell::new(extend), |
| 97 | marker: PhantomData, |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 98 | unexpected: unexpected, |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 99 | } |
| 100 | } |
| 101 | |
| 102 | pub fn cursor(&self) -> Cursor<'a> { |
| 103 | self.cell.get() |
| 104 | } |
| 105 | |
| 106 | pub fn is_empty(&self) -> bool { |
| 107 | self.cursor().eof() |
| 108 | } |
| 109 | |
| 110 | pub fn lookahead1(&self) -> Lookahead1<'a> { |
| 111 | Lookahead1::new(self.scope, self.cursor()) |
| 112 | } |
| 113 | |
| 114 | pub fn parse<T: Parse>(&self) -> Result<T> { |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 115 | self.check_unexpected()?; |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 116 | T::parse(self) |
| 117 | } |
| 118 | |
David Tolnay | 3a515a0 | 2018-08-25 21:08:27 -0400 | [diff] [blame] | 119 | pub fn call<T>(&self, function: fn(ParseStream) -> Result<T>) -> Result<T> { |
| 120 | function(self) |
| 121 | } |
| 122 | |
David Tolnay | b77c8b6 | 2018-08-25 16:39:41 -0400 | [diff] [blame] | 123 | pub fn peek<T: Peek>(&self, token: T) -> bool { |
| 124 | self.lookahead1().peek(token) |
| 125 | } |
| 126 | |
David Tolnay | 577d033 | 2018-08-25 21:45:24 -0400 | [diff] [blame^] | 127 | pub fn parse_terminated<T, P: Parse>( |
| 128 | &self, |
| 129 | parser: fn(ParseStream) -> Result<T>, |
| 130 | ) -> Result<Punctuated<T, P>> { |
| 131 | Punctuated::parse_terminated2(self, parser) |
| 132 | } |
| 133 | |
David Tolnay | b77c8b6 | 2018-08-25 16:39:41 -0400 | [diff] [blame] | 134 | pub fn fork(&self) -> Self { |
| 135 | self.clone() |
| 136 | } |
| 137 | |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 138 | // Not public API. |
| 139 | #[doc(hidden)] |
| 140 | pub fn step_cursor<F, R>(&self, function: F) -> Result<R> |
| 141 | where |
| 142 | F: for<'c> FnOnce(StepCursor<'c, 'a>) -> Result<(R, Cursor<'c>)>, |
| 143 | { |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 144 | self.check_unexpected()?; |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 145 | match function(StepCursor { |
| 146 | scope: self.scope, |
| 147 | cursor: self.cell.get(), |
| 148 | marker: PhantomData, |
| 149 | }) { |
| 150 | Ok((ret, cursor)) => { |
| 151 | self.cell.set(cursor); |
| 152 | Ok(ret) |
| 153 | } |
| 154 | Err(err) => Err(err), |
| 155 | } |
| 156 | } |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 157 | |
| 158 | // Not public API. |
| 159 | #[doc(hidden)] |
David Tolnay | b77c8b6 | 2018-08-25 16:39:41 -0400 | [diff] [blame] | 160 | pub fn parse_synom<T>(&self, parse: fn(Cursor) -> PResult<T>) -> Result<T> { |
| 161 | self.step_cursor(|step| parse(step.cursor)) |
| 162 | } |
| 163 | |
| 164 | // Not public API. |
| 165 | #[doc(hidden)] |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 166 | pub fn get_unexpected(&self) -> Rc<Cell<Option<Span>>> { |
| 167 | self.unexpected.clone() |
| 168 | } |
| 169 | |
| 170 | // Not public API. |
| 171 | #[doc(hidden)] |
| 172 | pub fn check_unexpected(&self) -> Result<()> { |
| 173 | match self.unexpected.get() { |
| 174 | Some(span) => Err(Error::new(span, "unexpected token")), |
| 175 | None => Ok(()), |
| 176 | } |
| 177 | } |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | impl Parse for Ident { |
| 181 | fn parse(input: ParseStream) -> Result<Self> { |
| 182 | input.step_cursor(|cursor| { |
| 183 | if let Some((ident, rest)) = cursor.ident() { |
David Tolnay | c4fdb1a | 2018-08-24 21:11:07 -0400 | [diff] [blame] | 184 | match ident.to_string().as_str() { |
| 185 | "_" |
| 186 | // Based on https://doc.rust-lang.org/grammar.html#keywords |
| 187 | // and https://github.com/rust-lang/rfcs/blob/master/text/2421-unreservations-2018.md |
| 188 | | "abstract" | "as" | "become" | "box" | "break" | "const" |
| 189 | | "continue" | "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" |
| 190 | | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" |
| 191 | | "mod" | "move" | "mut" | "override" | "priv" | "proc" | "pub" |
| 192 | | "ref" | "return" | "Self" | "self" | "static" | "struct" |
| 193 | | "super" | "trait" | "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" |
| 194 | | "virtual" | "where" | "while" | "yield" => {} |
| 195 | _ => return Ok((ident, rest)), |
| 196 | } |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 197 | } |
David Tolnay | c4fdb1a | 2018-08-24 21:11:07 -0400 | [diff] [blame] | 198 | Err(cursor.error("expected identifier")) |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 199 | }) |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | // In reality the impl would be for Punctuated. |
| 204 | impl<T: Parse> Parse for Vec<T> { |
| 205 | fn parse(input: ParseStream) -> Result<Self> { |
| 206 | let mut vec = Vec::new(); |
| 207 | while !input.is_empty() { |
| 208 | let t = input.parse::<T>()?; |
| 209 | vec.push(t); |
| 210 | } |
| 211 | Ok(vec) |
| 212 | } |
| 213 | } |