stage1 初步实现
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user