mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-01 10:25:41 +00:00
Merge #1168
1168: Add all remaining mbe matchers r=matklad a=edwin0cheng This PR adds following mbe matchers: * block * meta * tt * literal * vis Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
commit
d15abaa06f
@ -731,4 +731,95 @@ MACRO_ITEMS@[0; 40)
|
||||
}
|
||||
"#, r#"extern crate a ; mod b ; mod c {} use d ; const E : i32 = 0 ; static F : i32 = 0 ; impl G {} struct H ; enum I {Foo} trait J {} fn h () {} extern {} type T = u8 ;"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block() {
|
||||
let rules = create_rules(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($ i:block) => { fn foo() $ i }
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_expansion(&rules, "foo! { { 1; } }", "fn foo () {1 ;}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_meta() {
|
||||
let rules = create_rules(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($ i:meta) => (
|
||||
#[$ i]
|
||||
fn bar() {}
|
||||
)
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_expansion(
|
||||
&rules,
|
||||
r#"foo! { cfg(target_os = "windows") }"#,
|
||||
r#"# [cfg (target_os = "windows")] fn bar () {}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tt_block() {
|
||||
let rules = create_rules(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($ i:tt) => { fn foo() $ i }
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_expansion(&rules, r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tt_group() {
|
||||
let rules = create_rules(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($($ i:tt)*) => { $($ i)* }
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_expansion(&rules, r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lifetime() {
|
||||
let rules = create_rules(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } }
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_expansion(&rules, r#"foo!{'a}"#, r#"struct Ref < 'a > {s : & 'a str}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_literal() {
|
||||
let rules = create_rules(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;};
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_expansion(&rules, r#"foo!(u8 0)"#, r#"const VALUE : u8 = 0 ;"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vis() {
|
||||
let rules = create_rules(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($ vis:vis $ name:ident) => { $ vis fn $ name() {}};
|
||||
}
|
||||
"#,
|
||||
);
|
||||
assert_expansion(&rules, r#"foo!(pub foo);"#, r#"pub fn foo () {}"#);
|
||||
}
|
||||
}
|
||||
|
@ -161,11 +161,43 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
|
||||
let pat = input.eat_stmt().ok_or(ExpandError::UnexpectedToken)?.clone();
|
||||
res.inner.insert(text.clone(), Binding::Simple(pat.into()));
|
||||
}
|
||||
"block" => {
|
||||
let block =
|
||||
input.eat_block().ok_or(ExpandError::UnexpectedToken)?.clone();
|
||||
res.inner.insert(text.clone(), Binding::Simple(block.into()));
|
||||
}
|
||||
"meta" => {
|
||||
let meta =
|
||||
input.eat_meta().ok_or(ExpandError::UnexpectedToken)?.clone();
|
||||
res.inner.insert(text.clone(), Binding::Simple(meta.into()));
|
||||
}
|
||||
"tt" => {
|
||||
let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone();
|
||||
res.inner.insert(text.clone(), Binding::Simple(token.into()));
|
||||
}
|
||||
"item" => {
|
||||
let item =
|
||||
input.eat_item().ok_or(ExpandError::UnexpectedToken)?.clone();
|
||||
res.inner.insert(text.clone(), Binding::Simple(item.into()));
|
||||
}
|
||||
"lifetime" => {
|
||||
let lifetime =
|
||||
input.eat_lifetime().ok_or(ExpandError::UnexpectedToken)?.clone();
|
||||
res.inner.insert(text.clone(), Binding::Simple(lifetime.into()));
|
||||
}
|
||||
"literal" => {
|
||||
let literal =
|
||||
input.eat_literal().ok_or(ExpandError::UnexpectedToken)?.clone();
|
||||
res.inner.insert(
|
||||
text.clone(),
|
||||
Binding::Simple(tt::Leaf::from(literal).into()),
|
||||
);
|
||||
}
|
||||
"vis" => {
|
||||
let vis = input.eat_vis().ok_or(ExpandError::UnexpectedToken)?.clone();
|
||||
res.inner.insert(text.clone(), Binding::Simple(vis.into()));
|
||||
}
|
||||
|
||||
_ => return Err(ExpandError::UnexpectedToken),
|
||||
}
|
||||
}
|
||||
|
@ -46,10 +46,22 @@ impl<'a> Parser<'a> {
|
||||
self.parse(|src, sink| ra_parser::parse_stmt(src, sink, false))
|
||||
}
|
||||
|
||||
pub fn parse_block(self) -> Option<tt::TokenTree> {
|
||||
self.parse(ra_parser::parse_block)
|
||||
}
|
||||
|
||||
pub fn parse_meta(self) -> Option<tt::TokenTree> {
|
||||
self.parse(ra_parser::parse_meta)
|
||||
}
|
||||
|
||||
pub fn parse_item(self) -> Option<tt::TokenTree> {
|
||||
self.parse(ra_parser::parse_item)
|
||||
}
|
||||
|
||||
pub fn parse_vis(self) -> Option<tt::TokenTree> {
|
||||
self.parse(ra_parser::parse_vis)
|
||||
}
|
||||
|
||||
fn parse<F>(self, f: F) -> Option<tt::TokenTree>
|
||||
where
|
||||
F: FnOnce(&dyn TokenSource, &mut dyn TreeSink),
|
||||
|
@ -157,7 +157,10 @@ fn convert_tt(
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let child = if token.kind().is_keyword() || token.kind() == IDENT {
|
||||
let child: tt::TokenTree = if token.kind().is_keyword()
|
||||
|| token.kind() == IDENT
|
||||
|| token.kind() == LIFETIME
|
||||
{
|
||||
let relative_range = token.range() - global_offset;
|
||||
let id = token_map.alloc(relative_range);
|
||||
let text = token.text().clone();
|
||||
|
@ -41,6 +41,13 @@ impl<'a> TtCursor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn at_literal(&mut self) -> Option<&'a tt::Literal> {
|
||||
match self.current() {
|
||||
Some(tt::TokenTree::Leaf(tt::Leaf::Literal(i))) => Some(i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn bump(&mut self) {
|
||||
self.pos += 1;
|
||||
}
|
||||
@ -79,6 +86,13 @@ impl<'a> TtCursor<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn eat_literal(&mut self) -> Option<&'a tt::Literal> {
|
||||
self.at_literal().map(|i| {
|
||||
self.bump();
|
||||
i
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn eat_path(&mut self) -> Option<tt::TokenTree> {
|
||||
let parser = Parser::new(&mut self.pos, self.subtree);
|
||||
parser.parse_path()
|
||||
@ -104,11 +118,37 @@ impl<'a> TtCursor<'a> {
|
||||
parser.parse_stmt()
|
||||
}
|
||||
|
||||
pub(crate) fn eat_block(&mut self) -> Option<tt::TokenTree> {
|
||||
let parser = Parser::new(&mut self.pos, self.subtree);
|
||||
parser.parse_block()
|
||||
}
|
||||
|
||||
pub(crate) fn eat_meta(&mut self) -> Option<tt::TokenTree> {
|
||||
let parser = Parser::new(&mut self.pos, self.subtree);
|
||||
parser.parse_meta()
|
||||
}
|
||||
|
||||
pub(crate) fn eat_item(&mut self) -> Option<tt::TokenTree> {
|
||||
let parser = Parser::new(&mut self.pos, self.subtree);
|
||||
parser.parse_item()
|
||||
}
|
||||
|
||||
pub(crate) fn eat_lifetime(&mut self) -> Option<tt::TokenTree> {
|
||||
// check if it start from "`"
|
||||
if let Some(ident) = self.at_ident() {
|
||||
if ident.text.chars().next()? != '\'' {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
self.eat_ident().cloned().map(|ident| tt::Leaf::from(ident).into())
|
||||
}
|
||||
|
||||
pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> {
|
||||
let parser = Parser::new(&mut self.pos, self.subtree);
|
||||
parser.parse_vis()
|
||||
}
|
||||
|
||||
pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ParseError> {
|
||||
if self.at_char(char) {
|
||||
self.bump();
|
||||
|
@ -95,6 +95,37 @@ pub(crate) fn stmt(p: &mut Parser, with_semi: bool) {
|
||||
expressions::stmt(p, with_semi)
|
||||
}
|
||||
|
||||
pub(crate) fn block(p: &mut Parser) {
|
||||
expressions::block(p);
|
||||
}
|
||||
|
||||
// Parse a meta item , which excluded [], e.g : #[ MetaItem ]
|
||||
pub(crate) fn meta_item(p: &mut Parser) {
|
||||
fn is_delimiter(p: &mut Parser) -> bool {
|
||||
match p.current() {
|
||||
L_CURLY | L_PAREN | L_BRACK => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
if is_delimiter(p) {
|
||||
items::token_tree(p);
|
||||
return;
|
||||
}
|
||||
|
||||
let m = p.start();
|
||||
while !p.at(EOF) {
|
||||
if is_delimiter(p) {
|
||||
items::token_tree(p);
|
||||
break;
|
||||
} else {
|
||||
p.bump();
|
||||
}
|
||||
}
|
||||
|
||||
m.complete(p, TOKEN_TREE);
|
||||
}
|
||||
|
||||
pub(crate) fn item(p: &mut Parser) {
|
||||
items::item_or_macro(p, true, items::ItemFlavor::Mod)
|
||||
}
|
||||
@ -136,7 +167,7 @@ impl BlockLike {
|
||||
}
|
||||
}
|
||||
|
||||
fn opt_visibility(p: &mut Parser) -> bool {
|
||||
pub(crate) fn opt_visibility(p: &mut Parser) -> bool {
|
||||
match p.current() {
|
||||
PUB_KW => {
|
||||
let m = p.start();
|
||||
|
@ -93,11 +93,27 @@ pub fn parse_stmt(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink,
|
||||
parse_from_tokens(token_source, tree_sink, |p| grammar::stmt(p, with_semi));
|
||||
}
|
||||
|
||||
/// Parse given tokens into the given sink as a block
|
||||
pub fn parse_block(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) {
|
||||
parse_from_tokens(token_source, tree_sink, grammar::block);
|
||||
}
|
||||
|
||||
pub fn parse_meta(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) {
|
||||
parse_from_tokens(token_source, tree_sink, grammar::meta_item);
|
||||
}
|
||||
|
||||
/// Parse given tokens into the given sink as an item
|
||||
pub fn parse_item(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) {
|
||||
parse_from_tokens(token_source, tree_sink, grammar::item);
|
||||
}
|
||||
|
||||
/// Parse given tokens into the given sink as an visibility qualifier
|
||||
pub fn parse_vis(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) {
|
||||
parse_from_tokens(token_source, tree_sink, |p| {
|
||||
grammar::opt_visibility(p);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn parse_macro_items(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) {
|
||||
parse_from_tokens(token_source, tree_sink, grammar::macro_items);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user