Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Implementation of the vis macro matcher.
  • Loading branch information
DanielKeep authored and durka committed Apr 15, 2017
commit a2489495d909c43cfbefaeb79db6a77b13908257
1 change: 1 addition & 0 deletions src/libsyntax/ext/tt/macro_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
15 changes: 14 additions & 1 deletion src/libsyntax/ext/tt/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,19 @@ fn is_in_follow(tok: &quoted::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`, \
Expand All @@ -813,7 +826,7 @@ fn has_legal_fragment_specifier(tok: &quoted::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,
}
}
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/libsyntax/parse/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ pub enum Nonterminal {
NtGenerics(ast::Generics),
NtWhereClause(ast::WhereClause),
NtArg(ast::Arg),
NtVis(ast::Visibility),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the comment // These are not exposed to macros .... applies to NtVis, it's better moved higher in the list.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

}

impl fmt::Debug for Nonterminal {
Expand All @@ -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(..)"),
}
}
}
5 changes: 5 additions & 0 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}
}
Expand Down Expand Up @@ -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,
Expand Down
119 changes: 119 additions & 0 deletions src/test/run-pass/macro-pub-matcher.rs
Original file line number Diff line number Diff line change
@@ -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.
*/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DanielKeep why did you not use :vis at the top level of this macro??

($(#[$($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() {}