floats iter 2.1 fixup: drop task-tags + refresh stale prose + uppercase-E + leading-dot tests

This commit is contained in:
2026-05-10 15:04:50 +02:00
parent d0c9133ae4
commit f960e39f8b
+36 -4
View File
@@ -10,7 +10,9 @@
//! 3. After tokenisation, classify by first character:
//! - `"` ⇒ string literal (consume until closing `"`; `\"` and
//! `\n` escapes supported).
//! - digit, or `-` followed by digit ⇒ integer literal.
//! - digit, or `-` followed by digit ⇒ integer or float literal
//! (float if the token contains `.`, `e`, or `E`; integer
//! otherwise).
//! - otherwise ⇒ ident.
//!
//! Operators (`+`, `==`, `<=`, `**`), qualified names like
@@ -40,7 +42,7 @@ pub enum Tok {
/// Integer literal. Original textual form preserved for error messages;
/// parsed `i64` value carried for direct use.
Int(i64),
/// IEEE-754 binary64 literal (Floats milestone iter 2). The
/// IEEE-754 binary64 literal. The
/// payload is the bit pattern produced by `f64::to_bits`. The
/// surface forms recognised by the lexer are
/// `<digits>.<digits>(e[+-]?<digits>)?` and
@@ -49,7 +51,7 @@ pub enum Tok {
Float(u64),
/// String literal contents (after escape processing).
Str(String),
/// Identifier. Anything that isn't a paren, integer, or string.
/// Identifier. Anything that isn't a paren, integer, float, or string.
Ident(String),
}
@@ -347,7 +349,7 @@ mod tests {
assert!(matches!(&toks[0].tok, Tok::Str(s) if s == "em — dash and naïve"));
}
/// Iter 22-floats.2 RED: a `<digits>.<digits>` token lexes as
/// A `<digits>.<digits>` token lexes as
/// `Tok::Float` carrying the IEEE-754 binary64 bit pattern of
/// `f64::from_str(raw).unwrap().to_bits()`. Pinned literal:
/// `1.5_f64` → bit pattern `0x3FF8000000000000`.
@@ -475,4 +477,34 @@ mod tests {
"expected InvalidFloat for `1..5`, got {err:?}"
);
}
/// Spec A2 grammar accepts both `e` and `E` for the exponent
/// marker. The `looks_like_float` validator handles both bytes;
/// pin the uppercase form explicitly.
#[test]
fn float_uppercase_exponent() {
let toks = tokenize("1.5E3 2E-5").unwrap();
assert_eq!(toks.len(), 2);
match toks[0].tok {
Tok::Float(b) => assert_eq!(b, 1.5e3_f64.to_bits()),
ref other => panic!("expected Tok::Float, got {other:?}"),
}
match toks[1].tok {
Tok::Float(b) => assert_eq!(b, 2e-5_f64.to_bits()),
ref other => panic!("expected Tok::Float, got {other:?}"),
}
}
/// Spec A2 rejects bare leading dot at the *float* level — `.5` is
/// not a float literal. The lexer's digit-lead rule does not fire
/// (first byte `.` is not a digit and not `-`-followed-by-digit),
/// so `.5` falls through to the maximal-non-paren-non-whitespace
/// run and lexes as `Tok::Ident(".5")`. Downstream parser /
/// typecheck stages produce the appropriate diagnostic.
#[test]
fn float_leading_dot_lexes_as_ident() {
let toks = tokenize(".5").unwrap();
assert_eq!(toks.len(), 1);
assert!(matches!(&toks[0].tok, Tok::Ident(s) if s == ".5"));
}
}