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