summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2026-08-31 23:05:16 +0200
committerNathan Reiner <nathan@nathanreiner.xyz>2026-08-31 23:05:16 +0200
commit804204db7cf1e8a28defd359d17fa72949e13eff (patch)
tree3536d961838d1a6640d1295d808768736bf2317b /src
parent956cd84ca545f1d93e2218cbbdbb39c81a46bec8 (diff)
Implement with ptrCast to make it more transparent.
Diffstat (limited to 'src')
-rw-r--r--src/Dict.zig66
-rw-r--r--src/Float.zig22
-rw-r--r--src/Int.zig41
-rw-r--r--src/Interpreter.zig10
-rw-r--r--src/List.zig49
-rw-r--r--src/Object.zig40
-rw-r--r--src/Str.zig28
-rw-r--r--src/Tuple.zig37
-rw-r--r--src/Watcher.zig62
-rw-r--r--src/dict.zig143
-rw-r--r--src/error.zig126
-rw-r--r--src/float.zig26
-rw-r--r--src/function.zig1
-rw-r--r--src/int.zig40
-rw-r--r--src/list.zig108
-rw-r--r--src/main.zig21
-rw-r--r--src/object.zig35
-rw-r--r--src/root.zig44
-rw-r--r--src/str.zig26
-rw-r--r--src/tuple.zig46
20 files changed, 648 insertions, 323 deletions
diff --git a/src/Dict.zig b/src/Dict.zig
deleted file mode 100644
index 89964cf..0000000
--- a/src/Dict.zig
+++ /dev/null
@@ -1,66 +0,0 @@
-const std = @import("std");
-const c = @import("c");
-
-const zpy = @import("root.zig");
-
-const Self = @This();
-
-object: zpy.Object,
-
-pub const Key = union(enum) {
- string: [*c]const u8,
- object: zpy.Object,
-};
-
-pub fn new() zpy.Error!Self {
- if (c.PyDict_New()) |object| {
- return .{ .object = .fromPtr(object) };
- }
-
- return error.Exception;
-}
-
-pub fn clear(self: *Self) void {
- c.PyDict_Clear(self.object.ptr);
-}
-
-pub fn contains(self: *const Self, key: Key) bool {
- return switch (key) {
- .string => |str| c.PyDict_ContainsString(self.object.ptr, str),
- .object => |obj| c.PyDict_Contains(self.object.ptr, obj.ptr),
- } == 1;
-}
-
-pub fn copy(self: *const Self) Self {
- return .{ .object = .fromPtr(c.PyDict_Copy(self.object.ptr)) };
-}
-
-pub fn set(self: *Self, key: Key, value: zpy.Object) !void {
- const ret = switch (key) {
- .string => |str| c.PyDict_SetItemString(self.object.ptr, str, value.ptr),
- .object => |obj| c.PyDict_SetItem(self.object.ptr, obj.ptr, value.ptr),
- };
-
- if (ret == -1) return error.Exception;
-}
-
-pub fn get(self: *const Self, key: Key) ?zpy.Object {
- return .fromC(switch (key) {
- .string => |str| c.PyDict_GetItemString(self.object.ptr, str),
- .object => |obj| c.PyDict_GetItem(self.object.ptr, obj.ptr),
- });
-}
-
-pub fn delete(self: *Self, key: Key) !void {
- const ret = switch (key) {
- .string => |str| c.PyDict_DelItemString(self.object.ptr, str),
- .object => |obj| c.PyDict_DelItem(self.object.ptr, obj.ptr),
- };
-
- if (ret == -1) return error.Exception;
-}
-
-pub fn deinit(self: *Self) void {
- self.object.decref();
- self.* = undefined;
-}
diff --git a/src/Float.zig b/src/Float.zig
deleted file mode 100644
index 5877d12..0000000
--- a/src/Float.zig
+++ /dev/null
@@ -1,22 +0,0 @@
-const c = @import("c");
-
-const zpy = @import("root.zig");
-const conversion = zpy.conversion;
-
-const Self = @This();
-
-object: zpy.Object,
-
-pub fn from(value: f64) !Self {
- return .{
- .object = .fromPtr(try conversion.ptr(c.PyFloat_FromDouble(value))),
- };
-}
-
-pub fn asDouble(self: *const Self) f64 {
- return c.PyFloat_asDouble(self.object.ptr);
-}
-
-pub fn deinit(self: *Self) void {
- self.object.decref();
-}
diff --git a/src/Int.zig b/src/Int.zig
deleted file mode 100644
index bd13e99..0000000
--- a/src/Int.zig
+++ /dev/null
@@ -1,41 +0,0 @@
-const std = @import("std");
-const c = @import("c");
-
-const zpy = @import("root.zig");
-const conversion = zpy.conversion;
-
-const Self = @This();
-
-object: zpy.Object,
-
-pub fn from(value: anytype) !Self {
- const T = @TypeOf(value);
- const result = switch (@typeInfo(T)) {
- .int => |i| switch (i.signedness) {
- .signed => c.PyLong_FromLong(value),
- .unsigned => c.PyLong_FromUnsignedLong(value),
- },
- .comptime_int => c.PyLong_FromLong(value),
- .float => c.PyLong_FromDouble(value),
- else => @compileError("value must be numberic."),
- };
-
- return .{
- .object = .fromPtr(try conversion.ptr(result)),
- };
-}
-
-pub fn as(self: *const Self, T: type) T {
- return switch(@typeInfo(T)) {
- .int => |i| switch (i) {
- .signed => c.PyLong_AsLong(self.object.ptr),
- .unsigned => c.PyLong_AsUnsignedLong(self.object.ptr),
- },
- .float => c.PyLong_AsDouble(self.object.ptr),
- else => @compileError("value must be numberic."),
- };
-}
-
-pub fn deinit(self: *Self) void {
- self.object.decref();
-}
diff --git a/src/Interpreter.zig b/src/Interpreter.zig
index 6862706..6768659 100644
--- a/src/Interpreter.zig
+++ b/src/Interpreter.zig
@@ -4,7 +4,7 @@ const zpy = @import("root.zig");
const Self = @This();
-globals: zpy.Dict,
+globals: *zpy.Dict,
pub fn init() !Self {
c.Py_Initialize();
@@ -20,14 +20,14 @@ pub const RunOptions = struct {
locals: ?*zpy.Dict = null,
};
-pub fn run(self: *Self, str: [*c]const u8, options: RunOptions) zpy.Error!zpy.Object {
+pub fn run(self: *Self, str: [*c]const u8, options: RunOptions) !*zpy.Object {
if (c.PyRun_String(
str,
c.Py_file_input,
- self.globals.object.ptr,
- if (options.locals) |loc| loc.object.ptr else null,
+ @ptrCast(self.globals),
+ @ptrCast(options.locals),
)) |object| {
- return .fromPtr(object);
+ return @ptrCast(object);
}
return error.Exception;
diff --git a/src/List.zig b/src/List.zig
deleted file mode 100644
index 6c9f65c..0000000
--- a/src/List.zig
+++ /dev/null
@@ -1,49 +0,0 @@
-const c = @import("c");
-
-const zpy = @import("root.zig");
-const conversion = zpy.conversion;
-
-const Self = @This();
-
-object: zpy.Object,
-
-pub fn new(items: []const zpy.Object) !Self {
- var list: Self = .{
- .object = .fromPtr(try conversion.ptr(c.PyList_New(items.len))),
- };
- errdefer list.deinit();
-
- for (items, 0..) |item, index| {
- try list.insert(index, item);
- }
-}
-
-pub fn size(self: *const Self) usize {
- return @as(usize, c.PyList_Size(self.object.ptr));
-}
-
-pub fn get(self: *const Self, index: usize) !zpy.Object {
- return .fromC(try conversion.ptr(c.PyList_GetItem(self.object.ptr, index)));
-}
-
-pub fn set(self: *Self, index: usize, value: zpy.Object) !void {
- return conversion.success(
- c.PyList_SetItem(self.object.ptr, index, value.ptr),
- );
-}
-
-pub fn insert(self: *Self, index: usize, value: zpy.Object) !void {
- return .conversion.success(
- c.PyList_Insert(self.object.ptr, index, value.ptr)
- );
-}
-
-pub fn append(self: *Self, value: zpy.Object) !void {
- return .conversion.success(
- c.PyList_Append(self.object.ptr, value.ptr),
- );
-}
-
-pub fn deinit(self: *Self) void {
- self.object.decref();
-}
diff --git a/src/Object.zig b/src/Object.zig
deleted file mode 100644
index 018d8b3..0000000
--- a/src/Object.zig
+++ /dev/null
@@ -1,40 +0,0 @@
-const std = @import("std");
-const c = @import("c");
-const zpy = @import("root.zig");
-
-const Self = @This();
-
-ptr: *c.PyObject,
-
-pub fn fromPtr(ptr: *c.PyObject) Self {
- return .{ .ptr = ptr };
-}
-
-
-pub fn fromC(ptr: [*c]c.PyObject) ?Self {
- return if (ptr) |p| .fromPtr(p) else null;
-}
-
-pub fn decref(self: *Self) void {
- c.Py_DecRef(self.ptr);
-}
-
-pub fn repr(self: *const Self) zpy.Str {
- return .{ .object = .fromPtr(c.PyObject_Repr(self.ptr)) };
-}
-
-pub fn call(self: *Self, args: zpy.Tuple, kwargs: ?zpy.Dict) zpy.Error!zpy.Object {
- const kwargs_ptr: ?*c.PyObject = if (kwargs) |kw| kw.object.ptr else null;
- if (c.PyObject_Call(self.ptr, args.object.ptr, kwargs_ptr)) |object| {
- return .fromPtr(object);
- }
-
- return error.Exception;
-}
-
-pub fn format(self: *const Self, writer: *std.Io.Writer) !void {
- var str = self.repr();
- defer str.deinit();
-
- try writer.print("{s}", .{str.asUtf8() catch return error.WriteFailed});
-}
diff --git a/src/Str.zig b/src/Str.zig
deleted file mode 100644
index 8f49c61..0000000
--- a/src/Str.zig
+++ /dev/null
@@ -1,28 +0,0 @@
-
-const c = @import("c");
-const zpy = @import("root.zig");
-const conversion = zpy.conversion;
-
-const Self = @This();
-
-object: zpy.Object,
-
-pub fn fromString(buffer: []const u8) Self {
- return .{
- .object = .fromPtr(c.PyUnicode_FromStringAndSize(@ptrCast(buffer), @intCast(buffer.len)))
- };
-}
-
-pub fn asUtf8(self: *Self) zpy.Error![]const u8 {
- var size: c.Py_ssize_t = undefined;
- const string: [*]const u8 = c.PyUnicode_AsUTF8AndSize(self.object.ptr, &size);
-
- if (size == -1) return error.Exception;
-
- return string[0..@as(usize, @intCast(size))];
-}
-
-pub fn deinit(self: *Self) void {
- self.object.decref();
- self.* = undefined;
-}
diff --git a/src/Tuple.zig b/src/Tuple.zig
deleted file mode 100644
index af1ec80..0000000
--- a/src/Tuple.zig
+++ /dev/null
@@ -1,37 +0,0 @@
-
-const c = @import("c");
-const zpy = @import("root.zig");
-const conversion = zpy.conversion;
-
-const Self = @This();
-
-object: zpy.Object,
-
-pub fn new(length: usize) !Self {
- return .{
- .object = .fromPtr(try conversion.ptr(c.PyTuple_New(@intCast(length)))),
- };
-}
-
-pub fn pack(values: []const zpy.Object) !Self {
- var tuple = try new(values.len);
- errdefer tuple.object.decref();
-
- for (values, 0..) |value, index| {
- try tuple.set(index, value);
- }
-
- return tuple;
-}
-
-pub fn size(self: *const Self) usize {
- return c.PyTuple_GET_SIZE(self.object.ptr);
-}
-
-pub fn get(self: *Self, index: usize) zpy.Error!zpy.Object {
- return .fromPtr(conversion.ptr(c.PyTuple_GetItem(self.object.ptr, @intCast(index))) catch return error.IndexError);
-}
-
-pub fn set(self: *Self, index: usize, value: zpy.Object) zpy.Error!void {
- conversion.success(c.PyTuple_SetItem(self.object.ptr, @intCast(index), value.ptr)) catch return error.IndexError;
-}
diff --git a/src/Watcher.zig b/src/Watcher.zig
new file mode 100644
index 0000000..4a0a7c3
--- /dev/null
+++ b/src/Watcher.zig
@@ -0,0 +1,62 @@
+const std = @import("std");
+const c = @import("c");
+const zpy = @import("root.zig");
+
+const Self = @This();
+
+id: c_int,
+
+pub const Event = enum(u32) {
+ added = c.PyDict_EVENT_ADDED,
+ modified = c.PyDict_EVENT_MODIFIED,
+ deleted = c.PyDict_EVENT_DELETED,
+ cloned = c.PyDict_EVENT_CLONED,
+ cleared = c.PyDict_EVENT_CLEARED,
+ deallocated = c.PyDict_EVENT_DEALLOCATED,
+};
+
+pub const Callback = fn (Event, *zpy.Dict, *zpy.Object, *zpy.Object) error{Exception}!void;
+
+pub fn add(callback: Callback) !Self {
+ const wrapper = struct {
+ pub fn wrapper(
+ event: c_uint,
+ dict: [*c]c.PyObject,
+ key: [*c]c.PyObject,
+ value: [*c]c.PyObject,
+ ) callconv(.c) c_int {
+ return if (std.meta.isError(callback(
+ @enumFromInt(event),
+ @ptrCast(dict),
+ @ptrCast(key),
+ @ptrCast(value),
+ ))) -1 else 0;
+ }
+ }.wrapper;
+
+ const result = c.PyDict_AddWatcher(&wrapper);
+
+ if (result == -1) {
+ return error.Exception;
+ }
+
+ return .{ .id = result };
+}
+
+pub fn clear(self: Self) !void {
+ if (c.PyDict_Clear(self.id) == -1) {
+ return error.Exception;
+ }
+}
+
+pub fn watch(self: Self, dict: *zpy.Dict) !void {
+ if (c.PyDict_Watch(self.id, @ptrCast(dict)) == -1) {
+ return error.Exception;
+ }
+}
+
+pub fn unwatch(self: Self, dict: *zpy.Dict) !void {
+ if (c.PyDict_Unwatch(self.id, @ptrCast(dict)) == -1) {
+ return error.Exception;
+ }
+}
diff --git a/src/dict.zig b/src/dict.zig
new file mode 100644
index 0000000..a38d18d
--- /dev/null
+++ b/src/dict.zig
@@ -0,0 +1,143 @@
+const std = @import("std");
+const c = @import("c");
+
+const zpy = @import("root.zig");
+
+pub const Dict = extern struct {
+ const Self = @This();
+
+ data: c.PyObject,
+
+ pub const Key = union(enum) {
+ string: [*c]const u8,
+ object: *zpy.Object,
+ };
+
+ pub fn new() !*Self {
+ return @ptrCast(c.PyDict_New() orelse return error.Exception);
+ }
+
+ pub fn clear(self: *Self) void {
+ c.PyDict_Clear(self.object.ptr);
+ }
+
+ pub fn contains(self: *const Self, key: Key) bool {
+ return switch (key) {
+ .string => |str| c.PyDict_ContainsString(@ptrCast(self), str),
+ .object => |obj| c.PyDict_Contains(@ptrCast(self), @ptrCast(obj)),
+ } == 1;
+ }
+
+ pub fn copy(self: *const Self) *Self {
+ return @ptrCast(c.PyDict_Copy(@ptrCast(self)));
+ }
+
+ pub fn set(self: *Self, key: Key, value: zpy.Object) !void {
+ const ret = switch (key) {
+ .string => |str| c.PyDict_SetItemString(self.object.ptr, str, value.ptr),
+ .object => |obj| c.PyDict_SetItem(self.object.ptr, obj.ptr, value.ptr),
+ };
+
+ if (ret == -1) return error.Exception;
+ }
+
+ pub fn get(self: *const Self, key: Key) ?*zpy.Object {
+ return @ptrCast(switch (key) {
+ .string => |str| c.PyDict_GetItemString(@ptrCast(@constCast(self)), str),
+ .object => |obj| c.PyDict_GetItem(@ptrCast(@constCast(self)), @ptrCast(obj)),
+ });
+ }
+
+ pub fn delete(self: *Self, key: Key) !void {
+ const ret = switch (key) {
+ .string => |str| c.PyDict_DelItemString(@ptrCast(self), str),
+ .object => |obj| c.PyDict_DelItem(@ptrCast(self), @ptrCast(obj)),
+ };
+
+ if (ret == -1) return error.Exception;
+ }
+
+ pub fn setDefault(self: *Self, key: *zpy.Object, default: *zpy.Object) *zpy.Object {
+ return @ptrCast(c.PyDict_SetDefault(
+ @ptrCast(self),
+ @ptrCast(key),
+ @ptrCast(default),
+ ));
+ }
+
+ pub fn pop(self: *Self, key: Key) ?zpy.Object {
+ var result: ?*c.PyObject = undefined;
+
+ switch (key) {
+ .string => |str| c.PyDict_PopString(@ptrCast(self), str, &result),
+ .object => |obj| c.PyDict_Pop(@ptrCast(self), @ptrCast(obj), &result),
+ }
+
+ return result;
+ }
+
+ pub fn items(self: *const Self) zpy.List {
+ return @ptrCast(c.PyDict_Items(@ptrCast(@constCast(self))));
+ }
+
+ pub fn keys(self: *const Self) zpy.List {
+ return @ptrCast(c.PyDict_Keys(@ptrCast(@constCast(self))));
+ }
+
+ pub fn values(self: *const Self) zpy.List {
+ return @ptrCast(c.PyDict_Values(@ptrCast(@constCast(self))));
+ }
+
+ pub fn size(self: *const Self) usize {
+ return @intCast(c.PyDict_Size(@ptrCast(@constCast(self))));
+ }
+
+ pub const Iterator = struct {
+ dict: *Dict,
+ position: c.Py_ssize_t = 0,
+
+ pub const Pair = struct {
+ key: *zpy.Object,
+ value: *zpy.Object,
+ };
+
+ pub fn next(self: *@This()) ?Pair {
+ var pair: Pair = undefined;
+
+ if (c.PyDict_Next(
+ @ptrCast(self.dict),
+ &self.position,
+ @ptrCast(&pair.key),
+ @ptrCast(&pair.value),
+ ) == 1) {
+ return pair;
+ }
+
+ return null;
+ }
+ };
+
+ pub fn iterator(self: *Self) Iterator {
+ return .{ .dict = self };
+ }
+
+ pub fn merge(self: *Self, other: *Self) !void {
+ if (c.PyDict_Merge(
+ @ptrCast(self),
+ @ptrCast(other),
+ 0,
+ ) == -1) {
+ return error.Exception;
+ }
+ }
+
+ pub fn update(self: *Self, other: *Self) !void {
+ if (c.PyDict_Merge(
+ @ptrCast(self),
+ @ptrCast(other),
+ 1,
+ ) == -1) {
+ return error.Exception;
+ }
+ }
+};
diff --git a/src/error.zig b/src/error.zig
new file mode 100644
index 0000000..21002f2
--- /dev/null
+++ b/src/error.zig
@@ -0,0 +1,126 @@
+const std = @import("std");
+const c = @import("c");
+
+pub const Exception = enum {
+
+ const Self = @This();
+
+ base_exception,
+ base_exception_group,
+ exception,
+ arithmetic_error,
+ assertion_error,
+ attribute_error,
+ blocking_io_error,
+ broken_pipe_error,
+ buffer_error,
+ child_process_error,
+ connection_aborted_error,
+ connection_error,
+ connection_refused_error,
+ connection_reset_error,
+ eof_error,
+ file_exists_error,
+ file_not_found_error,
+ floating_point_error,
+ generator_exit,
+ import_error,
+ indentation_error,
+ index_error,
+ interrupted_error,
+ is_a_directory_error,
+ key_error,
+ keyboard_interrupt,
+ lookup_error,
+ memory_error,
+ module_not_found_error,
+ name_error,
+ not_a_directory_error,
+ not_implemented_error,
+ os_error,
+ overflow_error,
+ permission_error,
+ process_lookup_error,
+ python_finalization_error,
+ recursion_error,
+ reference_error,
+ runtime_error,
+ stop_async_iteration,
+ stop_iteration,
+ syntax_error,
+ system_error,
+ system_exit,
+ tab_error,
+ timeout_error,
+ type_error,
+ unbound_local_error,
+ unicode_decode_error,
+ unicode_encode_error,
+ unicode_error,
+ unicode_translate_error,
+ value_error,
+ zero_division_error,
+ unknown_error,
+
+ pub fn concreteException() ?Self {
+ const err = c.PyErr_Occurred() orelse return null;
+
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_BaseException) == 1) return .base_exception;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_BaseExceptionGroup) == 1) return .base_exception_group;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_Exception) == 1) return .exception;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ArithmeticError) == 1) return .arithmetic_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_AssertionError) == 1) return .assertion_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_AttributeError) == 1) return .attribute_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_BlockingIOError) == 1) return .blocking_io_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_BrokenPipeError) == 1) return .broken_pipe_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_BufferError) == 1) return .buffer_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ChildProcessError) == 1) return .child_process_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ConnectionAbortedError) == 1) return .connection_aborted_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ConnectionError) == 1) return .connection_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ConnectionRefusedError) == 1) return .connection_refused_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ConnectionResetError) == 1) return .connection_reset_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_EOFError) == 1) return .e_o_f_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_FileExistsError) == 1) return .file_exists_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_FileNotFoundError) == 1) return .file_not_found_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_FloatingPointError) == 1) return .floating_point_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_GeneratorExit) == 1) return .generator_exit;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ImportError) == 1) return .import_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_IndentationError) == 1) return .indentation_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_IndexError) == 1) return .index_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_InterruptedError) == 1) return .interrupted_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_IsADirectoryError) == 1) return .is_a_directory_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_KeyError) == 1) return .key_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_KeyboardInterrupt) == 1) return .keyboard_interrupt;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_LookupError) == 1) return .lookup_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_MemoryError) == 1) return .memory_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ModuleNotFoundError) == 1) return .module_not_found_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_NameError) == 1) return .name_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_NotADirectoryError) == 1) return .not_a_directory_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_NotImplementedError) == 1) return .not_implemented_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_OSError) == 1) return .o_s_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_OverflowError) == 1) return .overflow_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_PermissionError) == 1) return .permission_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ProcessLookupError) == 1) return .process_lookup_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_PythonFinalizationError) == 1) return .python_finalization_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_RecursionError) == 1) return .recursion_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ReferenceError) == 1) return .reference_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_RuntimeError) == 1) return .runtime_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_StopAsyncIteration) == 1) return .stop_async_iteration;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_StopIteration) == 1) return .stop_iteration;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_SyntaxError) == 1) return .syntax_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_SystemError) == 1) return .system_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_SystemExit) == 1) return .system_exit;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_TabError) == 1) return .tab_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_TimeoutError) == 1) return .timeout_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_TypeError) == 1) return .type_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_UnboundLocalError) == 1) return .unbound_local_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_UnicodeDecodeError) == 1) return .unicode_decode_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_UnicodeEncodeError) == 1) return .unicode_encode_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_UnicodeError) == 1) return .unicode_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_UnicodeTranslateError) == 1) return .unicode_translate_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ValueError) == 1) return .value_error;
+ if (c.PyErr_GivenExceptionMatches(err, c.PyErr_ZeroDivisionError) == 1) return .zero_division_error;
+
+ return .unknown_error;
+ }
+};
diff --git a/src/float.zig b/src/float.zig
new file mode 100644
index 0000000..ffe9903
--- /dev/null
+++ b/src/float.zig
@@ -0,0 +1,26 @@
+const c = @import("c");
+
+const zpy = @import("root.zig");
+
+
+pub const Float = extern struct {
+ const Self = @This();
+
+ object: c.PyObject,
+
+ pub fn from(value: f64) !*Self {
+ return @ptrCast(c.PyFloat_FromDouble(value) orelse return error.Exception);
+ }
+
+ pub fn asDouble(self: *const Self) f64 {
+ return c.PyFloat_asDouble(self.object.ptr);
+ }
+
+ pub fn deinit(self: *Self) void {
+ self.object.decref();
+ }
+
+ pub fn asObject(self: *Self) *zpy.Object {
+ return @ptrCast(self);
+ }
+};
diff --git a/src/function.zig b/src/function.zig
deleted file mode 100644
index 8b13789..0000000
--- a/src/function.zig
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/int.zig b/src/int.zig
new file mode 100644
index 0000000..d5e7589
--- /dev/null
+++ b/src/int.zig
@@ -0,0 +1,40 @@
+const std = @import("std");
+const c = @import("c");
+
+const zpy = @import("root.zig");
+
+pub const Int = extern struct {
+ const Self = @This();
+
+ data: c.PyObject,
+
+ pub fn from(value: anytype) !*Self {
+ const T = @TypeOf(value);
+ const result = switch (@typeInfo(T)) {
+ .int => |i| switch (i.signedness) {
+ .signed => c.PyLong_FromLong(value),
+ .unsigned => c.PyLong_FromUnsignedLong(value),
+ },
+ .comptime_int => c.PyLong_FromLong(value),
+ .float => c.PyLong_FromDouble(value),
+ else => @compileError("value must be numberic."),
+ };
+
+ return @ptrCast(result orelse return error.Exception);
+ }
+
+ pub fn as(self: *const Self, T: type) T {
+ return switch(@typeInfo(T)) {
+ .int => |i| switch (i) {
+ .signed => c.PyLong_AsLong(self.object.ptr),
+ .unsigned => c.PyLong_AsUnsignedLong(self.object.ptr),
+ },
+ .float => c.PyLong_AsDouble(self.object.ptr),
+ else => @compileError("value must be numberic."),
+ };
+ }
+
+ pub fn asObject(self: *Self) *zpy.Object {
+ return @ptrCast(self);
+ }
+};
diff --git a/src/list.zig b/src/list.zig
new file mode 100644
index 0000000..2d72990
--- /dev/null
+++ b/src/list.zig
@@ -0,0 +1,108 @@
+const std = @import("std");
+const c = @import("c");
+
+const zpy = @import("root.zig");
+
+pub const List = extern struct {
+ const Self = @This();
+
+ data: c.PyObject,
+
+ pub fn new(items: []const *zpy.Object) !*Self {
+ var list: *Self = @ptrCast(c.PyList_New(@intCast(items.len)) orelse return error.Exception);
+ errdefer list.asObject().decref();
+
+ for (items, 0..) |item, index| {
+ list.setUnchecked(index, item);
+ }
+
+ return list;
+ }
+
+ pub fn size(self: *const Self) usize {
+ return @as(usize, c.PyList_Size(@ptrCast(@constCast(self))));
+ }
+
+ pub fn get(self: *const Self, index: usize) !*zpy.Object {
+ return @ptrCast(c.PyList_GetItem(@ptrCast(self), @intCast(index)) orelse return error.Exception);
+ }
+
+ pub fn getUnchecked(self: *const Self, index: usize) !*zpy.Object {
+ return @ptrCast(c.PyList_GET_ITEM(@ptrCast(self), @intCast(index)) orelse return error.Exception);
+ }
+
+ pub fn set(self: *Self, index: usize, value: *zpy.Object) !void {
+ if (c.PyList_SetItem(@ptrCast(self), @intCast(index), @ptrCast(value)) == -1) {
+ return error.Exception;
+ }
+ }
+
+ /// Sets item without any error checking or releasing the resource when replacing.
+ pub fn setUnchecked(self: *Self, index: usize, value: *zpy.Object) void {
+ c.PyList_SET_ITEM(@ptrCast(self), @intCast(index), @ptrCast(value));
+ }
+
+ pub fn insert(self: *Self, index: usize, value: *zpy.Object) !void {
+ if (c.PyList_Insert(@ptrCast(self), @intCast(index), @ptrCast(value)) == -1) {
+ return error.Exception;
+ }
+ }
+
+ pub fn append(self: *Self, value: *zpy.Object) !void {
+ if (c.PyList_Append(@ptrCast(self), @ptrCast(value)) == -1) {
+ return error.Exception;
+ }
+ }
+
+ pub fn getSlice(self: *const Self, from: usize, to: usize) !*Self {
+ return @ptrCast(c.PyList_GetSlice(
+ @ptrCast(@constCast(self)),
+ @intCast(from),
+ @intCast(to),
+ ) orelse return error.Exception);
+ }
+
+ pub fn setSlice(self: *Self, from: usize, to: usize, itemlist: *zpy.Object) !void {
+ if (c.PyList_SetSlice(
+ @ptrCast(self),
+ @intCast(from),
+ @intCast(to),
+ @ptrCast(itemlist),
+ ) == -1) {
+ return error.Exception;
+ }
+ }
+
+ pub fn extend(self: *Self, iterable: *zpy.Object) !void {
+ if (c.PyList_Extend(
+ @ptrCast(self),
+ @ptrCast(iterable),
+ ) == -1) {
+ return error.Exception;
+ }
+ }
+
+ pub fn clear(self: *Self) void {
+ c.PyList_Clear(@ptrCast(self));
+ }
+
+ pub fn sort(self: *Self) !void {
+ if (c.PyList_Sort(@ptrCast(self)) == -1) {
+ return error.Exception;
+ }
+ }
+
+ pub fn reverse(self: *Self) !void {
+ if (c.PyList_Sort(@ptrCast(self)) == -1) {
+ return error.Exception;
+ }
+ }
+
+ pub fn asTuple(self: *Self) *zpy.Tuple {
+ return @ptrCast(c.PyList_AsTuple(@ptrCast(self)));
+ }
+
+ pub fn asObject(self: *Self) *zpy.Object {
+ return @ptrCast(self);
+ }
+};
diff --git a/src/main.zig b/src/main.zig
index cfd7704..fa6fe82 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -7,15 +7,28 @@ pub fn main() !void {
var py: zpy.Interpreter = try .init();
defer py.deinit();
- _ = try py.run("def hello(a, b): return a + b", .{ });
+ _ = try py.run("def hello(a, b): return a + b", .{});
var test_fn = py.globals.get(.{ .string = "hello" }) orelse unreachable;
defer test_fn.decref();
var result = try test_fn.call(try .pack(&.{
- (try zpy.Int.from(42)).object,
- (try zpy.Int.from(20)).object,
+ (try zpy.List.new(&.{
+ (try zpy.Int.from(5)).asObject(),
+ (try zpy.Int.from(6)).asObject(),
+ })).asObject(),
+ (try zpy.List.new(&.{
+ (try zpy.Int.from(2)).asObject(),
+ (try zpy.Int.from(3)).asObject(),
+ (try zpy.Int.from(9)).asObject(),
+ })).asObject(),
}), null);
defer result.decref();
- std.debug.print("hello() = {f}\n", .{result});
+ std.debug.print("hello = {f}\n", .{result});
+
+ var global_iterator = py.globals.iterator();
+
+ while (global_iterator.next()) |pair| {
+ std.debug.print("{f}\n", .{pair.key});
+ }
}
diff --git a/src/object.zig b/src/object.zig
new file mode 100644
index 0000000..70392c0
--- /dev/null
+++ b/src/object.zig
@@ -0,0 +1,35 @@
+const std = @import("std");
+const c = @import("c");
+const zpy = @import("root.zig");
+
+pub const Object = extern struct {
+ const Self = @This();
+
+ data: c.PyObject,
+
+ pub fn decref(self: *Self) void {
+ c.Py_DecRef(@ptrCast(self));
+ }
+
+ pub fn repr(self: *const Self) *zpy.Str {
+ return @ptrCast(c.PyObject_Repr(@ptrCast(@constCast(self))));
+ }
+
+ pub fn call(self: *Self, args: *zpy.Tuple, kwargs: ?*zpy.Dict) !*zpy.Object {
+ if (c.PyObject_Call(
+ @ptrCast(self),
+ @ptrCast(args),
+ @ptrCast(kwargs),
+ )) |object| {
+ return @ptrCast(object);
+ }
+ return error.Exception;
+ }
+
+ pub fn format(self: *const Self, writer: *std.Io.Writer) !void {
+ var str = self.repr();
+ defer str.asObject().decref();
+
+ try writer.print("{s}", .{str.asUtf8() catch return error.WriteFailed});
+ }
+};
diff --git a/src/root.zig b/src/root.zig
index ff7e017..c45470f 100644
--- a/src/root.zig
+++ b/src/root.zig
@@ -1,35 +1,19 @@
const std = @import("std");
-pub const Object = @import("Object.zig");
-pub const Interpreter = @import("Interpreter.zig");
-pub const Dict = @import("Dict.zig");
-pub const Str = @import("Str.zig");
-pub const Tuple = @import("Tuple.zig");
-pub const Fn = @import("function.zig").Fn;
-pub const Int = @import("Int.zig");
-pub const Float = @import("Float.zig");
-pub const List = @import("List.zig");
-
-pub const Error = error {
- Exception,
- IndexError,
-};
+const err = @import("error.zig");
+pub const Exception = err.Exception;
-pub const conversion = struct {
- fn PtrFromCPtr(T: type) type {
- const info = @typeInfo(T);
- return *info.pointer.child;
- }
+pub const Object = @import("object.zig").Object;
+pub const Dict = @import("dict.zig").Dict;
+pub const Watcher = @import("Watcher.zig");
+pub const Str = @import("str.zig").Str;
+pub const Tuple = @import("tuple.zig").Tuple;
+pub const Int = @import("int.zig").Int;
+pub const Float = @import("float.zig").Float;
+pub const List = @import("list.zig").List;
- pub fn ptr(value: anytype) Error!PtrFromCPtr(@TypeOf(value)) {
- if (value) |p| {
- return p;
- }
-
- return error.Exception;
- }
+pub const Interpreter = @import("Interpreter.zig");
- pub fn success(value: c_int) Error!void {
- if (value == -1) return error.Exception;
- }
-};
+test {
+ _ = std.testing.refAllDecls(@This());
+}
diff --git a/src/str.zig b/src/str.zig
new file mode 100644
index 0000000..7dde4f9
--- /dev/null
+++ b/src/str.zig
@@ -0,0 +1,26 @@
+
+const c = @import("c");
+const zpy = @import("root.zig");
+
+pub const Str = extern struct {
+ const Self = @This();
+
+ data: c.PyObject,
+
+ pub fn fromString(buffer: []const u8) *Self {
+ return @ptrCast(c.PyUnicode_FromStringAndSize(@ptrCast(buffer), @intCast(buffer.len)));
+ }
+
+ pub fn asUtf8(self: *Self) ![]const u8 {
+ var size: c.Py_ssize_t = undefined;
+ const string: [*]const u8 = c.PyUnicode_AsUTF8AndSize(@ptrCast(self), &size);
+
+ if (size == -1) return error.Exception;
+
+ return string[0..@as(usize, @intCast(size))];
+ }
+
+ pub fn asObject(self: *Self) *zpy.Object {
+ return @ptrCast(self);
+ }
+};
diff --git a/src/tuple.zig b/src/tuple.zig
new file mode 100644
index 0000000..ba82003
--- /dev/null
+++ b/src/tuple.zig
@@ -0,0 +1,46 @@
+const c = @import("c");
+const zpy = @import("root.zig");
+
+pub const Tuple = extern struct {
+ const Self = @This();
+
+ data: c.PyObject,
+
+ pub fn new(length: usize) !*Self {
+ return @ptrCast(c.PyTuple_New(@intCast(length)) orelse return error.Exception);
+ }
+
+ pub fn pack(values: []const *zpy.Object) !*Self {
+ var tuple = try new(values.len);
+ errdefer tuple.asObject().decref();
+
+ for (values, 0..) |value, index| {
+ try tuple.set(index, value);
+ }
+
+ return tuple;
+ }
+
+ pub fn size(self: *const Self) usize {
+ return c.PyTuple_GET_SIZE(self.object.ptr);
+ }
+
+ pub fn get(self: *Self, index: usize) !*zpy.Object {
+ return @ptrCast(
+ c.PyTuple_GetItem(
+ self.object.ptr,
+ @intCast(index),
+ ) orelse return error.Exception,
+ );
+ }
+
+ pub fn set(self: *Self, index: usize, value: *zpy.Object) !void {
+ if (c.PyTuple_SetItem(@ptrCast(self), @intCast(index), @ptrCast(value)) == -1) {
+ return error.Exception;
+ }
+ }
+
+ pub fn asObject(self: *Self) *zpy.Object {
+ return @ptrCast(self);
+ }
+};