015 interpreter dataflow

✓ Passing This code compiles and runs correctly.

Code

// Test: Interpreter Dataflow with Branch Constructor
// Tests the interpreter returning structured data via branch constructors

~import "$std/runtime"


const std = @import("std");

// ============================================================================
// Events that produce data
// ============================================================================

~pub event validate { data: []const u8 }
| valid { value: []const u8 }
| invalid { reason: []const u8 }

~proc validate {
    // Simple validation - non-empty = valid
    if (data.len > 0) {
        return .{ .valid = .{ .value = data } };
    }
    return .{ .invalid = .{ .reason = "empty input" } };
}

~pub event transform { input: []const u8 }
| transformed { output: []const u8 }

~proc transform {
    // Simple transform - uppercase first char (just return as-is for test)
    return .{ .transformed = .{ .output = input } };
}

// Register events
~std.runtime:register(scope: "api") {
    validate
    transform
}

// ============================================================================
// Entry point
// ============================================================================

pub fn main() void {
    const koru_parser = @import("koru_parser");
    const koru_errors = @import("koru_errors");

    std.debug.print("\n", .{});
    std.debug.print("╔══════════════════════════════════════════════════════════════╗\n", .{});
    std.debug.print("║           INTERPRETER DATAFLOW TEST                          ║\n", .{});
    std.debug.print("╚══════════════════════════════════════════════════════════════╝\n\n", .{});

    const dispatcher_fn = dispatch_api;

    // ========================================================================
    // Test 1: Simple dispatch, terminal on branch
    // ========================================================================
    std.debug.print("Test 1: Simple flow ending on branch terminal (_)\n", .{});
    {
        // ~validate(data: "hello")
        // | valid v |> _
        const test_source =
            \\~validate(data: "hello")
            \\| valid v |> _
        ;

        var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
        defer arena.deinit();
        const allocator = arena.allocator();

        var reporter = koru_errors.ErrorReporter.init(allocator, "test", test_source) catch return;
        defer reporter.deinit();

        var parser = koru_parser.Parser.init(allocator, test_source, "test", &[_][]const u8{}, null) catch return;
        defer parser.deinit();

        const parse_result = parser.parse() catch {
            std.debug.print("  ERROR: Parse failed\n", .{});
            return;
        };

        std.debug.print("  Parsed. Looking for flow...\n", .{});

        for (parse_result.source_file.items) |item| {
            if (item == .flow) {
                const ast_inv = &item.flow.invocation;
                std.debug.print("  Found flow: {s}\n", .{ast_inv.path.segments[0]});
                std.debug.print("  Continuations: {d}\n", .{item.flow.continuations.len});

                // Cast and dispatch
                const inv: *const Invocation = @ptrCast(ast_inv);
                var result: DispatchResult = undefined;
                dispatcher_fn(inv, &result) catch |err| {
                    std.debug.print("  ERROR: Dispatch failed: {}\n", .{err});
                    return;
                };

                std.debug.print("  Dispatch result: branch={s}\n", .{result.branch});
                std.debug.print("  ✓ TEST 1 PASSED\n\n", .{});
                break;
            }
        }
    }

    // ========================================================================
    // Test 2: Flow with branch constructor terminal - FULL EXECUTION
    // ========================================================================
    std.debug.print("Test 2: Full dataflow execution with branch constructor\n", .{});
    {
        const test_source =
            \\~validate(data: "hello")
            \\| valid v |> result { status: "ok", input: "hello" }
        ;

        var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
        defer arena.deinit();
        const allocator = arena.allocator();

        var reporter = koru_errors.ErrorReporter.init(allocator, "test", test_source) catch return;
        defer reporter.deinit();

        var parser = koru_parser.Parser.init(allocator, test_source, "test", &[_][]const u8{}, null) catch return;
        defer parser.deinit();

        const parse_result = parser.parse() catch |err| {
            std.debug.print("  ERROR: Parse failed: {}\n", .{err});
            return;
        };

        std.debug.print("  Parsed successfully!\n", .{});

        // Find and execute the flow
        for (parse_result.source_file.items) |item| {
            if (item == .flow) {
                const flow = &item.flow;

                // Step 1: Dispatch the invocation
                const ast_inv = &flow.invocation;
                const inv: *const Invocation = @ptrCast(ast_inv);
                var dispatch_result: DispatchResult = undefined;
                dispatcher_fn(inv, &dispatch_result) catch |err| {
                    std.debug.print("  ERROR: Dispatch failed: {}\n", .{err});
                    return;
                };

                std.debug.print("  Dispatched: branch={s}\n", .{dispatch_result.branch});

                // Step 2: Find matching continuation
                for (flow.continuations) |cont| {
                    if (std.mem.eql(u8, cont.branch, dispatch_result.branch)) {
                        std.debug.print("  Matched continuation: {s}\n", .{cont.branch});

                        // Step 3: Check node type
                        if (cont.node) |node| {
                            if (node == .branch_constructor) {
                                const bc = node.branch_constructor;
                                std.debug.print("  Found branch constructor: {s}\n", .{bc.branch_name});

                                // Step 4: Build the result!
                                std.debug.print("  RESULT:\n", .{});
                                std.debug.print("    branch: {s}\n", .{bc.branch_name});
                                std.debug.print("    fields:\n", .{});
                                for (bc.fields) |field| {
                                    // Evaluate expression (strip quotes for strings)
                                    var value = field.expression_str orelse "";
                                    if (value.len >= 2 and value[0] == '"' and value[value.len-1] == '"') {
                                        value = value[1..value.len-1];
                                    }
                                    std.debug.print("      {s}: {s}\n", .{field.name, value});
                                }
                            } else if (node == .terminal) {
                                std.debug.print("  RESULT (terminal):\n", .{});
                                std.debug.print("    branch: {s}\n", .{dispatch_result.branch});
                            }
                        }
                        break;
                    }
                }

                std.debug.print("  ✓ TEST 2 PASSED\n\n", .{});
                break;
            }
        }
    }

    std.debug.print("╔══════════════════════════════════════════════════════════════╗\n", .{});
    std.debug.print("║                 ALL DATAFLOW TESTS PASSED                    ║\n", .{});
    std.debug.print("╚══════════════════════════════════════════════════════════════╝\n", .{});
}
input.kz