1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
const std = @import("std");
const jv = @import("../jv.zig");
const Instr = @import("./compile.zig").Instr;
pub const ExecuteError = error{
Unimplemented,
InvalidType,
InternalError,
};
const ValueStack = struct {
const Self = @This();
const Stack = std.ArrayList(jv.Value);
stack: Stack,
allocator: std.mem.Allocator,
pub fn init(allocator: std.mem.Allocator) !Self {
return .{
.stack = try Stack.initCapacity(allocator, 16),
.allocator = allocator,
};
}
pub fn deinit(self: *Self) void {
self.stack.deinit(self.allocator);
}
pub fn push(self: *Self, value: jv.Value) !void {
try self.stack.append(self.allocator, value);
}
pub fn pop(self: *Self) ExecuteError!jv.Value {
return self.stack.pop() orelse return error.InternalError;
}
pub fn popInteger(self: *Self) ExecuteError!i64 {
const value = try self.pop();
return switch (value) {
.integer => |i| i,
else => error.InvalidType,
};
}
pub fn popNumber(self: *Self) ExecuteError!f64 {
const value = try self.pop();
return switch (value) {
.integer => |i| @floatFromInt(i),
.float => |f| f,
else => error.InvalidType,
};
}
pub fn popString(self: *Self) ExecuteError![]const u8 {
const value = try self.pop();
return switch (value) {
.string => |s| s,
else => error.InvalidType,
};
}
pub fn popArray(self: *Self) ExecuteError!jv.Array {
const value = try self.pop();
return switch (value) {
.array => |a| a,
else => error.InvalidType,
};
}
pub fn popObject(self: *Self) ExecuteError!jv.Object {
const value = try self.pop();
return switch (value) {
.object => |o| o,
else => error.InvalidType,
};
}
};
pub fn execute(allocator: std.mem.Allocator, instrs: []const Instr, input: jv.Value) !jv.Value {
var value_stack = try ValueStack.init(allocator);
defer value_stack.deinit();
try value_stack.push(input);
const len = instrs.len;
var pc: usize = 0;
while (pc < len) {
const cur = instrs[pc];
switch (cur) {
.nop => {},
.array_index => {
const index: usize = @intCast(try value_stack.popInteger());
const array = try value_stack.popArray();
const result = if (index < array.items.len) array.items[index] else .null;
try value_stack.push(result);
},
.object_key => |key| {
const obj = try value_stack.popObject();
const result = obj.get(key) orelse .null;
try value_stack.push(result);
},
.literal => |value| {
try value_stack.push(value.*);
},
}
pc += 1;
}
return value_stack.pop();
}
|