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