Commit 57f6d1addfc4f2bc7285a69dff64c48971fa03aa

Thomas de Grivel 2024-08-05T13:06:41

wip integer_reduce

diff --git a/.ikc3_history b/.ikc3_history
index 5b705fa..5625af5 100644
--- a/.ikc3_history
+++ b/.ikc3_history
@@ -1,6 +1,3 @@
-type(-256 * 256 - 1)
-type(-256 * 256 + 1)
--256 * 256 + 1
 type(-65536 * 65536 + 1)
 type(-65536 * 65536 - 1)
 type(-65536 * 65536 + 1)
@@ -97,3 +94,6 @@ Struct.offset(%HTTP.Response{}, :body)
 quote "a#{a}"
 "a#{a}"
 "a#{:a}"
+quote "a#{:a}"
+quote "a#{%KC3.Operator{}}"
+quote "a#{%KC3.Operator{sym: :-}}"
diff --git a/libkc3/integer.c b/libkc3/integer.c
index 0021305..c0a629c 100644
--- a/libkc3/integer.c
+++ b/libkc3/integer.c
@@ -18,6 +18,7 @@
 #include "integer.h"
 #include "sym.h"
 #include "tag.h"
+#include "tag_init.h"
 #include "tag_type.h"
 #include "ratio.h"
 
@@ -520,6 +521,49 @@ s_integer * integer_pow (const s_integer *a, const s_integer *b,
   return dest;
 }
 
