Skip to content

Commit 43a066c

Browse files
author
Jonas Schievink
committed
Fix conversion of float literals in TtTreeSink
1 parent 505f2d9 commit 43a066c

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs

+30
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,33 @@ const _: () = 0e0;
175175
"#]],
176176
);
177177
}
178+
179+
#[test]
180+
fn float_literal_in_tt() {
181+
check(
182+
r#"
183+
macro_rules! constant {
184+
($( $ret:expr; )*) => {};
185+
}
186+
187+
macro_rules! float_const_impl {
188+
() => ( constant!(0.3; 3.3;); );
189+
}
190+
191+
float_const_impl! {}
192+
"#,
193+
expect![[r#"
194+
macro_rules! constant {
195+
($( $ret:expr; )*) => {};
196+
}
197+
198+
macro_rules! float_const_impl {
199+
() => ( constant!(0.3; 3.3;); );
200+
}
201+
202+
constant!(0.3;
203+
3.3;
204+
);
205+
"#]],
206+
);
207+
}

crates/mbe/src/syntax_bridge.rs

+50
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@ struct TtTreeSink<'a> {
740740
text_pos: TextSize,
741741
inner: SyntaxTreeBuilder,
742742
token_map: TokenMap,
743+
remaining_float_lit_text: String,
743744
}
744745

745746
impl<'a> TtTreeSink<'a> {
@@ -751,6 +752,7 @@ impl<'a> TtTreeSink<'a> {
751752
text_pos: 0.into(),
752753
inner: SyntaxTreeBuilder::default(),
753754
token_map: TokenMap::default(),
755+
remaining_float_lit_text: String::new(),
754756
}
755757
}
756758

@@ -777,6 +779,54 @@ impl<'a> TtTreeSink<'a> {
777779
n_tokens = 2;
778780
}
779781

782+
// We need to split a float `tt::Literal` into up to 3 tokens consumed by the parser.
783+
match self.cursor.token_tree() {
784+
Some(tt::buffer::TokenTreeRef::Subtree(sub, _)) if sub.delimiter.is_none() => {
785+
self.cursor = self.cursor.subtree().unwrap()
786+
}
787+
_ => {}
788+
}
789+
let literal = match self.cursor.token_tree() {
790+
Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Literal(lit), _)) => Some(lit),
791+
_ => None,
792+
};
793+
if matches!(
794+
kind,
795+
FLOAT_NUMBER_PART | FLOAT_NUMBER_START_0 | FLOAT_NUMBER_START_1 | FLOAT_NUMBER_START_2
796+
) {
797+
if self.remaining_float_lit_text.is_empty() {
798+
always!(
799+
literal.is_some(),
800+
"kind={:?}, cursor tt={:?}",
801+
kind,
802+
self.cursor.token_tree()
803+
);
804+
let text = literal.map_or(String::new(), |lit| lit.to_string());
805+
self.cursor = self.cursor.bump();
806+
match text.split_once('.') {
807+
Some((start, end)) => {
808+
self.inner.token(kind, start);
809+
self.remaining_float_lit_text = format!(".{end}");
810+
return;
811+
}
812+
None => {
813+
self.inner.token(kind, &text);
814+
return;
815+
}
816+
}
817+
} else {
818+
self.inner.token(kind, &self.remaining_float_lit_text);
819+
self.remaining_float_lit_text.clear();
820+
return;
821+
}
822+
}
823+
if kind == DOT && !self.remaining_float_lit_text.is_empty() {
824+
always!(self.remaining_float_lit_text.chars().next() == Some('.'));
825+
self.inner.token(kind, ".");
826+
self.remaining_float_lit_text = self.remaining_float_lit_text[1..].to_string();
827+
return;
828+
}
829+
780830
let mut last = self.cursor;
781831
for _ in 0..n_tokens {
782832
let tmp: u8;

0 commit comments

Comments
 (0)