mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
add TopEntryPoint
This commit is contained in:
parent
8e7fc7be65
commit
afffa096f6
8 changed files with 96 additions and 52 deletions
|
@ -714,8 +714,7 @@ impl Attr {
|
||||||
hygiene: &Hygiene,
|
hygiene: &Hygiene,
|
||||||
id: AttrId,
|
id: AttrId,
|
||||||
) -> Option<Attr> {
|
) -> Option<Attr> {
|
||||||
let (parse, _) =
|
let (parse, _) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MetaItem).ok()?;
|
||||||
mbe::token_tree_to_syntax_node(tt, mbe::ParserEntryPoint::MetaItem).ok()?;
|
|
||||||
let ast = ast::Meta::cast(parse.syntax_node())?;
|
let ast = ast::Meta::cast(parse.syntax_node())?;
|
||||||
|
|
||||||
Self::from_src(db, ast, hygiene, id)
|
Self::from_src(db, ast, hygiene, id)
|
||||||
|
|
|
@ -72,7 +72,7 @@ struct BasicAdtInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> {
|
fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> {
|
||||||
let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::ParserEntryPoint::Items)?; // FragmentKind::Items doesn't parse attrs?
|
let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MacroItems)?; // FragmentKind::Items doesn't parse attrs?
|
||||||
let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| {
|
let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| {
|
||||||
debug!("derive node didn't parse");
|
debug!("derive node didn't parse");
|
||||||
mbe::ExpandError::UnexpectedToken
|
mbe::ExpandError::UnexpectedToken
|
||||||
|
|
|
@ -497,11 +497,11 @@ fn token_tree_to_syntax_node(
|
||||||
expand_to: ExpandTo,
|
expand_to: ExpandTo,
|
||||||
) -> Result<(Parse<SyntaxNode>, mbe::TokenMap), ExpandError> {
|
) -> Result<(Parse<SyntaxNode>, mbe::TokenMap), ExpandError> {
|
||||||
let entry_point = match expand_to {
|
let entry_point = match expand_to {
|
||||||
ExpandTo::Statements => mbe::ParserEntryPoint::Statements,
|
ExpandTo::Statements => mbe::TopEntryPoint::MacroStmts,
|
||||||
ExpandTo::Items => mbe::ParserEntryPoint::Items,
|
ExpandTo::Items => mbe::TopEntryPoint::MacroItems,
|
||||||
ExpandTo::Pattern => mbe::ParserEntryPoint::Pattern,
|
ExpandTo::Pattern => mbe::TopEntryPoint::Pattern,
|
||||||
ExpandTo::Type => mbe::ParserEntryPoint::Type,
|
ExpandTo::Type => mbe::TopEntryPoint::Type,
|
||||||
ExpandTo::Expr => mbe::ParserEntryPoint::Expr,
|
ExpandTo::Expr => mbe::TopEntryPoint::Expr,
|
||||||
};
|
};
|
||||||
mbe::token_tree_to_syntax_node(tt, entry_point)
|
mbe::token_tree_to_syntax_node(tt, entry_point)
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,7 @@ pub fn expand_eager_macro(
|
||||||
let arg_file_id = arg_id;
|
let arg_file_id = arg_id;
|
||||||
|
|
||||||
let parsed_args = diagnostic_sink
|
let parsed_args = diagnostic_sink
|
||||||
.result(mbe::token_tree_to_syntax_node(&parsed_args, mbe::ParserEntryPoint::Expr))?
|
.result(mbe::token_tree_to_syntax_node(&parsed_args, mbe::TopEntryPoint::Expr))?
|
||||||
.0;
|
.0;
|
||||||
let result = eager_macro_recur(
|
let result = eager_macro_recur(
|
||||||
db,
|
db,
|
||||||
|
|
|
@ -24,7 +24,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: we probably should re-think `token_tree_to_syntax_node` interfaces
|
// FIXME: we probably should re-think `token_tree_to_syntax_node` interfaces
|
||||||
pub use ::parser::ParserEntryPoint;
|
pub use ::parser::TopEntryPoint;
|
||||||
pub use tt::{Delimiter, DelimiterKind, Punct};
|
pub use tt::{Delimiter, DelimiterKind, Punct};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
|
|
@ -9,9 +9,7 @@ use syntax::{
|
||||||
};
|
};
|
||||||
use tt::buffer::{Cursor, TokenBuffer};
|
use tt::buffer::{Cursor, TokenBuffer};
|
||||||
|
|
||||||
use crate::{
|
use crate::{to_parser_input::to_parser_input, tt_iter::TtIter, ExpandError, TokenMap};
|
||||||
to_parser_input::to_parser_input, tt_iter::TtIter, ExpandError, ParserEntryPoint, TokenMap,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Convert the syntax node to a `TokenTree` (what macro
|
/// Convert the syntax node to a `TokenTree` (what macro
|
||||||
/// will consume).
|
/// will consume).
|
||||||
|
@ -46,7 +44,7 @@ pub fn syntax_node_to_token_tree_censored(
|
||||||
|
|
||||||
pub fn token_tree_to_syntax_node(
|
pub fn token_tree_to_syntax_node(
|
||||||
tt: &tt::Subtree,
|
tt: &tt::Subtree,
|
||||||
entry_point: ParserEntryPoint,
|
entry_point: parser::TopEntryPoint,
|
||||||
) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> {
|
) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> {
|
||||||
let buffer = match tt {
|
let buffer = match tt {
|
||||||
tt::Subtree { delimiter: None, token_trees } => {
|
tt::Subtree { delimiter: None, token_trees } => {
|
||||||
|
@ -55,7 +53,7 @@ pub fn token_tree_to_syntax_node(
|
||||||
_ => TokenBuffer::from_subtree(tt),
|
_ => TokenBuffer::from_subtree(tt),
|
||||||
};
|
};
|
||||||
let parser_input = to_parser_input(&buffer);
|
let parser_input = to_parser_input(&buffer);
|
||||||
let parser_output = parser::parse(&parser_input, entry_point);
|
let parser_output = entry_point.parse(&parser_input);
|
||||||
let mut tree_sink = TtTreeSink::new(buffer.begin());
|
let mut tree_sink = TtTreeSink::new(buffer.begin());
|
||||||
for event in parser_output.iter() {
|
for event in parser_output.iter() {
|
||||||
match event {
|
match event {
|
||||||
|
|
|
@ -83,43 +83,47 @@ pub(crate) mod entry {
|
||||||
attributes::meta(p);
|
attributes::meta(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) mod top {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub(crate) fn source_file(p: &mut Parser) {
|
||||||
|
let m = p.start();
|
||||||
|
p.eat(SHEBANG);
|
||||||
|
items::mod_contents(p, false);
|
||||||
|
m.complete(p, SOURCE_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn macro_stmts(p: &mut Parser) {
|
||||||
|
let m = p.start();
|
||||||
|
|
||||||
|
while !p.at(EOF) {
|
||||||
|
if p.at(T![;]) {
|
||||||
|
p.bump(T![;]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
expressions::stmt(p, expressions::StmtWithSemi::Optional, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.complete(p, MACRO_STMTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn macro_items(p: &mut Parser) {
|
||||||
|
let m = p.start();
|
||||||
|
items::mod_contents(p, false);
|
||||||
|
m.complete(p, MACRO_ITEMS);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod entry_points {
|
pub(crate) mod entry_points {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub(crate) fn source_file(p: &mut Parser) {
|
|
||||||
let m = p.start();
|
|
||||||
p.eat(SHEBANG);
|
|
||||||
items::mod_contents(p, false);
|
|
||||||
m.complete(p, SOURCE_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn stmt_optional_semi(p: &mut Parser) {
|
pub(crate) fn stmt_optional_semi(p: &mut Parser) {
|
||||||
expressions::stmt(p, expressions::StmtWithSemi::Optional, false);
|
expressions::stmt(p, expressions::StmtWithSemi::Optional, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn macro_items(p: &mut Parser) {
|
|
||||||
let m = p.start();
|
|
||||||
items::mod_contents(p, false);
|
|
||||||
m.complete(p, MACRO_ITEMS);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn macro_stmts(p: &mut Parser) {
|
|
||||||
let m = p.start();
|
|
||||||
|
|
||||||
while !p.at(EOF) {
|
|
||||||
if p.at(T![;]) {
|
|
||||||
p.bump(T![;]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
expressions::stmt(p, expressions::StmtWithSemi::Optional, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
m.complete(p, MACRO_STMTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn attr(p: &mut Parser) {
|
pub(crate) fn attr(p: &mut Parser) {
|
||||||
attributes::outer_attrs(p);
|
attributes::outer_attrs(p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ pub use crate::{
|
||||||
syntax_kind::SyntaxKind,
|
syntax_kind::SyntaxKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parse a syntactic construct at the *start* of the input.
|
/// Parse a prefix of the input as a given syntactic construct.
|
||||||
///
|
///
|
||||||
/// This is used by macro-by-example parser to implement things like `$i:item`
|
/// 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.
|
/// and the naming of variants follows the naming of macro fragments.
|
||||||
|
@ -83,13 +83,61 @@ impl PrefixEntryPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// rust-analyzer parser allows you to choose one of the possible entry points.
|
/// rust-analyzer parser allows you to choose one of the possible entry points.
|
||||||
///
|
///
|
||||||
/// The primary consumer of this API are declarative macros, `$x:expr` matchers
|
/// The primary consumer of this API are declarative macros, `$x:expr` matchers
|
||||||
/// are implemented by calling into the parser with non-standard entry point.
|
/// are implemented by calling into the parser with non-standard entry point.
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
pub enum ParserEntryPoint {
|
pub enum ParserEntryPoint {
|
||||||
SourceFile,
|
|
||||||
Path,
|
Path,
|
||||||
Expr,
|
Expr,
|
||||||
StatementOptionalSemi,
|
StatementOptionalSemi,
|
||||||
|
@ -97,14 +145,12 @@ pub enum ParserEntryPoint {
|
||||||
Pattern,
|
Pattern,
|
||||||
Item,
|
Item,
|
||||||
MetaItem,
|
MetaItem,
|
||||||
Items,
|
|
||||||
Statements,
|
|
||||||
Attr,
|
Attr,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse given tokens into the given sink as a rust file.
|
/// Parse given tokens into the given sink as a rust file.
|
||||||
pub fn parse_source_file(inp: &Input) -> Output {
|
pub fn parse_source_file(input: &Input) -> Output {
|
||||||
parse(inp, ParserEntryPoint::SourceFile)
|
TopEntryPoint::SourceFile.parse(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the given [`Input`] into [`Output`] assuming that the top-level
|
/// Parses the given [`Input`] into [`Output`] assuming that the top-level
|
||||||
|
@ -117,7 +163,6 @@ pub fn parse_source_file(inp: &Input) -> Output {
|
||||||
/// indices between the four stages.
|
/// indices between the four stages.
|
||||||
pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output {
|
pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output {
|
||||||
let entry_point: fn(&'_ mut parser::Parser) = match entry_point {
|
let entry_point: fn(&'_ mut parser::Parser) = match entry_point {
|
||||||
ParserEntryPoint::SourceFile => grammar::entry_points::source_file,
|
|
||||||
ParserEntryPoint::Path => grammar::entry::prefix::path,
|
ParserEntryPoint::Path => grammar::entry::prefix::path,
|
||||||
ParserEntryPoint::Expr => grammar::entry::prefix::expr,
|
ParserEntryPoint::Expr => grammar::entry::prefix::expr,
|
||||||
ParserEntryPoint::Type => grammar::entry::prefix::ty,
|
ParserEntryPoint::Type => grammar::entry::prefix::ty,
|
||||||
|
@ -125,8 +170,6 @@ pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output {
|
||||||
ParserEntryPoint::Item => grammar::entry::prefix::item,
|
ParserEntryPoint::Item => grammar::entry::prefix::item,
|
||||||
ParserEntryPoint::MetaItem => grammar::entry::prefix::meta_item,
|
ParserEntryPoint::MetaItem => grammar::entry::prefix::meta_item,
|
||||||
ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi,
|
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,
|
ParserEntryPoint::Attr => grammar::entry_points::attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue