aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/jq/compile.zig
blob: 5719f9c80491a8a6db2b04ee5aa0c0ca34b336de (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
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
const std = @import("std");
const jv = @import("../jv.zig");
const Ast = @import("./parse.zig").Ast;

pub const Opcode = enum {
    nop,
    ret,
    subexp_begin,
    subexp_end,
    array_index,
    add,
    object_key,
    literal,
};

pub const Instr = union(Opcode) {
    nop,
    ret,
    subexp_begin,
    subexp_end,
    array_index,
    add,
    object_key: []const u8,
    literal: *jv.Value,

    pub fn op(self: @This()) Opcode {
        return self;
    }
};

fn compileExpr(allocator: std.mem.Allocator, compile_allocator: std.mem.Allocator, ast: *const Ast) ![]Instr {
    var instrs = try std.ArrayList(Instr).initCapacity(allocator, 16);

    switch (ast.*) {
        .identity => try instrs.append(allocator, .nop),
        .array_index => |index| {
            const index_instrs = try compileExpr(allocator, compile_allocator, index);
            defer allocator.free(index_instrs);
            try instrs.append(allocator, .subexp_begin);
            try instrs.appendSlice(allocator, index_instrs);
            try instrs.append(allocator, .subexp_end);
            try instrs.append(allocator, .array_index);
        },
        .object_key => |key| try instrs.append(allocator, .{ .object_key = key }),
        .literal => |value| try instrs.append(allocator, .{ .literal = value }),
        .binary_expr => |binary_expr| {
            const rhs_instrs = try compileExpr(allocator, compile_allocator, binary_expr.rhs);
            defer allocator.free(rhs_instrs);
            const lhs_instrs = try compileExpr(allocator, compile_allocator, binary_expr.lhs);
            defer allocator.free(lhs_instrs);
            try instrs.append(allocator, .subexp_begin);
            try instrs.appendSlice(allocator, rhs_instrs);
            try instrs.append(allocator, .subexp_end);
            try instrs.append(allocator, .subexp_begin);
            try instrs.appendSlice(allocator, lhs_instrs);
            try instrs.append(allocator, .subexp_end);
            try instrs.append(allocator, .add);
        },
        .pipe => |pipe_expr| {
            const lhs_instrs = try compileExpr(allocator, compile_allocator, pipe_expr.lhs);
            defer allocator.free(lhs_instrs);
            const rhs_instrs = try compileExpr(allocator, compile_allocator, pipe_expr.rhs);
            defer allocator.free(rhs_instrs);
            try instrs.appendSlice(allocator, lhs_instrs);
            try instrs.appendSlice(allocator, rhs_instrs);
        },
    }

    return instrs.toOwnedSlice(allocator);
}

pub fn compile(allocator: std.mem.Allocator, compile_allocator: std.mem.Allocator, ast: *const Ast) ![]Instr {
    var instrs = try std.ArrayList(Instr).initCapacity(allocator, 16);
    const expr_instrs = try compileExpr(allocator, compile_allocator, ast);
    defer allocator.free(expr_instrs);
    try instrs.appendSlice(allocator, expr_instrs);
    try instrs.append(allocator, .ret);
    return instrs.toOwnedSlice(allocator);
}