010 generics bracket syntax

✓ Passing This code compiles and runs correctly.

Code

// Test: Parser accepts generic params in event names via bracket syntax
//
// ~ring.new[T:u32;N:1024](name: "my_ring")
//
// This is NOT phantom type syntax (which appears on TYPE references).
// This is generic parameter syntax (which appears on EVENT names).
//
// Phantom:  *Entity[position+velocity]  ← on type
// Generic:  ring.new[T:u32;N:1024]      ← on event name
//
// Semicolon separates params to avoid ambiguity with nested types:
//   ring.new[T:HashMap<K,V>;N:64]  ← clear!
//   ring.new[T:HashMap<K,V>,N:64]  ← comma soup
//
// Parser sees the brackets as part of the event name string.
// Transform receives full name: "ring.new[T:u32;N:1024]"
// Transform parses brackets, extracts T=u32, N=1024, synthesizes typed code.

~[comptime|transform]pub event ring.* {
    event_name: []const u8,
    item: *const Item,
    program: *const Program,
}
| transformed { program: *const Program }

~proc ring.* {
    const std = @import("std");
    const ast = @import("ast");
    const ast_functional = @import("ast_functional");
    const allocator = std.heap.page_allocator;

    // Parse generic params from event_name
    // e.g., "ring.new[T:u32;N:1024]" → command="new", T="u32", N="1024"

    // Find the bracket position
    const bracket_start = std.mem.indexOf(u8, event_name, "[");
    const bracket_end = std.mem.lastIndexOf(u8, event_name, "]");

    if (bracket_start == null or bracket_end == null) {
        // No generic params - this is fine for some ring operations
        return .{ .transformed = .{ .program = program } };
    }

    const command = event_name[5..bracket_start.?]; // Skip "ring."
    const params_str = event_name[bracket_start.? + 1 .. bracket_end.?];

    // For this test, just verify we can parse the params
    // Real implementation would use a proper parser
    const code = std.fmt.allocPrint(
        allocator,
        "// ring.{s} with params: {s}\n",
        .{ command, params_str }
    ) catch unreachable;

    const flow = if (item.* == .flow) &item.flow else return .{ .transformed = .{ .program = program } };

    const inline_code_item = ast.Item{
        .inline_code = ast.InlineCode{
            .code = code,
            .location = flow.location,
            .module = allocator.dupe(u8, flow.module) catch unreachable,
        },
    };

    const maybe_new_program = ast_functional.replaceFlowRecursive(allocator, program, flow, inline_code_item) catch unreachable;
    if (maybe_new_program) |new_program| {
        const result = allocator.create(ast.Program) catch unreachable;
        result.* = new_program;
        return .{ .transformed = .{ .program = result } };
    }
    return .{ .transformed = .{ .program = program } };
}

// This invocation has generic params in brackets
~ring.new[T:u32;N:1024](name: "my_ring")
input.kz