Implementation of the vis macro matcher.
This commit is contained in:
parent
ae23e65eb8
commit
a2489495d9
6 changed files with 142 additions and 1 deletions
|
|
@ -529,6 +529,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
|
|||
token::NtPath(panictry!(p.parse_path(PathStyle::Type)))
|
||||
},
|
||||
"meta" => token::NtMeta(panictry!(p.parse_meta_item())),
|
||||
"vis" => token::NtVis(panictry!(p.parse_visibility(true))),
|
||||
// this is not supposed to happen, since it has been checked
|
||||
// when compiling the macro.
|
||||
_ => p.span_bug(sp, "invalid fragment specifier")
|
||||
|
|
|
|||
|
|
@ -790,6 +790,19 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result<bool, (String, &'
|
|||
// harmless
|
||||
Ok(true)
|
||||
},
|
||||
"vis" => {
|
||||
// Explicitly disallow `priv`, on the off chance it comes back.
|
||||
match *tok {
|
||||
Comma => Ok(true),
|
||||
ModSep => Ok(true),
|
||||
MatchNt(_, ref frag, _, _) => {
|
||||
let name = frag.name.as_str();
|
||||
Ok(name == "ident" || name == "ty")
|
||||
},
|
||||
Ident(i, _) if i.name.as_str() != "priv" => Ok(true),
|
||||
_ => Ok(false)
|
||||
}
|
||||
},
|
||||
"" => Ok(true), // keywords::Invalid
|
||||
_ => Err((format!("invalid fragment specifier `{}`", frag),
|
||||
"valid fragment specifiers are `ident`, `block`, \
|
||||
|
|
@ -813,7 +826,7 @@ fn has_legal_fragment_specifier(tok: "ed::TokenTree) -> Result<(), String> {
|
|||
fn is_legal_fragment_specifier(frag: &str) -> bool {
|
||||
match frag {
|
||||
"item" | "block" | "stmt" | "expr" | "pat" |
|
||||
"path" | "ty" | "ident" | "meta" | "tt" | "" => true,
|
||||
"path" | "ty" | "ident" | "meta" | "tt" | "vis" | "" => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -636,6 +636,7 @@ pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T)
|
|||
token::NtWhereClause(where_clause) =>
|
||||
token::NtWhereClause(fld.fold_where_clause(where_clause)),
|
||||
token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)),
|
||||
token::NtVis(vis) => token::NtVis(fld.fold_vis(vis)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -371,6 +371,7 @@ pub enum Nonterminal {
|
|||
NtGenerics(ast::Generics),
|
||||
NtWhereClause(ast::WhereClause),
|
||||
NtArg(ast::Arg),
|
||||
NtVis(ast::Visibility),
|
||||
}
|
||||
|
||||
impl fmt::Debug for Nonterminal {
|
||||
|
|
@ -392,6 +393,7 @@ impl fmt::Debug for Nonterminal {
|
|||
NtGenerics(..) => f.pad("NtGenerics(..)"),
|
||||
NtWhereClause(..) => f.pad("NtWhereClause(..)"),
|
||||
NtArg(..) => f.pad("NtArg(..)"),
|
||||
NtVis(..) => f.pad("NtVis(..)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -293,6 +293,7 @@ pub fn token_to_string(tok: &Token) -> String {
|
|||
token::NtGenerics(ref e) => generics_to_string(&e),
|
||||
token::NtWhereClause(ref e) => where_clause_to_string(&e),
|
||||
token::NtArg(ref e) => arg_to_string(&e),
|
||||
token::NtVis(ref e) => vis_to_string(&e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -373,6 +374,10 @@ pub fn ident_to_string(id: ast::Ident) -> String {
|
|||
to_string(|s| s.print_ident(id))
|
||||
}
|
||||
|
||||
pub fn vis_to_string(v: &ast::Visibility) -> String {
|
||||
to_string(|s| s.print_visibility(v))
|
||||
}
|
||||
|
||||
pub fn fun_to_string(decl: &ast::FnDecl,
|
||||
unsafety: ast::Unsafety,
|
||||
constness: ast::Constness,
|
||||
|
|
|
|||
119
src/test/run-pass/macro-pub-matcher.rs
Normal file
119
src/test/run-pass/macro-pub-matcher.rs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#![allow(dead_code, unused_imports)]
|
||||
#![feature(pub_restricted)]
|
||||
|
||||
/**
|
||||
Ensure that `:vis` matches can be captured in existing positions, and passed
|
||||
through without the need for reparse tricks.
|
||||
*/
|
||||
macro_rules! vis_passthru {
|
||||
($vis:vis const $name:ident: $ty:ty = $e:expr;) => { $vis const $name: $ty = $e; };
|
||||
($vis:vis enum $name:ident {}) => { $vis struct $name {} };
|
||||
($vis:vis extern "C" fn $name:ident() {}) => { $vis extern "C" fn $name() {} };
|
||||
($vis:vis fn $name:ident() {}) => { $vis fn $name() {} };
|
||||
($vis:vis mod $name:ident {}) => { $vis mod $name {} };
|
||||
($vis:vis static $name:ident: $ty:ty = $e:expr;) => { $vis static $name: $ty = $e; };
|
||||
($vis:vis struct $name:ident;) => { $vis struct $name; };
|
||||
($vis:vis trait $name:ident {}) => { $vis trait $name {} };
|
||||
($vis:vis type $name:ident = $ty:ty;) => { $vis type $name = $ty; };
|
||||
($vis:vis use $path:ident as $name:ident;) => { $vis use self::$path as $name; };
|
||||
}
|
||||
|
||||
mod with_pub {
|
||||
vis_passthru! { pub const A: i32 = 0; }
|
||||
vis_passthru! { pub enum B {} }
|
||||
vis_passthru! { pub extern "C" fn c() {} }
|
||||
vis_passthru! { pub mod d {} }
|
||||
vis_passthru! { pub static E: i32 = 0; }
|
||||
vis_passthru! { pub struct F; }
|
||||
vis_passthru! { pub trait G {} }
|
||||
vis_passthru! { pub type H = i32; }
|
||||
vis_passthru! { pub use A as I; }
|
||||
}
|
||||
|
||||
mod without_pub {
|
||||
vis_passthru! { const A: i32 = 0; }
|
||||
vis_passthru! { enum B {} }
|
||||
vis_passthru! { extern "C" fn c() {} }
|
||||
vis_passthru! { mod d {} }
|
||||
vis_passthru! { static E: i32 = 0; }
|
||||
vis_passthru! { struct F; }
|
||||
vis_passthru! { trait G {} }
|
||||
vis_passthru! { type H = i32; }
|
||||
vis_passthru! { use A as I; }
|
||||
}
|
||||
|
||||
mod with_pub_restricted {
|
||||
vis_passthru! { pub(crate) const A: i32 = 0; }
|
||||
vis_passthru! { pub(crate) enum B {} }
|
||||
vis_passthru! { pub(crate) extern "C" fn c() {} }
|
||||
vis_passthru! { pub(crate) mod d {} }
|
||||
vis_passthru! { pub(crate) static E: i32 = 0; }
|
||||
vis_passthru! { pub(crate) struct F; }
|
||||
vis_passthru! { pub(crate) trait G {} }
|
||||
vis_passthru! { pub(crate) type H = i32; }
|
||||
vis_passthru! { pub(crate) use A as I; }
|
||||
}
|
||||
|
||||
mod garden {
|
||||
mod with_pub_restricted_path {
|
||||
vis_passthru! { pub(::garden) const A: i32 = 0; }
|
||||
vis_passthru! { pub(::garden) enum B {} }
|
||||
vis_passthru! { pub(::garden) extern "C" fn c() {} }
|
||||
vis_passthru! { pub(::garden) mod d {} }
|
||||
vis_passthru! { pub(::garden) static E: i32 = 0; }
|
||||
vis_passthru! { pub(::garden) struct F; }
|
||||
vis_passthru! { pub(::garden) trait G {} }
|
||||
vis_passthru! { pub(::garden) type H = i32; }
|
||||
vis_passthru! { pub(::garden) use A as I; }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Ensure that the `:vis` matcher works in a more complex situation: parsing a
|
||||
struct definition.
|
||||
*/
|
||||
macro_rules! vis_parse_struct {
|
||||
/*
|
||||
The rule duplication is currently unavoidable due to the leading attribute
|
||||
matching.
|
||||
*/
|
||||
($(#[$($attrs:tt)*])* pub($($vis:tt)*) struct $name:ident {$($body:tt)*}) => {
|
||||
vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, pub($($vis)*), $name, $($body)* }
|
||||
};
|
||||
($(#[$($attrs:tt)*])* pub struct $name:ident {$($body:tt)*}) => {
|
||||
vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, pub, $name, $($body)* }
|
||||
};
|
||||
($(#[$($attrs:tt)*])* struct $name:ident {$($body:tt)*}) => {
|
||||
vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, , $name, $($body)* }
|
||||
};
|
||||
|
||||
($(#[$($attrs:tt)*])* pub($($vis:tt)*) struct $name:ident ($($body:tt)*);) => {
|
||||
vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, pub($($vis)*), $name, $($body)* }
|
||||
};
|
||||
($(#[$($attrs:tt)*])* pub struct $name:ident ($($body:tt)*);) => {
|
||||
vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, pub, $name, $($body)* }
|
||||
};
|
||||
($(#[$($attrs:tt)*])* struct $name:ident ($($body:tt)*);) => {
|
||||
vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, , $name, $($body)* }
|
||||
};
|
||||
|
||||
(@parse_fields $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fname:ident: $fty:ty),* $(,)*) => {
|
||||
$(#[$attrs])* $vis struct $name { $($fvis $fname: $fty,)* }
|
||||
};
|
||||
|
||||
(@parse_tuple $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fty:ty),* $(,)*) => {
|
||||
$(#[$attrs])* $vis struct $name ( $($fvis $fty,)* );
|
||||
};
|
||||
}
|
||||
|
||||
mod test_struct {
|
||||
vis_parse_struct! { pub(crate) struct A { pub a: i32, b: i32, pub(crate) c: i32 } }
|
||||
vis_parse_struct! { pub struct B { a: i32, pub(crate) b: i32, pub c: i32 } }
|
||||
vis_parse_struct! { struct C { pub(crate) a: i32, pub b: i32, c: i32 } }
|
||||
|
||||
vis_parse_struct! { pub(crate) struct D (pub i32, i32, pub(crate) i32); }
|
||||
vis_parse_struct! { pub struct E (i32, pub(crate) i32, pub i32); }
|
||||
vis_parse_struct! { struct F (pub(crate) i32, pub i32, i32); }
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue