diff options
| -rw-r--r-- | src/Dict.zig | 66 | ||||
| -rw-r--r-- | src/Float.zig | 22 | ||||
| -rw-r--r-- | src/Int.zig | 41 | ||||
| -rw-r--r-- | src/Interpreter.zig | 10 | ||||
| -rw-r--r-- | src/List.zig | 49 | ||||
| -rw-r--r-- | src/Object.zig | 40 | ||||
| -rw-r--r-- | src/Str.zig | 28 | ||||
| -rw-r--r-- | src/Tuple.zig | 37 | ||||
| -rw-r--r-- | src/Watcher.zig | 62 | ||||
| -rw-r--r-- | src/dict.zig | 143 | ||||
| -rw-r--r-- | src/error.zig | 126 | ||||
| -rw-r--r-- | src/float.zig | 26 | ||||
| -rw-r--r-- | src/function.zig | 1 | ||||
| -rw-r--r-- | src/int.zig | 40 | ||||
| -rw-r--r-- | src/list.zig | 108 | ||||
| -rw-r--r-- | src/main.zig | 21 | ||||
| -rw-r--r-- | src/object.zig | 35 | ||||
| -rw-r--r-- | src/root.zig | 44 | ||||
| -rw-r--r-- | src/str.zig | 26 | ||||
| -rw-r--r-- | src/tuple.zig | 46 |
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); + } +}; |