mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
Compare commits
5 Commits
d00c058c46
...
f22191faa6
Author | SHA1 | Date | |
---|---|---|---|
|
f22191faa6 | ||
|
ca7552c9f6 | ||
|
fdc26c6b93 | ||
|
0bafc17994 | ||
|
15fd2ef8a0 |
@ -5,8 +5,12 @@ python prebuild.py
|
||||
SRC=$(find src/ -name "*.c")
|
||||
|
||||
FLAGS="-std=c11 -lm -Iinclude -O0 -Wfatal-errors -g -DDEBUG -DPK_ENABLE_OS=1"
|
||||
|
||||
SANITIZE_FLAGS="-fsanitize=address,leak,undefined"
|
||||
# SANITIZE_FLAGS=""
|
||||
|
||||
if [ "$(uname)" == "Darwin" ]; then
|
||||
SANITIZE_FLAGS="-fsanitize=address,undefined"
|
||||
fi
|
||||
|
||||
echo "Compiling C files..."
|
||||
clang $FLAGS $SANITIZE_FLAGS $SRC src2/main.c -o main
|
||||
|
@ -10,8 +10,6 @@ extern "C" {
|
||||
|
||||
typedef uint16_t StrName;
|
||||
|
||||
#define py_name(name) pk_StrName__map(name)
|
||||
|
||||
uint16_t pk_StrName__map(const char*);
|
||||
uint16_t pk_StrName__map2(c11_string);
|
||||
const char* pk_StrName__rmap(uint16_t index);
|
||||
|
@ -8,45 +8,38 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct pk_TypeInfo{
|
||||
typedef struct pk_TypeInfo {
|
||||
py_Name name;
|
||||
py_Type base;
|
||||
|
||||
py_TValue self; // the type object itself
|
||||
py_TValue self;
|
||||
py_TValue module; // the module where the type is defined
|
||||
bool subclass_enabled;
|
||||
|
||||
void (*dtor)(void*);
|
||||
void (*gc_mark)(void*);
|
||||
|
||||
c11_vector/*T=StrName*/ annotated_fields;
|
||||
c11_vector /*T=StrName*/ annotated_fields;
|
||||
|
||||
py_CFunction on_end_subclass; // backdoor for enum module
|
||||
|
||||
/* Magic Caches */
|
||||
/* Magic Slots */
|
||||
py_TValue magic[64];
|
||||
// // unary operators
|
||||
// py_CFunction m__repr__, m__str__, m__hash__, m__len__;
|
||||
// py_CFunction m__iter__, m__next__, m__neg__, m__invert__;
|
||||
// // binary operators
|
||||
// py_CFunction m__eq__, m__lt__, m__le__, m__gt__, m__ge__, m__contains__;
|
||||
// py_CFunction m__add__, m__sub__, m__mul__, m__truediv__, m__floordiv__;
|
||||
// py_CFunction m__mod__, m__pow__, m__matmul__;
|
||||
// py_CFunction m__lshift__, m__rshift__, m__and__, m__xor__, m__or__;
|
||||
// // indexer
|
||||
// py_CFunction m__getitem__, m__setitem__, m__delitem__;
|
||||
// // attribute access (internal use only)
|
||||
// py_CFunction m__getattr__, m__setattr__, m__delattr__;
|
||||
} pk_TypeInfo;
|
||||
|
||||
void pk_TypeInfo__ctor(pk_TypeInfo* self, py_Name name, py_Type base, PyObject* obj, const py_TValue* module, bool subclass_enabled);
|
||||
void pk_TypeInfo__ctor(pk_TypeInfo* self,
|
||||
py_Name name,
|
||||
py_Type index,
|
||||
py_Type base,
|
||||
const py_TValue* module,
|
||||
bool subclass_enabled);
|
||||
void pk_TypeInfo__dtor(pk_TypeInfo* self);
|
||||
|
||||
typedef struct pk_VM {
|
||||
Frame* top_frame;
|
||||
|
||||
pk_NameDict modules;
|
||||
c11_vector/*T=pk_TypeInfo*/ types;
|
||||
c11_vector /*T=pk_TypeInfo*/ types;
|
||||
|
||||
py_TValue StopIteration; // a special Exception class
|
||||
py_TValue builtins; // builtins module
|
||||
@ -60,7 +53,6 @@ typedef struct pk_VM {
|
||||
// singleton objects
|
||||
py_TValue True, False, None, NotImplemented, Ellipsis;
|
||||
|
||||
py_Error* last_error;
|
||||
py_TValue last_retval;
|
||||
py_TValue reg[8]; // users' registers
|
||||
|
||||
@ -81,7 +73,7 @@ void pk_VM__pop_frame(pk_VM* self);
|
||||
|
||||
void pk_VM__init_builtins(pk_VM* self);
|
||||
|
||||
typedef enum pk_FrameResult{
|
||||
typedef enum pk_FrameResult {
|
||||
RES_RETURN,
|
||||
RES_CALL,
|
||||
RES_YIELD,
|
||||
@ -90,7 +82,11 @@ typedef enum pk_FrameResult{
|
||||
|
||||
pk_FrameResult pk_VM__run_top_frame(pk_VM* self);
|
||||
|
||||
py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const py_TValue* module, bool subclass_enabled);
|
||||
py_Type pk_VM__new_type(pk_VM* self,
|
||||
const char* name,
|
||||
py_Type base,
|
||||
const py_TValue* module,
|
||||
bool subclass_enabled);
|
||||
|
||||
// type registration
|
||||
py_Type pk_list__register();
|
||||
|
@ -24,9 +24,9 @@ typedef struct py_TValue {
|
||||
union {
|
||||
int64_t _i64;
|
||||
double _f64;
|
||||
PyObject* _obj;
|
||||
void* _ptr;
|
||||
bool _bool;
|
||||
py_CFunction _cfunc;
|
||||
PyObject* _obj;
|
||||
// Vec2
|
||||
};
|
||||
} py_TValue;
|
||||
@ -46,20 +46,10 @@ const static py_Type tp_dict = {19}, tp_property = {20}, tp_star_wrapper = {21};
|
||||
const static py_Type tp_staticmethod = {22}, tp_classmethod = {23};
|
||||
const static py_Type tp_none_type = {24}, tp_not_implemented_type = {25};
|
||||
const static py_Type tp_ellipsis = {26};
|
||||
const static py_Type tp_op_call = {27}, tp_op_yield = {28};
|
||||
const static py_Type tp_syntax_error = {29}, tp_stop_iteration = {30};
|
||||
const static py_Type tp_syntax_error = {27}, tp_stop_iteration = {28};
|
||||
|
||||
extern py_TValue PY_NULL, PY_OP_CALL, PY_OP_YIELD;
|
||||
extern py_TValue PY_NULL;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
SSO types:
|
||||
1. int64_t
|
||||
2. double
|
||||
3. bool (dummy)
|
||||
4. tuple (extra + void*)
|
||||
5. string (extra + void* or buf)
|
||||
*/
|
@ -8,18 +8,27 @@ typedef struct py_TValue py_TValue;
|
||||
typedef struct pk_VM pk_VM;
|
||||
typedef uint16_t py_Name;
|
||||
typedef int16_t py_Type;
|
||||
typedef py_TValue* py_Ref;
|
||||
typedef struct py_Str py_Str;
|
||||
|
||||
typedef struct py_Error {
|
||||
py_Type type;
|
||||
} py_Error;
|
||||
typedef int64_t py_i64;
|
||||
typedef double py_f64;
|
||||
|
||||
/// Generic reference.
|
||||
typedef py_TValue* py_Ref;
|
||||
/// An object reference which has the same lifespan as the object.
|
||||
typedef py_TValue* py_ObjectRef;
|
||||
/// A global reference which has the same lifespan as the VM.
|
||||
typedef py_TValue* py_GlobalRef;
|
||||
/// A specific location in the stack.
|
||||
typedef py_TValue* py_StackRef;
|
||||
/// A temporary reference which has a short or unknown lifespan.
|
||||
typedef py_TValue* py_TmpRef;
|
||||
|
||||
/// Native function signature.
|
||||
/// @param argc number of arguments.
|
||||
/// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument.
|
||||
/// @return true if the function is successful.
|
||||
typedef bool (*py_CFunction)(int argc, py_TValue* argv);
|
||||
typedef bool (*py_CFunction)(int argc, py_StackRef argv);
|
||||
|
||||
typedef enum BindType {
|
||||
BindType_FUNCTION,
|
||||
@ -36,19 +45,20 @@ void py_finalize();
|
||||
/// Run a simple source string. Do not change the stack.
|
||||
bool py_exec(const char*);
|
||||
/// Eval a simple expression.
|
||||
/// The result will be set to `vm->last_retval`.
|
||||
/// The result will be set to `py_retval()`.
|
||||
bool py_eval(const char*);
|
||||
|
||||
/************* Values Creation *************/
|
||||
void py_newint(py_Ref, int64_t);
|
||||
void py_newfloat(py_Ref, double);
|
||||
void py_newint(py_Ref, py_i64);
|
||||
void py_newfloat(py_Ref, py_f64);
|
||||
void py_newbool(py_Ref, bool);
|
||||
void py_newstr(py_Ref, const char*);
|
||||
void py_newstrn(py_Ref, const char*, int);
|
||||
void py_newStr_(py_Ref, py_Str);
|
||||
// void py_newfstr(py_Ref, const char*, ...);
|
||||
void py_newbytes(py_Ref, const unsigned char*, int);
|
||||
void py_newnone(py_Ref);
|
||||
void py_newnotimplemented(py_Ref out);
|
||||
void py_newellipsis(py_Ref out);
|
||||
void py_newnull(py_Ref);
|
||||
|
||||
/// Create a tuple with n UNINITIALIZED elements.
|
||||
@ -60,6 +70,10 @@ void py_newlist(py_Ref);
|
||||
/// You should initialize all elements before using it.
|
||||
void py_newlistn(py_Ref, int n);
|
||||
|
||||
py_Name py_name(const char*);
|
||||
const char* py_name2str(py_Name);
|
||||
bool py_ismagicname(py_Name);
|
||||
|
||||
// opaque types
|
||||
void py_newdict(py_Ref);
|
||||
void py_newset(py_Ref);
|
||||
@ -76,8 +90,6 @@ void py_newfunction2(py_Ref out,
|
||||
// old style argc-based function
|
||||
void py_newnativefunc(py_Ref out, py_CFunction);
|
||||
|
||||
void py_newnotimplemented(py_Ref out);
|
||||
|
||||
/// Create a new object.
|
||||
/// @param out output reference.
|
||||
/// @param type type of the object.
|
||||
@ -85,10 +97,11 @@ void py_newnotimplemented(py_Ref out);
|
||||
/// @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);
|
||||
/************* Type Cast *************/
|
||||
int64_t py_toint(const py_Ref);
|
||||
double py_tofloat(const py_Ref);
|
||||
bool py_castfloat(const py_Ref, double* out);
|
||||
py_i64 py_toint(const py_Ref);
|
||||
py_f64 py_tofloat(const py_Ref);
|
||||
bool py_castfloat(const py_Ref, py_f64* out);
|
||||
bool py_tobool(const py_Ref);
|
||||
py_Type py_totype(const py_Ref);
|
||||
const char* py_tostr(const py_Ref);
|
||||
const char* py_tostrn(const py_Ref, int* size);
|
||||
|
||||
@ -104,17 +117,19 @@ bool py_isinstance(const py_Ref obj, py_Type type);
|
||||
bool py_issubclass(py_Type derived, py_Type base);
|
||||
|
||||
/************* References *************/
|
||||
#define py_offset(p, i) (py_Ref)((char*)p + ((i) << 4))
|
||||
|
||||
#define TypeError(x) false
|
||||
#define py_arg(i) (py_Ref)((char*)argv + ((i) << 4))
|
||||
#define py_arg(i) py_offset(argv, i)
|
||||
#define py_checkargc(n) \
|
||||
if(argc != n) return TypeError()
|
||||
|
||||
py_Ref py_tpmagic(py_Type type, py_Name name);
|
||||
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
|
||||
py_Ref py_bind(py_Ref obj, const char* sig, py_CFunction f);
|
||||
py_Ref py_bind2(py_Ref obj,
|
||||
py_TmpRef py_bind(py_Ref obj, const char* sig, py_CFunction f);
|
||||
py_TmpRef py_bind2(py_Ref obj,
|
||||
const char* sig,
|
||||
py_CFunction f,
|
||||
BindType bt,
|
||||
@ -127,23 +142,23 @@ void py_bindnativefunc(py_Ref obj, const char* name, py_CFunction f);
|
||||
|
||||
/// Get the reference to the i-th register.
|
||||
/// @lifespan: Permanent.
|
||||
py_Ref py_reg(int i);
|
||||
py_GlobalRef py_reg(int i);
|
||||
|
||||
/// Get the reference of the object's `__dict__`.
|
||||
/// The object must have a `__dict__`.
|
||||
/// Returns a reference to the value or NULL if not found.
|
||||
/// @lifespan: Object.
|
||||
py_Ref py_getdict(const py_Ref self, py_Name name);
|
||||
py_ObjectRef py_getdict(const py_Ref self, py_Name name);
|
||||
void py_setdict(py_Ref self, py_Name name, const py_Ref val);
|
||||
|
||||
/// Get the reference of the i-th slot of the object.
|
||||
/// The object must have slots and `i` must be in range.
|
||||
/// @lifespan: Object.
|
||||
py_Ref py_getslot(const py_Ref self, int i);
|
||||
py_ObjectRef py_getslot(const py_Ref self, int i);
|
||||
void py_setslot(py_Ref self, int i, const py_Ref val);
|
||||
|
||||
py_Ref py_getupvalue(py_Ref argv);
|
||||
void py_setupvalue(py_Ref argv, const py_Ref val);
|
||||
py_TmpRef py_getupvalue(py_StackRef argv);
|
||||
void py_setupvalue(py_StackRef argv, const py_Ref val);
|
||||
|
||||
/// Gets the attribute of the object.
|
||||
bool py_getattr(const py_Ref self, py_Name name, py_Ref out);
|
||||
@ -164,7 +179,7 @@ bool py_delitem(py_Ref self, const py_Ref key);
|
||||
|
||||
/// Perform a binary operation on the stack.
|
||||
/// It assumes `lhs` and `rhs` are already pushed to the stack.
|
||||
/// The result will be set to `vm->last_retval`.
|
||||
/// The result will be set to `py_retval()`.
|
||||
bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop);
|
||||
|
||||
#define py_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__)
|
||||
@ -188,7 +203,7 @@ void py_assign(py_Ref dst, const py_Ref src);
|
||||
/************* Stack Operations *************/
|
||||
/// Returns a reference to the i-th object from the top of the stack.
|
||||
/// i should be negative, e.g. (-1) means TOS.
|
||||
py_Ref py_peek(int i);
|
||||
py_StackRef py_peek(int i);
|
||||
/// Pushes the object to the stack.
|
||||
void py_push(const py_Ref src);
|
||||
/// Pops an object from the stack.
|
||||
@ -196,7 +211,7 @@ void py_pop();
|
||||
/// Shrink the stack by n.
|
||||
void py_shrink(int n);
|
||||
/// Get a temporary variable from the stack and returns the reference to it.
|
||||
py_Ref py_pushtmp();
|
||||
py_StackRef py_pushtmp();
|
||||
/// Free n temporary variable.
|
||||
#define py_poptmp(n) py_shrink(n)
|
||||
|
||||
@ -207,15 +222,18 @@ py_Ref py_pushtmp();
|
||||
#define py_duptop() py_push(py_peek(-1))
|
||||
#define py_dupsecond() py_push(py_peek(-2))
|
||||
/************* Modules *************/
|
||||
py_Ref py_newmodule(const char* name, const char* package);
|
||||
py_Ref py_getmodule(const char* name);
|
||||
py_TmpRef py_newmodule(const char* name, const char* package);
|
||||
py_TmpRef py_getmodule(const char* name);
|
||||
|
||||
/// Import a module.
|
||||
bool py_import(const char* name, py_Ref out);
|
||||
/// The result will be set to `py_retval()`.
|
||||
bool py_import(const char* name);
|
||||
|
||||
/************* Errors *************/
|
||||
py_Error* py_lasterror();
|
||||
void py_Error__print(py_Error*);
|
||||
/// Print the last error to the console.
|
||||
void py_printexc();
|
||||
/// Format the last error to a string.
|
||||
void py_formatexc(char* out);
|
||||
|
||||
/************* Operators *************/
|
||||
/// Equivalent to `bool(val)`.
|
||||
@ -230,48 +248,48 @@ int py_lt(const py_Ref, const py_Ref);
|
||||
int py_ge(const py_Ref, const py_Ref);
|
||||
int py_gt(const py_Ref, const py_Ref);
|
||||
|
||||
bool py_hash(const py_Ref, int64_t* out);
|
||||
bool py_hash(const py_Ref, py_i64* out);
|
||||
|
||||
/// Compare two objects without using magic methods.
|
||||
/// Python equivalent to `lhs is rhs`.
|
||||
bool py_isidentical(const py_Ref, const py_Ref);
|
||||
|
||||
/// A stack operation that calls a function.
|
||||
/// It assumes `argc + kwargc` arguments are already pushed to the stack.
|
||||
/// The result will be set to `vm->last_retval`.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack size will be reduced by `argc + kwargc`.
|
||||
bool pk_vectorcall(int argc, int kwargc, bool op_call);
|
||||
/// Call a function.
|
||||
/// It prepares the stack and then performs a `vectorcall(argc, 0, false)`.
|
||||
/// The result will be set to `vm->last_retval`.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack remains unchanged after the operation.
|
||||
bool py_call(py_Ref f, int argc, py_Ref argv);
|
||||
/// Call a non-magic method.
|
||||
/// It prepares the stack and then performs a `vectorcall(argc+1, 0, false)`.
|
||||
/// The result will be set to `vm->last_retval`.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack remains unchanged after the operation.
|
||||
bool py_callmethod(py_Ref self, py_Name, int argc, py_Ref argv);
|
||||
/// Call a magic method.
|
||||
/// The result will be set to `vm->last_retval`.
|
||||
/// 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);
|
||||
|
||||
#define py_repr(self) py_callmagic(__repr__, 1, self)
|
||||
#define py_str(self) py_callmagic(__str__, 1, self)
|
||||
|
||||
/// The return value of the most recent vectorcall.
|
||||
py_Ref py_lastretval();
|
||||
/// The return value of the most recent call.
|
||||
py_GlobalRef py_retval();
|
||||
|
||||
#define py_isnull(self) ((self)->type == 0)
|
||||
|
||||
/* tuple */
|
||||
|
||||
// unchecked functions, if self is not a tuple, the behavior is undefined
|
||||
py_Ref py_tuple__getitem(const py_Ref self, int i);
|
||||
py_ObjectRef py_tuple__getitem(const py_Ref self, int i);
|
||||
void py_tuple__setitem(py_Ref self, int i, const py_Ref val);
|
||||
int py_tuple__len(const py_Ref self);
|
||||
|
||||
// unchecked functions, if self is not a list, the behavior is undefined
|
||||
py_Ref py_list__getitem(const py_Ref self, int i);
|
||||
py_ObjectRef py_list__getitem(const py_Ref self, int i);
|
||||
void py_list__setitem(py_Ref self, int i, const py_Ref val);
|
||||
void py_list__delitem(py_Ref self, int i);
|
||||
int py_list__len(const py_Ref self);
|
||||
@ -286,11 +304,11 @@ pk_TypeInfo* pk_tpinfo(const py_Ref self);
|
||||
/// Search the magic method from the given type to the base type.
|
||||
/// Returns the reference or NULL if not found.
|
||||
/// @lifespan: Permanent.
|
||||
py_Ref py_tpfindmagic(py_Type, py_Name name);
|
||||
py_GlobalRef py_tpfindmagic(py_Type, py_Name name);
|
||||
|
||||
/// Get the type object of the given type.
|
||||
/// @lifespan: Permanent.
|
||||
py_Ref py_tpobject(py_Type type);
|
||||
py_GlobalRef py_tpobject(py_Type type);
|
||||
|
||||
#define MAGIC_METHOD(x) extern uint16_t x;
|
||||
#include "pocketpy/xmacros/magics.h"
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "pocketpy/common/smallmap.h"
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@ -80,6 +81,18 @@ c11_string pk_StrName__rmap2(uint16_t index) {
|
||||
return (c11_string){p, strlen(p)};
|
||||
}
|
||||
|
||||
py_Name py_name(const char* name) {
|
||||
return pk_StrName__map(name);
|
||||
}
|
||||
|
||||
const char* py_name2str(py_Name name) {
|
||||
return pk_StrName__rmap(name);
|
||||
}
|
||||
|
||||
bool py_ismagicname(py_Name name){
|
||||
return name <= __missing__;
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
#define MAGIC_METHOD(x) uint16_t x;
|
||||
#include "pocketpy/xmacros/magics.h"
|
||||
|
@ -13,6 +13,9 @@ int NameError(py_Name name) { return -1; }
|
||||
|
||||
static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
|
||||
|
||||
// private
|
||||
void py_newStr_(py_Ref, py_Str);
|
||||
|
||||
#define DISPATCH() \
|
||||
do { \
|
||||
frame->ip++; \
|
||||
@ -665,11 +668,7 @@ static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// eq/ne op never fails
|
||||
if(op == __eq__ || op == __ne__) {
|
||||
self->last_retval = (op == __eq__) ? self->False : self->True;
|
||||
return true;
|
||||
}
|
||||
// eq/ne op never fails due to object.__eq__
|
||||
return BinaryOptError(byte.arg);
|
||||
}
|
||||
|
||||
|
@ -45,13 +45,13 @@
|
||||
if(py_isint(&argv[1])) { \
|
||||
int64_t lhs = py_toint(&argv[0]); \
|
||||
int64_t rhs = py_toint(&argv[1]); \
|
||||
rint(py_lastretval(), lhs op rhs); \
|
||||
rint(py_retval(), lhs op rhs); \
|
||||
} else if(py_isfloat(&argv[1])) { \
|
||||
int64_t lhs = py_toint(&argv[0]); \
|
||||
double rhs = py_tofloat(&argv[1]); \
|
||||
rfloat(py_lastretval(), lhs op rhs); \
|
||||
rfloat(py_retval(), lhs op rhs); \
|
||||
} else { \
|
||||
py_newnotimplemented(py_lastretval()); \
|
||||
py_newnotimplemented(py_retval()); \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
@ -60,9 +60,9 @@
|
||||
double lhs = py_tofloat(&argv[0]); \
|
||||
double rhs; \
|
||||
if(py_castfloat(&argv[1], &rhs)) { \
|
||||
rfloat(py_lastretval(), lhs op rhs); \
|
||||
rfloat(py_retval(), lhs op rhs); \
|
||||
} else { \
|
||||
py_newnotimplemented(py_lastretval()); \
|
||||
py_newnotimplemented(py_retval()); \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
@ -83,14 +83,14 @@ DEF_NUM_BINARY_OP(__ge__, >=, py_newbool, py_newbool)
|
||||
static bool _py_int__neg__(int argc, py_Ref argv) {
|
||||
py_checkargc(1);
|
||||
int64_t val = py_toint(&argv[0]);
|
||||
py_newint(py_lastretval(), -val);
|
||||
py_newint(py_retval(), -val);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _py_float__neg__(int argc, py_Ref argv) {
|
||||
py_checkargc(1);
|
||||
double val = py_tofloat(&argv[0]);
|
||||
py_newfloat(py_lastretval(), -val);
|
||||
py_newfloat(py_retval(), -val);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -99,9 +99,9 @@ static bool _py_int__truediv__(int argc, py_Ref argv) {
|
||||
int64_t lhs = py_toint(&argv[0]);
|
||||
double rhs;
|
||||
if(py_castfloat(&argv[1], &rhs)) {
|
||||
py_newfloat(py_lastretval(), lhs / rhs);
|
||||
py_newfloat(py_retval(), lhs / rhs);
|
||||
} else {
|
||||
py_newnotimplemented(py_lastretval());
|
||||
py_newnotimplemented(py_retval());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -111,9 +111,9 @@ static bool _py_float__truediv__(int argc, py_Ref argv) {
|
||||
double lhs = py_tofloat(&argv[0]);
|
||||
double rhs;
|
||||
if(py_castfloat(&argv[1], &rhs)) {
|
||||
py_newfloat(py_lastretval(), lhs / rhs);
|
||||
py_newfloat(py_retval(), lhs / rhs);
|
||||
} else {
|
||||
py_newnotimplemented(py_lastretval());
|
||||
py_newnotimplemented(py_retval());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -129,7 +129,7 @@ static bool _py_number__pow__(int argc, py_Ref argv) {
|
||||
if(lhs == 0) {
|
||||
return ZeroDivisionError("0.0 cannot be raised to a negative power");
|
||||
} else {
|
||||
py_newfloat(py_lastretval(), pow(lhs, rhs));
|
||||
py_newfloat(py_retval(), pow(lhs, rhs));
|
||||
}
|
||||
} else {
|
||||
int64_t ret = 1;
|
||||
@ -138,15 +138,15 @@ static bool _py_number__pow__(int argc, py_Ref argv) {
|
||||
lhs *= lhs;
|
||||
rhs >>= 1;
|
||||
}
|
||||
py_newint(py_lastretval(), ret);
|
||||
py_newint(py_retval(), ret);
|
||||
}
|
||||
} else {
|
||||
double lhs, rhs;
|
||||
py_castfloat(&argv[0], &lhs);
|
||||
if(py_castfloat(&argv[1], &rhs)) {
|
||||
py_newfloat(py_lastretval(), pow(lhs, rhs));
|
||||
py_newfloat(py_retval(), pow(lhs, rhs));
|
||||
} else {
|
||||
py_newnotimplemented(py_lastretval());
|
||||
py_newnotimplemented(py_retval());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -158,9 +158,9 @@ static bool _py_int__floordiv__(int argc, py_Ref argv) {
|
||||
if(py_isint(&argv[1])) {
|
||||
int64_t rhs = py_toint(&argv[1]);
|
||||
if(rhs == 0) return -1;
|
||||
py_newint(py_lastretval(), lhs / rhs);
|
||||
py_newint(py_retval(), lhs / rhs);
|
||||
} else {
|
||||
py_newnotimplemented(py_lastretval());
|
||||
py_newnotimplemented(py_retval());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -171,9 +171,9 @@ static bool _py_int__mod__(int argc, py_Ref argv) {
|
||||
if(py_isint(&argv[1])) {
|
||||
int64_t rhs = py_toint(&argv[1]);
|
||||
if(rhs == 0) return ZeroDivisionError("integer division or modulo by zero");
|
||||
py_newint(py_lastretval(), lhs % rhs);
|
||||
py_newint(py_retval(), lhs % rhs);
|
||||
} else {
|
||||
py_newnotimplemented(py_lastretval());
|
||||
py_newnotimplemented(py_retval());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -181,7 +181,7 @@ static bool _py_int__mod__(int argc, py_Ref argv) {
|
||||
static bool _py_int__invert__(int argc, py_Ref argv) {
|
||||
py_checkargc(1);
|
||||
int64_t val = py_toint(&argv[0]);
|
||||
py_newint(py_lastretval(), ~val);
|
||||
py_newint(py_retval(), ~val);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -194,7 +194,7 @@ static bool _py_int__bit_length(int argc, py_Ref argv) {
|
||||
x >>= 1;
|
||||
bits++;
|
||||
}
|
||||
py_newint(py_lastretval(), bits);
|
||||
py_newint(py_retval(), bits);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -204,9 +204,9 @@ static bool _py_int__bit_length(int argc, py_Ref argv) {
|
||||
int64_t lhs = py_toint(&argv[0]); \
|
||||
if(py_isint(&argv[1])) { \
|
||||
int64_t rhs = py_toint(&argv[1]); \
|
||||
py_newint(py_lastretval(), lhs op rhs); \
|
||||
py_newint(py_retval(), lhs op rhs); \
|
||||
} else { \
|
||||
py_newnotimplemented(py_lastretval()); \
|
||||
py_newnotimplemented(py_retval()); \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static unsigned char* pk_default_import_file(const char* path) { return NULL; }
|
||||
|
||||
static void pk_default_stdout(const char* fmt, ...) {
|
||||
@ -23,8 +26,8 @@ static void pk_default_stderr(const char* fmt, ...) {
|
||||
|
||||
void pk_TypeInfo__ctor(pk_TypeInfo* self,
|
||||
py_Name name,
|
||||
py_Type index,
|
||||
py_Type base,
|
||||
PyObject* obj,
|
||||
const py_TValue* module,
|
||||
bool subclass_enabled) {
|
||||
memset(self, 0, sizeof(pk_TypeInfo));
|
||||
@ -32,7 +35,11 @@ void pk_TypeInfo__ctor(pk_TypeInfo* self,
|
||||
self->name = name;
|
||||
self->base = base;
|
||||
|
||||
self->self = PyVar__fromobj(obj);
|
||||
// create type object with __dict__
|
||||
pk_ManagedHeap* heap = &pk_current_vm->heap;
|
||||
PyObject* typeobj = pk_ManagedHeap__new(heap, tp_type, -1, sizeof(py_Type));
|
||||
self->self = PyVar__fromobj(typeobj);
|
||||
|
||||
self->module = module ? *module : PY_NULL;
|
||||
self->subclass_enabled = subclass_enabled;
|
||||
|
||||
@ -56,7 +63,6 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
self->_stdout = pk_default_stdout;
|
||||
self->_stderr = pk_default_stderr;
|
||||
|
||||
self->last_error = NULL;
|
||||
self->last_retval = PY_NULL;
|
||||
|
||||
self->__curr_class = PY_NULL;
|
||||
@ -66,37 +72,9 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
pk_ManagedHeap__ctor(&self->heap, self);
|
||||
ValueStack__ctor(&self->stack);
|
||||
|
||||
self->True = (py_TValue){
|
||||
.type = tp_bool,
|
||||
.is_ptr = true,
|
||||
.extra = 1,
|
||||
._obj = pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 0),
|
||||
};
|
||||
self->False = (py_TValue){
|
||||
.type = tp_bool,
|
||||
.is_ptr = true,
|
||||
.extra = 0,
|
||||
._obj = pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 0),
|
||||
};
|
||||
self->None = (py_TValue){
|
||||
.type = tp_none_type,
|
||||
.is_ptr = true,
|
||||
._obj = pk_ManagedHeap__gcnew(&self->heap, tp_none_type, 0, 0),
|
||||
};
|
||||
self->NotImplemented = (py_TValue){
|
||||
.type = tp_not_implemented_type,
|
||||
.is_ptr = true,
|
||||
._obj = pk_ManagedHeap__gcnew(&self->heap, tp_not_implemented_type, 0, 0),
|
||||
};
|
||||
self->Ellipsis = (py_TValue){
|
||||
.type = tp_ellipsis,
|
||||
.is_ptr = true,
|
||||
._obj = pk_ManagedHeap__gcnew(&self->heap, tp_ellipsis, 0, 0),
|
||||
};
|
||||
|
||||
/* Init Builtin Types */
|
||||
// 0: unused
|
||||
pk_TypeInfo__ctor(c11_vector__emplace(&self->types), 0, 0, NULL, NULL, false);
|
||||
pk_TypeInfo__ctor(c11_vector__emplace(&self->types), 0, 0, 0, NULL, false);
|
||||
#define validate(t, expr) \
|
||||
if(t != (expr)) abort()
|
||||
|
||||
@ -136,14 +114,11 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
pk_VM__new_type(self, "NotImplementedType", tp_object, NULL, false));
|
||||
validate(tp_ellipsis, pk_VM__new_type(self, "ellipsis", tp_object, NULL, false));
|
||||
|
||||
validate(tp_op_call, pk_VM__new_type(self, "__op_call", tp_object, NULL, false));
|
||||
validate(tp_op_yield, pk_VM__new_type(self, "__op_yield", tp_object, NULL, false));
|
||||
|
||||
validate(tp_syntax_error, pk_VM__new_type(self, "SyntaxError", tp_exception, NULL, false));
|
||||
validate(tp_stop_iteration, pk_VM__new_type(self, "StopIteration", tp_exception, NULL, false));
|
||||
#undef validate
|
||||
|
||||
self->StopIteration = c11__at(pk_TypeInfo, &self->types, tp_stop_iteration)->self;
|
||||
self->StopIteration = *py_tpobject(tp_stop_iteration);
|
||||
self->builtins = *py_newmodule("builtins", NULL);
|
||||
|
||||
/* Setup Public Builtin Types */
|
||||
@ -167,7 +142,7 @@ void pk_VM__ctor(pk_VM* self) {
|
||||
for(int i = 0; i < PK_ARRAY_COUNT(public_types); i++) {
|
||||
py_Type t = public_types[i];
|
||||
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &self->types, t);
|
||||
py_setdict(&self->builtins, ti->name, &ti->self);
|
||||
py_setdict(&self->builtins, ti->name, py_tpobject(t));
|
||||
}
|
||||
py_setdict(&self->builtins, py_name("NotImplemented"), &self->NotImplemented);
|
||||
|
||||
@ -207,13 +182,10 @@ py_Type pk_VM__new_type(pk_VM* self,
|
||||
py_Type base,
|
||||
const py_TValue* module,
|
||||
bool subclass_enabled) {
|
||||
py_Type type = self->types.count;
|
||||
py_Type index = self->types.count;
|
||||
pk_TypeInfo* ti = c11_vector__emplace(&self->types);
|
||||
PyObject* typeobj = pk_ManagedHeap__gcnew(&self->heap, tp_type, -1, sizeof(py_Type));
|
||||
py_Type* value = PyObject__value(typeobj);
|
||||
*value = type;
|
||||
pk_TypeInfo__ctor(ti, py_name(name), base, typeobj, module, subclass_enabled);
|
||||
return type;
|
||||
pk_TypeInfo__ctor(ti, py_name(name), index, base, module, subclass_enabled);
|
||||
return index;
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
|
@ -1,6 +1,4 @@
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
py_TValue PY_NULL = {.type=0, .is_ptr=false, .extra=0, ._i64=0};
|
||||
py_TValue PY_OP_CALL = {.type=27, .is_ptr=false, .extra=0, ._i64=0};
|
||||
py_TValue PY_OP_YIELD = {.type=28, .is_ptr=false, .extra=0, ._i64=0};
|
||||
|
||||
|
@ -29,7 +29,13 @@ bool py_castfloat(const py_Ref self, double* out){
|
||||
|
||||
bool py_tobool(const py_Ref self){
|
||||
assert(self->type == tp_bool);
|
||||
return self->extra;
|
||||
return self->_bool;
|
||||
}
|
||||
|
||||
py_Type py_totype(const py_Ref self){
|
||||
assert(self->type == tp_type);
|
||||
py_Type* ud = py_touserdata(self);
|
||||
return *ud;
|
||||
}
|
||||
|
||||
const char* py_tostr(const py_Ref self){
|
||||
|
@ -1,15 +0,0 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
|
||||
py_Error* py_lasterror(){
|
||||
return pk_current_vm->last_error;
|
||||
}
|
||||
|
||||
void py_Error__print(py_Error* self){
|
||||
abort();
|
||||
}
|
||||
|
@ -1,9 +1,20 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
bool py_isidentical(const py_Ref lhs, const py_Ref rhs) {
|
||||
if(lhs->is_ptr && rhs->is_ptr) { return lhs->_obj == rhs->_obj; }
|
||||
return false;
|
||||
if(lhs->type != rhs->type) return false;
|
||||
switch(lhs->type){
|
||||
case tp_int: return lhs->_i64 == rhs->_i64;
|
||||
case tp_float: return lhs->_f64 == rhs->_f64;
|
||||
case tp_bool: return lhs->_bool == rhs->_bool;
|
||||
case tp_nativefunc: return lhs->_cfunc == rhs->_cfunc;
|
||||
case tp_none_type: return true;
|
||||
case tp_not_implemented_type: return true;
|
||||
case tp_ellipsis: return true;
|
||||
// fallback to pointer comparison
|
||||
default: return lhs->is_ptr && rhs->is_ptr && lhs->_obj == rhs->_obj;
|
||||
}
|
||||
}
|
||||
|
||||
int py_bool(const py_Ref val) { return 1; }
|
||||
@ -26,7 +37,7 @@ bool py_delitem(py_Ref self, const py_Ref key) { return -1; }
|
||||
int py_##name(const py_Ref lhs, const py_Ref rhs) { \
|
||||
bool ok = py_binaryop(lhs, rhs, op, rop); \
|
||||
if(!ok) return -1; \
|
||||
return py_tobool(py_lastretval()); \
|
||||
return py_tobool(py_retval()); \
|
||||
}
|
||||
|
||||
COMPARE_OP_IMPL(eq, __eq__, __eq__)
|
||||
|
@ -10,11 +10,20 @@ py_Ref py_reg(int i){
|
||||
|
||||
py_Ref py_getdict(const py_Ref self, py_Name name){
|
||||
assert(self && self->is_ptr);
|
||||
if(self->type == tp_type && py_ismagicname(name)){
|
||||
py_Type* ud = py_touserdata(self);
|
||||
py_Ref slot = py_tpmagic(*ud, name);
|
||||
return py_isnull(slot) ? NULL : slot;
|
||||
}
|
||||
return pk_NameDict__try_get(PyObject__dict(self->_obj), name);
|
||||
}
|
||||
|
||||
void py_setdict(py_Ref self, py_Name name, const py_Ref val){
|
||||
assert(self && self->is_ptr);
|
||||
if(self->type == tp_type && py_ismagicname(name)){
|
||||
py_Type* ud = py_touserdata(self);
|
||||
*py_tpmagic(*ud, name) = *val;
|
||||
}
|
||||
pk_NameDict__set(PyObject__dict(self->_obj), name, *val);
|
||||
}
|
||||
|
||||
|
@ -17,10 +17,29 @@ void py_newfloat(py_Ref out, double val) {
|
||||
}
|
||||
|
||||
void py_newbool(py_Ref out, bool val) {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
*out = val ? vm->True : vm->False;
|
||||
out->type = tp_bool;
|
||||
out->is_ptr = false;
|
||||
out->_bool = val;
|
||||
}
|
||||
|
||||
void py_newnone(py_Ref out) {
|
||||
out->type = tp_none_type;
|
||||
out->is_ptr = false;
|
||||
}
|
||||
|
||||
void py_newnotimplemented(py_Ref out) {
|
||||
out->type = tp_not_implemented_type;
|
||||
out->is_ptr = false;
|
||||
}
|
||||
|
||||
void py_newellipsis(py_Ref out) {
|
||||
out->type = tp_ellipsis;
|
||||
out->is_ptr = false;
|
||||
}
|
||||
|
||||
|
||||
void py_newnull(py_Ref out) { out->type = 0; }
|
||||
|
||||
void py_newstr(py_Ref out, const char* data) {
|
||||
pk_ManagedHeap* heap = &pk_current_vm->heap;
|
||||
PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_str, 0, sizeof(py_Str));
|
||||
@ -61,13 +80,6 @@ void py_newbytes(py_Ref out, const unsigned char* data, int size) {
|
||||
out->_obj = obj;
|
||||
}
|
||||
|
||||
void py_newnone(py_Ref out) {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
*out = vm->None;
|
||||
}
|
||||
|
||||
void py_newnull(py_Ref out) { out->type = 0; }
|
||||
|
||||
void py_newfunction(py_Ref out, py_CFunction f, const char* sig) {
|
||||
py_newfunction2(out, f, sig, BindType_FUNCTION, NULL, NULL);
|
||||
}
|
||||
@ -101,11 +113,6 @@ void py_bindnativefunc(py_Ref obj, const char *name, py_CFunction f){
|
||||
py_setdict(obj, py_name(name), &tmp);
|
||||
}
|
||||
|
||||
void py_newnotimplemented(py_Ref out) {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
*out = vm->NotImplemented;
|
||||
}
|
||||
|
||||
void py_newslice(py_Ref out, const py_Ref start, const py_Ref stop, const py_Ref step) {
|
||||
py_newobject(out, tp_slice, 3, 0);
|
||||
py_setslot(out, 0, start);
|
||||
|
@ -50,7 +50,7 @@ bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) { return -1
|
||||
|
||||
bool pk_vectorcall(int argc, int kwargc, bool op_call) { return -1; }
|
||||
|
||||
py_Ref py_lastretval() { return &pk_current_vm->last_retval; }
|
||||
py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
||||
|
||||
bool py_getunboundmethod(const py_Ref self,
|
||||
py_Name name,
|
||||
@ -66,7 +66,7 @@ pk_TypeInfo* pk_tpinfo(const py_Ref self) {
|
||||
}
|
||||
|
||||
py_Ref py_tpfindmagic(py_Type t, py_Name name) {
|
||||
assert(name < 64);
|
||||
assert(py_ismagicname(name));
|
||||
pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data;
|
||||
do {
|
||||
py_Ref f = &types[t].magic[name];
|
||||
@ -77,7 +77,7 @@ py_Ref py_tpfindmagic(py_Type t, py_Name name) {
|
||||
}
|
||||
|
||||
py_Ref py_tpmagic(py_Type type, py_Name name) {
|
||||
assert(name < 64);
|
||||
assert(py_ismagicname(name));
|
||||
pk_VM* vm = pk_current_vm;
|
||||
return &c11__at(pk_TypeInfo, &vm->types, type)->magic[name];
|
||||
}
|
||||
@ -89,8 +89,9 @@ py_Ref py_tpobject(py_Type type) {
|
||||
|
||||
bool py_callmagic(py_Name name, int argc, py_Ref argv) {
|
||||
assert(argc >= 1);
|
||||
assert(py_ismagicname(name));
|
||||
py_Ref tmp = py_tpfindmagic(argv->type, name);
|
||||
if(!tmp) return TypeError(name);
|
||||
if(tmp->type == tp_nativefunc) { return tmp->_cfunc(argc, argv); }
|
||||
if(tmp->type == tp_nativefunc) return tmp->_cfunc(argc, argv);
|
||||
return py_call(tmp, argc, argv);
|
||||
}
|
@ -30,7 +30,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
if(py_eval(source)) {
|
||||
// handle the result
|
||||
bool _L0 = py_tobool(py_lastretval());
|
||||
bool _L0 = py_tobool(py_retval());
|
||||
printf("%d\n", _L0);
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
bool ok = py_binaryadd(r0, r1);
|
||||
assert(ok);
|
||||
double res = py_tofloat(py_lastretval());
|
||||
double res = py_tofloat(py_retval());
|
||||
printf("%f\n", res);
|
||||
|
||||
py_finalize();
|
||||
|
Loading…
x
Reference in New Issue
Block a user