Fix up the syntax tree for macro 2.0

This commit is contained in:
Lukas Wirth 2024-07-03 10:41:19 +02:00
parent 26c7bfd0b4
commit 013b6a883f
9 changed files with 226 additions and 169 deletions

View file

@ -172,15 +172,30 @@ impl DeclarativeMacroExpander {
), ),
ast::Macro::MacroDef(macro_def) => ( ast::Macro::MacroDef(macro_def) => (
match macro_def.body() { match macro_def.body() {
Some(arg) => { Some(body) => {
let tt = mbe::syntax_node_to_token_tree( let span =
arg.syntax(), map.span_for_range(macro_def.macro_token().unwrap().text_range());
let args = macro_def.args().map(|args| {
mbe::syntax_node_to_token_tree(
args.syntax(),
map.as_ref(),
span,
DocCommentDesugarMode::Mbe,
)
});
let body = mbe::syntax_node_to_token_tree(
body.syntax(),
map.as_ref(), map.as_ref(),
map.span_for_range(macro_def.macro_token().unwrap().text_range()), span,
DocCommentDesugarMode::Mbe, DocCommentDesugarMode::Mbe,
); );
mbe::DeclarativeMacro::parse_macro2(&tt, edition, new_meta_vars) mbe::DeclarativeMacro::parse_macro2(
args.as_ref(),
&body,
edition,
new_meta_vars,
)
} }
None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected( None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected(
"expected a token tree".into(), "expected a token tree".into(),

View file

@ -156,7 +156,7 @@ impl DeclarativeMacro {
let mut err = None; let mut err = None;
while src.len() > 0 { while src.len() > 0 {
let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) { let rule = match Rule::parse(edition, &mut src, new_meta_vars) {
Ok(it) => it, Ok(it) => it,
Err(e) => { Err(e) => {
err = Some(Box::new(e)); err = Some(Box::new(e));
@ -184,19 +184,34 @@ impl DeclarativeMacro {
/// The new, unstable `macro m {}` flavor. /// The new, unstable `macro m {}` flavor.
pub fn parse_macro2( pub fn parse_macro2(
tt: &tt::Subtree<Span>, args: Option<&tt::Subtree<Span>>,
body: &tt::Subtree<Span>,
edition: impl Copy + Fn(SyntaxContextId) -> Edition, edition: impl Copy + Fn(SyntaxContextId) -> Edition,
// FIXME: Remove this once we drop support for rust 1.76 (defaults to true then) // FIXME: Remove this once we drop support for rust 1.76 (defaults to true then)
new_meta_vars: bool, new_meta_vars: bool,
) -> DeclarativeMacro { ) -> DeclarativeMacro {
let mut src = TtIter::new(tt);
let mut rules = Vec::new(); let mut rules = Vec::new();
let mut err = None; let mut err = None;
if tt::DelimiterKind::Brace == tt.delimiter.kind { if let Some(args) = args {
cov_mark::hit!(parse_macro_def_simple);
let rule = (|| {
let lhs = MetaTemplate::parse_pattern(edition, args)?;
let rhs = MetaTemplate::parse_template(edition, body, new_meta_vars)?;
Ok(crate::Rule { lhs, rhs })
})();
match rule {
Ok(rule) => rules.push(rule),
Err(e) => err = Some(Box::new(e)),
}
} else {
cov_mark::hit!(parse_macro_def_rules); cov_mark::hit!(parse_macro_def_rules);
let mut src = TtIter::new(body);
while src.len() > 0 { while src.len() > 0 {
let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) { let rule = match Rule::parse(edition, &mut src, new_meta_vars) {
Ok(it) => it, Ok(it) => it,
Err(e) => { Err(e) => {
err = Some(Box::new(e)); err = Some(Box::new(e));
@ -213,19 +228,6 @@ impl DeclarativeMacro {
break; break;
} }
} }
} else {
cov_mark::hit!(parse_macro_def_simple);
match Rule::parse(edition, &mut src, false, new_meta_vars) {
Ok(rule) => {
if src.len() != 0 {
err = Some(Box::new(ParseError::expected("remaining tokens in macro def")));
}
rules.push(rule);
}
Err(e) => {
err = Some(Box::new(e));
}
}
} }
for Rule { lhs, .. } in &rules { for Rule { lhs, .. } in &rules {
@ -262,14 +264,11 @@ impl Rule {
fn parse( fn parse(
edition: impl Copy + Fn(SyntaxContextId) -> Edition, edition: impl Copy + Fn(SyntaxContextId) -> Edition,
src: &mut TtIter<'_, Span>, src: &mut TtIter<'_, Span>,
expect_arrow: bool,
new_meta_vars: bool, new_meta_vars: bool,
) -> Result<Self, ParseError> { ) -> Result<Self, ParseError> {
let lhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?; let lhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?;
if expect_arrow { src.expect_char('=').map_err(|()| ParseError::expected("expected `=`"))?;
src.expect_char('=').map_err(|()| ParseError::expected("expected `=`"))?; src.expect_char('>').map_err(|()| ParseError::expected("expected `>`"))?;
src.expect_char('>').map_err(|()| ParseError::expected("expected `>`"))?;
}
let rhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?; let rhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?;
let lhs = MetaTemplate::parse_pattern(edition, lhs)?; let lhs = MetaTemplate::parse_pattern(edition, lhs)?;

View file

@ -372,13 +372,11 @@ fn macro_def(p: &mut Parser<'_>, m: Marker) {
// macro m { ($i:ident) => {} } // macro m { ($i:ident) => {} }
token_tree(p); token_tree(p);
} else if p.at(T!['(']) { } else if p.at(T!['(']) {
let m = p.start();
token_tree(p); token_tree(p);
match p.current() { match p.current() {
T!['{'] | T!['['] | T!['('] => token_tree(p), T!['{'] | T!['['] | T!['('] => token_tree(p),
_ => p.error("expected `{`, `[`, `(`"), _ => p.error("expected `{`, `[`, `(`"),
} }
m.complete(p, TOKEN_TREE);
} else { } else {
p.error("unmatched `(`"); p.error("unmatched `(`");
} }

View file

@ -5,15 +5,14 @@ SOURCE_FILE
NAME NAME
IDENT "m" IDENT "m"
TOKEN_TREE TOKEN_TREE
TOKEN_TREE L_PAREN "("
L_PAREN "(" DOLLAR "$"
DOLLAR "$" IDENT "i"
IDENT "i" COLON ":"
COLON ":" IDENT "ident"
IDENT "ident" R_PAREN ")"
R_PAREN ")" WHITESPACE " "
WHITESPACE " " TOKEN_TREE
TOKEN_TREE L_CURLY "{"
L_CURLY "{" R_CURLY "}"
R_CURLY "}"
WHITESPACE "\n" WHITESPACE "\n"

View file

@ -39,16 +39,15 @@ SOURCE_FILE
NAME NAME
IDENT "m" IDENT "m"
TOKEN_TREE TOKEN_TREE
TOKEN_TREE L_PAREN "("
L_PAREN "(" DOLLAR "$"
DOLLAR "$" COLON ":"
COLON ":" IDENT "ident"
IDENT "ident" R_PAREN ")"
R_PAREN ")" WHITESPACE " "
WHITESPACE " " TOKEN_TREE
TOKEN_TREE L_CURLY "{"
L_CURLY "{" R_CURLY "}"
R_CURLY "}"
WHITESPACE "\n" WHITESPACE "\n"
FN FN
VISIBILITY VISIBILITY

View file

@ -5,51 +5,50 @@ SOURCE_FILE
NAME NAME
IDENT "parse_use_trees" IDENT "parse_use_trees"
TOKEN_TREE TOKEN_TREE
L_PAREN "("
DOLLAR "$"
TOKEN_TREE TOKEN_TREE
L_PAREN "(" L_PAREN "("
DOLLAR "$" DOLLAR "$"
TOKEN_TREE IDENT "s"
L_PAREN "(" COLON ":"
DOLLAR "$" IDENT "expr"
IDENT "s" R_PAREN ")"
COLON ":" COMMA ","
IDENT "expr" STAR "*"
R_PAREN ")" WHITESPACE " "
DOLLAR "$"
TOKEN_TREE
L_PAREN "("
COMMA "," COMMA ","
STAR "*" R_PAREN ")"
WHITESPACE " " STAR "*"
R_PAREN ")"
WHITESPACE " "
TOKEN_TREE
L_CURLY "{"
WHITESPACE "\n "
IDENT "vec"
BANG "!"
TOKEN_TREE
L_BRACK "["
WHITESPACE "\n "
DOLLAR "$" DOLLAR "$"
TOKEN_TREE TOKEN_TREE
L_PAREN "(" L_PAREN "("
IDENT "parse_use_tree"
TOKEN_TREE
L_PAREN "("
DOLLAR "$"
IDENT "s"
R_PAREN ")"
COMMA "," COMMA ","
R_PAREN ")" R_PAREN ")"
STAR "*" STAR "*"
R_PAREN ")"
WHITESPACE " "
TOKEN_TREE
L_CURLY "{"
WHITESPACE "\n " WHITESPACE "\n "
IDENT "vec" R_BRACK "]"
BANG "!" WHITESPACE "\n"
TOKEN_TREE R_CURLY "}"
L_BRACK "["
WHITESPACE "\n "
DOLLAR "$"
TOKEN_TREE
L_PAREN "("
IDENT "parse_use_tree"
TOKEN_TREE
L_PAREN "("
DOLLAR "$"
IDENT "s"
R_PAREN ")"
COMMA ","
R_PAREN ")"
STAR "*"
WHITESPACE "\n "
R_BRACK "]"
WHITESPACE "\n"
R_CURLY "}"
WHITESPACE "\n\n" WHITESPACE "\n\n"
FN FN
ATTR ATTR
@ -80,79 +79,62 @@ SOURCE_FILE
NAME NAME
IDENT "test_merge" IDENT "test_merge"
TOKEN_TREE TOKEN_TREE
L_PAREN "("
TOKEN_TREE TOKEN_TREE
L_PAREN "(" L_BRACK "["
TOKEN_TREE DOLLAR "$"
L_BRACK "[" TOKEN_TREE
DOLLAR "$" L_PAREN "("
TOKEN_TREE DOLLAR "$"
L_PAREN "(" IDENT "input"
DOLLAR "$" COLON ":"
IDENT "input" IDENT "expr"
COLON ":" R_PAREN ")"
IDENT "expr" COMMA ","
R_PAREN ")" STAR "*"
COMMA "," WHITESPACE " "
STAR "*" DOLLAR "$"
WHITESPACE " "
DOLLAR "$"
TOKEN_TREE
L_PAREN "("
COMMA ","
R_PAREN ")"
STAR "*"
R_BRACK "]"
COMMA ","
WHITESPACE " "
TOKEN_TREE
L_BRACK "["
DOLLAR "$"
TOKEN_TREE
L_PAREN "("
DOLLAR "$"
IDENT "output"
COLON ":"
IDENT "expr"
R_PAREN ")"
COMMA ","
STAR "*"
WHITESPACE " "
DOLLAR "$"
TOKEN_TREE
L_PAREN "("
COMMA ","
R_PAREN ")"
STAR "*"
R_BRACK "]"
R_PAREN ")"
WHITESPACE " "
TOKEN_TREE
L_CURLY "{"
WHITESPACE "\n "
IDENT "assert_eq"
BANG "!"
TOKEN_TREE TOKEN_TREE
L_PAREN "(" L_PAREN "("
WHITESPACE "\n "
IDENT "merge_use_trees"
TOKEN_TREE
L_PAREN "("
IDENT "parse_use_trees"
BANG "!"
TOKEN_TREE
L_PAREN "("
DOLLAR "$"
TOKEN_TREE
L_PAREN "("
DOLLAR "$"
IDENT "input"
COMMA ","
R_PAREN ")"
STAR "*"
R_PAREN ")"
R_PAREN ")"
COMMA "," COMMA ","
WHITESPACE "\n " R_PAREN ")"
STAR "*"
R_BRACK "]"
COMMA ","
WHITESPACE " "
TOKEN_TREE
L_BRACK "["
DOLLAR "$"
TOKEN_TREE
L_PAREN "("
DOLLAR "$"
IDENT "output"
COLON ":"
IDENT "expr"
R_PAREN ")"
COMMA ","
STAR "*"
WHITESPACE " "
DOLLAR "$"
TOKEN_TREE
L_PAREN "("
COMMA ","
R_PAREN ")"
STAR "*"
R_BRACK "]"
R_PAREN ")"
WHITESPACE " "
TOKEN_TREE
L_CURLY "{"
WHITESPACE "\n "
IDENT "assert_eq"
BANG "!"
TOKEN_TREE
L_PAREN "("
WHITESPACE "\n "
IDENT "merge_use_trees"
TOKEN_TREE
L_PAREN "("
IDENT "parse_use_trees" IDENT "parse_use_trees"
BANG "!" BANG "!"
TOKEN_TREE TOKEN_TREE
@ -161,17 +143,33 @@ SOURCE_FILE
TOKEN_TREE TOKEN_TREE
L_PAREN "(" L_PAREN "("
DOLLAR "$" DOLLAR "$"
IDENT "output" IDENT "input"
COMMA "," COMMA ","
R_PAREN ")" R_PAREN ")"
STAR "*" STAR "*"
R_PAREN ")" R_PAREN ")"
COMMA ","
WHITESPACE "\n "
R_PAREN ")" R_PAREN ")"
SEMICOLON ";" COMMA ","
WHITESPACE "\n " WHITESPACE "\n "
R_CURLY "}" IDENT "parse_use_trees"
BANG "!"
TOKEN_TREE
L_PAREN "("
DOLLAR "$"
TOKEN_TREE
L_PAREN "("
DOLLAR "$"
IDENT "output"
COMMA ","
R_PAREN ")"
STAR "*"
R_PAREN ")"
COMMA ","
WHITESPACE "\n "
R_PAREN ")"
SEMICOLON ";"
WHITESPACE "\n "
R_CURLY "}"
WHITESPACE "\n" WHITESPACE "\n"
R_CURLY "}" R_CURLY "}"
WHITESPACE "\n" WHITESPACE "\n"

View file

@ -6,7 +6,8 @@ use crate::{
ast::{ ast::{
self, self,
operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}, operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp},
support, AstChildren, AstNode, support, ArgList, AstChildren, AstNode, BlockExpr, ClosureExpr, Const, Expr, Fn,
FormatArgsArg, FormatArgsExpr, MacroDef, Static, TokenTree,
}, },
AstToken, AstToken,
SyntaxKind::*, SyntaxKind::*,
@ -435,3 +436,57 @@ impl AstNode for CallableExpr {
} }
} }
} }
impl MacroDef {
fn tts(&self) -> (Option<ast::TokenTree>, Option<ast::TokenTree>) {
let mut types = support::children(self.syntax());
let first = types.next();
let second = types.next();
(first, second)
}
pub fn args(&self) -> Option<TokenTree> {
match self.tts() {
(Some(args), Some(_)) => Some(args),
_ => None,
}
}
pub fn body(&self) -> Option<TokenTree> {
match self.tts() {
(Some(body), None) | (_, Some(body)) => Some(body),
_ => None,
}
}
}
impl ClosureExpr {
pub fn body(&self) -> Option<Expr> {
support::child(&self.syntax)
}
}
impl Const {
pub fn body(&self) -> Option<Expr> {
support::child(&self.syntax)
}
}
impl Fn {
pub fn body(&self) -> Option<BlockExpr> {
support::child(&self.syntax)
}
}
impl Static {
pub fn body(&self) -> Option<Expr> {
support::child(&self.syntax)
}
}
impl FormatArgsExpr {
pub fn args(&self) -> AstChildren<FormatArgsArg> {
support::children(&self.syntax)
}
}
impl ArgList {
pub fn args(&self) -> AstChildren<Expr> {
support::children(&self.syntax)
}
}

View file

@ -20,7 +20,6 @@ pub struct ArgList {
pub(crate) syntax: SyntaxNode, pub(crate) syntax: SyntaxNode,
} }
impl ArgList { impl ArgList {
pub fn args(&self) -> AstChildren<Expr> { support::children(&self.syntax) }
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
} }
@ -191,7 +190,6 @@ pub struct ClosureExpr {
} }
impl ast::HasAttrs for ClosureExpr {} impl ast::HasAttrs for ClosureExpr {}
impl ClosureExpr { impl ClosureExpr {
pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) } pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) } pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) } pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
@ -211,7 +209,6 @@ impl ast::HasDocComments for Const {}
impl ast::HasName for Const {} impl ast::HasName for Const {}
impl ast::HasVisibility for Const {} impl ast::HasVisibility for Const {}
impl Const { impl Const {
pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
@ -356,7 +353,6 @@ impl ast::HasName for Fn {}
impl ast::HasVisibility for Fn {} impl ast::HasVisibility for Fn {}
impl Fn { impl Fn {
pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) } pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) }
pub fn body(&self) -> Option<BlockExpr> { support::child(&self.syntax) }
pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) } pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) }
pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) } pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
@ -418,7 +414,6 @@ pub struct FormatArgsExpr {
} }
impl ast::HasAttrs for FormatArgsExpr {} impl ast::HasAttrs for FormatArgsExpr {}
impl FormatArgsExpr { impl FormatArgsExpr {
pub fn args(&self) -> AstChildren<FormatArgsArg> { support::children(&self.syntax) }
pub fn template(&self) -> Option<Expr> { support::child(&self.syntax) } pub fn template(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) } pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
@ -652,8 +647,6 @@ impl ast::HasDocComments for MacroDef {}
impl ast::HasName for MacroDef {} impl ast::HasName for MacroDef {}
impl ast::HasVisibility for MacroDef {} impl ast::HasVisibility for MacroDef {}
impl MacroDef { impl MacroDef {
pub fn args(&self) -> Option<TokenTree> { support::child(&self.syntax) }
pub fn body(&self) -> Option<TokenTree> { support::child(&self.syntax) }
pub fn macro_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![macro]) } pub fn macro_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![macro]) }
} }
@ -1224,7 +1217,6 @@ impl ast::HasDocComments for Static {}
impl ast::HasName for Static {} impl ast::HasName for Static {}
impl ast::HasVisibility for Static {} impl ast::HasVisibility for Static {}
impl Static { impl Static {
pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }

View file

@ -692,6 +692,8 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r
| "self_ty" | "self_ty"
| "iterable" | "iterable"
| "condition" | "condition"
| "args"
| "body"
); );
if manually_implemented { if manually_implemented {
return; return;