feat(ast2ir): 添加多种表达式和语句类型的TODO实现

添加了对CAST、COMPOUND、LVALUE、BUILTIN等表达式类型的支持,
以及SWITCH、CASE、DEFAULT等语句类型的框架实现。

fix(hir_dump): 修复整数值格式化显示问题

修改了整数值的获取方式,从原来的const_int.int32改为integer.data.digit,
并添加了hack注释说明。

fix(lir_module): 修复数据符号添加中的比较操作符错误

将赋值操作符'='改为相等比较操作符'==',修正了条件判断逻辑。

refactor(mir_x86): 改进寄存器分配和指令选择逻辑

添加了函数元数据字段用于虚拟寄存器计数,改进了移动指令的处理逻辑,
将条件分支相关代码替换为setcc指令序列。

fix(parser): 修正类型指针返回类型一致性

统一了类型获取函数的返回类型,从const指针改为非const指针,
确保类型系统的一致性。

fix(parser): 修复结构体类型解析中的类型分配问题

修改了匿名结构体类型的处理逻辑,确保类型声明能够正确挂载到AST中。

fix(config): 修正emit-target参数类型配置

将emit-target选项的参数类型从字符串改为布尔型,修正了配置解析。

test: 增加全局超时控制和测试优化

添加了全局超时机制防止测试无限等待,改进了测试运行器的统计信息输出。
This commit is contained in:
zzy
2026-05-06 18:06:33 +08:00
parent aa8a1ff8ce
commit 096177e7e8
11 changed files with 153 additions and 104 deletions

View File

@@ -609,8 +609,9 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
else else
return scc_hir_builder_load(&ctx->builder, field_ptr); return scc_hir_builder_load(&ctx->builder, field_ptr);
} }
case SCC_AST_EXPR_CAST: case SCC_AST_EXPR_CAST: {
break; TODO();
} break;
case SCC_AST_EXPR_SIZE_OF: { case SCC_AST_EXPR_SIZE_OF: {
TODO(); TODO();
// return scc_hir_builder_integer( // return scc_hir_builder_integer(
@@ -622,10 +623,14 @@ scc_hir_value_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx,
// &ctx->builder, scc_hir_builder_type_u64(&ctx->builder), val); // &ctx->builder, scc_hir_builder_type_u64(&ctx->builder), val);
} }
case SCC_AST_EXPR_COMPOUND: { case SCC_AST_EXPR_COMPOUND: {
TODO();
} break;
case SCC_AST_EXPR_LVALUE: {
TODO();
} break;
case SCC_AST_EXPR_BUILTIN: {
TODO();
} break; } break;
case SCC_AST_EXPR_LVALUE:
break;
// SCC_AST_EXPR_BUILTIN,// 内置表达式 ... directive map to ir builtin
case SCC_AST_EXPR_INT_LITERAL: { case SCC_AST_EXPR_INT_LITERAL: {
// FIXME maybe using some array to int; // FIXME maybe using some array to int;
scc_hir_type_ref_t type_ref = scc_hir_builder_type_i32(&ctx->builder); scc_hir_type_ref_t type_ref = scc_hir_builder_type_i32(&ctx->builder);
@@ -884,9 +889,17 @@ void scc_ast2ir_stmt(scc_ast2ir_ctx_t *ctx, const scc_ast_stmt_t *stmt) {
scc_hir_builder_set_current_bblock(&ctx->builder, exit_block); scc_hir_builder_set_current_bblock(&ctx->builder, exit_block);
break; break;
} }
// SCC_AST_STMT_SWITCH, // switch 语句 case SCC_AST_STMT_SWITCH: {
// SCC_AST_STMT_CASE, // case 语句 scc_hir_value_ref_t exit_block =
// SCC_AST_STMT_DEFAULT, // default 语句 scc_hir_builder_bblock(&ctx->builder, "switch_exit");
scc_hashtable_set(&ctx->break_cache, stmt, (void *)exit_block);
// TODO:
} break;
case SCC_AST_STMT_CASE:
case SCC_AST_STMT_DEFAULT:
UNREACHABLE();
break;
case SCC_AST_STMT_BREAK: { case SCC_AST_STMT_BREAK: {
scc_hir_bblock_ref_t target = scc_hir_bblock_ref_t target =
(usize)scc_hashtable_get(&ctx->break_cache, stmt->jump._target); (usize)scc_hashtable_get(&ctx->break_cache, stmt->jump._target);
@@ -1098,7 +1111,11 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
&ctx->builder, scc_hir_builder_type_i32(&ctx->builder), &val); &ctx->builder, scc_hir_builder_type_i32(&ctx->builder), &val);
scc_hashtable_set(&ctx->ast2ir_cache, item, scc_hashtable_set(&ctx->ast2ir_cache, item,
(void *)(usize)item_val_ref); (void *)(usize)item_val_ref);
scc_ap_set_int(&val, ++idx); // FIXME hack ap
idx = val.data.digit;
idx += 1;
// scc_ap_add 1 ();
scc_ap_set_int(&val, idx);
} }
} break; } break;
case SCC_AST_DECL_TYPEDEF: case SCC_AST_DECL_TYPEDEF:

