mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
Compare commits
2 Commits
b02e76b690
...
f12a379760
Author | SHA1 | Date | |
---|---|---|---|
|
f12a379760 | ||
|
d3d61dde0c |
@ -123,14 +123,15 @@ PK_API void py_resetallvm();
|
||||
PK_API void* py_getvmctx();
|
||||
/// Set the current VM context. This is used for user-defined data.
|
||||
PK_API void py_setvmctx(void* ctx);
|
||||
/// Setup the callbacks for the current VM.
|
||||
PK_API py_Callbacks* py_callbacks();
|
||||
|
||||
/// Set `sys.argv`. Used for storing command-line arguments.
|
||||
PK_API void py_sys_setargv(int argc, char** argv);
|
||||
/// Set the trace function for the current VM.
|
||||
PK_API void py_sys_settrace(py_TraceFunc func, bool reset);
|
||||
/// Invoke the garbage collector.
|
||||
PK_API int py_gc_collect();
|
||||
/// Setup the callbacks for the current VM.
|
||||
PK_API py_Callbacks* py_callbacks();
|
||||
|
||||
/// Wrapper for `PK_MALLOC(size)`.
|
||||
PK_API void* py_malloc(size_t size);
|
||||
@ -139,18 +140,16 @@ PK_API void* py_realloc(void* ptr, size_t size);
|
||||
/// Wrapper for `PK_FREE(ptr)`.
|
||||
PK_API void py_free(void* ptr);
|
||||
|
||||
/// Begin the watchdog with `timeout` in milliseconds.
|
||||
/// `PK_ENABLE_WATCHDOG` must be defined to `1` to use this feature.
|
||||
/// You need to call `py_watchdog_end()` later.
|
||||
/// If `timeout` is reached, `TimeoutError` will be raised.
|
||||
PK_API void py_watchdog_begin(py_i64 timeout);
|
||||
/// Reset the watchdog.
|
||||
PK_API void py_watchdog_end();
|
||||
/// A shorthand for `True`.
|
||||
PK_API py_GlobalRef py_True();
|
||||
/// A shorthand for `False`.
|
||||
PK_API py_GlobalRef py_False();
|
||||
/// A shorthand for `None`.
|
||||
PK_API py_GlobalRef py_None();
|
||||
/// A shorthand for `nil`. `nil` is not a valid python object.
|
||||
PK_API py_GlobalRef py_NIL();
|
||||
|
||||
/// Bind a compile-time function via "decl-based" style.
|
||||
PK_API void py_macrobind(const char* sig, py_CFunction f);
|
||||
/// Get a compile-time function by name.
|
||||
PK_API py_ItemRef py_macroget(py_Name name);
|
||||
/************* Frame Ops *************/
|
||||
|
||||
/// Get the current source location of the frame.
|
||||
PK_API const char* py_Frame_sourceloc(py_Frame* frame, int* lineno);
|
||||
@ -162,6 +161,14 @@ PK_API void py_Frame_newlocals(py_Frame* frame, py_OutRef out);
|
||||
/// Returns `NULL` if not available.
|
||||
PK_API py_StackRef py_Frame_function(py_Frame* frame);
|
||||
|
||||
/************* Code Execution *************/
|
||||
|
||||
/// Compile a source string into a code object.
|
||||
/// Use python's `exec()` or `eval()` to execute it.
|
||||
PK_API bool py_compile(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
bool is_dynamic) PY_RAISE PY_RETURN;
|
||||
/// Run a source string.
|
||||
/// @param source source string.
|
||||
/// @param filename filename (for error messages).
|
||||
@ -172,10 +179,8 @@ PK_API bool py_exec(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
py_Ref module) PY_RAISE PY_RETURN;
|
||||
|
||||
/// Evaluate a source string. Equivalent to `py_exec(source, "<string>", EVAL_MODE, module)`.
|
||||
PK_API bool py_eval(const char* source, py_Ref module) PY_RAISE PY_RETURN;
|
||||
|
||||
/// Run a source string with smart interpretation.
|
||||
/// Example:
|
||||
/// `py_newstr(py_r0(), "abc");`
|
||||
@ -191,28 +196,7 @@ PK_API bool py_smartexec(const char* source, py_Ref module, ...) PY_RAISE PY_RET
|
||||
/// `// res will be 3`.
|
||||
PK_API bool py_smarteval(const char* source, py_Ref module, ...) PY_RAISE PY_RETURN;
|
||||
|
||||
/// Compile a source string into a code object.
|
||||
/// Use python's `exec()` or `eval()` to execute it.
|
||||
PK_API bool py_compile(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
bool is_dynamic) PY_RAISE PY_RETURN;
|
||||
|
||||
/// Python equivalent to `globals()`.
|
||||
PK_API void py_newglobals(py_OutRef);
|
||||
/// Python equivalent to `locals()`.
|
||||
PK_API void py_newlocals(py_OutRef);
|
||||
|
||||
/************* Values Creation *************/
|
||||
|
||||
/// A shorthand for `True`.
|
||||
PK_API py_GlobalRef py_True();
|
||||
/// A shorthand for `False`.
|
||||
PK_API py_GlobalRef py_False();
|
||||
/// A shorthand for `None`.
|
||||
PK_API py_GlobalRef py_None();
|
||||
/// A shorthand for `nil`. `nil` is not a valid python object.
|
||||
PK_API py_GlobalRef py_NIL();
|
||||
/************* Value Creation *************/
|
||||
|
||||
/// Create an `int` object.
|
||||
PK_API void py_newint(py_OutRef, py_i64);
|
||||
@ -241,19 +225,6 @@ PK_API void py_newellipsis(py_OutRef);
|
||||
/// Create a `nil` object. `nil` is an invalid representation of an object.
|
||||
/// Don't use it unless you know what you are doing.
|
||||
PK_API void py_newnil(py_OutRef);
|
||||
/// Create a `tuple` with `n` UNINITIALIZED elements.
|
||||
/// You should initialize all elements before using it.
|
||||
PK_API py_ObjectRef py_newtuple(py_OutRef, int n);
|
||||
/// Create an empty `list`.
|
||||
PK_API void py_newlist(py_OutRef);
|
||||
/// Create a `list` with `n` UNINITIALIZED elements.
|
||||
/// You should initialize all elements before using it.
|
||||
PK_API void py_newlistn(py_OutRef, int n);
|
||||
/// Create an empty `dict`.
|
||||
PK_API void py_newdict(py_OutRef);
|
||||
/// Create an UNINITIALIZED `slice` object.
|
||||
/// You should use `py_setslot()` to set `start`, `stop`, and `step`.
|
||||
PK_API void py_newslice(py_OutRef);
|
||||
/// Create a `nativefunc` object.
|
||||
PK_API void py_newnativefunc(py_OutRef, py_CFunction);
|
||||
/// Create a `function` object.
|
||||
@ -264,8 +235,15 @@ PK_API py_Name py_newfunction(py_OutRef out,
|
||||
int slots);
|
||||
/// Create a `boundmethod` object.
|
||||
PK_API void py_newboundmethod(py_OutRef out, py_Ref self, py_Ref func);
|
||||
/// Create a new object.
|
||||
/// @param out output reference.
|
||||
/// @param type type of the object.
|
||||
/// @param slots number of slots. Use `-1` to create a `__dict__`.
|
||||
/// @param udsize size of your userdata.
|
||||
/// @return pointer to the userdata.
|
||||
PK_API void* py_newobject(py_OutRef out, py_Type type, int slots, int udsize);
|
||||
|
||||
/************* Name Conversions *************/
|
||||
/************* Name Conversion *************/
|
||||
|
||||
/// Convert a null-terminated string to a name.
|
||||
PK_API py_Name py_name(const char*);
|
||||
@ -278,184 +256,6 @@ PK_API py_Name py_namev(c11_sv);
|
||||
/// Convert a name to a `c11_sv`.
|
||||
PK_API c11_sv py_name2sv(py_Name);
|
||||
|
||||
/************* Meta Operations *************/
|
||||
|
||||
/// Create a new type.
|
||||
/// @param name name of the type.
|
||||
/// @param base base type.
|
||||
/// @param module module where the type is defined. Use `NULL` for built-in types.
|
||||
/// @param dtor destructor function. Use `NULL` if not needed.
|
||||
PK_API py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, py_Dtor dtor);
|
||||
|
||||
/// Create a new object.
|
||||
/// @param out output reference.
|
||||
/// @param type type of the object.
|
||||
/// @param slots number of slots. Use `-1` to create a `__dict__`.
|
||||
/// @param udsize size of your userdata.
|
||||
/// @return pointer to the userdata.
|
||||
PK_API void* py_newobject(py_OutRef out, py_Type type, int slots, int udsize);
|
||||
|
||||
/************* Type Cast *************/
|
||||
|
||||
/// Convert an `int` object in python to `int64_t`.
|
||||
PK_API py_i64 py_toint(py_Ref);
|
||||
/// Get the address of the trivial value object.
|
||||
PK_API void* py_totrivial(py_Ref);
|
||||
/// Convert a `float` object in python to `double`.
|
||||
PK_API py_f64 py_tofloat(py_Ref);
|
||||
/// Cast a `int` or `float` object in python to `double`.
|
||||
/// If successful, return true and set the value to `out`.
|
||||
/// Otherwise, return false and raise `TypeError`.
|
||||
PK_API bool py_castfloat(py_Ref, py_f64* out) PY_RAISE;
|
||||
/// 32-bit version of `py_castfloat`.
|
||||
PK_API bool py_castfloat32(py_Ref, float* out) PY_RAISE;
|
||||
/// Cast a `int` object in python to `int64_t`.
|
||||
PK_API bool py_castint(py_Ref, py_i64* out) PY_RAISE;
|
||||
/// Convert a `bool` object in python to `bool`.
|
||||
PK_API bool py_tobool(py_Ref);
|
||||
/// Convert a `type` object in python to `py_Type`.
|
||||
PK_API py_Type py_totype(py_Ref);
|
||||
/// Convert a `str` object in python to null-terminated string.
|
||||
PK_API const char* py_tostr(py_Ref);
|
||||
/// Convert a `str` object in python to char array.
|
||||
PK_API const char* py_tostrn(py_Ref, int* size);
|
||||
/// Convert a `str` object in python to `c11_sv`.
|
||||
PK_API c11_sv py_tosv(py_Ref);
|
||||
/// Convert a `bytes` object in python to char array.
|
||||
PK_API unsigned char* py_tobytes(py_Ref, int* size);
|
||||
/// Resize a `bytes` object. It can only be resized down.
|
||||
PK_API void py_bytes_resize(py_Ref, int size);
|
||||
/// Convert a user-defined object to its userdata.
|
||||
PK_API void* py_touserdata(py_Ref);
|
||||
|
||||
#define py_isint(self) py_istype(self, tp_int)
|
||||
#define py_isfloat(self) py_istype(self, tp_float)
|
||||
#define py_isbool(self) py_istype(self, tp_bool)
|
||||
#define py_isstr(self) py_istype(self, tp_str)
|
||||
#define py_islist(self) py_istype(self, tp_list)
|
||||
#define py_istuple(self) py_istype(self, tp_tuple)
|
||||
#define py_isdict(self) py_istype(self, tp_dict)
|
||||
|
||||
#define py_isnil(self) py_istype(self, 0)
|
||||
#define py_isnone(self) py_istype(self, tp_NoneType)
|
||||
|
||||
/// Get the type of the object.
|
||||
PK_API py_Type py_typeof(py_Ref self);
|
||||
/// Get type by module and name. e.g. `py_gettype("time", py_name("struct_time"))`.
|
||||
/// Return `0` if not found.
|
||||
PK_API py_Type py_gettype(const char* module, py_Name name);
|
||||
/// Check if the object is exactly the given type.
|
||||
PK_API bool py_istype(py_Ref, py_Type);
|
||||
/// Check if the object is an instance of the given type.
|
||||
PK_API bool py_isinstance(py_Ref obj, py_Type type);
|
||||
/// Check if the derived type is a subclass of the base type.
|
||||
PK_API bool py_issubclass(py_Type derived, py_Type base);
|
||||
|
||||
/// Get the magic method from the given type only.
|
||||
/// Return `nil` if not found.
|
||||
PK_API PK_DEPRECATED py_GlobalRef py_tpgetmagic(py_Type type, py_Name name);
|
||||
/// Search the magic method from the given type to the base type.
|
||||
/// Return `NULL` if not found.
|
||||
PK_API py_GlobalRef py_tpfindmagic(py_Type, py_Name name);
|
||||
/// Search the name from the given type to the base type.
|
||||
/// Return `NULL` if not found.
|
||||
PK_API py_ItemRef py_tpfindname(py_Type, py_Name name);
|
||||
/// Get the base type of the given type.
|
||||
PK_API py_Type py_tpbase(py_Type type);
|
||||
|
||||
/// Get the type object of the given type.
|
||||
PK_API py_GlobalRef py_tpobject(py_Type type);
|
||||
/// Get the type name.
|
||||
PK_API const char* py_tpname(py_Type type);
|
||||
/// Call a type to create a new instance.
|
||||
PK_API bool py_tpcall(py_Type type, int argc, py_Ref argv) PY_RAISE PY_RETURN;
|
||||
/// Disable the type for subclassing.
|
||||
PK_API void py_tpsetfinal(py_Type type);
|
||||
/// Set attribute hooks for the given type.
|
||||
PK_API void py_tphookattributes(py_Type type,
|
||||
bool (*getattribute)(py_Ref self, py_Name name) PY_RAISE PY_RETURN,
|
||||
bool (*setattribute)(py_Ref self, py_Name name, py_Ref val)
|
||||
PY_RAISE PY_RETURN,
|
||||
bool (*delattribute)(py_Ref self, py_Name name) PY_RAISE,
|
||||
bool (*getunboundmethod)(py_Ref self, py_Name name) PY_RETURN);
|
||||
|
||||
/// Check if the object is an instance of the given type exactly.
|
||||
/// Raise `TypeError` if the check fails.
|
||||
PK_API bool py_checktype(py_Ref self, py_Type type) PY_RAISE;
|
||||
|
||||
/// Check if the object is an instance of the given type or its subclass.
|
||||
/// Raise `TypeError` if the check fails.
|
||||
PK_API bool py_checkinstance(py_Ref self, py_Type type) PY_RAISE;
|
||||
|
||||
#define py_checkint(self) py_checktype(self, tp_int)
|
||||
#define py_checkfloat(self) py_checktype(self, tp_float)
|
||||
#define py_checkbool(self) py_checktype(self, tp_bool)
|
||||
#define py_checkstr(self) py_checktype(self, tp_str)
|
||||
|
||||
/************* References *************/
|
||||
|
||||
/// Get the i-th register.
|
||||
/// All registers are located in a contiguous memory.
|
||||
PK_API py_GlobalRef py_getreg(int i);
|
||||
/// Set the i-th register.
|
||||
PK_API void py_setreg(int i, py_Ref val);
|
||||
|
||||
#define py_r0() py_getreg(0)
|
||||
#define py_r1() py_getreg(1)
|
||||
#define py_r2() py_getreg(2)
|
||||
#define py_r3() py_getreg(3)
|
||||
#define py_r4() py_getreg(4)
|
||||
#define py_r5() py_getreg(5)
|
||||
#define py_r6() py_getreg(6)
|
||||
#define py_r7() py_getreg(7)
|
||||
|
||||
/// Get variable in the `__main__` module.
|
||||
PK_API py_ItemRef py_getglobal(py_Name name);
|
||||
/// Set variable in the `__main__` module.
|
||||
PK_API void py_setglobal(py_Name name, py_Ref val);
|
||||
/// Get variable in the `builtins` module.
|
||||
PK_API py_ItemRef py_getbuiltin(py_Name name);
|
||||
|
||||
/// Get the last return value.
|
||||
/// Please note that `py_retval()` cannot be used as input argument.
|
||||
PK_API py_GlobalRef py_retval();
|
||||
|
||||
/// Get an item from the object's `__dict__`.
|
||||
/// Return `NULL` if not found.
|
||||
PK_API py_ItemRef py_getdict(py_Ref self, py_Name name);
|
||||
/// Set an item to the object's `__dict__`.
|
||||
PK_API void py_setdict(py_Ref self, py_Name name, py_Ref val);
|
||||
/// Delete an item from the object's `__dict__`.
|
||||
/// Return `true` if the deletion is successful.
|
||||
PK_API bool py_deldict(py_Ref self, py_Name name);
|
||||
/// Prepare an insertion to the object's `__dict__`.
|
||||
PK_API py_ItemRef py_emplacedict(py_Ref self, py_Name name);
|
||||
/// Apply a function to all items in the object's `__dict__`.
|
||||
/// Return `true` if the function is successful for all items.
|
||||
/// NOTE: Be careful if `f` modifies the object's `__dict__`.
|
||||
PK_API bool
|
||||
py_applydict(py_Ref self, bool (*f)(py_Name name, py_Ref val, void* ctx), void* ctx) PY_RAISE;
|
||||
/// Clear the object's `__dict__`. This function is dangerous.
|
||||
PK_API void py_cleardict(py_Ref self);
|
||||
|
||||
/// Get the i-th slot of the object.
|
||||
/// The object must have slots and `i` must be in valid range.
|
||||
PK_API py_ObjectRef py_getslot(py_Ref self, int i);
|
||||
/// Set the i-th slot of the object.
|
||||
PK_API void py_setslot(py_Ref self, int i, py_Ref val);
|
||||
|
||||
/************* Inspection *************/
|
||||
|
||||
/// Get the current `function` object on the stack.
|
||||
/// Return `NULL` if not available.
|
||||
/// NOTE: This function should be placed at the beginning of your decl-based bindings.
|
||||
PK_API py_StackRef py_inspect_currentfunction();
|
||||
/// Get the current `module` object where the code is executed.
|
||||
/// Return `NULL` if not available.
|
||||
PK_API py_GlobalRef py_inspect_currentmodule();
|
||||
/// Get the current frame object.
|
||||
/// Return `NULL` if not available.
|
||||
PK_API py_Frame* py_inspect_currentframe();
|
||||
/************* Bindings *************/
|
||||
|
||||
/// Bind a function to the object via "decl-based" style.
|
||||
@ -487,6 +287,225 @@ PK_API void
|
||||
py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter);
|
||||
/// Bind a magic method to type.
|
||||
PK_API void py_bindmagic(py_Type type, py_Name name, py_CFunction f);
|
||||
/// Bind a compile-time function via "decl-based" style.
|
||||
PK_API void py_macrobind(const char* sig, py_CFunction f);
|
||||
/// Get a compile-time function by name.
|
||||
PK_API py_ItemRef py_macroget(py_Name name);
|
||||
|
||||
/************* Value Cast *************/
|
||||
|
||||
/// Convert an `int` object in python to `int64_t`.
|
||||
PK_API py_i64 py_toint(py_Ref);
|
||||
/// Get the address of the trivial value object (16 bytes).
|
||||
PK_API void* py_totrivial(py_Ref);
|
||||
/// Convert a `float` object in python to `double`.
|
||||
PK_API py_f64 py_tofloat(py_Ref);
|
||||
/// Cast a `int` or `float` object in python to `double`.
|
||||
/// If successful, return true and set the value to `out`.
|
||||
/// Otherwise, return false and raise `TypeError`.
|
||||
PK_API bool py_castfloat(py_Ref, py_f64* out) PY_RAISE;
|
||||
/// 32-bit version of `py_castfloat`.
|
||||
PK_API bool py_castfloat32(py_Ref, float* out) PY_RAISE;
|
||||
/// Cast a `int` object in python to `int64_t`.
|
||||
PK_API bool py_castint(py_Ref, py_i64* out) PY_RAISE;
|
||||
/// Convert a `bool` object in python to `bool`.
|
||||
PK_API bool py_tobool(py_Ref);
|
||||
/// Convert a `type` object in python to `py_Type`.
|
||||
PK_API py_Type py_totype(py_Ref);
|
||||
/// Convert a user-defined object to its userdata.
|
||||
PK_API void* py_touserdata(py_Ref);
|
||||
/// Convert a `str` object in python to null-terminated string.
|
||||
PK_API const char* py_tostr(py_Ref);
|
||||
/// Convert a `str` object in python to char array.
|
||||
PK_API const char* py_tostrn(py_Ref, int* size);
|
||||
/// Convert a `str` object in python to `c11_sv`.
|
||||
PK_API c11_sv py_tosv(py_Ref);
|
||||
/// Convert a `bytes` object in python to char array.
|
||||
PK_API unsigned char* py_tobytes(py_Ref, int* size);
|
||||
/// Resize a `bytes` object. It can only be resized down.
|
||||
PK_API void py_bytes_resize(py_Ref, int size);
|
||||
|
||||
/************* Type System *************/
|
||||
|
||||
/// Create a new type.
|
||||
/// @param name name of the type.
|
||||
/// @param base base type.
|
||||
/// @param module module where the type is defined. Use `NULL` for built-in types.
|
||||
/// @param dtor destructor function. Use `NULL` if not needed.
|
||||
PK_API py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, py_Dtor dtor);
|
||||
/// Check if the object is exactly the given type.
|
||||
PK_API bool py_istype(py_Ref, py_Type);
|
||||
/// Get the type of the object.
|
||||
PK_API py_Type py_typeof(py_Ref self);
|
||||
/// Check if the object is an instance of the given type.
|
||||
PK_API bool py_isinstance(py_Ref obj, py_Type type);
|
||||
/// Check if the derived type is a subclass of the base type.
|
||||
PK_API bool py_issubclass(py_Type derived, py_Type base);
|
||||
/// Get type by module and name. e.g. `py_gettype("time", py_name("struct_time"))`.
|
||||
/// Return `0` if not found.
|
||||
PK_API py_Type py_gettype(const char* module, py_Name name);
|
||||
/// Check if the object is an instance of the given type exactly.
|
||||
/// Raise `TypeError` if the check fails.
|
||||
PK_API bool py_checktype(py_Ref self, py_Type type) PY_RAISE;
|
||||
/// Check if the object is an instance of the given type or its subclass.
|
||||
/// Raise `TypeError` if the check fails.
|
||||
PK_API bool py_checkinstance(py_Ref self, py_Type type) PY_RAISE;
|
||||
/// Get the magic method from the given type only.
|
||||
/// Return `nil` if not found.
|
||||
PK_API PK_DEPRECATED py_GlobalRef py_tpgetmagic(py_Type type, py_Name name);
|
||||
/// Search the magic method from the given type to the base type.
|
||||
/// Return `NULL` if not found.
|
||||
PK_API py_GlobalRef py_tpfindmagic(py_Type, py_Name name);
|
||||
/// Search the name from the given type to the base type.
|
||||
/// Return `NULL` if not found.
|
||||
PK_API py_ItemRef py_tpfindname(py_Type, py_Name name);
|
||||
/// Get the base type of the given type.
|
||||
PK_API py_Type py_tpbase(py_Type type);
|
||||
/// Get the type object of the given type.
|
||||
PK_API py_GlobalRef py_tpobject(py_Type type);
|
||||
/// Get the type name.
|
||||
PK_API const char* py_tpname(py_Type type);
|
||||
/// Disable the type for subclassing.
|
||||
PK_API void py_tpsetfinal(py_Type type);
|
||||
/// Set attribute hooks for the given type.
|
||||
PK_API void py_tphookattributes(py_Type type,
|
||||
bool (*getattribute)(py_Ref self, py_Name name) PY_RAISE PY_RETURN,
|
||||
bool (*setattribute)(py_Ref self, py_Name name, py_Ref val)
|
||||
PY_RAISE PY_RETURN,
|
||||
bool (*delattribute)(py_Ref self, py_Name name) PY_RAISE,
|
||||
bool (*getunboundmethod)(py_Ref self, py_Name name) PY_RETURN);
|
||||
|
||||
#define py_isint(self) py_istype(self, tp_int)
|
||||
#define py_isfloat(self) py_istype(self, tp_float)
|
||||
#define py_isbool(self) py_istype(self, tp_bool)
|
||||
#define py_isstr(self) py_istype(self, tp_str)
|
||||
#define py_islist(self) py_istype(self, tp_list)
|
||||
#define py_istuple(self) py_istype(self, tp_tuple)
|
||||
#define py_isdict(self) py_istype(self, tp_dict)
|
||||
#define py_isnil(self) py_istype(self, 0)
|
||||
#define py_isnone(self) py_istype(self, tp_NoneType)
|
||||
|
||||
#define py_checkint(self) py_checktype(self, tp_int)
|
||||
#define py_checkfloat(self) py_checktype(self, tp_float)
|
||||
#define py_checkbool(self) py_checktype(self, tp_bool)
|
||||
#define py_checkstr(self) py_checktype(self, tp_str)
|
||||
|
||||
/************* Inspection *************/
|
||||
|
||||
/// Get the current `function` object on the stack.
|
||||
/// Return `NULL` if not available.
|
||||
/// NOTE: This function should be placed at the beginning of your decl-based bindings.
|
||||
PK_API py_StackRef py_inspect_currentfunction();
|
||||
/// Get the current `module` object where the code is executed.
|
||||
/// Return `NULL` if not available.
|
||||
PK_API py_GlobalRef py_inspect_currentmodule();
|
||||
/// Get the current frame object.
|
||||
/// Return `NULL` if not available.
|
||||
PK_API py_Frame* py_inspect_currentframe();
|
||||
/// Python equivalent to `globals()`.
|
||||
PK_API void py_newglobals(py_OutRef);
|
||||
/// Python equivalent to `locals()`.
|
||||
PK_API void py_newlocals(py_OutRef);
|
||||
|
||||
/************* Dict & Slots *************/
|
||||
|
||||
/// Get the i-th register.
|
||||
/// All registers are located in a contiguous memory.
|
||||
PK_API py_GlobalRef py_getreg(int i);
|
||||
/// Set the i-th register.
|
||||
PK_API void py_setreg(int i, py_Ref val);
|
||||
/// Get the last return value.
|
||||
/// Please note that `py_retval()` cannot be used as input argument.
|
||||
PK_API py_GlobalRef py_retval();
|
||||
|
||||
#define py_r0() py_getreg(0)
|
||||
#define py_r1() py_getreg(1)
|
||||
#define py_r2() py_getreg(2)
|
||||
#define py_r3() py_getreg(3)
|
||||
#define py_r4() py_getreg(4)
|
||||
#define py_r5() py_getreg(5)
|
||||
#define py_r6() py_getreg(6)
|
||||
#define py_r7() py_getreg(7)
|
||||
|
||||
/// Get an item from the object's `__dict__`.
|
||||
/// Return `NULL` if not found.
|
||||
PK_API py_ItemRef py_getdict(py_Ref self, py_Name name);
|
||||
/// Set an item to the object's `__dict__`.
|
||||
PK_API void py_setdict(py_Ref self, py_Name name, py_Ref val);
|
||||
/// Delete an item from the object's `__dict__`.
|
||||
/// Return `true` if the deletion is successful.
|
||||
PK_API bool py_deldict(py_Ref self, py_Name name);
|
||||
/// Prepare an insertion to the object's `__dict__`.
|
||||
PK_API py_ItemRef py_emplacedict(py_Ref self, py_Name name);
|
||||
/// Apply a function to all items in the object's `__dict__`.
|
||||
/// Return `true` if the function is successful for all items.
|
||||
/// NOTE: Be careful if `f` modifies the object's `__dict__`.
|
||||
PK_API bool
|
||||
py_applydict(py_Ref self, bool (*f)(py_Name name, py_Ref val, void* ctx), void* ctx) PY_RAISE;
|
||||
/// Clear the object's `__dict__`. This function is dangerous.
|
||||
PK_API void py_cleardict(py_Ref self);
|
||||
/// Get the i-th slot of the object.
|
||||
/// The object must have slots and `i` must be in valid range.
|
||||
PK_API py_ObjectRef py_getslot(py_Ref self, int i);
|
||||
/// Set the i-th slot of the object.
|
||||
PK_API void py_setslot(py_Ref self, int i, py_Ref val);
|
||||
/// Get variable in the `builtins` module.
|
||||
PK_API py_ItemRef py_getbuiltin(py_Name name);
|
||||
/// Get variable in the `__main__` module.
|
||||
PK_API py_ItemRef py_getglobal(py_Name name);
|
||||
/// Set variable in the `__main__` module.
|
||||
PK_API void py_setglobal(py_Name name, py_Ref val);
|
||||
|
||||
/************* Stack Ops *************/
|
||||
|
||||
/// Get the i-th object from the top of the stack.
|
||||
/// `i` should be negative, e.g. (-1) means TOS.
|
||||
PK_API py_StackRef py_peek(int i);
|
||||
/// Push the object to the stack.
|
||||
PK_API void py_push(py_Ref src);
|
||||
/// Push a `nil` object to the stack.
|
||||
PK_API void py_pushnil();
|
||||
/// Push a `None` object to the stack.
|
||||
PK_API void py_pushnone();
|
||||
/// Push a `py_Name` to the stack. This is used for keyword arguments.
|
||||
PK_API void py_pushname(py_Name name);
|
||||
/// Pop an object from the stack.
|
||||
PK_API void py_pop();
|
||||
/// Shrink the stack by n.
|
||||
PK_API void py_shrink(int n);
|
||||
/// Get a temporary variable from the stack.
|
||||
PK_API py_StackRef py_pushtmp();
|
||||
/// Get the unbound method of the object.
|
||||
/// Assume the object is located at the top of the stack.
|
||||
/// If return true: `[self] -> [unbound, self]`.
|
||||
/// If return false: `[self] -> [self]` (no change).
|
||||
PK_API bool py_pushmethod(py_Name name);
|
||||
/// Evaluate an expression and push the result to the stack.
|
||||
/// This function is used for testing.
|
||||
PK_API bool py_pusheval(const char* expr, py_GlobalRef module) PY_RAISE;
|
||||
/// Call a callable object via pocketpy's calling convention.
|
||||
/// You need to prepare the stack using the following format:
|
||||
/// `callable, self/nil, arg1, arg2, ..., k1, v1, k2, v2, ...`.
|
||||
/// `argc` is the number of positional arguments excluding `self`.
|
||||
/// `kwargc` is the number of keyword arguments.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack size will be reduced by `2 + argc + kwargc * 2`.
|
||||
PK_API bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE PY_RETURN;
|
||||
/// Call a function.
|
||||
/// It prepares the stack and then performs a `vectorcall(argc, 0, false)`.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack remains unchanged if successful.
|
||||
PK_API bool py_call(py_Ref f, int argc, py_Ref argv) PY_RAISE PY_RETURN;
|
||||
/// Call a type to create a new instance.
|
||||
PK_API bool py_tpcall(py_Type type, int argc, py_Ref argv) PY_RAISE PY_RETURN;
|
||||
|
||||
#ifndef NDEBUG
|
||||
/// Call a `py_CFunction` in a safe way.
|
||||
/// This function does extra checks to help you debug `py_CFunction`.
|
||||
PK_API bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) PY_RAISE PY_RETURN;
|
||||
#else
|
||||
#define py_callcfunc(f, argc, argv) (f((argc), (argv)))
|
||||
#endif
|
||||
|
||||
#define PY_CHECK_ARGC(n) \
|
||||
if(argc != n) return TypeError("expected %d arguments, got %d", n, argc)
|
||||
@ -498,25 +517,13 @@ PK_API void py_bindmagic(py_Type type, py_Name name, py_CFunction f);
|
||||
#define py_arg(i) (&argv[i])
|
||||
#define py_assign(dst, src) *(dst) = *(src)
|
||||
|
||||
/************* Python Equivalents *************/
|
||||
|
||||
/// Python equivalent to `getattr(self, name)`.
|
||||
PK_API bool py_getattr(py_Ref self, py_Name name) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `setattr(self, name, val)`.
|
||||
PK_API bool py_setattr(py_Ref self, py_Name name, py_Ref val) PY_RAISE;
|
||||
/// Python equivalent to `delattr(self, name)`.
|
||||
PK_API bool py_delattr(py_Ref self, py_Name name) PY_RAISE;
|
||||
/// Python equivalent to `self[key]`.
|
||||
PK_API bool py_getitem(py_Ref self, py_Ref key) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `self[key] = val`.
|
||||
PK_API bool py_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
|
||||
/// Python equivalent to `del self[key]`.
|
||||
PK_API bool py_delitem(py_Ref self, py_Ref key) PY_RAISE;
|
||||
|
||||
/// Perform a binary operation.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack remains unchanged after the operation.
|
||||
PK_API bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) PY_RAISE PY_RETURN;
|
||||
|
||||
/************* Python Ops *************/
|
||||
|
||||
/// lhs + rhs
|
||||
PK_API bool py_binaryadd(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs - rhs
|
||||
@ -543,68 +550,74 @@ PK_API bool py_binaryor(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
PK_API bool py_binaryxor(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs @ rhs
|
||||
PK_API bool py_binarymatmul(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs == rhs
|
||||
PK_API bool py_eq(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs != rhs
|
||||
PK_API bool py_ne(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs < rhs
|
||||
PK_API bool py_lt(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs <= rhs
|
||||
PK_API bool py_le(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs > rhs
|
||||
PK_API bool py_gt(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs >= rhs
|
||||
PK_API bool py_ge(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
|
||||
/************* Stack Operations *************/
|
||||
/// Python equivalent to `lhs is rhs`.
|
||||
PK_API bool py_isidentical(py_Ref, py_Ref);
|
||||
/// Python equivalent to `bool(val)`.
|
||||
/// 1: true, 0: false, -1: error
|
||||
PK_API int py_bool(py_Ref val) PY_RAISE;
|
||||
/// Compare two objects.
|
||||
/// 1: lhs == rhs, 0: lhs != rhs, -1: error
|
||||
PK_API int py_equal(py_Ref lhs, py_Ref rhs) PY_RAISE;
|
||||
/// Compare two objects.
|
||||
/// 1: lhs < rhs, 0: lhs >= rhs, -1: error
|
||||
PK_API int py_less(py_Ref lhs, py_Ref rhs) PY_RAISE;
|
||||
/// Python equivalent to `callable(val)`.
|
||||
PK_API bool py_callable(py_Ref val);
|
||||
/// Get the hash value of the object.
|
||||
PK_API bool py_hash(py_Ref, py_i64* out) PY_RAISE;
|
||||
/// Get the iterator of the object.
|
||||
PK_API bool py_iter(py_Ref) PY_RAISE PY_RETURN;
|
||||
/// Get the next element from the iterator.
|
||||
/// 1: success, 0: StopIteration, -1: error
|
||||
PK_API int py_next(py_Ref) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `str(val)`.
|
||||
PK_API bool py_str(py_Ref val) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `repr(val)`.
|
||||
PK_API bool py_repr(py_Ref val) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `len(val)`.
|
||||
PK_API bool py_len(py_Ref val) PY_RAISE PY_RETURN;
|
||||
|
||||
/// Get the i-th object from the top of the stack.
|
||||
/// `i` should be negative, e.g. (-1) means TOS.
|
||||
PK_API py_StackRef py_peek(int i);
|
||||
/// Push the object to the stack.
|
||||
PK_API void py_push(py_Ref src);
|
||||
/// Push a `nil` object to the stack.
|
||||
PK_API void py_pushnil();
|
||||
/// Push a `None` object to the stack.
|
||||
PK_API void py_pushnone();
|
||||
/// Push a `py_Name` to the stack. This is used for keyword arguments.
|
||||
PK_API void py_pushname(py_Name name);
|
||||
/// Pop an object from the stack.
|
||||
PK_API void py_pop();
|
||||
/// Shrink the stack by n.
|
||||
PK_API void py_shrink(int n);
|
||||
/// Get a temporary variable from the stack.
|
||||
PK_API py_StackRef py_pushtmp();
|
||||
/// Get the unbound method of the object.
|
||||
/// Assume the object is located at the top of the stack.
|
||||
/// If return true: `[self] -> [unbound, self]`.
|
||||
/// If return false: `[self] -> [self]` (no change).
|
||||
PK_API bool py_pushmethod(py_Name name);
|
||||
/// Call a callable object via pocketpy's calling convention.
|
||||
/// You need to prepare the stack using the following format:
|
||||
/// `callable, self/nil, arg1, arg2, ..., k1, v1, k2, v2, ...`.
|
||||
/// `argc` is the number of positional arguments excluding `self`.
|
||||
/// `kwargc` is the number of keyword arguments.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack size will be reduced by `2 + argc + kwargc * 2`.
|
||||
PK_API bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE PY_RETURN;
|
||||
/// Evaluate an expression and push the result to the stack.
|
||||
/// This function is used for testing.
|
||||
PK_API bool py_pusheval(const char* expr, py_GlobalRef module) PY_RAISE;
|
||||
/// Python equivalent to `getattr(self, name)`.
|
||||
PK_API bool py_getattr(py_Ref self, py_Name name) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `setattr(self, name, val)`.
|
||||
PK_API bool py_setattr(py_Ref self, py_Name name, py_Ref val) PY_RAISE;
|
||||
/// Python equivalent to `delattr(self, name)`.
|
||||
PK_API bool py_delattr(py_Ref self, py_Name name) PY_RAISE;
|
||||
/// Python equivalent to `self[key]`.
|
||||
PK_API bool py_getitem(py_Ref self, py_Ref key) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `self[key] = val`.
|
||||
PK_API bool py_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
|
||||
/// Python equivalent to `del self[key]`.
|
||||
PK_API bool py_delitem(py_Ref self, py_Ref key) PY_RAISE;
|
||||
|
||||
/************* Modules *************/
|
||||
/************* Module System *************/
|
||||
|
||||
/// Create a new module.
|
||||
PK_API py_GlobalRef py_newmodule(const char* path);
|
||||
/// Get a module by path.
|
||||
PK_API py_GlobalRef py_getmodule(const char* path);
|
||||
/// Create a new module.
|
||||
PK_API py_GlobalRef py_newmodule(const char* path);
|
||||
/// Reload an existing module.
|
||||
PK_API bool py_importlib_reload(py_Ref module) PY_RAISE PY_RETURN;
|
||||
|
||||
/// Import a module.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// -1: error, 0: not found, 1: success
|
||||
PK_API int py_import(const char* path) PY_RAISE PY_RETURN;
|
||||
|
||||
/************* Errors *************/
|
||||
/************* PyException *************/
|
||||
|
||||
/// Raise an exception by type and message. Always return false.
|
||||
PK_API bool py_exception(py_Type type, const char* fmt, ...) PY_RAISE;
|
||||
/// Raise an exception object. Always return false.
|
||||
PK_API bool py_raise(py_Ref) PY_RAISE;
|
||||
/// Print the unhandled exception.
|
||||
PK_API void py_printexc();
|
||||
/// Format the unhandled exception and return a null-terminated string.
|
||||
/// The returned string should be freed by the caller.
|
||||
PK_API char* py_formatexc();
|
||||
/// Check if there is an unhandled exception.
|
||||
PK_API bool py_checkexc();
|
||||
/// Check if the unhandled exception is an instance of the given type.
|
||||
@ -613,6 +626,15 @@ PK_API bool py_matchexc(py_Type type) PY_RETURN;
|
||||
/// Clear the unhandled exception.
|
||||
/// @param p0 the unwinding point. Use `NULL` if not needed.
|
||||
PK_API void py_clearexc(py_StackRef p0);
|
||||
/// Print the unhandled exception.
|
||||
PK_API void py_printexc();
|
||||
/// Format the unhandled exception and return a null-terminated string.
|
||||
/// The returned string should be freed by the caller.
|
||||
PK_API char* py_formatexc();
|
||||
/// Raise an exception by type and message. Always return false.
|
||||
PK_API bool py_exception(py_Type type, const char* fmt, ...) PY_RAISE;
|
||||
/// Raise an exception object. Always return false.
|
||||
PK_API bool py_raise(py_Ref) PY_RAISE;
|
||||
|
||||
#define NameError(n) py_exception(tp_NameError, "name '%n' is not defined", (n))
|
||||
#define TypeError(...) py_exception(tp_TypeError, __VA_ARGS__)
|
||||
@ -630,100 +652,40 @@ PK_API void py_clearexc(py_StackRef p0);
|
||||
"cannot access local variable '%n' where it is not associated with a value", \
|
||||
(n))
|
||||
|
||||
PK_API bool StopIteration() PY_RAISE;
|
||||
PK_API bool KeyError(py_Ref key) PY_RAISE;
|
||||
PK_API bool StopIteration() PY_RAISE;
|
||||
|
||||
/************* Operators *************/
|
||||
/************* Debugger *************/
|
||||
|
||||
/// Python equivalent to `bool(val)`.
|
||||
/// 1: true, 0: false, -1: error
|
||||
PK_API int py_bool(py_Ref val) PY_RAISE;
|
||||
/// Compare two objects.
|
||||
/// 1: lhs == rhs, 0: lhs != rhs, -1: error
|
||||
PK_API int py_equal(py_Ref lhs, py_Ref rhs) PY_RAISE;
|
||||
/// Compare two objects.
|
||||
/// 1: lhs < rhs, 0: lhs >= rhs, -1: error
|
||||
PK_API int py_less(py_Ref lhs, py_Ref rhs) PY_RAISE;
|
||||
|
||||
/// lhs == rhs
|
||||
PK_API bool py_eq(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs != rhs
|
||||
PK_API bool py_ne(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs < rhs
|
||||
PK_API bool py_lt(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs <= rhs
|
||||
PK_API bool py_le(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs > rhs
|
||||
PK_API bool py_gt(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
/// lhs >= rhs
|
||||
PK_API bool py_ge(py_Ref lhs, py_Ref rhs) PY_RAISE PY_RETURN;
|
||||
|
||||
/// Python equivalent to `callable(val)`.
|
||||
PK_API bool py_callable(py_Ref val);
|
||||
/// Get the hash value of the object.
|
||||
PK_API bool py_hash(py_Ref, py_i64* out) PY_RAISE;
|
||||
/// Get the iterator of the object.
|
||||
PK_API bool py_iter(py_Ref) PY_RAISE PY_RETURN;
|
||||
/// Get the next element from the iterator.
|
||||
/// 1: success, 0: StopIteration, -1: error
|
||||
PK_API int py_next(py_Ref) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `lhs is rhs`.
|
||||
PK_API bool py_isidentical(py_Ref, py_Ref);
|
||||
/// Call a function.
|
||||
/// It prepares the stack and then performs a `vectorcall(argc, 0, false)`.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack remains unchanged if successful.
|
||||
PK_API bool py_call(py_Ref f, int argc, py_Ref argv) PY_RAISE PY_RETURN;
|
||||
|
||||
#ifndef NDEBUG
|
||||
/// Call a `py_CFunction` in a safe way.
|
||||
/// This function does extra checks to help you debug `py_CFunction`.
|
||||
PK_API bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) PY_RAISE PY_RETURN;
|
||||
#else
|
||||
#define py_callcfunc(f, argc, argv) (f((argc), (argv)))
|
||||
#endif
|
||||
|
||||
/// Python equivalent to `str(val)`.
|
||||
PK_API bool py_str(py_Ref val) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `repr(val)`.
|
||||
PK_API bool py_repr(py_Ref val) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `len(val)`.
|
||||
PK_API bool py_len(py_Ref val) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `json.dumps(val)`.
|
||||
PK_API bool py_json_dumps(py_Ref val, int indent) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `json.loads(val)`.
|
||||
PK_API bool py_json_loads(const char* source) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `pickle.dumps(val)`.
|
||||
PK_API bool py_pickle_dumps(py_Ref val) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `pickle.loads(val)`.
|
||||
PK_API bool py_pickle_loads(const unsigned char* data, int size) PY_RAISE PY_RETURN;
|
||||
|
||||
/************* Profiler *************/
|
||||
PK_API void py_profiler_begin();
|
||||
PK_API void py_profiler_end();
|
||||
PK_API void py_profiler_reset();
|
||||
PK_API char* py_profiler_report();
|
||||
|
||||
/************* DAP *************/
|
||||
#if PK_ENABLE_OS
|
||||
PK_API void py_debugger_waitforattach(const char* hostname, unsigned short port);
|
||||
PK_API bool py_debugger_isattached();
|
||||
PK_API void py_debugger_exceptionbreakpoint(py_Ref exc);
|
||||
PK_API void py_debugger_exit(int exitCode);
|
||||
PK_API void py_debugger_exit(int code);
|
||||
#else
|
||||
#define py_debugger_waitforattach(hostname, port)
|
||||
#define py_debugger_isattached() (false)
|
||||
#define py_debugger_exceptionbreakpoint(exc)
|
||||
#define py_debugger_exit(exitCode)
|
||||
#define py_debugger_exit(code)
|
||||
#endif
|
||||
|
||||
/************* Unchecked Functions *************/
|
||||
/************* PyTuple *************/
|
||||
|
||||
/// Create a `tuple` with `n` UNINITIALIZED elements.
|
||||
/// You should initialize all elements before using it.
|
||||
PK_API py_ObjectRef py_newtuple(py_OutRef, int n);
|
||||
PK_API py_ObjectRef py_tuple_data(py_Ref self);
|
||||
PK_API py_ObjectRef py_tuple_getitem(py_Ref self, int i);
|
||||
PK_API void py_tuple_setitem(py_Ref self, int i, py_Ref val);
|
||||
PK_API int py_tuple_len(py_Ref self);
|
||||
|
||||
/************* PyList *************/
|
||||
|
||||
/// Create an empty `list`.
|
||||
PK_API void py_newlist(py_OutRef);
|
||||
/// Create a `list` with `n` UNINITIALIZED elements.
|
||||
/// You should initialize all elements before using it.
|
||||
PK_API void py_newlistn(py_OutRef, int n);
|
||||
PK_API py_ItemRef py_list_data(py_Ref self);
|
||||
PK_API py_ItemRef py_list_getitem(py_Ref self, int i);
|
||||
PK_API void py_list_setitem(py_Ref self, int i, py_Ref val);
|
||||
@ -735,6 +697,10 @@ PK_API py_ItemRef py_list_emplace(py_Ref self);
|
||||
PK_API void py_list_clear(py_Ref self);
|
||||
PK_API void py_list_insert(py_Ref self, int i, py_Ref val);
|
||||
|
||||
/************* PyDict *************/
|
||||
|
||||
/// Create an empty `dict`.
|
||||
PK_API void py_newdict(py_OutRef);
|
||||
/// -1: error, 0: not found, 1: found
|
||||
PK_API int py_dict_getitem(py_Ref self, py_Ref key) PY_RAISE PY_RETURN;
|
||||
/// true: success, false: error
|
||||
@ -761,6 +727,14 @@ PK_API bool
|
||||
/// noexcept
|
||||
PK_API int py_dict_len(py_Ref self);
|
||||
|
||||
/************* PySlice *************/
|
||||
|
||||
/// Create an UNINITIALIZED `slice` object.
|
||||
/// You should use `py_setslot()` to set `start`, `stop`, and `step`.
|
||||
PK_API py_ObjectRef py_newslice(py_OutRef);
|
||||
/// Create a `slice` object from 3 integers.
|
||||
PK_API void py_newsliceint(py_OutRef out, py_i64 start, py_i64 stop, py_i64 step);
|
||||
|
||||
/************* random module *************/
|
||||
PK_API void py_newRandom(py_OutRef out);
|
||||
PK_API void py_Random_seed(py_Ref self, py_i64 seed);
|
||||
@ -789,6 +763,32 @@ PK_API c11_vec3i py_tovec3i(py_Ref self);
|
||||
PK_API c11_mat3x3* py_tomat3x3(py_Ref self);
|
||||
PK_API c11_color32 py_tocolor32(py_Ref self);
|
||||
|
||||
/************* json module *************/
|
||||
/// Python equivalent to `json.dumps(val)`.
|
||||
PK_API bool py_json_dumps(py_Ref val, int indent) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `json.loads(val)`.
|
||||
PK_API bool py_json_loads(const char* source) PY_RAISE PY_RETURN;
|
||||
|
||||
/************* pickle module *************/
|
||||
/// Python equivalent to `pickle.dumps(val)`.
|
||||
PK_API bool py_pickle_dumps(py_Ref val) PY_RAISE PY_RETURN;
|
||||
/// Python equivalent to `pickle.loads(val)`.
|
||||
PK_API bool py_pickle_loads(const unsigned char* data, int size) PY_RAISE PY_RETURN;
|
||||
|
||||
/************* pkpy module *************/
|
||||
/// Begin the watchdog with `timeout` in milliseconds.
|
||||
/// `PK_ENABLE_WATCHDOG` must be defined to `1` to use this feature.
|
||||
/// You need to call `py_watchdog_end()` later.
|
||||
/// If `timeout` is reached, `TimeoutError` will be raised.
|
||||
PK_API void py_watchdog_begin(py_i64 timeout);
|
||||
/// Reset the watchdog.
|
||||
PK_API void py_watchdog_end();
|
||||
|
||||
PK_API void py_profiler_begin();
|
||||
PK_API void py_profiler_end();
|
||||
PK_API void py_profiler_reset();
|
||||
PK_API char* py_profiler_report();
|
||||
|
||||
/************* Others *************/
|
||||
|
||||
/// An utility function to read a line from stdin for REPL.
|
||||
|
@ -27,20 +27,29 @@ class defaultdict(dict):
|
||||
|
||||
|
||||
class deque[T]:
|
||||
_data: list[T]
|
||||
_head: int
|
||||
_tail: int
|
||||
_maxlen: int | None
|
||||
_capacity: int
|
||||
_data: list[T]
|
||||
|
||||
def __init__(self, iterable: Iterable[T] = None, maxlen: int | None = None):
|
||||
if maxlen is not None:
|
||||
assert maxlen > 0
|
||||
|
||||
def __init__(self, iterable: Iterable[T] = None):
|
||||
self._data = [None] * 8 # type: ignore
|
||||
self._head = 0
|
||||
self._tail = 0
|
||||
self._capacity = len(self._data)
|
||||
self._maxlen = maxlen
|
||||
self._capacity = 8 if maxlen is None else maxlen + 1
|
||||
self._data = [None] * self._capacity # type: ignore
|
||||
|
||||
if iterable is not None:
|
||||
self.extend(iterable)
|
||||
|
||||
@property
|
||||
def maxlen(self) -> int | None:
|
||||
return self._maxlen
|
||||
|
||||
def __resize_2x(self):
|
||||
backup = list(self)
|
||||
self._capacity *= 2
|
||||
@ -51,19 +60,25 @@ class deque[T]:
|
||||
self._data.extend([None] * (self._capacity - len(backup)))
|
||||
|
||||
def append(self, x: T):
|
||||
if (self._tail + 1) % self._capacity == self._head:
|
||||
if self._maxlen is None:
|
||||
self.__resize_2x()
|
||||
else:
|
||||
self.popleft()
|
||||
self._data[self._tail] = x
|
||||
self._tail = (self._tail + 1) % self._capacity
|
||||
if (self._tail + 1) % self._capacity == self._head:
|
||||
self.__resize_2x()
|
||||
|
||||
def appendleft(self, x: T):
|
||||
if (self._tail + 1) % self._capacity == self._head:
|
||||
if self._maxlen is None:
|
||||
self.__resize_2x()
|
||||
else:
|
||||
self.pop()
|
||||
self._head = (self._head - 1) % self._capacity
|
||||
self._data[self._head] = x
|
||||
if (self._tail + 1) % self._capacity == self._head:
|
||||
self.__resize_2x()
|
||||
|
||||
def copy(self):
|
||||
return deque(self)
|
||||
return deque(self, maxlen=self.maxlen)
|
||||
|
||||
def count(self, x: T) -> int:
|
||||
n = 0
|
||||
@ -84,12 +99,15 @@ class deque[T]:
|
||||
if self._head == self._tail:
|
||||
raise IndexError("pop from an empty deque")
|
||||
self._tail = (self._tail - 1) % self._capacity
|
||||
return self._data[self._tail]
|
||||
x = self._data[self._tail]
|
||||
self._data[self._tail] = None
|
||||
return x
|
||||
|
||||
def popleft(self) -> T:
|
||||
if self._head == self._tail:
|
||||
raise IndexError("pop from an empty deque")
|
||||
x = self._data[self._head]
|
||||
self._data[self._head] = None
|
||||
self._head = (self._head + 1) % self._capacity
|
||||
return x
|
||||
|
||||
@ -144,5 +162,7 @@ class deque[T]:
|
||||
return not self == other
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"deque({list(self)!r})"
|
||||
if self.maxlen is None:
|
||||
return f"deque({list(self)!r})"
|
||||
return f"deque({list(self)!r}, maxlen={self.maxlen})"
|
||||
|
||||
|
@ -1,59 +1,10 @@
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
|
||||
void py_newstr(py_OutRef out, const char* data) { py_newstrv(out, (c11_sv){data, strlen(data)}); }
|
||||
|
||||
char* py_newstrn(py_OutRef out, int size) {
|
||||
if(size < 16) {
|
||||
out->type = tp_str;
|
||||
out->is_ptr = false;
|
||||
c11_string* ud = (c11_string*)(&out->extra);
|
||||
c11_string__ctor3(ud, size);
|
||||
return ud->data;
|
||||
}
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
int total_size = sizeof(c11_string) + size + 1;
|
||||
PyObject* obj = ManagedHeap__gcnew(heap, tp_str, 0, total_size);
|
||||
c11_string* ud = PyObject__userdata(obj);
|
||||
c11_string__ctor3(ud, size);
|
||||
out->type = tp_str;
|
||||
out->is_ptr = true;
|
||||
out->_obj = obj;
|
||||
return ud->data;
|
||||
}
|
||||
|
||||
void py_newstrv(py_OutRef out, c11_sv sv) {
|
||||
char* data = py_newstrn(out, sv.size);
|
||||
memcpy(data, sv.data, sv.size);
|
||||
}
|
||||
|
||||
void py_newfstr(py_OutRef out, const char* fmt, ...) {
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
pk_vsprintf(&buf, fmt, args);
|
||||
va_end(args);
|
||||
c11_sbuf__py_submit(&buf, out);
|
||||
}
|
||||
|
||||
unsigned char* py_newbytes(py_OutRef out, int size) {
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
// 4 bytes size + data
|
||||
PyObject* obj = ManagedHeap__gcnew(heap, tp_bytes, 0, sizeof(c11_bytes) + size);
|
||||
c11_bytes* ud = PyObject__userdata(obj);
|
||||
ud->size = size;
|
||||
out->type = tp_bytes;
|
||||
out->is_ptr = true;
|
||||
out->_obj = obj;
|
||||
return ud->data;
|
||||
}
|
||||
|
||||
c11_string* pk_tostr(py_Ref self) {
|
||||
assert(self->type == tp_str);
|
||||
if(!self->is_ptr) {
|
||||
@ -63,33 +14,6 @@ c11_string* pk_tostr(py_Ref self) {
|
||||
}
|
||||
}
|
||||
|
||||
const char* py_tostr(py_Ref self) { return pk_tostr(self)->data; }
|
||||
|
||||
const char* py_tostrn(py_Ref self, int* size) {
|
||||
c11_string* ud = pk_tostr(self);
|
||||
*size = ud->size;
|
||||
return ud->data;
|
||||
}
|
||||
|
||||
c11_sv py_tosv(py_Ref self) {
|
||||
c11_string* ud = pk_tostr(self);
|
||||
return c11_string__sv(ud);
|
||||
}
|
||||
|
||||
unsigned char* py_tobytes(py_Ref self, int* size) {
|
||||
assert(self->type == tp_bytes);
|
||||
c11_bytes* ud = PyObject__userdata(self->_obj);
|
||||
*size = ud->size;
|
||||
return ud->data;
|
||||
}
|
||||
|
||||
void py_bytes_resize(py_Ref self, int size) {
|
||||
assert(self->type == tp_bytes);
|
||||
c11_bytes* ud = PyObject__userdata(self->_obj);
|
||||
if(size > ud->size) c11__abort("bytes can only be resized down: %d > %d", ud->size, size);
|
||||
ud->size = size;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
static bool str__new__(int argc, py_Ref argv) {
|
||||
assert(argc >= 1);
|
||||
@ -673,18 +597,4 @@ py_Type pk_bytes__register() {
|
||||
return type;
|
||||
}
|
||||
|
||||
bool py_str(py_Ref val) {
|
||||
if(val->type == tp_str) {
|
||||
py_assign(py_retval(), val);
|
||||
return true;
|
||||
}
|
||||
py_Ref tmp = py_tpfindmagic(val->type, __str__);
|
||||
if(!tmp) return py_repr(val);
|
||||
return py_call(tmp, 1, val);
|
||||
}
|
||||
|
||||
bool py_repr(py_Ref val) { return pk_callmagic(__repr__, 1, val); }
|
||||
|
||||
bool py_len(py_Ref val) { return pk_callmagic(__len__, 1, val); }
|
||||
|
||||
#undef DEF_STR_CMP_OP
|
File diff suppressed because one or more lines are too long
@ -586,10 +586,10 @@ __NEXT_STEP:
|
||||
case OP_BUILD_SLICE: {
|
||||
// [start, stop, step]
|
||||
py_TValue tmp;
|
||||
py_newslice(&tmp);
|
||||
py_setslot(&tmp, 0, THIRD());
|
||||
py_setslot(&tmp, 1, SECOND());
|
||||
py_setslot(&tmp, 2, TOP());
|
||||
py_ObjectRef slots = py_newslice(&tmp);
|
||||
slots[0] = *THIRD();
|
||||
slots[1] = *SECOND();
|
||||
slots[2] = *TOP();
|
||||
STACK_SHRINK(3);
|
||||
PUSH(&tmp);
|
||||
DISPATCH();
|
||||
@ -1298,57 +1298,6 @@ bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop) {
|
||||
rhs_t);
|
||||
}
|
||||
|
||||
bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) {
|
||||
VM* self = pk_current_vm;
|
||||
PUSH(lhs);
|
||||
PUSH(rhs);
|
||||
bool ok = pk_stack_binaryop(self, op, rop);
|
||||
STACK_SHRINK(2);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool py_binaryadd(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __add__, __radd__); }
|
||||
|
||||
bool py_binarysub(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __sub__, __rsub__); }
|
||||
|
||||
bool py_binarymul(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __mul__, __rmul__); }
|
||||
|
||||
bool py_binarytruediv(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __truediv__, __rtruediv__);
|
||||
}
|
||||
|
||||
bool py_binaryfloordiv(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __floordiv__, __rfloordiv__);
|
||||
}
|
||||
|
||||
bool py_binarymod(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __mod__, __rmod__); }
|
||||
|
||||
bool py_binarypow(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __pow__, __rpow__); }
|
||||
|
||||
bool py_binarylshift(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __lshift__, 0); }
|
||||
|
||||
bool py_binaryrshift(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __rshift__, 0); }
|
||||
|
||||
bool py_binaryand(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __and__, 0); }
|
||||
|
||||
bool py_binaryor(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __or__, 0); }
|
||||
|
||||
bool py_binaryxor(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __xor__, 0); }
|
||||
|
||||
bool py_binarymatmul(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __matmul__, 0); }
|
||||
|
||||
bool py_eq(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __eq__, __eq__); }
|
||||
|
||||
bool py_ne(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __ne__, __ne__); }
|
||||
|
||||
bool py_lt(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __lt__, __gt__); }
|
||||
|
||||
bool py_le(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __le__, __ge__); }
|
||||
|
||||
bool py_gt(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __gt__, __lt__); }
|
||||
|
||||
bool py_ge(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __ge__, __le__); }
|
||||
|
||||
static bool stack_format_object(VM* self, c11_sv spec) {
|
||||
// format TOS via `spec` inplace
|
||||
// spec: '!r:.2f', '.2f'
|
||||
@ -1514,14 +1463,3 @@ static bool stack_format_object(VM* self, c11_sv spec) {
|
||||
#undef INSERT_THIRD
|
||||
#undef vectorcall_opcall
|
||||
#undef RESET_CO_CACHE
|
||||
|
||||
void py_sys_settrace(py_TraceFunc func, bool reset) {
|
||||
TraceInfo* info = &pk_current_vm->trace_info;
|
||||
info->func = func;
|
||||
if(!reset) return;
|
||||
if(info->prev_loc.src) {
|
||||
PK_DECREF(info->prev_loc.src);
|
||||
info->prev_loc.src = NULL;
|
||||
}
|
||||
info->prev_loc.lineno = -1;
|
||||
}
|
@ -162,44 +162,3 @@ SourceLocation Frame__source_location(py_Frame* self) {
|
||||
loc.src = self->co->src;
|
||||
return loc;
|
||||
}
|
||||
|
||||
const char* py_Frame_sourceloc(py_Frame* self, int* lineno) {
|
||||
SourceLocation loc = Frame__source_location(self);
|
||||
*lineno = loc.lineno;
|
||||
return loc.src->filename->data;
|
||||
}
|
||||
|
||||
void py_Frame_newglobals(py_Frame* frame, py_OutRef out) {
|
||||
if(!frame) {
|
||||
pk_mappingproxy__namedict(out, pk_current_vm->main);
|
||||
return;
|
||||
}
|
||||
if(frame->globals->type == tp_module) {
|
||||
pk_mappingproxy__namedict(out, frame->globals);
|
||||
} else {
|
||||
*out = *frame->globals; // dict
|
||||
}
|
||||
}
|
||||
|
||||
void py_Frame_newlocals(py_Frame* frame, py_OutRef out) {
|
||||
if(!frame) {
|
||||
py_newdict(out);
|
||||
return;
|
||||
}
|
||||
if(frame->is_locals_special) {
|
||||
switch(frame->locals->type) {
|
||||
case tp_locals: frame = frame->locals->_ptr; break;
|
||||
case tp_dict: *out = *frame->locals; return;
|
||||
case tp_nil: py_newdict(out); return;
|
||||
default: c11__unreachable();
|
||||
}
|
||||
}
|
||||
FastLocals__to_dict(frame->locals, frame->co);
|
||||
py_assign(out, py_retval());
|
||||
}
|
||||
|
||||
py_StackRef py_Frame_function(py_Frame* self) {
|
||||
if(self->is_locals_special) return NULL;
|
||||
assert(self->p0->type == tp_function);
|
||||
return self->p0;
|
||||
}
|
@ -11,45 +11,11 @@ py_ItemRef pk_tpfindname(py_TypeInfo* ti, py_Name name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PK_INLINE py_ItemRef py_tpfindname(py_Type type, py_Name name) {
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
return pk_tpfindname(ti, name);
|
||||
}
|
||||
|
||||
PK_INLINE py_Ref py_tpfindmagic(py_Type t, py_Name name) {
|
||||
// assert(py_ismagicname(name));
|
||||
return py_tpfindname(t, name);
|
||||
}
|
||||
|
||||
PK_INLINE py_Type py_tpbase(py_Type t) {
|
||||
assert(t);
|
||||
py_TypeInfo* ti = pk_typeinfo(t);
|
||||
return ti->base;
|
||||
}
|
||||
|
||||
PK_DEPRECATED py_Ref py_tpgetmagic(py_Type type, py_Name name) {
|
||||
// assert(py_ismagicname(name));
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
py_Ref retval = py_getdict(&ti->self, name);
|
||||
return retval != NULL ? retval : py_NIL();
|
||||
}
|
||||
|
||||
py_Ref py_tpobject(py_Type type) {
|
||||
assert(type);
|
||||
return &pk_typeinfo(type)->self;
|
||||
}
|
||||
|
||||
const char* py_tpname(py_Type type) {
|
||||
if(!type) return "nil";
|
||||
py_Name name = pk_typeinfo(type)->name;
|
||||
return py_name2str(name);
|
||||
}
|
||||
|
||||
PK_INLINE py_TypeInfo* pk_typeinfo(py_Type type) {
|
||||
#ifndef NDEBUG
|
||||
int length = pk_current_vm->types.length;
|
||||
if(type < 0 || type >= length) {
|
||||
c11__abort("type index %d is out of bounds [0, %d)", type, length);
|
||||
if(type <= 0 || type >= length) {
|
||||
c11__abort("type index %d is out of bounds (0, %d)", type, length);
|
||||
}
|
||||
#endif
|
||||
return c11__getitem(TypePointer, &pk_current_vm->types, type).ti;
|
||||
@ -150,28 +116,3 @@ py_Type pk_newtypewithmode(py_Name name,
|
||||
return pk_newtype(py_name2str(name), base, module, dtor, is_python, is_final);
|
||||
}
|
||||
|
||||
py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, void (*dtor)(void*)) {
|
||||
if(strlen(name) == 0) c11__abort("type name cannot be empty");
|
||||
py_Type type = pk_newtype(name, base, module, dtor, false, false);
|
||||
if(module) py_setdict(module, py_name(name), py_tpobject(type));
|
||||
return type;
|
||||
}
|
||||
|
||||
void py_tpsetfinal(py_Type type) {
|
||||
assert(type);
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
ti->is_final = true;
|
||||
}
|
||||
|
||||
void py_tphookattributes(py_Type type,
|
||||
bool (*getattribute)(py_Ref self, py_Name name),
|
||||
bool (*setattribute)(py_Ref self, py_Name name, py_Ref val),
|
||||
bool (*delattribute)(py_Ref self, py_Name name),
|
||||
bool (*getunboundmethod)(py_Ref self, py_Name name)) {
|
||||
assert(type);
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
ti->getattribute = getattribute;
|
||||
ti->setattribute = setattribute;
|
||||
ti->delattribute = delattribute;
|
||||
ti->getunboundmethod = getunboundmethod;
|
||||
}
|
||||
|
@ -8,198 +8,8 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/common/_generated.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
py_Ref py_getmodule(const char* path) {
|
||||
VM* vm = pk_current_vm;
|
||||
return BinTree__try_get(&vm->modules, (void*)path);
|
||||
}
|
||||
|
||||
py_Ref py_getbuiltin(py_Name name) { return py_getdict(pk_current_vm->builtins, name); }
|
||||
|
||||
py_Ref py_getglobal(py_Name name) { return py_getdict(pk_current_vm->main, name); }
|
||||
|
||||
void py_setglobal(py_Name name, py_Ref val) { py_setdict(pk_current_vm->main, name, val); }
|
||||
|
||||
static void py_ModuleInfo__dtor(py_ModuleInfo* mi) {
|
||||
c11_string__delete(mi->name);
|
||||
c11_string__delete(mi->package);
|
||||
c11_string__delete(mi->path);
|
||||
}
|
||||
|
||||
py_Type pk_module__register() {
|
||||
py_Type type = pk_newtype("module", tp_object, NULL, (py_Dtor)py_ModuleInfo__dtor, false, true);
|
||||
return type;
|
||||
}
|
||||
|
||||
py_Ref py_newmodule(const char* path) {
|
||||
int path_len = strlen(path);
|
||||
if(path_len > PK_MAX_MODULE_PATH_LEN) c11__abort("module path too long: %s", path);
|
||||
if(path_len == 0) c11__abort("module path cannot be empty");
|
||||
|
||||
py_ModuleInfo* mi = py_newobject(py_retval(), tp_module, -1, sizeof(py_ModuleInfo));
|
||||
|
||||
int last_dot = c11_sv__rindex((c11_sv){path, path_len}, '.');
|
||||
if(last_dot == -1) {
|
||||
mi->name = c11_string__new(path);
|
||||
mi->package = c11_string__new("");
|
||||
} else {
|
||||
const char* start = path + last_dot + 1;
|
||||
mi->name = c11_string__new(start);
|
||||
mi->package = c11_string__new2(path, last_dot);
|
||||
}
|
||||
|
||||
mi->path = c11_string__new(path);
|
||||
path = mi->path->data;
|
||||
|
||||
// we do not allow override in order to avoid memory leak
|
||||
// it is because Module objects are not garbage collected
|
||||
bool exists = BinTree__contains(&pk_current_vm->modules, (void*)path);
|
||||
if(exists) c11__abort("module '%s' already exists", path);
|
||||
|
||||
BinTree__set(&pk_current_vm->modules, (void*)path, py_retval());
|
||||
py_GlobalRef retval = py_getmodule(path);
|
||||
mi->self = retval;
|
||||
|
||||
// setup __name__
|
||||
py_newstrv(py_emplacedict(retval, __name__), c11_string__sv(mi->name));
|
||||
// setup __package__
|
||||
py_newstrv(py_emplacedict(retval, __package__), c11_string__sv(mi->package));
|
||||
// setup __path__
|
||||
py_newstrv(py_emplacedict(retval, __path__), c11_string__sv(mi->path));
|
||||
return retval;
|
||||
}
|
||||
|
||||
int load_module_from_dll_desktop_only(const char* path) PY_RAISE PY_RETURN;
|
||||
|
||||
int py_import(const char* path_cstr) {
|
||||
VM* vm = pk_current_vm;
|
||||
c11_sv path = {path_cstr, strlen(path_cstr)};
|
||||
if(path.size == 0) return ValueError("empty module name");
|
||||
|
||||
if(path.data[0] == '.') {
|
||||
// try relative import
|
||||
int dot_count = 1;
|
||||
while(dot_count < path.size && path.data[dot_count] == '.')
|
||||
dot_count++;
|
||||
|
||||
c11_sv top_filename = c11_string__sv(vm->top_frame->co->src->filename);
|
||||
int is_init = c11_sv__endswith(top_filename, (c11_sv){"__init__.py", 11});
|
||||
|
||||
py_ModuleInfo* mi = py_touserdata(vm->top_frame->module);
|
||||
c11_sv package_sv = c11_string__sv(mi->path);
|
||||
if(package_sv.size == 0) {
|
||||
return ImportError("attempted relative import with no known parent package");
|
||||
}
|
||||
|
||||
c11_vector /* T=c11_sv */ cpnts = c11_sv__split(package_sv, '.');
|
||||
for(int i = is_init; i < dot_count; i++) {
|
||||
if(cpnts.length == 0)
|
||||
return ImportError("attempted relative import beyond top-level package");
|
||||
c11_vector__pop(&cpnts);
|
||||
}
|
||||
|
||||
if(dot_count < path.size) {
|
||||
c11_sv last_cpnt = c11_sv__slice(path, dot_count);
|
||||
c11_vector__push(c11_sv, &cpnts, last_cpnt);
|
||||
}
|
||||
|
||||
// join cpnts
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
for(int i = 0; i < cpnts.length; i++) {
|
||||
if(i > 0) c11_sbuf__write_char(&buf, '.');
|
||||
c11_sbuf__write_sv(&buf, c11__getitem(c11_sv, &cpnts, i));
|
||||
}
|
||||
|
||||
c11_vector__dtor(&cpnts);
|
||||
c11_string* new_path = c11_sbuf__submit(&buf);
|
||||
int res = py_import(new_path->data);
|
||||
c11_string__delete(new_path);
|
||||
return res;
|
||||
}
|
||||
|
||||
assert(path.data[0] != '.' && path.data[path.size - 1] != '.');
|
||||
|
||||
// check existing module
|
||||
py_GlobalRef ext_mod = py_getmodule(path.data);
|
||||
if(ext_mod) {
|
||||
py_assign(py_retval(), ext_mod);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(vm->callbacks.lazyimport) {
|
||||
py_GlobalRef lazymod = vm->callbacks.lazyimport(path_cstr);
|
||||
if(lazymod) {
|
||||
c11__rtassert(py_istype(lazymod, tp_module));
|
||||
py_assign(py_retval(), lazymod);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// try import
|
||||
c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP);
|
||||
c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
|
||||
|
||||
bool need_free = true;
|
||||
const char* data = load_kPythonLib(path_cstr);
|
||||
if(data != NULL) {
|
||||
need_free = false;
|
||||
goto __SUCCESS;
|
||||
}
|
||||
|
||||
data = vm->callbacks.importfile(filename->data);
|
||||
if(data != NULL) goto __SUCCESS;
|
||||
|
||||
c11_string__delete(filename);
|
||||
filename = c11_string__new3("%s%c__init__.py", slashed_path->data, PK_PLATFORM_SEP);
|
||||
data = vm->callbacks.importfile(filename->data);
|
||||
if(data != NULL) goto __SUCCESS;
|
||||
|
||||
c11_string__delete(filename);
|
||||
c11_string__delete(slashed_path);
|
||||
// not found
|
||||
return load_module_from_dll_desktop_only(path_cstr);
|
||||
|
||||
__SUCCESS:
|
||||
do {
|
||||
} while(0);
|
||||
py_GlobalRef mod = py_newmodule(path_cstr);
|
||||
bool ok = py_exec((const char*)data, filename->data, EXEC_MODE, mod);
|
||||
py_assign(py_retval(), mod);
|
||||
|
||||
c11_string__delete(filename);
|
||||
c11_string__delete(slashed_path);
|
||||
if(need_free) PK_FREE((void*)data);
|
||||
return ok ? 1 : -1;
|
||||
}
|
||||
|
||||
bool py_importlib_reload(py_Ref module) {
|
||||
VM* vm = pk_current_vm;
|
||||
py_ModuleInfo* mi = py_touserdata(module);
|
||||
// We should ensure that the module is its original py_GlobalRef
|
||||
module = mi->self;
|
||||
c11_sv path = c11_string__sv(mi->path);
|
||||
c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP);
|
||||
c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
|
||||
char* data = vm->callbacks.importfile(filename->data);
|
||||
if(data == NULL) {
|
||||
c11_string__delete(filename);
|
||||
filename = c11_string__new3("%s%c__init__.py", slashed_path->data, PK_PLATFORM_SEP);
|
||||
data = vm->callbacks.importfile(filename->data);
|
||||
}
|
||||
c11_string__delete(slashed_path);
|
||||
if(data == NULL) return ImportError("module '%v' not found", path);
|
||||
// py_cleardict(module); BUG: removing old classes will cause RELOAD_MODE to fail
|
||||
bool ok = py_exec(data, filename->data, RELOAD_MODE, module);
|
||||
c11_string__delete(filename);
|
||||
PK_FREE(data);
|
||||
py_assign(py_retval(), module);
|
||||
return ok;
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
|
||||
static bool builtins_exit(int argc, py_Ref argv) {
|
||||
int code = 0;
|
||||
@ -399,18 +209,6 @@ static bool builtins_issubclass(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool py_callable(py_Ref val) {
|
||||
switch(val->type) {
|
||||
case tp_nativefunc: return true;
|
||||
case tp_function: return true;
|
||||
case tp_type: return true;
|
||||
case tp_boundmethod: return true;
|
||||
case tp_staticmethod: return true;
|
||||
case tp_classmethod: return true;
|
||||
default: return py_tpfindmagic(val->type, __call__);
|
||||
}
|
||||
}
|
||||
|
||||
static bool builtins_callable(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
bool res = py_callable(py_arg(0));
|
||||
@ -519,16 +317,6 @@ static bool builtins_locals(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void py_newglobals(py_OutRef out) {
|
||||
py_Frame* frame = pk_current_vm->top_frame;
|
||||
py_Frame_newglobals(frame, out);
|
||||
}
|
||||
|
||||
void py_newlocals(py_OutRef out) {
|
||||
py_Frame* frame = pk_current_vm->top_frame;
|
||||
py_Frame_newlocals(frame, out);
|
||||
}
|
||||
|
||||
static void pk_push_special_locals() {
|
||||
py_Frame* frame = pk_current_vm->top_frame;
|
||||
if(!frame) {
|
||||
@ -622,70 +410,6 @@ static bool builtins_eval(int argc, py_Ref argv) {
|
||||
return _builtins_execdyn("eval", argc, argv, EVAL_MODE);
|
||||
}
|
||||
|
||||
static bool
|
||||
pk_smartexec(const char* source, py_Ref module, enum py_CompileMode mode, va_list args) {
|
||||
if(module == NULL) module = pk_current_vm->main;
|
||||
pk_mappingproxy__namedict(py_pushtmp(), module); // globals
|
||||
py_newdict(py_pushtmp()); // locals
|
||||
bool ok = py_compile(source, "<string>", mode, true);
|
||||
if(!ok) return false;
|
||||
py_push(py_retval());
|
||||
// [globals, locals, code]
|
||||
CodeObject* co = py_touserdata(py_peek(-1));
|
||||
py_StackRef locals = py_peek(-2);
|
||||
int max_index = -1;
|
||||
c11__foreach(Bytecode, &co->codes, bc) {
|
||||
if(bc->op == OP_LOAD_NAME) {
|
||||
c11_sv name = py_name2sv(c11__getitem(py_Name, &co->names, bc->arg));
|
||||
if(name.data[0] != '_') continue;
|
||||
int index;
|
||||
if(name.size == 1) {
|
||||
index = 0;
|
||||
} else if(name.size == 2 && isdigit(name.data[1])) {
|
||||
index = name.data[1] - '0';
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
max_index = c11__max(max_index, index);
|
||||
}
|
||||
}
|
||||
|
||||
if(max_index == -1) return ValueError("no placeholder found in the source");
|
||||
|
||||
for(int i = 0; i <= max_index; i++) {
|
||||
py_Ref val = va_arg(args, py_Ref);
|
||||
char buf[3];
|
||||
buf[0] = '_';
|
||||
buf[1] = '0' + i;
|
||||
buf[2] = '\0';
|
||||
py_dict_setitem_by_str(locals, buf, val);
|
||||
if(i == 0) {
|
||||
// _ => _0
|
||||
py_dict_setitem_by_str(locals, "_", val);
|
||||
}
|
||||
}
|
||||
ok = pk_execdyn(co, module, py_peek(-3), locals);
|
||||
if(!ok) return false;
|
||||
py_shrink(3);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool py_smartexec(const char* source, py_Ref module, ...) {
|
||||
va_list args;
|
||||
va_start(args, module);
|
||||
bool ok = pk_smartexec(source, module, EXEC_MODE, args);
|
||||
va_end(args);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool py_smarteval(const char* source, py_Ref module, ...) {
|
||||
va_list args;
|
||||
va_start(args, module);
|
||||
bool ok = pk_smartexec(source, module, EVAL_MODE, args);
|
||||
va_end(args);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool builtins_compile(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(3);
|
||||
for(int i = 0; i < 3; i++) {
|
@ -40,8 +40,3 @@ void pk__add_module_gc() {
|
||||
py_bindfunc(mod, "disable", gc_disable);
|
||||
py_bindfunc(mod, "isenabled", gc_isenabled);
|
||||
}
|
||||
|
||||
int py_gc_collect() {
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
return ManagedHeap__collect(heap);
|
||||
}
|
@ -189,9 +189,3 @@ bool py_json_loads(const char* source) {
|
||||
return py_exec(source, "<json>", EVAL_MODE, mod);
|
||||
}
|
||||
|
||||
bool py_pusheval(const char* expr, py_GlobalRef module) {
|
||||
bool ok = py_exec(expr, "<string>", EVAL_MODE, module);
|
||||
if(!ok) return false;
|
||||
py_push(py_retval());
|
||||
return true;
|
||||
}
|
||||
|
61
src/public/Bindings.c
Normal file
61
src/public/Bindings.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
void py_bind(py_Ref obj, const char* sig, py_CFunction f) {
|
||||
py_Ref tmp = py_pushtmp();
|
||||
py_Name name = py_newfunction(tmp, sig, f, NULL, 0);
|
||||
py_setdict(obj, name, tmp);
|
||||
py_pop();
|
||||
}
|
||||
|
||||
void py_bindmethod(py_Type type, const char* name, py_CFunction f) {
|
||||
py_TValue tmp;
|
||||
py_newnativefunc(&tmp, f);
|
||||
py_setdict(py_tpobject(type), py_name(name), &tmp);
|
||||
}
|
||||
|
||||
void py_bindstaticmethod(py_Type type, const char* name, py_CFunction f) {
|
||||
py_TValue tmp;
|
||||
py_newnativefunc(&tmp, f);
|
||||
bool ok = py_tpcall(tp_staticmethod, 1, &tmp);
|
||||
if(!ok) {
|
||||
py_printexc();
|
||||
c11__abort("py_bindstaticmethod(): failed to create staticmethod");
|
||||
}
|
||||
py_setdict(py_tpobject(type), py_name(name), py_retval());
|
||||
}
|
||||
|
||||
void py_bindfunc(py_Ref obj, const char* name, py_CFunction f) {
|
||||
py_TValue tmp;
|
||||
py_newnativefunc(&tmp, f);
|
||||
py_setdict(obj, py_name(name), &tmp);
|
||||
}
|
||||
|
||||
void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter) {
|
||||
py_TValue tmp;
|
||||
py_newobject(&tmp, tp_property, 2, 0);
|
||||
py_newnativefunc(py_getslot(&tmp, 0), getter);
|
||||
if(setter) {
|
||||
py_newnativefunc(py_getslot(&tmp, 1), setter);
|
||||
} else {
|
||||
py_setslot(&tmp, 1, py_None());
|
||||
}
|
||||
py_setdict(py_tpobject(type), py_name(name), &tmp);
|
||||
}
|
||||
|
||||
void py_bindmagic(py_Type type, py_Name name, py_CFunction f) {
|
||||
py_Ref tmp = py_emplacedict(py_tpobject(type), name);
|
||||
py_newnativefunc(tmp, f);
|
||||
}
|
||||
|
||||
void py_macrobind(const char* sig, py_CFunction f) {
|
||||
py_Ref tmp = py_pushtmp();
|
||||
py_Name name = py_newfunction(tmp, sig, f, NULL, 0);
|
||||
NameDict__set(&pk_current_vm->compile_time_funcs, name, tmp);
|
||||
py_pop();
|
||||
}
|
||||
|
||||
py_ItemRef py_macroget(py_Name name) {
|
||||
NameDict* d = &pk_current_vm->compile_time_funcs;
|
||||
if(d->length == 0) return NULL;
|
||||
return NameDict__try_get(d, name);
|
||||
}
|
@ -6,13 +6,14 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/compiler/compiler.h"
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
py_Type pk_code__register() {
|
||||
py_Type type = pk_newtype("code", tp_object, NULL, (py_Dtor)CodeObject__dtor, false, true);
|
||||
return type;
|
||||
}
|
||||
|
||||
bool _py_compile(CodeObject* out,
|
||||
static bool _py_compile(CodeObject* out,
|
||||
const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
@ -33,20 +34,6 @@ bool _py_compile(CodeObject* out,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool py_compile(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
bool is_dynamic) {
|
||||
CodeObject co;
|
||||
bool ok = _py_compile(&co, source, filename, mode, is_dynamic);
|
||||
if(ok) {
|
||||
// compile success
|
||||
CodeObject* ud = py_newobject(py_retval(), tp_code, 0, sizeof(CodeObject));
|
||||
*ud = co;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool pk_exec(CodeObject* co, py_Ref module) {
|
||||
VM* vm = pk_current_vm;
|
||||
if(!module) module = vm->main;
|
||||
@ -92,6 +79,68 @@ bool pk_execdyn(CodeObject* co, py_Ref module, py_Ref globals, py_Ref locals) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
pk_smartexec(const char* source, py_Ref module, enum py_CompileMode mode, va_list args) {
|
||||
if(module == NULL) module = pk_current_vm->main;
|
||||
pk_mappingproxy__namedict(py_pushtmp(), module); // globals
|
||||
py_newdict(py_pushtmp()); // locals
|
||||
bool ok = py_compile(source, "<string>", mode, true);
|
||||
if(!ok) return false;
|
||||
py_push(py_retval());
|
||||
// [globals, locals, code]
|
||||
CodeObject* co = py_touserdata(py_peek(-1));
|
||||
py_StackRef locals = py_peek(-2);
|
||||
int max_index = -1;
|
||||
c11__foreach(Bytecode, &co->codes, bc) {
|
||||
if(bc->op == OP_LOAD_NAME) {
|
||||
c11_sv name = py_name2sv(c11__getitem(py_Name, &co->names, bc->arg));
|
||||
if(name.data[0] != '_') continue;
|
||||
int index;
|
||||
if(name.size == 1) {
|
||||
index = 0;
|
||||
} else if(name.size == 2 && isdigit(name.data[1])) {
|
||||
index = name.data[1] - '0';
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
max_index = c11__max(max_index, index);
|
||||
}
|
||||
}
|
||||
|
||||
if(max_index == -1) return ValueError("no placeholder found in the source");
|
||||
|
||||
for(int i = 0; i <= max_index; i++) {
|
||||
py_Ref val = va_arg(args, py_Ref);
|
||||
char buf[3];
|
||||
buf[0] = '_';
|
||||
buf[1] = '0' + i;
|
||||
buf[2] = '\0';
|
||||
py_dict_setitem_by_str(locals, buf, val);
|
||||
if(i == 0) {
|
||||
// _ => _0
|
||||
py_dict_setitem_by_str(locals, "_", val);
|
||||
}
|
||||
}
|
||||
ok = pk_execdyn(co, module, py_peek(-3), locals);
|
||||
if(!ok) return false;
|
||||
py_shrink(3);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool py_compile(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
bool is_dynamic) {
|
||||
CodeObject co;
|
||||
bool ok = _py_compile(&co, source, filename, mode, is_dynamic);
|
||||
if(ok) {
|
||||
// compile success
|
||||
CodeObject* ud = py_newobject(py_retval(), tp_code, 0, sizeof(CodeObject));
|
||||
*ud = co;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) {
|
||||
CodeObject co;
|
||||
if(!_py_compile(&co, source, filename, mode, false)) return false;
|
||||
@ -102,4 +151,20 @@ bool py_exec(const char* source, const char* filename, enum py_CompileMode mode,
|
||||
|
||||
bool py_eval(const char* source, py_Ref module) {
|
||||
return py_exec(source, "<string>", EVAL_MODE, module);
|
||||
}
|
||||
}
|
||||
|
||||
bool py_smartexec(const char* source, py_Ref module, ...) {
|
||||
va_list args;
|
||||
va_start(args, module);
|
||||
bool ok = pk_smartexec(source, module, EXEC_MODE, args);
|
||||
va_end(args);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool py_smarteval(const char* source, py_Ref module, ...) {
|
||||
va_list args;
|
||||
va_start(args, module);
|
||||
bool ok = pk_smartexec(source, module, EVAL_MODE, args);
|
||||
va_end(args);
|
||||
return ok;
|
||||
}
|
@ -1,13 +1,11 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
py_Ref py_getreg(int i) { return pk_current_vm->reg + i; }
|
||||
|
||||
void py_setreg(int i, py_Ref val) { pk_current_vm->reg[i] = *val; }
|
||||
|
||||
PK_INLINE py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
||||
|
||||
PK_INLINE py_Ref py_getdict(py_Ref self, py_Name name) {
|
||||
assert(self && self->is_ptr);
|
||||
return NameDict__try_get(PyObject__dict(self->_obj), name);
|
||||
@ -18,6 +16,11 @@ PK_INLINE void py_setdict(py_Ref self, py_Name name, py_Ref val) {
|
||||
NameDict__set(PyObject__dict(self->_obj), name, val);
|
||||
}
|
||||
|
||||
bool py_deldict(py_Ref self, py_Name name) {
|
||||
assert(self && self->is_ptr);
|
||||
return NameDict__del(PyObject__dict(self->_obj), name);
|
||||
}
|
||||
|
||||
py_ItemRef py_emplacedict(py_Ref self, py_Name name) {
|
||||
py_setdict(self, name, py_NIL());
|
||||
return py_getdict(self, name);
|
||||
@ -41,11 +44,6 @@ void py_cleardict(py_Ref self) {
|
||||
NameDict__clear(dict);
|
||||
}
|
||||
|
||||
bool py_deldict(py_Ref self, py_Name name) {
|
||||
assert(self && self->is_ptr);
|
||||
return NameDict__del(PyObject__dict(self->_obj), name);
|
||||
}
|
||||
|
||||
py_Ref py_getslot(py_Ref self, int i) {
|
||||
assert(self && self->is_ptr);
|
||||
assert(i >= 0 && i < self->_obj->slots);
|
||||
@ -58,59 +56,8 @@ void py_setslot(py_Ref self, int i, py_Ref val) {
|
||||
PyObject__slots(self->_obj)[i] = *val;
|
||||
}
|
||||
|
||||
py_StackRef py_inspect_currentfunction() {
|
||||
VM* vm = pk_current_vm;
|
||||
if(vm->curr_decl_based_function) return vm->curr_decl_based_function;
|
||||
py_Frame* frame = vm->top_frame;
|
||||
if(!frame || frame->is_locals_special) return NULL;
|
||||
return frame->p0;
|
||||
}
|
||||
py_Ref py_getbuiltin(py_Name name) { return py_getdict(pk_current_vm->builtins, name); }
|
||||
|
||||
py_GlobalRef py_inspect_currentmodule() {
|
||||
py_Frame* frame = pk_current_vm->top_frame;
|
||||
if(!frame) return NULL;
|
||||
return frame->module;
|
||||
}
|
||||
py_Ref py_getglobal(py_Name name) { return py_getdict(pk_current_vm->main, name); }
|
||||
|
||||
py_Frame* py_inspect_currentframe() { return pk_current_vm->top_frame; }
|
||||
|
||||
/* Stack References */
|
||||
py_Ref py_peek(int i) {
|
||||
assert(i <= 0);
|
||||
return pk_current_vm->stack.sp + i;
|
||||
}
|
||||
|
||||
void py_pop() {
|
||||
VM* vm = pk_current_vm;
|
||||
vm->stack.sp--;
|
||||
}
|
||||
|
||||
void py_shrink(int n) {
|
||||
VM* vm = pk_current_vm;
|
||||
vm->stack.sp -= n;
|
||||
}
|
||||
|
||||
void py_push(py_Ref src) {
|
||||
VM* vm = pk_current_vm;
|
||||
*vm->stack.sp++ = *src;
|
||||
}
|
||||
|
||||
void py_pushnil() {
|
||||
VM* vm = pk_current_vm;
|
||||
py_newnil(vm->stack.sp++);
|
||||
}
|
||||
|
||||
void py_pushnone() {
|
||||
VM* vm = pk_current_vm;
|
||||
py_newnone(vm->stack.sp++);
|
||||
}
|
||||
|
||||
void py_pushname(py_Name name) {
|
||||
VM* vm = pk_current_vm;
|
||||
py_newint(vm->stack.sp++, (uintptr_t)name);
|
||||
}
|
||||
|
||||
py_Ref py_pushtmp() {
|
||||
VM* vm = pk_current_vm;
|
||||
return vm->stack.sp++;
|
||||
}
|
||||
void py_setglobal(py_Name name, py_Ref val) { py_setdict(pk_current_vm->main, name, val); }
|
43
src/public/FrameOps.c
Normal file
43
src/public/FrameOps.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
const char* py_Frame_sourceloc(py_Frame* self, int* lineno) {
|
||||
SourceLocation loc = Frame__source_location(self);
|
||||
*lineno = loc.lineno;
|
||||
return loc.src->filename->data;
|
||||
}
|
||||
|
||||
void py_Frame_newglobals(py_Frame* frame, py_OutRef out) {
|
||||
if(!frame) {
|
||||
pk_mappingproxy__namedict(out, pk_current_vm->main);
|
||||
return;
|
||||
}
|
||||
if(frame->globals->type == tp_module) {
|
||||
pk_mappingproxy__namedict(out, frame->globals);
|
||||
} else {
|
||||
*out = *frame->globals; // dict
|
||||
}
|
||||
}
|
||||
|
||||
void py_Frame_newlocals(py_Frame* frame, py_OutRef out) {
|
||||
if(!frame) {
|
||||
py_newdict(out);
|
||||
return;
|
||||
}
|
||||
if(frame->is_locals_special) {
|
||||
switch(frame->locals->type) {
|
||||
case tp_locals: frame = frame->locals->_ptr; break;
|
||||
case tp_dict: *out = *frame->locals; return;
|
||||
case tp_nil: py_newdict(out); return;
|
||||
default: c11__unreachable();
|
||||
}
|
||||
}
|
||||
FastLocals__to_dict(frame->locals, frame->co);
|
||||
py_assign(out, py_retval());
|
||||
}
|
||||
|
||||
py_StackRef py_Frame_function(py_Frame* self) {
|
||||
if(self->is_locals_special) return NULL;
|
||||
assert(self->p0->type == tp_function);
|
||||
return self->p0;
|
||||
}
|
161
src/public/GlobalSetup.c
Normal file
161
src/public/GlobalSetup.c
Normal file
@ -0,0 +1,161 @@
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/common/name.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
_Thread_local VM* pk_current_vm;
|
||||
|
||||
static bool pk_initialized;
|
||||
static bool pk_finalized;
|
||||
|
||||
static VM pk_default_vm;
|
||||
static VM* pk_all_vm[16];
|
||||
static py_TValue _True, _False, _None, _NIL;
|
||||
|
||||
void py_initialize() {
|
||||
c11__rtassert(!pk_finalized);
|
||||
|
||||
if(pk_initialized) {
|
||||
// c11__abort("py_initialize() can only be called once!");
|
||||
return;
|
||||
}
|
||||
|
||||
pk_names_initialize();
|
||||
|
||||
// check endianness
|
||||
int x = 1;
|
||||
bool is_little_endian = *(char*)&x == 1;
|
||||
if(!is_little_endian) c11__abort("is_little_endian != true");
|
||||
|
||||
static_assert(sizeof(py_TValue) == 24, "sizeof(py_TValue) != 24");
|
||||
static_assert(offsetof(py_TValue, extra) == 4, "offsetof(py_TValue, extra) != 4");
|
||||
|
||||
pk_current_vm = pk_all_vm[0] = &pk_default_vm;
|
||||
|
||||
// initialize some convenient references
|
||||
py_newbool(&_True, true);
|
||||
py_newbool(&_False, false);
|
||||
py_newnone(&_None);
|
||||
py_newnil(&_NIL);
|
||||
VM__ctor(&pk_default_vm);
|
||||
|
||||
pk_initialized = true;
|
||||
}
|
||||
|
||||
void py_finalize() {
|
||||
if(pk_finalized) c11__abort("py_finalize() can only be called once!");
|
||||
pk_finalized = true;
|
||||
|
||||
for(int i = 1; i < 16; i++) {
|
||||
VM* vm = pk_all_vm[i];
|
||||
if(vm) {
|
||||
// temp fix https://github.com/pocketpy/pocketpy/issues/315
|
||||
// TODO: refactor VM__ctor and VM__dtor
|
||||
pk_current_vm = vm;
|
||||
VM__dtor(vm);
|
||||
PK_FREE(vm);
|
||||
}
|
||||
}
|
||||
pk_current_vm = &pk_default_vm;
|
||||
VM__dtor(&pk_default_vm);
|
||||
pk_current_vm = NULL;
|
||||
|
||||
pk_names_finalize();
|
||||
}
|
||||
|
||||
int py_currentvm() {
|
||||
for(int i = 0; i < 16; i++) {
|
||||
if(pk_all_vm[i] == pk_current_vm) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void py_switchvm(int index) {
|
||||
if(index < 0 || index >= 16) c11__abort("invalid vm index");
|
||||
if(!pk_all_vm[index]) {
|
||||
pk_current_vm = pk_all_vm[index] = PK_MALLOC(sizeof(VM));
|
||||
memset(pk_current_vm, 0, sizeof(VM));
|
||||
VM__ctor(pk_all_vm[index]);
|
||||
} else {
|
||||
pk_current_vm = pk_all_vm[index];
|
||||
}
|
||||
}
|
||||
|
||||
void py_resetvm() {
|
||||
VM* vm = pk_current_vm;
|
||||
VM__dtor(vm);
|
||||
memset(vm, 0, sizeof(VM));
|
||||
VM__ctor(vm);
|
||||
}
|
||||
|
||||
void py_resetallvm() {
|
||||
for(int i = 0; i < 16; i++) {
|
||||
py_switchvm(i);
|
||||
py_resetvm();
|
||||
}
|
||||
py_switchvm(0);
|
||||
}
|
||||
|
||||
void* py_getvmctx() { return pk_current_vm->ctx; }
|
||||
|
||||
void py_setvmctx(void* ctx) { pk_current_vm->ctx = ctx; }
|
||||
|
||||
py_Callbacks* py_callbacks() { return &pk_current_vm->callbacks; }
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
void py_sys_setargv(int argc, char** argv) {
|
||||
py_GlobalRef sys = py_getmodule("sys");
|
||||
py_Ref argv_list = py_getdict(sys, py_name("argv"));
|
||||
py_list_clear(argv_list);
|
||||
for(int i = 0; i < argc; i++) {
|
||||
py_newstr(py_list_emplace(argv_list), argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void py_sys_settrace(py_TraceFunc func, bool reset) {
|
||||
TraceInfo* info = &pk_current_vm->trace_info;
|
||||
info->func = func;
|
||||
if(!reset) return;
|
||||
if(info->prev_loc.src) {
|
||||
PK_DECREF(info->prev_loc.src);
|
||||
info->prev_loc.src = NULL;
|
||||
}
|
||||
info->prev_loc.lineno = -1;
|
||||
}
|
||||
|
||||
int py_gc_collect() {
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
return ManagedHeap__collect(heap);
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
void* py_malloc(size_t size) { return PK_MALLOC(size); }
|
||||
|
||||
void* py_realloc(void* ptr, size_t size) { return PK_REALLOC(ptr, size); }
|
||||
|
||||
void py_free(void* ptr) { PK_FREE(ptr); }
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
py_GlobalRef py_True() { return &_True; }
|
||||
|
||||
py_GlobalRef py_False() { return &_False; }
|
||||
|
||||
py_GlobalRef py_None() { return &_None; }
|
||||
|
||||
py_GlobalRef py_NIL() { return &_NIL; }
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
const char* pk_opname(Opcode op) {
|
||||
const static char* OP_NAMES[] = {
|
||||
#define OPCODE(name) #name,
|
||||
#include "pocketpy/xmacros/opcodes.h"
|
||||
#undef OPCODE
|
||||
};
|
||||
return OP_NAMES[op];
|
||||
}
|
28
src/public/Inspection.c
Normal file
28
src/public/Inspection.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
py_StackRef py_inspect_currentfunction() {
|
||||
VM* vm = pk_current_vm;
|
||||
if(vm->curr_decl_based_function) return vm->curr_decl_based_function;
|
||||
py_Frame* frame = vm->top_frame;
|
||||
if(!frame || frame->is_locals_special) return NULL;
|
||||
return frame->p0;
|
||||
}
|
||||
|
||||
py_GlobalRef py_inspect_currentmodule() {
|
||||
py_Frame* frame = pk_current_vm->top_frame;
|
||||
if(!frame) return NULL;
|
||||
return frame->module;
|
||||
}
|
||||
|
||||
py_Frame* py_inspect_currentframe() { return pk_current_vm->top_frame; }
|
||||
|
||||
void py_newglobals(py_OutRef out) {
|
||||
py_Frame* frame = pk_current_vm->top_frame;
|
||||
py_Frame_newglobals(frame, out);
|
||||
}
|
||||
|
||||
void py_newlocals(py_OutRef out) {
|
||||
py_Frame* frame = pk_current_vm->top_frame;
|
||||
py_Frame_newlocals(frame, out);
|
||||
}
|
191
src/public/ModuleSystem.c
Normal file
191
src/public/ModuleSystem.c
Normal file
@ -0,0 +1,191 @@
|
||||
#include "pocketpy/common/str.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/common/_generated.h"
|
||||
|
||||
|
||||
py_Ref py_getmodule(const char* path) {
|
||||
VM* vm = pk_current_vm;
|
||||
return BinTree__try_get(&vm->modules, (void*)path);
|
||||
}
|
||||
|
||||
py_Ref py_newmodule(const char* path) {
|
||||
int path_len = strlen(path);
|
||||
if(path_len > PK_MAX_MODULE_PATH_LEN) c11__abort("module path too long: %s", path);
|
||||
if(path_len == 0) c11__abort("module path cannot be empty");
|
||||
|
||||
py_ModuleInfo* mi = py_newobject(py_retval(), tp_module, -1, sizeof(py_ModuleInfo));
|
||||
|
||||
int last_dot = c11_sv__rindex((c11_sv){path, path_len}, '.');
|
||||
if(last_dot == -1) {
|
||||
mi->name = c11_string__new(path);
|
||||
mi->package = c11_string__new("");
|
||||
} else {
|
||||
const char* start = path + last_dot + 1;
|
||||
mi->name = c11_string__new(start);
|
||||
mi->package = c11_string__new2(path, last_dot);
|
||||
}
|
||||
|
||||
mi->path = c11_string__new(path);
|
||||
path = mi->path->data;
|
||||
|
||||
// we do not allow override in order to avoid memory leak
|
||||
// it is because Module objects are not garbage collected
|
||||
bool exists = BinTree__contains(&pk_current_vm->modules, (void*)path);
|
||||
if(exists) c11__abort("module '%s' already exists", path);
|
||||
|
||||
BinTree__set(&pk_current_vm->modules, (void*)path, py_retval());
|
||||
py_GlobalRef retval = py_getmodule(path);
|
||||
mi->self = retval;
|
||||
|
||||
// setup __name__
|
||||
py_newstrv(py_emplacedict(retval, __name__), c11_string__sv(mi->name));
|
||||
// setup __package__
|
||||
py_newstrv(py_emplacedict(retval, __package__), c11_string__sv(mi->package));
|
||||
// setup __path__
|
||||
py_newstrv(py_emplacedict(retval, __path__), c11_string__sv(mi->path));
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void py_ModuleInfo__dtor(py_ModuleInfo* mi) {
|
||||
c11_string__delete(mi->name);
|
||||
c11_string__delete(mi->package);
|
||||
c11_string__delete(mi->path);
|
||||
}
|
||||
|
||||
py_Type pk_module__register() {
|
||||
py_Type type = pk_newtype("module", tp_object, NULL, (py_Dtor)py_ModuleInfo__dtor, false, true);
|
||||
return type;
|
||||
}
|
||||
|
||||
int load_module_from_dll_desktop_only(const char* path) PY_RAISE PY_RETURN;
|
||||
|
||||
int py_import(const char* path_cstr) {
|
||||
VM* vm = pk_current_vm;
|
||||
c11_sv path = {path_cstr, strlen(path_cstr)};
|
||||
if(path.size == 0) return ValueError("empty module name");
|
||||
|
||||
if(path.data[0] == '.') {
|
||||
// try relative import
|
||||
int dot_count = 1;
|
||||
while(dot_count < path.size && path.data[dot_count] == '.')
|
||||
dot_count++;
|
||||
|
||||
c11_sv top_filename = c11_string__sv(vm->top_frame->co->src->filename);
|
||||
int is_init = c11_sv__endswith(top_filename, (c11_sv){"__init__.py", 11});
|
||||
|
||||
py_ModuleInfo* mi = py_touserdata(vm->top_frame->module);
|
||||
c11_sv package_sv = c11_string__sv(mi->path);
|
||||
if(package_sv.size == 0) {
|
||||
return ImportError("attempted relative import with no known parent package");
|
||||
}
|
||||
|
||||
c11_vector /* T=c11_sv */ cpnts = c11_sv__split(package_sv, '.');
|
||||
for(int i = is_init; i < dot_count; i++) {
|
||||
if(cpnts.length == 0)
|
||||
return ImportError("attempted relative import beyond top-level package");
|
||||
c11_vector__pop(&cpnts);
|
||||
}
|
||||
|
||||
if(dot_count < path.size) {
|
||||
c11_sv last_cpnt = c11_sv__slice(path, dot_count);
|
||||
c11_vector__push(c11_sv, &cpnts, last_cpnt);
|
||||
}
|
||||
|
||||
// join cpnts
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
for(int i = 0; i < cpnts.length; i++) {
|
||||
if(i > 0) c11_sbuf__write_char(&buf, '.');
|
||||
c11_sbuf__write_sv(&buf, c11__getitem(c11_sv, &cpnts, i));
|
||||
}
|
||||
|
||||
c11_vector__dtor(&cpnts);
|
||||
c11_string* new_path = c11_sbuf__submit(&buf);
|
||||
int res = py_import(new_path->data);
|
||||
c11_string__delete(new_path);
|
||||
return res;
|
||||
}
|
||||
|
||||
assert(path.data[0] != '.' && path.data[path.size - 1] != '.');
|
||||
|
||||
// check existing module
|
||||
py_GlobalRef ext_mod = py_getmodule(path.data);
|
||||
if(ext_mod) {
|
||||
py_assign(py_retval(), ext_mod);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(vm->callbacks.lazyimport) {
|
||||
py_GlobalRef lazymod = vm->callbacks.lazyimport(path_cstr);
|
||||
if(lazymod) {
|
||||
c11__rtassert(py_istype(lazymod, tp_module));
|
||||
py_assign(py_retval(), lazymod);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// try import
|
||||
c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP);
|
||||
c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
|
||||
|
||||
bool need_free = true;
|
||||
const char* data = load_kPythonLib(path_cstr);
|
||||
if(data != NULL) {
|
||||
need_free = false;
|
||||
goto __SUCCESS;
|
||||
}
|
||||
|
||||
data = vm->callbacks.importfile(filename->data);
|
||||
if(data != NULL) goto __SUCCESS;
|
||||
|
||||
c11_string__delete(filename);
|
||||
filename = c11_string__new3("%s%c__init__.py", slashed_path->data, PK_PLATFORM_SEP);
|
||||
data = vm->callbacks.importfile(filename->data);
|
||||
if(data != NULL) goto __SUCCESS;
|
||||
|
||||
c11_string__delete(filename);
|
||||
c11_string__delete(slashed_path);
|
||||
// not found
|
||||
return load_module_from_dll_desktop_only(path_cstr);
|
||||
|
||||
__SUCCESS:
|
||||
do {
|
||||
} while(0);
|
||||
py_GlobalRef mod = py_newmodule(path_cstr);
|
||||
bool ok = py_exec((const char*)data, filename->data, EXEC_MODE, mod);
|
||||
py_assign(py_retval(), mod);
|
||||
|
||||
c11_string__delete(filename);
|
||||
c11_string__delete(slashed_path);
|
||||
if(need_free) PK_FREE((void*)data);
|
||||
return ok ? 1 : -1;
|
||||
}
|
||||
|
||||
bool py_importlib_reload(py_Ref module) {
|
||||
VM* vm = pk_current_vm;
|
||||
py_ModuleInfo* mi = py_touserdata(module);
|
||||
// We should ensure that the module is its original py_GlobalRef
|
||||
module = mi->self;
|
||||
c11_sv path = c11_string__sv(mi->path);
|
||||
c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP);
|
||||
c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
|
||||
char* data = vm->callbacks.importfile(filename->data);
|
||||
if(data == NULL) {
|
||||
c11_string__delete(filename);
|
||||
filename = c11_string__new3("%s%c__init__.py", slashed_path->data, PK_PLATFORM_SEP);
|
||||
data = vm->callbacks.importfile(filename->data);
|
||||
}
|
||||
c11_string__delete(slashed_path);
|
||||
if(data == NULL) return ImportError("module '%v' not found", path);
|
||||
// py_cleardict(module); BUG: removing old classes will cause RELOAD_MODE to fail
|
||||
bool ok = py_exec(data, filename->data, RELOAD_MODE, module);
|
||||
c11_string__delete(filename);
|
||||
PK_FREE(data);
|
||||
py_assign(py_retval(), module);
|
||||
return ok;
|
||||
}
|
@ -141,28 +141,6 @@ py_Type pk_StopIteration__register() {
|
||||
return type;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
bool py_checkexc() {
|
||||
VM* vm = pk_current_vm;
|
||||
return !py_isnil(&vm->unhandled_exc);
|
||||
}
|
||||
|
||||
bool py_matchexc(py_Type type) {
|
||||
VM* vm = pk_current_vm;
|
||||
if(py_isnil(&vm->unhandled_exc)) return false;
|
||||
bool ok = py_issubclass(vm->unhandled_exc.type, type);
|
||||
if(ok) vm->last_retval = vm->unhandled_exc;
|
||||
return ok;
|
||||
}
|
||||
|
||||
void py_clearexc(py_StackRef p0) {
|
||||
VM* vm = pk_current_vm;
|
||||
py_newnil(&vm->unhandled_exc);
|
||||
if(p0) {
|
||||
c11__rtassert(p0 >= vm->stack.begin && p0 <= vm->stack.sp);
|
||||
vm->stack.sp = p0;
|
||||
}
|
||||
}
|
||||
|
||||
static void c11_sbuf__write_exc(c11_sbuf* self, py_Ref exc) {
|
||||
c11_sbuf__write_cstr(self, "Traceback (most recent call last):\n");
|
||||
@ -212,6 +190,29 @@ char* safe_stringify_exception(py_Ref exc) {
|
||||
return c11_strdup(message);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
bool py_checkexc() {
|
||||
VM* vm = pk_current_vm;
|
||||
return !py_isnil(&vm->unhandled_exc);
|
||||
}
|
||||
|
||||
bool py_matchexc(py_Type type) {
|
||||
VM* vm = pk_current_vm;
|
||||
if(py_isnil(&vm->unhandled_exc)) return false;
|
||||
bool ok = py_issubclass(vm->unhandled_exc.type, type);
|
||||
if(ok) vm->last_retval = vm->unhandled_exc;
|
||||
return ok;
|
||||
}
|
||||
|
||||
void py_clearexc(py_StackRef p0) {
|
||||
VM* vm = pk_current_vm;
|
||||
py_newnil(&vm->unhandled_exc);
|
||||
if(p0) {
|
||||
c11__rtassert(p0 >= vm->stack.begin && p0 <= vm->stack.sp);
|
||||
vm->stack.sp = p0;
|
||||
}
|
||||
}
|
||||
|
||||
void py_printexc() {
|
||||
char* msg = py_formatexc();
|
||||
if(!msg) return;
|
||||
@ -299,4 +300,10 @@ bool KeyError(py_Ref key) {
|
||||
bool ok = py_tpcall(tp_KeyError, 1, key);
|
||||
if(!ok) return false;
|
||||
return py_raise(py_retval());
|
||||
}
|
||||
}
|
||||
|
||||
bool StopIteration() {
|
||||
bool ok = py_tpcall(tp_StopIteration, 0, NULL);
|
||||
if(!ok) return false;
|
||||
return py_raise(py_retval());
|
||||
}
|
@ -4,12 +4,20 @@
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
void py_newslice(py_OutRef out) {
|
||||
py_ObjectRef py_newslice(py_OutRef out) {
|
||||
VM* vm = pk_current_vm;
|
||||
PyObject* obj = ManagedHeap__gcnew(&vm->heap, tp_slice, 3, 0);
|
||||
out->type = tp_slice;
|
||||
out->is_ptr = true;
|
||||
out->_obj = obj;
|
||||
return PyObject__slots(obj);
|
||||
}
|
||||
|
||||
void py_newsliceint(py_OutRef out, py_i64 start, py_i64 stop, py_i64 step) {
|
||||
py_Ref slots = py_newslice(out);
|
||||
py_newint(&slots[0], start);
|
||||
py_newint(&slots[1], stop);
|
||||
py_newint(&slots[2], step);
|
||||
}
|
||||
|
||||
static bool slice__new__(int argc, py_Ref argv) {
|
@ -4,6 +4,48 @@
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
bool py_binaryadd(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __add__, __radd__); }
|
||||
|
||||
bool py_binarysub(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __sub__, __rsub__); }
|
||||
|
||||
bool py_binarymul(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __mul__, __rmul__); }
|
||||
|
||||
bool py_binarytruediv(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __truediv__, __rtruediv__);
|
||||
}
|
||||
|
||||
bool py_binaryfloordiv(py_Ref lhs, py_Ref rhs) {
|
||||
return py_binaryop(lhs, rhs, __floordiv__, __rfloordiv__);
|
||||
}
|
||||
|
||||
bool py_binarymod(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __mod__, __rmod__); }
|
||||
|
||||
bool py_binarypow(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __pow__, __rpow__); }
|
||||
|
||||
bool py_binarylshift(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __lshift__, 0); }
|
||||
|
||||
bool py_binaryrshift(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __rshift__, 0); }
|
||||
|
||||
bool py_binaryand(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __and__, 0); }
|
||||
|
||||
bool py_binaryor(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __or__, 0); }
|
||||
|
||||
bool py_binaryxor(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __xor__, 0); }
|
||||
|
||||
bool py_binarymatmul(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __matmul__, 0); }
|
||||
|
||||
bool py_eq(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __eq__, __eq__); }
|
||||
|
||||
bool py_ne(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __ne__, __ne__); }
|
||||
|
||||
bool py_lt(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __lt__, __gt__); }
|
||||
|
||||
bool py_le(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __le__, __ge__); }
|
||||
|
||||
bool py_gt(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __gt__, __lt__); }
|
||||
|
||||
bool py_ge(py_Ref lhs, py_Ref rhs) { return py_binaryop(lhs, rhs, __ge__, __le__); }
|
||||
|
||||
bool py_isidentical(py_Ref lhs, py_Ref rhs) {
|
||||
if(lhs->type != rhs->type) return false;
|
||||
switch(lhs->type) {
|
||||
@ -52,6 +94,29 @@ int py_bool(py_Ref val) {
|
||||
}
|
||||
}
|
||||
|
||||
int py_equal(py_Ref lhs, py_Ref rhs) {
|
||||
if(py_isidentical(lhs, rhs)) return 1;
|
||||
if(!py_eq(lhs, rhs)) return -1;
|
||||
return py_bool(py_retval());
|
||||
}
|
||||
|
||||
int py_less(py_Ref lhs, py_Ref rhs) {
|
||||
if(!py_lt(lhs, rhs)) return -1;
|
||||
return py_bool(py_retval());
|
||||
}
|
||||
|
||||
bool py_callable(py_Ref val) {
|
||||
switch(val->type) {
|
||||
case tp_nativefunc: return true;
|
||||
case tp_function: return true;
|
||||
case tp_type: return true;
|
||||
case tp_boundmethod: return true;
|
||||
case tp_staticmethod: return true;
|
||||
case tp_classmethod: return true;
|
||||
default: return py_tpfindmagic(val->type, __call__);
|
||||
}
|
||||
}
|
||||
|
||||
bool py_hash(py_Ref val, int64_t* out) {
|
||||
py_TypeInfo* ti = pk_typeinfo(val->type);
|
||||
do {
|
||||
@ -119,6 +184,20 @@ int py_next(py_Ref val) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool py_str(py_Ref val) {
|
||||
if(val->type == tp_str) {
|
||||
py_assign(py_retval(), val);
|
||||
return true;
|
||||
}
|
||||
py_Ref tmp = py_tpfindmagic(val->type, __str__);
|
||||
if(!tmp) return py_repr(val);
|
||||
return py_call(tmp, 1, val);
|
||||
}
|
||||
|
||||
bool py_repr(py_Ref val) { return pk_callmagic(__repr__, 1, val); }
|
||||
|
||||
bool py_len(py_Ref val) { return pk_callmagic(__len__, 1, val); }
|
||||
|
||||
bool py_getattr(py_Ref self, py_Name name) {
|
||||
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
|
||||
py_TypeInfo* ti = pk_typeinfo(self->type);
|
||||
@ -277,14 +356,3 @@ bool py_delitem(py_Ref self, py_Ref key) {
|
||||
py_shrink(2);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int py_equal(py_Ref lhs, py_Ref rhs) {
|
||||
if(py_isidentical(lhs, rhs)) return 1;
|
||||
if(!py_eq(lhs, rhs)) return -1;
|
||||
return py_bool(py_retval());
|
||||
}
|
||||
|
||||
int py_less(py_Ref lhs, py_Ref rhs) {
|
||||
if(!py_lt(lhs, rhs)) return -1;
|
||||
return py_bool(py_retval());
|
||||
}
|
@ -1,140 +1,61 @@
|
||||
#include "pocketpy/interpreter/typeinfo.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/common/name.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
_Thread_local VM* pk_current_vm;
|
||||
|
||||
static bool pk_initialized;
|
||||
static bool pk_finalized;
|
||||
|
||||
static VM pk_default_vm;
|
||||
static VM* pk_all_vm[16];
|
||||
static py_TValue _True, _False, _None, _NIL;
|
||||
|
||||
void py_initialize() {
|
||||
c11__rtassert(!pk_finalized);
|
||||
|
||||
if(pk_initialized) {
|
||||
// c11__abort("py_initialize() can only be called once!");
|
||||
return;
|
||||
}
|
||||
|
||||
pk_names_initialize();
|
||||
|
||||
// check endianness
|
||||
int x = 1;
|
||||
bool is_little_endian = *(char*)&x == 1;
|
||||
if(!is_little_endian) c11__abort("is_little_endian != true");
|
||||
|
||||
static_assert(sizeof(py_TValue) == 24, "sizeof(py_TValue) != 24");
|
||||
static_assert(offsetof(py_TValue, extra) == 4, "offsetof(py_TValue, extra) != 4");
|
||||
|
||||
pk_current_vm = pk_all_vm[0] = &pk_default_vm;
|
||||
|
||||
// initialize some convenient references
|
||||
py_newbool(&_True, true);
|
||||
py_newbool(&_False, false);
|
||||
py_newnone(&_None);
|
||||
py_newnil(&_NIL);
|
||||
VM__ctor(&pk_default_vm);
|
||||
|
||||
pk_initialized = true;
|
||||
PK_INLINE py_Ref py_peek(int i) {
|
||||
assert(i <= 0);
|
||||
return pk_current_vm->stack.sp + i;
|
||||
}
|
||||
|
||||
void* py_malloc(size_t size) { return PK_MALLOC(size); }
|
||||
|
||||
void* py_realloc(void* ptr, size_t size) { return PK_REALLOC(ptr, size); }
|
||||
|
||||
void py_free(void* ptr) { PK_FREE(ptr); }
|
||||
|
||||
py_GlobalRef py_True() { return &_True; }
|
||||
|
||||
py_GlobalRef py_False() { return &_False; }
|
||||
|
||||
py_GlobalRef py_None() { return &_None; }
|
||||
|
||||
py_GlobalRef py_NIL() { return &_NIL; }
|
||||
|
||||
void py_finalize() {
|
||||
if(pk_finalized) c11__abort("py_finalize() can only be called once!");
|
||||
pk_finalized = true;
|
||||
|
||||
for(int i = 1; i < 16; i++) {
|
||||
VM* vm = pk_all_vm[i];
|
||||
if(vm) {
|
||||
// temp fix https://github.com/pocketpy/pocketpy/issues/315
|
||||
// TODO: refactor VM__ctor and VM__dtor
|
||||
pk_current_vm = vm;
|
||||
VM__dtor(vm);
|
||||
PK_FREE(vm);
|
||||
}
|
||||
}
|
||||
pk_current_vm = &pk_default_vm;
|
||||
VM__dtor(&pk_default_vm);
|
||||
pk_current_vm = NULL;
|
||||
|
||||
pk_names_finalize();
|
||||
}
|
||||
|
||||
void py_switchvm(int index) {
|
||||
if(index < 0 || index >= 16) c11__abort("invalid vm index");
|
||||
if(!pk_all_vm[index]) {
|
||||
pk_current_vm = pk_all_vm[index] = PK_MALLOC(sizeof(VM));
|
||||
memset(pk_current_vm, 0, sizeof(VM));
|
||||
VM__ctor(pk_all_vm[index]);
|
||||
} else {
|
||||
pk_current_vm = pk_all_vm[index];
|
||||
}
|
||||
}
|
||||
|
||||
void py_resetvm() {
|
||||
PK_INLINE void py_push(py_Ref src) {
|
||||
VM* vm = pk_current_vm;
|
||||
VM__dtor(vm);
|
||||
memset(vm, 0, sizeof(VM));
|
||||
VM__ctor(vm);
|
||||
*vm->stack.sp++ = *src;
|
||||
}
|
||||
|
||||
void py_resetallvm() {
|
||||
for(int i = 0; i < 16; i++) {
|
||||
py_switchvm(i);
|
||||
py_resetvm();
|
||||
}
|
||||
py_switchvm(0);
|
||||
PK_INLINE void py_pushnil() {
|
||||
VM* vm = pk_current_vm;
|
||||
py_newnil(vm->stack.sp++);
|
||||
}
|
||||
|
||||
int py_currentvm() {
|
||||
for(int i = 0; i < 16; i++) {
|
||||
if(pk_all_vm[i] == pk_current_vm) return i;
|
||||
}
|
||||
return -1;
|
||||
PK_INLINE void py_pushnone() {
|
||||
VM* vm = pk_current_vm;
|
||||
py_newnone(vm->stack.sp++);
|
||||
}
|
||||
|
||||
void* py_getvmctx() { return pk_current_vm->ctx; }
|
||||
|
||||
void py_setvmctx(void* ctx) { pk_current_vm->ctx = ctx; }
|
||||
|
||||
void py_sys_setargv(int argc, char** argv) {
|
||||
py_GlobalRef sys = py_getmodule("sys");
|
||||
py_Ref argv_list = py_getdict(sys, py_name("argv"));
|
||||
py_list_clear(argv_list);
|
||||
for(int i = 0; i < argc; i++) {
|
||||
py_newstr(py_list_emplace(argv_list), argv[i]);
|
||||
}
|
||||
PK_INLINE void py_pushname(py_Name name) {
|
||||
VM* vm = pk_current_vm;
|
||||
py_newint(vm->stack.sp++, (uintptr_t)name);
|
||||
}
|
||||
|
||||
py_Callbacks* py_callbacks() { return &pk_current_vm->callbacks; }
|
||||
PK_INLINE void py_pop() {
|
||||
VM* vm = pk_current_vm;
|
||||
vm->stack.sp--;
|
||||
}
|
||||
|
||||
const char* pk_opname(Opcode op) {
|
||||
const static char* OP_NAMES[] = {
|
||||
#define OPCODE(name) #name,
|
||||
#include "pocketpy/xmacros/opcodes.h"
|
||||
#undef OPCODE
|
||||
};
|
||||
return OP_NAMES[op];
|
||||
PK_INLINE void py_shrink(int n) {
|
||||
VM* vm = pk_current_vm;
|
||||
vm->stack.sp -= n;
|
||||
}
|
||||
|
||||
PK_INLINE py_Ref py_pushtmp() {
|
||||
VM* vm = pk_current_vm;
|
||||
return vm->stack.sp++;
|
||||
}
|
||||
|
||||
PK_INLINE bool py_pushmethod(py_Name name) {
|
||||
bool ok = pk_loadmethod(py_peek(-1), name);
|
||||
if(ok) pk_current_vm->stack.sp++;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool py_pusheval(const char* expr, py_GlobalRef module) {
|
||||
bool ok = py_exec(expr, "<string>", EVAL_MODE, module);
|
||||
if(!ok) return false;
|
||||
py_push(py_retval());
|
||||
return true;
|
||||
}
|
||||
|
||||
PK_INLINE bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
|
||||
return VM__vectorcall(pk_current_vm, argc, kwargc, false) != RES_ERROR;
|
||||
}
|
||||
|
||||
bool py_call(py_Ref f, int argc, py_Ref argv) {
|
||||
@ -180,15 +101,15 @@ bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
|
||||
return VM__vectorcall(pk_current_vm, argc, kwargc, false) != RES_ERROR;
|
||||
bool py_tpcall(py_Type type, int argc, py_Ref argv) {
|
||||
return py_call(py_tpobject(type), argc, argv);
|
||||
}
|
||||
|
||||
PK_INLINE py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
||||
|
||||
bool py_pushmethod(py_Name name) {
|
||||
bool ok = pk_loadmethod(py_peek(-1), name);
|
||||
if(ok) pk_current_vm->stack.sp++;
|
||||
bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) {
|
||||
py_push(lhs);
|
||||
py_push(rhs);
|
||||
bool ok = pk_stack_binaryop(pk_current_vm, op, rop);
|
||||
py_shrink(2);
|
||||
return ok;
|
||||
}
|
||||
|
||||
@ -267,10 +188,6 @@ bool pk_loadmethod(py_StackRef self, py_Name name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool py_tpcall(py_Type type, int argc, py_Ref argv) {
|
||||
return py_call(py_tpobject(type), argc, argv);
|
||||
}
|
||||
|
||||
bool pk_callmagic(py_Name name, int argc, py_Ref argv) {
|
||||
assert(argc >= 1);
|
||||
// assert(py_ismagicname(name));
|
||||
@ -278,9 +195,3 @@ bool pk_callmagic(py_Name name, int argc, py_Ref argv) {
|
||||
if(!tmp) return AttributeError(argv, name);
|
||||
return py_call(tmp, argc, argv);
|
||||
}
|
||||
|
||||
bool StopIteration() {
|
||||
bool ok = py_tpcall(tp_StopIteration, 0, NULL);
|
||||
if(!ok) return false;
|
||||
return py_raise(py_retval());
|
||||
}
|
104
src/public/TypeSystem.c
Normal file
104
src/public/TypeSystem.c
Normal file
@ -0,0 +1,104 @@
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, void (*dtor)(void*)) {
|
||||
if(strlen(name) == 0) c11__abort("type name cannot be empty");
|
||||
py_Type type = pk_newtype(name, base, module, dtor, false, false);
|
||||
if(module) py_setdict(module, py_name(name), py_tpobject(type));
|
||||
return type;
|
||||
}
|
||||
|
||||
PK_INLINE bool py_istype(py_Ref self, py_Type type) { return self->type == type; }
|
||||
|
||||
PK_INLINE py_Type py_typeof(py_Ref self) { return self->type; }
|
||||
|
||||
bool py_isinstance(py_Ref obj, py_Type type) { return py_issubclass(obj->type, type); }
|
||||
|
||||
bool py_issubclass(py_Type derived, py_Type base) {
|
||||
assert(derived != 0 && base != 0);
|
||||
py_TypeInfo* derived_ti = pk_typeinfo(derived);
|
||||
py_TypeInfo* base_ti = pk_typeinfo(base);
|
||||
do {
|
||||
if(derived_ti == base_ti) return true;
|
||||
derived_ti = derived_ti->base_ti;
|
||||
} while(derived_ti);
|
||||
return false;
|
||||
}
|
||||
|
||||
py_Type py_gettype(const char* module, py_Name name) {
|
||||
py_Ref mod;
|
||||
if(module != NULL) {
|
||||
mod = py_getmodule(module);
|
||||
if(!mod) return tp_nil;
|
||||
} else {
|
||||
mod = pk_current_vm->builtins;
|
||||
}
|
||||
py_Ref object = py_getdict(mod, name);
|
||||
if(object && py_istype(object, tp_type)) return py_totype(object);
|
||||
return tp_nil;
|
||||
}
|
||||
|
||||
bool py_checktype(py_Ref self, py_Type type) {
|
||||
if(self->type == type) return true;
|
||||
return TypeError("expected '%t', got '%t'", type, self->type);
|
||||
}
|
||||
|
||||
bool py_checkinstance(py_Ref self, py_Type type) {
|
||||
if(py_isinstance(self, type)) return true;
|
||||
return TypeError("expected '%t' or its subclass, got '%t'", type, self->type);
|
||||
}
|
||||
|
||||
PK_DEPRECATED py_Ref py_tpgetmagic(py_Type type, py_Name name) {
|
||||
// assert(py_ismagicname(name));
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
py_Ref retval = py_getdict(&ti->self, name);
|
||||
return retval != NULL ? retval : py_NIL();
|
||||
}
|
||||
|
||||
PK_INLINE py_Ref py_tpfindmagic(py_Type t, py_Name name) {
|
||||
// assert(py_ismagicname(name));
|
||||
return py_tpfindname(t, name);
|
||||
}
|
||||
|
||||
PK_INLINE py_ItemRef py_tpfindname(py_Type type, py_Name name) {
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
return pk_tpfindname(ti, name);
|
||||
}
|
||||
|
||||
PK_INLINE py_Type py_tpbase(py_Type t) {
|
||||
assert(t);
|
||||
py_TypeInfo* ti = pk_typeinfo(t);
|
||||
return ti->base;
|
||||
}
|
||||
|
||||
py_Ref py_tpobject(py_Type type) {
|
||||
assert(type);
|
||||
return &pk_typeinfo(type)->self;
|
||||
}
|
||||
|
||||
const char* py_tpname(py_Type type) {
|
||||
if(!type) return "nil";
|
||||
py_Name name = pk_typeinfo(type)->name;
|
||||
return py_name2str(name);
|
||||
}
|
||||
|
||||
void py_tpsetfinal(py_Type type) {
|
||||
assert(type);
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
ti->is_final = true;
|
||||
}
|
||||
|
||||
void py_tphookattributes(py_Type type,
|
||||
bool (*getattribute)(py_Ref self, py_Name name),
|
||||
bool (*setattribute)(py_Ref self, py_Name name, py_Ref val),
|
||||
bool (*delattribute)(py_Ref self, py_Name name),
|
||||
bool (*getunboundmethod)(py_Ref self, py_Name name)) {
|
||||
assert(type);
|
||||
py_TypeInfo* ti = pk_typeinfo(type);
|
||||
ti->getattribute = getattribute;
|
||||
ti->setattribute = setattribute;
|
||||
ti->delattribute = delattribute;
|
||||
ti->getunboundmethod = getunboundmethod;
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
int64_t py_toint(py_Ref self) {
|
||||
py_i64 py_toint(py_Ref self) {
|
||||
assert(self->type == tp_int);
|
||||
return self->_i64;
|
||||
}
|
||||
@ -55,3 +55,30 @@ void* py_touserdata(py_Ref self) {
|
||||
assert(self && self->is_ptr);
|
||||
return PyObject__userdata(self->_obj);
|
||||
}
|
||||
|
||||
const char* py_tostr(py_Ref self) { return pk_tostr(self)->data; }
|
||||
|
||||
const char* py_tostrn(py_Ref self, int* size) {
|
||||
c11_string* ud = pk_tostr(self);
|
||||
*size = ud->size;
|
||||
return ud->data;
|
||||
}
|
||||
|
||||
c11_sv py_tosv(py_Ref self) {
|
||||
c11_string* ud = pk_tostr(self);
|
||||
return c11_string__sv(ud);
|
||||
}
|
||||
|
||||
unsigned char* py_tobytes(py_Ref self, int* size) {
|
||||
assert(self->type == tp_bytes);
|
||||
c11_bytes* ud = PyObject__userdata(self->_obj);
|
||||
*size = ud->size;
|
||||
return ud->data;
|
||||
}
|
||||
|
||||
void py_bytes_resize(py_Ref self, int size) {
|
||||
assert(self->type == tp_bytes);
|
||||
c11_bytes* ud = PyObject__userdata(self->_obj);
|
||||
if(size > ud->size) c11__abort("bytes can only be resized down: %d > %d", ud->size, size);
|
||||
ud->size = size;
|
||||
}
|
@ -32,6 +32,54 @@ void py_newbool(py_OutRef out, bool val) {
|
||||
out->_bool = val;
|
||||
}
|
||||
|
||||
void py_newstr(py_OutRef out, const char* data) { py_newstrv(out, (c11_sv){data, strlen(data)}); }
|
||||
|
||||
char* py_newstrn(py_OutRef out, int size) {
|
||||
if(size < 16) {
|
||||
out->type = tp_str;
|
||||
out->is_ptr = false;
|
||||
c11_string* ud = (c11_string*)(&out->extra);
|
||||
c11_string__ctor3(ud, size);
|
||||
return ud->data;
|
||||
}
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
int total_size = sizeof(c11_string) + size + 1;
|
||||
PyObject* obj = ManagedHeap__gcnew(heap, tp_str, 0, total_size);
|
||||
c11_string* ud = PyObject__userdata(obj);
|
||||
c11_string__ctor3(ud, size);
|
||||
out->type = tp_str;
|
||||
out->is_ptr = true;
|
||||
out->_obj = obj;
|
||||
return ud->data;
|
||||
}
|
||||
|
||||
void py_newstrv(py_OutRef out, c11_sv sv) {
|
||||
char* data = py_newstrn(out, sv.size);
|
||||
memcpy(data, sv.data, sv.size);
|
||||
}
|
||||
|
||||
void py_newfstr(py_OutRef out, const char* fmt, ...) {
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
pk_vsprintf(&buf, fmt, args);
|
||||
va_end(args);
|
||||
c11_sbuf__py_submit(&buf, out);
|
||||
}
|
||||
|
||||
unsigned char* py_newbytes(py_OutRef out, int size) {
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
// 4 bytes size + data
|
||||
PyObject* obj = ManagedHeap__gcnew(heap, tp_bytes, 0, sizeof(c11_bytes) + size);
|
||||
c11_bytes* ud = PyObject__userdata(obj);
|
||||
ud->size = size;
|
||||
out->type = tp_bytes;
|
||||
out->is_ptr = true;
|
||||
out->_obj = obj;
|
||||
return ud->data;
|
||||
}
|
||||
|
||||
void py_newnone(py_OutRef out) {
|
||||
out->type = tp_NoneType;
|
||||
out->is_ptr = false;
|
||||
@ -58,66 +106,6 @@ void py_newnativefunc(py_OutRef out, py_CFunction f) {
|
||||
out->_cfunc = f;
|
||||
}
|
||||
|
||||
void py_bindmethod(py_Type type, const char* name, py_CFunction f) {
|
||||
py_TValue tmp;
|
||||
py_newnativefunc(&tmp, f);
|
||||
py_setdict(py_tpobject(type), py_name(name), &tmp);
|
||||
}
|
||||
|
||||
void py_bindstaticmethod(py_Type type, const char* name, py_CFunction f) {
|
||||
py_TValue tmp;
|
||||
py_newnativefunc(&tmp, f);
|
||||
bool ok = py_tpcall(tp_staticmethod, 1, &tmp);
|
||||
if(!ok) {
|
||||
py_printexc();
|
||||
c11__abort("py_bindstaticmethod(): failed to create staticmethod");
|
||||
}
|
||||
py_setdict(py_tpobject(type), py_name(name), py_retval());
|
||||
}
|
||||
|
||||
void py_bindfunc(py_Ref obj, const char* name, py_CFunction f) {
|
||||
py_TValue tmp;
|
||||
py_newnativefunc(&tmp, f);
|
||||
py_setdict(obj, py_name(name), &tmp);
|
||||
}
|
||||
|
||||
void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter) {
|
||||
py_TValue tmp;
|
||||
py_newobject(&tmp, tp_property, 2, 0);
|
||||
py_newnativefunc(py_getslot(&tmp, 0), getter);
|
||||
if(setter) {
|
||||
py_newnativefunc(py_getslot(&tmp, 1), setter);
|
||||
} else {
|
||||
py_setslot(&tmp, 1, py_None());
|
||||
}
|
||||
py_setdict(py_tpobject(type), py_name(name), &tmp);
|
||||
}
|
||||
|
||||
void py_bindmagic(py_Type type, py_Name name, py_CFunction f) {
|
||||
py_Ref tmp = py_emplacedict(py_tpobject(type), name);
|
||||
py_newnativefunc(tmp, f);
|
||||
}
|
||||
|
||||
void py_bind(py_Ref obj, const char* sig, py_CFunction f) {
|
||||
py_Ref tmp = py_pushtmp();
|
||||
py_Name name = py_newfunction(tmp, sig, f, NULL, 0);
|
||||
py_setdict(obj, name, tmp);
|
||||
py_pop();
|
||||
}
|
||||
|
||||
void py_macrobind(const char* sig, py_CFunction f) {
|
||||
py_Ref tmp = py_pushtmp();
|
||||
py_Name name = py_newfunction(tmp, sig, f, NULL, 0);
|
||||
NameDict__set(&pk_current_vm->compile_time_funcs, name, tmp);
|
||||
py_pop();
|
||||
}
|
||||
|
||||
py_ItemRef py_macroget(py_Name name) {
|
||||
NameDict* d = &pk_current_vm->compile_time_funcs;
|
||||
if(d->length == 0) return NULL;
|
||||
return NameDict__try_get(d, name);
|
||||
}
|
||||
|
||||
py_Name py_newfunction(py_OutRef out,
|
||||
const char* sig,
|
||||
py_CFunction f,
|
@ -1,45 +0,0 @@
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
PK_INLINE bool py_istype(py_Ref self, py_Type type) { return self->type == type; }
|
||||
|
||||
bool py_checktype(py_Ref self, py_Type type) {
|
||||
if(self->type == type) return true;
|
||||
return TypeError("expected '%t', got '%t'", type, self->type);
|
||||
}
|
||||
|
||||
bool py_checkinstance(py_Ref self, py_Type type) {
|
||||
if(py_isinstance(self, type)) return true;
|
||||
return TypeError("expected '%t' or its subclass, got '%t'", type, self->type);
|
||||
}
|
||||
|
||||
bool py_isinstance(py_Ref obj, py_Type type) { return py_issubclass(obj->type, type); }
|
||||
|
||||
bool py_issubclass(py_Type derived, py_Type base) {
|
||||
assert(derived != 0 && base != 0);
|
||||
py_TypeInfo* derived_ti = pk_typeinfo(derived);
|
||||
py_TypeInfo* base_ti = pk_typeinfo(base);
|
||||
do {
|
||||
if(derived_ti == base_ti) return true;
|
||||
derived_ti = derived_ti->base_ti;
|
||||
} while(derived_ti);
|
||||
return false;
|
||||
}
|
||||
|
||||
py_Type py_typeof(py_Ref self) { return self->type; }
|
||||
|
||||
py_Type py_gettype(const char* module, py_Name name) {
|
||||
py_Ref mod;
|
||||
if(module != NULL) {
|
||||
mod = py_getmodule(module);
|
||||
if(!mod) return tp_nil;
|
||||
} else {
|
||||
mod = pk_current_vm->builtins;
|
||||
}
|
||||
py_Ref object = py_getdict(mod, name);
|
||||
if(object && py_istype(object, tp_type)) return py_totype(object);
|
||||
return tp_nil;
|
||||
}
|
@ -516,3 +516,31 @@ d = deque()
|
||||
for i in range(100):
|
||||
d.append(1)
|
||||
gc.collect()
|
||||
|
||||
# test maxlen
|
||||
q = deque(maxlen=3)
|
||||
assertEqual(q.maxlen, 3)
|
||||
q.append(1)
|
||||
q.append(2)
|
||||
q.append(3)
|
||||
assertEqual(list(q), [1, 2, 3])
|
||||
assertEqual(q._data, [1, 2, 3, None])
|
||||
q.append(4)
|
||||
assertEqual(list(q), [2, 3, 4])
|
||||
assertEqual(q._data, [None, 2, 3, 4])
|
||||
q.appendleft(1)
|
||||
assertEqual(list(q), [1, 2, 3])
|
||||
assertEqual(q._data, [1, 2, 3, None])
|
||||
q.appendleft(0)
|
||||
assertEqual(list(q), [0, 1, 2])
|
||||
assertEqual(q._data, [1, 2, None, 0])
|
||||
q.pop()
|
||||
assertEqual(list(q), [0, 1])
|
||||
assertEqual(q._data, [1, None, None, 0])
|
||||
assertEqual(len(q), 2)
|
||||
assertEqual(q._capacity, 4)
|
||||
q.popleft()
|
||||
assertEqual(list(q), [1])
|
||||
assertEqual(q._data, [1, None, None, None])
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user