add py_import

This commit is contained in:
blueloveTH 2024-08-04 14:57:59 +08:00
parent 205f6ff225
commit 8e1e29ddd6
19 changed files with 420 additions and 78 deletions

View File

@ -30,6 +30,7 @@ bool c11__sveq2(c11_sv a, const char* b);
c11_string* c11_string__new(const char* data); c11_string* c11_string__new(const char* data);
c11_string* c11_string__new2(const char* data, int size); c11_string* c11_string__new2(const char* data, int size);
c11_string* c11_string__new3(const char* fmt, ...);
void c11_string__ctor(c11_string* self, const char* data); void c11_string__ctor(c11_string* self, const char* data);
void c11_string__ctor2(c11_string* self, const char* data, int size); void c11_string__ctor2(c11_string* self, const char* data, int size);
c11_string* c11_string__copy(c11_string* self); c11_string* c11_string__copy(c11_string* self);
@ -45,6 +46,7 @@ c11_sv c11_sv__slice(c11_sv sv, int start);
c11_sv c11_sv__slice2(c11_sv sv, int start, int stop); c11_sv c11_sv__slice2(c11_sv sv, int start, int stop);
c11_sv c11_sv__strip(c11_sv sv, c11_sv chars, bool left, bool right); c11_sv c11_sv__strip(c11_sv sv, c11_sv chars, bool left, bool right);
int c11_sv__index(c11_sv self, char c); int c11_sv__index(c11_sv self, char c);
int c11_sv__rindex(c11_sv self, char c);
int c11_sv__index2(c11_sv self, c11_sv sub, int start); int c11_sv__index2(c11_sv self, c11_sv sub, int start);
int c11_sv__count(c11_sv self, c11_sv sub); int c11_sv__count(c11_sv self, c11_sv sub);

View File

@ -0,0 +1,44 @@
#pragma once
#include "pocketpy/common/vector.h"
#include "pocketpy/common/str.h"
#include "pocketpy/pocketpy.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct VfsEntry {
bool is_file;
union {
struct {
int size;
unsigned char* data;
} _file;
c11_vector _dir;
};
} VfsEntry;
#define SMALLMAP_T__HEADER
#define K c11_sv
#define V VfsEntry
#define NAME VfsDir
#define less(a, b) (c11_sv__cmp((a), (b)) < 0)
#define equal(a, b) (c11_sv__cmp((a), (b)) == 0)
#include "pocketpy/xmacros/smallmap.h"
#undef SMALLMAP_T__HEADER
typedef struct Vfs {
VfsEntry root;
} Vfs;
void Vfs__ctor(Vfs* self);
void Vfs__dtor(Vfs* self);
#ifdef __cplusplus
}
#endif

View File

