Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
27 changes: 27 additions & 0 deletions pastey-test-suite/tests/test_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,33 @@ fn test_literal_suffix() {
assert_eq!(literal!(32), 1);
}

#[test]
fn test_float_literal() {
let x: f32 = paste!([<0.0 f32>]);
assert_eq!(x, 0.0f32);

let y: f64 = paste!([<1.5 f64>]);
assert_eq!(y, 1.5f64);

macro_rules! typed_float {
($ty:tt) => {
paste!([<1.0 $ty>])
};
}

let _: f32 = typed_float!(f32);
let _: f64 = typed_float!(f64);
}

#[test]
fn test_negative_float_literal() {
let x: f32 = paste!([< -1.5 f32>]);
assert_eq!(x, -1.5f32);

let y: f64 = paste!([<-0.5 f64>]);
assert_eq!(y, -0.5f64);
}

#[test]
fn test_underscore() {
paste! {
Expand Down
40 changes: 38 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,22 +251,35 @@ fn parse_bracket_as_segments(input: TokenStream, scope: Span) -> Result<Vec<Segm
}
}
}
if string.value.contains(&['\\', '.', '+'][..])
// Numeric literals (e.g. `0.0`, `1.5f32`) start with a digit and may
// contain `.`. Allow them through; reject other literals that contain
// unsupported characters such as `\`, `+`, or `.`.
let is_numeric_literal = string.value.starts_with(|ch: char| ch.is_ascii_digit())
&& !string.value.contains('+');
if (!is_numeric_literal && string.value.contains(&['\\', '.', '+'][..]))
|| string.value.starts_with("b'")
|| string.value.starts_with("b\"")
|| string.value.starts_with("br\"")
{
return Err(Error::new(string.span, "unsupported literal"));
}
let mut range = 0..string.value.len();
let is_quoted = string.value.starts_with("r\"")
|| string.value.starts_with(&['"', '\''][..]);
if string.value.starts_with("r\"") {
range.start += 2;
range.end -= 1;
} else if string.value.starts_with(&['"', '\''][..]) {
range.start += 1;
range.end -= 1;
}
string.value = string.value[range].replace('-', "_");
// Only replace `-` with `_` in quoted string/char literal content.
// Numeric literals and bare `-` punct segments must not be altered.
string.value = if is_quoted {
string.value[range].replace('-', "_")
} else {
string.value[range].to_string()
};
}
}

Expand All @@ -291,6 +304,29 @@ fn pasted_to_tokens(mut pasted: String, span: Span) -> Result<TokenStream> {
return Ok(tokens);
}

if pasted.starts_with('-') {
let rest = &pasted[1..];
if rest.starts_with(|ch: char| ch.is_ascii_digit()) {
let mut minus = TokenTree::Punct(Punct::new('-', Spacing::Alone));
minus.set_span(span);
tokens.extend(iter::once(minus));
let literal = match panic::catch_unwind(|| Literal::from_str(rest)) {
Ok(Ok(mut literal)) => {
literal.set_span(span);
TokenTree::Literal(literal)
}
Ok(Err(LexError { .. })) | Err(_) => {
return Err(Error::new(
span,
&format!("`{:?}` is not a valid literal", pasted),
));
}
};
tokens.extend(iter::once(literal));
return Ok(tokens);
}
}

if pasted.starts_with('\'') {
let mut apostrophe = TokenTree::Punct(Punct::new('\'', Spacing::Joint));
apostrophe.set_span(span);
Expand Down
4 changes: 4 additions & 0 deletions src/segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ pub(crate) fn parse(tokens: &mut Peekable<token_stream::IntoIter>) -> Result<Vec
value: "#".to_string(),
span: punct.span(),
})),
'-' => segments.push(Segment::String(LitStr {
value: "-".to_owned(),
span: punct.span(),
})),
_ => return Err(Error::new(punct.span(), "unexpected punct")),
},
TokenTree::Group(group) => {
Expand Down