mmm, youre right. I’m using empty array now instead null.
// runtime
fn evaluate(node: *const Node) Value {
std.debug.print("evaluate: {any}\n\n", .{node});
return switch (node.kind) {
.Program => {
var last_evaluated: ?Value = null;
for (node.children) |statement| {
last_evaluated = evaluate(statement);
}
return last_evaluated orelse Value.mkNull();
},
.BinaryExpression => {
const NodeProps = node.props.?.BinaryExpression;
const left_node = evaluate(NodeProps.left);
const right_node = evaluate(NodeProps.right);
return eval_binary_expr(left_node, right_node, NodeProps.operator);
},
.Number => {
return Value.mkNumber(node.props.?.Number.value);
},
else => @panic("?"),
};
}
pub fn run(source: []const u8) Parser.Errors!Value {
const AST = try Parser.init(source);
std.debug.print("run: {any}\n\n", .{AST});
return evaluate(&AST);
}
Look logs:
run: ast.Node{ .kind = ast.Node.Kind.Program, .props = null, .children = { ast.Node{ .kind = ast.Node.Kind.BinaryExpression, .props = ast.Node.Properties{ ... }, .children = { ... } } } }
evaluate: ast.Node{ .kind = ast.Node.Kind.Program, .props = null, .children = { ast.Node{ .kind = ast.Node.Kind.Program, .props = ast.Node.Properties{ ... }, .children = { ... } } } }
evaluate: ast.Node{ .kind = ast.Node.Kind.Program, .props = ast.Node.Properties{ .Program = void }, .children = { ast.Node{ .kind = ast.Node.Kind.thread 1872 panic: invalid enum value
C:\Users\esmer\zig\lib\std\fmt.zig:538:37: 0x843e8 in formatType__anon_8233 (main.exe.obj)
try writer.writeAll(@tagName(value));
^
C:\Users\esmer\zig\lib\std\fmt.zig:607:31: 0x9150c in formatType__anon_8519 (main.exe.obj)
try formatType(@field(value, f.name), ANY, options, writer, max_depth - 1);
^
C:\Users\esmer\zig\lib\std\fmt.zig:614:38: 0x91211 in formatType__anon_8518 (main.exe.obj)
return formatType(value.*, actual_fmt, options, writer, max_depth);
^
C:\Users\esmer\zig\lib\std\fmt.zig:640:35: 0x8472d in formatType__anon_8235 (main.exe.obj)
try formatType(elem, actual_fmt, options, writer, max_depth - 1);
^
C:\Users\esmer\zig\lib\std\fmt.zig:607:31: 0x9181f in formatType__anon_8519 (main.exe.obj)
try formatType(@field(value, f.name), ANY, options, writer, max_depth - 1);
^
C:\Users\esmer\zig\lib\std\fmt.zig:614:38: 0x84861 in formatType__anon_8240 (main.exe.obj)
return formatType(value.*, actual_fmt, options, writer, max_depth);
^
C:\Users\esmer\zig\lib\std\fmt.zig:184:23: 0x6ea7c in format__anon_7250 (main.exe.obj)
try formatType(
^
C:\Users\esmer\zig\lib\std\io\Writer.zig:23:26: 0x36112 in print__anon_4361 (main.exe.obj)
return std.fmt.format(self, format, args);
^
C:\Users\esmer\zig\lib\std\debug.zig:88:27: 0x33560 in print__anon_4282 (main.exe.obj)
nosuspend stderr.print(fmt, args) catch return;
^
C:\Users\esmer\OneDrive\Documentos\vp\src\runtime.zig:49:20: 0x31abc in evaluate (main.exe.obj)
std.debug.print("evaluate: {any}\n\n", .{node});
^
C:\Users\esmer\OneDrive\Documentos\vp\src\runtime.zig:55:42: 0x31b9e in evaluate (main.exe.obj)
last_evaluated = evaluate(statement);
^
C:\Users\esmer\OneDrive\Documentos\vp\src\runtime.zig:77:20: 0x31150 in run (main.exe.obj)
return evaluate(&AST);
^
C:\Users\esmer\OneDrive\Documentos\vp\src\main.zig:8:20: 0x3102d in main (main.exe.obj)
Runtime.run("5 + 6"),
^
C:\Users\esmer\zig\lib\std\start.zig:350:53: 0x313c1 in WinStartup (main.exe.obj)
std.os.windows.ntdll.RtlExitUserProcess(callMain());
^
???:?:?: 0x7ffaafb5257c in ??? (KERNEL32.DLL)
???:?:?: 0x7ffab0aeaf07 in ??? (ntdll.dll)
about the parser:
pub fn init(source: []const u8) Errors!Node {
var tokens = try Lexer.init(source);
defer tokens.deinit();
var src = try Reader.init(&tokens);
var program_children = std.ArrayList(*const Node).init(allocator);
errdefer program_children.deinit();
while (if (src.curr()) |c| c.tag != TokenTag.EOF else false) {
const stmt = parse_stmt(&src);
try program_children.append(&stmt);
}
const node = Node{
.kind = .Program,
.children = try program_children.toOwnedSlice(),
.props = null,
};
return node;
}
...