Skip to content
Open
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
2 changes: 0 additions & 2 deletions crates/parser/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,6 @@ pub(super) fn process(mut events: Vec<Event>, mut errors: Vec<String>) -> Output
}
Event::FloatSplitHack { ends_in_dot } => {
res.float_split_hack(ends_in_dot);
let ev = mem::replace(&mut events[i + 1], Event::tombstone());
assert!(matches!(ev, Event::Finish), "{ev:?}");
}
Event::Error { err } => {
// Move the string out of the side table; each index is visited
Expand Down
22 changes: 15 additions & 7 deletions crates/parser/src/grammar/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,13 +598,21 @@ fn field_expr<const FLOAT_RECOVERY: bool>(
if p.at_ts(PATH_NAME_REF_OR_INDEX_KINDS) {
name_ref_mod_path_or_index(p);
} else if p.at(FLOAT_NUMBER) {
return match p.split_float(m) {
(true, m) => {
let lhs = m.complete(p, FIELD_EXPR);
postfix_dot_expr::<true>(p, lhs)
}
(false, m) => Ok(m.complete(p, FIELD_EXPR)),
};
if p.float_has_dot() {
p.split_float();
name_ref_mod_path_or_index(p);
let lhs = m.complete(p, FIELD_EXPR);
return postfix_dot_expr::<false>(p, lhs);
}

// No `.` in the float lexeme (e.g. `1e0`): recover without FloatSplit.
let (inner, outer) = p.nest_field_expr(m);
let err = p.start();
p.error("illegal float literal");
p.bump(FLOAT_NUMBER);
err.complete(p, ERROR);
inner.complete(p, FIELD_EXPR);
return Ok(outer.complete(p, FIELD_EXPR));
} else {
p.error("expected field name or number");
}
Expand Down
12 changes: 12 additions & 0 deletions crates/parser/src/grammar/expressions/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,19 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
// fn foo() {
// builtin#offset_of(Foo, (bar.baz.0));
// }

// test offset_of_tuple_fields
// fn foo() {
// builtin#offset_of(ComplexTup, 0.1);
// builtin#offset_of(ComplexTup, 0.1.1.1);
// builtin#offset_of(ComplexTup, 0. 1);
// builtin#offset_of(ComplexTup, 0 .1.1.1);
// }
while !p.at(EOF) && !p.at(T![')']) {
// `0.1` is one FLOAT_NUMBER; split so the name/DOT loop sees INT/DOT/INT.
if p.at(FLOAT_NUMBER) && p.float_has_dot() {
p.split_float();
}
name_ref_mod_path_or_index(p);
if !p.at(T![')']) {
p.expect(T![.]);
Expand Down
18 changes: 17 additions & 1 deletion crates/parser/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type bits = u64;
pub struct Input {
kind: Vec<SyntaxKind>,
joint: Vec<bits>,
/// Whether a `FLOAT_NUMBER` lexeme contains `'.'`. Indexed like [`Self::joint`].
float_has_dot: Vec<bits>,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't actually need this because when a float is split, a dotless float (scientific notation) is not allowed, so we can assume the float has a dot and the caller should emit an error. In fact this is what we already do.

contextual_kind: Vec<SyntaxKind>,
edition: Vec<Edition>,
}
Expand All @@ -25,9 +27,11 @@ pub struct Input {
impl Input {
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
let bits_capacity = capacity.div_ceil(bits::BITS as usize);
Self {
kind: Vec::with_capacity(capacity),
joint: Vec::with_capacity(capacity.div_ceil(bits::BITS as usize)),
joint: Vec::with_capacity(bits_capacity),
float_has_dot: Vec::with_capacity(bits_capacity),
contextual_kind: Vec::with_capacity(capacity),
edition: Vec::with_capacity(capacity),
}
Expand Down Expand Up @@ -62,11 +66,19 @@ impl Input {
let (idx, b_idx) = self.bit_index(n);
self.joint[idx] |= 1 << b_idx;
}
/// Marks the last pushed token as a `FLOAT_NUMBER` whose text contains `.`.
#[inline]
pub fn set_float_has_dot(&mut self) {
let n = self.len() - 1;
let (idx, b_idx) = self.bit_index(n);
self.float_has_dot[idx] |= 1 << b_idx;
}
#[inline]
fn push_impl(&mut self, kind: SyntaxKind, contextual_kind: SyntaxKind, edition: Edition) {
let idx = self.len();
if idx.is_multiple_of(bits::BITS as usize) {
self.joint.push(0);
self.float_has_dot.push(0);
}
self.kind.push(kind);
self.contextual_kind.push(contextual_kind);
Expand All @@ -89,6 +101,10 @@ impl Input {
let (idx, b_idx) = self.bit_index(n);
self.joint[idx] & (1 << b_idx) != 0
}
pub(crate) fn float_has_dot(&self, n: usize) -> bool {
let (idx, b_idx) = self.bit_index(n);
self.float_has_dot[idx] & (1 << b_idx) != 0
}
}

impl Input {
Expand Down
6 changes: 2 additions & 4 deletions crates/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,8 @@ impl TopEntryPoint {
match step {
Step::Enter { .. } => depth += 1,
Step::Exit => depth -= 1,
Step::FloatSplit { ends_in_dot: has_pseudo_dot } => {
depth -= 1 + !has_pseudo_dot as usize
}
Step::Token { .. } | Step::Error { .. } => (),
// FloatSplit does not contribute to tree depth; nesting is Enter/Exit.
Step::Token { .. } | Step::FloatSplit { .. } | Step::Error { .. } => (),
}
}
assert!(!first, "no tree at all");
Expand Down
Loading
Loading