#ifndef __SPL_DIAG_H__ #define __SPL_DIAG_H__ #include "../stage0/include/utils.h" #include "spl_dbg.h" typedef enum { SPL_DIAG_LEVEL_NOTE = 0, SPL_DIAG_LEVEL_WARN, SPL_DIAG_LEVEL_ERROR, SPL_DIAG_LEVEL_FATAL, } spl_diag_level_t; typedef enum { SPL_STAGE_NONE = 0, SPL_STAGE_LEX, SPL_STAGE_PARSE, SPL_STAGE_SEMA, SPL_STAGE_AST2IR, SPL_STAGE_IR2VM, SPL_STAGE_DRIVER, } spl_diag_stage_t; /* kind 枚举:边写边补。新增时放对应分组末尾即可。 */ typedef enum { SPL_DIAG_KIND_NONE = 0, /* 词法 / 语法 */ SPL_DIAG_KIND_LEX_UNEXPECTED, SPL_DIAG_KIND_PARSE_EXPECTED, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, /* sema */ SPL_DIAG_KIND_UNDEFINED_SYMBOL, SPL_DIAG_KIND_DUPLICATE_SYMBOL, SPL_DIAG_KIND_TYPE_MISMATCH, SPL_DIAG_KIND_ARG_COUNT_MISMATCH, SPL_DIAG_KIND_NOT_A_FUNCTION, SPL_DIAG_KIND_NO_FIELD, SPL_DIAG_KIND_NO_METHOD, SPL_DIAG_KIND_INDEX_BASE_INVALID, SPL_DIAG_KIND_TUPLE_INDEX_OOB, SPL_DIAG_KIND_FITS_OVERFLOW, SPL_DIAG_KIND_CIRCULAR_DEP, SPL_DIAG_KIND_BREAK_OUTSIDE_LOOP, SPL_DIAG_KIND_CONTINUE_OUTSIDE_LOOP, SPL_DIAG_KIND_UNDEFINED_LABEL, SPL_DIAG_KIND_CAST_INVALID, SPL_DIAG_KIND_UNKNOWN_ATTR, SPL_DIAG_KIND_UNKNOWN_INTRIN, SPL_DIAG_KIND_INTRIN_ARG_COUNT, SPL_DIAG_KIND_VAR_UNINITIALIZED, SPL_DIAG_KIND_CANNOT_INFER, SPL_DIAG_KIND_MUST_RETURN_VALUE, /* ast2ir */ SPL_DIAG_KIND_UNHANDLED_NODE, SPL_DIAG_KIND_IMPLICIT_CAST_FAIL, SPL_DIAG_KIND_NO_LVALUE, SPL_DIAG_KIND_BAD_FIELD_INDEX, SPL_DIAG_KIND_BAD_BLOCK, /* ir2vm */ SPL_DIAG_KIND_IR_UNKNOWN_KIND, SPL_DIAG_KIND_FRAME_OVERFLOW, /* 通用 */ SPL_DIAG_KIND_INTERNAL, } spl_diag_kind_t; typedef struct { spl_dbg_node_t loc; char *fn_name; char *label; } spl_diag_frame_t; typedef VEC(spl_diag_frame_t) spl_diag_frame_vec_t; typedef struct { spl_dbg_node_t loc; char *message; } spl_diag_note_t; typedef VEC(spl_diag_note_t) spl_diag_note_vec_t; typedef struct { spl_diag_level_t level; spl_diag_stage_t stage; spl_diag_kind_t kind; spl_dbg_node_t loc; char *message; spl_diag_frame_vec_t ctx; spl_diag_note_vec_t notes; } spl_diag_record_t; typedef VEC(spl_diag_record_t) spl_diag_record_vec_t; typedef struct spl_diag { spl_diag_frame_vec_t ctx; spl_diag_record_vec_t records; usize num_printed; bool collect; usize n_errors; usize n_warns; usize n_fatals; spl_diag_stage_t stage; void *fout; bool color; } spl_diag_t; void spl_diag_init(spl_diag_t *d, void *fout); void spl_diag_drop(spl_diag_t *d); void spl_diag_reset(spl_diag_t *d); void spl_diag_set_stage(spl_diag_t *d, spl_diag_stage_t stage); void spl_diag_set_output(spl_diag_t *d, FILE *out); void spl_diag_set_color(spl_diag_t *d, bool enabled); void spl_diag_set_collect(spl_diag_t *d, bool enabled); void spl_diag_push(spl_diag_t *d, const spl_dbg_node_t *loc, const char *fn_name, const char *label); void spl_diag_pop(spl_diag_t *d); usize spl_diag_depth(const spl_diag_t *d); /* ============================================================ * 发射 * * 每个级别都生成独立的 spl_diag_record_t: * - 计入 records(collect=true 时) * - error/fatal 计入 n_errors,warn 计入 n_warns * - 立刻输出到 out(如果非 NULL) * * 四种级别的语义区别: * note —— 一般信息;不阻塞;用在前序诊断之外的独立说明 * warn —— 警告;不阻塞;driver 可忽略 * error —— 用户代码错误;调用者应 return 0 * fatal —— 用户代码错误到数据结构已损坏;调用者必须 return 0 * ============================================================ */ void spl_diag_note(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, ...); void spl_diag_warn(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, ...); void spl_diag_error(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, ...); void spl_diag_fatal(spl_diag_t *d, spl_diag_kind_t kind, const spl_dbg_node_t *loc, const char *fmt, ...); /* 挂到最近一条记录(records 末尾)的 notes 列表下。 * 不生成独立记录、不计入计数,输出时显示为: * note: * * 使用场景:辅助说明前一条诊断,例如 * spl_diag_error(d, DUPLICATE_SYMBOL, &n->dbg, "duplicate symbol `foo`"); * spl_diag_attach_note(d, &prev->dbg, "previously defined here"); * 约束:只在 records 非空时生效;否则静默丢弃,不报错。 */ void spl_diag_attach_note(spl_diag_t *d, const spl_dbg_node_t *loc, const char *fmt, ...); bool spl_diag_has_error(const spl_diag_t *d); bool spl_diag_has_fatal(const spl_diag_t *d); usize spl_diag_error_count(const spl_diag_t *d); usize spl_diag_warn_count(const spl_diag_t *d); void spl_diag_summary(const spl_diag_t *d); const char *spl_diag_kind_name(spl_diag_kind_t k); const char *spl_diag_stage_name(spl_diag_stage_t s); const char *spl_diag_level_name(spl_diag_level_t l); #endif /* __SPL_DIAG_H__ */