diff --git a/crates/ailang-surface/src/parse.rs b/crates/ailang-surface/src/parse.rs index fd884a7..1b5753b 100644 --- a/crates/ailang-surface/src/parse.rs +++ b/crates/ailang-surface/src/parse.rs @@ -162,6 +162,7 @@ fn tok_label(t: &Tok) -> String { Tok::LParen => "`(`".into(), Tok::RParen => "`)`".into(), Tok::Int(v) => format!("integer `{v}`"), + Tok::Float(bits) => format!("float `0x{bits:016x}`"), Tok::Str(s) => format!("string {s:?}"), Tok::Ident(s) => format!("ident `{s}`"), } @@ -1233,6 +1234,10 @@ impl<'a> Parser<'a> { self.cur += 1; Ok(Term::Lit { lit: Literal::Int { value: v } }) } + Some(Token { tok: Tok::Float(bits), .. }) => { + self.cur += 1; + Ok(Term::Lit { lit: Literal::Float { bits } }) + } Some(Token { tok: Tok::Str(s), .. }) => { self.cur += 1; Ok(Term::Lit { lit: Literal::Str { value: s } }) @@ -1627,6 +1632,10 @@ impl<'a> Parser<'a> { self.cur += 1; Literal::Int { value: v } } + Some(Token { tok: Tok::Float(bits), .. }) => { + self.cur += 1; + Literal::Float { bits } + } Some(Token { tok: Tok::Str(s), .. }) => { self.cur += 1; Literal::Str { value: s } @@ -1640,7 +1649,7 @@ impl<'a> Parser<'a> { Literal::Bool { value: false } } else { return Err(ParseError::Unexpected { - expected: "literal form (integer, string, `true`, or `false`)".into(), + expected: "literal form (integer, float, string, `true`, or `false`)".into(), got: tok_label(&Tok::Ident(s)), pos: span.start, }); @@ -1648,7 +1657,7 @@ impl<'a> Parser<'a> { } Some(t) => { return Err(ParseError::Unexpected { - expected: "literal form (integer, string, `true`, or `false`)".into(), + expected: "literal form (integer, float, string, `true`, or `false`)".into(), got: tok_label(&t.tok), pos: t.span.start, }); @@ -2403,4 +2412,20 @@ mod tests { "expected duplicate-doc diagnostic, got: {msg}" ); } + + /// Floats milestone iter 2.2 RED: `1.5` parses as + /// `Term::Lit { lit: Literal::Float { bits: 0x3ff8_0000_0000_0000 } }`. + /// Property protected: a `Tok::Float` produced by the lexer flows through + /// `parse_term` into a `Literal::Float` AST node carrying the same bit + /// pattern, so the surface→AST translation is bit-exact. + #[test] + fn parses_float_atom_term() { + let t = parse_term("1.5").expect("parse term"); + match t { + Term::Lit { lit: Literal::Float { bits } } => { + assert_eq!(bits, 0x3ff8_0000_0000_0000u64); + } + other => panic!("expected Term::Lit::Float, got {other:?}"), + } + } }