const std = @import("std");
const py = @cImport(@cInclude("Python.h"));
const signal = @import("./signal.zig");
export fn keepalive() void {
signal.keepalive();
}
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
var allocator = gpa.allocator();
pub const General = error{RuntimeError};
const PyObject = py.PyObject;
var didInit = false;
var globals: *PyObject = undefined;
export fn cowasm_python_init() c_int {
if (didInit) return 0;
py.Py_Initialize();
globals = py.PyDict_New() orelse {
return 1;
};
didInit = true;
return 0;
}
pub fn assertInit() !void {
if (!didInit) {
std.debug.print("call init() first\n", .{});
return General.RuntimeError;
}
}
extern fn wasmSendString(ptr: [*]const u8, len: usize) void;
extern fn wasmSetException() void;
export fn cowasm_python_repr(s: [*:0]const u8) i32 {
const r = repr(s) catch |err| {
wasmSetException();
std.debug.print("python error: '{}'\nwhen evaluating '{s}'", .{ err, s });
return 1;
};
defer allocator.free(r);
const ptr: [*]const u8 = r[0..1];
wasmSendString(ptr, std.mem.len(r));
return 0;
}
fn repr(s: [*:0]const u8) ![]u8 {
try assertInit();
var pstr = py.PyRun_String(s, py.Py_eval_input, globals, globals) orelse {
py.PyErr_Clear();
std.debug.print("eval -- PyRun_String failed\n", .{});
return General.RuntimeError;
};
defer py.Py_DECREF(pstr);
var rep = py.PyObject_Repr(pstr) orelse {
py.PyErr_Clear();
std.debug.print("eval -- PyObject_Repr failed\n", .{});
return General.RuntimeError;
};
defer py.Py_DECREF(rep);
const str_rep = py.PyUnicode_AsUTF8(rep);
return try std.fmt.allocPrint(
allocator,
"{s}",
.{str_rep},
);
}
fn exec(s: [*:0]const u8) !void {
try assertInit();
var pstr = py.PyRun_String(s, py.Py_file_input, globals, globals) orelse {
py.PyErr_Clear();
std.debug.print("failed to run '{s}'\n", .{s});
return General.RuntimeError;
};
py.Py_DECREF(pstr);
}
export fn cowasm_python_exec(s: [*:0]const u8) i32 {
exec(s) catch |err| {
wasmSetException();
std.debug.print("python error: '{}'\nwhen evaluating '{s}'", .{ err, s });
return 1;
};
return 0;
}
export fn cowasm_python_terminal(argc: i32, argv: [*c][*c]u8) i32 {
assertInit() catch |err| {
std.debug.print("terminal: must first init python -- {}", .{err});
return 1;
};
const r = py.Py_BytesMain(argc, argv);
return r;
}