1 //! The Rust parser. 2 //! 3 //! NOTE: The crate is undergoing refactors, don't believe everything the docs 4 //! say :-) 5 //! 6 //! The parser doesn't know about concrete representation of tokens and syntax 7 //! trees. Abstract [`TokenSource`] and [`TreeSink`] traits are used instead. As 8 //! a consequence, this crate does not contain a lexer. 9 //! 10 //! The [`Parser`] struct from the [`parser`] module is a cursor into the 11 //! sequence of tokens. Parsing routines use [`Parser`] to inspect current 12 //! state and advance the parsing. 13 //! 14 //! The actual parsing happens in the [`grammar`] module. 15 //! 16 //! Tests for this crate live in the `syntax` crate. 17 //! 18 //! [`Parser`]: crate::parser::Parser 19 20 #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] 21 #![allow(rustdoc::private_intra_doc_links)] 22 23 mod lexed_str; 24 mod token_set; 25 mod syntax_kind; 26 mod event; 27 mod parser; 28 mod grammar; 29 mod input; 30 mod output; 31 mod shortcuts; 32 33 #[cfg(test)] 34 mod tests; 35 36 pub(crate) use token_set::TokenSet; 37 38 pub use crate::{ 39 input::Input, 40 lexed_str::LexedStr, 41 output::{Output, Step}, 42 shortcuts::StrStep, 43 syntax_kind::SyntaxKind, 44 }; 45 46 /// Parse the whole of the input as a given syntactic construct. 47 /// 48 /// This covers two main use-cases: 49 /// 50 /// * Parsing a Rust file. 51 /// * Parsing a result of macro expansion. 52 /// 53 /// That is, for something like 54 /// 55 /// ``` 56 /// quick_check! { 57 /// fn prop() {} 58 /// } 59 /// ``` 60 /// 61 /// the input to the macro will be parsed with [`PrefixEntryPoint::Item`], and 62 /// the result will be [`TopEntryPoint::MacroItems`]. 63 /// 64 /// [`TopEntryPoint::parse`] makes a guarantee that 65 /// * all input is consumed 66 /// * the result is a valid tree (there's one root node) 67 #[derive(Debug)] 68 pub enum TopEntryPoint { 69 SourceFile, 70 MacroStmts, 71 MacroItems, 72 Pattern, 73 Type, 74 Expr, 75 /// Edge case -- macros generally don't expand to attributes, with the 76 /// exception of `cfg_attr` which does! 77 MetaItem, 78 } 79 80 impl TopEntryPoint { parse(&self, input: &Input) -> Output81 pub fn parse(&self, input: &Input) -> Output { 82 let entry_point: fn(&'_ mut parser::Parser<'_>) = match self { 83 TopEntryPoint::SourceFile => grammar::entry::top::source_file, 84 TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts, 85 TopEntryPoint::MacroItems => grammar::entry::top::macro_items, 86 TopEntryPoint::Pattern => grammar::entry::top::pattern, 87 TopEntryPoint::Type => grammar::entry::top::type_, 88 TopEntryPoint::Expr => grammar::entry::top::expr, 89 TopEntryPoint::MetaItem => grammar::entry::top::meta_item, 90 }; 91 let mut p = parser::Parser::new(input); 92 entry_point(&mut p); 93 let events = p.finish(); 94 let res = event::process(events); 95 96 if cfg!(debug_assertions) { 97 let mut depth = 0; 98 let mut first = true; 99 for step in res.iter() { 100 assert!(depth > 0 || first); 101 first = false; 102 match step { 103 Step::Enter { .. } => depth += 1, 104 Step::Exit => depth -= 1, 105 Step::FloatSplit { ends_in_dot: has_pseudo_dot } => { 106 depth -= 1 + !has_pseudo_dot as usize 107 } 108 Step::Token { .. } | Step::Error { .. } => (), 109 } 110 } 111 assert!(!first, "no tree at all"); 112 assert_eq!(depth, 0, "unbalanced tree"); 113 } 114 115 res 116 } 117 } 118 119 /// Parse a prefix of the input as a given syntactic construct. 120 /// 121 /// This is used by macro-by-example parser to implement things like `$i:item` 122 /// and the naming of variants follows the naming of macro fragments. 123 /// 124 /// Note that this is generally non-optional -- the result is intentionally not 125 /// `Option<Output>`. The way MBE work, by the time we *try* to parse `$e:expr` 126 /// we already commit to expression. In other words, this API by design can't be 127 /// used to implement "rollback and try another alternative" logic. 128 #[derive(Debug)] 129 pub enum PrefixEntryPoint { 130 Vis, 131 Block, 132 Stmt, 133 Pat, 134 PatTop, 135 Ty, 136 Expr, 137 Path, 138 Item, 139 MetaItem, 140 } 141 142 impl PrefixEntryPoint { parse(&self, input: &Input) -> Output143 pub fn parse(&self, input: &Input) -> Output { 144 let entry_point: fn(&'_ mut parser::Parser<'_>) = match self { 145 PrefixEntryPoint::Vis => grammar::entry::prefix::vis, 146 PrefixEntryPoint::Block => grammar::entry::prefix::block, 147 PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt, 148 PrefixEntryPoint::Pat => grammar::entry::prefix::pat, 149 PrefixEntryPoint::PatTop => grammar::entry::prefix::pat_top, 150 PrefixEntryPoint::Ty => grammar::entry::prefix::ty, 151 PrefixEntryPoint::Expr => grammar::entry::prefix::expr, 152 PrefixEntryPoint::Path => grammar::entry::prefix::path, 153 PrefixEntryPoint::Item => grammar::entry::prefix::item, 154 PrefixEntryPoint::MetaItem => grammar::entry::prefix::meta_item, 155 }; 156 let mut p = parser::Parser::new(input); 157 entry_point(&mut p); 158 let events = p.finish(); 159 event::process(events) 160 } 161 } 162 163 /// A parsing function for a specific braced-block. 164 pub struct Reparser(fn(&mut parser::Parser<'_>)); 165 166 impl Reparser { 167 /// If the node is a braced block, return the corresponding `Reparser`. for_node( node: SyntaxKind, first_child: Option<SyntaxKind>, parent: Option<SyntaxKind>, ) -> Option<Reparser>168 pub fn for_node( 169 node: SyntaxKind, 170 first_child: Option<SyntaxKind>, 171 parent: Option<SyntaxKind>, 172 ) -> Option<Reparser> { 173 grammar::reparser(node, first_child, parent).map(Reparser) 174 } 175 176 /// Re-parse given tokens using this `Reparser`. 177 /// 178 /// Tokens must start with `{`, end with `}` and form a valid brace 179 /// sequence. parse(self, tokens: &Input) -> Output180 pub fn parse(self, tokens: &Input) -> Output { 181 let Reparser(r) = self; 182 let mut p = parser::Parser::new(tokens); 183 r(&mut p); 184 let events = p.finish(); 185 event::process(events) 186 } 187 } 188