mirror of
https://gitee.com/openharmony/third_party_rust_syn
synced 2025-02-17 05:57:30 +00:00
Require Ident to contain a valid ident
This commit is contained in:
parent
37ea608ccf
commit
570695ea93
@ -13,7 +13,7 @@ publish = false # this branch contains breaking changes
|
||||
[features]
|
||||
default = ["parsing", "printing", "clone-impls"]
|
||||
full = []
|
||||
parsing = ["unicode-xid", "synom/parsing"]
|
||||
parsing = ["synom/parsing"]
|
||||
printing = ["quote", "synom/printing"]
|
||||
visit = []
|
||||
fold = []
|
||||
@ -23,7 +23,7 @@ extra-traits = ["synom/extra-traits"]
|
||||
[dependencies]
|
||||
quote = { git = 'https://github.com/dtolnay/quote', optional = true }
|
||||
proc-macro2 = { git = 'https://github.com/alexcrichton/proc-macro2' }
|
||||
unicode-xid = { version = "0.0.4", optional = true }
|
||||
unicode-xid = "0.1"
|
||||
synom = { version = "0.11", path = "synom" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
13
src/expr.rs
13
src/expr.rs
@ -1253,11 +1253,11 @@ pub mod parsing {
|
||||
impl Synom for FieldValue {
|
||||
named!(parse -> Self, alt!(
|
||||
do_parse!(
|
||||
name: wordlike >>
|
||||
ident: field_ident >>
|
||||
colon: syn!(Colon) >>
|
||||
value: syn!(Expr) >>
|
||||
(FieldValue {
|
||||
ident: name,
|
||||
ident: ident,
|
||||
expr: value,
|
||||
is_shorthand: false,
|
||||
attrs: Vec::new(),
|
||||
@ -1413,6 +1413,7 @@ pub mod parsing {
|
||||
Mac {
|
||||
path: what,
|
||||
bang_token: bang,
|
||||
ident: None,
|
||||
tokens: vec![TokenTree(proc_macro2::TokenTree {
|
||||
span: ((data.1).0).0,
|
||||
kind: TokenKind::Sequence(Delimiter::Brace, data.0),
|
||||
@ -1582,7 +1583,7 @@ pub mod parsing {
|
||||
impl Synom for FieldPat {
|
||||
named!(parse -> Self, alt!(
|
||||
do_parse!(
|
||||
ident: wordlike >>
|
||||
ident: field_ident >>
|
||||
colon: syn!(Colon) >>
|
||||
pat: syn!(Pat) >>
|
||||
(FieldPat {
|
||||
@ -1628,14 +1629,14 @@ pub mod parsing {
|
||||
));
|
||||
}
|
||||
|
||||
named!(wordlike -> Ident, alt!(
|
||||
named!(field_ident -> Ident, alt!(
|
||||
syn!(Ident)
|
||||
|
|
||||
do_parse!(
|
||||
lit: syn!(Lit) >>
|
||||
({
|
||||
let s = lit.value.to_string();
|
||||
if s.parse::<u32>().is_ok() {
|
||||
let s = lit.to_string();
|
||||
if s.parse::<usize>().is_ok() {
|
||||
Ident::new(s.into(), lit.span)
|
||||
} else {
|
||||
return parse_error();
|
||||
|
60
src/ident.rs
60
src/ident.rs
@ -4,11 +4,27 @@ use std::fmt::{self, Display};
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use proc_macro2::Symbol;
|
||||
use unicode_xid::UnicodeXID;
|
||||
|
||||
use Span;
|
||||
use tokens;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// A word of Rust code, such as a keyword or variable name.
|
||||
///
|
||||
/// An identifier consists of at least one Unicode code point, the first of
|
||||
/// which has the XID_Start property and the rest of which have the XID_Continue
|
||||
/// property. An underscore may be used as the first character as long as it is
|
||||
/// not the only character.
|
||||
///
|
||||
/// - The empty string is not an identifier. Use `Option<Ident>`.
|
||||
/// - An underscore by itself is not an identifier. Use
|
||||
/// `syn::tokens::Underscore` instead.
|
||||
/// - A lifetime is not an identifier. Use `syn::Lifetime` instead.
|
||||
///
|
||||
/// An identifier constructed with `Ident::new` is permitted to be a Rust
|
||||
/// keyword, though parsing an identifier with `syn!(Ident)` rejects Rust
|
||||
/// keywords.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Ident {
|
||||
pub sym: Symbol,
|
||||
pub span: Span,
|
||||
@ -16,6 +32,42 @@ pub struct Ident {
|
||||
|
||||
impl Ident {
|
||||
pub fn new(sym: Symbol, span: Span) -> Self {
|
||||
let s = sym.as_str();
|
||||
|
||||
if s.is_empty() {
|
||||
panic!("ident is not allowed to be empty; use Option<Ident>");
|
||||
}
|
||||
|
||||
if s.starts_with('\'') {
|
||||
panic!("ident is not allowed to be a lifetime; use syn::Lifetime");
|
||||
}
|
||||
|
||||
if s == "_" {
|
||||
panic!("`_` is not a valid ident; use syn::tokens::Underscore");
|
||||
}
|
||||
|
||||
fn xid_ok(s: &str) -> bool {
|
||||
let mut chars = s.chars();
|
||||
let first = chars.next().unwrap();
|
||||
if !(UnicodeXID::is_xid_start(first) || first == '_') {
|
||||
return false;
|
||||
}
|
||||
for ch in chars {
|
||||
if !UnicodeXID::is_xid_continue(ch) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn integer_ok(s: &str) -> bool {
|
||||
s.bytes().all(|digit| digit >= b'0' && digit <= b'9')
|
||||
}
|
||||
|
||||
if !(xid_ok(s) || integer_ok(s)) {
|
||||
panic!("{:?} is not a valid ident", s);
|
||||
}
|
||||
|
||||
Ident {
|
||||
sym: sym,
|
||||
span: span,
|
||||
@ -59,12 +111,6 @@ impl From<String> for Ident {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Ident {
|
||||
fn from(u: usize) -> Self {
|
||||
Ident::new(u.to_string()[..].into(), Span::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Ident {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.sym.as_str()
|
||||
|
523
src/item.rs
523
src/item.rs
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(large_enum_variant))]
|
||||
|
||||
extern crate proc_macro2;
|
||||
extern crate unicode_xid;
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
extern crate quote;
|
||||
|
@ -9,12 +9,11 @@ ast_struct! {
|
||||
/// Represents a macro invocation. The Path indicates which macro
|
||||
/// is being invoked, and the vector of token-trees contains the source
|
||||
/// of the macro invocation.
|
||||
///
|
||||
/// NB: the additional ident for a `macro_rules`-style macro is actually
|
||||
/// stored in the enclosing item. Oog.
|
||||
pub struct Mac {
|
||||
pub path: Path,
|
||||
pub bang_token: tokens::Bang,
|
||||
/// The `example` in `macro_rules! example { ... }`.
|
||||
pub ident: Option<Ident>,
|
||||
pub tokens: Vec<TokenTree>,
|
||||
}
|
||||
}
|
||||
@ -147,6 +146,7 @@ pub mod parsing {
|
||||
(Mac {
|
||||
path: what,
|
||||
bang_token: bang,
|
||||
ident: None,
|
||||
tokens: vec![body],
|
||||
})
|
||||
));
|
||||
|
88
src/ty.rs
88
src/ty.rs
@ -101,13 +101,18 @@ ast_struct! {
|
||||
pub struct Path {
|
||||
/// A `::foo` path, is relative to the crate root rather than current
|
||||
/// module (like paths in an import).
|
||||
pub global: bool,
|
||||
pub leading_colon: Option<tokens::Colon2>,
|
||||
/// The segments in the path: the things separated by `::`.
|
||||
pub segments: Delimited<PathSegment, tokens::Colon2>,
|
||||
}
|
||||
}
|
||||
|
||||
impl Path {
|
||||
pub fn global(&self) -> bool {
|
||||
self.leading_colon.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "printing")]
|
||||
ast_struct! {
|
||||
pub struct PathTokens<'a>(pub &'a Option<QSelf>, pub &'a Path);
|
||||
@ -118,7 +123,6 @@ impl<T> From<T> for Path
|
||||
{
|
||||
fn from(segment: T) -> Self {
|
||||
Path {
|
||||
global: false,
|
||||
leading_colon: None,
|
||||
segments: vec![(segment.into(), None)].into(),
|
||||
}
|
||||
@ -147,7 +151,7 @@ impl<T> From<T> for PathSegment
|
||||
fn from(ident: T) -> Self {
|
||||
PathSegment {
|
||||
ident: ident.into(),
|
||||
parameters: PathParameters::none(),
|
||||
parameters: PathParameters::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,6 +161,7 @@ ast_enum! {
|
||||
///
|
||||
/// E.g. `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`
|
||||
pub enum PathParameters {
|
||||
None,
|
||||
/// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`
|
||||
AngleBracketed(AngleBracketedParameterData),
|
||||
/// The `(A, B)` and `C` in `Foo(A, B) -> C`
|
||||
@ -164,13 +169,16 @@ ast_enum! {
|
||||
}
|
||||
}
|
||||
|
||||
impl PathParameters {
|
||||
pub fn none() -> Self {
|
||||
PathParameters::AngleBracketed(AngleBracketedParameterData::default())
|
||||
impl Default for PathParameters {
|
||||
fn default() -> Self {
|
||||
PathParameters::None
|
||||
}
|
||||
}
|
||||
|
||||
impl PathParameters {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match *self {
|
||||
PathParameters::None => true,
|
||||
PathParameters::AngleBracketed(ref bracketed) => {
|
||||
bracketed.lifetimes.is_empty() && bracketed.types.is_empty() &&
|
||||
bracketed.bindings.is_empty()
|
||||
@ -182,11 +190,9 @@ impl PathParameters {
|
||||
|
||||
ast_struct! {
|
||||
/// A path like `Foo<'a, T>`
|
||||
#[derive(Default)]
|
||||
pub struct AngleBracketedParameterData {
|
||||
pub lt_token: Option<tokens::Lt>,
|
||||
pub gt_token: Option<tokens::Gt>,
|
||||
|
||||
pub turbofish: Option<tokens::Colon2>,
|
||||
pub lt_token: tokens::Lt,
|
||||
/// The lifetime parameters for this path segment.
|
||||
pub lifetimes: Delimited<Lifetime, tokens::Comma>,
|
||||
/// The type parameters for this path segment, if present.
|
||||
@ -195,6 +201,7 @@ ast_struct! {
|
||||
///
|
||||
/// E.g., `Foo<A=Bar>`.
|
||||
pub bindings: Delimited<TypeBinding, tokens::Comma>,
|
||||
pub gt_token: tokens::Gt,
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,10 +252,9 @@ ast_struct! {
|
||||
/// ```
|
||||
pub struct QSelf {
|
||||
pub lt_token: tokens::Lt,
|
||||
pub gt_token: tokens::Gt,
|
||||
pub as_token: Option<tokens::As>,
|
||||
pub ty: Box<Ty>,
|
||||
pub position: usize,
|
||||
pub position: Option<(tokens::As, usize)>,
|
||||
pub gt_token: tokens::Gt,
|
||||
}
|
||||
}
|
||||
|
||||
@ -513,7 +519,7 @@ pub mod parsing {
|
||||
|
|
||||
do_parse!(
|
||||
lt: syn!(Lt) >>
|
||||
this: map!(syn!(Ty), Box::new) >>
|
||||
this: syn!(Ty) >>
|
||||
path: option!(do_parse!(
|
||||
as_: syn!(As) >>
|
||||
path: syn!(Path) >>
|
||||
@ -523,7 +529,7 @@ pub mod parsing {
|
||||
colon2: syn!(Colon2) >>
|
||||
rest: call!(Delimited::parse_separated_nonempty) >>
|
||||
({
|
||||
let (pos, path, as_) = match path {
|
||||
let (pos, path) = match path {
|
||||
Some((as_, mut path)) => {
|
||||
let pos = path.segments.len();
|
||||
if !path.segments.is_empty() && !path.segments.trailing_delim() {
|
||||
@ -532,22 +538,20 @@ pub mod parsing {
|
||||
for item in rest {
|
||||
path.segments.push(item);
|
||||
}
|
||||
(pos, path, Some(as_))
|
||||
(Some((as_, pos)), path)
|
||||
}
|
||||
None => {
|
||||
(0, Path {
|
||||
leading_colon: None,
|
||||
global: false,
|
||||
(None, Path {
|
||||
leading_colon: Some(colon2),
|
||||
segments: rest,
|
||||
}, None)
|
||||
})
|
||||
}
|
||||
};
|
||||
(Some(QSelf {
|
||||
ty: this,
|
||||
lt_token: lt,
|
||||
ty: Box::new(this),
|
||||
position: pos,
|
||||
gt_token: gt,
|
||||
lt_token: lt,
|
||||
as_token: as_,
|
||||
}), path)
|
||||
})
|
||||
)
|
||||
@ -615,12 +619,11 @@ pub mod parsing {
|
||||
|
||||
impl Synom for Path {
|
||||
named!(parse -> Self, do_parse!(
|
||||
global: option!(syn!(Colon2)) >>
|
||||
colon: option!(syn!(Colon2)) >>
|
||||
segments: call!(Delimited::parse_separated_nonempty) >>
|
||||
(Path {
|
||||
global: global.is_some(),
|
||||
leading_colon: colon,
|
||||
segments: segments,
|
||||
leading_colon: global,
|
||||
})
|
||||
));
|
||||
}
|
||||
@ -628,7 +631,8 @@ pub mod parsing {
|
||||
impl Synom for PathSegment {
|
||||
named!(parse -> Self, alt!(
|
||||
do_parse!(
|
||||
id: option!(syn!(Ident)) >>
|
||||
ident: syn!(Ident) >>
|
||||
turbofish: option!(syn!(Colon2)) >>
|
||||
lt: syn!(Lt) >>
|
||||
lifetimes: call!(Delimited::parse_terminated) >>
|
||||
types: cond!(
|
||||
@ -645,14 +649,15 @@ pub mod parsing {
|
||||
) >>
|
||||
gt: syn!(Gt) >>
|
||||
(PathSegment {
|
||||
ident: id.unwrap_or_else(|| "".into()),
|
||||
ident: ident,
|
||||
parameters: PathParameters::AngleBracketed(
|
||||
AngleBracketedParameterData {
|
||||
gt_token: Some(gt),
|
||||
lt_token: Some(lt),
|
||||
turbofish: turbofish,
|
||||
lt_token: lt,
|
||||
lifetimes: lifetimes,
|
||||
types: types.unwrap_or_default(),
|
||||
bindings: bindings.unwrap_or_default(),
|
||||
gt_token: gt,
|
||||
}
|
||||
),
|
||||
})
|
||||
@ -661,17 +666,17 @@ pub mod parsing {
|
||||
mod_style_path_segment
|
||||
));
|
||||
}
|
||||
|
||||
named!(ty_no_eq_after -> Ty, terminated!(syn!(Ty), not!(syn!(Eq))));
|
||||
|
||||
impl Path {
|
||||
named!(pub parse_mod_style -> Self, do_parse!(
|
||||
global: option!(syn!(Colon2)) >>
|
||||
colon: option!(syn!(Colon2)) >>
|
||||
segments: call!(Delimited::parse_separated_nonempty_with,
|
||||
mod_style_path_segment) >>
|
||||
(Path {
|
||||
global: global.is_some(),
|
||||
leading_colon: colon,
|
||||
segments: segments,
|
||||
leading_colon: global,
|
||||
})
|
||||
));
|
||||
}
|
||||
@ -840,14 +845,12 @@ mod printing {
|
||||
};
|
||||
qself.lt_token.to_tokens(tokens);
|
||||
qself.ty.to_tokens(tokens);
|
||||
if qself.position > 0 {
|
||||
qself.as_token.to_tokens(tokens);
|
||||
let mut segments = self.1.segments.iter();
|
||||
if let Some((as_token, pos)) = qself.position {
|
||||
as_token.to_tokens(tokens);
|
||||
self.1.leading_colon.to_tokens(tokens);
|
||||
for (i, segment) in self.1.segments
|
||||
.iter()
|
||||
.take(qself.position)
|
||||
.enumerate() {
|
||||
if i == qself.position - 1 {
|
||||
for (i, segment) in (&mut segments).take(pos).enumerate() {
|
||||
if i + 1 == pos {
|
||||
segment.item().to_tokens(tokens);
|
||||
qself.gt_token.to_tokens(tokens);
|
||||
segment.delimiter().to_tokens(tokens);
|
||||
@ -857,8 +860,9 @@ mod printing {
|
||||
}
|
||||
} else {
|
||||
qself.gt_token.to_tokens(tokens);
|
||||
self.1.leading_colon.to_tokens(tokens);
|
||||
}
|
||||
for segment in self.1.segments.iter().skip(qself.position) {
|
||||
for segment in segments {
|
||||
segment.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
@ -916,6 +920,7 @@ mod printing {
|
||||
impl ToTokens for PathParameters {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
match *self {
|
||||
PathParameters::None => {}
|
||||
PathParameters::AngleBracketed(ref parameters) => {
|
||||
parameters.to_tokens(tokens);
|
||||
}
|
||||
@ -928,6 +933,7 @@ mod printing {
|
||||
|
||||
impl ToTokens for AngleBracketedParameterData {
|
||||
fn to_tokens(&self, tokens: &mut Tokens) {
|
||||
self.turbofish.to_tokens(tokens);
|
||||
self.lt_token.to_tokens(tokens);
|
||||
self.lifetimes.to_tokens(tokens);
|
||||
self.types.to_tokens(tokens);
|
||||
|
Loading…
x
Reference in New Issue
Block a user