stage1 初步实现

This commit is contained in:
zzy
2026-08-06 19:26:30 +08:00
parent a56b4cbb70
commit 314100afbc
35 changed files with 556 additions and 2236 deletions

View File

@@ -1,4 +1,4 @@
// WRITE BY AI
// WRITE BY AI
/* spl_sema.c SPL 语义分析
*
* 两趟 AST 遍历splc0 显式先 run 再 check
@@ -9,6 +9,7 @@
* 命名实体放 def_table两张表 id 空间完全独立。
*/
#include "spl_sema.h"
#include "spl_builtin.h"
#include <stdio.h>
#include <string.h>
@@ -456,6 +457,13 @@ static void sema_const_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_
if (!n)
return;
register_binding(sema, n->const_decl.name, n->const_decl.type_expr, scope, agg_def, ref);
/* 标记 const赋值检查拒绝写入 */
spl_ast_node_t *nn = node_at(sema->ast, ref);
if (nn && nn->resolved_def_id) {
spl_def_node_t *d = def_at(sema, nn->resolved_def_id);
if (d)
d->var_def.is_const = 1;
}
}
/* fn 声明:建 fn type + FN_PARAMS def + 登记名字。不建 fn_scope由 check 新建)。
@@ -580,6 +588,29 @@ static bool expr_is_int_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) {
}
}
/* 浮点字面量(含负号前缀):允许拓宽/窄化到目标浮点类型 */
static bool expr_is_float_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) {
spl_ast_node_t *n = node_at(sema->ast, ref);
if (!n || n->kind != SPL_AST_EXPR)
return false;
switch (n->expr.op) {
case SPL_AST_PRIMARY_EXPR: {
spl_ast_node_t *pn = node_at(sema->ast, n->expr.op_expr.left);
int k = pn && pn->kind == SPL_AST_EXPR ? (int)pn->primary_expr.kind : -1;
return k == SPL_AST_FLOAT;
}
case SPL_AST_PREFIX_EXPR:
return expr_is_float_literal(sema, n->expr.op_expr.left);
default:
return false;
}
}
/* 字面量(整型或浮点):检查时允许类型拓宽 */
static bool expr_is_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) {
return expr_is_int_literal(sema, ref) || expr_is_float_literal(sema, ref);
}
/* 打开 SPL_TYPE_ID 绑定节点返回真实类型newtype 预留;当前无调用产生该节点) */
static spl_type_id_t underlying(spl_sema_t *sema, spl_type_id_t tid) {
spl_type_node_t *t = type_node(sema, tid);
@@ -650,6 +681,9 @@ static int type_compatible(spl_sema_t *sema, spl_type_id_t dst, spl_type_id_t sr
/* 字面量值已隐含满足范围(检查时由调用方保证),此处允许拓宽 */
return 1;
}
/* 浮点字面量可赋值到目标浮点f64 字面量 → f32 变量,值可表示则允许) */
if (is_literal && d->kind == SPL_TYPE_FLOAT && s->kind == SPL_TYPE_FLOAT)
return 1;
/* isize/usize机器字宽与 i32 混合:比较/算术/传参可用splc1 与旧测试事实标准) */
if (d->kind == SPL_TYPE_INT && s->kind == SPL_TYPE_INT) {
int dbits = d->int_type.bits, sbits = s->int_type.bits;
@@ -772,8 +806,8 @@ static spl_type_id_t infer_binary_cmp(spl_sema_t *sema, spl_ast_node_ref_t ref,
return 0;
}
int w = 0;
if (type_compatible(sema, l, r, expr_is_int_literal(sema, e->expr.op_expr.right), &w) ||
type_compatible(sema, r, l, expr_is_int_literal(sema, e->expr.op_expr.left), &w)) {
if (type_compatible(sema, l, r, expr_is_literal(sema, e->expr.op_expr.right), &w) ||
type_compatible(sema, r, l, expr_is_literal(sema, e->expr.op_expr.left), &w)) {
return spl_type_bool(&sema->type);
}
sema_error(sema, ref, "type mismatch in comparison");
@@ -919,7 +953,7 @@ static spl_type_id_t infer_agg_init(spl_sema_t *sema, spl_ast_node_ref_t ref, sp
int w = 0;
if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et &&
!type_compatible(sema, mt, et,
expr_is_int_literal(sema, item->aggregate_init_item.expr), &w)) {
expr_is_literal(sema, item->aggregate_init_item.expr), &w)) {
sema_error(sema, iref, "field type mismatch in aggregate literal");
}
}
@@ -942,8 +976,7 @@ static spl_type_id_t infer_array_lit(spl_sema_t *sema, spl_ast_node_ref_t ref, s
int w = 0;
if (!type_compatible(
sema, elem, et,
expr_is_int_literal(sema, pn->primary_expr.array_lit_expr.expr_list.data[i]),
&w)) {
expr_is_literal(sema, pn->primary_expr.array_lit_expr.expr_list.data[i]), &w)) {
sema_error(sema, pn->primary_expr.array_lit_expr.expr_list.data[i],
"element type mismatch in array literal");
}
@@ -1017,16 +1050,35 @@ static spl_type_id_t infer_primary(spl_sema_t *sema, spl_ast_node_ref_t ref, spl
return infer_expr(sema, pn->primary_expr.expr);
case SPL_AST_ARRAY_LIT:
return infer_array_lit(sema, ref, n);
case SPL_AST_BUILTIN_EXPR:
/* 内置调用:先推断实参,类型按名称约定 */
for (usize i = 0; i < pn->primary_expr.builtin_expr.expr_list.size; i++)
case SPL_AST_BUILTIN_EXPR: {
/* 内置调用:类型按注册表约定参数按需推断offsetof 字段名参数非表达式) */
const spl_builtin_t *bi = spl_builtin_lookup(pn->primary_expr.builtin_expr.ident);
if (!bi) {
sema_error(sema, ref, "unknown builtin");
return 0;
}
usize nargs = pn->primary_expr.builtin_expr.expr_list.size;
if (nargs < (usize)bi->min_args || (bi->max_args >= 0 && nargs > (usize)bi->max_args)) {
char buf[96];
snprintf(buf, sizeof buf, "builtin @%s: arg count mismatch", bi->name);
sema_error(sema, ref, buf);
return 0;
}
for (usize i = 0; i < nargs; i++) {
/* offsetof 第二参数为字段标识符,不按表达式推断 */
if (bi->kind == SPL_BUILTIN_OFFSET_OF && i == 1)
continue;
infer_expr(sema, pn->primary_expr.builtin_expr.expr_list.data[i]);
if (strcmp(pn->primary_expr.builtin_expr.ident, "sizeof") == 0)
return spl_type_int(&sema->type, sizeof(usize) * 8, 0);
if (strcmp(pn->primary_expr.builtin_expr.ident, "dbg") == 0 ||
strcmp(pn->primary_expr.builtin_expr.ident, "assert") == 0)
}
if (bi->ret_is_void)
return spl_type_void(&sema->type);
return spl_type_void(&sema->type);
if (bi->kind == SPL_BUILTIN_SIZE_OF || bi->kind == SPL_BUILTIN_BITSIZE_OF ||
bi->kind == SPL_BUILTIN_ALIGN_OF || bi->kind == SPL_BUILTIN_OFFSET_OF ||
bi->kind == SPL_BUILTIN_FIELD_COUNT)
return spl_type_int(&sema->type, sizeof(usize) * 8, 0);
sema_error(sema, ref, "unsupported builtin");
return 0;
}
case SPL_AST_BLOCK_EXPR: {
/* 块表达式:有独立 scope逐语句检查返回末尾表达式类型无则 void */
spl_ast_node_ref_vec_t *items = &pn->primary_expr.block_expr;
@@ -1223,7 +1275,7 @@ static spl_type_id_t infer_postfix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl
int w = 0;
if (!expr_is_null_literal(sema, args->data[i]) && at &&
!type_compatible(sema, t->fn_type.params.data[i], at,
expr_is_int_literal(sema, args->data[i]), &w)) {
expr_is_literal(sema, args->data[i]), &w)) {
sema_error(sema, args->data[i], "argument type mismatch");
}
}
@@ -1299,10 +1351,24 @@ static spl_type_id_t infer_expr(spl_sema_t *sema, spl_ast_node_ref_t ref) {
sema_error(sema, ref, "bad assignment");
return 0;
}
/* 不可写检查:赋值目标为 const 变量时拒绝 */
{
spl_ast_node_t *lhs = node_at(sema->ast, n->expr.op_expr.left);
if (lhs && lhs->kind == SPL_AST_EXPR && lhs->expr.op == SPL_AST_PRIMARY_EXPR) {
spl_ast_node_t *lpn = node_at(sema->ast, lhs->expr.op_expr.left);
if (lpn && lpn->kind == SPL_AST_EXPR &&
lpn->primary_expr.kind == SPL_AST_IDENT && lpn->resolved_def_id) {
spl_def_node_t *ld = def_at(sema, lpn->resolved_def_id);
if (ld && ld->kind == SPL_DEF_VAR && ld->var_def.is_const) {
sema_error(sema, ref, "cannot assign to const");
return 0;
}
}
}
}
int w = 0;
if (!expr_is_null_literal(sema, n->expr.op_expr.right) &&
!type_compatible(sema, l, r, expr_is_int_literal(sema, n->expr.op_expr.right),
&w)) {
!type_compatible(sema, l, r, expr_is_literal(sema, n->expr.op_expr.right), &w)) {
sema_error(sema, ref, "assignment type mismatch");
return 0;
}
@@ -1361,7 +1427,7 @@ static void check_var_init(spl_sema_t *sema, spl_ast_node_ref_t ref, const char
if (dt) {
int w = 0;
if (!expr_is_null_literal(sema, init_expr) && it &&
!type_compatible(sema, dt, it, expr_is_int_literal(sema, init_expr), &w)) {
!type_compatible(sema, dt, it, expr_is_literal(sema, init_expr), &w)) {
sema_error(sema, ref, "initializer type mismatch");
} else if (w) {
sema_warn(sema, ref, "pointer conversion involves wildcard");
@@ -1427,7 +1493,7 @@ static spl_type_id_t infer_agg_init_with_type(spl_sema_t *sema, spl_ast_node_ref
int w = 0;
if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et &&
!type_compatible(sema, mt, et,
expr_is_int_literal(sema, item->aggregate_init_item.expr), &w)) {
expr_is_literal(sema, item->aggregate_init_item.expr), &w)) {
sema_error(sema, iref, "field type mismatch in aggregate literal");
}
}
@@ -1492,6 +1558,33 @@ static void check_match(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t
sema_error(sema, ref, "match: arm pattern/body count mismatch");
return;
}
/* 穷举检查enum 必须覆盖所有变体,或含通配 _含表达式的整数 match 免检) */
{
spl_def_id_t adef = def_for_type(sema, mtype);
spl_def_node_t *ad = adef ? &sema->type.def_table.data[adef] : NULL;
int is_enum_agg = ad && ad->kind == SPL_DEF_AGG;
if (is_enum_agg) {
int has_wild = 0;
usize covered = 0;
for (usize i = 0; i < arms->size; i++) {
spl_ast_node_t *pk = node_at(sema->ast, arms->data[i]);
if (!pk)
continue;
/* _ 通配ident 与 expr 均为空 */
if (!pk->packed_expr.ident && !pk->packed_expr.expr) {
has_wild = 1;
break;
}
if (pk->packed_expr.ident) {
/* 变体被覆盖:匹配臂中出现的合法变体计数 */
if (agg_member_type(sema, mtype, pk->packed_expr.ident))
covered++;
}
}
if (!has_wild && covered < ad->agg_def.size)
sema_error(sema, ref, "match must be exhaustive");
}
}
for (usize i = 0; i < arms->size; i++) {
spl_ast_node_t *pk = node_at(sema->ast, arms->data[i]);
if (!pk)
@@ -1517,7 +1610,7 @@ static void check_match(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t
spl_type_id_t et = infer_expr(sema, pk->packed_expr.expr);
int w = 0;
if (is_int_tid(sema, mtype) && et &&
!type_compatible(sema, mtype, et, expr_is_int_literal(sema, pk->packed_expr.expr),
!type_compatible(sema, mtype, et, expr_is_literal(sema, pk->packed_expr.expr),
&w)) {
sema_error(sema, pk->packed_expr.expr, "match arm pattern type mismatch");
}
@@ -1625,7 +1718,7 @@ static void check_stmt(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_sema_ctx_t
if (ctx.ret) {
if (!expr_is_null_literal(sema, rd->block_item.ret_statement.expr) && et &&
!type_compatible(sema, ctx.ret, et,
expr_is_int_literal(sema, rd->block_item.ret_statement.expr),
expr_is_literal(sema, rd->block_item.ret_statement.expr),
NULL)) {
sema_error(sema, rd->block_item.ret_statement.expr, "ret type mismatch");
}
@@ -1668,9 +1761,17 @@ static void check_block(spl_sema_t *sema, spl_ast_node_ref_vec_t *block, spl_sco
b->block_item.var_decl);
} else if (b->block_item.kind == SPL_AST_CONSTDECL) {
spl_ast_node_t *cd = node_at(sema->ast, b->block_item.const_decl);
if (cd)
if (cd) {
register_binding(sema, cd->const_decl.name, cd->const_decl.type_expr, scope, 0,
b->block_item.const_decl);
/* 标记 const赋值检查拒绝写入 */
spl_ast_node_t *cn = node_at(sema->ast, b->block_item.const_decl);
if (cn && cn->resolved_def_id) {
spl_def_node_t *cdd = def_at(sema, cn->resolved_def_id);
if (cdd)
cdd->var_def.is_const = 1;
}
}
} else if (b->block_item.kind == SPL_AST_TYPEDECL) {
spl_ast_node_t *td = node_at(sema->ast, b->block_item.type_decl);
if (td)
@@ -1826,6 +1927,9 @@ void spl_sema_run(spl_sema_t *sema) {
sema_var_decl(sema, mref, sema->root_scope, sema->root_def);
else if (m->kind == SPL_AST_CONST_DECL)
sema_const_decl(sema, mref, sema->root_scope, sema->root_def);
else if (m->kind == SPL_AST_MEMBER_DECL && m->member_decl.name)
register_binding(sema, m->member_decl.name, m->member_decl.type_expr, sema->root_scope,
sema->root_def, mref);
}
sema->current_scope = sema->root_scope;
}