parser/
lib.rs

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