Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/parser/src/lib.rs')
-rw-r--r--crates/parser/src/lib.rs126
1 files changed, 79 insertions, 47 deletions
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 841d2aa4e9..c5014be6c3 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -41,63 +41,95 @@ pub use crate::{
syntax_kind::SyntaxKind,
};
-/// rust-analyzer parser allows you to choose one of the possible entry points.
+/// Parse a prefix of the input as a given syntactic construct.
///
-/// The primary consumer of this API are declarative macros, `$x:expr` matchers
-/// are implemented by calling into the parser with non-standard entry point.
-#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
-pub enum ParserEntryPoint {
- SourceFile,
- Path,
+/// This is used by macro-by-example parser to implement things like `$i:item`
+/// and the naming of variants follows the naming of macro fragments.
+///
+/// Note that this is generally non-optional -- the result is intentionally not
+/// `Option<Output>`. The way MBE work, by the time we *try* to parse `$e:expr`
+/// we already commit to expression. In other words, this API by design can't be
+/// used to implement "rollback and try another alternative" logic.
+#[derive(Debug)]
+pub enum PrefixEntryPoint {
+ Vis,
+ Block,
+ Stmt,
+ Pat,
+ Ty,
Expr,
- Statement,
- StatementOptionalSemi,
- Type,
- Pattern,
+ Path,
Item,
- Block,
- Visibility,
MetaItem,
- Items,
- Statements,
- Attr,
}
-/// Parse given tokens into the given sink as a rust file.
-pub fn parse_source_file(inp: &Input) -> Output {
- parse(inp, ParserEntryPoint::SourceFile)
+impl PrefixEntryPoint {
+ pub fn parse(&self, input: &Input) -> Output {
+ let entry_point: fn(&'_ mut parser::Parser) = match self {
+ PrefixEntryPoint::Vis => grammar::entry::prefix::vis,
+ PrefixEntryPoint::Block => grammar::entry::prefix::block,
+ PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt,
+ PrefixEntryPoint::Pat => grammar::entry::prefix::pat,
+ PrefixEntryPoint::Ty => grammar::entry::prefix::ty,
+ PrefixEntryPoint::Expr => grammar::entry::prefix::expr,
+ PrefixEntryPoint::Path => grammar::entry::prefix::path,
+ PrefixEntryPoint::Item => grammar::entry::prefix::item,
+ PrefixEntryPoint::MetaItem => grammar::entry::prefix::meta_item,
+ };
+ let mut p = parser::Parser::new(input);
+ entry_point(&mut p);
+ let events = p.finish();
+ event::process(events)
+ }
}
-/// Parses the given [`Input`] into [`Output`] assuming that the top-level
-/// syntactic construct is the given [`ParserEntryPoint`].
+/// Parse the whole of the input as a given syntactic construct.
+///
+/// This covers two main use-cases:
+///
+/// * Parsing a Rust file.
+/// * Parsing a result of macro expansion.
///
-/// Both input and output here are fairly abstract. The overall flow is that the
-/// caller has some "real" tokens, converts them to [`Input`], parses them to
-/// [`Output`], and then converts that into a "real" tree. The "real" tree is
-/// made of "real" tokens, so this all hinges on rather tight coordination of
-/// indices between the four stages.
-pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output {
- let entry_point: fn(&'_ mut parser::Parser) = match entry_point {
- ParserEntryPoint::SourceFile => grammar::entry_points::source_file,
- ParserEntryPoint::Path => grammar::entry_points::path,
- ParserEntryPoint::Expr => grammar::entry_points::expr,
- ParserEntryPoint::Type => grammar::entry_points::type_,
- ParserEntryPoint::Pattern => grammar::entry_points::pattern,
- ParserEntryPoint::Item => grammar::entry_points::item,
- ParserEntryPoint::Block => grammar::entry_points::block_expr,
- ParserEntryPoint::Visibility => grammar::entry_points::visibility,
- ParserEntryPoint::MetaItem => grammar::entry_points::meta_item,
- ParserEntryPoint::Statement => grammar::entry_points::stmt,
- ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi,
- ParserEntryPoint::Items => grammar::entry_points::macro_items,
- ParserEntryPoint::Statements => grammar::entry_points::macro_stmts,
- ParserEntryPoint::Attr => grammar::entry_points::attr,
- };
+/// That is, for something like
+///
+/// ```
+/// quick_check! {
+/// fn prop() {}
+/// }
+/// ```
+///
+/// the input to the macro will be parsed with [`PrefixEntryPoint::Item`], and
+/// the result will be [`TopEntryPoint::Items`].
+///
+/// This *should* (but currently doesn't) guarantee that all input is consumed.
+#[derive(Debug)]
+pub enum TopEntryPoint {
+ SourceFile,
+ MacroStmts,
+ MacroItems,
+ Pattern,
+ Type,
+ Expr,
+ MetaItem,
+}
- let mut p = parser::Parser::new(inp);
- entry_point(&mut p);
- let events = p.finish();
- event::process(events)
+impl TopEntryPoint {
+ pub fn parse(&self, input: &Input) -> Output {
+ let entry_point: fn(&'_ mut parser::Parser) = match self {
+ TopEntryPoint::SourceFile => grammar::entry::top::source_file,
+ TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts,
+ TopEntryPoint::MacroItems => grammar::entry::top::macro_items,
+ // FIXME
+ TopEntryPoint::Pattern => grammar::entry::prefix::pat,
+ TopEntryPoint::Type => grammar::entry::prefix::ty,
+ TopEntryPoint::Expr => grammar::entry::prefix::expr,
+ TopEntryPoint::MetaItem => grammar::entry::prefix::meta_item,
+ };
+ let mut p = parser::Parser::new(input);
+ entry_point(&mut p);
+ let events = p.finish();
+ event::process(events)
+ }
}
/// A parsing function for a specific braced-block.