verbose_air: add human-readable AIR printer and --verbose-air CLI flag
Add verbose_air.c/h implementing a human-readable AIR printer for debugging the C sema, ported from src/Air/print.zig. Types print as human-readable names (u32, *const u8, fn (...) noreturn) instead of raw IP indices. Add --verbose-air flag to zig0 CLI and a `zig build zig0` target for building the standalone executable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
49
build.zig
49
build.zig
@@ -10,8 +10,34 @@ const assert = std.debug.assert;
|
||||
const DevEnv = @import("src/dev.zig").Env;
|
||||
const ValueInterpretMode = enum { direct, by_name };
|
||||
|
||||
const zig0_headers = &[_][]const u8{ "common.h", "ast.h", "parser.h", "zir.h", "astgen.h", "intern_pool.h", "air.h", "type.h", "value.h", "sema.h", "dump.h" };
|
||||
const zig0_c_lib_files = &[_][]const u8{ "tokenizer.c", "ast.c", "zig0.c", "parser.c", "zir.c", "astgen.c", "intern_pool.c", "air.c", "type.c", "value.c", "sema.c" };
|
||||
const zig0_headers = &[_][]const u8{
|
||||
"air.h",
|
||||
"ast.h",
|
||||
"astgen.h",
|
||||
"common.h",
|
||||
"dump.h",
|
||||
"intern_pool.h",
|
||||
"parser.h",
|
||||
"sema.h",
|
||||
"type.h",
|
||||
"value.h",
|
||||
"verbose_air.h",
|
||||
"zir.h",
|
||||
};
|
||||
const zig0_c_lib_files = &[_][]const u8{
|
||||
"air.c",
|
||||
"ast.c",
|
||||
"astgen.c",
|
||||
"intern_pool.c",
|
||||
"parser.c",
|
||||
"sema.c",
|
||||
"tokenizer.c",
|
||||
"type.c",
|
||||
"value.c",
|
||||
"verbose_air.c",
|
||||
"zig0.c",
|
||||
"zir.c",
|
||||
};
|
||||
const zig0_all_c_files = zig0_c_lib_files ++ &[_][]const u8{"main.c"};
|
||||
const zig0_cflags = &[_][]const u8{
|
||||
"-std=c11",
|
||||
@@ -712,6 +738,25 @@ pub fn build(b: *std.Build) !void {
|
||||
const test_zig0_step = b.step("test-zig0", "Run zig0 C implementation tests");
|
||||
addZig0TestStep(b, test_zig0_step, zig0_target, optimize, zig0_cc, zig0_no_exec, zig0_valgrind, zig0_test_timeout, zig0_exe_options);
|
||||
|
||||
// zig0 standalone executable
|
||||
const zig0_step = b.step("zig0", "Build zig0 standalone executable");
|
||||
const zig0_mod = b.createModule(.{
|
||||
.target = zig0_target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
zig0_mod.addCSourceFiles(.{
|
||||
.root = b.path("stage0"),
|
||||
.files = zig0_all_c_files,
|
||||
.flags = zig0_cflags,
|
||||
});
|
||||
zig0_mod.linkSystemLibrary("c", .{});
|
||||
const zig0_exe = b.addExecutable(.{
|
||||
.name = "zig0",
|
||||
.root_module = zig0_mod,
|
||||
});
|
||||
const zig0_install = b.addInstallArtifact(zig0_exe, .{});
|
||||
zig0_step.dependOn(&zig0_install.step);
|
||||
|
||||
const fmt_zig0 = b.step("fmt-zig0", "Format zig0 C code");
|
||||
const clang_format = b.addSystemCommand(&.{ "clang-format", "-i" });
|
||||
for (zig0_all_c_files ++ zig0_headers) |f| clang_format.addFileArg(b.path(b.fmt("stage0/{s}", .{f})));
|
||||
|
||||
@@ -24,6 +24,7 @@ const CAir = extern struct {
|
||||
/// Matches C `SemaFuncAir` struct layout (sema.h).
|
||||
const CSemaFuncAir = extern struct {
|
||||
name: ?[*:0]u8,
|
||||
func_ip: u32, // InternPoolIndex
|
||||
air: CAir,
|
||||
};
|
||||
|
||||
@@ -98,6 +99,7 @@ const AirCollector = struct {
|
||||
|
||||
try self.funcs.append(gpa, .{
|
||||
.name = name_copy.ptr,
|
||||
.func_ip = std.math.maxInt(u32), // IP_INDEX_NONE
|
||||
.air = .{
|
||||
.inst_len = inst_len,
|
||||
.inst_cap = inst_len,
|
||||
|
||||
@@ -3,22 +3,41 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int zig0Run(char* program, char** msg);
|
||||
int zig0RunFile(char* fname, char** msg);
|
||||
int zig0RunFile(const char* fname, bool verbose_air, char** msg);
|
||||
|
||||
static void usage(const char* argv0) {
|
||||
fprintf(stderr, "Usage: %s program.zig\n", argv0);
|
||||
fprintf(stderr, "Usage: %s [--verbose-air] program.zig\n", argv0);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
bool verbose_air = false;
|
||||
const char* fname = NULL;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--verbose-air") == 0) {
|
||||
verbose_air = true;
|
||||
} else if (argv[i][0] == '-') {
|
||||
fprintf(stderr, "Unknown option: %s\n", argv[i]);
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
} else if (fname == NULL) {
|
||||
fname = argv[i];
|
||||
} else {
|
||||
fprintf(stderr, "Unexpected argument: %s\n", argv[i]);
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fname == NULL) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* msg;
|
||||
switch (zig0RunFile(argv[1], &msg)) {
|
||||
switch (zig0RunFile(fname, verbose_air, &msg)) {
|
||||
case 0:
|
||||
return 0;
|
||||
break;
|
||||
|
||||
@@ -3241,6 +3241,7 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
|
||||
}
|
||||
SemaFuncAir* entry = &list->items[list->len++];
|
||||
entry->name = func_name;
|
||||
entry->func_ip = IP_INDEX_NONE;
|
||||
entry->air.inst_tags = sema->air_inst_tags;
|
||||
entry->air.inst_datas = sema->air_inst_datas;
|
||||
entry->air.inst_len = sema->air_inst_len;
|
||||
|
||||
@@ -110,6 +110,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
char* name; // function FQN (owned, null-terminated)
|
||||
InternPoolIndex func_ip; // IP index of function value (for name resolution)
|
||||
Air air; // per-function Air (owns its arrays)
|
||||
} SemaFuncAir;
|
||||
|
||||
|
||||
1102
stage0/verbose_air.c
Normal file
1102
stage0/verbose_air.c
Normal file
File diff suppressed because it is too large
Load Diff
13
stage0/verbose_air.h
Normal file
13
stage0/verbose_air.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// verbose_air.h — Human-readable AIR printer for debugging.
|
||||
// Ported from src/Air/print.zig.
|
||||
#ifndef _ZIG0_VERBOSE_AIR_H__
|
||||
#define _ZIG0_VERBOSE_AIR_H__
|
||||
|
||||
#include "intern_pool.h"
|
||||
#include "sema.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void verboseAirPrint(
|
||||
FILE* out, const SemaFuncAirList* list, const InternPool* ip);
|
||||
|
||||
#endif
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "astgen.h"
|
||||
#include "intern_pool.h"
|
||||
#include "sema.h"
|
||||
#include "verbose_air.h"
|
||||
#include "zir.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
@@ -13,7 +14,7 @@
|
||||
// - code = 0: program successfully terminated.
|
||||
// - code = 1: panicked, panic message in msg. Caller should free msg.
|
||||
// - code = 2: interpreter error, error in msg. Caller should free msg.
|
||||
static int zig0Run(const char* program, char** msg) {
|
||||
static int zig0Run(const char* program, bool verbose_air, char** msg) {
|
||||
uint32_t len = (uint32_t)strlen(program);
|
||||
Ast ast = astParse(program, len);
|
||||
if (ast.has_error) {
|
||||
@@ -43,6 +44,8 @@ static int zig0Run(const char* program, char** msg) {
|
||||
InternPool ip = ipInit();
|
||||
Sema sema = semaInit(&ip, zir);
|
||||
SemaFuncAirList func_airs = semaAnalyze(&sema);
|
||||
if (verbose_air)
|
||||
verboseAirPrint(stderr, &func_airs, &ip);
|
||||
semaDeinit(&sema);
|
||||
semaFuncAirListDeinit(&func_airs);
|
||||
ipDeinit(&ip);
|
||||
@@ -52,7 +55,7 @@ static int zig0Run(const char* program, char** msg) {
|
||||
|
||||
// API: run and:
|
||||
// code = 3: abnormal error, expect something in stderr.
|
||||
int zig0RunFile(const char* fname, char** msg) {
|
||||
int zig0RunFile(const char* fname, bool verbose_air, char** msg) {
|
||||
FILE* f = fopen(fname, "r");
|
||||
if (f == NULL) {
|
||||
perror("fopen");
|
||||
@@ -89,7 +92,7 @@ int zig0RunFile(const char* fname, char** msg) {
|
||||
fclose(f);
|
||||
program[fsize] = 0;
|
||||
|
||||
int code = zig0Run(program, msg);
|
||||
int code = zig0Run(program, verbose_air, msg);
|
||||
free(program);
|
||||
return code;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user