stage2 提供词法分析器通过与stage1的差异测试 stage1提供数组到切片的隐式转换

This commit is contained in:
zzy committed 2026-09-18 19:40:10 +08:00
1 parent c30143609a
commit bb9d0a9f18
13 files changed
+1275 -52

No files matched your search

+130 -1
View File
@@ -133,12 +133,33 @@ static bool collect_headers(void) {
return true;
}
// stage2 的所有 .spl:作为 splc1.sir 的依赖(不解析 @import,保守全量重建)。
static Nob_Files g_spl2 = {0};
static bool collect_spl2_entry(Nob_Walk_Entry entry) {
if (entry.type != NOB_FILE_REGULAR)
return true;
const char *dot = strrchr(entry.path, '.');
if (!dot || strcmp(dot, ".spl") != 0)
return true;
da_append(&g_spl2, nob_temp_strdup(entry.path));
return true;
}
static bool collect_spl2(void) {
if (g_spl2.count > 0)
return true;
return nob_walk_dir("stage2", collect_spl2_entry);
}
static bool prepare_build(void) {
if (!nob_mkdir_if_not_exists(BUILD_FOLDER))
return false;
if (!sync_cflags_stamp())
return false;
return collect_headers();
if (!collect_headers())
return false;
return collect_spl2();
}
static bool build_object(const char *src) {
@@ -320,6 +341,105 @@ static bool test_once_with_dump(const char *fname, void *user_data) {
return nob_cmd_run(&cmd);
}
// 用 splc0 编译 stage2/splc1.spl -> build/splc1.sir(依赖 stage2 全部 .spl)。
static bool build_splc1(void) {
if (!build_target("splc0"))
return false;
const char *src = "stage2/splc1.spl";
const char *sir = BUILD_FOLDER "splc1.sir";
size_t ninputs = g_spl2.count + 2;
const char **inputs = (const char **)nob_temp_alloc(sizeof(const char *) * ninputs);
inputs[0] = src;
for (size_t i = 0; i < g_spl2.count; ++i)
inputs[i + 1] = g_spl2.items[i];
inputs[ninputs - 1] = CFLAGS_STAMP;
int needs = nob_needs_rebuild(sir, inputs, ninputs);
if (needs < 0)
return false;
if (needs == 0)
return true;
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, exe_path("splc0"), src, sir);
return nob_cmd_run(&cmd);
}
static bool run_capture(Nob_Cmd *cmd, Nob_Cmd_Result *result) {
Nob_String_Builder rendered = {0};
nob_cmd_render(*cmd, &rendered);
Nob_String_View sv = nob_sb_to_sv(rendered);
bool ok = nob_cmd_capture_popen(nob_temp_sv_to_cstr(sv), result);
nob_sb_free(rendered);
return ok;
}
// diff 测试:对同一文件跑 `splc0 --dump <mode>` 与 `spl_cli splc1.sir --dump <mode>`,
// 逐字节比较 stdout。
static bool test_once_diff(const char *fname, void *user_data) {
const char *mode = (const char *)user_data;
if (!mode) {
nob_log(NOB_ERROR, "diff test requires a mode: lex|ast|sema|ir|vm");
return false;
}
if (!build_target("splc0"))
return false;
if (!build_target("spl_cli"))
return false;
if (!build_splc1())
return false;
Nob_Cmd c_cmd = {0};
nob_cmd_append(&c_cmd, exe_path("splc0"), "--dump", (char *)mode, (char *)fname,
BUILD_FOLDER "diff_c.sir");
Nob_Cmd_Result c_res = {0};
if (!run_capture(&c_cmd, &c_res)) {
nob_cmd_result_free(c_res);
return false;
}
Nob_Cmd s_cmd = {0};
nob_cmd_append(&s_cmd, exe_path("spl_cli"), BUILD_FOLDER "splc1.sir", "--dump",
(char *)mode, (char *)fname);
Nob_Cmd_Result s_res = {0};
if (!run_capture(&s_cmd, &s_res)) {
nob_cmd_result_free(c_res);
nob_cmd_result_free(s_res);
return false;
}
Nob_String_View c_out = nob_sb_to_sv(c_res.out);
Nob_String_View s_out = nob_sb_to_sv(s_res.out);
bool same = nob_sv_eq(c_out, s_out);
if (!same) {
nob_log(NOB_ERROR, "diff mismatch: %s (c=%zu bytes, spl=%zu bytes)", fname,
c_out.count, s_out.count);
// 打印首个不相同行(按行比较)。
Nob_String_View ca = c_out;
Nob_String_View sa = s_out;
size_t lineno = 1;
while (ca.count > 0 || sa.count > 0) {
Nob_String_View cl = nob_sv_chop_by_delim(&ca, '\n');
Nob_String_View sl = nob_sv_chop_by_delim(&sa, '\n');
if (!nob_sv_eq(cl, sl)) {
nob_log(NOB_ERROR, " line %zu:", lineno);
nob_log(NOB_ERROR, " c : %.*s", (int)cl.count, cl.data);
nob_log(NOB_ERROR, " spl: %.*s", (int)sl.count, sl.data);
break;
}
lineno++;
}
nob_log(NOB_ERROR, "--- c stderr/stdout merged above; exit=%d vs spl exit=%d ---",
c_res.exit_code, s_res.exit_code);
}
nob_cmd_result_free(c_res);
nob_cmd_result_free(s_res);
return same;
}
static bool is_stage_name(const char *s) {
return strcmp(s, "stage1") == 0 || strcmp(s, "stage2") == 0 || strcmp(s, "diff") == 0;
}
@@ -481,6 +601,15 @@ int main(int argc, char **argv) {
}
}
// diff 需要显式 mode,且使用专门的双编译器比较函数。
if (strcmp(stage, "diff") == 0) {
if (!mode_name) {
nob_log(NOB_ERROR, "diff requires a mode: lex|ast|sema|ir|vm");
return 1;
}
tfn = test_once_diff;
}
// 3. 剩下的都当 pattern
Nob_Files files = {0};
while (argc > 0) {