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 | b77c8b6 | 2018-08-25 16:39:41 -0400 | [diff] [blame^] | 14 | use synom::PResult; |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 15 | |
David Tolnay | b625418 | 2018-08-25 08:44:54 -0400 | [diff] [blame] | 16 | pub use error::{Error, Result}; |
| 17 | pub use lookahead::{Lookahead1, Peek}; |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 18 | |
| 19 | /// Parsing interface implemented by all types that can be parsed in a default |
| 20 | /// way from a token stream. |
| 21 | pub trait Parse: Sized { |
| 22 | fn parse(input: ParseStream) -> Result<Self>; |
| 23 | } |
| 24 | |
| 25 | /// Input to a Syn parser function. |
| 26 | pub type ParseStream<'a> = &'a ParseBuffer<'a>; |
| 27 | |
| 28 | /// Cursor position within a buffered token stream. |
| 29 | #[derive(Clone)] |
| 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 | |
| 69 | // Not public API. |
| 70 | #[doc(hidden)] |
| 71 | pub fn error<T: Display>(self, message: T) -> Error { |
| 72 | error::new_at(self.scope, self.cursor, message) |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | impl<'a> ParseBuffer<'a> { |
| 77 | // Not public API. |
| 78 | #[doc(hidden)] |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 79 | 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] | 80 | let extend = unsafe { mem::transmute::<Cursor<'a>, Cursor<'static>>(cursor) }; |
| 81 | ParseBuffer { |
| 82 | scope: scope, |
| 83 | cell: Cell::new(extend), |
| 84 | marker: PhantomData, |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 85 | unexpected: unexpected, |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 86 | } |
| 87 | } |
| 88 | |
| 89 | pub fn cursor(&self) -> Cursor<'a> { |
| 90 | self.cell.get() |
| 91 | } |
| 92 | |
| 93 | pub fn is_empty(&self) -> bool { |
| 94 | self.cursor().eof() |
| 95 | } |
| 96 | |
| 97 | pub fn lookahead1(&self) -> Lookahead1<'a> { |
| 98 | Lookahead1::new(self.scope, self.cursor()) |
| 99 | } |
| 100 | |
| 101 | pub fn parse<T: Parse>(&self) -> Result<T> { |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 102 | self.check_unexpected()?; |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 103 | T::parse(self) |
| 104 | } |
| 105 | |
David Tolnay | b77c8b6 | 2018-08-25 16:39:41 -0400 | [diff] [blame^] | 106 | pub fn peek<T: Peek>(&self, token: T) -> bool { |
| 107 | self.lookahead1().peek(token) |
| 108 | } |
| 109 | |
| 110 | pub fn fork(&self) -> Self { |
| 111 | self.clone() |
| 112 | } |
| 113 | |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 114 | // Not public API. |
| 115 | #[doc(hidden)] |
| 116 | pub fn step_cursor<F, R>(&self, function: F) -> Result<R> |
| 117 | where |
| 118 | F: for<'c> FnOnce(StepCursor<'c, 'a>) -> Result<(R, Cursor<'c>)>, |
| 119 | { |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 120 | self.check_unexpected()?; |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 121 | match function(StepCursor { |
| 122 | scope: self.scope, |
| 123 | cursor: self.cell.get(), |
| 124 | marker: PhantomData, |
| 125 | }) { |
| 126 | Ok((ret, cursor)) => { |
| 127 | self.cell.set(cursor); |
| 128 | Ok(ret) |
| 129 | } |
| 130 | Err(err) => Err(err), |
| 131 | } |
| 132 | } |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 133 | |
| 134 | // Not public API. |
| 135 | #[doc(hidden)] |
David Tolnay | b77c8b6 | 2018-08-25 16:39:41 -0400 | [diff] [blame^] | 136 | pub fn parse_synom<T>(&self, parse: fn(Cursor) -> PResult<T>) -> Result<T> { |
| 137 | self.step_cursor(|step| parse(step.cursor)) |
| 138 | } |
| 139 | |
| 140 | // Not public API. |
| 141 | #[doc(hidden)] |
David Tolnay | eafc805 | 2018-08-25 16:33:53 -0400 | [diff] [blame] | 142 | pub fn get_unexpected(&self) -> Rc<Cell<Option<Span>>> { |
| 143 | self.unexpected.clone() |
| 144 | } |
| 145 | |
| 146 | // Not public API. |
| 147 | #[doc(hidden)] |
| 148 | pub fn check_unexpected(&self) -> Result<()> { |
| 149 | match self.unexpected.get() { |
| 150 | Some(span) => Err(Error::new(span, "unexpected token")), |
| 151 | None => Ok(()), |
| 152 | } |
| 153 | } |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 154 | } |
| 155 | |
| 156 | impl Parse for Ident { |
| 157 | fn parse(input: ParseStream) -> Result<Self> { |
| 158 | input.step_cursor(|cursor| { |
| 159 | if let Some((ident, rest)) = cursor.ident() { |
David Tolnay | c4fdb1a | 2018-08-24 21:11:07 -0400 | [diff] [blame] | 160 | match ident.to_string().as_str() { |
| 161 | "_" |
| 162 | // Based on https://doc.rust-lang.org/grammar.html#keywords |
| 163 | // and https://github.com/rust-lang/rfcs/blob/master/text/2421-unreservations-2018.md |
| 164 | | "abstract" | "as" | "become" | "box" | "break" | "const" |
| 165 | | "continue" | "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" |
| 166 | | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" |
| 167 | | "mod" | "move" | "mut" | "override" | "priv" | "proc" | "pub" |
| 168 | | "ref" | "return" | "Self" | "self" | "static" | "struct" |
| 169 | | "super" | "trait" | "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" |
| 170 | | "virtual" | "where" | "while" | "yield" => {} |
| 171 | _ => return Ok((ident, rest)), |
| 172 | } |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 173 | } |
David Tolnay | c4fdb1a | 2018-08-24 21:11:07 -0400 | [diff] [blame] | 174 | Err(cursor.error("expected identifier")) |
David Tolnay | 18c754c | 2018-08-21 23:26:58 -0400 | [diff] [blame] | 175 | }) |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | // In reality the impl would be for Punctuated. |
| 180 | impl<T: Parse> Parse for Vec<T> { |
| 181 | fn parse(input: ParseStream) -> Result<Self> { |
| 182 | let mut vec = Vec::new(); |
| 183 | while !input.is_empty() { |
| 184 | let t = input.parse::<T>()?; |
| 185 | vec.push(t); |
| 186 | } |
| 187 | Ok(vec) |
| 188 | } |
| 189 | } |