Skip to content

Commit

Permalink
Merge pull request #286 from dtolnay/literalfromstr
Browse files Browse the repository at this point in the history
impl FromStr for Literal
  • Loading branch information
dtolnay committed May 20, 2021
2 parents 56043a1 + 24f0bb5 commit 6fcc4a2
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 7 deletions.
20 changes: 20 additions & 0 deletions src/fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ impl LexError {
pub(crate) fn span(&self) -> Span {
self.span
}

fn call_site() -> Self {
LexError {
span: Span::call_site(),
}
}
}

impl TokenStream {
Expand Down Expand Up @@ -887,6 +893,20 @@ impl Literal {
}
}

impl FromStr for Literal {
type Err = LexError;

fn from_str(repr: &str) -> Result<Self, Self::Err> {
let cursor = get_cursor(repr);
if let Ok((_rest, literal)) = parse::literal(cursor) {
if literal.text.len() == repr.len() {
return Ok(literal);
}
}
Err(LexError::call_site())
}
}

impl Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.text, f)
Expand Down
11 changes: 11 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,17 @@ impl Literal {
}
}

impl FromStr for Literal {
type Err = LexError;

fn from_str(repr: &str) -> Result<Self, LexError> {
repr.parse().map(Literal::_new).map_err(|inner| LexError {
inner,
_marker: Marker,
})
}
}

impl Debug for Literal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.inner, f)
Expand Down
4 changes: 2 additions & 2 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl<'a> Cursor<'a> {
}
}

struct Reject;
pub(crate) struct Reject;
type PResult<'a, O> = Result<(Cursor<'a>, O), Reject>;

fn skip_whitespace(input: Cursor) -> Cursor {
Expand Down Expand Up @@ -310,7 +310,7 @@ fn ident_not_raw(input: Cursor) -> PResult<&str> {
Ok((input.advance(end), &input.rest[..end]))
}

fn literal(input: Cursor) -> PResult<Literal> {
pub(crate) fn literal(input: Cursor) -> PResult<Literal> {
let rest = literal_nocapture(input)?;
let end = input.len() - rest.len();
Ok((rest, Literal::_new(input.rest[..end].to_string())))
Expand Down
38 changes: 33 additions & 5 deletions src/wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ pub(crate) enum LexError {
Fallback(fallback::LexError),
}

impl LexError {
fn call_site() -> Self {
LexError::Fallback(fallback::LexError {
span: fallback::Span::call_site(),
})
}
}

fn mismatch() -> ! {
panic!("stable/nightly mismatch")
}
Expand Down Expand Up @@ -108,11 +116,7 @@ impl FromStr for TokenStream {
// Work around https://github.com/rust-lang/rust/issues/58736.
fn proc_macro_parse(src: &str) -> Result<proc_macro::TokenStream, LexError> {
let result = panic::catch_unwind(|| src.parse().map_err(LexError::Compiler));
result.unwrap_or_else(|_| {
Err(LexError::Fallback(fallback::LexError {
span: fallback::Span::call_site(),
}))
})
result.unwrap_or_else(|_| Err(LexError::call_site()))
}

impl Display for TokenStream {
Expand Down Expand Up @@ -912,6 +916,30 @@ impl From<fallback::Literal> for Literal {
}
}

impl FromStr for Literal {
type Err = LexError;

fn from_str(repr: &str) -> Result<Self, Self::Err> {
if inside_proc_macro() {
// TODO: use libproc_macro's FromStr impl once it is available in
// rustc. https://github.com/rust-lang/rust/pull/84717
let tokens = proc_macro_parse(repr)?;
let mut iter = tokens.into_iter();
if let (Some(proc_macro::TokenTree::Literal(literal)), None) =
(iter.next(), iter.next())
{
if literal.to_string().len() == repr.len() {
return Ok(Literal::Compiler(literal));
}
}
Err(LexError::call_site())
} else {
let literal = fallback::Literal::from_str(repr)?;
Ok(Literal::Fallback(literal))
}
}
}

impl Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expand Down
14 changes: 14 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,20 @@ fn literal_iter_negative() {
assert!(iter.next().is_none());
}

#[test]
fn literal_parse() {
assert!("1".parse::<Literal>().is_ok());
assert!("1.0".parse::<Literal>().is_ok());
assert!("'a'".parse::<Literal>().is_ok());
assert!("\"\n\"".parse::<Literal>().is_ok());
assert!("0 1".parse::<Literal>().is_err());
assert!(" 0".parse::<Literal>().is_err());
assert!("0 ".parse::<Literal>().is_err());
assert!("/* comment */0".parse::<Literal>().is_err());
assert!("0/* comment */".parse::<Literal>().is_err());
assert!("0// comment".parse::<Literal>().is_err());
}

#[test]
fn roundtrip() {
fn roundtrip(p: &str) {
Expand Down

0 comments on commit 6fcc4a2

Please sign in to comment.