]> Repositorios git - scryer-prolog.git/commitdiff
make Fixnum::build_with harder to accidentally misuse
authorBennet Bleßmann <[email protected]>
Wed, 22 Jan 2025 20:10:44 +0000 (21:10 +0100)
committerMark Thom <[email protected]>
Tue, 8 Jul 2025 05:39:34 +0000 (22:39 -0700)
change trait bound order for better

19 files changed:
src/arena.rs
src/arithmetic.rs
src/forms.rs
src/functor_macro.rs
src/heap_print.rs
src/indexing.rs
src/machine/arithmetic_ops.rs
src/machine/attributed_variables.rs
src/machine/dispatch.rs
src/machine/loader.rs
src/machine/machine_state.rs
src/machine/machine_state_impl.rs
src/machine/mod.rs
src/machine/system_calls.rs
src/macros.rs
src/parser/ast.rs
src/parser/lexer.rs
src/parser/parser.rs
src/types.rs

index a9f9a76b9a8d198a0156ab1f9f33c5057559c121..a6ccb921be1892e7feaa3e8c0fbee8ebb57928c4 100644 (file)
@@ -784,7 +784,9 @@ mod tests {
             _ => { unreachable!() }
         );
 
-        let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 54));
+        let fixnum_b_cell = fixnum_as_cell!(
+            Fixnum::build_with_checked(1i64 << 54).expect("1 << 54 fits in Fixnum")
+        );
 
         assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
 
@@ -793,41 +795,29 @@ mod tests {
             None => unreachable!(),
         }
 
-        if Fixnum::build_with_checked(1 << 56).is_ok() {
-            unreachable!()
-        }
-
-        if Fixnum::build_with_checked(i64::MAX).is_ok() {
-            unreachable!()
-        }
-
-        if Fixnum::build_with_checked(i64::MIN).is_ok() {
-            unreachable!()
-        }
-
-        match Fixnum::build_with_checked(-1) {
-            Ok(n) => assert_eq!(n.get_num(), -1),
-            _ => unreachable!(),
-        }
+        Fixnum::build_with_checked(1i64 << 56).expect_err("1 << 56 is too large for fixnum");
 
-        match Fixnum::build_with_checked((1 << 55) - 1) {
-            Ok(n) => assert_eq!(n.get_num(), (1 << 55) - 1),
-            _ => unreachable!(),
-        }
+        Fixnum::build_with_checked(i64::MAX).expect_err("i64::MAX is too large for Fixnum");
+        Fixnum::build_with_checked(i64::MIN).expect_err("i64::MIN is too small for Fixnum");
+        assert_eq!(
+            Fixnum::build_with_checked(-1i64)
+                .expect("-1 fits in fixnum")
+                .get_num(),
+            -1
+        );
 
-        match Fixnum::build_with_checked(-(1 << 55)) {
-            Ok(n) => assert_eq!(n.get_num(), -(1 << 55)),
-            _ => unreachable!(),
-        }
+        Fixnum::build_with_checked((1i64 << 55) - 1)
+            .expect("(1 << 55) - 1 is the largest value that fits in Fixnum");
 
-        if Fixnum::build_with_checked(-(1 << 55) - 1).is_ok() {
-            unreachable!()
-        }
+        Fixnum::build_with_checked(-(1i64 << 55))
+            .expect("-(1 << 55) is the smallest value that fits in fixnum");
+        Fixnum::build_with_checked(-(1i64 << 55) - 1)
+            .expect_err("-(1<<55) - 1 is too small for Fixnum");
 
-        match Fixnum::build_with_checked(-1) {
-            Ok(n) => assert_eq!(-n, Fixnum::build_with(1)),
-            _ => unreachable!(),
-        }
+        assert_eq!(
+            -Fixnum::build_with_checked(-1i64).expect("-1 fits in Fixnum"),
+            Fixnum::build_with(1)
+        );
 
         // float
 