View File

@@ -455,12 +455,12 @@ static void format_ref_or_value(scc_hir_dump_t *ctx,
scc_tree_dump_append_fmt(ctx->dump_ctx, "%%%u", value_ref); scc_tree_dump_append_fmt(ctx->dump_ctx, "%%%u", value_ref);
return; return;
} }
// FIXME if (value->tag == SCC_HIR_VALUE_TAG_INTEGER) {
// if (value->tag == SCC_HIR_VALUE_TAG_INTEGER) { // FIXME hack ap
// scc_tree_dump_append_fmt(ctx->dump_ctx, "%d", scc_tree_dump_append_fmt(ctx->dump_ctx, "%d",
// value->data.const_int.int32); value->data.integer.data.digit);
// return; return;
// } }
if (value->name && value->name[0] != '\0') { if (value->name && value->name[0] != '\0') {
scc_tree_dump_node(ctx->dump_ctx, "%%%u[%s]", value_ref, value->name); scc_tree_dump_node(ctx->dump_ctx, "%%%u[%s]", value_ref, value->name);
} else { } else {

View File

@@ -71,7 +71,7 @@ scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *lir_module,
scc_vec_push(lir_module->symbol_metas, meta); scc_vec_push(lir_module->symbol_metas, meta);
scc_cfg_symbol_id_t id = scc_cfg_symbol_id_t id =
scc_cfg_module_add_symbol(&lir_module->cfg_module, &sym); scc_cfg_module_add_symbol(&lir_module->cfg_module, &sym);
if (id = SCC_CFG_ID_nullptr) { if (id == SCC_CFG_ID_nullptr) {
/* 冲突时释放已分配的数据 */ /* 冲突时释放已分配的数据 */
scc_free(meta->data.init_data); scc_free(meta->data.init_data);
return SCC_CFG_ID_nullptr; return SCC_CFG_ID_nullptr;

View File

@@ -46,6 +46,7 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_instr_t *instr) {
typedef struct x86_isel { typedef struct x86_isel {
scc_mir_instr_vec_t instrs; scc_mir_instr_vec_t instrs;
scc_lir_func_meta_t *func_meta;
} x86_isel_t; } x86_isel_t;
static void add_instr(x86_isel_t *isel, const scc_mir_instr_t *instr) { static void add_instr(x86_isel_t *isel, const scc_mir_instr_t *instr) {
@@ -103,15 +104,14 @@ static scc_mir_operand_t lir_val_to_mir_op(const scc_lir_val_t *val) {
// 虚拟临时寄存器分配(简单递增) // 虚拟临时寄存器分配(简单递增)
static scc_mir_operand_t new_vreg_temp(x86_isel_t *isel) { static scc_mir_operand_t new_vreg_temp(x86_isel_t *isel) {
// FIXME return (scc_mir_operand_t){.kind = SCC_MIR_OP_VREG,
static int next_temp = 10000; // 避免与常规 vreg 冲突 .vreg = isel->func_meta->vregs_count++};
return (scc_mir_operand_t){.kind = SCC_MIR_OP_VREG, .vreg = next_temp++};
} }
static void emit_move(x86_isel_t *isel, scc_mir_operand_t dst, static void emit_move(x86_isel_t *isel, scc_mir_operand_t dst,
scc_mir_operand_t src, u8 size) { scc_mir_operand_t src, u8 size) {
if (dst.kind == SCC_MIR_OP_VREG || dst.kind == SCC_MIR_OP_PREG) { if (dst.kind == SCC_MIR_OP_VREG || dst.kind == SCC_MIR_OP_PREG) {
if (src.kind == SCC_MIR_OP_VREG) { if (src.kind == SCC_MIR_OP_VREG || src.kind == SCC_MIR_OP_PREG) {
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89, dst, src); add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89, dst, src);
} else if (src.kind == SCC_MIR_OP_IMM) { } else if (src.kind == SCC_MIR_OP_IMM) {
add_instr_2(isel, add_instr_2(isel,
@@ -126,7 +126,7 @@ static void emit_move(x86_isel_t *isel, scc_mir_operand_t dst,
UNREACHABLE(); UNREACHABLE();
} }
} else if (dst.kind == SCC_MIR_OP_MEM) { } else if (dst.kind == SCC_MIR_OP_MEM) {
if (src.kind == SCC_MIR_OP_VREG) { if (src.kind == SCC_MIR_OP_VREG || src.kind == SCC_MIR_OP_PREG) {
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, src); add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, src);
} else if (src.kind == SCC_MIR_OP_IMM) { } else if (src.kind == SCC_MIR_OP_IMM) {
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_IMMZ, dst, src); add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_IMMZ, dst, src);
@@ -158,51 +158,34 @@ static void emit_compare(x86_isel_t *isel, scc_mir_operand_t op0,
} }
} }
static scc_x86_iform_t cond_to_jcc(scc_lir_cond_t cond) { /* 条件码到 setcc 指令的映射 */
static scc_x86_iform_t cond_to_setcc(scc_lir_cond_t cond) {
switch (cond) { switch (cond) {
case SCC_LIR_COND_EQ: case SCC_LIR_COND_EQ:
return SCC_X86_IFORM_JZ_RELBRZ; return SCC_X86_IFORM_SETZ_GPR8;
case SCC_LIR_COND_NE: case SCC_LIR_COND_NE:
return SCC_X86_IFORM_JNZ_RELBRZ; return SCC_X86_IFORM_SETNZ_GPR8;
case SCC_LIR_COND_SLT: case SCC_LIR_COND_SLT:
return SCC_X86_IFORM_JL_RELBRZ; return SCC_X86_IFORM_SETL_GPR8;
case SCC_LIR_COND_SLE: case SCC_LIR_COND_SLE:
return SCC_X86_IFORM_JLE_RELBRZ; return SCC_X86_IFORM_SETLE_GPR8;
case SCC_LIR_COND_SGT: case SCC_LIR_COND_SGT:
return SCC_X86_IFORM_JNLE_RELBRZ; // JNLE = JG return SCC_X86_IFORM_SETNLE_GPR8; // SETG
case SCC_LIR_COND_SGE: case SCC_LIR_COND_SGE:
return SCC_X86_IFORM_JNL_RELBRZ; // JNL = JGE return SCC_X86_IFORM_SETNL_GPR8; // SETGE
case SCC_LIR_COND_ULT: case SCC_LIR_COND_ULT:
return SCC_X86_IFORM_JB_RELBRZ; return SCC_X86_IFORM_SETB_GPR8;
case SCC_LIR_COND_ULE: case SCC_LIR_COND_ULE:
return SCC_X86_IFORM_JBE_RELBRZ; return SCC_X86_IFORM_SETBE_GPR8;
case SCC_LIR_COND_UGT: case SCC_LIR_COND_UGT:
return SCC_X86_IFORM_JNBE_RELBRZ; // JNBE = JA return SCC_X86_IFORM_SETNBE_GPR8; // SETA
case SCC_LIR_COND_UGE: case SCC_LIR_COND_UGE:
return SCC_X86_IFORM_JNB_RELBRZ; // JNB = JAE return SCC_X86_IFORM_SETNB_GPR8; // SETAE
// 浮点比较暂不处理(需要 fcomi + jcc
default: default:
UNREACHABLE(); UNREACHABLE();
} }
} }
static void emit_compare_and_branch(x86_isel_t *isel, scc_lir_cond_t cond,
scc_mir_operand_t lhs,
scc_mir_operand_t rhs,
scc_mir_operand_t true_bb,
scc_mir_operand_t false_bb, u8 size) {
if (lhs.kind == SCC_MIR_OP_VREG && rhs.kind == SCC_MIR_OP_IMM)
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_IMMZ, lhs, rhs);
else if (lhs.kind == SCC_MIR_OP_VREG && rhs.kind == SCC_MIR_OP_VREG)
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_39, lhs, rhs);
else
UNREACHABLE();
scc_x86_iform_t jcc = cond_to_jcc(cond);
add_instr_1(isel, jcc, true_bb);
add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, false_bb);
}
static void emit_ret(x86_isel_t *isel, scc_lir_val_t ret_val) { static void emit_ret(x86_isel_t *isel, scc_lir_val_t ret_val) {
if (ret_val.kind != SCC_LIR_INSTR_KIND_NONE) { if (ret_val.kind != SCC_LIR_INSTR_KIND_NONE) {
scc_mir_operand_t rax = {.kind = SCC_MIR_OP_PREG, scc_mir_operand_t rax = {.kind = SCC_MIR_OP_PREG,
@@ -212,12 +195,19 @@ static void emit_ret(x86_isel_t *isel, scc_lir_val_t ret_val) {
add_instr_0(isel, SCC_X86_IFORM_RET_NEAR); add_instr_0(isel, SCC_X86_IFORM_RET_NEAR);
} }
static void emit_copy_if_needed(x86_isel_t *isel, scc_mir_operand_t dst,
scc_mir_operand_t src0, u8 size) {
if (dst.kind == SCC_MIR_OP_VREG && src0.kind == SCC_MIR_OP_VREG &&
dst.vreg == src0.vreg) {
return;
}
emit_move(isel, dst, src0, size);
}
static void emit_binary_op(x86_isel_t *isel, scc_lir_op_t op, static void emit_binary_op(x86_isel_t *isel, scc_lir_op_t op,
scc_mir_operand_t dst, scc_mir_operand_t src0, scc_mir_operand_t dst, scc_mir_operand_t src0,
scc_mir_operand_t src1, u8 size) { scc_mir_operand_t src1, u8 size) {
if (dst.kind == SCC_MIR_OP_VREG && src0.kind == SCC_MIR_OP_VREG && emit_copy_if_needed(isel, dst, src0, size);
dst.vreg != src0.vreg)
emit_move(isel, dst, src0, size);
bool is_imm = (src1.kind == SCC_MIR_OP_IMM); bool is_imm = (src1.kind == SCC_MIR_OP_IMM);
scc_x86_iform_t iform; scc_x86_iform_t iform;
@@ -297,6 +287,9 @@ static void sel_mir(x86_isel_t *isel, const scc_lir_instr_t *instr) {
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, src0); add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, src0);
break; break;
case SCC_LIR_STORE_ADDR:
TODO();
break;
case SCC_LIR_STORE: case SCC_LIR_STORE:
// 将 src0 存入 [src1] // 将 src0 存入 [src1]
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, src1, src0); add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, src1, src0);
@@ -327,9 +320,7 @@ static void sel_mir(x86_isel_t *isel, const scc_lir_instr_t *instr) {
case SCC_LIR_MUL: case SCC_LIR_MUL:
// imul dst, src0, src1 → 需要 mov + imul // imul dst, src0, src1 → 需要 mov + imul
if (src0.kind == SCC_MIR_OP_VREG && dst.kind == SCC_MIR_OP_VREG && emit_copy_if_needed(isel, dst, src0, size);
src0.vreg != dst.vreg)
emit_move(isel, dst, src0, size);
add_instr_2(isel, SCC_X86_IFORM_IMUL_GPRV_GPRV, dst, src1); add_instr_2(isel, SCC_X86_IFORM_IMUL_GPRV_GPRV, dst, src1);
break; break;
@@ -337,9 +328,7 @@ static void sel_mir(x86_isel_t *isel, const scc_lir_instr_t *instr) {
case SCC_LIR_SHR: case SCC_LIR_SHR:
case SCC_LIR_SAR: case SCC_LIR_SAR:
// 双地址dst = dst op count // 双地址dst = dst op count
if (src0.kind == SCC_MIR_OP_VREG && dst.kind == SCC_MIR_OP_VREG && emit_copy_if_needed(isel, dst, src0, size);
src0.vreg != dst.vreg)
emit_move(isel, dst, src0, size);
if (src1.kind == SCC_MIR_OP_IMM) { if (src1.kind == SCC_MIR_OP_IMM) {
scc_x86_iform_t iform; scc_x86_iform_t iform;
@@ -415,25 +404,46 @@ static void sel_mir(x86_isel_t *isel, const scc_lir_instr_t *instr) {
break; break;
} }
/* ---- 比较与分支 ---- */ /* ---- 比较指令 ---- */
case SCC_LIR_CMP: case SCC_LIR_CMP: {
// 比较并设置标志位,结果通过后续 BR 使用。 // 1. 比较并设置标志位
// 当前 LIR 中 CMP 不直接生成 setcc需要配合分支。 if (src0.kind == SCC_MIR_OP_VREG && src1.kind == SCC_MIR_OP_IMM)
emit_compare(isel, src0, src1, size); add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_IMMZ, src0, src1);
// 如果有需要将比较结果写入 to即 bool 值),可后续添加 SETcc else if (src0.kind == SCC_MIR_OP_VREG && src1.kind == SCC_MIR_OP_VREG)
break; add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_39, src0, src1);
else
UNREACHABLE();
// 2. 标志位 -> 布尔值 (写入 dst)
scc_x86_iform_t setcc = cond_to_setcc(instr->metadata.cond);
add_instr_1(isel, setcc, dst); // 注意 setcc 只写低 8 位
// 若需 32/64 位布尔值,可再 movzx dst, dst
if (size > 1) {
// movzx dst, dst (假设 MOVZX_GPRV_GPR8 存在;这里临时用 and 模拟)
// 简单处理:用 and dst, 1 清理高位
scc_mir_operand_t one = {.kind = SCC_MIR_OP_IMM, .imm = 1};
add_instr_2(isel, SCC_X86_IFORM_AND_GPRV_IMMZ, dst, one);
}
break;
}
/* ---- 条件分支 ---- */
case SCC_LIR_BR: { case SCC_LIR_BR: {
// 条件分支:依赖前一条 CMP 设置的标志位 // arg0 是 CMP 产生的布尔值 (0 或 1)
// 问题LIR 的 BR 未携带条件码,实际需要依据前一条 CMP 的条件。 // test src0, src0 ; jnz true_bb ; jmp false_bb
// 这里暂时无法精确生成 jcc故保留原始构造假的直接跳转待上层 IR 合并 scc_mir_operand_t true_bb = {.kind = SCC_MIR_OP_BLOCK,
// CMP+BR 后再完善。 以下代码仅为占位,实际不可用。 scc_mir_operand_t .block_id =
// true_bb = { .kind = SCC_MIR_OP_BLOCK, .block_id = instr->metadata.br.true_target};
// instr->metadata.br.true_target }; scc_mir_operand_t false_bb = { scc_mir_operand_t false_bb = {.kind = SCC_MIR_OP_BLOCK,
// .kind = SCC_MIR_OP_BLOCK, .block_id = instr->metadata.br.false_target .block_id =
// }; add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, true_bb); // instr->metadata.br.false_target};
// 不合理占位
UNREACHABLE(); // 当前不可达,要求上层保证 CMP+BR 合并 // test src0, src0
add_instr_2(isel, SCC_X86_IFORM_TEST_GPRV_GPRV, src0, src0);
// jnz true
add_instr_1(isel, SCC_X86_IFORM_JNZ_RELBRZ, true_bb);
// jmp false
add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, false_bb);
break; break;
} }
@@ -448,7 +458,6 @@ static void sel_mir(x86_isel_t *isel, const scc_lir_instr_t *instr) {
case SCC_LIR_CALL: case SCC_LIR_CALL:
emit_call(isel, instr->metadata.call.callee, dst); emit_call(isel, instr->metadata.call.callee, dst);
break; break;
case SCC_LIR_RET: case SCC_LIR_RET:
emit_ret(isel, instr->metadata.ret_val); emit_ret(isel, instr->metadata.ret_val);
break; break;
@@ -478,6 +487,7 @@ static void sel_func(const scc_lir_module_t *lir_module,
const scc_lir_func_t *func) { const scc_lir_func_t *func) {
x86_isel_t isel; x86_isel_t isel;
isel.func_meta = SCC_LIR_FUNC_META(func);
scc_vec_foreach(func->bblocks, i) { scc_vec_foreach(func->bblocks, i) {
scc_vec_init(isel.instrs); scc_vec_init(isel.instrs);
@@ -507,7 +517,7 @@ void scc_isel_x86_64(scc_mir_module_t *mir_module,
Assert(func_meta != nullptr); Assert(func_meta != nullptr);
scc_mir_func_meta_init(func_meta); scc_mir_func_meta_init(func_meta);
scc_vec_push(mir_module->func_metas, func_meta); scc_vec_push(mir_module->func_metas, func_meta);
func->meta = func_meta;
sel_func(lir_module, func); sel_func(lir_module, func);
func->meta = func_meta;
} }
} }

View File

@@ -21,8 +21,6 @@ typedef struct scc_parser {
int errcode; int errcode;
} scc_parser_t; } scc_parser_t;
// static inline scc_ast_qual_type_t *scc_parser_
/** /**
* @brief 初始化解析器 * @brief 初始化解析器
* @param parser 解析器实例 * @param parser 解析器实例
@@ -120,8 +118,8 @@ static inline void scc_parse_type_sema(scc_parser_t *parser,
scc_sema_type(parser, type ? type->base.type : SCC_AST_UNKNOWN, type); scc_sema_type(parser, type ? type->base.type : SCC_AST_UNKNOWN, type);
} }
static inline const scc_ast_qual_type_t * static inline scc_ast_qual_type_t *scc_parse_got_type(scc_parser_t *parser,
scc_parse_got_type(scc_parser_t *parser, const char *name) { const char *name) {
return parser->sema_ctx->got_type(parser->sema_ctx, name); return parser->sema_ctx->got_type(parser->sema_ctx, name);
} }

View File

@@ -10,8 +10,8 @@ typedef struct scc_sema_ctx scc_sema_ctx_t;
typedef void (*scc_sema_callback_t)(scc_sema_ctx_t *context, typedef void (*scc_sema_callback_t)(scc_sema_ctx_t *context,
scc_ast_node_kind_t node_type, void *node); scc_ast_node_kind_t node_type, void *node);
typedef const scc_ast_qual_type_t *(*scc_sema_got_type_t)( typedef scc_ast_qual_type_t *(*scc_sema_got_type_t)(scc_sema_ctx_t *context,
scc_sema_ctx_t *context, const char *name); const char *name);
/** /**
* @brief 语义分析回调集合 * @brief 语义分析回调集合

View File

@@ -573,7 +573,7 @@ static scc_ast_qual_type_t *parse_record_type(scc_parser_t *parser,
UNREACHABLE(); UNREACHABLE();
break; break;
} }
const scc_ast_qual_type_t *type = nullptr; scc_ast_qual_type_t *type = nullptr;
if (name == nullptr) { if (name == nullptr) {
name = "<anonymous>"; name = "<anonymous>";
} }
@@ -581,7 +581,6 @@ static scc_ast_qual_type_t *parse_record_type(scc_parser_t *parser,
type = scc_parse_got_type(parser, scc_str_as_cstr(&symbol_name)); type = scc_parse_got_type(parser, scc_str_as_cstr(&symbol_name));
if (type == nullptr) { if (type == nullptr) {
new_type:
scc_ast_canon_type_t *canon = scc_ast_ctx_alloc_type(parser->ast_ctx); scc_ast_canon_type_t *canon = scc_ast_ctx_alloc_type(parser->ast_ctx);
scc_ast_decl_t *decl = SCC_AST_ALLOC_DECL(parser->ast_ctx); scc_ast_decl_t *decl = SCC_AST_ALLOC_DECL(parser->ast_ctx);
@@ -602,7 +601,12 @@ static scc_ast_qual_type_t *parse_record_type(scc_parser_t *parser,
} }
_scc_ast_decl_record_init(decl, decl_kind, name, nullptr, *pos); _scc_ast_decl_record_init(decl, decl_kind, name, nullptr, *pos);
const scc_ast_qual_type_t *qual_type = // FIXME 必须立即挂载到AST但是需要hack
{
scc_vec_push(parser->translation_unit->declarations, decl);
}
scc_ast_qual_type_t *qual_type =
SCC_AST_ALLOC_QUAL_TYPE(parser->ast_ctx); SCC_AST_ALLOC_QUAL_TYPE(parser->ast_ctx);
_scc_ast_type_record_init(qual_type, canon, type_kind, name, decl, _scc_ast_type_record_init(qual_type, canon, type_kind, name, decl,
*pos); *pos);

View File

@@ -9,8 +9,8 @@ static void dummy_sema_callback(scc_sema_ctx_t *context,
return; return;
} }
static const scc_ast_qual_type_t * static scc_ast_qual_type_t *dummy_got_type_callback(scc_sema_ctx_t *context,
dummy_got_type_callback(scc_sema_ctx_t *context, const char *name) { const char *name) {
(void)context; (void)context;
(void)name; (void)name;
return nullptr; return nullptr;
@@ -61,6 +61,7 @@ scc_ast_translation_unit_t *scc_parse_translation_unit(scc_parser_t *parser) {
return nullptr; return nullptr;
unit->base.type = SCC_AST_TRANSLATION_UNIT; unit->base.type = SCC_AST_TRANSLATION_UNIT;
scc_vec_init(unit->declarations); scc_vec_init(unit->declarations);
parser->translation_unit = unit;
/** /**
* Program := (Declaration | Definition)* * Program := (Declaration | Definition)*

View File

@@ -3,8 +3,8 @@
#include <scc_sema.h> #include <scc_sema.h>
#include <sema_symtab.h> #include <sema_symtab.h>
static const scc_ast_qual_type_t *got_type_callback(scc_sema_ctx_t *sema_ctx, static scc_ast_qual_type_t *got_type_callback(scc_sema_ctx_t *sema_ctx,
const char *name); const char *name);
static void gen_symbol_name(const scc_ast_decl_t *decl, scc_str_t *name) { static void gen_symbol_name(const scc_ast_decl_t *decl, scc_str_t *name) {
switch (decl->base.type) { switch (decl->base.type) {
@@ -219,8 +219,8 @@ static void decl_callback(scc_sema_ctx_t *sema_ctx,
return; return;
} }
static const scc_ast_qual_type_t *got_type_callback(scc_sema_ctx_t *sema_ctx, static scc_ast_qual_type_t *got_type_callback(scc_sema_ctx_t *sema_ctx,
const char *name) { const char *name) {
scc_sema_symtab_t *sema_symtab = sema_ctx->context; scc_sema_symtab_t *sema_symtab = sema_ctx->context;
scc_ast_node_t *node = scc_sema_symtab_lookup_symbol(sema_symtab, name); scc_ast_node_t *node = scc_sema_symtab_lookup_symbol(sema_symtab, name);
if (SCC_AST_IS_A(scc_ast_qual_type_t, node)) { if (SCC_AST_IS_A(scc_ast_qual_type_t, node)) {

View File

@@ -227,8 +227,7 @@ static void setup_argparse(scc_argparse_t *argparse, scc_config_t *config,
scc_argparse_opt_t opt_emit_target; scc_argparse_opt_t opt_emit_target;
scc_argparse_opt_init(&opt_emit_target, 0, "emit-target", scc_argparse_opt_init(&opt_emit_target, 0, "emit-target",
scc_hints[SCC_HINT_EMIT_TARGET]); scc_hints[SCC_HINT_EMIT_TARGET]);
scc_argparse_spec_setup_string(&opt_emit_target.spec, scc_argparse_spec_setup_bool(&opt_emit_target.spec, &(config->emit_target));
&(config->emit_target));
scc_argparse_cmd_add_opt(root, &opt_emit_target); scc_argparse_cmd_add_opt(root, &opt_emit_target);
} }

View File

@@ -14,6 +14,7 @@ import sys
import tempfile import tempfile
import tomllib import tomllib
import uuid import uuid
import time
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Sequence from typing import Sequence
@@ -24,7 +25,7 @@ from typing import Sequence
WORKSPACE = Path(__file__).resolve().parent WORKSPACE = Path(__file__).resolve().parent
CC_PATH = WORKSPACE / "../../build/dev/scc" CC_PATH = WORKSPACE / "../../build/dev/scc"
CONFIG_PATH = WORKSPACE / "expect.toml" CONFIG_PATH = WORKSPACE / "expect.toml"
DEFAULT_TIMEOUT = 10 # seconds DEFAULT_TIMEOUT = 1 # seconds
logger = logging.getLogger("scc-test") logger = logging.getLogger("scc-test")
@@ -173,14 +174,30 @@ class Runner:
except OSError: except OSError:
pass pass
def run_all(self, tests: Sequence[TestCase]) -> tuple[int, int]: def run_all(self, tests: Sequence[TestCase], global_timeout: float | None = None) -> tuple[int, int]:
"""Run a sequence of tests. Returns (passed, total).""" """Run a sequence of tests. Returns (passed, total)."""
passed = 0 passed = 0
tested = 0
start_time = time.monotonic()
for idx, test in enumerate(tests, start=1): for idx, test in enumerate(tests, start=1):
if global_timeout is not None and (time.monotonic() - start_time) >= global_timeout:
logger.warning(
"Global timeout (%.1fs) reached - skipping remaining %d tests.",
global_timeout, len(tests) - tested
)
break
logger.info("(%d/%d) %s", idx, len(tests), test.description) logger.info("(%d/%d) %s", idx, len(tests), test.description)
if self.run_one(test): if self.run_one(test):
passed += 1 passed += 1
return passed, len(tests) tested += 1
total_skipped = len(tests) - tested
if total_skipped > 0:
logger.warning("%d tests skipped due to global timeout.", total_skipped)
return passed, tested
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -302,8 +319,8 @@ def main() -> None:
return return
# Filter tests # Filter tests
tests = select_tests(all_tests, args.tests) selected = select_tests(all_tests, args.tests)
if not tests: if not selected:
logger.warning("No tests to run.") logger.warning("No tests to run.")
return return
@@ -314,11 +331,14 @@ def main() -> None:
keep_temps=args.keep_temps, keep_temps=args.keep_temps,
) )
passed, total = runner.run_all(tests) global_timeout = DEFAULT_TIMEOUT * 3
passed, total = runner.run_all(selected, global_timeout)
logger.info("=" * 40) logger.info("=" * 40)
logger.info("Summary: %d/%d passed", passed, total) if global_timeout and total < len(selected):
if passed != total: logger.info("Summary: %d/%d passed (%d skipped due to timeout)",
sys.exit(1) passed, total, len(selected) - total)
else:
logger.info("Summary: %d/%d passed", passed, total)
runner.cleanup() runner.cleanup()