Files
spl/stage1/spl_diag.h
T

165 lines
5.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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: <loc>
* <msg>
* 使用场景:辅助说明前一条诊断,例如
* 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__ */