fix f64 indexing, introduce bespoke F64Table type (#3065)

This commit is contained in:
Mark Thom
2025-09-11 23:58:36 -07:00
parent 368c9fd9dd
commit ffea37d899
14 changed files with 291 additions and 183 deletions

View File

@@ -22,6 +22,7 @@ use dashu::Integer;
use dashu::Rational;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
use ordered_float::OrderedFloat;
use scryer_modular_bitfield::error::OutOfBounds;
use scryer_modular_bitfield::prelude::*;
@@ -706,7 +707,7 @@ pub enum Literal {
Fixnum(Fixnum),
Integer(TypedArenaPtr<Integer>),
Rational(TypedArenaPtr<Rational>),
F64Offset(F64Offset),
F64(F64Offset, OrderedFloat<f64>),
}
/*

View File

@@ -54,28 +54,10 @@ impl Token {
}
}
#[derive(Debug)]
enum Number {
BigInt(TypedArenaPtr<Integer>),
Fixnum(Fixnum),
Float(F64Offset),
}
impl Number {
#[inline]
#[allow(clippy::wrong_self_convention)]
fn to_literal(self) -> Literal {
match self {
Number::BigInt(ibig) => Literal::Integer(ibig),
Number::Fixnum(fixnum) => Literal::Fixnum(fixnum),
Number::Float(f) => Literal::F64Offset(f),
}
}
}
#[derive(Debug)]
enum NumberToken {
Number(Number),
Integer(GInteger),
Float(F64Offset, OrderedFloat<f64>),
Partial(String),
}
@@ -84,7 +66,9 @@ impl NumberToken {
#[allow(clippy::wrong_self_convention)]
fn to_token(self) -> Option<Token> {
match self {
NumberToken::Number(number) => Some(Token::Literal(number.to_literal())),
NumberToken::Float(offset, fl) => Some(Token::Literal(Literal::F64(offset, fl))),
NumberToken::Integer(GInteger::BigInt(n)) => Some(Token::Literal(Literal::Integer(n))),
NumberToken::Integer(GInteger::Fixnum(n)) => Some(Token::Literal(Literal::Fixnum(n))),
NumberToken::Partial(_) => None,
}
}
@@ -105,6 +89,22 @@ macro_rules! try_nt {
}};
}
#[derive(Debug)]
enum GInteger {
BigInt(TypedArenaPtr<Integer>),
Fixnum(Fixnum),
}
impl GInteger {
#[inline]
fn to_literal(self) -> Literal {
match self {
GInteger::BigInt(integer) => Literal::Integer(integer),
GInteger::Fixnum(fixnum) => Literal::Fixnum(fixnum),
}
}
}
pub(crate) struct Lexer<'a, R> {
pub(crate) reader: R,
pub(crate) machine_st: &'a mut MachineState,
@@ -523,7 +523,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}
self.parse_integer_by_radix(&token, 16)
.map(NumberToken::Number)
.map(NumberToken::Integer)
} else {
self.return_char(start);
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
@@ -554,7 +554,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}
self.parse_integer_by_radix(&token, 8)
.map(NumberToken::Number)
.map(NumberToken::Integer)
} else {
self.return_char(start);
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
@@ -585,7 +585,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}
self.parse_integer_by_radix(&token, 2)
.map(NumberToken::Number)
.map(NumberToken::Integer)
} else {
self.return_char(start);
Err(ParserError::ParseBigInt(self.line_num, self.col_num))
@@ -680,10 +680,16 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}
}
fn vacate_with_float(&mut self, mut token: String) -> Result<Number, ParserError> {
fn vacate_with_float(
&mut self,
mut token: String,
) -> Result<(F64Offset, OrderedFloat<f64>), ParserError> {
self.return_char(token.pop().unwrap());
let n = parse_float_lossy(&token)?;
Ok(Number::Float(float_alloc!(n, self.machine_st.arena)))
let offset = float_alloc!(n, self.machine_st.arena);
Ok((offset, OrderedFloat(n)))
}
fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> {
@@ -704,24 +710,24 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}
}
fn parse_integer_by_radix(&mut self, token: &str, radix: u32) -> Result<Number, ParserError> {
fn parse_integer_by_radix(&mut self, token: &str, radix: u32) -> Result<GInteger, ParserError> {
i64::from_str_radix(token, radix)
.map(|n| {
Fixnum::build_with_checked(n)
.map(Number::Fixnum)
.map(GInteger::Fixnum)
.unwrap_or_else(|_| {
Number::BigInt(arena_alloc!(Integer::from(n), &mut self.machine_st.arena))
GInteger::BigInt(arena_alloc!(Integer::from(n), &mut self.machine_st.arena))
})
})
.or_else(|_| {
Integer::from_str_radix(token, radix)
.map(|n| Number::BigInt(arena_alloc!(n, &mut self.machine_st.arena)))
.map(|n| GInteger::BigInt(arena_alloc!(n, &mut self.machine_st.arena)))
.map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
}
#[inline]
fn parse_integer(&mut self, token: &str) -> Result<Number, ParserError> {
fn parse_integer(&mut self, token: &str) -> Result<GInteger, ParserError> {
self.parse_integer_by_radix(token, 10)
}
@@ -743,7 +749,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
if self.reader.peek_char().is_none() {
self.return_char('.');
self.parse_integer(&token).map(NumberToken::Number)
self.parse_integer(&token).map(NumberToken::Integer)
} else if decimal_digit_char!(self.lookahead_char()?) {
token.push('.');
token.push(self.read_char()?);
@@ -761,12 +767,18 @@ impl<'a, R: CharRead> Lexer<'a, R> {
token.push(c);
let c = match self.lookahead_char() {
Err(_) => return self.vacate_with_float(token).map(NumberToken::Number),
Err(_) => {
return self
.vacate_with_float(token)
.map(|(offset, fl)| NumberToken::Float(offset, fl))
}
Ok(c) => c,
};
if !sign_char!(c) && !decimal_digit_char!(c) {
return self.vacate_with_float(token).map(NumberToken::Number);
return self
.vacate_with_float(token)
.map(|(offset, fl)| NumberToken::Float(offset, fl));
}
if sign_char!(c) {
@@ -776,14 +788,18 @@ impl<'a, R: CharRead> Lexer<'a, R> {
let c = match self.lookahead_char() {
Err(_) => {
self.return_char(token.pop().unwrap());
return self.vacate_with_float(token).map(NumberToken::Number);
return self
.vacate_with_float(token)
.map(|(offset, fl)| NumberToken::Float(offset, fl));
}
Ok(c) => c,
};
if !decimal_digit_char!(c) {
self.return_char(token.pop().unwrap());
return self.vacate_with_float(token).map(NumberToken::Number);
return self
.vacate_with_float(token)
.map(|(offset, fl)| NumberToken::Float(offset, fl));
}
}
@@ -805,30 +821,27 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}
let n = parse_float_lossy(&token)?;
let offset = float_alloc!(n, self.machine_st.arena);
Ok(NumberToken::Number(Number::Float(float_alloc!(
n,
self.machine_st.arena
))))
Ok(NumberToken::Float(offset, OrderedFloat(n)))
} else {
return self.vacate_with_float(token).map(NumberToken::Number);
self.vacate_with_float(token)
.map(|(offset, fl)| NumberToken::Float(offset, fl))
}
} else {
let n = parse_float_lossy(&token)?;
Ok(NumberToken::Number(Number::Float(float_alloc!(
n,
self.machine_st.arena
))))
let offset = float_alloc!(n, self.machine_st.arena);
Ok(NumberToken::Float(offset, OrderedFloat(n)))
}
} else {
self.return_char('.');
self.parse_integer(&token).map(NumberToken::Number)
self.parse_integer(&token).map(NumberToken::Integer)
}
} else if token.starts_with('0') && token.len() == 1 {
if c == 'x' {
self.hexadecimal_constant(c).or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
self.parse_integer(&token).map(NumberToken::Number)
self.parse_integer(&token).map(NumberToken::Integer)
} else {
Err(e)
}
@@ -836,7 +849,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
} else if c == 'o' {
self.octal_constant(c).or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
self.parse_integer(&token).map(NumberToken::Number)
self.parse_integer(&token).map(NumberToken::Integer)
} else {
Err(e)
}
@@ -844,7 +857,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
} else if c == 'b' {
self.binary_constant(c).or_else(|e| {
if let ParserError::ParseBigInt(..) = e {
self.parse_integer(&token).map(NumberToken::Number)
self.parse_integer(&token).map(NumberToken::Integer)
} else {
Err(e)
}
@@ -861,14 +874,16 @@ impl<'a, R: CharRead> Lexer<'a, R> {
self.skip_char(c);
self.return_char('\'');
return Ok(NumberToken::Number(Number::Fixnum(Fixnum::build_with(0))));
return Ok(NumberToken::Integer(GInteger::Fixnum(Fixnum::build_with(
0,
))));
} else {
self.return_char('\\');
}
}
self.get_single_quoted_char()
.map(|c| NumberToken::Number(Number::Fixnum(Fixnum::build_with(c))))
.map(|c| NumberToken::Integer(GInteger::Fixnum(Fixnum::build_with(c))))
.or_else(|err| {
match err {
ParserError::UnexpectedChar('\'', ..) => {}
@@ -876,13 +891,13 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}
self.return_char(c);
self.parse_integer(&token).map(NumberToken::Number)
self.parse_integer(&token).map(NumberToken::Integer)
})
} else {
self.parse_integer(&token).map(NumberToken::Number)
self.parse_integer(&token).map(NumberToken::Integer)
}
} else {
self.parse_integer(&token).map(NumberToken::Number)
self.parse_integer(&token).map(NumberToken::Integer)
}
}
@@ -954,13 +969,12 @@ impl<'a, R: CharRead> Lexer<'a, R> {
Ok(n) => Ok(Token::Literal(n.to_literal())),
Err(_) => {
let n = parse_float_lossy(&token_string)?;
Ok(Token::Literal(Literal::F64Offset(float_alloc!(
n,
self.machine_st.arena
))))
let offset = float_alloc!(n, self.machine_st.arena);
Ok(Token::Literal(Literal::F64(offset, OrderedFloat(n))))
}
},
Ok(NumberToken::Number(n)) => Ok(Token::Literal(n.to_literal())),
Ok(NumberToken::Float(offset, n)) => Ok(Token::Literal(Literal::F64(offset, n))),
Ok(NumberToken::Integer(n)) => Ok(Token::Literal(n.to_literal())),
Err(e) => Err(e),
}
}

View File

@@ -1,9 +1,10 @@
use dashu::Integer;
use dashu::Rational;
use ordered_float::OrderedFloat;
use crate::arena::*;
use crate::atom_table::*;
use crate::offset_table::OffsetTable;
use crate::offset_table::F64Offset;
use crate::parser::ast::*;
use crate::parser::char_reader::*;
use crate::parser::lexer::*;
@@ -911,7 +912,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
fn negate_number<N, Negator, ToLiteral>(&mut self, n: N, negator: Negator, constr: ToLiteral)
where
Negator: Fn(N, &mut Arena) -> N,
ToLiteral: Fn(N, &mut Arena) -> Literal,
ToLiteral: Fn(N) -> Literal,
{
if let Some(desc) = self.stack.last().cloned() {
if let Some(term) = self.terms.last().cloned() {
@@ -924,7 +925,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
self.terms.pop();
let arena = &mut self.lexer.machine_st.arena;
let literal = constr(negator(n, arena), arena);
let literal = constr(negator(n, arena));
self.shift(Token::Literal(literal), 0, TERM);
@@ -935,7 +936,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
}
}
let literal = constr(n, &mut self.lexer.machine_st.arena);
let literal = constr(n);
self.shift(Token::Literal(literal), 0, TERM);
}
@@ -952,42 +953,36 @@ impl<'a, R: CharRead> Parser<'a, R> {
arena_alloc!(data, arena)
}
fn negate_f64(
(_offset, n): (F64Offset, OrderedFloat<f64>),
arena: &mut Arena,
) -> (F64Offset, OrderedFloat<f64>) {
let offset = arena.f64_tbl.build_with(-n);
(offset, -n)
}
match token {
Token::String(string) => {
self.shift(Token::String(string), 0, TERM);
}
Token::Literal(Literal::Integer(n)) => {
self.negate_number(n, negate_int_rc, |n, _| Literal::Integer(n))
self.negate_number(n, negate_int_rc, Literal::Integer)
}
Token::Literal(Literal::Rational(n)) => {
self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r))
self.negate_number(n, negate_rat_rc, Literal::Rational)
}
Token::Literal(Literal::F64Offset(n))
if self
.lexer
.machine_st
.arena
.f64_tbl
.get_entry(n)
.is_infinite() =>
{
Token::Literal(Literal::F64(_offset, n)) if n.is_infinite() => {
return Err(ParserError::InfiniteFloat(
self.lexer.line_num,
self.lexer.col_num,
));
}
Token::Literal(Literal::F64Offset(n)) => {
let n = self.lexer.machine_st.arena.f64_tbl.get_entry(n);
self.negate_number(
n,
|n, _| -n,
|n, arena| Literal::F64Offset(arena.f64_tbl.build_with(n)),
)
}
Token::Literal(Literal::Fixnum(n)) => {
self.negate_number(n, |n, _| -n, |n, _| Literal::Fixnum(n))
Token::Literal(Literal::F64(offset, n)) => {
self.negate_number((offset, n), negate_f64, |(offset, n)| {
Literal::F64(offset, n)
})
}
Token::Literal(Literal::Fixnum(n)) => self.negate_number(n, |n, _| -n, Literal::Fixnum),
Token::Literal(c) => {
if let Literal::Atom(name) = c {
if !self.shift_op(name, op_dir)? {