Repository navigation
refactor(codegen): extract blocks/asset_wiring.zig from main_zig.zig (part of #183) - #197
Conversation
There was a problem hiding this comment.
Code Review
This pull request initiates a refactoring plan to split the large src/main_zig.zig file into smaller, more maintainable submodules under src/codegen/. It extracts discovery and scanning helpers into src/codegen/scan.zig, string/identifier helpers into src/codegen/idents.zig, and asset-backend wiring emitters into src/codegen/blocks/asset_wiring.zig. Additionally, a bash script is introduced to verify that the generated output remains bit-identical across all examples. The review feedback highlights a potential memory leak in discoverPluginFlowDecls if subsequent toOwnedSlice allocations fail, and suggests replacing std.debug.print with standard logging facilities like std.log.err for CLI warnings.
| return .{ | ||
| .flow_nodes = try flow_nodes.toOwnedSlice(allocator), | ||
| .pin_styles = try pin_styles.toOwnedSlice(allocator), | ||
| .coercions = try coercions.toOwnedSlice(allocator), | ||
| .allocator = allocator, | ||
| }; |
There was a problem hiding this comment.
There is a potential memory leak if any of the subsequent toOwnedSlice calls fail (e.g., due to Out Of Memory) after flow_nodes.toOwnedSlice has succeeded. When toOwnedSlice succeeds, it resets the underlying ArrayList to empty, which means the top-level errdefer blocks will no longer free the successfully allocated slices. To prevent this, we should allocate the slices first and register errdefer blocks to clean them up if a subsequent allocation fails.
const flow_nodes_slice = try flow_nodes.toOwnedSlice(allocator);
errdefer {
for (flow_nodes_slice) |e| {
allocator.free(e.module_import_path);
allocator.free(e.module_sanitized);
allocator.free(e.node_name);
if (e.constructs) |c| allocator.free(c);
}
allocator.free(flow_nodes_slice);
}
const pin_styles_slice = try pin_styles.toOwnedSlice(allocator);
errdefer {
for (pin_styles_slice) |e| {
allocator.free(e.module_import_path);
allocator.free(e.module_sanitized);
allocator.free(e.type_name);
}
allocator.free(pin_styles_slice);
}
const coercions_slice = try coercions.toOwnedSlice(allocator);
return .{
.flow_nodes = flow_nodes_slice,
.pin_styles = pin_styles_slice,
.coercions = coercions_slice,
.allocator = allocator,
};
| const append = struct { | ||
| fn f(b: *[256]u8, idx: *usize, bytes: []const u8) void { | ||
| if (idx.* + bytes.len > b.len) { | ||
| std.debug.print("labelle: path too long for identifier (max {d} chars): too many escaped chars\n", .{b.len}); |
There was a problem hiding this comment.
In CLI tools, standard logging facilities (such as std.log.err) or writing directly to stderr should be used for user-facing warnings/errors, rather than using debug-specific print functions like std.debug.print.
std.log.err("labelle: path too long for identifier (max {d} chars): too many escaped chars", .{b.len});
References
- In CLI tools, use standard logging facilities (e.g.,
std.log.warn) or write tostderrfor user-facing warnings, rather than using debug-specific print functions (e.g.,std.debug.print).
There was a problem hiding this comment.
Pull request overview
Refactors the main.zig generator by extracting self-contained codegen helpers into dedicated modules to reduce src/main_zig.zig size while preserving byte-identical generated output via re-export shims.
Changes:
- Extracts plugin/script discovery helpers into
src/codegen/scan.zigand leaf identifier/string helpers intosrc/codegen/idents.zig, re-exporting fromsrc/main_zig.zigto keep existing imports stable. - Extracts asset-backend wiring emitters into
src/codegen/blocks/asset_wiring.zig, re-exporting the threewrite*BackendWiringhelpers. - Adds a regeneration script (
scripts/gen_all_examples.sh) and a refactor plan doc (docs/REFACTOR-PLAN-main-zig.md) to support bit-identical verification and incremental slicing.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main_zig.zig | Imports new modules and re-exports moved helpers to preserve existing call sites. |
| src/codegen/scan.zig | New module containing AST-based discovery logic and pathToIdent tests moved from main_zig.zig. |
| src/codegen/idents.zig | New leaf utility module for identifier/string emission helpers extracted from main_zig.zig. |
| src/codegen/blocks/asset_wiring.zig | New module containing the three asset-backend wiring emitters extracted verbatim. |
| scripts/gen_all_examples.sh | Adds a script to regenerate all bundled examples for before/after diffing. |
| docs/REFACTOR-PLAN-main-zig.md | Adds an incremental refactor plan and documents the bit-identical verification workflow. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// now live in `src/codegen/scan.zig`. They are re-exported below so | ||
| /// `root.zig` and `test/tests.zig` can keep their existing imports | ||
| /// unchanged while the split lands incrementally. See | ||
| /// `docs/REFACTOR-PLAN-main-zig.md` for the full cut plan. |
PR SummaryLow Risk Overview
Reviewed by Cursor Bugbot for commit 66c7a61. Bugbot is set up for automated code reviews on this repo. Configure here. |
…(part of #183) Fourth extraction per the plan in #193. Moved writeImageBackendWiring/writeAudioBackendWiring/writeFontBackendWiring to src/codegen/blocks/asset_wiring.zig (377 lines of pure emit, no state). Re-exported from main_zig.zig so callers don't change. Bit-identical generated output across all 8 working bundled examples (scripts/gen_all_examples.sh green; sokol_imgui soft-fails on missing labelle-imgui sibling, same as baseline). Refs: #183 Builds on: #195 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3316131. Configure here.
| const scene_manifest = @import("scene_manifest.zig"); | ||
| const scan = @import("codegen/scan.zig"); | ||
| const idents = @import("codegen/idents.zig"); | ||
| pub const asset_wiring = @import("codegen/blocks/asset_wiring.zig"); |
There was a problem hiding this comment.
Module import unnecessarily pub, inconsistent with sibling imports
Low Severity
The asset_wiring import is declared pub const while every other module import in the file (std, tpl, config, cache, script_scanner, scene_manifest, scan, idents) uses const (private). This unnecessarily exposes the internal module through main_zig.asset_wiring, breaking the established pattern where only individual symbols are selectively re-exported. Relatedly, writeImageBackendWiring was originally fn (private) but is now re-exported as pub const, widening the API surface — root.zig only re-exports the audio and font variants, suggesting the image variant was intentionally private.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 3316131. Configure here.
3316131 to
66c7a61
Compare
… of #183) Per the plan in #193. Moved buildSetupCode (raylib/sdl/bgfx/wgpu loop-backend setup) + buildGuiDrawCode to src/codegen/lifecycle/loop.zig (235 lines). Re-exported from main_zig.zig so the orchestrator's references stay unchanged. HIGH-risk extraction per the plan -- preserves call order across writeXxxWiring helpers + emitResourceLoad. Verified bit-identical across all 8 working bundled examples (scripts/gen_all_examples.sh); sokol_imgui still soft-fails because the labelle-imgui sibling repo is absent, same as on origin/main. On this branch the helpers reached by buildSetupCode (writeImageBackendWiring, writeAudioBackendWiring, writeFontBackendWiring, emitResourceLoad, LoadStyle) are still inline in main_zig.zig -- pubified here so the new module can reach them. When the parallel blocks/asset_wiring + blocks/resource_loader cuts (PRs #197, #199) land, lifecycle/loop.zig's imports flip to the new modules and the pub markers in main_zig.zig retire alongside the moved bodies. main_zig.zig shrank 3817 -> 3628 lines (-189). zig build test: 506/510 passed (4 skipped) -- unchanged from baseline. Refs: #183 Builds on: #202 (umbrella) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>


Summary
writeImageBackendWiring,writeAudioBackendWiring,writeFontBackendWiring(377 lines of puretry w.print(...)emit, no shared state) fromsrc/main_zig.zigtosrc/codegen/blocks/asset_wiring.zig(402 lines with header).pub constre-exports inmain_zig.zigso every existing call site (the twobuildSetupCode/buildCallbackInitCodecalls, theroot.zigre-exports, thetest/tests.zigshape tests) stays byte-for-byte unchanged.docs/REFACTOR-PLAN-main-zig.mdstep 4 (low risk; "meaningful demo of the block-extraction pattern").main_zig.zig: 3817 → 3453 lines.Base-branch dependency
This PR is stacked on
refactor/183-extract-next(#195). Merge that first; once merged the base will retarget tomaincleanly (no logical conflicts with the other two parallel extractions — each touches a different line range inmain_zig.zigand only co-edits thepub constre-export header).Bit-identical verification
scripts/gen_all_examples.shregenerated against the pre-extraction baseline (origin/refactor/183-extract-next) and the post-extraction branch:sokol_imguisoft-fails identically on both sides (missinglabelle-imguisibling).flow_catalog.json— only thegenerated_atISO-8601 timestamp differs, the documented expected drift (see plan §"Bit-identical verification").main.zigis byte-identical (cmp pass across all 8 examples).Test plan
zig buildexit 0zig build test --summary all: 22/22 steps succeeded; 506/510 tests passed (4 skipped) — identical to baseline.scripts/gen_all_examples.shbyte-identical diff vs baseline (excl.flow_catalog.jsontimestamp drift).