aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/jq/execute.zig
blob: dfad6c4befe445ec19bea8457f0243934eff6ede (plain)
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
const std = @import("std");
const jv = @import("../jv.zig");
const Instr = @import("./compile.zig").Instr;

pub const ExecuteError = error{
    Unimplemented,
    InvalidType,
    InternalError,
};

pub fn execute(allocator: std.mem.Allocator, instrs: []const Instr, input: jv.Value) !jv.Value {
    var value_stack = try std.array_list.Aligned(jv.Value, null).initCapacity(allocator, 16);
    defer value_stack.deinit(allocator);

    try value_stack.append(allocator, input);

    const len = instrs.len;
    var pc: usize = 0;
    while (pc < len) {
        const cur = instrs[pc];
        switch (cur) {
            .nop => {},
            .array_index => {
                const v1 = value_stack.pop() orelse return error.InternalError;
                const v1_integer = switch (v1) {
                    .integer => |integer| integer,
                    else => return error.InvalidType,
                };
                const v2 = value_stack.pop() orelse return error.InternalError;
                const v2_array = switch (v2) {
                    .array => |array| array,
                    else => return error.InvalidType,
                };
                const index: usize = @intCast(v1_integer);
                const result = if (index < v2_array.items.len) v2_array.items[index] else .null;
                try value_stack.append(allocator, result);
            },
            .literal => |value| {
                try value_stack.append(allocator, value.*);
            },
        }
        pc += 1;
    }

    const result = value_stack.pop() orelse return error.InternalError;
    return result;
}