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
111
112
113
114
|
const std = @import("std");
const jv = @import("../jv.zig");
const Ast = @import("./parse.zig").Ast;
pub const Opcode = enum {
nop,
ret,
jump,
fork,
subexp_begin,
subexp_end,
array_index,
add,
object_key,
literal,
};
pub const Instr = union(Opcode) {
const Self = @This();
nop,
ret,
jump: usize,
fork: usize,
subexp_begin,
subexp_end,
array_index,
add,
object_key: []const u8,
literal: *jv.Value,
pub fn op(self: Self) Opcode {
return self;
}
pub fn deinit(self: Self, allocator: std.mem.Allocator) void {
switch (self) {
.object_key => |key| allocator.free(key),
.literal => |value| allocator.destroy(value),
else => {},
}
}
};
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);
},
.comma => |comma_expr| {
// FORK l1
// <lhs>
// JUMP l2
// l1: <rhs>
// l2:
const lhs_instrs = try compileExpr(allocator, compile_allocator, comma_expr.lhs);
defer allocator.free(lhs_instrs);
const rhs_instrs = try compileExpr(allocator, compile_allocator, comma_expr.rhs);
defer allocator.free(rhs_instrs);
const fork_index = instrs.items.len;
try instrs.append(allocator, .{ .fork = 0 });
try instrs.appendSlice(allocator, lhs_instrs);
const jump_index = instrs.items.len;
try instrs.append(allocator, .{ .jump = 0 });
const l1 = instrs.items.len;
try instrs.appendSlice(allocator, rhs_instrs);
const l2 = instrs.items.len;
instrs.items[fork_index] = .{ .fork = l1 - fork_index };
instrs.items[jump_index] = .{ .jump = l2 - jump_index };
},
}
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);
}
|