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:
bors[bot] 2019-04-19 13:54:34 +00:00
commit d15abaa06f
7 changed files with 227 additions and 2 deletions

View file

@ -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 () {}"#);
}
}

View file

@ -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),
}
}

View file

@ -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),

View file

@ -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();

View file

@ -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();

View file

@ -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();

View file

@ -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);
}