+s_tag * integer_reduce (const s_integer *i, s_tag *dest)
+{
+  static s_integer s8_min = {0};
+  static s_integer s16_min = {0};
+  static s_integer s32_min = {0};
+  static s_integer s64_min = {0};
+  static s_integer u8_max = {0};
+  static s_integer u16_max = {0};
+  static s_integer u32_max = {0};
+  static s_integer u64_max = {0};
+  static s_integer zero = {0};
+  if (s8_min.mp_int.sign != MP_NEG) {
+    integer_init_s8(&s8_min, S8_MIN);
+    integer_init_s16(&s16_min, S16_MIN);
+    integer_init_s32(&s32_min, S32_MIN);
+    integer_init_s64(&s64_min, S64_MIN);
+    integer_init_u8(&u8_max, U8_MAX);
+    integer_init_u16(&u16_max, U16_MAX);
+    integer_init_u32(&u32_max, U32_MAX);
+    integer_init_u64(&u64_max, U64_MAX);
+    integer_init_u8(&zero, 0);
+  }
+  if (compare_integer(i, &u64_max) > 0)
+    return tag_init_integer_copy(dest, i);
+  if (compare_integer(i, &u32_max) > 0)
+    return tag_init_u64(dest, integer_to_u64(i));
+  if (compare_integer(i, &u16_max) > 0)
+    return tag_init_u32(dest, integer_to_u32(i));
+  if (compare_integer(i, &u8_max) > 0)
+    return tag_init_u16(dest, integer_to_u16(i));
+  if (compare_integer(i, &zero) >= 0)
+    return tag_init_u8(dest, integer_to_u8(i));
+  if (compare_integer(i, &s8_min) >= 0)
+    return tag_init_s8(dest, integer_to_s8(i));
+  if (compare_integer(i, &s16_min) >= 0)
+    return tag_init_s16(dest, integer_to_s16(i));
+  if (compare_integer(i, &s32_min) >= 0)
+    return tag_init_s32(dest, integer_to_s32(i));
+  if (compare_integer(i, &s64_min) >= 0)
+    return tag_init_s64(dest, integer_to_s64(i));
+  return tag_init_integer_copy(dest, i);
+}
+
 s_integer * integer_set_f32 (s_integer *a, f32 x)
 {
   sw r;
diff --git a/libkc3/integer.h b/libkc3/integer.h
index e4d7407..5d6bd9c 100644
--- a/libkc3/integer.h
+++ b/libkc3/integer.h
@@ -94,23 +94,24 @@ s_integer * integer_new (void);
 s_integer * integer_new_copy (const s_integer *a);
 
 /* Observers */
-uw   integer_bits (const s_integer *i);
-uw   integer_bytes (const s_integer *i);
-bool integer_is_negative (const s_integer *i);
-bool integer_is_positive (const s_integer *i);
-bool integer_is_zero (const s_integer *i);
-f32  integer_to_f32 (const s_integer *i);
-f64  integer_to_f64 (const s_integer *i);
-f128 integer_to_f128 (const s_integer *i);
-s8   integer_to_s8 (const s_integer *i);
-s16  integer_to_s16 (const s_integer *i);
-s32  integer_to_s32 (const s_integer *i);
-s64  integer_to_s64 (const s_integer *i);
-sw   integer_to_sw (const s_integer *i);
-u8   integer_to_u8 (const s_integer *i);
-u16  integer_to_u16 (const s_integer *i);
-u32  integer_to_u32 (const s_integer *i);
-u64  integer_to_u64 (const s_integer *i);
-uw   integer_to_uw (const s_integer *i);
+uw      integer_bits (const s_integer *i);
+uw      integer_bytes (const s_integer *i);
+bool    integer_is_negative (const s_integer *i);
+bool    integer_is_positive (const s_integer *i);
+bool    integer_is_zero (const s_integer *i);
+s_tag * integer_reduce (const s_integer *i, s_tag *dest);
+f32     integer_to_f32 (const s_integer *i);
+f64     integer_to_f64 (const s_integer *i);
+f128    integer_to_f128 (const s_integer *i);
+s8      integer_to_s8 (const s_integer *i);
+s16     integer_to_s16 (const s_integer *i);
+s32     integer_to_s32 (const s_integer *i);
+s64     integer_to_s64 (const s_integer *i);
+sw      integer_to_sw (const s_integer *i);
+u8      integer_to_u8 (const s_integer *i);
+u16     integer_to_u16 (const s_integer *i);
+u32     integer_to_u32 (const s_integer *i);
+u64     integer_to_u64 (const s_integer *i);
+uw      integer_to_uw (const s_integer *i);
 
 #endif /* LIBKC3_INTEGER_H */
diff --git a/libkc3/tag.c b/libkc3/tag.c
index 00484f8..7f82832 100644
--- a/libkc3/tag.c
+++ b/libkc3/tag.c
@@ -541,34 +541,93 @@ s_tag * tag_init_time (s_tag *tag)
 
 s_tag * tag_integer_reduce (s_tag *tag)
 {
-  uw bytes;
-  e_bool negative;
+  s_integer *i;
+  s_integer j;
+  static s_integer s8_min = {0};
+  static s_integer s16_min = {0};
+  static s_integer s32_min = {0};
+  static s_integer s64_min = {0};
+  static s_integer u8_max = {0};
+  static s_integer u16_max = {0};
+  static s_integer u32_max = {0};
+  static s_integer u64_max = {0};
+  static s_integer zero = {0};
   assert(tag);
+  if (s8_min.mp_int.sign != MP_NEG) {
+    integer_init_s8(&s8_min, S8_MIN);
+    integer_init_s16(&s16_min, S16_MIN);
+    integer_init_s32(&s32_min, S32_MIN);
+    integer_init_s64(&s64_min, S64_MIN);
+    integer_init_u8(&u8_max, U8_MAX);
+    integer_init_u16(&u16_max, U16_MAX);
+    integer_init_u32(&u32_max, U32_MAX);
+    integer_init_u64(&u64_max, U64_MAX);
+    integer_init_u8(&zero, 0);
+  }
   switch (tag->type) {
   case TAG_INTEGER:
-    bytes = integer_bytes(&tag->data.integer);
-    if (bytes > 8)
-      break;
-    negative = integer_is_negative(&tag->data.integer);
-    if (bytes > 4) {
-      if (negative)
-        return tag_cast_integer_to_s64(tag);
-      return tag_cast_integer_to_u64(tag);
-    }
-    if (bytes > 2) {
-      if (negative)
-        return tag_cast_integer_to_s32(tag);
-      return tag_cast_integer_to_u32(tag);
-    }
-    if (bytes > 1) {
-      if (negative)
-        return tag_cast_integer_to_s16(tag);
-      return tag_cast_integer_to_u16(tag);
-    }
-    if (negative)
-      return tag_cast_integer_to_s8(tag);
-    return tag_cast_integer_to_u8(tag);
-  default: ;
+    i = &tag->data.integer;
+    if (compare_integer(i, &u64_max) > 0)
+      return tag;
+    if (compare_integer(i, &u32_max) > 0)
+      return tag_init_u64(tag, integer_to_u64(i));
+    if (compare_integer(i, &u16_max) > 0)
+      return tag_init_u32(tag, integer_to_u32(i));
+    if (compare_integer(i, &u8_max) > 0)
+      return tag_init_u16(tag, integer_to_u16(i));
+    if (compare_integer(i, &zero) >= 0)
+      return tag_init_u8(tag, integer_to_u8(i));
+    if (compare_integer(i, &s8_min) >= 0)
+      return tag_init_s8(tag, integer_to_s8(i));
+    if (compare_integer(i, &s16_min) >= 0)
+      return tag_init_s16(tag, integer_to_s16(i));
+    if (compare_integer(i, &s32_min) >= 0)
+      return tag_init_s32(tag, integer_to_s32(i));
+    if (compare_integer(i, &s64_min) >= 0)
+      return tag_init_s64(tag, integer_to_s64(i));
+    return tag;
+  case TAG_S8:
+    integer_init_s8(&j, tag->data.s8);
+    integer_reduce(&j, tag);
+    integer_clean(&j);
+    return tag;
+  case TAG_S16:
+    integer_init_s16(&j, tag->data.s16);
+    integer_reduce(&j, tag);
+    integer_clean(&j);
+    return tag;
+  case TAG_S32:
+    integer_init_s32(&j, tag->data.s32);
+    integer_reduce(&j, tag);
+    integer_clean(&j);
+    return tag;
+  case TAG_S64:
+    integer_init_s64(&j, tag->data.s64);
+    integer_reduce(&j, tag);
+    integer_clean(&j);
+    return tag;
+  case TAG_U8:
+    integer_init_u8(&j, tag->data.u8);
+    integer_reduce(&j, tag);
+    integer_clean(&j);
+    return tag;
+  case TAG_U16:
+    integer_init_u16(&j, tag->data.u16);
+    integer_reduce(&j, tag);
+    integer_clean(&j);
+    return tag;
+  case TAG_U32:
+    integer_init_u32(&j, tag->data.u32);
+    integer_reduce(&j, tag);
+    integer_clean(&j);
+    return tag;
+  case TAG_U64:
+    integer_init_u64(&j, tag->data.u64);
+    integer_reduce(&j, tag);
+    integer_clean(&j);
+    return tag;
+  default:
+    break;
   }
   return tag;
 }
diff --git a/libkc3/tag_init.rb b/libkc3/tag_init.rb
index 4e16205..c8edd64 100644
--- a/libkc3/tag_init.rb
+++ b/libkc3/tag_init.rb
@@ -326,7 +326,6 @@ class TagInitList
        TagInit.new("ident", "TAG_IDENT", :init_mode_direct,
                    [Arg.new("const s_ident *", "ident")]),
        TagInit1.new("ident", "1", "TAG_IDENT", :init_mode_init),
-#       TagInit.new("integer", "TAG_INTEGER", :init_mode_init, []),
        TagInit1.new("integer", "1", "TAG_INTEGER", :init_mode_init),
        TagInit.new("integer", "copy", "TAG_INTEGER", :init_mode_init,
                    [Arg.new("const s_integer *", "i")]),
diff --git a/libkc3/tag_sub.c b/libkc3/tag_sub.c
index 3a5165e..5337b94 100644
--- a/libkc3/tag_sub.c
+++ b/libkc3/tag_sub.c
@@ -20,6 +20,7 @@
 s_tag * tag_sub (const s_tag *a, const s_tag *b, s_tag *dest)
 {
   s_complex c;
+  s16 i_s16;
   s_integer tmp = {0};
   s_integer tmp2 = {0};
   s_ratio r;
@@ -916,7 +917,12 @@ s_tag * tag_sub (const s_tag *a, const s_tag *b, s_tag *dest)
       integer_clean(&tmp2);
       return dest;
     case TAG_U8:
-      return tag_init_s16(dest, (s16) a->data.u8 - (s16) b->data.u8);
+      i_s16 = (s16) a->data.u8 - (s16) b->data.u8;
+      if (i_s16 < S8_MIN)
+        return tag_init_s16(dest, i_s16);
+      if (i_s16 < 0)
+        return tag_init_s8(dest, i_s16);
+      return tag_init_u8(dest, i_s16);
     case TAG_U16:
       return tag_init_s32(dest, (s32) a->data.u8 - (s32) b->data.u16);
     case TAG_U32:
diff --git a/test/ikc3/puts.kc3 b/test/ikc3/puts.kc3
index 8a8fe27..e0c41a6 100644
--- a/test/ikc3/puts.kc3
+++ b/test/ikc3/puts.kc3
@@ -2,3 +2,5 @@ quote puts("Test")
 puts("Test")
 quote puts(%{hello: "World !"})
 puts(%{hello: "World !"})
+quote puts("Test #{:a}")
+puts("Test #{:a}")
diff --git a/test/ikc3/puts.out.expected b/test/ikc3/puts.out.expected
index 3f2e50e..a179909 100644
--- a/test/ikc3/puts.out.expected
+++ b/test/ikc3/puts.out.expected
@@ -4,3 +4,6 @@ Test
 puts(%{hello: "World !"})
 %{hello: "World !"}
 (Sw) 20
+puts("Test #{:a}")
+Test #{:a}
+(Sw) 10