✓
Passing This code compiles and runs correctly.
Code
// Test: Koru Interpreter
// Tests the interpreter parsing and executing Koru code at runtime
~import "$std/runtime"
~import "$std/interpreter"
const std = @import("std");
// ============================================================================
// Events to dispatch to
// ============================================================================
~pub event greet { name: []const u8 }
| greeted { message: []const u8 }
~proc greet {
std.debug.print("GREET handler: Hello, {s}!\n", .{name});
return .{ .greeted = .{ .message = "Hello!" } };
}
~pub event farewell { name: []const u8 }
| departed { message: []const u8 }
~proc farewell {
std.debug.print("FAREWELL handler: Goodbye, {s}!\n", .{name});
return .{ .departed = .{ .message = "Goodbye!" } };
}
// Register events for runtime dispatch
~std.runtime:register(scope: "test") {
greet
farewell
}
// ============================================================================
// Entry point - tests the interpreter
// ============================================================================
pub fn main() void {
std.debug.print("=== INTERPRETER TEST ===\n\n", .{});
// Get imports
const koru_parser = @import("koru_parser");
const koru_errors = @import("koru_errors");
// Use the generated dispatcher directly
const dispatcher_fn = dispatch_test;
// ========================================================================
// Test 1: Manual dispatch (baseline)
// ========================================================================
std.debug.print("Test 1: Manual dispatch 'greet'\n", .{});
{
// Use inline types from the generated registry
const segments = [_][]const u8{"greet"};
const path = Path{
.module_qualifier = null,
.segments = &segments,
};
var args_array = [_]Arg{
.{ .name = "name", .value = "World" },
};
const inv = Invocation{
.path = path,
.args = &args_array,
};
var result: DispatchResult = undefined;
dispatcher_fn(&inv, &result) catch |err| {
std.debug.print("ERROR: {}\n", .{err});
return;
};
std.debug.print("Result: branch={s}\n", .{result.branch});
std.debug.print("=== TEST 1 PASSED ===\n\n", .{});
}
// ========================================================================
// Test 2: Parse Koru source and dispatch!
// ========================================================================
std.debug.print("Test 2: Parse and dispatch '~greet(name: \"Runtime\")'\n", .{});
{
const test_source = "~greet(name: \"Runtime\")";
// Create allocator
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
// Create error reporter
var reporter = koru_errors.ErrorReporter.init(
allocator,
"test",
test_source
) catch {
std.debug.print("ERROR: Failed to init reporter\n", .{});
return;
};
defer reporter.deinit();
// Initialize parser
var parser = koru_parser.Parser.init(
allocator,
test_source,
"runtime_input",
&[_][]const u8{},
null
) catch {
std.debug.print("ERROR: Failed to init parser\n", .{});
return;
};
defer parser.deinit();
// Parse!
const parse_result = parser.parse() catch {
std.debug.print("ERROR: Parse failed\n", .{});
if (parser.reporter.hasErrors()) {
const err = parser.reporter.errors.items[0];
std.debug.print(" {s} at {}:{}\n", .{err.message, err.location.line, err.location.column});
}
return;
};
std.debug.print("Parsed {d} items\n", .{parse_result.source_file.items.len});
// Find the flow
var flow_found = false;
for (parse_result.source_file.items) |item| {
if (item == .flow) {
flow_found = true;
const flow = item.flow;
const ast_inv = &flow.invocation;
std.debug.print("Found flow: {s} with {d} args\n", .{
if (ast_inv.path.segments.len > 0) ast_inv.path.segments[0] else "?",
ast_inv.args.len
});
// Cast ast.Invocation to inline Invocation (same memory layout)
const inv: *const Invocation = @ptrCast(ast_inv);
// Dispatch it!
var result: DispatchResult = undefined;
dispatcher_fn(inv, &result) catch |err| {
std.debug.print("ERROR: Dispatch failed: {}\n", .{err});
return;
};
std.debug.print("Result: branch={s}\n", .{result.branch});
break;
}
}
if (!flow_found) {
std.debug.print("ERROR: No flow found in parsed source\n", .{});
return;
}
std.debug.print("=== TEST 2 PASSED ===\n\n", .{});
}
// ========================================================================
// Test 3: Parse multi-arg call
// ========================================================================
std.debug.print("Test 3: Parse '~farewell(name: \"Claude\")'\n", .{});
{
const test_source = "~farewell(name: \"Claude\")";
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, "runtime", &[_][]const u8{}, null) catch return;
defer parser.deinit();
const parse_result = parser.parse() catch {
std.debug.print("ERROR: Parse failed\n", .{});
return;
};
for (parse_result.source_file.items) |item| {
if (item == .flow) {
const ast_inv = &item.flow.invocation;
const inv: *const Invocation = @ptrCast(ast_inv);
var result: DispatchResult = undefined;
dispatcher_fn(inv, &result) catch |err| {
std.debug.print("ERROR: {}\n", .{err});
return;
};
std.debug.print("Result: branch={s}\n", .{result.branch});
break;
}
}
std.debug.print("=== TEST 3 PASSED ===\n\n", .{});
}
std.debug.print("=== ALL INTERPRETER TESTS PASSED ===\n", .{});
}