@ -4,6 +4,7 @@
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include "pocketpy/interpreter/gc.h" #include "pocketpy/interpreter/gc.h"
#include "pocketpy/interpreter/frame.h" #include "pocketpy/interpreter/frame.h"
#include "pocketpy/interpreter/vfs.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -39,7 +40,7 @@ typedef struct pk_VM {
py_TValue main; // __main__ module py_TValue main; // __main__ module
void (*ceval_on_step)(Frame*, Bytecode); void (*ceval_on_step)(Frame*, Bytecode);
unsigned char* (*import_file)(const char*); unsigned char* (*import_file)(const char*, int*);
void (*print)(const char*); void (*print)(const char*);
py_TValue last_retval; py_TValue last_retval;
@ -48,6 +49,7 @@ typedef struct pk_VM {
py_TValue reg[8]; // users' registers py_TValue reg[8]; // users' registers
Vfs __vfs;
py_TValue* __curr_class; py_TValue* __curr_class;
FuncDecl_ __dynamic_func_decl; FuncDecl_ __dynamic_func_decl;
py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES]; py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];
@ -124,6 +126,8 @@ py_Type pk_Exception__register();
py_TValue pk_builtins__register(); py_TValue pk_builtins__register();
void pk__add_module_pkpy();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -92,11 +92,8 @@ void py_newlistn(py_Ref, int n);
void py_newdict(py_Ref); void py_newdict(py_Ref);
void py_newslice(py_Ref); void py_newslice(py_Ref);
void py_newnativefunc(py_Ref out, py_CFunction); void py_newnativefunc(py_Ref out, py_CFunction);
py_Name py_newfunction(py_Ref out, py_Name
const char* sig, py_newfunction(py_Ref out, const char* sig, py_CFunction f, const char* docstring, int slots);
py_CFunction f,
const char* docstring,
int slots);
/************* Name Convertions *************/ /************* Name Convertions *************/
py_Name py_name(const char*); py_Name py_name(const char*);
@ -262,12 +259,12 @@ py_StackRef py_pushtmp();
bool py_pushmethod(py_Name name); bool py_pushmethod(py_Name name);
/************* Modules *************/ /************* Modules *************/
py_TmpRef py_newmodule(const char* name, const char* package); py_TmpRef py_newmodule(const char* path);
py_TmpRef py_getmodule(const char* name); py_TmpRef py_getmodule(const char* path);
/// 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) PY_RAISE; bool py_import(const char* path) PY_RAISE;
/************* Errors *************/ /************* Errors *************/
/// Raise an exception by name and message. Always returns false. /// Raise an exception by name and message. Always returns false.
@ -286,6 +283,7 @@ bool py_checkexc();
#define RuntimeError(...) py_exception("RuntimeError", __VA_ARGS__) #define RuntimeError(...) py_exception("RuntimeError", __VA_ARGS__)
#define ValueError(...) py_exception("ValueError", __VA_ARGS__) #define ValueError(...) py_exception("ValueError", __VA_ARGS__)
#define IndexError(...) py_exception("IndexError", __VA_ARGS__) #define IndexError(...) py_exception("IndexError", __VA_ARGS__)
#define ImportError(...) py_exception("ImportError", __VA_ARGS__)
#define NotImplementedError() py_exception("NotImplementedError", "") #define NotImplementedError() py_exception("NotImplementedError", "")
#define AttributeError(self, n) \ #define AttributeError(self, n) \
py_exception("AttributeError", "'%t' object has no attribute '%n'", (self)->type, (n)) py_exception("AttributeError", "'%t' object has no attribute '%n'", (self)->type, (n))
@ -362,6 +360,11 @@ 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);
/************* Virtual File System *************/
unsigned char* py_vfsread(const char* path, int* size);
bool py_vfswrite(const char* path, unsigned char* data, int size);
char** py_vfslist(const char* path, int* length);
/************* Others *************/ /************* Others *************/
int py_replinput(char* buf); int py_replinput(char* buf);

View File

@ -56,6 +56,7 @@ MAGIC_METHOD(__exit__)
MAGIC_METHOD(__name__) MAGIC_METHOD(__name__)
MAGIC_METHOD(__all__) MAGIC_METHOD(__all__)
MAGIC_METHOD(__package__) MAGIC_METHOD(__package__)
MAGIC_METHOD(__module_is_pending__)
MAGIC_METHOD(__path__) MAGIC_METHOD(__path__)
MAGIC_METHOD(__class__) MAGIC_METHOD(__class__)
MAGIC_METHOD(__abs__) MAGIC_METHOD(__abs__)

View File

@ -2,6 +2,3 @@ from typing import Any
def next(iter) -> Any | StopIteration: def next(iter) -> Any | StopIteration:
... ...
def _enable_instance_dict(obj) -> None:
...

View File

@ -1,4 +1,4 @@
from __builtins import next as __builtins_next from pkpy import next as __builtins_next
def all(iterable): def all(iterable):
for i in iterable: for i in iterable:

View File

@ -1,4 +1,4 @@
from __builtins import _enable_instance_dict from pkpy import _enable_instance_dict
from typing import Generic, TypeVar, Iterable from typing import Generic, TypeVar, Iterable
T = TypeVar('T') T = TypeVar('T')

View File

@ -1,4 +1,4 @@
from __builtins import next from pkpy import next
class cache: class cache:
def __init__(self, f): def __init__(self, f):

View File

