移除了对scc_abi包的依赖,将相关头文件从libs/abi移动到libs/ast2ir目录下。 重构了基本类型解析功能,将parse_base_type函数提取为独立的 scc_ast2ir_parse_base_type实现,并支持有符号/无符号类型区分。 feat(ast2ir): 实现整数常量表达式求值器 新增了完整的整数常量表达式求值功能,支持C11标准中的常量表达式规则, 包括字面量、标识符、sizeof/_Alignof、一元/二元运算、条件表达式和 类型转换等操作。该功能用于数组大小和枚举值的编译期计算验证。 refactor(ast2ir): 完善类型提升和算术转换机制 改进了整数提升和寻常算术转换的实现,修复了移位操作的符号处理问题, 添加了无符号比较操作的支持,增强了类型安全检查,统一了错误处理流程。 fix(ast2ir): 修复赋值表达式返回值和数组大小计算问题 修正了赋值表达式的返回值处理,确保返回右侧值而不是存储指令引用。 使用新的常量表达式求值器替代原有的硬编码数组大小计算,提高了 数组声明的正确性。
1029 lines
25 KiB
C
1029 lines
25 KiB
C
#include <ap.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <utest/acutest.h>
|
|
|
|
/* ---------- helpers ---------- */
|
|
|
|
static int eql_int(const scc_ap_t *ap, isize expected) {
|
|
return scc_ap_eql(
|
|
ap, &(scc_ap_t){.capacity = -1,
|
|
.len = expected < 0 ? -1 : 1,
|
|
.data.digit =
|
|
(scc_ap_digit)(expected < 0
|
|
? -(uint64_t)(int64_t)expected
|
|
: (uint64_t)expected)});
|
|
}
|
|
|
|
/* ---------- scc_ap_init / scc_ap_drop ---------- */
|
|
|
|
void test_init_zero(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
TEST_CHECK(ap.capacity == -1);
|
|
TEST_CHECK(ap.len == 1);
|
|
TEST_CHECK(ap.data.digit == 0);
|
|
TEST_CHECK(eql_int(&ap, 0));
|
|
}
|
|
|
|
void test_drop_resets(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_set_int(&ap, 42);
|
|
scc_ap_drop(&ap);
|
|
TEST_CHECK(ap.capacity == -1);
|
|
TEST_CHECK(ap.len == 1);
|
|
TEST_CHECK(ap.data.digit == 0);
|
|
TEST_CHECK(eql_int(&ap, 0));
|
|
}
|
|
|
|
/* ---------- scc_ap_set_int ---------- */
|
|
|
|
void test_set_int_positive(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_set_int(&ap, 42);
|
|
TEST_CHECK(eql_int(&ap, 42));
|
|
}
|
|
|
|
void test_set_int_negative(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_set_int(&ap, -42);
|
|
TEST_CHECK(eql_int(&ap, -42));
|
|
}
|
|
|
|
void test_set_int_zero(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_set_int(&ap, 0);
|
|
TEST_CHECK(eql_int(&ap, 0));
|
|
}
|
|
|
|
void test_set_int_edge(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_set_int(&ap, 2147483647); /* INT_MAX */
|
|
TEST_CHECK(eql_int(&ap, 2147483647));
|
|
scc_ap_set_int(&ap, -2147483647 - 1); /* INT_MIN */
|
|
TEST_CHECK(eql_int(&ap, -2147483647 - 1));
|
|
}
|
|
|
|
/* ---------- scc_ap_set_digit ---------- */
|
|
|
|
void test_set_digit_basic(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_set_digit(&ap, 123);
|
|
TEST_CHECK(eql_int(&ap, 123));
|
|
}
|
|
|
|
void test_set_digit_zero(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_set_digit(&ap, 0);
|
|
TEST_CHECK(eql_int(&ap, 0));
|
|
}
|
|
|
|
void test_set_digit_max(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_set_digit(&ap, (scc_ap_digit)INTPTR_MAX);
|
|
TEST_CHECK(eql_int(&ap, INTPTR_MAX));
|
|
}
|
|
|
|
/* ---------- scc_ap_from_string ---------- */
|
|
|
|
void test_from_string_decimal(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "12345", -1, 10);
|
|
TEST_CHECK(eql_int(&ap, 12345));
|
|
}
|
|
|
|
void test_from_string_negative(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "-12345", -1, 10);
|
|
TEST_CHECK(eql_int(&ap, -12345));
|
|
}
|
|
|
|
void test_from_string_hex(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "0xFF", -1, 0);
|
|
TEST_CHECK(eql_int(&ap, 255));
|
|
}
|
|
|
|
void test_from_string_hex_no_prefix(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "FF", -1, 16);
|
|
TEST_CHECK(eql_int(&ap, 255));
|
|
}
|
|
|
|
void test_from_string_octal(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "077", -1, 0);
|
|
TEST_CHECK(eql_int(&ap, 63));
|
|
}
|
|
|
|
void test_from_string_binary(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "0b1010", -1, 0);
|
|
TEST_CHECK(eql_int(&ap, 10));
|
|
}
|
|
|
|
void test_from_string_zero(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "0", -1, 10);
|
|
TEST_CHECK(eql_int(&ap, 0));
|
|
}
|
|
|
|
void test_from_string_empty(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "", -1, 10);
|
|
TEST_CHECK(eql_int(&ap, 0));
|
|
}
|
|
|
|
void test_from_string_negative_zero(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "-0", -1, 10);
|
|
TEST_CHECK(eql_int(&ap, 0));
|
|
/* Should be positive zero */
|
|
TEST_CHECK(ap.len > 0);
|
|
}
|
|
|
|
void test_from_string_len_exact(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "42extra", 2, 10);
|
|
TEST_CHECK(eql_int(&ap, 42));
|
|
}
|
|
|
|
void test_from_string_max(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "9223372036854775807", -1, 10); /* INT64_MAX */
|
|
TEST_CHECK(eql_int(&ap, 9223372036854775807LL));
|
|
}
|
|
|
|
void test_from_string_min(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "-9223372036854775808", -1, 10);
|
|
TEST_CHECK(eql_int(&ap, (-9223372036854775807LL - 1)));
|
|
}
|
|
|
|
/* ---------- scc_ap_add ---------- */
|
|
|
|
void test_add_basic(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 3);
|
|
scc_ap_set_int(&b, 5);
|
|
scc_ap_add(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 8));
|
|
}
|
|
|
|
void test_add_negative(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -3);
|
|
scc_ap_set_int(&b, 5);
|
|
scc_ap_add(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 2));
|
|
}
|
|
|
|
void test_add_both_negative(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -3);
|
|
scc_ap_set_int(&b, -5);
|
|
scc_ap_add(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, -8));
|
|
}
|
|
|
|
void test_add_zero(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_set_int(&b, 0);
|
|
scc_ap_add(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 42));
|
|
}
|
|
|
|
void test_add_to_max(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_from_string(&a, "9223372036854775806", -1, 10);
|
|
scc_ap_set_int(&b, 1);
|
|
scc_ap_add(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, INTPTR_MAX));
|
|
}
|
|
|
|
void test_add_to_min(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
/* INTPTR_MIN + 1 + (-1) = INTPTR_MIN */
|
|
scc_ap_from_string(&a, "-9223372036854775807", -1, 10);
|
|
scc_ap_set_int(&b, -1);
|
|
scc_ap_add(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, INTPTR_MIN));
|
|
}
|
|
|
|
/* ---------- scc_ap_sub ---------- */
|
|
|
|
void test_sub_basic(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 10);
|
|
scc_ap_set_int(&b, 3);
|
|
scc_ap_sub(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 7));
|
|
}
|
|
|
|
void test_sub_negative_result(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 3);
|
|
scc_ap_set_int(&b, 10);
|
|
scc_ap_sub(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, -7));
|
|
}
|
|
|
|
void test_sub_negatives(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -5);
|
|
scc_ap_set_int(&b, -3);
|
|
scc_ap_sub(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, -2));
|
|
}
|
|
|
|
void test_sub_zero(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_set_int(&b, 0);
|
|
scc_ap_sub(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 42));
|
|
}
|
|
|
|
void test_sub_from_min(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
/* (INTPTR_MIN + 1) - 1 = INTPTR_MIN */
|
|
scc_ap_from_string(&a, "-9223372036854775807", -1, 10);
|
|
scc_ap_set_int(&b, 1);
|
|
scc_ap_sub(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, INTPTR_MIN));
|
|
}
|
|
|
|
/* ---------- scc_ap_mul ---------- */
|
|
|
|
void test_mul_basic(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 6);
|
|
scc_ap_set_int(&b, 7);
|
|
scc_ap_mul(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 42));
|
|
}
|
|
|
|
void test_mul_negative(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -4);
|
|
scc_ap_set_int(&b, 5);
|
|
scc_ap_mul(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, -20));
|
|
}
|
|
|
|
void test_mul_both_negative(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -4);
|
|
scc_ap_set_int(&b, -5);
|
|
scc_ap_mul(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 20));
|
|
}
|
|
|
|
void test_mul_zero(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_set_int(&b, 0);
|
|
scc_ap_mul(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 0));
|
|
}
|
|
|
|
void test_mul_one(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 99);
|
|
scc_ap_set_int(&b, 1);
|
|
scc_ap_mul(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 99));
|
|
}
|
|
|
|
void test_mul_neg_one(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 99);
|
|
scc_ap_set_int(&b, -1);
|
|
scc_ap_mul(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, -99));
|
|
}
|
|
|
|
void test_mul_max(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 1);
|
|
scc_ap_from_string(&b, "9223372036854775807", -1, 10);
|
|
scc_ap_mul(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, INTPTR_MAX));
|
|
}
|
|
|
|
/* ---------- scc_ap_div ---------- */
|
|
|
|
void test_div_basic(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_set_int(&b, 6);
|
|
scc_ap_div(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 7));
|
|
}
|
|
|
|
void test_div_negative(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -42);
|
|
scc_ap_set_int(&b, 6);
|
|
scc_ap_div(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, -7));
|
|
}
|
|
|
|
void test_div_trunc_toward_zero(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 7);
|
|
scc_ap_set_int(&b, 3);
|
|
scc_ap_div(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 2));
|
|
}
|
|
|
|
void test_div_one(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 123);
|
|
scc_ap_set_int(&b, 1);
|
|
scc_ap_div(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 123));
|
|
}
|
|
|
|
void test_div_self(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_set_int(&b, 42);
|
|
scc_ap_div(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 1));
|
|
}
|
|
|
|
void test_div_zero_dividend(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 0);
|
|
scc_ap_set_int(&b, 7);
|
|
scc_ap_div(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 0));
|
|
}
|
|
|
|
/* ---------- scc_ap_mod ---------- */
|
|
|
|
void test_mod_basic(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 10);
|
|
scc_ap_set_int(&b, 3);
|
|
scc_ap_mod(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 1));
|
|
}
|
|
|
|
void test_mod_negative_dividend(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -10);
|
|
scc_ap_set_int(&b, 3);
|
|
scc_ap_mod(&r, &a, &b);
|
|
/* C truncates toward zero: -10 % 3 = -1 */
|
|
TEST_CHECK(eql_int(&r, -1));
|
|
}
|
|
|
|
void test_mod_self(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_set_int(&b, 42);
|
|
scc_ap_mod(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 0));
|
|
}
|
|
|
|
/* ---------- scc_ap_shl / scc_ap_shr / scc_ap_lshr ---------- */
|
|
|
|
void test_shl_basic(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 3);
|
|
scc_ap_shl(&r, &a, 2);
|
|
TEST_CHECK(eql_int(&r, 12)); /* 3 << 2 = 12 */
|
|
}
|
|
|
|
void test_shl_negative(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -3);
|
|
scc_ap_shl(&r, &a, 2);
|
|
TEST_CHECK(eql_int(&r, -12));
|
|
}
|
|
|
|
void test_shl_zero(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_shl(&r, &a, 0);
|
|
TEST_CHECK(eql_int(&r, 42));
|
|
}
|
|
|
|
void test_shl_by_62(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 1);
|
|
scc_ap_shl(&r, &a, 62);
|
|
TEST_CHECK(eql_int(&r, 4611686018427387904LL));
|
|
}
|
|
|
|
void test_shr_basic(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 12);
|
|
scc_ap_shr(&r, &a, 2);
|
|
TEST_CHECK(eql_int(&r, 3)); /* 12 >> 2 = 3 */
|
|
}
|
|
|
|
void test_shr_arithmetic_negative(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -12);
|
|
scc_ap_shr(&r, &a, 2);
|
|
TEST_CHECK(eql_int(&r, -3)); /* arithmetic: -12 >> 2 = -3 */
|
|
}
|
|
|
|
void test_shr_arithmetic_negative_rounding(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -7);
|
|
scc_ap_shr(&r, &a, 2);
|
|
TEST_CHECK(eql_int(&r, -2)); /* arithmetic: -7 >> 2 = -2 (rounds down) */
|
|
}
|
|
|
|
void test_shr_zero_shift(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -42);
|
|
scc_ap_shr(&r, &a, 0);
|
|
TEST_CHECK(eql_int(&r, -42));
|
|
}
|
|
|
|
void test_lshr_basic(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 12);
|
|
scc_ap_lshr(&r, &a, 2);
|
|
TEST_CHECK(eql_int(&r, 3)); /* 12 >> 2 = 3 */
|
|
}
|
|
|
|
void test_lshr_negative(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -1); /* 0xFFFFFFFFFFFFFFFF */
|
|
scc_ap_lshr(&r, &a, 63);
|
|
TEST_CHECK(eql_int(&r, 1)); /* 0xFFFFFFFFFFFFFFFF >> 63 = 1 */
|
|
}
|
|
|
|
void test_lshr_negative_bits(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -8); /* 0xFFFFFFFFFFFFFFF8 */
|
|
scc_ap_lshr(&r, &a, 2);
|
|
/* 0xFFFFFFFFFFFFFFF8 >> 2 = 0x3FFFFFFFFFFFFFFE = 4611686018427387902 */
|
|
TEST_CHECK(eql_int(&r, 4611686018427387902LL));
|
|
}
|
|
|
|
/* ---------- bitwise ---------- */
|
|
|
|
void test_and_basic(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 5);
|
|
scc_ap_set_int(&b, 3);
|
|
scc_ap_and(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 1)); /* 5 & 3 = 1 */
|
|
}
|
|
|
|
void test_and_negative(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -5);
|
|
scc_ap_set_int(&b, 3);
|
|
scc_ap_and(&r, &a, &b);
|
|
/* -5 = 0xFFFFFFFB, & 3 = 0x00000003 = 3 */
|
|
TEST_CHECK(eql_int(&r, 3));
|
|
}
|
|
|
|
void test_and_zero(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_set_int(&b, 0);
|
|
scc_ap_and(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 0));
|
|
}
|
|
|
|
void test_or_basic(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 5);
|
|
scc_ap_set_int(&b, 3);
|
|
scc_ap_or(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 7)); /* 5 | 3 = 7 */
|
|
}
|
|
|
|
void test_or_negative(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -5);
|
|
scc_ap_set_int(&b, 3);
|
|
scc_ap_or(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, -5)); /* -5 | 3 = -5 */
|
|
}
|
|
|
|
void test_xor_basic(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 5);
|
|
scc_ap_set_int(&b, 3);
|
|
scc_ap_xor(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, 6)); /* 5 ^ 3 = 6 */
|
|
}
|
|
|
|
void test_xor_negative(void) {
|
|
scc_ap_t a, b, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -5);
|
|
scc_ap_set_int(&b, 3);
|
|
scc_ap_xor(&r, &a, &b);
|
|
TEST_CHECK(eql_int(&r, -8)); /* -5 ^ 3 = -8 */
|
|
}
|
|
|
|
void test_not_basic(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 5);
|
|
scc_ap_not(&r, &a);
|
|
TEST_CHECK(eql_int(&r, -6)); /* ~5 = -6 */
|
|
}
|
|
|
|
void test_not_neg_one(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -1);
|
|
scc_ap_not(&r, &a);
|
|
TEST_CHECK(eql_int(&r, 0)); /* ~(-1) = 0 */
|
|
}
|
|
|
|
void test_not_zero(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 0);
|
|
scc_ap_not(&r, &a);
|
|
TEST_CHECK(eql_int(&r, -1)); /* ~0 = -1 */
|
|
}
|
|
|
|
/* ---------- scc_ap_neg ---------- */
|
|
|
|
void test_neg_positive(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_neg(&r, &a);
|
|
TEST_CHECK(eql_int(&r, -42));
|
|
}
|
|
|
|
void test_neg_negative(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, -42);
|
|
scc_ap_neg(&r, &a);
|
|
TEST_CHECK(eql_int(&r, 42));
|
|
}
|
|
|
|
void test_neg_zero(void) {
|
|
scc_ap_t a, r;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&r);
|
|
scc_ap_set_int(&a, 0);
|
|
scc_ap_neg(&r, &a);
|
|
TEST_CHECK(eql_int(&r, 0));
|
|
}
|
|
|
|
/* ---------- scc_ap_cmp ---------- */
|
|
|
|
void test_cmp_equal(void) {
|
|
scc_ap_t a, b;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_set_int(&b, 42);
|
|
TEST_CHECK(scc_ap_cmp(&a, &b) == 0);
|
|
}
|
|
|
|
void test_cmp_less(void) {
|
|
scc_ap_t a, b;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_set_int(&a, 3);
|
|
scc_ap_set_int(&b, 5);
|
|
TEST_CHECK(scc_ap_cmp(&a, &b) < 0);
|
|
}
|
|
|
|
void test_cmp_greater(void) {
|
|
scc_ap_t a, b;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_set_int(&a, 5);
|
|
scc_ap_set_int(&b, 3);
|
|
TEST_CHECK(scc_ap_cmp(&a, &b) > 0);
|
|
}
|
|
|
|
void test_cmp_neg_vs_pos(void) {
|
|
scc_ap_t a, b;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_set_int(&a, -5);
|
|
scc_ap_set_int(&b, 3);
|
|
TEST_CHECK(scc_ap_cmp(&a, &b) < 0);
|
|
}
|
|
|
|
/* ---------- scc_ap_is_zero ---------- */
|
|
|
|
void test_is_zero_true(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
TEST_CHECK(scc_ap_is_zero(&ap) != 0);
|
|
}
|
|
|
|
void test_is_zero_false_pos(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_set_int(&ap, 42);
|
|
TEST_CHECK(scc_ap_is_zero(&ap) == 0);
|
|
}
|
|
|
|
void test_is_zero_false_neg(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_set_int(&ap, -42);
|
|
TEST_CHECK(scc_ap_is_zero(&ap) == 0);
|
|
}
|
|
|
|
/* ---------- scc_ap_eql ---------- */
|
|
|
|
void test_eql_equal(void) {
|
|
scc_ap_t a, b;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_set_int(&b, 42);
|
|
TEST_CHECK(scc_ap_eql(&a, &b) != 0);
|
|
}
|
|
|
|
void test_eql_not_equal(void) {
|
|
scc_ap_t a, b;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_set_int(&a, 42);
|
|
scc_ap_set_int(&b, 43);
|
|
TEST_CHECK(scc_ap_eql(&a, &b) == 0);
|
|
}
|
|
|
|
void test_eql_neg_vs_pos(void) {
|
|
scc_ap_t a, b;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
scc_ap_set_int(&a, -42);
|
|
scc_ap_set_int(&b, 42);
|
|
TEST_CHECK(scc_ap_eql(&a, &b) == 0);
|
|
}
|
|
|
|
void test_eql_both_zero(void) {
|
|
scc_ap_t a, b;
|
|
scc_ap_init(&a);
|
|
scc_ap_init(&b);
|
|
/* +0 == 0 */
|
|
scc_ap_from_string(&a, "0", -1, 10);
|
|
scc_ap_from_string(&b, "-0", -1, 10);
|
|
TEST_CHECK(scc_ap_eql(&a, &b) != 0);
|
|
}
|
|
|
|
/* ---------- scc_ap_with_bits ---------- */
|
|
|
|
void test_with_bits_small(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_with_bits(&ap, 1);
|
|
TEST_CHECK(ap.capacity == -1);
|
|
}
|
|
|
|
void test_with_bits_64(void) {
|
|
scc_ap_t ap;
|
|
scc_ap_init(&ap);
|
|
scc_ap_with_bits(&ap, 64);
|
|
TEST_CHECK(ap.capacity == -1);
|
|
}
|
|
|
|
/* ---------- scc_ap_dump ---------- */
|
|
|
|
typedef struct {
|
|
char buf[128];
|
|
int pos;
|
|
} dump_ctx_t;
|
|
|
|
static void dump_char(char ch, void *user_data) {
|
|
dump_ctx_t *ctx = (dump_ctx_t *)user_data;
|
|
if (ctx->pos < (int)sizeof(ctx->buf) - 1)
|
|
ctx->buf[ctx->pos++] = ch;
|
|
}
|
|
|
|
void test_dump_positive(void) {
|
|
scc_ap_t ap;
|
|
dump_ctx_t ctx;
|
|
scc_ap_init(&ap);
|
|
scc_ap_set_int(&ap, 12345);
|
|
ctx.pos = 0;
|
|
ctx.buf[0] = '\0';
|
|
scc_ap_dump(&ap, dump_char, &ctx);
|
|
ctx.buf[ctx.pos] = '\0';
|
|
TEST_CHECK(strcmp(ctx.buf, "12345") == 0);
|
|
}
|
|
|
|
void test_dump_negative(void) {
|
|
scc_ap_t ap;
|
|
dump_ctx_t ctx;
|
|
scc_ap_init(&ap);
|
|
scc_ap_set_int(&ap, -12345);
|
|
ctx.pos = 0;
|
|
ctx.buf[0] = '\0';
|
|
scc_ap_dump(&ap, dump_char, &ctx);
|
|
ctx.buf[ctx.pos] = '\0';
|
|
TEST_CHECK(strcmp(ctx.buf, "-12345") == 0);
|
|
}
|
|
|
|
void test_dump_zero(void) {
|
|
scc_ap_t ap;
|
|
dump_ctx_t ctx;
|
|
scc_ap_init(&ap);
|
|
ctx.pos = 0;
|
|
ctx.buf[0] = '\0';
|
|
scc_ap_dump(&ap, dump_char, &ctx);
|
|
ctx.buf[ctx.pos] = '\0';
|
|
TEST_CHECK(strcmp(ctx.buf, "0") == 0);
|
|
}
|
|
|
|
void test_dump_max(void) {
|
|
scc_ap_t ap;
|
|
dump_ctx_t ctx;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "9223372036854775807", -1, 10);
|
|
ctx.pos = 0;
|
|
ctx.buf[0] = '\0';
|
|
scc_ap_dump(&ap, dump_char, &ctx);
|
|
ctx.buf[ctx.pos] = '\0';
|
|
TEST_CHECK(strcmp(ctx.buf, "9223372036854775807") == 0);
|
|
}
|
|
|
|
void test_dump_min(void) {
|
|
scc_ap_t ap;
|
|
dump_ctx_t ctx;
|
|
scc_ap_init(&ap);
|
|
scc_ap_from_string(&ap, "-9223372036854775808", -1, 10);
|
|
ctx.pos = 0;
|
|
ctx.buf[0] = '\0';
|
|
scc_ap_dump(&ap, dump_char, &ctx);
|
|
ctx.buf[ctx.pos] = '\0';
|
|
TEST_CHECK(strcmp(ctx.buf, "-9223372036854775808") == 0);
|
|
}
|
|
|
|
/* ---------- test list ---------- */
|
|
|
|
TEST_LIST = {
|
|
/* init / drop */
|
|
{"test_init_zero", test_init_zero},
|
|
{"test_drop_resets", test_drop_resets},
|
|
/* set_int */
|
|
{"test_set_int_positive", test_set_int_positive},
|
|
{"test_set_int_negative", test_set_int_negative},
|
|
{"test_set_int_zero", test_set_int_zero},
|
|
{"test_set_int_edge", test_set_int_edge},
|
|
/* set_digit */
|
|
{"test_set_digit_basic", test_set_digit_basic},
|
|
{"test_set_digit_zero", test_set_digit_zero},
|
|
{"test_set_digit_max", test_set_digit_max},
|
|
/* from_string */
|
|
{"test_from_string_decimal", test_from_string_decimal},
|
|
{"test_from_string_negative", test_from_string_negative},
|
|
{"test_from_string_hex", test_from_string_hex},
|
|
{"test_from_string_hex_no_prefix", test_from_string_hex_no_prefix},
|
|
{"test_from_string_octal", test_from_string_octal},
|
|
{"test_from_string_binary", test_from_string_binary},
|
|
{"test_from_string_zero", test_from_string_zero},
|
|
{"test_from_string_empty", test_from_string_empty},
|
|
{"test_from_string_negative_zero", test_from_string_negative_zero},
|
|
{"test_from_string_len_exact", test_from_string_len_exact},
|
|
{"test_from_string_max", test_from_string_max},
|
|
{"test_from_string_min", test_from_string_min},
|
|
/* add */
|
|
{"test_add_basic", test_add_basic},
|
|
{"test_add_negative", test_add_negative},
|
|
{"test_add_both_negative", test_add_both_negative},
|
|
{"test_add_zero", test_add_zero},
|
|
{"test_add_to_max", test_add_to_max},
|
|
{"test_add_to_min", test_add_to_min},
|
|
/* sub */
|
|
{"test_sub_basic", test_sub_basic},
|
|
{"test_sub_negative_result", test_sub_negative_result},
|
|
{"test_sub_negatives", test_sub_negatives},
|
|
{"test_sub_zero", test_sub_zero},
|
|
{"test_sub_from_min", test_sub_from_min},
|
|
/* mul */
|
|
{"test_mul_basic", test_mul_basic},
|
|
{"test_mul_negative", test_mul_negative},
|
|
{"test_mul_both_negative", test_mul_both_negative},
|
|
{"test_mul_zero", test_mul_zero},
|
|
{"test_mul_one", test_mul_one},
|
|
{"test_mul_neg_one", test_mul_neg_one},
|
|
{"test_mul_max", test_mul_max},
|
|
/* div */
|
|
{"test_div_basic", test_div_basic},
|
|
{"test_div_negative", test_div_negative},
|
|
{"test_div_trunc_toward_zero", test_div_trunc_toward_zero},
|
|
{"test_div_one", test_div_one},
|
|
{"test_div_self", test_div_self},
|
|
{"test_div_zero_dividend", test_div_zero_dividend},
|
|
/* mod */
|
|
{"test_mod_basic", test_mod_basic},
|
|
{"test_mod_negative_dividend", test_mod_negative_dividend},
|
|
{"test_mod_self", test_mod_self},
|
|
/* shl / shr / lshr */
|
|
{"test_shl_basic", test_shl_basic},
|
|
{"test_shl_negative", test_shl_negative},
|
|
{"test_shl_zero", test_shl_zero},
|
|
{"test_shl_by_62", test_shl_by_62},
|
|
{"test_shr_basic", test_shr_basic},
|
|
{"test_shr_arithmetic_negative", test_shr_arithmetic_negative},
|
|
{"test_shr_arithmetic_negative_rounding", test_shr_arithmetic_negative_rounding},
|
|
{"test_shr_zero_shift", test_shr_zero_shift},
|
|
{"test_lshr_basic", test_lshr_basic},
|
|
{"test_lshr_negative", test_lshr_negative},
|
|
{"test_lshr_negative_bits", test_lshr_negative_bits},
|
|
/* bitwise */
|
|
{"test_and_basic", test_and_basic},
|
|
{"test_and_negative", test_and_negative},
|
|
{"test_and_zero", test_and_zero},
|
|
{"test_or_basic", test_or_basic},
|
|
{"test_or_negative", test_or_negative},
|
|
{"test_xor_basic", test_xor_basic},
|
|
{"test_xor_negative", test_xor_negative},
|
|
{"test_not_basic", test_not_basic},
|
|
{"test_not_neg_one", test_not_neg_one},
|
|
{"test_not_zero", test_not_zero},
|
|
/* neg */
|
|
{"test_neg_positive", test_neg_positive},
|
|
{"test_neg_negative", test_neg_negative},
|
|
{"test_neg_zero", test_neg_zero},
|
|
/* cmp */
|
|
{"test_cmp_equal", test_cmp_equal},
|
|
{"test_cmp_less", test_cmp_less},
|
|
{"test_cmp_greater", test_cmp_greater},
|
|
{"test_cmp_neg_vs_pos", test_cmp_neg_vs_pos},
|
|
/* is_zero */
|
|
{"test_is_zero_true", test_is_zero_true},
|
|
{"test_is_zero_false_pos", test_is_zero_false_pos},
|
|
{"test_is_zero_false_neg", test_is_zero_false_neg},
|
|
/* eql */
|
|
{"test_eql_equal", test_eql_equal},
|
|
{"test_eql_not_equal", test_eql_not_equal},
|
|
{"test_eql_neg_vs_pos", test_eql_neg_vs_pos},
|
|
{"test_eql_both_zero", test_eql_both_zero},
|
|
/* with_bits */
|
|
{"test_with_bits_small", test_with_bits_small},
|
|
{"test_with_bits_64", test_with_bits_64},
|
|
/* dump */
|
|
{"test_dump_positive", test_dump_positive},
|
|
{"test_dump_negative", test_dump_negative},
|
|
{"test_dump_zero", test_dump_zero},
|
|
{"test_dump_max", test_dump_max},
|
|
{"test_dump_min", test_dump_min},
|
|
{nullptr, nullptr},
|
|
};
|