• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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