mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
...
This commit is contained in:
parent
66cefad078
commit
a648313fb7
@ -94,6 +94,7 @@ bool pk_arrayiter(py_Ref val);
|
|||||||
bool pk_arraycontains(py_Ref self, py_Ref val);
|
bool pk_arraycontains(py_Ref self, py_Ref val);
|
||||||
|
|
||||||
bool pk_pushmethod(py_StackRef self, py_Name name);
|
bool pk_pushmethod(py_StackRef self, py_Name name);
|
||||||
|
bool pk_callmagic(py_Name name, int argc, py_Ref argv);
|
||||||
|
|
||||||
/// Assumes [a, b] are on the stack, performs a binary op.
|
/// Assumes [a, b] are on the stack, performs a binary op.
|
||||||
/// The result is stored in `self->last_retval`.
|
/// The result is stored in `self->last_retval`.
|
||||||
|
@ -15,7 +15,8 @@ typedef int16_t py_Type;
|
|||||||
typedef int64_t py_i64;
|
typedef int64_t py_i64;
|
||||||
typedef double py_f64;
|
typedef double py_f64;
|
||||||
|
|
||||||
/* string_view */
|
#define PY_RAISE // mark a function that can raise an exception
|
||||||
|
|
||||||
typedef struct c11_sv {
|
typedef struct c11_sv {
|
||||||
const char* data;
|
const char* data;
|
||||||
int size;
|
int size;
|
||||||
@ -36,26 +37,33 @@ typedef py_TValue* py_TmpRef;
|
|||||||
/// @param argc number of arguments.
|
/// @param argc number of arguments.
|
||||||
/// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument.
|
/// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument.
|
||||||
/// @return true if the function is successful.
|
/// @return true if the function is successful.
|
||||||
typedef bool (*py_CFunction)(int argc, py_StackRef argv);
|
typedef bool (*py_CFunction)(int argc, py_StackRef argv) PY_RAISE;
|
||||||
|
|
||||||
enum py_BindType {
|
enum py_BindType { bt_function, bt_staticmethod, bt_classmethod };
|
||||||
bt_function,
|
|
||||||
bt_staticmethod,
|
|
||||||
bt_classmethod,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum py_CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, CELL_MODE };
|
enum py_CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, CELL_MODE };
|
||||||
|
|
||||||
/************* Global VMs *************/
|
extern py_GlobalRef py_True;
|
||||||
|
extern py_GlobalRef py_False;
|
||||||
|
extern py_GlobalRef py_None;
|
||||||
|
extern py_GlobalRef py_NIL;
|
||||||
|
|
||||||
|
/************* Global Setup *************/
|
||||||
|
/// Initialize the VM.
|
||||||
void py_initialize();
|
void py_initialize();
|
||||||
|
/// Finalize the VM.
|
||||||
void py_finalize();
|
void py_finalize();
|
||||||
|
|
||||||
/// Run a simple source string. Do not change the stack.
|
/// Run a source string.
|
||||||
bool py_exec(const char* source);
|
/// @param source source string.
|
||||||
/// Eval a simple expression.
|
/// @param filename filename (for error messages).
|
||||||
/// The result will be set to `py_retval()`.
|
/// @param mode compile mode. Use `EXEC_MODE` for statements `EVAL_MODE` for expressions.
|
||||||
bool py_eval(const char* source);
|
/// @param module target module. Use NULL for the main module.
|
||||||
bool py_exec2(const char* source, const char* filename, enum py_CompileMode mode);
|
/// @return true if the execution is successful.
|
||||||
|
bool py_exec(const char* source,
|
||||||
|
const char* filename,
|
||||||
|
enum py_CompileMode mode,
|
||||||
|
py_Ref module) PY_RAISE;
|
||||||
|
|
||||||
/************* Values Creation *************/
|
/************* Values Creation *************/
|
||||||
void py_newint(py_Ref, py_i64);
|
void py_newint(py_Ref, py_i64);
|
||||||
@ -78,6 +86,17 @@ void py_newlist(py_Ref);
|
|||||||
/// You should initialize all elements before using it.
|
/// You should initialize all elements before using it.
|
||||||
void py_newlistn(py_Ref, int n);
|
void py_newlistn(py_Ref, int n);
|
||||||
|
|
||||||
|
void py_newdict(py_Ref);
|
||||||
|
void py_newslice(py_Ref);
|
||||||
|
void py_newnativefunc(py_Ref out, py_CFunction);
|
||||||
|
py_Name py_newfunction(py_Ref out,
|
||||||
|
const char* sig,
|
||||||
|
py_CFunction f,
|
||||||
|
enum py_BindType bt,
|
||||||
|
const char* docstring,
|
||||||
|
int slots);
|
||||||
|
|
||||||
|
/************* Name Convertions *************/
|
||||||
py_Name py_name(const char*);
|
py_Name py_name(const char*);
|
||||||
const char* py_name2str(py_Name);
|
const char* py_name2str(py_Name);
|
||||||
py_Name py_namev(c11_sv name);
|
py_Name py_namev(c11_sv name);
|
||||||
@ -85,12 +104,7 @@ c11_sv py_name2sv(py_Name);
|
|||||||
|
|
||||||
#define py_ismagicname(name) (name <= __missing__)
|
#define py_ismagicname(name) (name <= __missing__)
|
||||||
|
|
||||||
// opaque types
|
/************* Meta Operations *************/
|
||||||
void py_newdict(py_Ref);
|
|
||||||
void py_newslice(py_Ref);
|
|
||||||
// old style argc-based function
|
|
||||||
void py_newnativefunc(py_Ref out, py_CFunction);
|
|
||||||
|
|
||||||
/// Create a new type.
|
/// Create a new type.
|
||||||
/// @param name name of the type.
|
/// @param name name of the type.
|
||||||
/// @param base base type.
|
/// @param base base type.
|
||||||
@ -104,6 +118,7 @@ py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, vo
|
|||||||
/// @param slots number of slots. Use -1 to create a `__dict__`.
|
/// @param slots number of slots. Use -1 to create a `__dict__`.
|
||||||
/// @param udsize size of your userdata. You can use `py_touserdata()` to get the pointer to it.
|
/// @param udsize size of your userdata. You can use `py_touserdata()` to get the pointer to it.
|
||||||
void* py_newobject(py_Ref out, py_Type type, int slots, int udsize);
|
void* py_newobject(py_Ref out, py_Type type, int slots, int udsize);
|
||||||
|
|
||||||
/************* Type Cast *************/
|
/************* Type Cast *************/
|
||||||
py_i64 py_toint(py_Ref);
|
py_i64 py_toint(py_Ref);
|
||||||
py_f64 py_tofloat(py_Ref);
|
py_f64 py_tofloat(py_Ref);
|
||||||
@ -125,15 +140,34 @@ void* py_touserdata(py_Ref);
|
|||||||
#define py_istuple(self) py_istype(self, tp_tuple)
|
#define py_istuple(self) py_istype(self, tp_tuple)
|
||||||
#define py_isdict(self) py_istype(self, tp_dict)
|
#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)
|
||||||
|
|
||||||
|
py_Type py_typeof(py_Ref self);
|
||||||
bool py_istype(py_Ref, py_Type);
|
bool py_istype(py_Ref, py_Type);
|
||||||
bool py_isinstance(py_Ref obj, py_Type type);
|
bool py_isinstance(py_Ref obj, py_Type type);
|
||||||
bool py_issubclass(py_Type derived, py_Type base);
|
bool py_issubclass(py_Type derived, py_Type base);
|
||||||
|
|
||||||
extern py_GlobalRef py_True;
|
/// Search the magic method from the given type to the base type.
|
||||||
extern py_GlobalRef py_False;
|
py_GlobalRef py_tpfindmagic(py_Type, py_Name name);
|
||||||
extern py_GlobalRef py_None;
|
/// Search the name from the given type to the base type.
|
||||||
extern py_GlobalRef py_NIL;
|
py_GlobalRef py_tpfindname(py_Type, py_Name name);
|
||||||
|
/// Get the type object of the given type.
|
||||||
|
py_GlobalRef py_tpobject(py_Type type);
|
||||||
|
/// Get the type name.
|
||||||
|
const char* py_tpname(py_Type type);
|
||||||
|
/// Call a type to create a new instance.
|
||||||
|
bool py_tpcall(py_Type type, int argc, py_Ref argv);
|
||||||
|
/// Find the magic method from the given type to the base type.
|
||||||
|
py_GlobalRef py_tpmagic(py_Type type, py_Name name);
|
||||||
|
|
||||||
|
/// Check if the object is an instance of the given type.
|
||||||
|
bool py_checktype(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 *************/
|
/************* References *************/
|
||||||
#define PY_CHECK_ARGC(n) \
|
#define PY_CHECK_ARGC(n) \
|
||||||
if(argc != n) return TypeError("expected %d arguments, got %d", n, argc)
|
if(argc != n) return TypeError("expected %d arguments, got %d", n, argc)
|
||||||
@ -144,27 +178,16 @@ extern py_GlobalRef py_NIL;
|
|||||||
#define py_offset(p, i) ((py_Ref)((char*)p + ((i) << 4)))
|
#define py_offset(p, i) ((py_Ref)((char*)p + ((i) << 4)))
|
||||||
#define py_arg(i) py_offset(argv, i)
|
#define py_arg(i) py_offset(argv, i)
|
||||||
|
|
||||||
py_GlobalRef py_tpmagic(py_Type type, py_Name name);
|
|
||||||
#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpmagic((type), __magic__), (f))
|
|
||||||
|
|
||||||
// new style decl-based bindings
|
|
||||||
void py_bind(py_Ref obj, const char* sig, py_CFunction f);
|
|
||||||
|
|
||||||
py_ObjectRef py_bind2(py_Ref obj,
|
|
||||||
const char* sig,
|
|
||||||
py_CFunction f,
|
|
||||||
enum py_BindType bt,
|
|
||||||
const char* docstring,
|
|
||||||
int slots);
|
|
||||||
|
|
||||||
// old style argc-based bindings
|
|
||||||
void py_bindmethod(py_Type type, const char* name, py_CFunction f);
|
|
||||||
void py_bindmethod2(py_Type type, const char* name, py_CFunction f, enum py_BindType bt);
|
|
||||||
void py_bindfunc(py_Ref obj, const char* name, py_CFunction f);
|
|
||||||
|
|
||||||
/// Get the reference to the i-th register.
|
/// Get the reference to the i-th register.
|
||||||
/// All registers are located in a contiguous memory.
|
/// All registers are located in a contiguous memory.
|
||||||
py_GlobalRef py_reg(int i);
|
py_GlobalRef py_getreg(int i);
|
||||||
|
/// Set the reference to the i-th register.
|
||||||
|
void py_setreg(int i, py_Ref val);
|
||||||
|
|
||||||
|
/// Equivalent to `*dst = *src`.
|
||||||
|
void py_assign(py_Ref dst, py_Ref src);
|
||||||
|
/// The return value of the most recent call.
|
||||||
|
py_GlobalRef py_retval();
|
||||||
|
|
||||||
/// Get the reference of the object's `__dict__`.
|
/// Get the reference of the object's `__dict__`.
|
||||||
/// The object must have a `__dict__`.
|
/// The object must have a `__dict__`.
|
||||||
@ -178,21 +201,28 @@ bool py_deldict(py_Ref self, py_Name name);
|
|||||||
py_ObjectRef py_getslot(py_Ref self, int i);
|
py_ObjectRef py_getslot(py_Ref self, int i);
|
||||||
void py_setslot(py_Ref self, int i, py_Ref val);
|
void py_setslot(py_Ref self, int i, py_Ref val);
|
||||||
|
|
||||||
/// Gets the attribute of the object.
|
/************* Bindings *************/
|
||||||
bool py_getattr(py_Ref self, py_Name name);
|
// new style decl-based bindings
|
||||||
/// Sets the attribute of the object.
|
void py_bind(py_Ref obj, const char* sig, py_CFunction f);
|
||||||
bool py_setattr(py_Ref self, py_Name name, py_Ref val);
|
// old style argc-based bindings
|
||||||
/// Deletes the attribute of the object.
|
void py_bindmethod(py_Type type, const char* name, py_CFunction f);
|
||||||
bool py_delattr(py_Ref self, py_Name name);
|
void py_bindfunc(py_Ref obj, const char* name, py_CFunction f);
|
||||||
|
|
||||||
bool py_getitem(py_Ref self, py_Ref key);
|
#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpmagic((type), __magic__), (f))
|
||||||
bool py_setitem(py_Ref self, py_Ref key, py_Ref val);
|
|
||||||
bool py_delitem(py_Ref self, py_Ref key);
|
/************* Python Equivalents *************/
|
||||||
|
bool py_getattr(py_Ref self, py_Name name) PY_RAISE;
|
||||||
|
bool py_setattr(py_Ref self, py_Name name, py_Ref val) PY_RAISE;
|
||||||
|
bool py_delattr(py_Ref self, py_Name name) PY_RAISE;
|
||||||
|
|
||||||
|
bool py_getitem(py_Ref self, py_Ref key) PY_RAISE;
|
||||||
|
bool py_setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
|
||||||
|
bool py_delitem(py_Ref self, py_Ref key) PY_RAISE;
|
||||||
|
|
||||||
/// Perform a binary operation on the stack.
|
/// Perform a binary operation on the stack.
|
||||||
/// It assumes `lhs` and `rhs` are already pushed to the stack.
|
/// It assumes `lhs` and `rhs` are already pushed to the stack.
|
||||||
/// The result will be set to `py_retval()`.
|
/// The result will be set to `py_retval()`.
|
||||||
bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop);
|
bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) PY_RAISE;
|
||||||
|
|
||||||
#define py_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__)
|
#define py_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__)
|
||||||
#define py_binarysub(lhs, rhs) py_binaryop(lhs, rhs, __sub__, __rsub__)
|
#define py_binarysub(lhs, rhs) py_binaryop(lhs, rhs, __sub__, __rsub__)
|
||||||
@ -209,9 +239,6 @@ bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop);
|
|||||||
#define py_binaryxor(lhs, rhs) py_binaryop(lhs, rhs, __xor__, 0)
|
#define py_binaryxor(lhs, rhs) py_binaryop(lhs, rhs, __xor__, 0)
|
||||||
#define py_binarymatmul(lhs, rhs) py_binaryop(lhs, rhs, __matmul__, 0)
|
#define py_binarymatmul(lhs, rhs) py_binaryop(lhs, rhs, __matmul__, 0)
|
||||||
|
|
||||||
/// Equivalent to `*dst = *src`.
|
|
||||||
void py_assign(py_Ref dst, py_Ref src);
|
|
||||||
|
|
||||||
/************* Stack Operations *************/
|
/************* Stack Operations *************/
|
||||||
/// Return a reference to the i-th object from the top of the stack.
|
/// Return a reference to the i-th object from the top of the stack.
|
||||||
/// i should be negative, e.g. (-1) means TOS.
|
/// i should be negative, e.g. (-1) means TOS.
|
||||||
@ -238,13 +265,13 @@ py_TmpRef py_getmodule(const char* name);
|
|||||||
|
|
||||||
/// Import a module.
|
/// Import a module.
|
||||||
/// The result will be set to `py_retval()`.
|
/// The result will be set to `py_retval()`.
|
||||||
bool py_import(const char* name);
|
bool py_import(const char* name) PY_RAISE;
|
||||||
|
|
||||||
/************* Errors *************/
|
/************* Errors *************/
|
||||||
/// Raise an exception by name and message. Always returns false.
|
/// Raise an exception by name and message. Always returns false.
|
||||||
bool py_exception(const char* name, const char* fmt, ...);
|
bool py_exception(const char* name, const char* fmt, ...) PY_RAISE;
|
||||||
/// Raise an expection object. Always returns false.
|
/// Raise an expection object. Always returns false.
|
||||||
bool py_raise(py_Ref);
|
bool py_raise(py_Ref) PY_RAISE;
|
||||||
/// Print the last error to the console.
|
/// Print the last error to the console.
|
||||||
void py_printexc();
|
void py_printexc();
|
||||||
/// Format the last error to a string.
|
/// Format the last error to a string.
|
||||||
@ -264,13 +291,16 @@ bool py_checkexc();
|
|||||||
py_exception("UnboundLocalError", "local variable '%n' referenced before assignment", (n))
|
py_exception("UnboundLocalError", "local variable '%n' referenced before assignment", (n))
|
||||||
|
|
||||||
bool StopIteration();
|
bool StopIteration();
|
||||||
bool KeyError(py_Ref key);
|
bool KeyError(py_Ref key) PY_RAISE;
|
||||||
|
|
||||||
/************* Operators *************/
|
/************* Operators *************/
|
||||||
|
int py_equal(py_Ref lhs, py_Ref rhs) PY_RAISE;
|
||||||
|
int py_less(py_Ref lhs, py_Ref rhs) PY_RAISE;
|
||||||
|
|
||||||
/// Equivalent to `bool(val)`.
|
/// Equivalent to `bool(val)`.
|
||||||
/// Returns 1 if `val` is truthy, otherwise 0.
|
/// Returns 1 if `val` is truthy, otherwise 0.
|
||||||
/// Returns -1 if an error occurred.
|
/// Returns -1 if an error occurred.
|
||||||
int py_bool(py_Ref val);
|
int py_bool(py_Ref val) PY_RAISE;
|
||||||
|
|
||||||
#define py_eq(lhs, rhs) py_binaryop(lhs, rhs, __eq__, __eq__)
|
#define py_eq(lhs, rhs) py_binaryop(lhs, rhs, __eq__, __eq__)
|
||||||
#define py_ne(lhs, rhs) py_binaryop(lhs, rhs, __ne__, __ne__)
|
#define py_ne(lhs, rhs) py_binaryop(lhs, rhs, __ne__, __ne__)
|
||||||
@ -279,61 +309,42 @@ int py_bool(py_Ref val);
|
|||||||
#define py_gt(lhs, rhs) py_binaryop(lhs, rhs, __gt__, __lt__)
|
#define py_gt(lhs, rhs) py_binaryop(lhs, rhs, __gt__, __lt__)
|
||||||
#define py_ge(lhs, rhs) py_binaryop(lhs, rhs, __ge__, __le__)
|
#define py_ge(lhs, rhs) py_binaryop(lhs, rhs, __ge__, __le__)
|
||||||
|
|
||||||
int py_equal(py_Ref lhs, py_Ref rhs);
|
bool py_hash(py_Ref, py_i64* out) PY_RAISE;
|
||||||
int py_less(py_Ref lhs, py_Ref rhs);
|
|
||||||
|
|
||||||
bool py_hash(py_Ref, py_i64* out);
|
|
||||||
|
|
||||||
/// Get the iterator of the object.
|
/// Get the iterator of the object.
|
||||||
bool py_iter(py_Ref);
|
bool py_iter(py_Ref) PY_RAISE;
|
||||||
/// Get the next element from the iterator.
|
/// Get the next element from the iterator.
|
||||||
/// 1: success, 0: StopIteration, -1: error
|
/// 1: success, 0: StopIteration, -1: error
|
||||||
int py_next(py_Ref);
|
int py_next(py_Ref) PY_RAISE;
|
||||||
|
|
||||||
/// Python equivalent to `lhs is rhs`.
|
/// Python equivalent to `lhs is rhs`.
|
||||||
bool py_isidentical(py_Ref, py_Ref);
|
bool py_isidentical(py_Ref, py_Ref);
|
||||||
|
|
||||||
/// A stack operation that calls a function.
|
/// A stack operation that calls a function.
|
||||||
/// It assumes `argc + kwargc` arguments are already pushed to the stack.
|
/// It assumes `argc + kwargc` arguments are already pushed to the stack.
|
||||||
/// The result will be set to `py_retval()`.
|
/// The result will be set to `py_retval()`.
|
||||||
/// The stack size will be reduced by `argc + kwargc`.
|
/// The stack size will be reduced by `argc + kwargc`.
|
||||||
bool py_vectorcall(uint16_t argc, uint16_t kwargc);
|
bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE;
|
||||||
/// Call a function.
|
/// Call a function.
|
||||||
/// It prepares the stack and then performs a `vectorcall(argc, 0, false)`.
|
/// It prepares the stack and then performs a `vectorcall(argc, 0, false)`.
|
||||||
/// The result will be set to `py_retval()`.
|
/// The result will be set to `py_retval()`.
|
||||||
/// The stack remains unchanged after the operation.
|
/// The stack remains unchanged after the operation.
|
||||||
bool py_call(py_Ref f, int argc, py_Ref argv);
|
bool py_call(py_Ref f, int argc, py_Ref argv) PY_RAISE;
|
||||||
/// Call a non-magic method.
|
/// Call a non-magic method.
|
||||||
/// It prepares the stack and then performs a `vectorcall(argc+1, 0, false)`.
|
/// It prepares the stack and then performs a `vectorcall(argc+1, 0, false)`.
|
||||||
/// The result will be set to `py_retval()`.
|
/// The result will be set to `py_retval()`.
|
||||||
/// The stack remains unchanged after the operation.
|
/// The stack remains unchanged after the operation.
|
||||||
bool py_callmethod(py_Ref self, py_Name, int argc, py_Ref argv);
|
bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) PY_RAISE;
|
||||||
/// Call a magic method using a continuous buffer.
|
|
||||||
/// The result will be set to `py_retval()`.
|
|
||||||
/// The stack remains unchanged after the operation.
|
|
||||||
bool py_callmagic(py_Name name, int argc, py_Ref argv);
|
|
||||||
/// Call a `py_CFunction` in a safe way.
|
/// Call a `py_CFunction` in a safe way.
|
||||||
bool py_callcfunc(py_StackRef p0, py_CFunction cfunc, int argc, py_Ref argv);
|
bool py_callcfunc(py_StackRef p0, py_CFunction cfunc, int argc, py_Ref argv) PY_RAISE;
|
||||||
|
|
||||||
bool py_str(py_Ref val);
|
bool py_str(py_Ref val) PY_RAISE;
|
||||||
#define py_repr(val) py_callmagic(__repr__, 1, val)
|
bool py_repr(py_Ref val) PY_RAISE;
|
||||||
#define py_len(val) py_callmagic(__len__, 1, val)
|
bool py_len(py_Ref val) PY_RAISE;
|
||||||
|
|
||||||
/// The return value of the most recent call.
|
/************* Unchecked Functions *************/
|
||||||
py_GlobalRef py_retval();
|
|
||||||
|
|
||||||
#define py_isnil(self) py_istype(self, 0)
|
|
||||||
#define py_isnone(self) py_istype(self, tp_NoneType)
|
|
||||||
|
|
||||||
/* tuple */
|
|
||||||
|
|
||||||
// unchecked functions, if self is not a tuple, the behavior is undefined
|
|
||||||
py_ObjectRef py_tuple__data(py_Ref self);
|
py_ObjectRef py_tuple__data(py_Ref self);
|
||||||
py_ObjectRef py_tuple__getitem(py_Ref self, int i);
|
py_ObjectRef py_tuple__getitem(py_Ref self, int i);
|
||||||
void py_tuple__setitem(py_Ref self, int i, py_Ref val);
|
void py_tuple__setitem(py_Ref self, int i, py_Ref val);
|
||||||
int py_tuple__len(py_Ref self);
|
int py_tuple__len(py_Ref self);
|
||||||
|
|
||||||
// unchecked functions, if self is not a list, the behavior is undefined
|
|
||||||
py_TmpRef py_list__data(py_Ref self);
|
py_TmpRef py_list__data(py_Ref self);
|
||||||
py_TmpRef py_list__getitem(py_Ref self, int i);
|
py_TmpRef py_list__getitem(py_Ref self, int i);
|
||||||
void py_list__setitem(py_Ref self, int i, py_Ref val);
|
void py_list__setitem(py_Ref self, int i, py_Ref val);
|
||||||
@ -344,44 +355,17 @@ void py_list__clear(py_Ref self);
|
|||||||
void py_list__insert(py_Ref self, int i, py_Ref val);
|
void py_list__insert(py_Ref self, int i, py_Ref val);
|
||||||
void py_list__reverse(py_Ref self);
|
void py_list__reverse(py_Ref self);
|
||||||
|
|
||||||
// unchecked functions, if self is not a dict, the behavior is undefined
|
py_TmpRef py_dict__getitem(py_Ref self, py_Ref key) PY_RAISE;
|
||||||
py_TmpRef py_dict__getitem(py_Ref self, py_Ref key);
|
void py_dict__setitem(py_Ref self, py_Ref key, py_Ref val) PY_RAISE;
|
||||||
void py_dict__setitem(py_Ref self, py_Ref key, py_Ref val);
|
void py_dict__delitem(py_Ref self, py_Ref key) PY_RAISE;
|
||||||
bool py_dict__contains(py_Ref self, py_Ref key);
|
bool py_dict__contains(py_Ref self, py_Ref key);
|
||||||
int py_dict__len(py_Ref self);
|
int py_dict__len(py_Ref self);
|
||||||
bool py_dict__apply(py_Ref self, bool (*f)(py_Ref key, py_Ref val, void* ctx), void* ctx);
|
bool py_dict__apply(py_Ref self, bool (*f)(py_Ref key, py_Ref val, void* ctx), void* ctx);
|
||||||
|
|
||||||
/// Search the magic method from the given type to the base type.
|
/************* Others *************/
|
||||||
/// Return the reference or NULL if not found.
|
|
||||||
py_GlobalRef py_tpfindmagic(py_Type, py_Name name);
|
|
||||||
|
|
||||||
/// Search the name from the given type to the base type.
|
|
||||||
/// Return the reference or NULL if not found.
|
|
||||||
py_GlobalRef py_tpfindname(py_Type, py_Name name);
|
|
||||||
|
|
||||||
/// Get the type object of the given type.
|
|
||||||
py_GlobalRef py_tpobject(py_Type type);
|
|
||||||
|
|
||||||
/// Get the type name.
|
|
||||||
const char* py_tpname(py_Type type);
|
|
||||||
|
|
||||||
/// Call a type to create a new instance.
|
|
||||||
bool py_tpcall(py_Type type, int argc, py_Ref argv);
|
|
||||||
|
|
||||||
/// Check if the object is an instance of the given type.
|
|
||||||
bool py_checktype(py_Ref self, py_Type type);
|
|
||||||
|
|
||||||
/// Get the type of the object.
|
|
||||||
py_Type py_typeof(py_Ref self);
|
|
||||||
|
|
||||||
#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)
|
|
||||||
|
|
||||||
int py_replinput(char* buf);
|
int py_replinput(char* buf);
|
||||||
|
|
||||||
/// Python favored string formatting.
|
/// Python favored string formatting. (just put here, not for users)
|
||||||
/// %d: int
|
/// %d: int
|
||||||
/// %i: py_i64 (int64_t)
|
/// %i: py_i64 (int64_t)
|
||||||
/// %f: py_f64 (double)
|
/// %f: py_f64 (double)
|
||||||
|
@ -717,7 +717,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
|||||||
}
|
}
|
||||||
/////////
|
/////////
|
||||||
case OP_UNARY_NEGATIVE: {
|
case OP_UNARY_NEGATIVE: {
|
||||||
if(!py_callmagic(__neg__, 1, TOP())) goto __ERROR;
|
if(!pk_callmagic(__neg__, 1, TOP())) goto __ERROR;
|
||||||
*TOP() = self->last_retval;
|
*TOP() = self->last_retval;
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
@ -735,7 +735,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_UNARY_INVERT: {
|
case OP_UNARY_INVERT: {
|
||||||
if(!py_callmagic(__invert__, 1, TOP())) goto __ERROR;
|
if(!pk_callmagic(__invert__, 1, TOP())) goto __ERROR;
|
||||||
*TOP() = self->last_retval;
|
*TOP() = self->last_retval;
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
@ -889,7 +889,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
|||||||
py_TValue* tmp = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
py_TValue* tmp = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
||||||
const char* string = py_tostr(tmp);
|
const char* string = py_tostr(tmp);
|
||||||
// TODO: optimize this
|
// TODO: optimize this
|
||||||
if(!py_exec2(string, "<eval>", EVAL_MODE)) goto __ERROR;
|
if(!py_exec(string, "<eval>", EVAL_MODE, &frame->module)) goto __ERROR;
|
||||||
PUSH(py_retval());
|
PUSH(py_retval());
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
@ -174,8 +174,8 @@ static void disassemble(CodeObject* co) {
|
|||||||
c11_vector__dtor(&jumpTargets);
|
c11_vector__dtor(&jumpTargets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) {
|
||||||
pk_VM__exec(pk_VM* vm, const char* source, const char* filename, enum py_CompileMode mode) {
|
pk_VM* vm = pk_current_vm;
|
||||||
CodeObject co;
|
CodeObject co;
|
||||||
pk_SourceData_ src = pk_SourceData__rcnew(source, filename, mode, false);
|
pk_SourceData_ src = pk_SourceData__rcnew(source, filename, mode, false);
|
||||||
Error* err = pk_compile(src, &co);
|
Error* err = pk_compile(src, &co);
|
||||||
@ -189,8 +189,9 @@ static bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
// disassemble(&co);
|
// disassemble(&co);
|
||||||
|
if(!module) module = &vm->main;
|
||||||
|
|
||||||
Frame* frame = Frame__new(&co, &vm->main, NULL, vm->stack.sp, vm->stack.sp, &co);
|
Frame* frame = Frame__new(&co, module, NULL, vm->stack.sp, vm->stack.sp, &co);
|
||||||
pk_VM__push_frame(vm, frame);
|
pk_VM__push_frame(vm, frame);
|
||||||
pk_FrameResult res = pk_VM__run_top_frame(vm);
|
pk_FrameResult res = pk_VM__run_top_frame(vm);
|
||||||
CodeObject__dtor(&co);
|
CodeObject__dtor(&co);
|
||||||
@ -200,14 +201,6 @@ static bool
|
|||||||
c11__unreachedable();
|
c11__unreachedable();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool py_exec(const char* source) { return pk_VM__exec(pk_current_vm, source, "<exec>", EXEC_MODE); }
|
|
||||||
|
|
||||||
bool py_eval(const char* source) { return pk_VM__exec(pk_current_vm, source, "<eval>", EVAL_MODE); }
|
|
||||||
|
|
||||||
bool py_exec2(const char* source, const char* filename, enum py_CompileMode mode) {
|
|
||||||
return pk_VM__exec(pk_current_vm, source, filename, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool py_call(py_Ref f, int argc, py_Ref argv) {
|
bool py_call(py_Ref f, int argc, py_Ref argv) {
|
||||||
if(f->type == tp_nativefunc) {
|
if(f->type == tp_nativefunc) {
|
||||||
py_TValue* p0 = pk_current_vm->stack.sp;
|
py_TValue* p0 = pk_current_vm->stack.sp;
|
||||||
@ -230,9 +223,7 @@ bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
|
|||||||
|
|
||||||
py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
||||||
|
|
||||||
bool py_pushmethod(py_Name name){
|
bool py_pushmethod(py_Name name) { return pk_pushmethod(py_peek(-1), name); }
|
||||||
return pk_pushmethod(py_peek(-1), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pk_pushmethod(py_StackRef self, py_Name name) {
|
bool pk_pushmethod(py_StackRef self, py_Name name) {
|
||||||
// NOTE: `out` and `out_self` may overlap with `self`
|
// NOTE: `out` and `out_self` may overlap with `self`
|
||||||
@ -317,7 +308,7 @@ bool py_tpcall(py_Type type, int argc, py_Ref argv) {
|
|||||||
return py_call(py_tpobject(type), argc, argv);
|
return py_call(py_tpobject(type), argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool py_callmagic(py_Name name, int argc, py_Ref argv) {
|
bool pk_callmagic(py_Name name, int argc, py_Ref argv) {
|
||||||
assert(argc >= 1);
|
assert(argc >= 1);
|
||||||
assert(py_ismagicname(name));
|
assert(py_ismagicname(name));
|
||||||
py_Ref tmp = py_tpfindmagic(argv->type, name);
|
py_Ref tmp = py_tpfindmagic(argv->type, name);
|
@ -156,7 +156,7 @@ static bool _py_builtins__hash(int argc, py_Ref argv) {
|
|||||||
|
|
||||||
static bool _py_builtins__abs(int argc, py_Ref argv) {
|
static bool _py_builtins__abs(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(1);
|
PY_CHECK_ARGC(1);
|
||||||
return py_callmagic(__abs__, 1, argv);
|
return pk_callmagic(__abs__, 1, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _py_builtins__sum(int argc, py_Ref argv) {
|
static bool _py_builtins__sum(int argc, py_Ref argv) {
|
||||||
@ -205,15 +205,13 @@ static bool _py_NoneType__repr__(int argc, py_Ref argv) {
|
|||||||
static bool _py_builtins__exec(int argc, py_Ref argv) {
|
static bool _py_builtins__exec(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(1);
|
PY_CHECK_ARGC(1);
|
||||||
PY_CHECK_ARG_TYPE(0, tp_str);
|
PY_CHECK_ARG_TYPE(0, tp_str);
|
||||||
bool ok = py_exec(py_tostr(argv));
|
return py_exec(py_tostr(argv), "<exec>", EXEC_MODE, NULL);
|
||||||
py_newnone(py_retval());
|
|
||||||
return ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _py_builtins__eval(int argc, py_Ref argv) {
|
static bool _py_builtins__eval(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(1);
|
PY_CHECK_ARGC(1);
|
||||||
PY_CHECK_ARG_TYPE(0, tp_str);
|
PY_CHECK_ARG_TYPE(0, tp_str);
|
||||||
return py_eval(py_tostr(argv));
|
return py_exec(py_tostr(argv), "<eval>", EVAL_MODE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
py_TValue pk_builtins__register() {
|
py_TValue pk_builtins__register() {
|
||||||
|
@ -500,6 +500,12 @@ py_Ref py_dict__getitem(py_Ref self, py_Ref key) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void py_dict__delitem(py_Ref self, py_Ref key) {
|
||||||
|
assert(py_isdict(self));
|
||||||
|
Dict* ud = py_touserdata(self);
|
||||||
|
Dict__pop(ud, key);
|
||||||
|
}
|
||||||
|
|
||||||
void py_dict__setitem(py_Ref self, py_Ref key, py_Ref val) {
|
void py_dict__setitem(py_Ref self, py_Ref key, py_Ref val) {
|
||||||
assert(py_isdict(self));
|
assert(py_isdict(self));
|
||||||
Dict* ud = py_touserdata(self);
|
Dict* ud = py_touserdata(self);
|
||||||
|
@ -178,7 +178,7 @@ bool py_delattr(py_Ref self, py_Name name) {
|
|||||||
bool py_getitem(py_Ref self, py_Ref key) {
|
bool py_getitem(py_Ref self, py_Ref key) {
|
||||||
py_push(self);
|
py_push(self);
|
||||||
py_push(key);
|
py_push(key);
|
||||||
bool ok = py_callmagic(__getitem__, 2, py_peek(-2));
|
bool ok = pk_callmagic(__getitem__, 2, py_peek(-2));
|
||||||
py_shrink(2);
|
py_shrink(2);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
@ -187,7 +187,7 @@ bool py_setitem(py_Ref self, py_Ref key, py_Ref val) {
|
|||||||
py_push(self);
|
py_push(self);
|
||||||
py_push(key);
|
py_push(key);
|
||||||
py_push(val);
|
py_push(val);
|
||||||
bool ok = py_callmagic(__setitem__, 3, py_peek(-3));
|
bool ok = pk_callmagic(__setitem__, 3, py_peek(-3));
|
||||||
py_shrink(3);
|
py_shrink(3);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
@ -195,7 +195,7 @@ bool py_setitem(py_Ref self, py_Ref key, py_Ref val) {
|
|||||||
bool py_delitem(py_Ref self, py_Ref key) {
|
bool py_delitem(py_Ref self, py_Ref key) {
|
||||||
py_push(self);
|
py_push(self);
|
||||||
py_push(key);
|
py_push(key);
|
||||||
bool ok = py_callmagic(__delitem__, 2, py_peek(-2));
|
bool ok = pk_callmagic(__delitem__, 2, py_peek(-2));
|
||||||
py_shrink(2);
|
py_shrink(2);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
@ -545,3 +545,11 @@ bool py_str(py_Ref val) {
|
|||||||
if(!tmp) return py_repr(val);
|
if(!tmp) return py_repr(val);
|
||||||
return py_call(tmp, 1, 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);
|
||||||
|
}
|
@ -4,7 +4,9 @@
|
|||||||
#include "pocketpy/objects/object.h"
|
#include "pocketpy/objects/object.h"
|
||||||
#include "pocketpy/interpreter/vm.h"
|
#include "pocketpy/interpreter/vm.h"
|
||||||
|
|
||||||
py_Ref py_reg(int i) { return pk_current_vm->reg + i; }
|
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; }
|
||||||
|
|
||||||
py_Ref py_getdict(py_Ref self, py_Name name) {
|
py_Ref py_getdict(py_Ref self, py_Name name) {
|
||||||
assert(self && self->is_ptr);
|
assert(self && self->is_ptr);
|
||||||
|
@ -49,10 +49,6 @@ void py_newnativefunc(py_Ref out, py_CFunction f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void py_bindmethod(py_Type type, const char* name, py_CFunction f) {
|
void py_bindmethod(py_Type type, const char* name, py_CFunction f) {
|
||||||
py_bindmethod2(type, name, f, bt_function);
|
|
||||||
}
|
|
||||||
|
|
||||||
void py_bindmethod2(py_Type type, const char* name, py_CFunction f, enum py_BindType bt) {
|
|
||||||
py_TValue tmp;
|
py_TValue tmp;
|
||||||
py_newnativefunc(&tmp, f);
|
py_newnativefunc(&tmp, f);
|
||||||
py_setdict(py_tpobject(type), py_name(name), &tmp);
|
py_setdict(py_tpobject(type), py_name(name), &tmp);
|
||||||
@ -66,28 +62,37 @@ void py_bindfunc(py_Ref obj, const char* name, py_CFunction f) {
|
|||||||
|
|
||||||
void py_bind(py_Ref obj, const char* sig, py_CFunction f) {
|
void py_bind(py_Ref obj, const char* sig, py_CFunction f) {
|
||||||
py_TValue tmp;
|
py_TValue tmp;
|
||||||
do {
|
py_Name name = py_newfunction(&tmp, sig, f, bt_function, NULL, 0);
|
||||||
char buffer[256];
|
|
||||||
snprintf(buffer, sizeof(buffer), "def %s: pass", sig);
|
|
||||||
// fn(a, b, *c, d=1) -> None
|
|
||||||
CodeObject code;
|
|
||||||
pk_SourceData_ source = pk_SourceData__rcnew(buffer, "<bind>", EXEC_MODE, false);
|
|
||||||
Error* err = pk_compile(source, &code);
|
|
||||||
if(err) c11__abort("py_bind(): failed to compile signature '%s'", sig);
|
|
||||||
if(code.func_decls.count != 1) c11__abort("py_bind(): invalid signature '%s'", sig);
|
|
||||||
FuncDecl_ decl = c11__getitem(FuncDecl_, &code.func_decls, 0);
|
|
||||||
// construct the function
|
|
||||||
Function* ud = py_newobject(&tmp, tp_function, 0, sizeof(Function));
|
|
||||||
Function__ctor(ud, decl, NULL);
|
|
||||||
ud->cfunc = f;
|
|
||||||
CodeObject__dtor(&code);
|
|
||||||
PK_DECREF(source);
|
|
||||||
} while(0);
|
|
||||||
Function* ud = py_touserdata(&tmp);
|
|
||||||
py_Name name = py_name(ud->decl->code.name->data);
|
|
||||||
py_setdict(obj, name, &tmp);
|
py_setdict(obj, name, &tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
py_Name py_newfunction(py_Ref out,
|
||||||
|
const char* sig,
|
||||||
|
py_CFunction f,
|
||||||
|
enum py_BindType bt,
|
||||||
|
const char* docstring,
|
||||||
|
int slots) {
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, sizeof(buffer), "def %s: pass", sig);
|
||||||
|
// fn(a, b, *c, d=1) -> None
|
||||||
|
CodeObject code;
|
||||||
|
pk_SourceData_ source = pk_SourceData__rcnew(buffer, "<bind>", EXEC_MODE, false);
|
||||||
|
Error* err = pk_compile(source, &code);
|
||||||
|
if(err || code.func_decls.count != 1) {
|
||||||
|
c11__abort("py_newfunction(): invalid signature '%s'", sig);
|
||||||
|
}
|
||||||
|
FuncDecl_ decl = c11__getitem(FuncDecl_, &code.func_decls, 0);
|
||||||
|
decl->docstring = docstring;
|
||||||
|
// construct the function
|
||||||
|
Function* ud = py_newobject(out, tp_function, slots, sizeof(Function));
|
||||||
|
Function__ctor(ud, decl, NULL);
|
||||||
|
ud->cfunc = f;
|
||||||
|
CodeObject__dtor(&code);
|
||||||
|
PK_DECREF(source);
|
||||||
|
assert(decl->rc.count == 1);
|
||||||
|
return py_name(ud->decl->code.name->data);
|
||||||
|
}
|
||||||
|
|
||||||
void* py_newobject(py_Ref out, py_Type type, int slots, int udsize) {
|
void* py_newobject(py_Ref out, py_Type type, int slots, int udsize) {
|
||||||
pk_ManagedHeap* heap = &pk_current_vm->heap;
|
pk_ManagedHeap* heap = &pk_current_vm->heap;
|
||||||
PyObject* obj = pk_ManagedHeap__gcnew(heap, type, slots, udsize);
|
PyObject* obj = pk_ManagedHeap__gcnew(heap, type, slots, udsize);
|
||||||
|
@ -49,13 +49,13 @@ int main(int argc, char** argv) {
|
|||||||
int size = py_replinput(buf);
|
int size = py_replinput(buf);
|
||||||
assert(size < sizeof(buf));
|
assert(size < sizeof(buf));
|
||||||
if(size >= 0) {
|
if(size >= 0) {
|
||||||
if(!py_exec2(buf, "<stdin>", REPL_MODE)) py_printexc();
|
if(!py_exec(buf, "<stdin>", REPL_MODE, NULL)) py_printexc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
char* source = read_file(argv[1]);
|
char* source = read_file(argv[1]);
|
||||||
if(source) {
|
if(source) {
|
||||||
if(!py_exec(source)) py_printexc();
|
if(!py_exec(source, argv[1], EXEC_MODE, NULL)) py_printexc();
|
||||||
free(source);
|
free(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user