PrecomputedFunc now stores raw [*]const u8 byte pointers instead of c.Air, eliminating per-function heap allocations and memcpy in parsePrecomputedAir. airCompareOne takes two PrecomputedFunc values; C-sema output is wrapped via precomputedFromCAir. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
99 lines
3.8 KiB
Zig
99 lines
3.8 KiB
Zig
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|
|
const Ast = std.zig.Ast;
|
|
const AstGen = std.zig.AstGen;
|
|
|
|
const parser_test = @import("parser_test.zig");
|
|
const astgen_test = @import("astgen_test.zig");
|
|
const sema_test = @import("sema_test.zig");
|
|
const c = parser_test.c;
|
|
const sc = sema_test.c;
|
|
const corpus = @import("corpus.zig");
|
|
|
|
test "stages: corpus" {
|
|
@setEvalBranchQuota(corpus.files.len * 2);
|
|
const gpa = std.testing.allocator;
|
|
inline for (corpus.files[0..corpus.num_passing]) |path| {
|
|
stagesCheck(gpa, path, @embedFile("../" ++ path)) catch {
|
|
std.debug.print("FAIL: {s}\n", .{path});
|
|
return error.TestFailed;
|
|
};
|
|
}
|
|
}
|
|
|
|
fn stagesCheck(gpa: Allocator, comptime path: []const u8, source: [:0]const u8) !void {
|
|
// Parse once with C parser
|
|
var c_ast = c.astParse(source.ptr, @intCast(source.len));
|
|
defer c.astDeinit(&c_ast);
|
|
|
|
// Convert C AST to Zig AST once
|
|
var tree = try parser_test.zigAst(gpa, c_ast);
|
|
defer tree.deinit(gpa);
|
|
|
|
// Stage 1: Parser — compare C and Zig ASTs, check canonical rendering
|
|
if (!std.debug.inValgrind()) {
|
|
var zig_tree = try Ast.parse(gpa, source, .zig);
|
|
defer zig_tree.deinit(gpa);
|
|
try parser_test.expectAstConsistent(tree, zig_tree, source);
|
|
}
|
|
if (tree.errors.len == 0) {
|
|
const formatted = try tree.renderAlloc(gpa);
|
|
defer gpa.free(formatted);
|
|
try std.testing.expectEqualStrings(source, formatted);
|
|
}
|
|
|
|
// Stage 2: AstGen — compare C and Zig ZIR
|
|
var ref_zir = try AstGen.generate(gpa, tree);
|
|
defer ref_zir.deinit(gpa);
|
|
|
|
var c_zir = c.astGen(&c_ast);
|
|
defer c.zirDeinit(&c_zir);
|
|
|
|
if (c_zir.has_compile_errors) {
|
|
std.debug.print("C port returned compile errors (inst_len={d})\n", .{c_zir.inst_len});
|
|
return error.TestUnexpectedResult;
|
|
}
|
|
|
|
try astgen_test.expectEqualZir(gpa, ref_zir, c_zir);
|
|
|
|
// Stage 3: Sema — compare C sema vs pre-computed AIR
|
|
{
|
|
// Symlink to the repo root inside a tmpDir so relative imports
|
|
// resolve within the module root, and paths stay under .zig-cache/tmp/
|
|
// to avoid 'std' module conflicts with lib/std/.
|
|
const this_dir = comptime std.fs.path.dirname(@src().file) orelse ".";
|
|
|
|
var tmp = std.testing.tmpDir(.{});
|
|
defer tmp.cleanup();
|
|
|
|
const abs_repo_root = std.fs.cwd().realpathAlloc(gpa, comptime this_dir ++ "/..") catch return error.ResolvePath;
|
|
defer gpa.free(abs_repo_root);
|
|
|
|
tmp.dir.symLink(abs_repo_root, "root", .{ .is_directory = true }) catch return error.SymlinkCreate;
|
|
|
|
var tmp_abs_buf: [std.fs.max_path_bytes]u8 = undefined;
|
|
const tmp_abs = tmp.dir.realpathZ(".", &tmp_abs_buf) catch return error.ResolvePath;
|
|
|
|
const repo_dir = comptime std.fs.path.dirname(path) orelse ".";
|
|
var source_dir_buf: [std.fs.max_path_bytes:0]u8 = undefined;
|
|
const source_dir_path = std.fmt.bufPrintZ(&source_dir_buf, "{s}/root/{s}", .{ tmp_abs, repo_dir }) catch unreachable;
|
|
var module_root_buf: [std.fs.max_path_bytes:0]u8 = undefined;
|
|
const module_root_path = std.fmt.bufPrintZ(&module_root_buf, "{s}/root", .{tmp_abs}) catch unreachable;
|
|
|
|
var c_ip = sc.ipInit();
|
|
defer sc.ipDeinit(&c_ip);
|
|
var c_sema: sc.Sema = undefined;
|
|
sc.semaInit(&c_sema, &c_ip, @bitCast(c_zir));
|
|
defer sc.semaDeinit(&c_sema);
|
|
c_sema.source_dir = source_dir_path.ptr;
|
|
c_sema.module_root = module_root_path.ptr;
|
|
var c_func_air_list = sc.semaAnalyze(&c_sema);
|
|
defer sc.semaFuncAirListDeinit(&c_func_air_list);
|
|
|
|
const air_data = @import("air_data").getData(path);
|
|
const precomputed = try sema_test.parsePrecomputedAir(air_data);
|
|
defer sema_test.freePrecomputedAir(precomputed);
|
|
try sema_test.airComparePrecomputed(precomputed, c_func_air_list);
|
|
}
|
|
}
|