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