This commit is contained in:
blueloveTH 2024-07-30 23:44:22 +08:00
parent 66cefad078
commit a648313fb7
11 changed files with 170 additions and 175 deletions

View File

@ -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`.

View File

@ -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)

View File

@ -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();
} }

View File

@ -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);

View File

@ -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() {

View File

@ -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);

View File

@ -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;
} }

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
} }
} }