refactor(ast2ir): 移除废弃的ABI依赖并优化类型转换处理
移除了对scc_abi包的依赖,将相关头文件从libs/abi移动到libs/ast2ir目录下。 重构了基本类型解析功能,将parse_base_type函数提取为独立的 scc_ast2ir_parse_base_type实现,并支持有符号/无符号类型区分。 feat(ast2ir): 实现整数常量表达式求值器 新增了完整的整数常量表达式求值功能,支持C11标准中的常量表达式规则, 包括字面量、标识符、sizeof/_Alignof、一元/二元运算、条件表达式和 类型转换等操作。该功能用于数组大小和枚举值的编译期计算验证。 refactor(ast2ir): 完善类型提升和算术转换机制 改进了整数提升和寻常算术转换的实现,修复了移位操作的符号处理问题, 添加了无符号比较操作的支持,增强了类型安全检查,统一了错误处理流程。 fix(ast2ir): 修复赋值表达式返回值和数组大小计算问题 修正了赋值表达式的返回值处理,确保返回右侧值而不是存储指令引用。 使用新的常量表达式求值器替代原有的硬编码数组大小计算,提高了 数组声明的正确性。
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
[package]
|
||||
name = "ap"
|
||||
version = "0.1.0"
|
||||
authors = []
|
||||
name = "ap"
|
||||
version = "0.1.0"
|
||||
authors = []
|
||||
description = ""
|
||||
|
||||
# dependencies = []
|
||||
dependencies = [{ name = "core", path = "../scc_core" }]
|
||||
# features = {}
|
||||
# default_features = []
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @brief Arbitrary Precision Library
|
||||
*
|
||||
*/
|
||||
#ifdef __SCC__
|
||||
#ifndef __NO_SCC_RUNTIME__
|
||||
#include <scc_core.h>
|
||||
#define SCC_AP_DIGIT u64
|
||||
#define SCC_AP_PANIC Panic
|
||||
@@ -49,21 +49,21 @@ typedef struct {
|
||||
} scc_ap_t;
|
||||
|
||||
static inline void scc_ap_init(scc_ap_t *ap) {
|
||||
ap->len = 0;
|
||||
ap->capacity = -1;
|
||||
ap->len = 1;
|
||||
ap->data.digit = 0;
|
||||
}
|
||||
|
||||
static inline void scc_ap_set_int(scc_ap_t *ap, int val) {
|
||||
ap->capacity = -1;
|
||||
SCC_AP_ASSERT(sizeof(scc_ap_digit) >= sizeof(int));
|
||||
if (val < 0) {
|
||||
ap->len = -1;
|
||||
ap->data.digit = (scc_ap_digit)(-(int64_t)val);
|
||||
} else {
|
||||
ap->len = 1;
|
||||
ap->data.digit = (scc_ap_digit)val;
|
||||
}
|
||||
SCC_AP_ASSERT(sizeof(scc_ap_digit) >= sizeof(int));
|
||||
ap->capacity = -1;
|
||||
ap->data.digit = val;
|
||||
}
|
||||
|
||||
void scc_ap_drop(scc_ap_t *ap);
|
||||
@@ -77,13 +77,20 @@ void scc_ap_mul(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b);
|
||||
void scc_ap_div(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b);
|
||||
void scc_ap_mod(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b);
|
||||
|
||||
/**
|
||||
* @brief equal
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
* @return int
|
||||
*/
|
||||
void scc_ap_shl(scc_ap_t *to, const scc_ap_t *from, unsigned shift);
|
||||
void scc_ap_shr(scc_ap_t *to, const scc_ap_t *from, unsigned shift);
|
||||
void scc_ap_lshr(scc_ap_t *to, const scc_ap_t *from, unsigned shift);
|
||||
|
||||
void scc_ap_and(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b);
|
||||
void scc_ap_or(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b);
|
||||
void scc_ap_xor(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b);
|
||||
void scc_ap_not(scc_ap_t *to, const scc_ap_t *from);
|
||||
|
||||
void scc_ap_neg(scc_ap_t *to, const scc_ap_t *from);
|
||||
|
||||
int scc_ap_cmp(const scc_ap_t *a, const scc_ap_t *b);
|
||||
int scc_ap_is_zero(const scc_ap_t *ap);
|
||||
|
||||
int scc_ap_eql(const scc_ap_t *a, const scc_ap_t *b);
|
||||
|
||||
typedef void (*ap_dump_fn)(const char ch, void *user_data);
|
||||
|
||||
@@ -1,48 +1,394 @@
|
||||
#include <ap.h>
|
||||
|
||||
static void *scc_ap_alloc(size_t size) {
|
||||
void *p = SCC_AP_MALLOC(size);
|
||||
SCC_AP_ASSERT(p != NULL);
|
||||
return p;
|
||||
/*
|
||||
* Fast-path (hack) implementation: all values stored in single-digit mode.
|
||||
* data.digit holds the absolute magnitude as u64, len sign indicates sign.
|
||||
* Arithmetic is done via isize with explicit overflow checks — anything
|
||||
* out of isize range triggers SCC_AP_PANIC.
|
||||
*/
|
||||
|
||||
/* ---------- internal helpers ---------- */
|
||||
|
||||
/* Convert from sign-magnitude (digit mode) to isize */
|
||||
static isize ap_to_isize(const scc_ap_t *ap) {
|
||||
SCC_AP_ASSERT(ap != nullptr);
|
||||
SCC_AP_ASSERT(ap->capacity == -1);
|
||||
uint64_t mag = ap->data.digit;
|
||||
if (ap->len < 0) {
|
||||
if (mag == 0)
|
||||
return 0;
|
||||
if (mag == (uint64_t)INTPTR_MAX + 1)
|
||||
return INTPTR_MIN;
|
||||
SCC_AP_ASSERT(mag <= (uint64_t)INTPTR_MAX);
|
||||
return -(isize)(int64_t)mag;
|
||||
}
|
||||
SCC_AP_ASSERT(mag <= (uint64_t)INTPTR_MAX);
|
||||
return (isize)(int64_t)mag;
|
||||
}
|
||||
|
||||
/* 重新分配内存 */
|
||||
static void *scc_ap_realloc_data(void *old, size_t new_size) {
|
||||
void *p = SCC_AP_REALLOC(old, new_size);
|
||||
SCC_AP_ASSERT(p != NULL);
|
||||
return p;
|
||||
/* Store isize value into sign-magnitude (digit mode) */
|
||||
static void ap_from_isize(scc_ap_t *ap, isize val) {
|
||||
ap->capacity = -1;
|
||||
if (val < 0) {
|
||||
ap->len = -1;
|
||||
ap->data.digit = (scc_ap_digit)(-(uint64_t)(int64_t)val);
|
||||
} else {
|
||||
ap->len = 1;
|
||||
ap->data.digit = (scc_ap_digit)val;
|
||||
}
|
||||
}
|
||||
|
||||
/* Checked addition */
|
||||
static isize ap_add_isize(isize a, isize b) {
|
||||
if (b > 0 && a > INTPTR_MAX - b)
|
||||
SCC_AP_PANIC("scc_ap_add: positive overflow");
|
||||
if (b < 0 && a < INTPTR_MIN - b)
|
||||
SCC_AP_PANIC("scc_ap_add: negative overflow");
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/* Checked subtraction: a - b */
|
||||
static isize ap_sub_isize(isize a, isize b) {
|
||||
/* a - b = a + (-b); -INTPTR_MIN overflows, handle specially */
|
||||
if (b == INTPTR_MIN) {
|
||||
if (a < 0)
|
||||
SCC_AP_PANIC("scc_ap_sub: overflow (a - INTPTR_MIN, a < 0)");
|
||||
SCC_AP_PANIC("scc_ap_sub: overflow (a - INTPTR_MIN, a >= 0)");
|
||||
}
|
||||
return ap_add_isize(a, -b);
|
||||
}
|
||||
|
||||
/* Checked multiplication */
|
||||
static isize ap_mul_isize(isize a, isize b) {
|
||||
if (a == 0 || b == 0)
|
||||
return 0;
|
||||
if (a == 1)
|
||||
return b;
|
||||
if (b == 1)
|
||||
return a;
|
||||
|
||||
/* Determine sign of result */
|
||||
int sign = ((a < 0) == (b < 0)) ? 1 : -1;
|
||||
|
||||
/* Absolute values as uint64 */
|
||||
uint64_t ua = (a == INTPTR_MIN)
|
||||
? (uint64_t)INTPTR_MAX + 1
|
||||
: (uint64_t)(a < 0 ? -(int64_t)a : (int64_t)a);
|
||||
uint64_t ub = (b == INTPTR_MIN)
|
||||
? (uint64_t)INTPTR_MAX + 1
|
||||
: (uint64_t)(b < 0 ? -(int64_t)b : (int64_t)b);
|
||||
|
||||
/* Overflow threshold */
|
||||
uint64_t limit =
|
||||
(sign > 0) ? (uint64_t)INTPTR_MAX : (uint64_t)INTPTR_MAX + 1;
|
||||
|
||||
if (ua != 0 && ub > limit / ua)
|
||||
SCC_AP_PANIC("scc_ap_mul: overflow");
|
||||
|
||||
isize result = (isize)(ua * ub);
|
||||
return (sign > 0) ? result : -result;
|
||||
}
|
||||
|
||||
/* Checked division */
|
||||
static isize ap_div_isize(isize a, isize b) {
|
||||
if (b == 0)
|
||||
SCC_AP_PANIC("scc_ap_div: division by zero");
|
||||
if (a == INTPTR_MIN && b == -1)
|
||||
SCC_AP_PANIC("scc_ap_div: overflow (INTPTR_MIN / -1)");
|
||||
return a / b;
|
||||
}
|
||||
|
||||
/* Checked modulo */
|
||||
static isize ap_mod_isize(isize a, isize b) {
|
||||
if (b == 0)
|
||||
SCC_AP_PANIC("scc_ap_mod: modulo by zero");
|
||||
if (a == INTPTR_MIN && b == -1)
|
||||
SCC_AP_PANIC("scc_ap_mod: overflow (INTPTR_MIN %% -1)");
|
||||
return a % b;
|
||||
}
|
||||
|
||||
/* ---------- public API ---------- */
|
||||
|
||||
void scc_ap_drop(scc_ap_t *ap) {
|
||||
SCC_AP_ASSERT(ap);
|
||||
// SCC_AP_FREE(ap->data);
|
||||
SCC_AP_ASSERT(ap != nullptr);
|
||||
/* In digit mode (capacity == -1), there's no heap allocation to free */
|
||||
scc_ap_init(ap);
|
||||
}
|
||||
|
||||
void scc_ap_with_bits(scc_ap_t *ap, int bits) {}
|
||||
|
||||
void scc_ap_from_string(scc_ap_t *ap, const char *str, int len, int base) {
|
||||
SCC_AP_ASSERT(base == 10);
|
||||
SCC_AP_ASSERT(ap && str);
|
||||
if (len == 0) {
|
||||
scc_ap_set_int(ap, 0);
|
||||
}
|
||||
// FIXME
|
||||
int int_lit = 0;
|
||||
for (int i = 0; i < len; i += 1) {
|
||||
int_lit = int_lit * 10 + (str[i] - '0');
|
||||
}
|
||||
scc_ap_set_int(ap, int_lit);
|
||||
void scc_ap_with_bits(scc_ap_t *ap, int bits) {
|
||||
SCC_AP_ASSERT(ap != nullptr);
|
||||
if (bits > (int)(sizeof(scc_ap_digit) * 8))
|
||||
SCC_AP_PANIC(
|
||||
"scc_ap_with_bits: request %d bits but digit only has %zu bits",
|
||||
bits, sizeof(scc_ap_digit) * 8);
|
||||
(void)ap;
|
||||
/* Fast path: always stays in digit mode */
|
||||
}
|
||||
|
||||
void scc_ap_set_digit(scc_ap_t *ap, scc_ap_digit digit) {}
|
||||
void scc_ap_from_string(scc_ap_t *ap, const char *str, int len, int base) {
|
||||
SCC_AP_ASSERT(ap != nullptr && str != nullptr);
|
||||
|
||||
void scc_ap_add_impl(scc_ap_t *to, const scc_ap_t *from_a,
|
||||
const scc_ap_t *from_b) {}
|
||||
/* len < 0 means null-terminated */
|
||||
if (len < 0) {
|
||||
len = 0;
|
||||
while (str[len] != '\0')
|
||||
len++;
|
||||
}
|
||||
if (len == 0) {
|
||||
ap_from_isize(ap, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
void scc_ap_add(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {}
|
||||
int i = 0;
|
||||
int sign = 1;
|
||||
|
||||
void scc_ap_sub(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {}
|
||||
/* Optional leading sign */
|
||||
if (str[i] == '-') {
|
||||
sign = -1;
|
||||
i++;
|
||||
} else if (str[i] == '+') {
|
||||
i++;
|
||||
}
|
||||
|
||||
typedef void (*ap_dump_fn)(const char ch, void *user_data);
|
||||
int scc_ap_dump(scc_ap_t *ap, ap_dump_fn dump_fn, void *user_data) { return 0; }
|
||||
if (i >= len) {
|
||||
ap_from_isize(ap, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---------- base auto-detection ---------- */
|
||||
/* hex: 0x / 0X */
|
||||
if ((base == 0 || base == 16) &&
|
||||
(i + 2 < len && str[i] == '0' &&
|
||||
(str[i + 1] == 'x' || str[i + 1] == 'X'))) {
|
||||
base = 16;
|
||||
i += 2;
|
||||
}
|
||||
/* binary: 0b / 0B */
|
||||
if ((base == 0 || base == 2) &&
|
||||
(i + 2 < len && str[i] == '0' &&
|
||||
(str[i + 1] == 'b' || str[i + 1] == 'B'))) {
|
||||
base = 2;
|
||||
i += 2;
|
||||
}
|
||||
if (base == 0) {
|
||||
if (i < len && str[i] == '0') {
|
||||
base = 8;
|
||||
i++;
|
||||
} else {
|
||||
base = 10;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- parse digits ---------- */
|
||||
uint64_t val = 0;
|
||||
for (; i < len; i++) {
|
||||
char ch = str[i];
|
||||
unsigned d;
|
||||
if (ch >= '0' && ch <= '9')
|
||||
d = (unsigned)(ch - '0');
|
||||
else if (ch >= 'a' && ch <= 'f')
|
||||
d = (unsigned)(ch - 'a' + 10);
|
||||
else if (ch >= 'A' && ch <= 'F')
|
||||
d = (unsigned)(ch - 'A' + 10);
|
||||
else
|
||||
break;
|
||||
if ((int)d >= base)
|
||||
break;
|
||||
|
||||
/* overflow check: val * base + d <= UINT64_MAX */
|
||||
if (val > (UINT64_MAX - d) / (unsigned)base)
|
||||
SCC_AP_PANIC("scc_ap_from_string: overflow");
|
||||
val = val * (unsigned)base + d;
|
||||
}
|
||||
|
||||
ap->capacity = -1;
|
||||
ap->data.digit = val;
|
||||
ap->len = (sign < 0 && val > 0) ? -1 : 1;
|
||||
}
|
||||
|
||||
void scc_ap_set_digit(scc_ap_t *ap, scc_ap_digit digit) {
|
||||
SCC_AP_ASSERT(ap != nullptr);
|
||||
if (digit > (scc_ap_digit)INTPTR_MAX)
|
||||
SCC_AP_PANIC("scc_ap_set_digit: value %llu exceeds isize range",
|
||||
(unsigned long long)digit);
|
||||
ap->capacity = -1;
|
||||
ap->data.digit = digit;
|
||||
ap->len = 1;
|
||||
}
|
||||
|
||||
void scc_ap_add(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
|
||||
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
|
||||
isize a = ap_to_isize(from_a);
|
||||
isize b = ap_to_isize(from_b);
|
||||
ap_from_isize(to, ap_add_isize(a, b));
|
||||
}
|
||||
|
||||
void scc_ap_sub(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
|
||||
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
|
||||
isize a = ap_to_isize(from_a);
|
||||
isize b = ap_to_isize(from_b);
|
||||
ap_from_isize(to, ap_sub_isize(a, b));
|
||||
}
|
||||
|
||||
void scc_ap_mul(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
|
||||
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
|
||||
isize a = ap_to_isize(from_a);
|
||||
isize b = ap_to_isize(from_b);
|
||||
ap_from_isize(to, ap_mul_isize(a, b));
|
||||
}
|
||||
|
||||
void scc_ap_div(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
|
||||
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
|
||||
isize a = ap_to_isize(from_a);
|
||||
isize b = ap_to_isize(from_b);
|
||||
ap_from_isize(to, ap_div_isize(a, b));
|
||||
}
|
||||
|
||||
void scc_ap_mod(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
|
||||
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
|
||||
isize a = ap_to_isize(from_a);
|
||||
isize b = ap_to_isize(from_b);
|
||||
ap_from_isize(to, ap_mod_isize(a, b));
|
||||
}
|
||||
|
||||
void scc_ap_shl(scc_ap_t *to, const scc_ap_t *from, unsigned shift) {
|
||||
SCC_AP_ASSERT(to != nullptr && from != nullptr);
|
||||
SCC_AP_ASSERT(from->capacity == -1);
|
||||
if (shift >= sizeof(scc_ap_digit) * 8)
|
||||
SCC_AP_PANIC("scc_ap_shl: shift %u exceeds digit width (%zu bits)",
|
||||
shift, sizeof(scc_ap_digit) * 8);
|
||||
/* left shift = multiply by 2^shift */
|
||||
isize val = ap_to_isize(from);
|
||||
isize result = ap_mul_isize(val, (isize)1 << shift);
|
||||
ap_from_isize(to, result);
|
||||
}
|
||||
|
||||
void scc_ap_shr(scc_ap_t *to, const scc_ap_t *from, unsigned shift) {
|
||||
SCC_AP_ASSERT(to != nullptr && from != nullptr);
|
||||
SCC_AP_ASSERT(from->capacity == -1);
|
||||
if (shift >= sizeof(scc_ap_digit) * 8)
|
||||
SCC_AP_PANIC("scc_ap_shr: shift %u exceeds digit width (%zu bits)",
|
||||
shift, sizeof(scc_ap_digit) * 8);
|
||||
/* arithmetic right shift — uses >> on isize (arithmetic on GCC/MSVC/Clang) */
|
||||
isize val = ap_to_isize(from);
|
||||
ap_from_isize(to, val >> shift);
|
||||
}
|
||||
|
||||
void scc_ap_lshr(scc_ap_t *to, const scc_ap_t *from, unsigned shift) {
|
||||
SCC_AP_ASSERT(to != nullptr && from != nullptr);
|
||||
SCC_AP_ASSERT(from->capacity == -1);
|
||||
if (shift >= sizeof(scc_ap_digit) * 8)
|
||||
SCC_AP_PANIC("scc_ap_lshr: shift %u exceeds digit width (%zu bits)",
|
||||
shift, sizeof(scc_ap_digit) * 8);
|
||||
/*
|
||||
* logical right shift: reinterpret the signed value as uint64 bit pattern,
|
||||
* shift right, store as non-negative magnitude.
|
||||
*/
|
||||
uint64_t bits;
|
||||
if (from->len < 0) {
|
||||
/* negative → two's complement bit pattern */
|
||||
bits = -(uint64_t)(int64_t)from->data.digit;
|
||||
} else {
|
||||
bits = from->data.digit;
|
||||
}
|
||||
to->capacity = -1;
|
||||
to->data.digit = bits >> shift;
|
||||
to->len = 1;
|
||||
}
|
||||
|
||||
/* ---------- bitwise ---------- */
|
||||
|
||||
void scc_ap_and(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b) {
|
||||
SCC_AP_ASSERT(to != nullptr && a != nullptr && b != nullptr);
|
||||
ap_from_isize(to, ap_to_isize(a) & ap_to_isize(b));
|
||||
}
|
||||
|
||||
void scc_ap_or(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b) {
|
||||
SCC_AP_ASSERT(to != nullptr && a != nullptr && b != nullptr);
|
||||
ap_from_isize(to, ap_to_isize(a) | ap_to_isize(b));
|
||||
}
|
||||
|
||||
void scc_ap_xor(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b) {
|
||||
SCC_AP_ASSERT(to != nullptr && a != nullptr && b != nullptr);
|
||||
ap_from_isize(to, ap_to_isize(a) ^ ap_to_isize(b));
|
||||
}
|
||||
|
||||
void scc_ap_not(scc_ap_t *to, const scc_ap_t *from) {
|
||||
SCC_AP_ASSERT(to != nullptr && from != nullptr);
|
||||
ap_from_isize(to, ~ap_to_isize(from));
|
||||
}
|
||||
|
||||
/* ---------- unary arithmetic ---------- */
|
||||
|
||||
void scc_ap_neg(scc_ap_t *to, const scc_ap_t *from) {
|
||||
SCC_AP_ASSERT(to != nullptr && from != nullptr);
|
||||
isize val = ap_to_isize(from);
|
||||
if (val == INTPTR_MIN)
|
||||
SCC_AP_PANIC("scc_ap_neg: overflow (INTPTR_MIN)");
|
||||
ap_from_isize(to, -val);
|
||||
}
|
||||
|
||||
/* ---------- comparison ---------- */
|
||||
|
||||
int scc_ap_cmp(const scc_ap_t *a, const scc_ap_t *b) {
|
||||
SCC_AP_ASSERT(a != nullptr && b != nullptr);
|
||||
isize va = ap_to_isize(a);
|
||||
isize vb = ap_to_isize(b);
|
||||
if (va < vb) return -1;
|
||||
if (va > vb) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scc_ap_is_zero(const scc_ap_t *ap) {
|
||||
SCC_AP_ASSERT(ap != nullptr);
|
||||
return ap->data.digit == 0;
|
||||
}
|
||||
|
||||
int scc_ap_eql(const scc_ap_t *a, const scc_ap_t *b) {
|
||||
SCC_AP_ASSERT(a != nullptr && b != nullptr);
|
||||
SCC_AP_ASSERT(a->capacity == -1 && b->capacity == -1);
|
||||
if (a->len != b->len) {
|
||||
/* -0 == +0 */
|
||||
if (a->data.digit == 0 && b->data.digit == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return a->data.digit == b->data.digit;
|
||||
}
|
||||
|
||||
int scc_ap_dump(scc_ap_t *ap, ap_dump_fn dump_fn, void *user_data) {
|
||||
SCC_AP_ASSERT(ap != nullptr && dump_fn != nullptr);
|
||||
SCC_AP_ASSERT(ap->capacity == -1);
|
||||
|
||||
isize val = ap_to_isize(ap);
|
||||
|
||||
if (val == 0) {
|
||||
dump_fn('0', user_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Buffer large enough for INT64_MIN "-9223372036854775808" */
|
||||
char buf[24];
|
||||
int pos = sizeof(buf);
|
||||
|
||||
if (val < 0) {
|
||||
dump_fn('-', user_data);
|
||||
/* Work with positive magnitude to avoid overflow when printing */
|
||||
uint64_t mag = ap->data.digit;
|
||||
while (mag > 0) {
|
||||
buf[--pos] = (char)('0' + (mag % 10));
|
||||
mag /= 10;
|
||||
}
|
||||
} else {
|
||||
uint64_t mag = (uint64_t)val;
|
||||
while (mag > 0) {
|
||||
buf[--pos] = (char)('0' + (mag % 10));
|
||||
mag /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = pos; i < (int)sizeof(buf); i++)
|
||||
dump_fn(buf[i], user_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
1028
runtime/ap/tests/test_ap.c
Normal file
1028
runtime/ap/tests/test_ap.c
Normal file
File diff suppressed because it is too large
Load Diff
184
runtime/ap/tests/test_ap_panic.c
Normal file
184
runtime/ap/tests/test_ap_panic.c
Normal file
@@ -0,0 +1,184 @@
|
||||
#include <ap.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <utest/acutest.h>
|
||||
|
||||
/*
|
||||
* Panic / overflow tests — each test calls SCC_AP_PANIC which aborts the
|
||||
* process. Run this file separately from the normal tests.
|
||||
*/
|
||||
|
||||
/* ---------- helper: attempt an operation and report result ---------- */
|
||||
|
||||
#define TRY_PANIC(call, label) \
|
||||
do { \
|
||||
fprintf(stderr, " " label " ... "); \
|
||||
call; \
|
||||
fprintf(stderr, "FAIL (no panic)\n"); \
|
||||
TEST_CHECK(0 && "expected panic"); \
|
||||
} while (0)
|
||||
|
||||
void test_add_overflow_positive(void) {
|
||||
scc_ap_t a, b, r;
|
||||
scc_ap_init(&a);
|
||||
scc_ap_init(&b);
|
||||
scc_ap_init(&r);
|
||||
scc_ap_from_string(&a, "9223372036854775807", -1, 10);
|
||||
scc_ap_set_int(&b, 1);
|
||||
TRY_PANIC(scc_ap_add(&r, &a, &b), "INTPTR_MAX + 1");
|
||||
}
|
||||
|
||||
void test_add_overflow_negative(void) {
|
||||
scc_ap_t a, b, r;
|
||||
scc_ap_init(&a);
|
||||
scc_ap_init(&b);
|
||||
scc_ap_init(&r);
|
||||
scc_ap_from_string(&a, "-9223372036854775808", -1, 10);
|
||||
scc_ap_set_int(&b, -1);
|
||||
TRY_PANIC(scc_ap_add(&r, &a, &b), "INTPTR_MIN + (-1)");
|
||||
}
|
||||
|
||||
void test_mul_overflow(void) {
|
||||
scc_ap_t a, b, r;
|
||||
scc_ap_init(&a);
|
||||
scc_ap_init(&b);
|
||||
scc_ap_init(&r);
|
||||
scc_ap_from_string(&a, "4611686018427387904", -1, 10); /* INT64_MAX/2 + 1 */
|
||||
scc_ap_set_int(&b, 2);
|
||||
TRY_PANIC(scc_ap_mul(&r, &a, &b), "(INT64_MAX/2+1) * 2");
|
||||
}
|
||||
|
||||
void test_div_by_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, 1);
|
||||
scc_ap_set_int(&b, 0);
|
||||
TRY_PANIC(scc_ap_div(&r, &a, &b), "1 / 0");
|
||||
}
|
||||
|
||||
void test_mod_by_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, 1);
|
||||
scc_ap_set_int(&b, 0);
|
||||
TRY_PANIC(scc_ap_mod(&r, &a, &b), "1 % 0");
|
||||
}
|
||||
|
||||
void test_from_string_overflow(void) {
|
||||
scc_ap_t ap;
|
||||
scc_ap_init(&ap);
|
||||
TRY_PANIC(scc_ap_from_string(&ap, "18446744073709551615", -1, 10),
|
||||
"UINT64_MAX as string");
|
||||
}
|
||||
|
||||
void test_set_digit_overflow(void) {
|
||||
scc_ap_t ap;
|
||||
scc_ap_init(&ap);
|
||||
TRY_PANIC(scc_ap_set_digit(&ap, (scc_ap_digit)18446744073709551615ULL),
|
||||
"set_digit(UINT64_MAX)");
|
||||
}
|
||||
|
||||
void test_sub_underflow(void) {
|
||||
scc_ap_t a, b, r;
|
||||
scc_ap_init(&a);
|
||||
scc_ap_init(&b);
|
||||
scc_ap_init(&r);
|
||||
scc_ap_from_string(&a, "-9223372036854775808", -1, 10);
|
||||
scc_ap_set_int(&b, 1);
|
||||
TRY_PANIC(scc_ap_sub(&r, &a, &b), "INTPTR_MIN - 1");
|
||||
}
|
||||
|
||||
void test_div_overflow(void) {
|
||||
scc_ap_t a, b, r;
|
||||
scc_ap_init(&a);
|
||||
scc_ap_init(&b);
|
||||
scc_ap_init(&r);
|
||||
scc_ap_from_string(&a, "-9223372036854775808", -1, 10);
|
||||
scc_ap_set_int(&b, -1);
|
||||
TRY_PANIC(scc_ap_div(&r, &a, &b), "INTPTR_MIN / -1");
|
||||
}
|
||||
|
||||
void test_mod_overflow(void) {
|
||||
scc_ap_t a, b, r;
|
||||
scc_ap_init(&a);
|
||||
scc_ap_init(&b);
|
||||
scc_ap_init(&r);
|
||||
scc_ap_from_string(&a, "-9223372036854775808", -1, 10);
|
||||
scc_ap_set_int(&b, -1);
|
||||
TRY_PANIC(scc_ap_mod(&r, &a, &b), "INTPTR_MIN % -1");
|
||||
}
|
||||
|
||||
void test_mul_overflow_neg_limit(void) {
|
||||
scc_ap_t a, b, r;
|
||||
scc_ap_init(&a);
|
||||
scc_ap_init(&b);
|
||||
scc_ap_init(&r);
|
||||
scc_ap_from_string(&a, "-9223372036854775808", -1, 10);
|
||||
scc_ap_set_int(&b, 2);
|
||||
TRY_PANIC(scc_ap_mul(&r, &a, &b), "INTPTR_MIN * 2");
|
||||
}
|
||||
|
||||
void test_with_bits_overflow(void) {
|
||||
scc_ap_t ap;
|
||||
scc_ap_init(&ap);
|
||||
TRY_PANIC(scc_ap_with_bits(&ap, 65), "with_bits(65)");
|
||||
}
|
||||
|
||||
/* ---------- shift overflow tests ---------- */
|
||||
|
||||
void test_shl_overflow(void) {
|
||||
scc_ap_t a, r;
|
||||
scc_ap_init(&a);
|
||||
scc_ap_init(&r);
|
||||
scc_ap_from_string(&a, "4611686018427387904", -1, 10); /* INT64_MAX/2+1 */
|
||||
TRY_PANIC(scc_ap_shl(&r, &a, 1), "(INT64_MAX/2+1) << 1");
|
||||
}
|
||||
|
||||
void test_shl_shift_ge_64(void) {
|
||||
scc_ap_t a, r;
|
||||
scc_ap_init(&a);
|
||||
scc_ap_init(&r);
|
||||
scc_ap_set_int(&a, 1);
|
||||
TRY_PANIC(scc_ap_shl(&r, &a, 64), "1 << 64");
|
||||
}
|
||||
|
||||
void test_shr_shift_ge_64(void) {
|
||||
scc_ap_t a, r;
|
||||
scc_ap_init(&a);
|
||||
scc_ap_init(&r);
|
||||
scc_ap_set_int(&a, 1);
|
||||
TRY_PANIC(scc_ap_shr(&r, &a, 64), "1 >> 64");
|
||||
}
|
||||
|
||||
void test_lshr_shift_ge_64(void) {
|
||||
scc_ap_t a, r;
|
||||
scc_ap_init(&a);
|
||||
scc_ap_init(&r);
|
||||
scc_ap_set_int(&a, 1);
|
||||
TRY_PANIC(scc_ap_lshr(&r, &a, 64), "1 lshr 64");
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{"test_add_overflow_positive", test_add_overflow_positive},
|
||||
{"test_add_overflow_negative", test_add_overflow_negative},
|
||||
{"test_mul_overflow", test_mul_overflow},
|
||||
{"test_mul_overflow_neg_limit", test_mul_overflow_neg_limit},
|
||||
{"test_div_by_zero", test_div_by_zero},
|
||||
{"test_div_overflow", test_div_overflow},
|
||||
{"test_mod_by_zero", test_mod_by_zero},
|
||||
{"test_mod_overflow", test_mod_overflow},
|
||||
{"test_sub_underflow", test_sub_underflow},
|
||||
{"test_from_string_overflow", test_from_string_overflow},
|
||||
{"test_set_digit_overflow", test_set_digit_overflow},
|
||||
{"test_with_bits_overflow", test_with_bits_overflow},
|
||||
/* shift overflow */
|
||||
{"test_shl_overflow", test_shl_overflow},
|
||||
{"test_shl_shift_ge_64", test_shl_shift_ge_64},
|
||||
{"test_shr_shift_ge_64", test_shr_shift_ge_64},
|
||||
{"test_lshr_shift_ge_64", test_lshr_shift_ge_64},
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
Reference in New Issue
Block a user