stage1 修复错误 提供类型检查
This commit is contained in:
@@ -68,6 +68,9 @@ void spl_comp_reset(spl_comp_t *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void spl_comp_error(spl_comp_t *ctx, const char *fmt, ...) {
|
void spl_comp_error(spl_comp_t *ctx, const char *fmt, ...) {
|
||||||
|
if (ctx->has_error)
|
||||||
|
return;
|
||||||
|
|
||||||
char body[COMP_ERROR_MAX - 64];
|
char body[COMP_ERROR_MAX - 64];
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
@@ -83,6 +86,9 @@ void spl_comp_error(spl_comp_t *ctx, const char *fmt, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void spl_comp_err_tok(spl_comp_t *ctx, spl_tok_t *tok, const char *fmt, ...) {
|
void spl_comp_err_tok(spl_comp_t *ctx, spl_tok_t *tok, const char *fmt, ...) {
|
||||||
|
if (ctx->has_error)
|
||||||
|
return;
|
||||||
|
|
||||||
char body[COMP_ERROR_MAX - 64];
|
char body[COMP_ERROR_MAX - 64];
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
|||||||
@@ -465,7 +465,7 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_type_item_vec_t *items, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
spl_comp_error(ctx, "unknown field '%s' in struct literal", fname);
|
spl_comp_err_tok(ctx, ftok, "unknown field '%s' in struct literal", fname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -794,6 +794,16 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
|||||||
if (peek(ctx)->type == TOK_L_PAREN) {
|
if (peek(ctx)->type == TOK_L_PAREN) {
|
||||||
int fi = spl_lookup_func(ctx, name);
|
int fi = spl_lookup_func(ctx, name);
|
||||||
if (fi < 0) {
|
if (fi < 0) {
|
||||||
|
/* Not a known function — check if it's a function pointer variable */
|
||||||
|
spl_var_info_t *v = spl_lookup_var(ctx, name);
|
||||||
|
if (v && v->type_idx >= 0 && spl_type_kind(&ctx->tctx, v->type_idx) == TYPE_FN) {
|
||||||
|
/* Load function pointer value, let postfix handle the call */
|
||||||
|
int vt_idx = v->type_idx;
|
||||||
|
emit_laddr(&ctx->emit, v->offset);
|
||||||
|
emit_load_ptr(&ctx->emit);
|
||||||
|
spl_expr_result_t r = {vt_idx, 0};
|
||||||
|
return r;
|
||||||
|
}
|
||||||
spl_comp_err_tok(ctx, t, "unknown function '%s'", name);
|
spl_comp_err_tok(ctx, t, "unknown function '%s'", name);
|
||||||
spl_expr_result_t r = {-1, 0};
|
spl_expr_result_t r = {-1, 0};
|
||||||
return r;
|
return r;
|
||||||
@@ -802,10 +812,19 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
|||||||
advance(ctx);
|
advance(ctx);
|
||||||
|
|
||||||
int nargs = parse_call_args_checked(ctx, f->name, f->param_type_indices, f->nparams);
|
int nargs = parse_call_args_checked(ctx, f->name, f->param_type_indices, f->nparams);
|
||||||
|
if (!ctx->has_error && nargs < f->nparams) {
|
||||||
|
spl_comp_err_tok(ctx, peek(ctx), "too few arguments to '%s': expected %d, got %d",
|
||||||
|
f->name, f->nparams, nargs);
|
||||||
|
}
|
||||||
|
if (!ctx->has_error) {
|
||||||
if (!expect(ctx, TOK_R_PAREN)) {
|
if (!expect(ctx, TOK_R_PAREN)) {
|
||||||
spl_expr_result_t _r = {-1, 0};
|
spl_expr_result_t _r = {-1, 0};
|
||||||
return _r;
|
return _r;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
spl_expr_result_t _r = {-1, 0};
|
||||||
|
return _r;
|
||||||
|
}
|
||||||
|
|
||||||
if (f->is_extern) {
|
if (f->is_extern) {
|
||||||
int nidx = spl_ensure_native(ctx, f->name);
|
int nidx = spl_ensure_native(ctx, f->name);
|
||||||
@@ -854,6 +873,21 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Function reference (not a call): get function address */
|
||||||
|
{
|
||||||
|
int fi = spl_lookup_func(ctx, name);
|
||||||
|
if (fi >= 0) {
|
||||||
|
spl_func_info_t *f = &vec_at(ctx->funcs, fi);
|
||||||
|
if (!f->is_extern) {
|
||||||
|
emit_push_u64(&ctx->emit, f->func_idx);
|
||||||
|
int fn_ptr_type =
|
||||||
|
spl_type_fn(&ctx->tctx, spl_type_basic(&ctx->tctx, SPL_USIZE), f->ret_type_idx);
|
||||||
|
spl_expr_result_t r = {fn_ptr_type, 1};
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int ttype_idx = spl_type_resolve(&ctx->tctx, name);
|
int ttype_idx = spl_type_resolve(&ctx->tctx, name);
|
||||||
if (ttype_idx >= 0) {
|
if (ttype_idx >= 0) {
|
||||||
if (peek(ctx)->type == TOK_L_BRACE &&
|
if (peek(ctx)->type == TOK_L_BRACE &&
|
||||||
@@ -873,8 +907,10 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
|
|||||||
static spl_expr_result_t parse_group(spl_comp_t *ctx) {
|
static spl_expr_result_t parse_group(spl_comp_t *ctx) {
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
spl_expr_result_t r = spl_parse_expr(ctx, PREC_MIN);
|
spl_expr_result_t r = spl_parse_expr(ctx, PREC_MIN);
|
||||||
|
if (!ctx->has_error) {
|
||||||
if (!expect(ctx, TOK_R_PAREN))
|
if (!expect(ctx, TOK_R_PAREN))
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -910,6 +946,9 @@ static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
|
|||||||
emit_binop(&ctx->emit, SPL_NOT, spl_type_emit_type(&ctx->tctx, right.type_idx));
|
emit_binop(&ctx->emit, SPL_NOT, spl_type_emit_type(&ctx->tctx, right.type_idx));
|
||||||
break;
|
break;
|
||||||
case TOK_AND:
|
case TOK_AND:
|
||||||
|
if (right.type_idx >= 0 && spl_type_kind(&ctx->tctx, right.type_idx) == TYPE_FN) {
|
||||||
|
return right;
|
||||||
|
}
|
||||||
if (!right.is_lvalue) {
|
if (!right.is_lvalue) {
|
||||||
spl_comp_err_tok(ctx, peek(ctx), "cannot take address of rvalue");
|
spl_comp_err_tok(ctx, peek(ctx), "cannot take address of rvalue");
|
||||||
spl_expr_result_t _r = {-1, 0};
|
spl_expr_result_t _r = {-1, 0};
|
||||||
@@ -995,10 +1034,15 @@ static spl_expr_result_t parse_primary_expr(spl_comp_t *ctx) {
|
|||||||
if (peek(ctx)->type == TOK_L_PAREN) {
|
if (peek(ctx)->type == TOK_L_PAREN) {
|
||||||
advance(ctx);
|
advance(ctx);
|
||||||
int nargs = parse_call_args(ctx);
|
int nargs = parse_call_args(ctx);
|
||||||
|
if (!ctx->has_error) {
|
||||||
if (!expect(ctx, TOK_R_PAREN)) {
|
if (!expect(ctx, TOK_R_PAREN)) {
|
||||||
spl_expr_result_t _r = {-1, 0};
|
spl_expr_result_t _r = {-1, 0};
|
||||||
return _r;
|
return _r;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
spl_expr_result_t _r = {-1, 0};
|
||||||
|
return _r;
|
||||||
|
}
|
||||||
for (int i = 0; i < nargs; i++) {
|
for (int i = 0; i < nargs; i++) {
|
||||||
emit_dbg_usize(&ctx->emit);
|
emit_dbg_usize(&ctx->emit);
|
||||||
emit_drop(&ctx->emit);
|
emit_drop(&ctx->emit);
|
||||||
@@ -1015,10 +1059,15 @@ static spl_expr_result_t parse_primary_expr(spl_comp_t *ctx) {
|
|||||||
return _r;
|
return _r;
|
||||||
}
|
}
|
||||||
int ti = spl_type_parse(&ctx->tctx, ctx);
|
int ti = spl_type_parse(&ctx->tctx, ctx);
|
||||||
|
if (!ctx->has_error) {
|
||||||
if (!expect(ctx, TOK_R_PAREN)) {
|
if (!expect(ctx, TOK_R_PAREN)) {
|
||||||
spl_expr_result_t _r = {-1, 0};
|
spl_expr_result_t _r = {-1, 0};
|
||||||
return _r;
|
return _r;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
spl_expr_result_t _r = {-1, 0};
|
||||||
|
return _r;
|
||||||
|
}
|
||||||
if (ti < 0) {
|
if (ti < 0) {
|
||||||
spl_comp_err_tok(ctx, peek(ctx), "@sizeof: invalid type");
|
spl_comp_err_tok(ctx, peek(ctx), "@sizeof: invalid type");
|
||||||
spl_expr_result_t r = {-1, 0};
|
spl_expr_result_t r = {-1, 0};
|
||||||
@@ -1112,14 +1161,29 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
int *cp = func->param_type_indices;
|
int full_np = func->nparams;
|
||||||
int cn = func->nparams;
|
nargs += parse_call_args_checked(ctx, func->name,
|
||||||
nargs += parse_call_args_checked(ctx, func->name, cp, cn);
|
func->param_type_indices, full_np);
|
||||||
|
if (is_instance && !ctx->has_error) {
|
||||||
|
int ok =
|
||||||
|
(nargs >= full_np) || (nargs == full_np - 1 && full_np == 1);
|
||||||
|
if (!ok) {
|
||||||
|
spl_comp_err_tok(
|
||||||
|
ctx, peek(ctx),
|
||||||
|
"too few arguments to '%s': expected %d, got %d",
|
||||||
|
func->name, full_np, nargs);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ctx->has_error) {
|
||||||
if (!expect(ctx, TOK_R_PAREN)) {
|
if (!expect(ctx, TOK_R_PAREN)) {
|
||||||
spl_expr_result_t _r = left;
|
spl_expr_result_t _r = left;
|
||||||
return _r;
|
return _r;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
spl_expr_result_t _r = left;
|
||||||
|
return _r;
|
||||||
|
}
|
||||||
|
|
||||||
if (func->func_idx < 0) {
|
if (func->func_idx < 0) {
|
||||||
fprintf(stderr, "WARN: method call '%s.' with invalid func_idx=%d\n",
|
fprintf(stderr, "WARN: method call '%s.' with invalid func_idx=%d\n",
|
||||||
@@ -1142,6 +1206,48 @@ static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t l
|
|||||||
}
|
}
|
||||||
if (found_method)
|
if (found_method)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Indirect call through function pointer: fn_ptr(args) */
|
||||||
|
if (left.type_idx >= 0 && peek(ctx)->type == TOK_L_PAREN &&
|
||||||
|
spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_FN) {
|
||||||
|
advance(ctx); /* ( */
|
||||||
|
|
||||||
|
int nargs = parse_call_args(ctx);
|
||||||
|
if (!ctx->has_error) {
|
||||||
|
if (!expect(ctx, TOK_R_PAREN)) {
|
||||||
|
spl_expr_result_t _r = left;
|
||||||
|
return _r;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
spl_expr_result_t _r = left;
|
||||||
|
return _r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If left is lvalue, load the function address value first */
|
||||||
|
if (left.is_lvalue) {
|
||||||
|
emit_load_ptr(&ctx->emit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stack currently: [args..., func_addr].
|
||||||
|
* CALLI expects: POP addr, POP nargs, call(addr, nargs).
|
||||||
|
* After all args are on stack: push nargs, push func_addr.
|
||||||
|
* But func_addr is already below args? No — we need:
|
||||||
|
* Stack: [..., func_addr, arg0, ..., argN-1]
|
||||||
|
* CALLI: POP addr, POP nargs, call(addr, nargs)
|
||||||
|
* Actually CALLI pops: TOS=addr, TOS-1=nargs.
|
||||||
|
* So we need: [args..., nargs, addr]
|
||||||
|
* But currently: [args..., addr] (addr is on TOS, loaded above)
|
||||||
|
* Push nargs ABOVE addr, then CALLI pops addr, then nargs:
|
||||||
|
* Stack: [args..., nargs, addr]
|
||||||
|
* TOS=addr → POP returns addr, then POP returns nargs. ✓ */
|
||||||
|
|
||||||
|
emit_push_u64(&ctx->emit, nargs);
|
||||||
|
emit_raw(&ctx->emit, SPL_CALLI, SPL_VOID, 0);
|
||||||
|
|
||||||
|
/* For now, result type is void — we don't know the return type from fn ptr */
|
||||||
|
left = (spl_expr_result_t){spl_type_basic(&ctx->tctx, SPL_VOID), 0};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left.type_idx >= 0 && spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_STRUCT) {
|
if (left.type_idx >= 0 && spl_type_kind(&ctx->tctx, left.type_idx) == TYPE_STRUCT) {
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ static int parse_params_decl(spl_comp_t *ctx, char pnames[][256], int ptypes[])
|
|||||||
ctx->tok_idx = saved;
|
ctx->tok_idx = saved;
|
||||||
}
|
}
|
||||||
while (1) {
|
while (1) {
|
||||||
|
if (peek(ctx)->type == TOK_ELLIPSIS) {
|
||||||
|
advance(ctx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
spl_tok_t *pname = advance(ctx);
|
spl_tok_t *pname = advance(ctx);
|
||||||
spl_tok_copy_name(pname, pnames[nparams], 256);
|
spl_tok_copy_name(pname, pnames[nparams], 256);
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
@@ -42,10 +46,6 @@ static int parse_params_decl(spl_comp_t *ctx, char pnames[][256], int ptypes[])
|
|||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (peek(ctx)->type == TOK_ELLIPSIS) {
|
|
||||||
advance(ctx);
|
|
||||||
skip_nl(ctx);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -408,7 +408,6 @@ static void parse_type_body(spl_comp_t *ctx, int container_type_idx, int is_enum
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx->tctx.current_type_idx = saved_current;
|
ctx->tctx.current_type_idx = saved_current;
|
||||||
spl_type_compute_layout(&ctx->tctx, container_type_idx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
@@ -746,4 +745,9 @@ void spl_parse_prog(spl_comp_t *ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Recompute all type layouts now that forward references are resolved */
|
||||||
|
for (int i = 0; i < (int)vec_size(ctx->tctx.types); i++) {
|
||||||
|
spl_type_compute_layout(&ctx->tctx, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ spl_expr_result_t spl_parse_block_expr(spl_comp_t *ctx) {
|
|||||||
result = (spl_expr_result_t){0};
|
result = (spl_expr_result_t){0};
|
||||||
} else {
|
} else {
|
||||||
/* Expression — look ahead for assignment */
|
/* Expression — look ahead for assignment */
|
||||||
|
usize before = ctx->tok_idx;
|
||||||
int is_assign = lookahead_is_assign(ctx);
|
int is_assign = lookahead_is_assign(ctx);
|
||||||
int saved_addr = ctx->addr_of_mode;
|
int saved_addr = ctx->addr_of_mode;
|
||||||
if (is_assign)
|
if (is_assign)
|
||||||
@@ -210,6 +211,14 @@ spl_expr_result_t spl_parse_block_expr(spl_comp_t *ctx) {
|
|||||||
spl_expr_result_t expr = spl_parse_expr(ctx, PREC_MIN);
|
spl_expr_result_t expr = spl_parse_expr(ctx, PREC_MIN);
|
||||||
ctx->addr_of_mode = saved_addr;
|
ctx->addr_of_mode = saved_addr;
|
||||||
|
|
||||||
|
/* Safety: if no token was consumed, advance to prevent infinite loop */
|
||||||
|
if (ctx->tok_idx == before) {
|
||||||
|
advance(ctx);
|
||||||
|
result = (spl_expr_result_t){0};
|
||||||
|
skip_nl(ctx);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
skip_nl(ctx);
|
skip_nl(ctx);
|
||||||
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_ENDLINE) {
|
if (peek(ctx)->type == TOK_SEMICOLON || peek(ctx)->type == TOK_ENDLINE) {
|
||||||
/* Expression statement: drop value, consume ; */
|
/* Expression statement: drop value, consume ; */
|
||||||
@@ -1140,6 +1149,7 @@ void spl_parse_stmt(spl_comp_t *ctx) {
|
|||||||
parse_extern_decl(ctx);
|
parse_extern_decl(ctx);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
snprintf(ctx->parse_context, sizeof(ctx->parse_context), "expression statement");
|
||||||
parse_expr_stmt(ctx);
|
parse_expr_stmt(ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,6 +304,32 @@ int spl_type_alias(spl_type_ctx_t *tctx, const char *name, int target_type_idx)
|
|||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spl_type_fn(spl_type_ctx_t *tctx, int params_type_idx, int ret_type_idx) {
|
||||||
|
spl_type_info_t t;
|
||||||
|
memset(&t, 0, sizeof(t));
|
||||||
|
t.kind = TYPE_FN;
|
||||||
|
t.byte_size = sizeof(spl_val_t);
|
||||||
|
t.slot_count = 1;
|
||||||
|
t.resolved = 1;
|
||||||
|
vec_init(t.items);
|
||||||
|
|
||||||
|
spl_type_item_t pi;
|
||||||
|
memset(&pi, 0, sizeof(pi));
|
||||||
|
pi.item_kind = ITEM_FIELD;
|
||||||
|
pi.aggregate_field.type_idx = params_type_idx;
|
||||||
|
pi.aggregate_field.offset = 0;
|
||||||
|
vec_push(t.items, pi);
|
||||||
|
|
||||||
|
spl_type_item_t ri;
|
||||||
|
memset(&ri, 0, sizeof(ri));
|
||||||
|
ri.item_kind = ITEM_FIELD;
|
||||||
|
ri.aggregate_field.type_idx = ret_type_idx;
|
||||||
|
ri.aggregate_field.offset = sizeof(spl_val_t);
|
||||||
|
vec_push(t.items, ri);
|
||||||
|
|
||||||
|
return spl_type_add(tctx, t);
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Item management
|
* Item management
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
@@ -317,6 +343,9 @@ void spl_type_add_field(spl_type_ctx_t *tctx, int type_idx, const char *name, in
|
|||||||
item.aggregate_field.type_idx = field_type_idx;
|
item.aggregate_field.type_idx = field_type_idx;
|
||||||
item.aggregate_field.offset = 0;
|
item.aggregate_field.offset = 0;
|
||||||
vec_push(t->items, item);
|
vec_push(t->items, item);
|
||||||
|
/* Adding field after layout was computed → needs recompute */
|
||||||
|
if (t->resolved == 1)
|
||||||
|
t->resolved = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void spl_type_add_var(spl_type_ctx_t *tctx, int type_idx, const char *name, int var_type_idx) {
|
void spl_type_add_var(spl_type_ctx_t *tctx, int type_idx, const char *name, int var_type_idx) {
|
||||||
@@ -339,6 +368,8 @@ void spl_type_add_variant(spl_type_ctx_t *tctx, int type_idx, const char *name,
|
|||||||
item.enum_field.type_idx = data_type_idx;
|
item.enum_field.type_idx = data_type_idx;
|
||||||
item.enum_field.value = vec_size(t->items);
|
item.enum_field.value = vec_size(t->items);
|
||||||
vec_push(t->items, item);
|
vec_push(t->items, item);
|
||||||
|
if (t->resolved == 1)
|
||||||
|
t->resolved = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void spl_type_add_method(spl_type_ctx_t *tctx, int type_idx, const char *name, int func_idx) {
|
void spl_type_add_method(spl_type_ctx_t *tctx, int type_idx, const char *name, int func_idx) {
|
||||||
@@ -382,8 +413,14 @@ void spl_type_compute_layout(spl_type_ctx_t *tctx, int type_idx) {
|
|||||||
if (type_idx < 0)
|
if (type_idx < 0)
|
||||||
return;
|
return;
|
||||||
spl_type_info_t *t = &vec_at(tctx->types, type_idx);
|
spl_type_info_t *t = &vec_at(tctx->types, type_idx);
|
||||||
if (t->resolved)
|
if (t->resolved == 1)
|
||||||
return;
|
return;
|
||||||
|
if (t->resolved == 2) {
|
||||||
|
fprintf(stderr, "error: circular type dependency in '%s'\n", t->name ? t->name : "?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t->resolved = 2; /* mark as in-progress */
|
||||||
|
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case TYPE_STRUCT: {
|
case TYPE_STRUCT: {
|
||||||
@@ -534,8 +571,9 @@ usize spl_type_array_len(spl_type_ctx_t *tctx, int type_idx) {
|
|||||||
int spl_type_is_scalar(spl_type_ctx_t *tctx, int type_idx) {
|
int spl_type_is_scalar(spl_type_ctx_t *tctx, int type_idx) {
|
||||||
if (type_idx < 0)
|
if (type_idx < 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
type_idx = spl_type_resolve_underlying(tctx, type_idx);
|
||||||
spl_type_info_t *t = &vec_at(tctx->types, type_idx);
|
spl_type_info_t *t = &vec_at(tctx->types, type_idx);
|
||||||
if (t->kind == TYPE_BASIC || t->kind == TYPE_PTR)
|
if (t->kind == TYPE_BASIC || t->kind == TYPE_PTR || t->kind == TYPE_FN)
|
||||||
return 1;
|
return 1;
|
||||||
if (t->kind == TYPE_ENUM) {
|
if (t->kind == TYPE_ENUM) {
|
||||||
vec_for(t->items, i) {
|
vec_for(t->items, i) {
|
||||||
@@ -575,6 +613,7 @@ int spl_type_resolve_underlying(spl_type_ctx_t *tctx, int type_idx) {
|
|||||||
spl_type_t spl_type_emit_type(spl_type_ctx_t *tctx, int type_idx) {
|
spl_type_t spl_type_emit_type(spl_type_ctx_t *tctx, int type_idx) {
|
||||||
if (type_idx < 0)
|
if (type_idx < 0)
|
||||||
return SPL_I32;
|
return SPL_I32;
|
||||||
|
type_idx = spl_type_resolve_underlying(tctx, type_idx);
|
||||||
spl_type_info_t *t = &vec_at(tctx->types, type_idx);
|
spl_type_info_t *t = &vec_at(tctx->types, type_idx);
|
||||||
if (t->kind == TYPE_BASIC)
|
if (t->kind == TYPE_BASIC)
|
||||||
return t->basic_type;
|
return t->basic_type;
|
||||||
@@ -656,6 +695,8 @@ const char *spl_type_str(spl_type_ctx_t *tctx, int type_idx) {
|
|||||||
return t->name ? t->name : "<?>";
|
return t->name ? t->name : "<?>";
|
||||||
case TYPE_NAME:
|
case TYPE_NAME:
|
||||||
return t->name ? t->name : "<alias>";
|
return t->name ? t->name : "<alias>";
|
||||||
|
case TYPE_FN:
|
||||||
|
return "fn";
|
||||||
default:
|
default:
|
||||||
return "<?>";
|
return "<?>";
|
||||||
}
|
}
|
||||||
@@ -857,6 +898,39 @@ int spl_type_parse(spl_type_ctx_t *tctx, struct spl_comp *ctx) {
|
|||||||
return ti;
|
return ti;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Inline function type: fn(params...) rettype */
|
||||||
|
if (tok->type == KW_FN) {
|
||||||
|
ctx->tok_idx++;
|
||||||
|
if (!expect(ctx, TOK_L_PAREN))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Parse comma-separated parameter types */
|
||||||
|
int param_types[64]; /* max 64 params */
|
||||||
|
int nparams = 0;
|
||||||
|
if (peek(ctx)->type != TOK_R_PAREN) {
|
||||||
|
for (;;) {
|
||||||
|
int pt = spl_type_parse(tctx, ctx);
|
||||||
|
if (pt >= 0 && nparams < 64)
|
||||||
|
param_types[nparams++] = pt;
|
||||||
|
if (peek(ctx)->type == TOK_COMMA) {
|
||||||
|
advance(ctx);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!expect(ctx, TOK_R_PAREN))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int ret_type = spl_type_parse(tctx, ctx);
|
||||||
|
if (ret_type < 0)
|
||||||
|
ret_type = spl_type_basic(tctx, SPL_VOID);
|
||||||
|
|
||||||
|
/* Store param types in a synthetic array type (slot 0 = count, slot 1..N = params) */
|
||||||
|
int params_arr = spl_type_array(tctx, spl_type_basic(tctx, SPL_USIZE), nparams);
|
||||||
|
return spl_type_fn(tctx, params_arr, ret_type);
|
||||||
|
}
|
||||||
|
|
||||||
/* Identifier: basic type or named type */
|
/* Identifier: basic type or named type */
|
||||||
if (tok->type == TOK_IDENT || ((int)tok->type >= (int)KW_AS && (int)tok->type <= (int)KW_ANY)) {
|
if (tok->type == TOK_IDENT || ((int)tok->type >= (int)KW_AS && (int)tok->type <= (int)KW_ANY)) {
|
||||||
const char *name = tok->lexeme;
|
const char *name = tok->lexeme;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ typedef enum {
|
|||||||
TYPE_UNION,
|
TYPE_UNION,
|
||||||
TYPE_ENUM,
|
TYPE_ENUM,
|
||||||
TYPE_NAME,
|
TYPE_NAME,
|
||||||
|
TYPE_FN,
|
||||||
TYPE_COUNT,
|
TYPE_COUNT,
|
||||||
} spl_type_kind_t;
|
} spl_type_kind_t;
|
||||||
|
|
||||||
@@ -123,6 +124,7 @@ int spl_type_struct(spl_type_ctx_t *tctx, const char *name);
|
|||||||
int spl_type_union(spl_type_ctx_t *tctx, const char *name);
|
int spl_type_union(spl_type_ctx_t *tctx, const char *name);
|
||||||
int spl_type_enum(spl_type_ctx_t *tctx, const char *name);
|
int spl_type_enum(spl_type_ctx_t *tctx, const char *name);
|
||||||
int spl_type_alias(spl_type_ctx_t *tctx, const char *name, int target_type_idx);
|
int spl_type_alias(spl_type_ctx_t *tctx, const char *name, int target_type_idx);
|
||||||
|
int spl_type_fn(spl_type_ctx_t *tctx, int params_type_idx, int ret_type_idx);
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* Item management — add members to aggregate types
|
* Item management — add members to aggregate types
|
||||||
|
|||||||
Reference in New Issue
Block a user