Skip to content

refactor(codegen): extract blocks/asset_wiring.zig from main_zig.zig (part of #183) - #197

Merged
apotema merged 1 commit into
feat/183-split-main-zigfrom
refactor/183-extract-asset-wiring
May 25, 2026
Merged

apotema merged 1 commit into
feat/183-split-main-zigfrom
refactor/183-extract-asset-wiring

Conversation

@apotema

@apotema apotema commented May 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Moves writeImageBackendWiring, writeAudioBackendWiring, writeFontBackendWiring (377 lines of pure try w.print(...) emit, no shared state) from src/main_zig.zig to src/codegen/blocks/asset_wiring.zig (402 lines with header).
  • Adds three pub const re-exports in main_zig.zig so every existing call site (the two buildSetupCode / buildCallbackInitCode calls, the root.zig re-exports, the test/tests.zig shape tests) stays byte-for-byte unchanged.
  • Fourth extraction per docs/REFACTOR-PLAN-main-zig.md step 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 to main cleanly (no logical conflicts with the other two parallel extractions — each touches a different line range in main_zig.zig and only co-edits the pub const re-export header).

Bit-identical verification

scripts/gen_all_examples.sh regenerated against the pre-extraction baseline (origin/refactor/183-extract-next) and the post-extraction branch:

  • 8 / 8 working bundled examples generate green (raylib, sokol, null, plugin-controllers, flows-smoke, asset-streaming-smoke, bgfx, wgpu). sokol_imgui soft-fails identically on both sides (missing labelle-imgui sibling).
  • 3314 / 3322 generated files byte-identical. The 8 differing files are all flow_catalog.json — only the generated_at ISO-8601 timestamp differs, the documented expected drift (see plan §"Bit-identical verification").
  • Every main.zig is byte-identical (cmp pass across all 8 examples).

Test plan

  • zig build exit 0
  • zig build test --summary all: 22/22 steps succeeded; 506/510 tests passed (4 skipped) — identical to baseline.
  • scripts/gen_all_examples.sh byte-identical diff vs baseline (excl. flow_catalog.json timestamp drift).

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/codegen/scan.zig
Comment on lines +653 to +658
return .{
.flow_nodes = try flow_nodes.toOwnedSlice(allocator),
.pin_styles = try pin_styles.toOwnedSlice(allocator),
.coercions = try coercions.toOwnedSlice(allocator),
.allocator = allocator,
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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,
    };

Comment thread src/codegen/scan.zig
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});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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
  1. In CLI tools, use standard logging facilities (e.g., std.log.warn) or write to stderr for user-facing warnings, rather than using debug-specific print functions (e.g., std.debug.print).

@apotema
apotema requested a review from Copilot May 25, 2026 18:52
@apotema
apotema changed the base branch from main to feat/183-split-main-zig May 25, 2026 18:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.zig and leaf identifier/string helpers into src/codegen/idents.zig, re-exporting from src/main_zig.zig to keep existing imports stable.
  • Extracts asset-backend wiring emitters into src/codegen/blocks/asset_wiring.zig, re-exporting the three write*BackendWiring helpers.
  • 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.

Comment on lines 3 to 6
Comment thread src/main_zig.zig
Comment on lines 6 to 9
/// 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.
Comment thread src/codegen/scan.zig
Comment on lines 28 to 29
@apotema
apotema marked this pull request as ready for review May 25, 2026 20:25
@cursor

cursor Bot commented May 25, 2026 •

Copy link
Copy Markdown

PR Summary

Low Risk
Mechanical file move with re-exports; PR verification reports byte-identical generated main.zig across examples.

Overview
Refactor #183 step 4: the three asset-backend codegen emitters (writeImageBackendWiring, writeAudioBackendWiring, writeFontBackendWiring) move out of main_zig.zig into new src/codegen/blocks/asset_wiring.zig. The bodies are unchanged string templates; main_zig.zig only adds @import("codegen/blocks/asset_wiring.zig") and pub const aliases so buildSetupCode / buildCallbackInitCode, root.zig, and tests keep the same symbols and emitted main.zig output.

writeImageBackendWiring is now pub in the block module (it was a private fn in main_zig before); visibility for callers is still via the re-exports. Audio/font helpers remain scaffolding with the same gating in the lifecycle builders; no new call sites or wiring behavior in this PR.

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>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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.

Comment thread src/main_zig.zig
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");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3316131. Configure here.

@apotema
apotema force-pushed the refactor/183-extract-asset-wiring branch from 3316131 to 66c7a61 Compare May 25, 2026 20:31
@apotema
apotema merged commit d65c958 into feat/183-split-main-zig May 25, 2026
1 check passed
apotema added a commit that referenced this pull request May 25, 2026
… 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants