-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgen_result_codes.zig
More file actions
113 lines (100 loc) · 4.37 KB
/
Copy pathgen_result_codes.zig
File metadata and controls
113 lines (100 loc) · 4.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
//
// gen_result_codes.zig — extract the canonical result-code contract from the
// Idris2 model (src/interface/abi/Types.idr) and emit the Zig source file
// (src/interface/ffi/src/result_codes_expected.zig) consumed by the comptime
// cross-check next to GsaResult in main.zig.
//
// Types.idr is the single source of truth: its `resultToInt` clauses define
// the stable (constructor, code) pairs. This tool lifts them into Zig so the
// compiler can assert GsaResult agrees name-for-name and value-for-value —
// the drift this closes shipped once already (codes 5-12 diverged silently).
//
// Run from the repository root:
// zig run scripts/gen_result_codes.zig
// CI re-runs this and `git diff --exit-code`s the result (abi-contract job).
const std = @import("std");
const TYPES_IDR = "src/interface/abi/Types.idr";
const OUT_ZIG = "src/interface/ffi/src/result_codes_expected.zig";
// Constructors whose Zig field name is not the mechanical CamelCase ->
// snake_case conversion. A constructor missing from both this table and the
// mechanical rule fails the build of the *generator*, forcing a conscious
// mapping decision for every new code.
const Override = struct { idris: []const u8, zig: []const u8 };
const overrides = [_]Override{
.{ .idris = "Error", .zig = "err" },
.{ .idris = "VeriSimDBUnavailable", .zig = "verisimdb_unavailable" },
};
const HEADER =
\\// SPDX-License-Identifier: MPL-2.0
\\// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
\\//
\\// @generated by scripts/gen_result_codes.zig from src/interface/abi/Types.idr
\\// DO NOT EDIT. Regenerate with: zig run scripts/gen_result_codes.zig
\\//
\\// Canonical result-code contract lifted from the Idris2 model
\\// (GSA.ABI.Types.resultToInt). Consumed by the comptime block next to
\\// GsaResult in main.zig to assert the two enums agree.
\\
\\pub const ResultCode = struct {
\\ idris_ctor: []const u8,
\\ zig_field: []const u8,
\\ code: c_int,
\\};
\\
\\pub const all = [_]ResultCode{
\\
;
fn zigFieldFor(alloc: std.mem.Allocator, ctor: []const u8) ![]const u8 {
for (overrides) |o| {
if (std.mem.eql(u8, o.idris, ctor)) return try alloc.dupe(u8, o.zig);
}
// Mechanical CamelCase -> snake_case (no consecutive-capital handling:
// constructors needing that must go in `overrides`).
var out = std.array_list.Managed(u8).init(alloc);
errdefer out.deinit();
for (ctor, 0..) |c, i| {
if (std.ascii.isUpper(c)) {
if (i != 0) try out.append('_');
try out.append(std.ascii.toLower(c));
} else {
try out.append(c);
}
}
return out.toOwnedSlice();
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const alloc = gpa.allocator();
const src = try std.fs.cwd().readFileAlloc(alloc, TYPES_IDR, 4 * 1024 * 1024);
defer alloc.free(src);
var out = std.array_list.Managed(u8).init(alloc);
defer out.deinit();
try out.appendSlice(HEADER);
var count: usize = 0;
var lines = std.mem.splitScalar(u8, src, '\n');
while (lines.next()) |line| {
const trimmed = std.mem.trim(u8, line, " \r\t");
if (!std.mem.startsWith(u8, trimmed, "resultToInt ")) continue;
if (std.mem.indexOfScalar(u8, trimmed, ':') != null) continue; // type signature
var it = std.mem.tokenizeAny(u8, trimmed, " \t");
_ = it.next(); // "resultToInt"
const ctor = it.next() orelse return error.BadClause;
const eq = it.next() orelse return error.BadClause;
if (!std.mem.eql(u8, eq, "=")) return error.BadClause;
const code = try std.fmt.parseInt(c_int, it.next() orelse return error.BadClause, 10);
const field = try zigFieldFor(alloc, ctor);
defer alloc.free(field);
try out.writer().print(
" .{{ .idris_ctor = \"{s}\", .zig_field = \"{s}\", .code = {d} }},\n",
.{ ctor, field, code },
);
count += 1;
}
try out.appendSlice("};\n");
if (count == 0) return error.NoClausesFound;
try std.fs.cwd().writeFile(.{ .sub_path = OUT_ZIG, .data = out.items });
std.debug.print("wrote {s} ({d} result codes)\n", .{ OUT_ZIG, count });
}