2023-01-02 14:28:25 +00:00
|
|
|
const std = @import("std");
|
|
|
|
|
const zml = @import("../../zml.zig");
|
|
|
|
|
const meta = zml.meta;
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
const py = @import("py.zig");
|
2023-04-04 17:20:53 +00:00
|
|
|
const pickle = @import("pickle.zig");
|
2023-01-02 14:28:25 +00:00
|
|
|
|
|
|
|
|
const MAX_DEPTH: usize = 250;
|
|
|
|
|
const MAX_PROTOCOL: u8 = 5;
|
|
|
|
|
|
|
|
|
|
pub const PickleMemo = struct {
|
2023-04-20 15:43:18 +00:00
|
|
|
map: std.AutoHashMap(u32, py.Any),
|
2023-01-02 14:28:25 +00:00
|
|
|
|
|
|
|
|
pub fn init(allocator: std.mem.Allocator) PickleMemo {
|
|
|
|
|
return .{
|
2023-04-20 15:43:18 +00:00
|
|
|
.map = std.AutoHashMap(u32, py.Any).init(allocator),
|
2023-01-02 14:28:25 +00:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn deinit(self: *PickleMemo) void {
|
2023-04-20 15:43:18 +00:00
|
|
|
const allocator = self.map.allocator;
|
2023-01-02 14:28:25 +00:00
|
|
|
var iterator = self.map.iterator();
|
|
|
|
|
defer iterator.deinit();
|
|
|
|
|
while (iterator.next()) |entry| {
|
2023-04-20 15:43:18 +00:00
|
|
|
entry.value_ptr.deinit(allocator);
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
self.map.deinit() catch unreachable;
|
|
|
|
|
self.* = undefined;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
pub fn resolve(self: *PickleMemo, allocator: std.mem.Allocator, op: py.Any, recursive: bool) !py.Any {
|
2023-01-02 14:28:25 +00:00
|
|
|
var used_op = op;
|
|
|
|
|
while (used_op == .ref) {
|
|
|
|
|
var count: usize = 0;
|
|
|
|
|
const val = self.map.get(op.ref) orelse {
|
|
|
|
|
return error.BadMemoRef;
|
|
|
|
|
};
|
|
|
|
|
if (!recursive) {
|
|
|
|
|
return val.clone(allocator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count += 1;
|
|
|
|
|
if (count >= MAX_DEPTH or val != .ref) {
|
|
|
|
|
used_op = try val.clone(allocator);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
used_op = val;
|
|
|
|
|
}
|
|
|
|
|
if (used_op.containsRef()) {
|
|
|
|
|
switch (used_op) {
|
|
|
|
|
.app, .object, .global => |v| {
|
|
|
|
|
if (v.member.containsRef()) {
|
|
|
|
|
v.member = try self.resolve(allocator, v.member, recursive);
|
|
|
|
|
}
|
|
|
|
|
for (v.args) |*item| {
|
|
|
|
|
if (item.containsRef()) {
|
|
|
|
|
item.* = try self.resolve(allocator, item.*, recursive);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
2023-04-20 15:43:18 +00:00
|
|
|
.set_state => |v| {
|
|
|
|
|
if (v.obj.containsRef()) {
|
|
|
|
|
v.obj = try self.resolve(allocator, v.obj, recursive);
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
2023-04-20 15:43:18 +00:00
|
|
|
if (v.state.containsRef()) {
|
|
|
|
|
v.state = try self.resolve(allocator, v.state, recursive);
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
.pers_id => |v| {
|
|
|
|
|
if (v.ref.containsRef()) {
|
|
|
|
|
v.ref = try self.resolve(allocator, v.ref, recursive);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
.seq => |*v| {
|
2023-01-25 12:16:27 +00:00
|
|
|
for (v.values) |*item| {
|
2023-01-02 14:28:25 +00:00
|
|
|
if (item.containsRef()) {
|
|
|
|
|
item.* = try self.resolve(allocator, item.*, recursive);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
else => {},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return used_op;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
pub fn insert(self: *PickleMemo, mid: u32, val: py.Any) !void {
|
2023-01-02 14:28:25 +00:00
|
|
|
_ = try self.map.fetchPut(mid, val);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
pub fn resolveMut(self: *PickleMemo, op: *py.Any, recursive: bool) !*py.Any {
|
2023-01-02 14:28:25 +00:00
|
|
|
if (op.* != .ref) return op;
|
|
|
|
|
var lastmid = op.ref;
|
|
|
|
|
var count: usize = 0;
|
|
|
|
|
var val = self.map.get(lastmid) orelse {
|
|
|
|
|
return error.BadMemoRef;
|
|
|
|
|
};
|
|
|
|
|
while (val == .ref) {
|
|
|
|
|
lastmid = val.ref;
|
|
|
|
|
if (!recursive) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
count += 1;
|
|
|
|
|
if (count >= MAX_DEPTH) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
val = self.map.get(lastmid) orelse {
|
|
|
|
|
return error.BadMemoRef;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return (self.map.getPtr(lastmid) orelse {
|
|
|
|
|
return error.BadMemoRef;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
const MemoError = py.Any.UnpickleError || error{BadMemoRef};
|
2023-01-02 14:28:25 +00:00
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
pub fn resolveAllRefsIter(self: *PickleMemo, allocator: std.mem.Allocator, depth: usize, vals: []py.Any, fix_values: bool) MemoError![]py.Any {
|
2023-01-02 14:28:25 +00:00
|
|
|
if (depth >= MAX_DEPTH) {
|
|
|
|
|
return vals;
|
|
|
|
|
}
|
2023-04-20 15:43:18 +00:00
|
|
|
const res = try allocator.alloc(py.Any, vals.len);
|
2023-01-02 14:28:25 +00:00
|
|
|
for (vals, 0..) |v, i| {
|
|
|
|
|
res[i] = try self.resolveAllRefs(allocator, depth + 1, v, fix_values);
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
pub fn resolveAllRefs(self: *PickleMemo, allocator: std.mem.Allocator, depth: usize, val: py.Any, fix_values: bool) !py.Any {
|
|
|
|
|
var output: py.Any = switch (val) {
|
2023-01-02 14:28:25 +00:00
|
|
|
.ref => try self.resolve(allocator, val, true),
|
2023-04-20 15:43:18 +00:00
|
|
|
inline .app, .object, .global => |v, tag| @unionInit(py.Any, @tagName(tag), try py.Object.init(
|
2023-01-02 14:28:25 +00:00
|
|
|
allocator,
|
|
|
|
|
try self.resolveAllRefs(allocator, depth + 1, v.member, fix_values),
|
|
|
|
|
try self.resolveAllRefsIter(allocator, depth + 1, v.args, fix_values),
|
2023-04-20 15:43:18 +00:00
|
|
|
try self.resolveAllRefsIter(allocator, depth + 1, v.kwargs, fix_values),
|
2023-01-02 14:28:25 +00:00
|
|
|
)),
|
2023-04-20 15:43:18 +00:00
|
|
|
.set_state => |v| .{ .set_state = try py.SetState.init(
|
2023-01-02 14:28:25 +00:00
|
|
|
allocator,
|
2023-04-20 15:43:18 +00:00
|
|
|
try self.resolveAllRefs(allocator, depth + 1, v.obj, fix_values),
|
|
|
|
|
try self.resolveAllRefs(allocator, depth + 1, v.state, fix_values),
|
2023-01-02 14:28:25 +00:00
|
|
|
) },
|
2023-01-25 12:16:27 +00:00
|
|
|
.seq => |v| .{ .seq = .{ .type = v.type, .values = try self.resolveAllRefsIter(allocator, depth + 1, v.values, fix_values) } },
|
2023-04-20 15:43:18 +00:00
|
|
|
.pers_id => |v| .{ .pers_id = try py.PersId.init(allocator, try self.resolveAllRefs(allocator, depth + 1, v.ref, fix_values)) },
|
2023-01-02 14:28:25 +00:00
|
|
|
else => try val.clone(allocator),
|
|
|
|
|
};
|
|
|
|
|
if (fix_values) {
|
|
|
|
|
output = try output.coerceFromRaw(allocator);
|
|
|
|
|
}
|
|
|
|
|
return output;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
pub fn evaluate(arena: std.mem.Allocator, x: []const pickle.Op, resolve_refs: bool) ![]const py.Any {
|
|
|
|
|
var stack = std.ArrayList(py.Any).init(arena);
|
2023-04-07 16:45:58 +00:00
|
|
|
var memo = PickleMemo.init(arena);
|
2023-01-02 14:28:25 +00:00
|
|
|
|
2023-04-07 16:45:58 +00:00
|
|
|
for (x) |op| {
|
2023-01-02 14:28:25 +00:00
|
|
|
switch (op) {
|
2023-04-07 16:45:58 +00:00
|
|
|
.mark => try stack.append(.{ .raw = op }),
|
|
|
|
|
.frame => {},
|
|
|
|
|
.stop => break,
|
|
|
|
|
.pop => _ = try pop(&stack),
|
2023-04-20 15:43:18 +00:00
|
|
|
.pop_mark => _ = try popMark(&stack),
|
2023-04-07 16:45:58 +00:00
|
|
|
.dup => if (stack.getLastOrNull()) |item|
|
|
|
|
|
try stack.append(try item.clone(arena))
|
|
|
|
|
else
|
|
|
|
|
return error.CannotDupEmptyStack,
|
2023-04-20 15:43:18 +00:00
|
|
|
.persid => |v| try stack.append(.{ .pers_id = try py.PersId.init(arena, .{ .string = try arena.dupe(u8, v) }) }),
|
|
|
|
|
.binpersid => try stack.append(.{ .pers_id = try py.PersId.init(arena, try pop(&stack)) }),
|
2023-04-07 16:45:58 +00:00
|
|
|
.reduce => try stack.append(.{ .global = blk: {
|
2023-04-20 15:43:18 +00:00
|
|
|
var args = try pop(&stack);
|
|
|
|
|
args = try memo.resolve(arena, args, true);
|
|
|
|
|
if (args != .seq) return error.InvalidInput;
|
|
|
|
|
var func = try pop(&stack);
|
|
|
|
|
func = try memo.resolve(arena, func, true);
|
|
|
|
|
break :blk try py.Object.init(arena, func, args.seq.values, &.{});
|
2023-01-02 14:28:25 +00:00
|
|
|
} }),
|
2023-04-07 16:45:58 +00:00
|
|
|
.build => try stack.append(blk: {
|
|
|
|
|
const args = try memo.resolve(arena, try pop(&stack), true);
|
|
|
|
|
const member = try memo.resolve(arena, try pop(&stack), true);
|
2023-04-20 15:43:18 +00:00
|
|
|
break :blk .{ .set_state = try py.SetState.init(arena, member, args) };
|
2023-01-02 14:28:25 +00:00
|
|
|
}),
|
2023-04-20 15:43:18 +00:00
|
|
|
.empty_dict => try stack.append(.{ .seq = .{ .type = .dict, .values = &[_]py.Any{} } }),
|
2023-04-07 16:45:58 +00:00
|
|
|
.get => |v| try stack.append(.{ .ref = v }),
|
2023-04-20 15:43:18 +00:00
|
|
|
.empty_list => try stack.append(.{ .seq = .{ .type = .list, .values = &[_]py.Any{} } }),
|
2023-04-07 16:45:58 +00:00
|
|
|
.put => |v| {
|
|
|
|
|
try memo.insert(v, try pop(&stack));
|
|
|
|
|
try stack.append(.{ .ref = v });
|
2023-01-02 14:28:25 +00:00
|
|
|
},
|
2023-04-07 16:45:58 +00:00
|
|
|
.tuple => try stack.append(blk: {
|
2023-04-20 15:43:18 +00:00
|
|
|
const popped = try popMark(&stack);
|
|
|
|
|
break :blk .{ .seq = .{ .type = .tuple, .values = try arena.dupe(py.Any, popped) } };
|
2023-01-02 14:28:25 +00:00
|
|
|
}),
|
2023-04-20 15:43:18 +00:00
|
|
|
.empty_tuple => try stack.append(.{ .seq = .{ .type = .tuple, .values = &[_]py.Any{} } }),
|
2023-01-02 14:28:25 +00:00
|
|
|
.setitem => {
|
2023-04-20 15:43:18 +00:00
|
|
|
const v = try memo.resolve(arena, try pop(&stack), true);
|
|
|
|
|
const k = try memo.resolve(arena, try pop(&stack), true);
|
2023-04-07 16:45:58 +00:00
|
|
|
const top = try lastMut(&stack);
|
2023-01-02 14:28:25 +00:00
|
|
|
const rtop = try memo.resolveMut(top, true);
|
|
|
|
|
switch (rtop.*) {
|
|
|
|
|
.global => |obj| {
|
2023-04-20 15:43:18 +00:00
|
|
|
try append(arena, &obj.kwargs, &.{ k, v });
|
2023-01-02 14:28:25 +00:00
|
|
|
},
|
2023-04-20 15:43:18 +00:00
|
|
|
.seq => |*dict| {
|
|
|
|
|
if (dict.type != .dict) return error.BadStackTopForSetItem;
|
|
|
|
|
try append(arena, &dict.values, &.{ k, v });
|
2023-01-02 14:28:25 +00:00
|
|
|
},
|
|
|
|
|
else => {
|
|
|
|
|
return error.BadStackTopForSetItem;
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
.setitems => {
|
2023-04-20 15:43:18 +00:00
|
|
|
const popped = try memo.resolveAllRefsIter(arena, 0, try popMark(&stack), true);
|
2023-04-07 16:45:58 +00:00
|
|
|
const top = try lastMut(&stack);
|
2023-01-02 14:28:25 +00:00
|
|
|
const rtop = try memo.resolveMut(top, true);
|
|
|
|
|
switch (rtop.*) {
|
|
|
|
|
.global => |obj| {
|
2023-04-20 15:43:18 +00:00
|
|
|
try append(arena, &obj.kwargs, popped);
|
2023-01-02 14:28:25 +00:00
|
|
|
},
|
2023-04-20 15:43:18 +00:00
|
|
|
.seq => |*dict| {
|
|
|
|
|
if (dict.type != .dict) return error.BadStackTopForSetItems;
|
|
|
|
|
try append(arena, &dict.values, popped);
|
2023-01-02 14:28:25 +00:00
|
|
|
},
|
|
|
|
|
else => {
|
|
|
|
|
return error.BadStackTopForSetItems;
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
.proto => |proto| meta.assert(proto <= MAX_PROTOCOL, "Unsupported protocol {d}", .{proto}),
|
2023-04-07 16:45:58 +00:00
|
|
|
.tuple1 => try stack.append(blk: {
|
2023-04-20 15:43:18 +00:00
|
|
|
const tup_values = try arena.alloc(py.Any, 1);
|
2023-04-07 16:45:58 +00:00
|
|
|
tup_values[0] = try pop(&stack);
|
2023-01-25 12:16:27 +00:00
|
|
|
break :blk .{ .seq = .{ .type = .tuple, .values = tup_values } };
|
2023-01-02 14:28:25 +00:00
|
|
|
}),
|
2023-04-07 16:45:58 +00:00
|
|
|
.tuple2 => try stack.append(blk: {
|
2023-04-20 15:43:18 +00:00
|
|
|
const tup_values = try arena.alloc(py.Any, 2);
|
2023-04-07 16:45:58 +00:00
|
|
|
inline for (0..2) |i| tup_values[(tup_values.len - 1) - i] = try pop(&stack);
|
2023-01-25 12:16:27 +00:00
|
|
|
break :blk .{ .seq = .{ .type = .tuple, .values = tup_values } };
|
2023-01-02 14:28:25 +00:00
|
|
|
}),
|
2023-04-07 16:45:58 +00:00
|
|
|
.tuple3 => try stack.append(blk: {
|
2023-04-20 15:43:18 +00:00
|
|
|
const tup_values = try arena.alloc(py.Any, 3);
|
2023-04-07 16:45:58 +00:00
|
|
|
inline for (0..3) |i| tup_values[(tup_values.len - 1) - i] = try pop(&stack);
|
2023-01-25 12:16:27 +00:00
|
|
|
break :blk .{ .seq = .{ .type = .tuple, .values = tup_values } };
|
2023-01-02 14:28:25 +00:00
|
|
|
}),
|
|
|
|
|
.append => {
|
2023-04-07 16:45:58 +00:00
|
|
|
const v = try pop(&stack);
|
|
|
|
|
const top = try lastMut(&stack);
|
2023-01-02 14:28:25 +00:00
|
|
|
const rtop = try memo.resolveMut(top, true);
|
|
|
|
|
switch (rtop.*) {
|
|
|
|
|
.global => |obj| {
|
2023-04-20 15:43:18 +00:00
|
|
|
// can this happen ?
|
|
|
|
|
try append(arena, &obj.args, &.{v});
|
2023-01-02 14:28:25 +00:00
|
|
|
},
|
2023-04-20 15:43:18 +00:00
|
|
|
.seq => |*seq| {
|
|
|
|
|
if (seq.type != .list) return error.BadStackTopForAppend;
|
|
|
|
|
try append(arena, &seq.values, &.{v});
|
2023-01-02 14:28:25 +00:00
|
|
|
},
|
|
|
|
|
else => {
|
|
|
|
|
return error.BadStackTopForAppend;
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
.appends => {
|
2023-04-20 15:43:18 +00:00
|
|
|
const postmark = try popMark(&stack);
|
2023-04-07 16:45:58 +00:00
|
|
|
const top = try lastMut(&stack);
|
2023-01-02 14:28:25 +00:00
|
|
|
const rtop = try memo.resolveMut(top, true);
|
|
|
|
|
switch (rtop.*) {
|
2023-04-20 15:43:18 +00:00
|
|
|
.global => try append(arena, &rtop.global.args, postmark),
|
|
|
|
|
.seq => |*seq| {
|
|
|
|
|
if (seq.type != .list) return error.BadStackTopForAppend;
|
|
|
|
|
try append(arena, &seq.values, postmark);
|
2023-01-02 14:28:25 +00:00
|
|
|
},
|
|
|
|
|
else => {
|
|
|
|
|
return error.BadStackTopForAppends;
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
2023-04-20 15:43:18 +00:00
|
|
|
.dict => try stack.append(.{ .seq = .{
|
|
|
|
|
.type = .dict,
|
|
|
|
|
.values = try arena.dupe(py.Any, try popMark(&stack)),
|
|
|
|
|
} }),
|
|
|
|
|
.list => try stack.append(.{ .seq = .{
|
|
|
|
|
.type = .list,
|
|
|
|
|
.values = try arena.dupe(py.Any, try popMark(&stack)),
|
|
|
|
|
} }),
|
|
|
|
|
.inst => |v| try stack.append(.{ .object = try py.Object.init(
|
|
|
|
|
arena,
|
|
|
|
|
try py.tuple(&.{ .{ .string = v.module }, .{ .string = v.class } }).clone(arena),
|
|
|
|
|
try arena.dupe(py.Any, try popMark(&stack)),
|
|
|
|
|
&.{},
|
|
|
|
|
) }),
|
2023-04-07 16:45:58 +00:00
|
|
|
.obj => try stack.append(blk: {
|
|
|
|
|
const mark = try findMark(&stack);
|
2023-04-20 15:43:18 +00:00
|
|
|
const args = try arena.dupe(py.Any, stack.items[mark + 2 ..]);
|
2023-04-07 16:45:58 +00:00
|
|
|
const member = stack.items[mark + 1];
|
2023-04-20 15:43:18 +00:00
|
|
|
break :blk .{ .object = try py.Object.init(arena, member, args, &.{}) };
|
2023-01-02 14:28:25 +00:00
|
|
|
}),
|
2023-04-07 16:45:58 +00:00
|
|
|
.newobj => try stack.append(blk: {
|
2023-04-20 15:43:18 +00:00
|
|
|
const args = try arena.alloc(py.Any, 1);
|
2023-04-07 16:45:58 +00:00
|
|
|
args[0] = try pop(&stack);
|
2023-04-20 15:43:18 +00:00
|
|
|
break :blk .{ .object = try py.Object.init(arena, try pop(&stack), args, &.{}) };
|
2023-01-02 14:28:25 +00:00
|
|
|
}),
|
2023-04-20 15:43:18 +00:00
|
|
|
.empty_set => try stack.append(.{ .seq = .{ .type = .set, .values = &[_]py.Any{} } }),
|
2023-01-02 14:28:25 +00:00
|
|
|
.additems => {
|
2023-04-20 15:43:18 +00:00
|
|
|
const postmark = try popMark(&stack);
|
2023-04-07 16:45:58 +00:00
|
|
|
const top = try lastMut(&stack);
|
2023-01-02 14:28:25 +00:00
|
|
|
const rtop = try memo.resolveMut(top, true);
|
|
|
|
|
switch (rtop.*) {
|
2023-04-20 15:43:18 +00:00
|
|
|
.seq => |*seq| {
|
|
|
|
|
if (seq.type != .set) return error.BadStackTopForAppend;
|
|
|
|
|
try append(arena, &seq.values, postmark);
|
2023-01-02 14:28:25 +00:00
|
|
|
},
|
|
|
|
|
else => {
|
2023-04-20 15:43:18 +00:00
|
|
|
return error.BadStackTopForAppends;
|
2023-01-02 14:28:25 +00:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
2023-04-20 15:43:18 +00:00
|
|
|
.frozenset => try stack.append(.{ .seq = .{
|
|
|
|
|
.type = .frozen_set,
|
|
|
|
|
.values = try arena.dupe(py.Any, try popMark(&stack)),
|
|
|
|
|
} }),
|
2023-04-07 16:45:58 +00:00
|
|
|
.newobj_ex => try stack.append(blk: {
|
|
|
|
|
const kwargs, const args, const cls = .{ try pop(&stack), try pop(&stack), try pop(&stack) };
|
2023-04-20 15:43:18 +00:00
|
|
|
break :blk .{ .object = try py.Object.init(arena, cls, args.seq.values, kwargs.seq.values) };
|
2023-01-02 14:28:25 +00:00
|
|
|
}),
|
2023-04-07 16:45:58 +00:00
|
|
|
.stack_global => try stack.append(blk: {
|
2023-01-02 14:28:25 +00:00
|
|
|
const gn, const mn = .{
|
2023-04-07 16:45:58 +00:00
|
|
|
try memo.resolve(arena, try pop(&stack), true),
|
|
|
|
|
try memo.resolve(arena, try pop(&stack), true),
|
2023-01-02 14:28:25 +00:00
|
|
|
};
|
2023-04-20 15:43:18 +00:00
|
|
|
const new_seq: py.Sequence = .{ .type = .tuple, .values = try arena.dupe(py.Any, &.{ gn, mn }) };
|
|
|
|
|
break :blk .{ .object = try py.Object.init(arena, .{ .seq = new_seq }, &.{}, &.{}) };
|
2023-01-02 14:28:25 +00:00
|
|
|
}),
|
|
|
|
|
.memoize => {
|
2023-04-07 16:45:58 +00:00
|
|
|
const item = stack.getLastOrNull() orelse {
|
2023-01-02 14:28:25 +00:00
|
|
|
return error.StackUnderrun;
|
|
|
|
|
};
|
2023-04-07 16:45:58 +00:00
|
|
|
try memo.insert(@intCast(memo.map.count()), try item.clone(arena));
|
2023-01-02 14:28:25 +00:00
|
|
|
},
|
2023-04-07 16:45:58 +00:00
|
|
|
else => try stack.append(.{ .raw = try op.clone(arena) }),
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-04-07 16:45:58 +00:00
|
|
|
if (resolve_refs) {
|
|
|
|
|
return try memo.resolveAllRefsIter(arena, 0, stack.items, true);
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
2023-04-07 16:45:58 +00:00
|
|
|
return stack.toOwnedSlice();
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
fn append(allocator: std.mem.Allocator, current: *[]py.Any, values: []const py.Any) !void {
|
|
|
|
|
var array_list = std.ArrayListUnmanaged(py.Any).fromOwnedSlice(current.*);
|
|
|
|
|
try array_list.appendSlice(allocator, values);
|
|
|
|
|
current.* = array_list.items;
|
2023-01-02 14:28:25 +00:00
|
|
|
}
|
2023-04-07 16:45:58 +00:00
|
|
|
|
|
|
|
|
test evaluate {
|
|
|
|
|
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
|
|
|
|
|
defer arena.deinit();
|
|
|
|
|
const allocator = arena.allocator();
|
2023-04-20 15:43:18 +00:00
|
|
|
const file = try std.fs.cwd().openFile("zml/aio/torch/simple_test_4.pickle", .{ .mode = .read_only });
|
2023-04-07 16:45:58 +00:00
|
|
|
var buffered_reader = std.io.bufferedReader(file.reader());
|
|
|
|
|
const ops = try pickle.parse(allocator, buffered_reader.reader(), 4096);
|
|
|
|
|
|
|
|
|
|
const vals = try evaluate(allocator, ops, true);
|
|
|
|
|
defer allocator.free(vals);
|
|
|
|
|
|
|
|
|
|
try std.testing.expect(vals.len == 1);
|
|
|
|
|
try std.testing.expect(vals[0] == .seq);
|
|
|
|
|
try std.testing.expect(vals[0].seq.type == .dict);
|
2023-04-20 15:43:18 +00:00
|
|
|
const entries = vals[0].seq.values;
|
|
|
|
|
const expected: []const py.Any = &.{
|
|
|
|
|
// Key, followed by its value
|
|
|
|
|
.{ .string = "hello" }, .{ .string = "world" },
|
|
|
|
|
.{ .string = "int" }, .{ .int64 = 1 },
|
|
|
|
|
.{ .string = "float" }, .{ .float64 = 3.141592 },
|
|
|
|
|
.{ .string = "list" },
|
|
|
|
|
.{
|
|
|
|
|
.seq = .{
|
|
|
|
|
.type = .list,
|
|
|
|
|
.values = @constCast(&[_]py.Any{
|
|
|
|
|
.{ .int64 = 255 },
|
|
|
|
|
.{ .int64 = 1234 },
|
|
|
|
|
.{ .int64 = -123 },
|
|
|
|
|
.{ .int64 = 1_000_000_000 },
|
|
|
|
|
.{ .int64 = 999_000_000_000 },
|
|
|
|
|
.{ .bigint = (try std.math.big.int.Managed.initSet(allocator, 999_000_000_000_000_000_000_000_000_000)).toConst() },
|
2023-04-07 16:45:58 +00:00
|
|
|
}),
|
2023-04-20 15:43:18 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
.{ .string = "bool" }, .{ .boolval = false },
|
|
|
|
|
.{ .string = "tuple" },
|
|
|
|
|
.{ .seq = .{
|
|
|
|
|
.type = .tuple,
|
|
|
|
|
.values = @constCast(&[_]py.Any{
|
|
|
|
|
.{ .string = "a" },
|
|
|
|
|
.{ .int64 = 10 },
|
|
|
|
|
}),
|
|
|
|
|
} },
|
2023-04-07 16:45:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
try std.testing.expectEqualDeep(expected, entries);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
pub fn pop(values: *std.ArrayList(py.Any)) !py.Any {
|
2023-04-07 16:45:58 +00:00
|
|
|
if (values.items.len == 0) {
|
|
|
|
|
return error.StackUnderrun;
|
|
|
|
|
}
|
|
|
|
|
return values.pop();
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
fn popMark(values: *std.ArrayList(py.Any)) ![]py.Any {
|
2023-04-07 16:45:58 +00:00
|
|
|
const mark = try findMark(values);
|
|
|
|
|
const popping = values.items[mark + 1 ..];
|
|
|
|
|
values.shrinkRetainingCapacity(mark);
|
2023-04-20 15:43:18 +00:00
|
|
|
return popping;
|
2023-04-07 16:45:58 +00:00
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
fn lastMut(values: *std.ArrayList(py.Any)) !*py.Any {
|
2023-04-07 16:45:58 +00:00
|
|
|
if (values.items.len == 0) {
|
|
|
|
|
return error.UnexpectedEmptyStack;
|
|
|
|
|
}
|
|
|
|
|
return &values.items[values.items.len - 1];
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-20 15:43:18 +00:00
|
|
|
fn findMark(values: *std.ArrayList(py.Any)) !usize {
|
2023-04-07 16:45:58 +00:00
|
|
|
const len = values.items.len;
|
|
|
|
|
for (0..len) |i| {
|
|
|
|
|
const idx = (len - 1) - i;
|
|
|
|
|
const val = values.items[idx];
|
|
|
|
|
if (val == .raw and val.raw == .mark) {
|
|
|
|
|
return idx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return error.MarkNotFound;
|
|
|
|
|
}
|