Skip to content

Commit 6fcc4a2

Browse files
authored
Merge pull request #286 from dtolnay/literalfromstr
impl FromStr for Literal
2 parents 56043a1 + 24f0bb5 commit 6fcc4a2

File tree

5 files changed

+80
-7
lines changed

5 files changed

+80
-7
lines changed

src/fallback.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ impl LexError {
4343
pub(crate) fn span(&self) -> Span {
4444
self.span
4545
}
46+
47+
fn call_site() -> Self {
48+
LexError {
49+
span: Span::call_site(),
50+
}
51+
}
4652
}
4753

4854
impl TokenStream {
@@ -887,6 +893,20 @@ impl Literal {
887893
}
888894
}
889895

896+
impl FromStr for Literal {
897+
type Err = LexError;
898+
899+
fn from_str(repr: &str) -> Result<Self, Self::Err> {
900+
let cursor = get_cursor(repr);
901+
if let Ok((_rest, literal)) = parse::literal(cursor) {
902+
if literal.text.len() == repr.len() {
903+
return Ok(literal);
904+
}
905+
}
906+
Err(LexError::call_site())
907+
}
908+
}
909+
890910
impl Display for Literal {
891911
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
892912
Display::fmt(&self.text, f)

src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,17 @@ impl Literal {
12031203
}
12041204
}
12051205

1206+
impl FromStr for Literal {
1207+
type Err = LexError;
1208+
1209+
fn from_str(repr: &str) -> Result<Self, LexError> {
1210+
repr.parse().map(Literal::_new).map_err(|inner| LexError {
1211+
inner,
1212+
_marker: Marker,
1213+
})
1214+
}
1215+
}
1216+
12061217
impl Debug for Literal {
12071218
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
12081219
Debug::fmt(&self.inner, f)

src/parse.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl<'a> Cursor<'a> {
5959
}
6060
}
6161

62-
struct Reject;
62+
pub(crate) struct Reject;
6363
type PResult<'a, O> = Result<(Cursor<'a>, O), Reject>;
6464

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

313-
fn literal(input: Cursor) -> PResult<Literal> {
313+
pub(crate) fn literal(input: Cursor) -> PResult<Literal> {
314314
let rest = literal_nocapture(input)?;
315315
let end = input.len() - rest.len();
316316
Ok((rest, Literal::_new(input.rest[..end].to_string())))

src/wrapper.rs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ pub(crate) enum LexError {
2929
Fallback(fallback::LexError),
3030
}
3131

32+
impl LexError {
33+
fn call_site() -> Self {
34+
LexError::Fallback(fallback::LexError {
35+
span: fallback::Span::call_site(),
36+
})
37+
}
38+
}
39+
3240
fn mismatch() -> ! {
3341
panic!("stable/nightly mismatch")
3442
}
@@ -108,11 +116,7 @@ impl FromStr for TokenStream {
108116
// Work around https://github.com/rust-lang/rust/issues/58736.
109117
fn proc_macro_parse(src: &str) -> Result<proc_macro::TokenStream, LexError> {
110118
let result = panic::catch_unwind(|| src.parse().map_err(LexError::Compiler));
111-
result.unwrap_or_else(|_| {
112-
Err(LexError::Fallback(fallback::LexError {
113-
span: fallback::Span::call_site(),
114-
}))
115-
})
119+
result.unwrap_or_else(|_| Err(LexError::call_site()))
116120
}
117121

118122
impl Display for TokenStream {
@@ -912,6 +916,30 @@ impl From<fallback::Literal> for Literal {
912916
}
913917
}
914918

919+
impl FromStr for Literal {
920+
type Err = LexError;
921+
922+
fn from_str(repr: &str) -> Result<Self, Self::Err> {
923+
if inside_proc_macro() {
924+
// TODO: use libproc_macro's FromStr impl once it is available in
925+
// rustc. https://github.com/rust-lang/rust/pull/84717
926+
let tokens = proc_macro_parse(repr)?;
927+
let mut iter = tokens.into_iter();
928+
if let (Some(proc_macro::TokenTree::Literal(literal)), None) =
929+
(iter.next(), iter.next())
930+
{
931+
if literal.to_string().len() == repr.len() {
932+
return Ok(Literal::Compiler(literal));
933+
}
934+
}
935+
Err(LexError::call_site())
936+
} else {
937+
let literal = fallback::Literal::from_str(repr)?;
938+
Ok(Literal::Fallback(literal))
939+
}
940+
}
941+
}
942+
915943
impl Display for Literal {
916944
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
917945
match self {

tests/test.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,20 @@ fn literal_iter_negative() {
163163
assert!(iter.next().is_none());
164164
}
165165

166+
#[test]
167+
fn literal_parse() {
168+
assert!("1".parse::<Literal>().is_ok());
169+
assert!("1.0".parse::<Literal>().is_ok());
170+
assert!("'a'".parse::<Literal>().is_ok());
171+
assert!("\"\n\"".parse::<Literal>().is_ok());
172+
assert!("0 1".parse::<Literal>().is_err());
173+
assert!(" 0".parse::<Literal>().is_err());
174+
assert!("0 ".parse::<Literal>().is_err());
175+
assert!("/* comment */0".parse::<Literal>().is_err());
176+
assert!("0/* comment */".parse::<Literal>().is_err());
177+
assert!("0// comment".parse::<Literal>().is_err());
178+
}
179+
166180
#[test]
167181
fn roundtrip() {
168182
fn roundtrip(p: &str) {

0 commit comments

Comments
 (0)