index 2bdcc3153872a88e9a3481a4a880d73d3c9b1124..2f0df28de6ec6cac6756338f46af6f713a947860 100644 (file)
@@ -358,9 +358,8 @@ impl<'a> ArithmeticEvaluator<'a> {
 pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalError> {
     match n {
         &Number::Integer(i) => {
-            let result = (&*i).try_into();
-            if let Ok(value) = result {
-                Ok(fixnum!(Number, value, arena))
+            if let Ok(value) = Fixnum::build_with_checked(&*i) {
+                Ok(Number::Fixnum(value))
             } else {
                 Ok(*n)
             }
@@ -369,11 +368,14 @@ pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalErro
         &Number::Float(f) => {
             let f = f.floor();
 
-            const I64_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MIN as f64);
-            const I64_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MAX as f64);
+            const FIXNUM_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MIN as f64);
+            const FIXNUM_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MAX as f64);
 
-            if I64_MIN_TO_F <= f && f <= I64_MAX_TO_F {
-                Ok(fixnum!(Number, f.into_inner() as i64, arena))
+            if (FIXNUM_MIN_TO_F..=FIXNUM_MAX_TO_F).contains(&f) {
+                Ok(Number::Fixnum(
+                    // Safety: We checked that the value is in range
+                    unsafe { Fixnum::build_with_unchecked(f.into_inner() as i64) },
+                ))
             } else {
                 Ok(Number::Integer(arena_alloc!(
                     Integer::try_from(classify_float(f.0)?).unwrap_or_else(|_| {
@@ -386,8 +388,8 @@ pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalErro
         Number::Rational(ref r) => {
             let floor = r.floor();
 
-            if let Ok(value) = (&floor).try_into() {
-                Ok(fixnum!(Number, value, arena))
+            if let Ok(value) = Fixnum::build_with_checked(&floor) {
+                Ok(Number::Fixnum(value))
             } else {
                 Ok(Number::Integer(arena_alloc!(floor, arena)))
             }
index 21a5cc91ba40199870273be03174dda12ed374ec..0779d5b8537dba017ef09f8ce0c07c9423c41c16 100644 (file)
@@ -697,14 +697,14 @@ impl ArenaFrom<isize> for Number {
 impl ArenaFrom<u32> for Number {
     #[inline]
     fn arena_from(value: u32, _arena: &mut Arena) -> Number {
-        Number::Fixnum(Fixnum::build_with(value as i64))
+        Number::Fixnum(Fixnum::build_with(value))
     }
 }
 
 impl ArenaFrom<i32> for Number {
     #[inline]
     fn arena_from(value: i32, _arena: &mut Arena) -> Number {
-        Number::Fixnum(Fixnum::build_with(value as i64))
+        Number::Fixnum(Fixnum::build_with(value))
     }
 }
 
index 7cc48eaad6215fe77d08eb9cdcf9c176b4845545..2725aa9d411714ff62583f4b2bda200a6eff4b8b 100644 (file)
@@ -78,7 +78,7 @@ macro_rules! build_functor {
      $res_len:expr,
      [$($subfunctor:expr),*]) => ({
          build_functor!([$($dt($($value),*)),*],
-                        [$($res, )* FunctorElement::Cell(fixnum_as_cell!(Fixnum::build_with($e as i64)))],
+                        [$($res, )* FunctorElement::Cell(fixnum_as_cell!(/*FIXME this is not safe*/ unsafe{Fixnum::build_with_unchecked($e as i64)}))],
                         1 + $res_len,
                         [$($subfunctor),*])
     });
index 9f1efee7146ec0346b13fb88c2176cead5ef8d89..c23344bfc8a3c9ceb0513cf21c4927c63a0fc350 100644 (file)
@@ -1500,7 +1500,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
 
             self.state_stack.push(TokenOrRedirect::NumberFocus(
                 max_depth,
-                NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port as i64))),
+                NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port))),
                 None,
             ));
             self.state_stack.push(TokenOrRedirect::Comma);
@@ -1527,7 +1527,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
 
                 TokenOrRedirect::NumberFocus(
                     max_depth,
-                    NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx_ptr_p))),
+                    NumberFocus::Unfocused(Number::Fixnum(
+                        /* FIXME this is not safe */
+                        unsafe { Fixnum::build_with_unchecked(idx_ptr_p) },
+                    )),
                     None,
                 )
             };
index b9bdfc2814fbdd0ebc79fe64e04b3ef63c64a510..345533adc6c3c61100e29b3f04c2ddb88235a9b2 100644 (file)
@@ -1104,11 +1104,7 @@ pub(crate) fn constant_key_alternatives(constant: Literal) -> Option<Literal> {
         _ => return None,
     };
 
-    if let Ok(n) = n.try_into() {
-        Fixnum::build_with_checked(n).map(Literal::Fixnum).ok()
-    } else {
-        None
-    }
+    Fixnum::build_with_checked(n).map(Literal::Fixnum).ok()
 }
 
 #[derive(Debug)]
index 43bb37234e7bacc4c21410da980f59fe1f7450c3..d1667795cf2310ee716daa638704ad9cba3cd90b 100644 (file)
@@ -198,11 +198,10 @@ pub(crate) fn neg(n: Number, arena: &mut Arena) -> Number {
 pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number {
     match n {
         Number::Fixnum(n) => {
-            if let Some(n) = n.get_num().checked_abs() {
-                fixnum!(Number, n, arena)
+            if let Some(n) = n.checked_abs() {
+                Number::Fixnum(n)
             } else {
-                let arena_int = Integer::from(n.get_num());
-                Number::arena_from(arena_int.abs(), arena)
+                Number::arena_from(Integer::from(Fixnum::MAX + 1), arena)
             }
         }
         Number::Integer(n) => {
@@ -1105,7 +1104,7 @@ pub(crate) fn round(num: Number, arena: &mut Arena) -> Result<Number, MachineStu
 
 pub(crate) fn bitwise_complement(n1: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
     match n1 {
-        Number::Fixnum(n) => Ok(Number::Fixnum(Fixnum::build_with(!n.get_num()))),
+        Number::Fixnum(n) => Ok(Number::Fixnum(!n)),
         Number::Integer(n1) => Ok(Number::arena_from(Integer::from(!&*n1), arena)),
         _ => {
             let stub_gen = || {
index 34e4755d7df560ca00f98c02e76ad362ca54e97f..4aaf45ee815537de271aef670dcbc8a348f2140d 100644 (file)
@@ -120,9 +120,21 @@ impl MachineState {
             and_frame[i] = self.registers[i];
         }
 
-        and_frame[arity + 1] = fixnum_as_cell!(Fixnum::build_with(self.b0 as i64));
-        and_frame[arity + 2] = fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
-        and_frame[arity + 3] = fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64));
+        and_frame[arity + 1] =
+            fixnum_as_cell!(
+                /* FIXME this is not safe */
+                unsafe { Fixnum::build_with_unchecked(self.b0 as i64) }
+            );
+        and_frame[arity + 2] =
+            fixnum_as_cell!(
+                /* FIXME this is not safe */
+                unsafe { Fixnum::build_with_unchecked(self.num_of_args as i64) }
+            );
+        and_frame[arity + 3] =
+            fixnum_as_cell!(
+                /* FIXME this is not safe */
+                unsafe { Fixnum::build_with_unchecked(self.attr_var_init.cp as i64) }
+            );
 
         self.verify_attributes()?;
 
index 3a88221a97a92aa19fad780d8be3b0e183d9c0bf..20dfd8eecefa4a21319ddd60c6a8ae5dad4a2202 100644 (file)
@@ -1021,9 +1021,13 @@ impl Machine {
                                         match self.find_living_dynamic_else(p + next_i) {
                                             Some(_) => {
                                                 self.machine_st.registers
-                                                    [self.machine_st.num_of_args + 1] = fixnum_as_cell!(
-                                                    Fixnum::build_with(self.machine_st.cc as i64)
-                                                );
+                                                    [self.machine_st.num_of_args + 1] =
+                                                    fixnum_as_cell!(unsafe {
+                                                        /* FIXME this is not safe */
+                                                        Fixnum::build_with_unchecked(
+                                                            self.machine_st.cc as i64,
+                                                        )
+                                                    });
 
                                                 self.machine_st.num_of_args += 1;
                                                 self.try_me_else(next_i);
@@ -1042,10 +1046,11 @@ impl Machine {
                                             .prelude
                                             .num_cells;
 
-                                        self.machine_st.cc = cell_as_fixnum!(
+                                        self.machine_st.cc = unsafe {
                                             self.machine_st.stack
                                                 [stack_loc!(OrFrame, self.machine_st.b, n - 1)]
-                                        )
+                                            .to_fixnum_or_cut_point_unchecked()
+                                        }
                                         .get_num()
                                             as usize;
 
@@ -1095,7 +1100,12 @@ impl Machine {
                                             Some(_) => {
                                                 self.machine_st.registers
                                                     [self.machine_st.num_of_args + 1] = fixnum_as_cell!(
-                                                    Fixnum::build_with(self.machine_st.cc as i64)
+                                                    /* FIXME this is not safe */
+                                                    unsafe {
+                                                        Fixnum::build_with_unchecked(
+                                                            self.machine_st.cc as i64,
+                                                        )
+                                                    }
                                                 );
 
                                                 self.machine_st.num_of_args += 1;
@@ -1115,10 +1125,11 @@ impl Machine {
                                             .prelude
                                             .num_cells;
 
-                                        self.machine_st.cc = cell_as_fixnum!(
+                                        self.machine_st.cc = unsafe {
                                             self.machine_st.stack
                                                 [stack_loc!(OrFrame, self.machine_st.b, n - 1)]
-                                        )
+                                            .to_fixnum_or_cut_point_unchecked()
+                                        }
                                         .get_num()
                                             as usize;
 
@@ -1174,7 +1185,10 @@ impl Machine {
                     &Instruction::GetLevel(r) => {
                         let b0 = self.machine_st.b0;
 
-                        self.machine_st[r] = fixnum_as_cell!(Fixnum::as_cutpoint(b0 as i64));
+                        self.machine_st[r] = fixnum_as_cell!(
+                            /* FIXME this is not safe */
+                            unsafe { Fixnum::build_with_unchecked(b0 as i64) }.as_cutpoint()
+                        );
                         self.machine_st.p += 1;
                     }
                     &Instruction::GetPrevLevel(r) => {
@@ -1185,12 +1199,18 @@ impl Machine {
                             .prelude
                             .b;
 
-                        self.machine_st[r] = fixnum_as_cell!(Fixnum::as_cutpoint(prev_b as i64));
+                        self.machine_st[r] = fixnum_as_cell!(
+                            /* FIXME this is not safe */
+                            unsafe { Fixnum::build_with_unchecked(prev_b as i64) }.as_cutpoint()
+                        );
                         self.machine_st.p += 1;
                     }
                     &Instruction::GetCutPoint(r) => {
                         self.machine_st[r] =
-                            fixnum_as_cell!(Fixnum::as_cutpoint(self.machine_st.b as i64));
+                            fixnum_as_cell!(/* FIXME this is not safe */ unsafe {
+                                Fixnum::build_with_unchecked(self.machine_st.b as i64)
+                            }
+                            .as_cutpoint());
                         self.machine_st.p += 1;
                     }
                     &Instruction::Cut(r) => {
@@ -3150,10 +3170,14 @@ impl Machine {
                                                 match self.find_living_dynamic(oi, ii + 1) {
                                                     Some(_) => {
                                                         self.machine_st.registers
-                                                            [self.machine_st.num_of_args + 1] =
-                                                            fixnum_as_cell!(Fixnum::build_with(
-                                                                self.machine_st.cc as i64
-                                                            ));
+                                                            [self.machine_st.num_of_args + 1] = fixnum_as_cell!(
+                                                            /* FIXME this is not safe */
+                                                            unsafe {
+                                                                Fixnum::build_with_unchecked(
+                                                                    self.machine_st.cc as i64,
+                                                                )
+                                                            }
+                                                        );
 
                                                         self.machine_st.num_of_args += 1;
                                                         self.indexed_try(offset);
@@ -3175,10 +3199,11 @@ impl Machine {
                                                     .prelude
                                                     .num_cells;
 
-                                                self.machine_st.cc = cell_as_fixnum!(
+                                                self.machine_st.cc = unsafe {
                                                     self.machine_st.stack
                                                         [stack_loc!(OrFrame, b, n - 1)]
-                                                )
+                                                    .to_fixnum_or_cut_point_unchecked()
+                                                }
                                                 .get_num()
                                                     as usize;
 
@@ -5256,8 +5281,11 @@ impl Machine {
                                 .machine_st
                                 .store(self.machine_st.deref(self.machine_st.registers[5]));
 
-                            self.machine_st
-                                .unify_fixnum(Fixnum::build_with(n as i64), r);
+                            self.machine_st.unify_fixnum(
+                                /* FIXME this is not safe */
+                                unsafe { Fixnum::build_with_unchecked(n as i64) },
+                                r,
+                            );
                         }
 
                         self.machine_st.call_at_index(2, p);
@@ -5299,8 +5327,11 @@ impl Machine {
                                 .machine_st
                                 .store(self.machine_st.deref(self.machine_st.registers[5]));
 
-                            self.machine_st
-                                .unify_fixnum(Fixnum::build_with(n as i64), r);
+                            self.machine_st.unify_fixnum(
+                                /* FIXME this is not safe */
+                                unsafe { Fixnum::build_with_unchecked(n as i64) },
+                                r,
+                            );
                         }
 
                         self.machine_st.execute_at_index(2, p);
index 89b83ed3158f630fa9546022c1618506b0d3be88..c18eceda1b4c71c6c51447f82398a0676491f802 100644 (file)
@@ -2344,7 +2344,9 @@ impl Machine {
                             MetaSpec::Either => atom_as_cell!(atom!("?")),
                             MetaSpec::Colon => atom_as_cell!(atom!(":")),
                             MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
-                                fixnum_as_cell!(Fixnum::build_with(*arg_num as i64))
+                                fixnum_as_cell!(/* FIXME this is not safe */ unsafe {
+                                    Fixnum::build_with_unchecked(*arg_num as i64)
+                                })
                             }
                         });
                     }
index 941d9f4d86b01e8c10aa0620a700308ce4b5c913..e323648316e051b110c15687cfd5a2b4defff714 100644 (file)
@@ -1003,7 +1003,10 @@ impl MachineState {
         arity: HeapCellValue,
     ) -> (Atom, usize) {
         let name = cell_as_atom!(self.store(self.deref(name)));
-        let arity = cell_as_fixnum!(self.store(self.deref(arity)));
+        let arity = unsafe {
+            self.store(self.deref(arity))
+                .to_fixnum_or_cut_point_unchecked()
+        };
 
         (name, usize::try_from(arity.get_num()).unwrap())
     }
index 038a16d73e3982a8acd85ea31d6b6ab3b9355fef..b72b18d2bafdf19cf2c315e9fb046eb70bdde47d 100644 (file)
@@ -940,7 +940,7 @@ impl MachineState {
                                     /*
                                     if pstr_atom.len() > offset as usize {
                                         self.heap.push(pstr_offset_as_cell!(h));
-                                        self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset)));
+                                        self.heap.push(fixnum_as_cell!(Fixnum::build_with_unchecked(offset as i64)));
 
                                         unify_fn!(*self, pstr_loc_as_cell!(h_len), a3);
                                     } else {
@@ -973,13 +973,13 @@ impl MachineState {
                             if n == 1 {
                                 self.unify_char(c, self.store(self.deref(self.registers[3])));
                             } else if n == 2 {
-                                let offset = c.len_utf8() as i64;
+                                let offset = c.len_utf8();
                                 let h_len = self.heap.len();
 
-                                if cstr_atom.len() > offset as usize {
+                                if cstr_atom.len() > offset{
                                     self.heap.push(atom_as_cstr_cell!(cstr_atom));
                                     self.heap.push(pstr_offset_as_cell!(h_len));
-                                    self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset)));
+                                    self.heap.push(fixnum_as_cell!(Fixnum::build_with_unchecked(offset as i64)));
 
                                     unify_fn!(*self, pstr_loc_as_cell!(h_len+1), self.registers[3]);
                                 } else {
@@ -1027,7 +1027,11 @@ impl MachineState {
 
         if !self.fail {
             let a3 = self.store(self.deref(self.registers[3]));
-            self.unify_fixnum(Fixnum::build_with(arity as i64), a3);
+            self.unify_fixnum(
+                /* FIXME this is not safe */
+                unsafe { Fixnum::build_with_unchecked(arity as i64) },
+                a3,
+            );
         }
     }
 
index 8f70b96fa67f0e953986c95260d97f6f9dddc5f6..4c9873732a104f5899039a237ccbd683bfe529bb 100644 (file)
@@ -1161,8 +1161,10 @@ impl Machine {
                 let (idx, arity) = if self.machine_st.effective_block() > prev_block {
                     (r_c_w_h, 0)
                 } else {
-                    self.machine_st.registers[1] =
-                        fixnum_as_cell!(Fixnum::build_with(b_cutoff as i64));
+                    self.machine_st.registers[1] = fixnum_as_cell!(
+                        /* FIXME this is not safe */
+                        unsafe { Fixnum::build_with_unchecked(b_cutoff as i64) }
+                    );
 
                     (r_c_wo_h, 1)
                 };
index 6875edfbb91659e119417f7995bcf00eaf96432c..3bee79d4c5623a08578482694da7b15be3781cb6 100644 (file)
@@ -578,9 +578,11 @@ impl MachineState {
 
             while lh_offset + 4 < self.lifted_heap.cell_len() {
                 let cell_threshold =
-                    cell_as_fixnum!(self.lifted_heap[lh_offset + 3]).get_num() as usize;
+                    unsafe { self.lifted_heap[lh_offset + 3].to_fixnum_or_cut_point_unchecked() }
+                        .get_num() as usize;
                 let pstr_upper_threshold =
-                    cell_as_fixnum!(self.lifted_heap[lh_offset + 4]).get_num() as usize;
+                    unsafe { self.lifted_heap[lh_offset + 4].to_fixnum_or_cut_point_unchecked() }
+                        .get_num() as usize;
 
                 for idx in lh_offset..cell_threshold {
                     section.push_cell(self.lifted_heap[idx] + offset);
@@ -740,7 +742,11 @@ impl MachineState {
         // self.heap.pop_cell();
 
         let target_n = self.store(self.deref(self.registers[1]));
-        self.unify_fixnum(Fixnum::build_with(brent_st.num_steps() as i64), target_n);
+        self.unify_fixnum(
+            /* FIXME this is not safe */
+            unsafe { Fixnum::build_with_unchecked(brent_st.num_steps() as i64) },
+            target_n,
+        );
 
         if !self.fail {
             unify!(self, self.registers[4], self.heap[prev_hare]);
@@ -749,7 +755,10 @@ impl MachineState {
 
     fn finalize_skip_max_list(&mut self, n: i64, value: HeapCellValue) {
         let target_n = self.store(self.deref(self.registers[1]));
-        self.unify_fixnum(Fixnum::build_with(n), target_n);
+        self.unify_fixnum(
+            /* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked(n) },
+            target_n,
+        );
 
         if !self.fail {
             let xs = self.registers[4];
@@ -881,7 +890,11 @@ impl MachineState {
         let value = self.store(self.deref(value));
 
         self.block = self.b;
-        self.unify_fixnum(Fixnum::build_with(self.block as i64), value);
+        self.unify_fixnum(
+            /* FIXME this is not safe */
+            unsafe { Fixnum::build_with_unchecked(self.block as i64) },
+            value,
+        );
 
         self.block
     }
@@ -959,7 +972,7 @@ impl MachineState {
         let mut tokens = vec![];
 
         match lexer.next_number_token() {
-            Ok(token @ Token::Literal(Literal::Atom(atom!("-")) | Literal::Char('-'))) => {
+            Ok(token @ Token::Literal(Literal::Atom(atom!("-")))) => {
                 tokens.push(token);
 
                 if let Ok(token) = lexer.next_number_token() {
@@ -1051,7 +1064,10 @@ impl MachineState {
         for index in s + 2..s + 2 + num_cells {
             if let HeapCellValueTag::CutPoint = self.heap[index].get_tag() {
                 // adjust cut point to occur after call_continuation.
-                and_frame[index - (s + 1)] = fixnum_as_cell!(Fixnum::as_cutpoint(self.b as i64));
+                and_frame[index - (s + 1)] = fixnum_as_cell!(
+                    /* FIXME this is not safe */
+                    unsafe { Fixnum::build_with_unchecked(self.b as i64) }.as_cutpoint()
+                );
             } else {
                 and_frame[index - (s + 1)] = self.heap[index];
             }
@@ -2332,7 +2348,7 @@ impl Machine {
             (HeapCellValueTag::Char, c) => {
                 let h = self.machine_st.heap.len();
 
-                self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64)));
+                self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(u32::from(c))));
                 self.machine_st.heap.push(empty_list_as_cell!());
 
                 unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]);
@@ -2342,7 +2358,7 @@ impl Machine {
                 debug_assert_eq!(arity, 0);
 
                 let name = name.as_str();
-                let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
+                let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c)));
 
                 let list_cell = resource_error_call_result!(
                     self.machine_st,
@@ -2439,7 +2455,10 @@ impl Machine {
         );
 
         let a2 = self.deref_register(2);
-        self.machine_st.unify_fixnum(Fixnum::build_with(len), a2);
+        self.machine_st.unify_fixnum(
+            /* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked(len) },
+            a2,
+        );
     }
 
     #[inline(always)]
@@ -2593,7 +2612,7 @@ impl Machine {
                 Ok(Number::Integer(n)) => {
                     let result: Result<u8, _> = (&*n).try_into();
                     if let Ok(value) = result {
-                        fixnum_as_cell!(Fixnum::build_with(value as i64))
+                        fixnum_as_cell!(Fixnum::build_with(value))
                     } else {
                         let err = self.machine_st.type_error(ValidType::InByte, addr);
                         return Err(self.machine_st.error_form(err, stub_gen()));
@@ -2601,7 +2620,7 @@ impl Machine {
                 }
                 Ok(Number::Fixnum(n)) => {
                     if let Ok(nb) = u8::try_from(n.get_num()) {
-                        fixnum_as_cell!(Fixnum::build_with(nb as i64))
+                        fixnum_as_cell!(Fixnum::build_with(nb))
                     } else {
                         let err = self.machine_st.type_error(ValidType::InByte, addr);
                         return Err(self.machine_st.error_form(err, stub_gen()));
@@ -2617,8 +2636,7 @@ impl Machine {
         loop {
             match stream.peek_byte().map_err(|e| e.kind()) {
                 Ok(b) => {
-                    self.machine_st
-                        .unify_fixnum(Fixnum::build_with(b as i64), addr);
+                    self.machine_st.unify_fixnum(Fixnum::build_with(b), addr);
                     break;
                 }
                 Err(ErrorKind::PermissionDenied) => {
@@ -2783,10 +2801,8 @@ impl Machine {
                     Ok(Number::Integer(n)) => {
                         let n: u32 = (&*n).try_into().unwrap();
 
-                        let n = std::char::from_u32(n).map(|_| n);
-
-                        if let Some(n) = n {
-                            fixnum_as_cell!(Fixnum::build_with(n as i64))
+                        if std::char::from_u32(n).is_some() {
+                            fixnum_as_cell!(Fixnum::build_with(n))
                         } else {
                             let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
                             return Err(self.machine_st.error_form(err, stub_gen()));
@@ -2798,7 +2814,7 @@ impl Machine {
                             .and_then(|n| std::char::from_u32(n).map(|_| n));
 
                         if let Some(n) = n {
-                            fixnum_as_cell!(Fixnum::build_with(n as i64))
+                            fixnum_as_cell!(Fixnum::build_with(n))
                         } else {
                             let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
                             return Err(self.machine_st.error_form(err, stub_gen()));
@@ -2818,7 +2834,7 @@ impl Machine {
             match result.map(|result| result.map_err(|e| e.kind())) {
                 Some(Ok(c)) => {
                     self.machine_st
-                        .unify_fixnum(Fixnum::build_with(c as i64), addr);
+                        .unify_fixnum(Fixnum::build_with(u32::from(c)), addr);
                     break;
                 }
                 Some(Err(ErrorKind::PermissionDenied)) => {
@@ -2896,7 +2912,7 @@ impl Machine {
         let codes = string
             .trim()
             .chars()
-            .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
+            .map(|c| fixnum_as_cell!(Fixnum::build_with(u32::from(c))));
 
         let list_cell = step_or_resource_error!(
             self.machine_st,
@@ -2939,7 +2955,9 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn lifted_heap_length(&mut self) {
         let a1 = self.machine_st.registers[1];
-        let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.cell_len() as i64);
+        /* FIXME this is not safe */
+        let lh_len =
+            unsafe { Fixnum::build_with_unchecked(self.machine_st.lifted_heap.cell_len() as i64) };
 
         self.machine_st.unify_fixnum(lh_len, a1);
     }
@@ -3002,7 +3020,7 @@ impl Machine {
         );
 
         self.machine_st
-            .unify_fixnum(Fixnum::build_with(c as i64), a2);
+            .unify_fixnum(Fixnum::build_with(u32::from(c)), a2);
 
         Ok(())
     }
@@ -3132,7 +3150,7 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn check_cut_point(&mut self) {
         let addr = self.deref_register(1);
-        let old_b = cell_as_fixnum!(addr).get_num() as usize;
+        let old_b = unsafe { addr.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
 
         let prev_b = self
             .machine_st
@@ -3442,7 +3460,7 @@ impl Machine {
                     let n: Result<u8, _> = (&*n).try_into();
 
                     if let Ok(value) = n {
-                        fixnum_as_cell!(Fixnum::build_with(value as i64))
+                        fixnum_as_cell!(Fixnum::build_with(value))
                     } else {
                         let err = self.machine_st.type_error(ValidType::InByte, addr);
                         return Err(self.machine_st.error_form(err, stub_gen()));
@@ -3450,7 +3468,7 @@ impl Machine {
                 }
                 Ok(Number::Fixnum(n)) => {
                     if let Ok(nb) = u8::try_from(n.get_num()) {
-                        fixnum_as_cell!(Fixnum::build_with(nb as i64))
+                        fixnum_as_cell!(Fixnum::build_with(nb))
                     } else {
                         let err = self.machine_st.type_error(ValidType::InByte, addr);
                         return Err(self.machine_st.error_form(err, stub_gen()));
@@ -3467,8 +3485,7 @@ impl Machine {
 
         match stream.read(&mut b) {
             Ok(1) => {
-                self.machine_st
-                    .unify_fixnum(Fixnum::build_with(b[0] as i64), addr);
+                self.machine_st.unify_fixnum(Fixnum::build_with(b[0]), addr);
             }
             _ => {
                 stream.set_past_end_of_stream(true);
@@ -3693,7 +3710,7 @@ impl Machine {
                     let n = std::char::from_u32(n);
 
                     if let Some(n) = n {
-                        fixnum_as_cell!(Fixnum::build_with(n as i64))
+                        fixnum_as_cell!(Fixnum::build_with(u32::from(n)))
                     } else {
                         let err = self
                             .machine_st
@@ -3737,7 +3754,7 @@ impl Machine {
             match result {
                 Some(Ok(c)) => {
                     self.machine_st
-                        .unify_fixnum(Fixnum::build_with(c as i64), addr);
+                        .unify_fixnum(Fixnum::build_with(u32::from(c)), addr);
                     break;
                 }
                 _ => {
@@ -3916,7 +3933,8 @@ impl Machine {
 
     #[inline(always)]
     pub(crate) fn copy_to_lifted_heap(&mut self) {
-        let lh_offset = cell_as_fixnum!(self.deref_register(1)).get_num() as usize;
+        let lh_offset =
+            unsafe { self.deref_register(1).to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
         let copy_target = self.machine_st.registers[2];
         let FindallCopyInfo {
             offset: old_threshold,
@@ -3935,11 +3953,14 @@ impl Machine {
             self.machine_st.lifted_heap[idx] -= self.machine_st.heap.cell_len() + lh_offset;
         }
 
-        self.machine_st.lifted_heap[old_threshold + 1] =
-            fixnum_as_cell!(Fixnum::build_with(pstr_threshold as i64));
-        self.machine_st.lifted_heap[old_threshold + 2] = fixnum_as_cell!(Fixnum::build_with(
-            self.machine_st.lifted_heap.cell_len() as i64
-        ));
+        self.machine_st.lifted_heap[old_threshold + 1] = fixnum_as_cell!(
+            /* FIXME this is not safe */
+            unsafe { Fixnum::build_with_unchecked(pstr_threshold as i64) }
+        );
+        self.machine_st.lifted_heap[old_threshold + 2] =
+            fixnum_as_cell!(/* FIXME this is not safe */ unsafe {
+                Fixnum::build_with_unchecked(self.machine_st.lifted_heap.cell_len() as i64)
+            });
 
         let mut pstr_threshold = heap_index!(pstr_threshold);
 
@@ -3958,7 +3979,8 @@ impl Machine {
     pub(crate) fn lookup_db_ref(&mut self) {
         let module_name = self.deref_register(1);
         let name = cell_as_atom!(self.deref_register(2));
-        let arity = cell_as_fixnum!(self.deref_register(3)).get_num() as usize;
+        let arity =
+            unsafe { self.deref_register(3).to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
 
         let module_name = read_heap_cell!(module_name,
             (HeapCellValueTag::Atom, (module_name, _arity)) => {
@@ -4285,7 +4307,12 @@ impl Machine {
                     return;
                 }
                 let value = self.rng.gen_range(lower..upper);
-                Number::Fixnum(Fixnum::build_with(value))
+                // Safety:
+                // - lower and uper bounds are Fixnum values
+                // - value is inbetween lower and upper
+                // - fixnums value range has no gaps
+                // so value is also a valid Fixnum value
+                Number::Fixnum(unsafe { Fixnum::build_with_unchecked(value) })
             }
             (Ok(Number::Fixnum(lower)), Ok(Number::Integer(upper))) => {
                 let lower = Integer::from(lower);
@@ -4463,7 +4490,7 @@ impl Machine {
                         // status code
                         let status = resp.status().as_u16();
                         self.machine_st
-                            .unify_fixnum(Fixnum::build_with(status as i64), address_status);
+                            .unify_fixnum(Fixnum::build_with(status), address_status);
                         // headers
                         let mut headers: Vec<HeapCellValue> = vec![];
 
@@ -5010,9 +5037,12 @@ impl Machine {
                     {
                         Ok(result) => {
                             match result {
-                                Value::Int(n) => self
-                                    .machine_st
-                                    .unify_fixnum(Fixnum::build_with(n), return_value),
+                                Value::Int(n) => self.machine_st.unify_fixnum(
+                                    Fixnum::build_with_checked(n).unwrap_or_else(|_| {
+                                        todo!("handle integer values that don't fit in fixnum")
+                                    }),
+                                    return_value,
+                                ),
                                 Value::Float(n) => {
                                     let n = float_alloc!(n, self.machine_st.arena);
                                     self.machine_st.unify_f64(n, return_value)
@@ -5060,7 +5090,16 @@ impl Machine {
 
         for val in args {
             expanded_args.push(match val {
-                Value::Int(n) => fixnum_as_cell!(Fixnum::build_with(n)),
+                Value::Int(n) => {
+                    if let Ok(fixnum) = Fixnum::build_with_checked(n) {
+                        fixnum_as_cell!(fixnum)
+                    } else {
+                        integer_as_cell!(Number::Integer(arena_alloc!(
+                            Integer::from(n),
+                            &mut self.machine_st.arena
+                        )))
+                    }
+                }
                 Value::Float(n) => HeapCellValue::from(float_alloc!(n, self.machine_st.arena)),
                 Value::CString(cstr) => atom_as_cell!(AtomTable::build_with(
                     &self.machine_st.atom_tbl,
@@ -5413,7 +5452,11 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn get_attr_var_queue_delimiter(&mut self) {
         let addr = self.deref_register(1);
-        let value = Fixnum::build_with(self.machine_st.attr_var_init.attr_var_queue.len() as i64);
+
+        /* FIXME this is not safe */
+        let value = unsafe {
+            Fixnum::build_with_unchecked(self.machine_st.attr_var_init.attr_var_queue.len() as i64)
+        };
 
         self.machine_st.unify_fixnum(value, addr);
     }
@@ -5682,7 +5725,7 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn get_continuation_chunk(&mut self) {
         let e = self.deref_register(1);
-        let e = cell_as_fixnum!(e).get_num() as usize;
+        let e = unsafe { e.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
         let h = self.machine_st.heap.cell_len();
 
         let p_functor_cell = self.deref_register(2);
@@ -5736,8 +5779,12 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn get_lifted_heap_from_offset_diff(&mut self) {
         let lh_offset = self.machine_st.registers[1];
-        let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset)))
-            .get_num() as usize;
+        let lh_offset = unsafe {
+            self.machine_st
+                .store(self.machine_st.deref(lh_offset))
+                .to_fixnum_or_cut_point_unchecked()
+        }
+        .get_num() as usize;
 
         if lh_offset >= self.machine_st.lifted_heap.cell_len() {
             let solutions = self.machine_st.registers[2];
@@ -5765,8 +5812,12 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn get_lifted_heap_from_offset(&mut self) {
         let lh_offset = self.machine_st.registers[1];
-        let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset)))
-            .get_num() as usize;
+        let lh_offset = unsafe {
+            self.machine_st
+                .store(self.machine_st.deref(lh_offset))
+                .to_fixnum_or_cut_point_unchecked()
+        }
+        .get_num() as usize;
 
         if lh_offset >= self.machine_st.lifted_heap.cell_len() {
             let solutions = self.machine_st.registers[2];
@@ -5888,7 +5939,7 @@ impl Machine {
             }
         };
 
-        let bp = cell_as_fixnum!(a1).get_num() as usize;
+        let bp = unsafe { a1.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
         let a3 = self.deref_register(3);
 
         let count = self.machine_st.cwil.add_limit(n, bp).clone();
@@ -5899,9 +5950,11 @@ impl Machine {
 
     #[inline(always)]
     pub(crate) fn inference_count(&mut self, count_var: HeapCellValue, count: Integer) {
-        if let Ok(value) = <&Integer as TryInto<i64>>::try_into(&count) {
-            self.machine_st
-                .unify_fixnum(Fixnum::build_with(value), count_var);
+        if let Some(value) = <&Integer as TryInto<i64>>::try_into(&count)
+            .ok()
+            .and_then(|i| Fixnum::build_with_checked(i).ok())
+        {
+            self.machine_st.unify_fixnum(value, count_var);
         } else {
             let count = arena_alloc!(count, &mut self.machine_st.arena);
             self.machine_st.unify_big_int(count, count_var);
@@ -6028,7 +6081,8 @@ impl Machine {
 
     #[inline(always)]
     pub(crate) fn remove_call_policy_check(&mut self) {
-        let bp = cell_as_fixnum!(self.deref_register(1)).get_num() as usize;
+        let bp =
+            unsafe { self.deref_register(1).to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
 
         if bp == self.machine_st.b && self.machine_st.cwil.is_empty() {
             self.machine_st.cwil.reset();
@@ -6040,12 +6094,10 @@ impl Machine {
         let a1 = self.deref_register(1);
         let a2 = self.deref_register(2);
 
-        let block = cell_as_fixnum!(a1).get_num() as usize;
+        let block = unsafe { a1.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
         let count = self.machine_st.cwil.remove_limit(block).clone();
-        let result = count.clone().try_into();
-
-        if let Ok(value) = result {
-            self.machine_st.unify_fixnum(Fixnum::build_with(value), a2);
+        if let Ok(value) = Fixnum::build_with_checked(&count) {
+            self.machine_st.unify_fixnum(value, a2);
         } else {
             let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
             self.machine_st.unify_big_int(count, a2);
@@ -6063,18 +6115,23 @@ impl Machine {
             self.machine_st.registers[i] = self.machine_st.stack[stack_loc!(AndFrame, e, i)];
         }
 
-        self.machine_st.b0 = cell_as_fixnum!(
+        self.machine_st.b0 = unsafe {
             self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 2)]
-        )
+                .to_fixnum_or_cut_point_unchecked()
+        }
         .get_num() as usize;
 
-        self.machine_st.num_of_args = cell_as_fixnum!(
+        self.machine_st.num_of_args = unsafe {
             self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 1)]
-        )
+                .to_fixnum_or_cut_point_unchecked()
+        }
         .get_num() as usize;
 
-        let p = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)]).get_num()
-            as usize;
+        let p = unsafe {
+            self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)]
+                .to_fixnum_or_cut_point_unchecked()
+        }
+        .get_num() as usize;
 
         self.machine_st.deallocate();
         self.machine_st.p = p;
@@ -6191,7 +6248,7 @@ impl Machine {
         let a1 = self.deref_register(1);
         let a2 = self.deref_register(2);
 
-        let bp = cell_as_fixnum!(a2).get_num() as usize;
+        let bp = unsafe { a2.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
         let prev_b = self
             .machine_st
             .stack
@@ -6214,7 +6271,7 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn clean_up_block(&mut self) {
         let nb = self.deref_register(1);
-        let nb = cell_as_fixnum!(nb).get_num() as usize;
+        let nb = unsafe { nb.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
 
         let b = self.machine_st.b;
 
@@ -6270,7 +6327,9 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn get_current_block(&mut self) {
         let addr = self.machine_st.registers[1];
-        let block = Fixnum::build_with(self.machine_st.block as i64);
+
+        /* FIXME this is not safe */
+        let block = unsafe { Fixnum::build_with_unchecked(self.machine_st.block as i64) };
 
         self.machine_st.unify_fixnum(block, addr);
     }
@@ -6278,21 +6337,27 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn get_current_scc_block(&mut self) {
         let addr = self.machine_st.registers[1];
-        let block = Fixnum::build_with(self.machine_st.scc_block as i64);
+
+        /* FIXME this is not safe */
+        let block = unsafe { Fixnum::build_with_unchecked(self.machine_st.scc_block as i64) };
 
         self.machine_st.unify_fixnum(block, addr);
     }
 
     #[inline(always)]
     pub(crate) fn get_b_value(&mut self) {
-        let n = Fixnum::as_cutpoint(i64::try_from(self.machine_st.b).unwrap());
+        /* FIXME this is not safe */
+        let n = unsafe { Fixnum::build_with_unchecked(i64::try_from(self.machine_st.b).unwrap()) }
+            .as_cutpoint();
         self.machine_st
             .unify_fixnum(n, self.machine_st.registers[1]);
     }
 
     #[inline(always)]
     pub(crate) fn get_cut_point(&mut self) {
-        let n = Fixnum::as_cutpoint(i64::try_from(self.machine_st.b0).unwrap());
+        /* FIXME this is not safe */
+        let n = unsafe { Fixnum::build_with_unchecked(i64::try_from(self.machine_st.b0).unwrap()) }
+            .as_cutpoint();
         self.machine_st
             .unify_fixnum(n, self.machine_st.registers[1]);
     }
@@ -6314,7 +6379,7 @@ impl Machine {
             let cp = and_frame.prelude.cp - 1;
 
             let e = and_frame.prelude.e;
-            let e = Fixnum::build_with(i64::try_from(e).unwrap());
+            let e = Fixnum::build_with_checked(e).unwrap();
 
             machine_st.unify_fixnum(e, machine_st.registers[2]);
 
@@ -6363,7 +6428,7 @@ impl Machine {
                     writer(&mut self.machine_st.heap)
                 );
 
-                let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap());
+                let e = Fixnum::build_with_checked(and_frame.prelude.e).unwrap();
                 self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
 
                 if !self.machine_st.fail {
@@ -6787,10 +6852,7 @@ impl Machine {
                     let port = tcp_listener.local_addr().map(|addr| addr.port()).ok();
 
                     if let Some(port) = port {
-                        (
-                            arena_alloc!(tcp_listener, &mut self.machine_st.arena),
-                            port as usize,
-                        )
+                        (arena_alloc!(tcp_listener, &mut self.machine_st.arena), port)
                     } else {
                         self.machine_st.fail = true;
                         return Ok(());
@@ -6817,7 +6879,7 @@ impl Machine {
 
         if had_zero_port {
             self.machine_st
-                .unify_fixnum(Fixnum::build_with(port as i64), self.deref_register(2));
+                .unify_fixnum(Fixnum::build_with(port), self.deref_register(2));
         }
 
         Ok(())
@@ -7266,7 +7328,8 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn term_variables_under_max_depth(&mut self) {
         // Term, MaxDepth, VarList
-        let max_depth = cell_as_fixnum!(self.deref_register(2)).get_num() as usize;
+        let max_depth =
+            unsafe { self.deref_register(2).to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
 
         self.machine_st.term_variables_under_max_depth(
             self.machine_st.registers[1],
@@ -7278,7 +7341,7 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn truncate_lifted_heap_to(&mut self) {
         let a1 = self.deref_register(1);
-        let lh_offset = cell_as_fixnum!(a1).get_num() as usize;
+        let lh_offset = unsafe { a1.to_fixnum_or_cut_point_unchecked() }.get_num() as usize;
 
         self.machine_st.lifted_heap.truncate(lh_offset);
     }
@@ -7561,7 +7624,7 @@ impl Machine {
             }
         }
 
-        let byte = Fixnum::build_with(bytes[0] as i64);
+        let byte = Fixnum::build_with(bytes[0]);
         self.machine_st.unify_fixnum(byte, arg);
     }
 
@@ -7587,7 +7650,7 @@ impl Machine {
                         context_len,
                         finalized_context
                             .iter()
-                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
                     )
                 )
             }
@@ -7604,7 +7667,7 @@ impl Machine {
                         context_len,
                         finalized_context
                             .iter()
-                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
                     )
                 )
             }
@@ -7621,7 +7684,7 @@ impl Machine {
                         context_len,
                         finalized_context
                             .iter()
-                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
                     )
                 )
             }
@@ -7638,7 +7701,7 @@ impl Machine {
                         context_len,
                         finalized_context
                             .iter()
-                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))),
                     )
                 )
             }
@@ -7655,7 +7718,7 @@ impl Machine {
                         context_len,
                         finalized_context
                             .iter()
-                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))),
                     )
                 )
             }
@@ -7672,7 +7735,7 @@ impl Machine {
                         context_len,
                         finalized_context
                             .iter()
-                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))),
                     )
                 )
             }
@@ -7689,7 +7752,7 @@ impl Machine {
                         context_len,
                         finalized_context
                             .iter()
-                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
                     )
                 )
             }
@@ -7714,7 +7777,7 @@ impl Machine {
                         ints.as_ref().len(),
                         ints.as_ref()
                             .iter()
-                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
                     )
                 )
             }
@@ -7754,7 +7817,7 @@ impl Machine {
                 tag.as_ref().len(),
                 tag.as_ref()
                     .iter()
-                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
             )
         );
 
@@ -7825,7 +7888,7 @@ impl Machine {
                     bytes.len(),
                     bytes
                         .iter()
-                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
                 )
             )
         };
@@ -7881,7 +7944,7 @@ impl Machine {
                     bytes.len(),
                     bytes
                         .iter()
-                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
                 )
             )
         };
@@ -7928,7 +7991,7 @@ impl Machine {
                 tag.as_ref().len(),
                 tag.as_ref()
                     .iter()
-                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
             )
         );
 
@@ -8068,7 +8131,7 @@ impl Machine {
                 sig.as_ref().len(),
                 sig.as_ref()
                     .iter()
-                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
             )
         );
 
@@ -8482,7 +8545,7 @@ impl Machine {
         let number = self.deref_register(1);
         let pop_count = integer_as_cell!(match Number::try_from(number) {
             Ok(Number::Fixnum(n)) => {
-                Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64))
+                Number::Fixnum(Fixnum::build_with(n.get_num().count_ones()))
             }
             Ok(Number::Integer(n)) => {
                 let value: usize = if n.sign() == Sign::Positive {
index 5347af3c2679d346b6aa8d2c73128f0ced902d2e..29e3369f8afebe46e2b956367a609aeeb8203fd8 100644 (file)
@@ -14,12 +14,6 @@ macro_rules! fixnum_as_cell {
     };
 }
 
-macro_rules! cell_as_fixnum {
-    ($cell:expr) => {
-        Fixnum::from_bytes($cell.into_bytes())
-    };
-}
-
 macro_rules! integer_as_cell {
     ($n: expr) => {{
         match $n {
index 9f1d7382c6f51fcd3c78e9a6f1e63cc9000fc59b..d67d97ced34af6ef22dd147d9978f927348a9ff4 100644 (file)
@@ -11,7 +11,10 @@ use std::cell::{Cell, Ref, RefCell, RefMut};
 use std::fmt;
 use std::hash::Hash;
 use std::hash::Hasher;
+use std::i64;
 use std::io::{Error as IOError, ErrorKind};
+use std::ops::Not;
+use std::ops::RangeInclusive;
 use std::ops::{Deref, Neg};
 use std::rc::Rc;
 use std::sync::Arc;
@@ -550,9 +553,90 @@ pub struct Fixnum {
     tag: B6,
 }
 
+mod private {
+    use dashu::Integer;
+
+    pub(crate) trait FitsInFixnumSeal {}
+    pub(crate) trait MightNotFitInFixnumSeal {}
+
+    macro_rules! impl_fits_in_fixnum {
+        ($t:ty) => {
+            impl $crate::parser::ast::private::FitsInFixnumSeal for $t {}
+
+            impl $crate::parser::ast::FitsInFixnum for $t {
+                fn into_i56(self) -> i64 {
+                    self.into()
+                }
+            }
+        };
+    }
+
+    impl_fits_in_fixnum!(u8);
+    impl_fits_in_fixnum!(i8);
+    impl_fits_in_fixnum!(u16);
+    impl_fits_in_fixnum!(i16);
+    impl_fits_in_fixnum!(u32);
+    impl_fits_in_fixnum!(i32);
+
+    impl FitsInFixnumSeal for char {}
+    impl super::FitsInFixnum for char {
+        fn into_i56(self) -> i64 {
+            u32::from(self) as i64
+        }
+    }
+
+    impl MightNotFitInFixnumSeal for i64 {}
+    impl MightNotFitInFixnumSeal for &Integer {}
+    impl MightNotFitInFixnumSeal for Integer {}
+    impl MightNotFitInFixnumSeal for usize {}
+}
+
+#[allow(private_bounds)]
+pub trait FitsInFixnum: private::FitsInFixnumSeal {
+    fn into_i56(self) -> i64;
+}
+
+#[allow(private_bounds)]
+pub trait MightNotFitInFixnum: private::MightNotFitInFixnumSeal {
+    fn try_into_i56(self) -> Option<i64>;
+}
+
+impl<T> MightNotFitInFixnum for T
+where
+    T: private::MightNotFitInFixnumSeal + TryInto<i64>,
+{
+    fn try_into_i56(self) -> Option<i64> {
+        let val = self.try_into().ok()?;
+        if Fixnum::RANGE.contains(&val) {
+            Some(val)
+        } else {
+            None
+        }
+    }
+}
+
 impl Fixnum {
+    pub(crate) const MIN: i64 = -(1 << 55);
+    pub(crate) const MAX: i64 = (1 << 55) - 1;
+    const RANGE: RangeInclusive<i64> = Self::MIN..=Self::MAX;
+
+    // if you have a type that is not guaranteed to fit use `Fixnum::build_with_checked` or `Fixnum::build_with_unchecked` instead
+    #[inline]
+    pub fn build_with(num: impl FitsInFixnum) -> Self {
+        // Safety: FitsInFixnum is only implemented by types that only have valid values
+        // and FitsInFixnumSeal ensures no one outside this crate can violate that
+        unsafe { Self::build_with_unchecked(num.into_i56()) }
+    }
+
     #[inline]
-    pub fn build_with(num: i64) -> Self {
+    pub unsafe fn build_with_unchecked(num: i64) -> Self {
+        debug_assert!(
+            Self::RANGE.contains(&num),
+            "{num} should be in the range {}..={}",
+            Self::MIN,
+            Self::MAX
+        );
+
         Fixnum::new()
             .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
             .with_tag(HeapCellValueTag::Fixnum as u8)
@@ -561,12 +645,8 @@ impl Fixnum {
     }
 
     #[inline]
-    pub fn as_cutpoint(num: i64) -> Self {
-        Fixnum::new()
-            .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
-            .with_tag(HeapCellValueTag::CutPoint as u8)
-            .with_m(false)
-            .with_f(false)
+    pub fn as_cutpoint(self) -> Self {
+        self.with_tag(HeapCellValueTag::CutPoint as u8)
     }
 
     #[inline]
@@ -575,20 +655,14 @@ impl Fixnum {
         HeapCellValueTag::from_bytes(self.tag()).unwrap()
     }
 
+    // if you have a type that is guaranteed to fit use `Fixnum::build_with` instead
     #[inline]
-    pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> {
-        const UPPER_BOUND: i64 = (1 << 55) - 1;
-        const LOWER_BOUND: i64 = -(1 << 55);
-
-        if (LOWER_BOUND..=UPPER_BOUND).contains(&num) {
-            Ok(Fixnum::new()
-                .with_m(false)
-                .with_f(false)
-                .with_tag(HeapCellValueTag::Fixnum as u8)
-                .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1)))
-        } else {
-            Err(OutOfBounds {})
-        }
+    pub fn build_with_checked(num: impl MightNotFitInFixnum) -> Result<Self, OutOfBounds> {
+        Ok(unsafe {
+            // Safety: all MightNotFitInFixnum impls return None when the value is out-of-bounds
+            // and MightNotFitInFixnumSeal ensures no one outside this crate can violate that
+            Self::build_with_unchecked(num.try_into_i56().ok_or(OutOfBounds {})?)
+        })
     }
 
     #[inline]
@@ -598,6 +672,10 @@ impl Fixnum {
         debug_assert!(!overflowed);
         n
     }
+
+    pub fn checked_abs(self) -> Option<Self> {
+        Self::build_with_checked(self.get_num().abs()).ok()
+    }
 }
 
 impl Neg for Fixnum {
@@ -605,7 +683,18 @@ impl Neg for Fixnum {
 
     #[inline]
     fn neg(self) -> Self::Output {
-        Fixnum::build_with(-self.get_num())
+        // Safety: the truncating behaviour is correct
+        unsafe { Self::build_with_unchecked(-self.get_num()) }
+    }
+}
+
+impl Not for Fixnum {
+    type Output = Self;
+
+    #[inline]
+    fn not(self) -> Self::Output {
+        // Safety: the truncating behaviour is correct
+        unsafe { Self::build_with_unchecked(!self.get_num()) }
     }
 }
 
index 95162196672c73f6dd85d839245ffd6c48059c87..a1b8cb4a4e63410e21bd6dd07987558afece918e 100644 (file)
@@ -1,9 +1,7 @@
-use crate::arena::F64Ptr;
-use crate::arena::TypedArenaPtr;
-
 use crate::arena::*;
 use crate::atom_table::*;
 pub use crate::machine::machine_state::*;
+use crate::offset_table::F64Ptr;
 use crate::parser::ast::*;
 use crate::parser::char_reader::*;
 use crate::parser::dashu::Integer;
@@ -662,15 +660,15 @@ impl<'a, R: CharRead> Lexer<'a, R> {
         }
     }
 
-    fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> {
+    fn vacate_with_float(&mut self, mut token: String) -> Result<Number, ParserError> {
         self.return_char(token.pop().unwrap());
 
         let n = parse_float_lossy(&token)?;
 
-        Ok(Token::Literal(Literal::from(float_alloc!(
+        Ok(Number::Float(float_alloc!(
             n,
             self.machine_st.arena
-        ))))
+        )))
     }
 
     fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> {
@@ -797,7 +795,8 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                         }
 
                         let n = parse_float_lossy(&token)?;
-                        Ok(Token::Literal(Literal::from(float_alloc!(
+
+                        Ok(NumberToken::Number(Number::Float(float_alloc!(
                             n,
                             self.machine_st.arena
                         ))))
@@ -806,7 +805,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                     }
                 } else {
                     let n = parse_float_lossy(&token)?;
-                    Ok(Token::Literal(Literal::from(float_alloc!(
+                    Ok(NumberToken::Number(Number::Float(float_alloc!(
                         n,
                         self.machine_st.arena
                     ))))
@@ -859,7 +858,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                 }
 
                 self.get_single_quoted_char()
-                    .map(|c| NumberToken::Number(Number::Fixnum(Fixnum::build_with(c as i64))))
+                    .map(|c| NumberToken::Number(Number::Fixnum(Fixnum::build_with(c))))
                     .or_else(|err| {
                         match err {
                             ParserError::UnexpectedChar('\'', ..) => {}
index b39fc557fcd574bdd6ac553d42831dfb318c6104..10702109ca31d45adb739bdb180c682ceef3327f 100644 (file)
@@ -389,7 +389,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
                         Cell::default(),
                         Box::new(Term::Literal(
                             Cell::default(),
-                            Literal::Fixnum(Fixnum::build_with(c as i64)),
+                            Literal::Fixnum(Fixnum::build_with(c)),
                         )),
                         Box::new(list),
                     );
@@ -963,12 +963,12 @@ impl<'a, R: CharRead> Parser<'a, R> {
             Token::Literal(Literal::Rational(n)) => {
                 self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r))
             }
-            Token::Literal(Literal::Float(n)) if n.as_ptr().is_infinite() => {
+           Token::Literal(Literal::Float(n)) if n.as_ptr().is_infinite() => {
                return Err(ParserError::InfiniteFloat(
                    self.lexer.line_num,
                    self.lexer.col_num,
                ));
-            }
+           }
             Token::Literal(Literal::Float(n)) => self.negate_number(
                 **n.as_ptr(),
                 |n, _| -n,
index e6dda7d98375ce49d3a3ff6ef59d0d7cff586be0..b47659309c2879b108709392122629c368693d1f 100644 (file)
@@ -588,6 +588,16 @@ impl HeapCellValue {
         }
     }
 
+    // FIXME: someone that knows this better should check if this can be split into `to_fixnum_unchecked` and `to_cut_point_unchecked` assuming thats always unambigusly knowable
+    #[inline]
+    pub unsafe fn to_fixnum_or_cut_point_unchecked(self) -> Fixnum {
+        debug_assert!(matches!(
+            self.get_tag(),
+            HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint
+        ));
+        Fixnum::from_bytes(self.into_bytes())
+    }
+
     #[inline]
     pub fn from_ptr_addr(ptr_bytes: usize) -> Self {
         HeapCellValue::from_bytes((ptr_bytes as u64).to_ne_bytes())