Skip to content

Commit d47cac0

Browse files
Antigravity Agentclaude
andcommitted
feat(gen): Add constants section support for Phase C
- Add ConstDef struct to tri_reader - Implement parseConstants() function - Generate pub const declarations in genStructTypes - skip_list.tri now generates MAX_LEVEL and PROBABILITY constants - Resolves: forward field can now use [MAX_LEVEL]?*Node(K, V) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 59fa8c9 commit d47cac0

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

tools/gen/tri_gen.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,12 @@ fn genStructTypes(
651651
try writer.print("// Level {d} Data Structures\n", .{spec.level});
652652
try writer.print("\nconst std = @import(\"std\");\n\n", .{});
653653

654+
// Generate constants
655+
for (spec.constants) |c| {
656+
try writer.print("pub const {s} = {s};\n", .{ c.name, c.value });
657+
}
658+
if (spec.constants.len > 0) try writer.print("\n", .{});
659+
654660
// Generate types
655661
for (spec.types) |td| {
656662
// Handle enum type definitions (e.g., Color = enum { Red, Black })

tools/gen/tri_reader.zig

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub const Spec = struct {
2525
// Level 5 (Data Structures) fields:
2626
spec_type: ?[]const u8 = null,
2727
types: []const TypeDef = &.{},
28-
// constants: stored as slice of ConstDef (deferred for MVP)
28+
constants: []const ConstDef = &.{},
2929

3030
pub fn deinit(self: *Spec, allocator: std.mem.Allocator) void {
3131
allocator.free(self.fields);
@@ -46,6 +46,11 @@ pub const TypeDef = struct {
4646
enum_values: []const []const u8 = &.{},
4747
};
4848

49+
pub const ConstDef = struct {
50+
name: []const u8,
51+
value: []const u8, // Stored as string for flexibility (int, float, etc.)
52+
};
53+
4954
pub const Storage = struct {
5055
bits: u8,
5156
align_bytes: u8,
@@ -428,6 +433,13 @@ const Parser = struct {
428433
_ = try self.parseConversion();
429434
} else if (std.mem.eql(u8, maybe_key, "ops")) {
430435
spec.ops = try self.parseOpList();
436+
} else if (std.mem.eql(u8, maybe_key, "constants")) {
437+
// constants: is a section header
438+
self.skipWhitespaceAndComments();
439+
if (self.peek()) |ch| {
440+
if (ch == ':') _ = self.advance();
441+
}
442+
spec.constants = try self.parseConstants();
431443
} else if (std.mem.eql(u8, maybe_key, "types")) {
432444
// types: is a section header, not a key-value pair
433445
// Skip to next line for type definitions
@@ -998,6 +1010,61 @@ const Parser = struct {
9981010
return list.toOwnedSlice(self.allocator);
9991011
}
10001012

1013+
fn parseConstants(self: *Parser) ![]const ConstDef {
1014+
// Parse constants: section
1015+
// Format: indent 2 (4 spaces): NAME: value
1016+
// Example:
1017+
// MAX_LEVEL: 16
1018+
// PROBABILITY: 0.5
1019+
1020+
var constants = try std.ArrayList(ConstDef).initCapacity(self.allocator, 0);
1021+
errdefer constants.deinit(self.allocator);
1022+
1023+
// Get current position (after "constants:" key)
1024+
const start_pos = self.pos;
1025+
1026+
// Split remaining content into lines
1027+
var lines_it = std.mem.splitScalar(u8, self.content[start_pos..], '\n');
1028+
1029+
while (lines_it.next()) |raw_line| {
1030+
// Skip empty lines and comments
1031+
const trimmed = std.mem.trimLeft(u8, raw_line, " \t\r");
1032+
if (trimmed.len == 0 or trimmed[0] == '#') continue;
1033+
1034+
// Count indentation (2-space units)
1035+
const indent = countIndent(raw_line);
1036+
1037+
// Check for top-level section ending (ops:, composite:, types:, etc.)
1038+
if (indent == 0) {
1039+
if (std.mem.indexOfScalar(u8, trimmed, ':')) |colon_idx| {
1040+
const key = trimmed[0..colon_idx];
1041+
if (std.mem.eql(u8, key, "ops") or std.mem.eql(u8, key, "composite") or
1042+
std.mem.eql(u8, key, "test_vectors") or std.mem.eql(u8, key, "description") or
1043+
std.mem.eql(u8, key, "storage") or std.mem.eql(u8, key, "level") or
1044+
std.mem.eql(u8, key, "format") or std.mem.eql(u8, key, "version") or
1045+
std.mem.eql(u8, key, "type") or std.mem.eql(u8, key, "types"))
1046+
{
1047+
break;
1048+
}
1049+
}
1050+
}
1051+
1052+
// Constant definition at indent 1 (2 spaces): "MAX_LEVEL: 16"
1053+
if (indent == 1) {
1054+
if (std.mem.indexOfScalar(u8, trimmed, ':')) |colon_idx| {
1055+
const const_name = std.mem.trimRight(u8, trimmed[0..colon_idx], " \t");
1056+
const const_value = std.mem.trim(u8, trimmed[colon_idx + 1 ..], " \t\r");
1057+
try constants.append(self.allocator, .{
1058+
.name = try self.allocator.dupe(u8, const_name),
1059+
.value = try self.allocator.dupe(u8, const_value),
1060+
});
1061+
}
1062+
}
1063+
}
1064+
1065+
return constants.toOwnedSlice(self.allocator);
1066+
}
1067+
10011068
fn parseTypes(self: *Parser) ![]const TypeDef {
10021069
// Line-based parser for indentation-based type definitions
10031070
// This handles YAML-like structure where type names are at indent 2

0 commit comments

Comments
 (0)