@ -1,4 +1,4 @@
from __builtins import next from pkpy import next
def zip_longest(a, b): def zip_longest(a, b):
a = iter(a) a = iter(a)

File diff suppressed because one or more lines are too long

View File

@ -16,6 +16,17 @@ c11_string* c11_string__new2(const char* data, int size) {
return retval; return retval;
} }
c11_string* c11_string__new3(const char* fmt, ...) {
c11_sbuf buf;
c11_sbuf__ctor(&buf);
va_list args;
va_start(args, fmt);
// c11_sbuf__write_vfmt(&buf, fmt, args);
pk_vsprintf(&buf, fmt, args);
va_end(args);
return c11_sbuf__submit(&buf);
}
void c11_string__ctor(c11_string* self, const char* data) { void c11_string__ctor(c11_string* self, const char* data) {
c11_string__ctor2(self, data, strlen(data)); c11_string__ctor2(self, data, strlen(data));
} }
@ -124,6 +135,13 @@ int c11_sv__index(c11_sv self, char c) {
return -1; return -1;
} }
int c11_sv__rindex(c11_sv self, char c) {
for(int i = self.size - 1; i >= 0; i--) {
if(self.data[i] == c) return i;
}
return -1;
}
int c11_sv__index2(c11_sv self, c11_sv sub, int start) { int c11_sv__index2(c11_sv self, c11_sv sub, int start) {
if(sub.size == 0) return start; if(sub.size == 0) return start;
int max_end = self.size - sub.size; int max_end = self.size - sub.size;

View File

@ -755,6 +755,47 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
} }
} }
//////// ////////
case OP_IMPORT_PATH: {
py_Ref path_object = c11__at(py_TValue, &frame->co->consts, byte.arg);
bool ok = py_import(py_tostr(path_object));
if(!ok) goto __ERROR;
PUSH(py_retval());
DISPATCH();
}
case OP_POP_IMPORT_STAR: {
// [module]
pk_NameDict* dict = PyObject__dict(TOP()->_obj);
py_Ref all = pk_NameDict__try_get(dict, __all__);
if(all) {
int length;
py_TValue* p = pk_arrayview(all, &length);
if(!p) {
TypeError("'__all__' must be a list or tuple, got '%t'", all->type);
goto __ERROR;
}
for(int i = 0; i < length; i++) {
py_Name name = py_namev(py_tosv(p + i));
py_Ref value = pk_NameDict__try_get(dict, name);
if(value == NULL) {
ImportError("cannot import name '%n'", name);
goto __ERROR;
} else {
py_setdict(&frame->module, name, value);
}
}
} else {
for(int i = 0; i < dict->count; i++) {
pk_NameDict_KV* kv = c11__at(pk_NameDict_KV, dict, i);
if(!kv->key) continue;
c11_sv name = py_name2sv(kv->key);
if(name.size == 0 || name.data[0] == '_') continue;
py_setdict(&frame->module, kv->key, &kv->value);
}
}
POP();
DISPATCH();
}
////////
case OP_UNPACK_SEQUENCE: { case OP_UNPACK_SEQUENCE: {
if(!stack_unpack_sequence(self, byte.arg)) goto __ERROR; if(!stack_unpack_sequence(self, byte.arg)) goto __ERROR;
DISPATCH(); DISPATCH();
@ -907,8 +948,9 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
pk_print_stack(self, frame, (Bytecode){0}); pk_print_stack(self, frame, (Bytecode){0});
py_BaseException__set_lineno(&self->curr_exception, Frame__lineno(frame), frame->co); py_BaseException__set_lineno(&self->curr_exception, Frame__lineno(frame), frame->co);
__ERROR_RE_RAISE: __ERROR_RE_RAISE:
do {} while(0); do {
//printf("error.op: %s, line: %d\n", pk_opname(byte.op), Frame__lineno(frame)); } while(0);
// printf("error.op: %s, line: %d\n", pk_opname(byte.op), Frame__lineno(frame));
int lineno = py_BaseException__get_lineno(&self->curr_exception, frame->co); int lineno = py_BaseException__get_lineno(&self->curr_exception, frame->co);
py_BaseException__stpush(&self->curr_exception, py_BaseException__stpush(&self->curr_exception,
frame->co->src, frame->co->src,

131
src/interpreter/vfs.c Normal file
View File

@ -0,0 +1,131 @@
#include "pocketpy/interpreter/vfs.h"
#include "pocketpy/interpreter/vm.h"
#define SMALLMAP_T__SOURCE
#define K c11_sv
#define V VfsEntry
#define NAME VfsDir
#define less(a, b) (c11_sv__cmp((a), (b)) < 0)
#define equal(a, b) (c11_sv__cmp((a), (b)) == 0)
#include "pocketpy/xmacros/smallmap.h"
#undef SMALLMAP_T__SOURCE
static VfsEntry* Vfs__get(const char* path) {
c11_vector /*T=c11_sv*/ cpnts = c11_sv__split((c11_sv){path, strlen(path)}, '/');
VfsEntry* root = &pk_current_vm->__vfs.root;
for(int i = 0; i < cpnts.count; i++) {
c11_sv cpnt = c11__getitem(c11_sv, &cpnts, i);
VfsEntry* entry = VfsDir__try_get(&root->_dir, cpnt);
if(entry == NULL) {
c11_vector__dtor(&cpnts);
return NULL;
}
if(entry->is_file) {
VfsEntry* retval = i == cpnts.count - 1 ? entry : NULL;
c11_vector__dtor(&cpnts);
return retval;
} else {
root = entry;
}
}
c11_vector__dtor(&cpnts);
return root;
}
static void VfsDir__delete_recursively(VfsDir* self) {
for(int i = 0; i < self->count; i++) {
VfsDir_KV* kv = c11__at(VfsDir_KV, self, i);
free((char*)kv->key.data);
if(kv->value.is_file) {
free(kv->value._file.data);
} else {
VfsDir__delete_recursively(&kv->value._dir);
}
}
VfsDir__dtor(self);
}
void Vfs__ctor(Vfs* self) {
self->root.is_file = false;
VfsDir__ctor(&self->root._dir);
}
void Vfs__dtor(Vfs* self) { VfsDir__delete_recursively(&self->root._dir); }
unsigned char* py_vfsread(const char* path, int* size) {
VfsEntry* entry = Vfs__get(path);
if(entry == NULL || !entry->is_file) return NULL;
*size = entry->_file.size;
unsigned char* retval = malloc(*size);
memcpy(retval, entry->_file.data, *size);
return retval;
}
static void VfsDir__dupset(VfsDir* self, c11_sv key, VfsEntry value) {
char* p = malloc(key.size);
memcpy(p, key.data, key.size);
VfsDir__set(self, (c11_sv){p, key.size}, value);
}
bool py_vfswrite(const char* path, unsigned char* data, int size) {
c11_vector /*T=c11_sv*/ cpnts = c11_sv__split((c11_sv){path, strlen(path)}, '/');
VfsEntry* root = &pk_current_vm->__vfs.root;
for(int i = 0; i < cpnts.count; i++) {
c11_sv cpnt = c11__getitem(c11_sv, &cpnts, i);
VfsEntry* entry = VfsDir__try_get(&root->_dir, cpnt);
if(entry == NULL) {
if(i == cpnts.count - 1) {
// create file
VfsEntry entry = {
.is_file = true,
._file.size = size,
._file.data = data,
};
VfsDir__dupset(&root->_dir, cpnt, entry);
c11_vector__dtor(&cpnts);
return true;
} else {
// create missing directory
VfsEntry entry = {
.is_file = false,
};
VfsDir__ctor(&entry._dir);
VfsDir__dupset(&root->_dir, cpnt, entry);
}
} else {
if(i == cpnts.count - 1) {
if(!entry->is_file) break;
// update file
free(entry->_file.data);
entry->_file.size = size;
entry->_file.data = data;
c11_vector__dtor(&cpnts);
return true;
} else {
if(entry->is_file) break;
root = entry;
}
}
}
c11_vector__dtor(&cpnts);
return false;
}
char** py_vfslist(const char* path, int* length) {
VfsEntry* entry = Vfs__get(path);
if(entry == NULL || entry->is_file) return NULL;
*length = 0;
char** ret = malloc(sizeof(char*) * entry->_dir.count);
for(int i = 0; i < entry->_dir.count; i++) {
VfsDir_KV* child = c11__at(VfsDir_KV, &entry->_dir, i);
if(child->value.is_file) {
int size = child->key.size;
ret[i] = malloc(size + 1);
memcpy(ret[i], child->key.data, size);
ret[i][size] = '\0';
(*length)++;
}
}
return ret;
}

View File

@ -3,13 +3,10 @@
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
#include "pocketpy/common/utils.h" #include "pocketpy/common/utils.h"
#include "pocketpy/objects/base.h" #include "pocketpy/objects/base.h"
#include "pocketpy/common/_generated.h"
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
#include <assert.h> static unsigned char* pk_default_import_file(const char* path, int* size) { return NULL; }
#include <stdarg.h>
#include <stdbool.h>
static unsigned char* pk_default_import_file(const char* path) { return NULL; }
static void pk_default_print(const char* data) { printf("%s", data); } static void pk_default_print(const char* data) { printf("%s", data); }
@ -39,6 +36,13 @@ static void pk_TypeInfo__ctor(pk_TypeInfo* self,
static void pk_TypeInfo__dtor(pk_TypeInfo* self) { c11_vector__dtor(&self->annotated_fields); } static void pk_TypeInfo__dtor(pk_TypeInfo* self) { c11_vector__dtor(&self->annotated_fields); }
static void save_site_package_to_vfs(const char* name, const char* source) {
char buf[512];
snprintf(buf, sizeof(buf), "site-packages/%s", name);
bool ok = py_vfswrite(buf, (unsigned char*)source, strlen(source) + 1);
if(!ok) c11__abort("failed to save '%s' to vfs", name);
}
void pk_VM__ctor(pk_VM* self) { void pk_VM__ctor(pk_VM* self) {
self->top_frame = NULL; self->top_frame = NULL;
@ -56,6 +60,7 @@ void pk_VM__ctor(pk_VM* self) {
self->curr_exception = *py_NIL; self->curr_exception = *py_NIL;
self->is_stopiteration = false; self->is_stopiteration = false;
Vfs__ctor(&self->__vfs);
self->__curr_class = NULL; self->__curr_class = NULL;
self->__dynamic_func_decl = NULL; self->__dynamic_func_decl = NULL;
@ -175,7 +180,23 @@ void pk_VM__ctor(pk_VM* self) {
py_newnotimplemented(&tmp); py_newnotimplemented(&tmp);
py_setdict(&self->builtins, py_name("NotImplemented"), &tmp); py_setdict(&self->builtins, py_name("NotImplemented"), &tmp);
self->main = *py_newmodule("__main__", NULL); // add modules
pk__add_module_pkpy();
self->main = *py_newmodule("__main__");
save_site_package_to_vfs("bisect.py", kPythonLibs_bisect);
save_site_package_to_vfs("cmath.py", kPythonLibs_cmath);
save_site_package_to_vfs("collections.py", kPythonLibs_collections);
save_site_package_to_vfs("colorsys.py", kPythonLibs_colorsys);
save_site_package_to_vfs("datetime.py", kPythonLibs_datetime);
save_site_package_to_vfs("functools.py", kPythonLibs_functools);
save_site_package_to_vfs("heapq.py", kPythonLibs_heapq);
save_site_package_to_vfs("itertools.py", kPythonLibs_itertools);
save_site_package_to_vfs("operator.py", kPythonLibs_operator);
save_site_package_to_vfs("pickle.py", kPythonLibs_pickle);
save_site_package_to_vfs("this.py", kPythonLibs_this);
save_site_package_to_vfs("typing.py", kPythonLibs_typing);
} }
void pk_VM__dtor(pk_VM* self) { void pk_VM__dtor(pk_VM* self) {
@ -188,6 +209,7 @@ void pk_VM__dtor(pk_VM* self) {
c11__foreach(pk_TypeInfo, &self->types, ti) pk_TypeInfo__dtor(ti); c11__foreach(pk_TypeInfo, &self->types, ti) pk_TypeInfo__dtor(ti);
c11_vector__dtor(&self->types); c11_vector__dtor(&self->types);
ValueStack__clear(&self->stack); ValueStack__clear(&self->stack);
Vfs__dtor(&self->__vfs);
} }
void pk_VM__push_frame(pk_VM* self, Frame* frame) { void pk_VM__push_frame(pk_VM* self, Frame* frame) {
@ -559,7 +581,7 @@ void pk_ManagedHeap__mark(pk_ManagedHeap* self) {
} }
void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) { void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) {
return; // return;
if(frame == NULL) return; if(frame == NULL) return;
py_TValue* sp = self->stack.sp; py_TValue* sp = self->stack.sp;

View File

@ -52,9 +52,9 @@ void py_finalize() {
pk_MemoryPools__finalize(); pk_MemoryPools__finalize();
} }
void py_switchvm(int index){ void py_switchvm(int index) {
if(index < 0 || index >= 16) c11__abort("invalid vm index"); if(index < 0 || index >= 16) c11__abort("invalid vm index");
if(!pk_all_vm[index]){ if(!pk_all_vm[index]) {
pk_all_vm[index] = malloc(sizeof(pk_VM)); pk_all_vm[index] = malloc(sizeof(pk_VM));
pk_VM__ctor(pk_all_vm[index]); pk_VM__ctor(pk_all_vm[index]);
} }
@ -123,13 +123,9 @@ static void disassemble(CodeObject* co) {
for(int j = 0; j < padding; j++) for(int j = 0; j < padding; j++)
c11_sbuf__write_char(&ss, ' '); c11_sbuf__write_char(&ss, ' ');
// _opcode_argstr(this, i, byte, co);
do { do {
if(Bytecode__is_forward_jump(&byte)) { if(Bytecode__is_forward_jump(&byte)) {
c11_sbuf__write_int(&ss, (int16_t)byte.arg); pk_sprintf(&ss, "%d (to %d)", (int16_t)byte.arg, (int16_t)byte.arg + i);
c11_sbuf__write_cstr(&ss, " (to ");
c11_sbuf__write_int(&ss, (int16_t)byte.arg + i);
c11_sbuf__write_char(&ss, ')');
break; break;
} }
@ -138,12 +134,8 @@ static void disassemble(CodeObject* co) {
case OP_LOAD_CONST: case OP_LOAD_CONST:
case OP_FORMAT_STRING: case OP_FORMAT_STRING:
case OP_IMPORT_PATH: { case OP_IMPORT_PATH: {
py_Ref tmp = c11__at(py_TValue, &co->consts, byte.arg); py_Ref path = c11__at(py_TValue, &co->consts, byte.arg);
c11_sbuf__write_cstr(&ss, " ("); pk_sprintf(&ss, " (%q)", py_tosv(path));
// here we need to use py_repr, however this function is not ready yet
c11_sbuf__write_cstr(&ss, "<class '");
c11_sbuf__write_cstr(&ss, py_tpname(tmp->type));
c11_sbuf__write_cstr(&ss, "'>)");
break; break;
} }
case OP_LOAD_NAME: case OP_LOAD_NAME:
@ -158,32 +150,24 @@ static void disassemble(CodeObject* co) {
case OP_GOTO: case OP_GOTO:
case OP_DELETE_GLOBAL: case OP_DELETE_GLOBAL:
case OP_STORE_CLASS_ATTR: { case OP_STORE_CLASS_ATTR: {
c11_sbuf__write_cstr(&ss, " ("); pk_sprintf(&ss, " (%n)", byte.arg);
c11_sbuf__write_cstr(&ss, py_name2str(byte.arg));
c11_sbuf__write_char(&ss, ')');
break; break;
} }
case OP_LOAD_FAST: case OP_LOAD_FAST:
case OP_STORE_FAST: case OP_STORE_FAST:
case OP_DELETE_FAST: { case OP_DELETE_FAST: {
py_Name name = c11__getitem(py_Name, &co->varnames, byte.arg); py_Name name = c11__getitem(py_Name, &co->varnames, byte.arg);
c11_sbuf__write_cstr(&ss, " ("); pk_sprintf(&ss, " (%n)", name);
c11_sbuf__write_cstr(&ss, py_name2str(name));
c11_sbuf__write_char(&ss, ')');
break; break;
} }
case OP_LOAD_FUNCTION: { case OP_LOAD_FUNCTION: {
const FuncDecl* decl = c11__getitem(FuncDecl*, &co->func_decls, byte.arg); const FuncDecl* decl = c11__getitem(FuncDecl*, &co->func_decls, byte.arg);
c11_sbuf__write_cstr(&ss, " ("); pk_sprintf(&ss, " (%s)", decl->code.name->data);
c11_sbuf__write_cstr(&ss, decl->code.name->data);
c11_sbuf__write_char(&ss, ')');
break; break;
} }
case OP_BINARY_OP: { case OP_BINARY_OP: {
py_Name name = byte.arg & 0xFF; py_Name name = byte.arg & 0xFF;
c11_sbuf__write_cstr(&ss, " ("); pk_sprintf(&ss, " (%n)", name);
c11_sbuf__write_cstr(&ss, py_name2str(name));
c11_sbuf__write_char(&ss, ')');
break; break;
} }
} }

View File

@ -5,12 +5,12 @@
#include "pocketpy/common/sstream.h" #include "pocketpy/common/sstream.h"
#include "pocketpy/interpreter/vm.h" #include "pocketpy/interpreter/vm.h"
py_Ref py_getmodule(const char* name) { py_Ref py_getmodule(const char* path) {
pk_VM* vm = pk_current_vm; pk_VM* vm = pk_current_vm;
return pk_NameDict__try_get(&vm->modules, py_name(name)); return pk_NameDict__try_get(&vm->modules, py_name(path));
} }
py_Ref py_newmodule(const char* name, const char* package) { py_Ref py_newmodule(const char* path) {
pk_ManagedHeap* heap = &pk_current_vm->heap; pk_ManagedHeap* heap = &pk_current_vm->heap;
PyObject* obj = pk_ManagedHeap__new(heap, tp_module, -1, 0); PyObject* obj = pk_ManagedHeap__new(heap, tp_module, -1, 0);
@ -23,33 +23,106 @@ py_Ref py_newmodule(const char* name, const char* package) {
._obj = obj, ._obj = obj,
}; };
py_newstr(r1, name); int last_dot = c11_sv__rindex((c11_sv){path, strlen(path)}, '.');
if(last_dot == -1) {
py_newstr(r1, path);
py_setdict(r0, __name__, r1); py_setdict(r0, __name__, r1);
py_newstr(r1, "");
package = package ? package : ""; py_setdict(r0, __package__, r1);
} else {
py_newstr(r1, package); const char* start = path + last_dot + 1;
py_newstr(r1, start);
py_setdict(r0, __name__, r1);
py_newstrn(r1, path, last_dot);
py_setdict(r0, __package__, r1); py_setdict(r0, __package__, r1);
// convert to fullname
if(package[0] != '\0') {
// package.name
char buf[256];
snprintf(buf, sizeof(buf), "%s.%s", package, name);
name = buf;
} }
py_newstr(r1, name); py_newstr(r1, path);
py_setdict(r0, __path__, r1); py_setdict(r0, __path__, r1);
// we do not allow override in order to avoid memory leak // we do not allow override in order to avoid memory leak
// it is because Module objects are not garbage collected // it is because Module objects are not garbage collected
bool exists = pk_NameDict__contains(&pk_current_vm->modules, py_name(name)); py_Name path_name = py_name(path);
if(exists) c11__abort("module '%s' already exists", name); bool exists = pk_NameDict__contains(&pk_current_vm->modules, path_name);
pk_NameDict__set(&pk_current_vm->modules, py_name(name), *r0); if(exists) c11__abort("module '%s' already exists", path);
pk_NameDict__set(&pk_current_vm->modules, path_name, *r0);
py_shrink(2); py_shrink(2);
return py_getmodule(name); return py_getmodule(path);
}
bool py_import(const char* path_cstr) {
pk_VM* vm = pk_current_vm;
c11_sv path = {path_cstr, strlen(path_cstr)};
if(path.size == 0) return ValueError("empty module name");
if(path.data[0] == '.') {
// try relative import
py_Ref package = py_getdict(&vm->top_frame->module, __package__);
c11_sv package_sv = py_tosv(package);
if(package_sv.size == 0) return ImportError("relative import %q with no known parent package", path);
c11_string* new_path = c11_string__new3("%v.%v", package_sv, path);
bool ok = py_import(new_path->data);
c11_string__delete(new_path);
return ok;
}
assert(path.data[0] != '.' && path.data[path.size - 1] != '.');
// check existing module
py_TmpRef ext_mod = py_getmodule(path.data);
if(ext_mod) {
py_Ref is_pending = py_getdict(ext_mod, __module_is_pending__);
if(is_pending) return ImportError("circular import detected");
py_assign(py_retval(), ext_mod);
return true;
}
// vector<std::string_view> path_cpnts = path.split('.');
// // check circular import
// if(__import_context.pending.size() > 128) { ImportError("maximum recursion depth exceeded
// while importing"); }
// try import
c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP);
c11_string* filename = c11_string__new3("site-packages/%s.py", slashed_path->data);
int size;
unsigned char* data = py_vfsread(filename->data, &size);
if(data != NULL) goto __SUCCESS;
c11_string__delete(filename);
filename = c11_string__new3("site-packages/%s/__init__.py", slashed_path->data);
data = py_vfsread(filename->data, &size);
if(data != NULL) goto __SUCCESS;
c11_string__delete(filename);
filename = c11_string__new3("%s.py", slashed_path->data);
data = vm->import_file(slashed_path->data, &size);
if(data != NULL) goto __SUCCESS;
c11_string__delete(filename);
filename = c11_string__new3("%s/__init__.py", slashed_path->data);
data = vm->import_file(slashed_path->data, &size);
if(data != NULL) goto __SUCCESS;
c11_string__delete(filename);
c11_string__delete(slashed_path);
return ImportError("module %q not found", path);
__SUCCESS:
py_push(py_newmodule(path_cstr));
py_Ref mod = py_peek(-1);
py_setdict(mod, __module_is_pending__, py_True);
bool ok = py_exec((const char*)data, filename->data, EXEC_MODE, mod);
py_deldict(mod, __module_is_pending__);
py_assign(py_retval(), mod);
py_pop();
c11_string__delete(filename);
c11_string__delete(slashed_path);
free(data);
return ok;
} }
////////////////////////// //////////////////////////
@ -224,7 +297,7 @@ static bool _py_builtins__eval(int argc, py_Ref argv) {
} }
py_TValue pk_builtins__register() { py_TValue pk_builtins__register() {
py_Ref builtins = py_newmodule("builtins", NULL); py_Ref builtins = py_newmodule("builtins");
py_bindfunc(builtins, "repr", _py_builtins__repr); py_bindfunc(builtins, "repr", _py_builtins__repr);
py_bindfunc(builtins, "exit", _py_builtins__exit); py_bindfunc(builtins, "exit", _py_builtins__exit);
py_bindfunc(builtins, "len", _py_builtins__len); py_bindfunc(builtins, "len", _py_builtins__len);

21
src/public/pkpy.c Normal file
View File

@ -0,0 +1,21 @@
#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 _py_pkpy__next(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
int res = py_next(argv);
if(res == -1) return false;
if(res) return true;
py_assign(py_retval(), py_tpobject(tp_StopIteration));
return true;
}
void pk__add_module_pkpy() {
py_Ref mod = py_newmodule("pkpy");
py_bindfunc(mod, "next", _py_pkpy__next);
}

View File

@ -1,4 +1,4 @@
from __builtins import next from pkpy import next
a = [1, 2, 3] a = [1, 2, 3]
a = iter(a) a = iter(a)