mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
Compare commits
7 Commits
651bf997fc
...
87bf0c9e7c
Author | SHA1 | Date | |
---|---|---|---|
|
87bf0c9e7c | ||
|
a96173fd6a | ||
|
d8f2808462 | ||
|
3e99f46273 | ||
|
3caca62f2c | ||
|
2eb3eabcc2 | ||
|
3fbbd9fb67 |
@ -64,3 +64,5 @@ int Frame__exit_block(Frame* self, ValueStack*, int);
|
||||
|
||||
UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock);
|
||||
void Frame__set_unwind_target(Frame* self, py_TValue* sp);
|
||||
|
||||
void Frame__gc_mark(Frame* self);
|
@ -5,3 +5,5 @@ void pk__add_module_os();
|
||||
void pk__add_module_math();
|
||||
void pk__add_module_dis();
|
||||
void pk__add_module_random();
|
||||
void pk__add_module_json();
|
||||
void pk__add_module_gc();
|
@ -21,6 +21,7 @@ typedef struct py_TypeInfo {
|
||||
c11_vector /*T=py_Name*/ annotated_fields;
|
||||
|
||||
void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module
|
||||
void (*gc_mark)(void* ud);
|
||||
|
||||
/* Magic Slots */
|
||||
py_TValue magic[64];
|
||||
@ -61,8 +62,9 @@ void VM__pop_frame(VM* self);
|
||||
bool pk__parse_int_slice(py_Ref slice, int length, int* start, int* stop, int* step);
|
||||
bool pk__normalize_index(int* index, int length);
|
||||
|
||||
void pk_list__mark(void* ud, void (*marker)(py_TValue*));
|
||||
void pk_dict__mark(void* ud, void (*marker)(py_TValue*));
|
||||
void pk__mark_value(py_TValue*);
|
||||
void pk__mark_namedict(NameDict*);
|
||||
void pk__tp_set_marker(py_Type type, void (*gc_mark)(void*));
|
||||
|
||||
bool pk_wrapper__self(int argc, py_Ref argv);
|
||||
bool pk_wrapper__NotImplementedError(int argc, py_Ref argv);
|
||||
|
@ -209,15 +209,16 @@ py_GlobalRef py_tpfindmagic(py_Type, py_Name name);
|
||||
/// Search the name from the given type to the base type.
|
||||
/// Return `NULL` if not found.
|
||||
py_GlobalRef py_tpfindname(py_Type, py_Name name);
|
||||
/// Get the magic method from the given type only.
|
||||
/// The returned reference is always valid. However, its value may be `nil`.
|
||||
py_GlobalRef py_tpgetmagic(py_Type 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) PY_RAISE;
|
||||
/// Get the magic method from the given type only.
|
||||
/// The returned reference is always valid. However, its value may be `nil`.
|
||||
py_GlobalRef py_tpmagic(py_Type type, py_Name name);
|
||||
|
||||
/// Check if the object is an instance of the given type.
|
||||
/// Raise `TypeError` if the check fails.
|
||||
@ -287,7 +288,7 @@ void py_bindfunc(py_Ref obj, const char* name, py_CFunction f);
|
||||
/// @param setter setter function. Use `NULL` if not needed.
|
||||
void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter);
|
||||
|
||||
#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpmagic((type), __magic__), (f))
|
||||
#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpgetmagic((type), __magic__), (f))
|
||||
|
||||
#define PY_CHECK_ARGC(n) \
|
||||
if(argc != n) return TypeError("expected %d arguments, got %d", n, argc)
|
||||
@ -454,6 +455,8 @@ bool py_str(py_Ref val) PY_RAISE;
|
||||
bool py_repr(py_Ref val) PY_RAISE;
|
||||
/// Python equivalent to `len(val)`.
|
||||
bool py_len(py_Ref val) PY_RAISE;
|
||||
/// Python equivalent to `json.dumps(val)`.
|
||||
bool py_json(py_Ref val) PY_RAISE;
|
||||
|
||||
/************* Unchecked Functions *************/
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import json
|
||||
from c import struct
|
||||
import builtins
|
||||
|
||||
_BASIC_TYPES = [int, float, str, bool, type(None)]
|
||||
@ -142,7 +141,8 @@ class _Unpickler:
|
||||
|
||||
# generic object
|
||||
cls = _find_class(o[0])
|
||||
if getattr(cls, '__struct__', False):
|
||||
# if getattr(cls, '__struct__', False):
|
||||
if False:
|
||||
inst = cls.fromstruct(struct.fromhex(o[1]))
|
||||
self.tag(index, inst)
|
||||
return inst
|
||||
|
File diff suppressed because one or more lines are too long
@ -909,6 +909,13 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
base = py_totype(TOP());
|
||||
}
|
||||
POP();
|
||||
|
||||
py_TypeInfo* base_ti = c11__at(py_TypeInfo, &self->types, base);
|
||||
if(base_ti->is_sealed){
|
||||
TypeError("type '%t' is not an acceptable base type", base);
|
||||
goto __ERROR;
|
||||
}
|
||||
|
||||
py_Type type =
|
||||
pk_newtype(py_name2str(name), base, frame->module, NULL, true, false);
|
||||
PUSH(py_tpobject(type));
|
||||
@ -1027,7 +1034,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
py_TValue* tmp = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
||||
const char* string = py_tostr(tmp);
|
||||
// TODO: optimize this
|
||||
if(!py_exec(string, "<eval>", EVAL_MODE, frame->module)) goto __ERROR;
|
||||
if(!py_exec(string, "<f-string>", EVAL_MODE, frame->module)) goto __ERROR;
|
||||
PUSH(py_retval());
|
||||
DISPATCH();
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
@ -133,6 +134,11 @@ void Frame__set_unwind_target(Frame* self, py_TValue* sp) {
|
||||
}
|
||||
}
|
||||
|
||||
void Frame__gc_mark(Frame *self){
|
||||
pk__mark_value(self->module);
|
||||
CodeObject__gc_mark(self->co);
|
||||
}
|
||||
|
||||
py_TValue* Frame__f_closure_try_get(Frame* self, py_Name name) {
|
||||
if(!self->has_function) return NULL;
|
||||
Function* ud = py_touserdata(self->p0);
|
||||
|
@ -71,9 +71,16 @@ static bool generator__next__(int argc, py_Ref argv) {
|
||||
}
|
||||
}
|
||||
|
||||
static void generator__gc_mark(void* ud){
|
||||
Generator* gen = ud;
|
||||
if(gen->frame) Frame__gc_mark(gen->frame);
|
||||
}
|
||||
|
||||
py_Type pk_generator__register() {
|
||||
py_Type type = pk_newtype("generator", tp_object, NULL, (py_Dtor)Generator__dtor, false, true);
|
||||
|
||||
pk__tp_set_marker(type, generator__gc_mark);
|
||||
|
||||
py_bindmagic(type, __iter__, pk_wrapper__self);
|
||||
py_bindmagic(type, __next__, generator__next__);
|
||||
return type;
|
||||
|
@ -197,6 +197,8 @@ void VM__ctor(VM* self) {
|
||||
pk__add_module_math();
|
||||
pk__add_module_dis();
|
||||
pk__add_module_random();
|
||||
pk__add_module_json();
|
||||
pk__add_module_gc();
|
||||
|
||||
// add python builtins
|
||||
do {
|
||||
@ -311,8 +313,12 @@ py_Type pk_newtype(const char* name,
|
||||
c11_vector* types = &pk_current_vm->types;
|
||||
py_Type index = types->count;
|
||||
py_TypeInfo* ti = c11_vector__emplace(types);
|
||||
py_TypeInfo* base_ti = base ? c11__at(py_TypeInfo, types, base) : NULL;
|
||||
if(base_ti && base_ti->is_sealed){
|
||||
c11__abort("type '%s' is not an acceptable base type", py_name2str(base_ti->name));
|
||||
}
|
||||
py_TypeInfo__ctor(ti, py_name(name), index, base, module ? *module : *py_NIL);
|
||||
if(!dtor && base) { dtor = c11__at(py_TypeInfo, types, base)->dtor; }
|
||||
if(!dtor && base) dtor = base_ti->dtor;
|
||||
ti->dtor = dtor;
|
||||
ti->is_python = is_python;
|
||||
ti->is_sealed = is_sealed;
|
||||
@ -533,10 +539,23 @@ void PyObject__delete(PyObject* self) {
|
||||
|
||||
static void mark_object(PyObject* obj);
|
||||
|
||||
static void mark_value(py_TValue* val) {
|
||||
void pk__mark_value(py_TValue* val) {
|
||||
if(val->is_ptr) mark_object(val->_obj);
|
||||
}
|
||||
|
||||
void pk__mark_namedict(NameDict* dict) {
|
||||
for(int i = 0; i < dict->count; i++) {
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, dict, i);
|
||||
pk__mark_value(&kv->value);
|
||||
}
|
||||
}
|
||||
|
||||
void pk__tp_set_marker(py_Type type, void (*gc_mark)(void*)) {
|
||||
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
|
||||
assert(ti->gc_mark == NULL);
|
||||
ti->gc_mark = gc_mark;
|
||||
}
|
||||
|
||||
static void mark_object(PyObject* obj) {
|
||||
if(obj->gc_marked) return;
|
||||
obj->gc_marked = true;
|
||||
@ -544,24 +563,19 @@ static void mark_object(PyObject* obj) {
|
||||
if(obj->slots > 0) {
|
||||
py_TValue* p = PyObject__slots(obj);
|
||||
for(int i = 0; i < obj->slots; i++)
|
||||
mark_value(p + i);
|
||||
return;
|
||||
}
|
||||
|
||||
if(obj->slots == -1) {
|
||||
pk__mark_value(p + i);
|
||||
} else if(obj->slots == -1) {
|
||||
NameDict* dict = PyObject__dict(obj);
|
||||
for(int j = 0; j < dict->count; j++) {
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, dict, j);
|
||||
mark_value(&kv->value);
|
||||
}
|
||||
return;
|
||||
pk__mark_namedict(dict);
|
||||
}
|
||||
|
||||
if(obj->type == tp_list) {
|
||||
pk_list__mark(PyObject__userdata(obj), mark_value);
|
||||
} else if(obj->type == tp_dict) {
|
||||
pk_dict__mark(PyObject__userdata(obj), mark_value);
|
||||
}
|
||||
py_TypeInfo* types = c11__at(py_TypeInfo, &pk_current_vm->types, obj->type);
|
||||
if(types->gc_mark) { types->gc_mark(PyObject__userdata(obj)); }
|
||||
}
|
||||
|
||||
void CodeObject__gc_mark(const CodeObject* self) {
|
||||
c11__foreach(py_TValue, &self->consts, i) { pk__mark_value(i); }
|
||||
c11__foreach(FuncDecl_, &self->func_decls, i) { CodeObject__gc_mark(&(*i)->code); }
|
||||
}
|
||||
|
||||
void ManagedHeap__mark(ManagedHeap* self) {
|
||||
@ -573,17 +587,17 @@ void ManagedHeap__mark(ManagedHeap* self) {
|
||||
}
|
||||
// mark value stack
|
||||
for(py_TValue* p = vm->stack.begin; p != vm->stack.end; p++) {
|
||||
mark_value(p);
|
||||
pk__mark_value(p);
|
||||
}
|
||||
// mark frame
|
||||
for(Frame* frame = vm->top_frame; frame; frame = frame->f_back) {
|
||||
mark_value(frame->module);
|
||||
Frame__gc_mark(frame);
|
||||
}
|
||||
// mark vm's registers
|
||||
mark_value(&vm->last_retval);
|
||||
mark_value(&vm->curr_exception);
|
||||
pk__mark_value(&vm->last_retval);
|
||||
pk__mark_value(&vm->curr_exception);
|
||||
for(int i = 0; i < c11__count_array(vm->reg); i++) {
|
||||
mark_value(&vm->reg[i]);
|
||||
pk__mark_value(&vm->reg[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
19
src/modules/gc.c
Normal file
19
src/modules/gc.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
static bool gc_collect(int argc, py_Ref argv){
|
||||
ManagedHeap* heap = &pk_current_vm->heap;
|
||||
int res = ManagedHeap__collect(heap);
|
||||
py_newint(py_retval(), res);
|
||||
return true;
|
||||
}
|
||||
|
||||
void pk__add_module_gc() {
|
||||
py_Ref mod = py_newmodule("gc");
|
||||
|
||||
py_bindfunc(mod, "collect", gc_collect);
|
||||
}
|
111
src/modules/json.c
Normal file
111
src/modules/json.c
Normal file
@ -0,0 +1,111 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include <math.h>
|
||||
|
||||
static bool json_loads(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_str);
|
||||
const char* source = py_tostr(argv);
|
||||
py_TmpRef mod = py_getmodule("json");
|
||||
return py_exec(source, "<json>", EVAL_MODE, mod);
|
||||
}
|
||||
|
||||
static bool json_dumps(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
return py_json(argv);
|
||||
}
|
||||
|
||||
void pk__add_module_json() {
|
||||
py_Ref mod = py_newmodule("json");
|
||||
|
||||
py_setdict(mod, py_name("null"), py_None);
|
||||
py_setdict(mod, py_name("true"), py_True);
|
||||
py_setdict(mod, py_name("false"), py_False);
|
||||
|
||||
py_bindfunc(mod, "loads", json_loads);
|
||||
py_bindfunc(mod, "dumps", json_dumps);
|
||||
}
|
||||
|
||||
static bool json__write_object(c11_sbuf* buf, py_TValue* obj);
|
||||
|
||||
static bool json__write_array(c11_sbuf* buf, py_TValue* arr, int length) {
|
||||
c11_sbuf__write_char(buf, '[');
|
||||
for(int i = 0; i < length; i++) {
|
||||
if(i != 0) c11_sbuf__write_cstr(buf, ", ");
|
||||
bool ok = json__write_object(buf, arr + i);
|
||||
if(!ok) return false;
|
||||
}
|
||||
c11_sbuf__write_char(buf, ']');
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
c11_sbuf* buf;
|
||||
bool first;
|
||||
} json__write_dict_kv_ctx;
|
||||
|
||||
static bool json__write_dict_kv(py_Ref k, py_Ref v, void* ctx_) {
|
||||
json__write_dict_kv_ctx* ctx = ctx_;
|
||||
if(!ctx->first) c11_sbuf__write_cstr(ctx->buf, ", ");
|
||||
ctx->first = false;
|
||||
if(!py_isstr(k)) return TypeError("keys must be strings");
|
||||
c11_sbuf__write_quoted(ctx->buf, py_tosv(k), '"');
|
||||
c11_sbuf__write_char(ctx->buf, ':');
|
||||
return json__write_object(ctx->buf, v);
|
||||
}
|
||||
|
||||
static bool json__write_object(c11_sbuf* buf, py_TValue* obj) {
|
||||
switch(obj->type) {
|
||||
case tp_NoneType: c11_sbuf__write_cstr(buf, "null"); return true;
|
||||
case tp_int: c11_sbuf__write_int(buf, obj->_i64); return true;
|
||||
case tp_float: {
|
||||
if(isnan(obj->_f64)) {
|
||||
c11_sbuf__write_cstr(buf, "NaN");
|
||||
} else if(isinf(obj->_f64)) {
|
||||
c11_sbuf__write_cstr(buf, obj->_f64 < 0 ? "-Infinity" : "Infinity");
|
||||
} else {
|
||||
c11_sbuf__write_f64(buf, obj->_f64, -1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case tp_bool: {
|
||||
c11_sbuf__write_cstr(buf, py_tobool(obj) ? "true" : "false");
|
||||
return true;
|
||||
}
|
||||
case tp_str: {
|
||||
c11_sbuf__write_quoted(buf, py_tosv(obj), '"');
|
||||
return true;
|
||||
}
|
||||
case tp_list: {
|
||||
return json__write_array(buf, py_list_data(obj), py_list_len(obj));
|
||||
}
|
||||
case tp_tuple: {
|
||||
return json__write_array(buf, py_tuple_data(obj), py_tuple_len(obj));
|
||||
}
|
||||
case tp_dict: {
|
||||
c11_sbuf__write_char(buf, '{');
|
||||
json__write_dict_kv_ctx ctx = {.buf = buf, .first = true};
|
||||
bool ok = py_dict_apply(obj, json__write_dict_kv, &ctx);
|
||||
if(!ok) return false;
|
||||
c11_sbuf__write_char(buf, '}');
|
||||
return true;
|
||||
}
|
||||
default: return TypeError("'%t' object is not JSON serializable", obj->type);
|
||||
}
|
||||
}
|
||||
|
||||
bool py_json(py_Ref val) {
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
bool ok = json__write_object(&buf, val);
|
||||
if(!ok){
|
||||
c11_sbuf__dtor(&buf);
|
||||
return false;
|
||||
}
|
||||
c11_sbuf__py_submit(&buf, py_retval());
|
||||
return true;
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
static bool _py_pkpy__next(int argc, py_Ref argv) {
|
||||
static bool pkpy_next(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
int res = py_next(argv);
|
||||
if(res == -1) return false;
|
||||
@ -17,5 +17,5 @@ static bool _py_pkpy__next(int argc, py_Ref argv) {
|
||||
void pk__add_module_pkpy() {
|
||||
py_Ref mod = py_newmodule("pkpy");
|
||||
|
||||
py_bindfunc(mod, "next", _py_pkpy__next);
|
||||
py_bindfunc(mod, "next", pkpy_next);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <stdint.h>
|
||||
|
||||
void Bytecode__set_signed_arg(Bytecode* self, int arg) {
|
||||
|
74
src/public/exec.c
Normal file
74
src/public/exec.c
Normal file
@ -0,0 +1,74 @@
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/objects/sourcedata.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/compiler/compiler.h"
|
||||
|
||||
typedef struct {
|
||||
const char* source;
|
||||
const char* filename;
|
||||
int mode;
|
||||
int is_dynamic;
|
||||
} py_ExecKey;
|
||||
|
||||
static int py_ExecKey__cmp(const py_ExecKey* a, const py_ExecKey* b) {
|
||||
return memcmp(a, b, sizeof(py_ExecKey));
|
||||
}
|
||||
|
||||
static void py_ExecKey__ctor(py_ExecKey* key, const char* source, const char* filename,
|
||||
enum py_CompileMode mode, bool is_dynamic) {
|
||||
key->source = source;
|
||||
key->filename = filename;
|
||||
key->mode = mode;
|
||||
key->is_dynamic = is_dynamic;
|
||||
}
|
||||
|
||||
static bool _py_exec(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
py_Ref module,
|
||||
bool is_dynamic) {
|
||||
VM* vm = pk_current_vm;
|
||||
// py_ExecKey cache_key;
|
||||
// py_ExecKey__ctor(&cache_key, source, filename, mode, is_dynamic);
|
||||
CodeObject co;
|
||||
SourceData_ src = SourceData__rcnew(source, filename, mode, is_dynamic);
|
||||
Error* err = pk_compile(src, &co);
|
||||
if(err) {
|
||||
py_exception(tp_SyntaxError, err->msg);
|
||||
py_BaseException__stpush(&vm->curr_exception, src, err->lineno, NULL);
|
||||
|
||||
PK_DECREF(src);
|
||||
free(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!module) module = &vm->main;
|
||||
|
||||
py_StackRef sp = vm->stack.sp;
|
||||
if(is_dynamic) {
|
||||
// [globals, locals]
|
||||
sp -= 2;
|
||||
}
|
||||
|
||||
Frame* frame = Frame__new(&co, module, sp, sp, false, is_dynamic);
|
||||
VM__push_frame(vm, frame);
|
||||
FrameResult res = VM__run_top_frame(vm);
|
||||
CodeObject__dtor(&co);
|
||||
PK_DECREF(src);
|
||||
if(res == RES_ERROR) return false;
|
||||
if(res == RES_RETURN) return true;
|
||||
c11__unreachedable();
|
||||
}
|
||||
|
||||
bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) {
|
||||
return _py_exec(source, filename, mode, module, false);
|
||||
}
|
||||
|
||||
bool py_execdyn(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) {
|
||||
return _py_exec(source, filename, mode, module, true);
|
||||
}
|
@ -7,8 +7,6 @@
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/compiler/compiler.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
VM* pk_current_vm;
|
||||
|
||||
@ -78,50 +76,6 @@ const char* pk_opname(Opcode op) {
|
||||
return OP_NAMES[op];
|
||||
}
|
||||
|
||||
static bool _py_exec(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
py_Ref module,
|
||||
bool is_dynamic) {
|
||||
VM* vm = pk_current_vm;
|
||||
CodeObject co;
|
||||
SourceData_ src = SourceData__rcnew(source, filename, mode, is_dynamic);
|
||||
Error* err = pk_compile(src, &co);
|
||||
if(err) {
|
||||
py_exception(tp_SyntaxError, err->msg);
|
||||
py_BaseException__stpush(&vm->curr_exception, src, err->lineno, NULL);
|
||||
|
||||
PK_DECREF(src);
|
||||
free(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!module) module = &vm->main;
|
||||
|
||||
py_StackRef sp = vm->stack.sp;
|
||||
if(is_dynamic) {
|
||||
// [globals, locals]
|
||||
sp -= 2;
|
||||
}
|
||||
|
||||
Frame* frame = Frame__new(&co, module, sp, sp, false, is_dynamic);
|
||||
VM__push_frame(vm, frame);
|
||||
FrameResult res = VM__run_top_frame(vm);
|
||||
CodeObject__dtor(&co);
|
||||
PK_DECREF(src);
|
||||
if(res == RES_ERROR) return false;
|
||||
if(res == RES_RETURN) return true;
|
||||
c11__unreachedable();
|
||||
}
|
||||
|
||||
bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) {
|
||||
return _py_exec(source, filename, mode, module, false);
|
||||
}
|
||||
|
||||
bool py_execdyn(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) {
|
||||
return _py_exec(source, filename, mode, module, true);
|
||||
}
|
||||
|
||||
bool py_call(py_Ref f, int argc, py_Ref argv) {
|
||||
if(f->type == tp_nativefunc) {
|
||||
return py_callcfunc(f->_cfunc, argc, argv);
|
||||
@ -220,7 +174,7 @@ py_Ref py_tpfindname(py_Type t, py_Name name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
py_Ref py_tpmagic(py_Type type, py_Name name) {
|
||||
py_Ref py_tpgetmagic(py_Type type, py_Name name) {
|
||||
assert(py_ismagicname(name));
|
||||
VM* vm = pk_current_vm;
|
||||
return &c11__at(py_TypeInfo, &vm->types, type)->magic[name];
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
@ -386,6 +387,7 @@ static bool builtins_ord(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool builtins_globals(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(0);
|
||||
Frame* frame = pk_current_vm->top_frame;
|
||||
if(frame->is_dynamic) {
|
||||
py_assign(py_retval(), &frame->p0[0]);
|
||||
@ -396,6 +398,7 @@ static bool builtins_globals(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool builtins_locals(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(0);
|
||||
Frame* frame = pk_current_vm->top_frame;
|
||||
if(frame->is_dynamic) {
|
||||
py_assign(py_retval(), &frame->p0[1]);
|
||||
@ -501,7 +504,6 @@ static bool function__closure__getter(int argc, py_Ref argv) {
|
||||
Function* ud = py_touserdata(argv);
|
||||
if(!ud->closure) {
|
||||
py_newnone(py_retval());
|
||||
return true;
|
||||
}
|
||||
py_Ref r0 = py_pushtmp();
|
||||
py_Ref retval = py_pushtmp();
|
||||
@ -520,10 +522,18 @@ static bool function__closure__getter(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void function__gc_mark(void* ud) {
|
||||
Function* func = ud;
|
||||
if(func->closure) pk__mark_namedict(func->closure);
|
||||
CodeObject__gc_mark(&func->decl->code);
|
||||
}
|
||||
|
||||
py_Type pk_function__register() {
|
||||
py_Type type =
|
||||
pk_newtype("function", tp_object, NULL, (void (*)(void*))Function__dtor, false, true);
|
||||
|
||||
pk__tp_set_marker(type, function__gc_mark);
|
||||
|
||||
py_bindproperty(type, "__closure__", function__closure__getter, NULL);
|
||||
return type;
|
||||
}
|
||||
|
@ -433,9 +433,21 @@ static bool dict_values(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dict__gc_mark(void* ud) {
|
||||
Dict* self = ud;
|
||||
for(int i = 0; i < self->entries.count; i++) {
|
||||
DictEntry* entry = c11__at(DictEntry, &self->entries, i);
|
||||
if(py_isnil(&entry->key)) continue;
|
||||
pk__mark_value(&entry->key);
|
||||
pk__mark_value(&entry->val);
|
||||
}
|
||||
}
|
||||
|
||||
py_Type pk_dict__register() {
|
||||
py_Type type = pk_newtype("dict", tp_object, NULL, (void (*)(void*))Dict__dtor, false, false);
|
||||
|
||||
pk__tp_set_marker(type, dict__gc_mark);
|
||||
|
||||
py_bindmagic(type, __new__, dict__new__);
|
||||
py_bindmagic(type, __init__, dict__init__);
|
||||
py_bindmagic(type, __getitem__, dict__getitem__);
|
||||
@ -532,13 +544,3 @@ bool py_dict_apply(py_Ref self, bool (*f)(py_Ref, py_Ref, void*), void* ctx) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void pk_dict__mark(void* ud, void (*marker)(py_TValue*)) {
|
||||
Dict* self = ud;
|
||||
for(int i = 0; i < self->entries.count; i++) {
|
||||
DictEntry* entry = c11__at(DictEntry, &self->entries, i);
|
||||
if(py_isnil(&entry->key)) continue;
|
||||
marker(&entry->key);
|
||||
marker(&entry->val);
|
||||
}
|
||||
}
|
@ -106,7 +106,7 @@ py_Type pk_BaseException__register() {
|
||||
}
|
||||
|
||||
py_Type pk_Exception__register() {
|
||||
py_Type type = pk_newtype("Exception", tp_BaseException, NULL, NULL, false, true);
|
||||
py_Type type = pk_newtype("Exception", tp_BaseException, NULL, NULL, false, false);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ int py_list_len(py_Ref self) {
|
||||
return userdata->count;
|
||||
}
|
||||
|
||||
void py_list_swap(py_Ref self, int i, int j){
|
||||
void py_list_swap(py_Ref self, int i, int j) {
|
||||
py_TValue* data = py_list_data(self);
|
||||
py_TValue tmp = data[i];
|
||||
data[i] = data[j];
|
||||
@ -408,10 +408,19 @@ static bool list__contains__(int argc, py_Ref argv) {
|
||||
return pk_arraycontains(py_arg(0), py_arg(1));
|
||||
}
|
||||
|
||||
static void list__gc_mark(void* ud) {
|
||||
List* self = ud;
|
||||
for(int i = 0; i < self->count; i++) {
|
||||
pk__mark_value(c11__at(py_TValue, self, i));
|
||||
}
|
||||
}
|
||||
|
||||
py_Type pk_list__register() {
|
||||
py_Type type =
|
||||
pk_newtype("list", tp_object, NULL, (void (*)(void*))c11_vector__dtor, false, true);
|
||||
|
||||
pk__tp_set_marker(type, list__gc_mark);
|
||||
|
||||
py_bindmagic(type, __len__, list__len__);
|
||||
py_bindmagic(type, __eq__, list__eq__);
|
||||
py_bindmagic(type, __ne__, list__ne__);
|
||||
@ -443,10 +452,3 @@ py_Type pk_list__register() {
|
||||
py_setdict(py_tpobject(type), __hash__, py_None);
|
||||
return type;
|
||||
}
|
||||
|
||||
void pk_list__mark(void* ud, void (*marker)(py_TValue*)) {
|
||||
List* self = ud;
|
||||
for(int i = 0; i < self->count; i++) {
|
||||
marker(c11__at(py_TValue, self, i));
|
||||
}
|
||||
}
|
@ -46,9 +46,9 @@ static bool object__repr__(int argc, py_Ref argv) {
|
||||
|
||||
static bool object__dict__getter(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
if(argv->is_ptr && argv->_obj->slots == -1){
|
||||
if(argv->is_ptr && argv->_obj->slots == -1) {
|
||||
pk_mappingproxy__namedict(py_retval(), argv);
|
||||
}else{
|
||||
} else {
|
||||
py_newnone(py_retval());
|
||||
}
|
||||
return true;
|
||||
@ -74,9 +74,9 @@ static bool type__base__getter(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
py_Type type = py_totype(argv);
|
||||
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
|
||||
if(ti->base){
|
||||
if(ti->base) {
|
||||
py_assign(py_retval(), py_tpobject(ti->base));
|
||||
}else{
|
||||
} else {
|
||||
py_newnone(py_retval());
|
||||
}
|
||||
return true;
|
||||
@ -90,6 +90,11 @@ static bool type__name__getter(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool type__getitem__(int argc, py_Ref argv) {
|
||||
py_assign(py_retval(), argv);
|
||||
return true;
|
||||
}
|
||||
|
||||
void pk_object__register() {
|
||||
// TODO: use staticmethod
|
||||
py_bindmagic(tp_object, __new__, object__new__);
|
||||
@ -102,6 +107,7 @@ void pk_object__register() {
|
||||
|
||||
py_bindmagic(tp_type, __repr__, type__repr__);
|
||||
py_bindmagic(tp_type, __new__, type__new__);
|
||||
py_bindmagic(tp_type, __getitem__, type__getitem__);
|
||||
|
||||
py_bindproperty(tp_type, "__base__", type__base__getter, NULL);
|
||||
py_bindproperty(tp_type, "__name__", type__name__getter, NULL);
|
||||
|
@ -14,7 +14,7 @@ py_Ref py_getdict(py_Ref self, py_Name name) {
|
||||
return NameDict__try_get(PyObject__dict(self->_obj), name);
|
||||
} else {
|
||||
py_Type* ud = py_touserdata(self);
|
||||
py_Ref slot = py_tpmagic(*ud, name);
|
||||
py_Ref slot = py_tpgetmagic(*ud, name);
|
||||
return py_isnil(slot) ? NULL : slot;
|
||||
}
|
||||
}
|
||||
@ -25,7 +25,7 @@ void py_setdict(py_Ref self, py_Name name, py_Ref val) {
|
||||
NameDict__set(PyObject__dict(self->_obj), name, *val);
|
||||
} else {
|
||||
py_Type* ud = py_touserdata(self);
|
||||
*py_tpmagic(*ud, name) = *val;
|
||||
*py_tpgetmagic(*ud, name) = *val;
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ bool py_deldict(py_Ref self, py_Name name) {
|
||||
|
||||
} else {
|
||||
py_Type* ud = py_touserdata(self);
|
||||
py_newnil(py_tpmagic(*ud, name));
|
||||
py_newnil(py_tpgetmagic(*ud, name));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -14,11 +14,7 @@ a = {
|
||||
'h': False
|
||||
}
|
||||
|
||||
try:
|
||||
import cjson as json
|
||||
print('[INFO] cjson is used')
|
||||
except ImportError:
|
||||
import json
|
||||
import json
|
||||
|
||||
assert json.loads("1") == 1
|
||||
assert json.loads('"1"') == "1"
|
||||
@ -29,7 +25,7 @@ assert json.loads("true") == True
|
||||
assert json.loads("false") == False
|
||||
assert json.loads("{}") == {}
|
||||
|
||||
assert json.loads(b"false") == False
|
||||
# assert json.loads(b"false") == False
|
||||
|
||||
_j = json.dumps(a)
|
||||
_a = json.loads(_j)
|
||||
|
Loading…
x
Reference in New Issue
Block a user