This commit is contained in:
blueloveTH 2024-08-04 18:51:58 +08:00
parent b1a8c6db8e
commit ea9dabdf99
22 changed files with 392 additions and 49 deletions

View File

@ -10,7 +10,7 @@
// Whether to compile os-related modules or not // Whether to compile os-related modules or not
#ifndef PK_ENABLE_OS // can be overridden by cmake #ifndef PK_ENABLE_OS // can be overridden by cmake
#define PK_ENABLE_OS 0 #define PK_ENABLE_OS 1
#endif #endif
// Enable `line_profiler` module and `breakpoint()` function // Enable `line_profiler` module and `breakpoint()` function

View File

@ -49,6 +49,8 @@ int c11_sv__index(c11_sv self, char c);
int c11_sv__rindex(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);
bool c11_sv__startswith(c11_sv self, c11_sv prefix);
bool c11_sv__endswith(c11_sv self, c11_sv suffix);
c11_string* c11_sv__replace(c11_sv self, char old, char new_); c11_string* c11_sv__replace(c11_sv self, char old, char new_);
c11_string* c11_sv__replace2(c11_sv self, c11_sv old, c11_sv new_); c11_string* c11_sv__replace2(c11_sv self, c11_sv old, c11_sv new_);

View File

@ -0,0 +1,13 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void pk__add_module_pkpy();
void pk__add_module_os();
void pk__add_module_math();
#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/modules.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -124,8 +125,6 @@ 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

@ -7,6 +7,10 @@
#include "pocketpy/common/config.h" #include "pocketpy/common/config.h"
#include "pocketpy/common/export.h" #include "pocketpy/common/export.h"
#ifdef __cplusplus
extern "C" {
#endif
/************* Public Types *************/ /************* Public Types *************/
typedef struct py_TValue py_TValue; typedef struct py_TValue py_TValue;
typedef uint16_t py_Name; typedef uint16_t py_Name;
@ -121,7 +125,7 @@ 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);
bool py_castfloat(py_Ref, py_f64* out); bool py_castfloat(py_Ref, py_f64* out) PY_RAISE;
bool py_tobool(py_Ref); bool py_tobool(py_Ref);
py_Type py_totype(py_Ref); py_Type py_totype(py_Ref);
const char* py_tostr(py_Ref); const char* py_tostr(py_Ref);
@ -186,6 +190,7 @@ py_GlobalRef py_retval();
py_ObjectRef py_getdict(py_Ref self, py_Name name); py_ObjectRef py_getdict(py_Ref self, py_Name name);
void py_setdict(py_Ref self, py_Name name, py_Ref val); void py_setdict(py_Ref self, py_Name name, py_Ref val);
bool py_deldict(py_Ref self, py_Name name); bool py_deldict(py_Ref self, py_Name name);
py_ObjectRef py_emplacedict(py_Ref self, py_Name name);
/// Get the reference of the i-th slot of the object. /// Get the reference of the i-th slot of the object.
/// The object must have slots and `i` must be in range. /// The object must have slots and `i` must be in range.
@ -264,7 +269,8 @@ 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* path) PY_RAISE; /// -1: error, 0: not found, 1: success
int 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.
@ -280,6 +286,8 @@ bool py_checkexc();
/// Clear the current exception. /// Clear the current exception.
void py_clearexc(py_StackRef p0); void py_clearexc(py_StackRef p0);
#define IOError(...) py_exception("IOError", __VA_ARGS__)
#define OSError(...) py_exception("OSError", __VA_ARGS__)
#define NameError(n) py_exception("NameError", "name '%n' is not defined", (n)) #define NameError(n) py_exception("NameError", "name '%n' is not defined", (n))
#define TypeError(...) py_exception("TypeError", __VA_ARGS__) #define TypeError(...) py_exception("TypeError", __VA_ARGS__)
#define RuntimeError(...) py_exception("RuntimeError", __VA_ARGS__) #define RuntimeError(...) py_exception("RuntimeError", __VA_ARGS__)

View File

@ -56,7 +56,6 @@ 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

@ -165,6 +165,16 @@ int c11_sv__count(c11_sv self, c11_sv sub) {
return cnt; return cnt;
} }
bool c11_sv__startswith(c11_sv self, c11_sv prefix) {
if(prefix.size > self.size) return false;
return memcmp(self.data, prefix.data, prefix.size) == 0;
}
bool c11_sv__endswith(c11_sv self, c11_sv suffix) {
if(suffix.size > self.size) return false;
return memcmp(self.data + self.size - suffix.size, suffix.data, suffix.size) == 0;
}
c11_vector /* T=c11_sv */ c11_sv__split(c11_sv self, char sep) { c11_vector /* T=c11_sv */ c11_sv__split(c11_sv self, char sep) {
c11_vector retval; c11_vector retval;
c11_vector__ctor(&retval, sizeof(c11_sv)); c11_vector__ctor(&retval, sizeof(c11_sv));

View File

@ -257,6 +257,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
// fallback to getattr // fallback to getattr
if(py_getattr(TOP(), byte.arg)) { if(py_getattr(TOP(), byte.arg)) {
py_assign(TOP(), py_retval()); py_assign(TOP(), py_retval());
py_newnil(SP()++);
} else { } else {
goto __ERROR; goto __ERROR;
} }
@ -757,8 +758,13 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
//////// ////////
case OP_IMPORT_PATH: { case OP_IMPORT_PATH: {
py_Ref path_object = c11__at(py_TValue, &frame->co->consts, byte.arg); py_Ref path_object = c11__at(py_TValue, &frame->co->consts, byte.arg);
bool ok = py_import(py_tostr(path_object)); const char* path = py_tostr(path_object);
if(!ok) goto __ERROR; int res = py_import(path);
if(res == -1) goto __ERROR;
if(res == 0) {
ImportError("module '%s' not found", path);
goto __ERROR;
}
PUSH(py_retval()); PUSH(py_retval());
DISPATCH(); DISPATCH();
} }

View File

@ -6,7 +6,22 @@
#include "pocketpy/common/_generated.h" #include "pocketpy/common/_generated.h"
#include "pocketpy/pocketpy.h" #include "pocketpy/pocketpy.h"
static char* pk_default_import_file(const char* path) { return NULL; } static char* pk_default_import_file(const char* path) {
#if PK_ENABLE_OS
FILE* f = fopen(path, "rb");
if(f == NULL) return NULL;
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
char* buffer = malloc(size + 1);
fread(buffer, 1, size, f);
buffer[size] = 0;
fclose(f);
return buffer;
#else
return NULL;
#endif
}
static void pk_default_print(const char* data) { printf("%s", data); } static void pk_default_print(const char* data) { printf("%s", data); }
@ -147,6 +162,7 @@ void pk_VM__ctor(pk_VM* self) {
const char** builtin_exceptions = (const char*[]){ const char** builtin_exceptions = (const char*[]){
"StackOverflowError", "StackOverflowError",
"IOError", "IOError",
"OSError",
"NotImplementedError", "NotImplementedError",
"TypeError", "TypeError",
"IndexError", "IndexError",
@ -174,6 +190,8 @@ void pk_VM__ctor(pk_VM* self) {
// add modules // add modules
pk__add_module_pkpy(); pk__add_module_pkpy();
pk__add_module_os();
pk__add_module_math();
self->main = *py_newmodule("__main__"); self->main = *py_newmodule("__main__");
} }
@ -559,7 +577,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;
@ -594,6 +612,11 @@ void pk_print_stack(pk_VM* self, Frame* frame, Bytecode byte) {
pk_sprintf(&buf, "%q", py_tosv(p)); pk_sprintf(&buf, "%q", py_tosv(p));
break; break;
} }
case tp_module: {
py_Ref path = py_getdict(p, __path__);
pk_sprintf(&buf, "<module '%v'>", py_tosv(path));
break;
}
default: { default: {
pk_sprintf(&buf, "(%t)", p->type); pk_sprintf(&buf, "(%t)", p->type);
break; break;

202
src/modules/math.c Normal file
View File

@ -0,0 +1,202 @@
#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>
#define ONE_ARG_FUNC(name, func) \
static bool math_##name(int argc, py_Ref argv) { \
PY_CHECK_ARGC(1); \
double x; \
if(!py_castfloat(py_arg(0), &x)) return false; \
py_newfloat(py_retval(), func(x)); \
return true; \
}
#define TWO_ARG_FUNC(name, func) \
static bool math_##name(int argc, py_Ref argv) { \
PY_CHECK_ARGC(2); \
double x, y; \
if(!py_castfloat(py_arg(0), &x)) return false; \
if(!py_castfloat(py_arg(1), &y)) return false; \
py_newfloat(py_retval(), func(x, y)); \
return true; \
}
ONE_ARG_FUNC(ceil, ceil)
ONE_ARG_FUNC(fabs, fabs)
ONE_ARG_FUNC(floor, floor)
ONE_ARG_FUNC(trunc, trunc)
static bool math_fsum(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_list);
py_Ref list = py_arg(0);
double sum = 0;
double c = 0;
for(int i = 0; i < py_list__len(list); i++) {
py_Ref item = py_list__getitem(list, i);
double x;
if(!py_castfloat(item, &x)) return false;
double y = x - c;
double t = sum + y;
c = (t - sum) - y;
sum = t;
}
py_newfloat(py_retval(), sum);
return true;
}
static bool math_gcd(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
PY_CHECK_ARG_TYPE(0, tp_int);
PY_CHECK_ARG_TYPE(1, tp_int);
py_i64 a = py_toint(py_arg(0));
py_i64 b = py_toint(py_arg(1));
if(a < 0) a = -a;
if(b < 0) b = -b;
while(b != 0) {
py_i64 t = b;
b = a % b;
a = t;
}
py_newint(py_retval(), a);
return true;
}
ONE_ARG_FUNC(isfinite, isfinite)
ONE_ARG_FUNC(isinf, isinf)
ONE_ARG_FUNC(isnan, isnan)
static bool math_isclose(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
double a, b;
if(!py_castfloat(py_arg(0), &a)) return false;
if(!py_castfloat(py_arg(1), &b)) return false;
py_newbool(py_retval(), fabs(a - b) < 1e-9);
return true;
}
ONE_ARG_FUNC(exp, exp)
static bool math_log(int argc, py_Ref argv) {
PY_CHECK_ARG_TYPE(0, tp_float);
double x;
if(!py_castfloat(py_arg(0), &x)) return false;
if(argc == 1) {
py_newfloat(py_retval(), log(x));
} else if(argc == 2) {
double base;
if(!py_castfloat(py_arg(1), &base)) return false;
py_newfloat(py_retval(), log(x) / log(base));
} else {
return TypeError("log() takes 1 or 2 arguments");
}
return true;
}
ONE_ARG_FUNC(log2, log2)
ONE_ARG_FUNC(log10, log10)
TWO_ARG_FUNC(pow, pow)
ONE_ARG_FUNC(sqrt, sqrt)
ONE_ARG_FUNC(acos, acos)
ONE_ARG_FUNC(asin, asin)
ONE_ARG_FUNC(atan, atan)
ONE_ARG_FUNC(cos, cos)
ONE_ARG_FUNC(sin, sin)
ONE_ARG_FUNC(tan, tan)
TWO_ARG_FUNC(atan2, atan2)
static bool math_degrees(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
double x;
if(!py_castfloat(py_arg(0), &x)) return false;
py_newfloat(py_retval(), x * 180 / 3.1415926535897932384);
return true;
}
static bool math_radians(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
double x;
if(!py_castfloat(py_arg(0), &x)) return false;
py_newfloat(py_retval(), x * 3.1415926535897932384 / 180);
return true;
}
static bool math_modf(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
double i;
double f = modf(py_tofloat(py_arg(0)), &i);
py_newtuple(py_retval(), 2);
py_Ref _0 = py_tuple__getitem(py_retval(), 0);
py_Ref _1 = py_tuple__getitem(py_retval(), 1);
py_newfloat(_0, f);
py_newfloat(_1, i);
return true;
}
static bool math_factorial(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_int);
py_i64 n = py_toint(py_arg(0));
if(n < 0) return ValueError("factorial() not defined for negative values");
py_i64 r = 1;
for(py_i64 i = 2; i <= n; i++)
r *= i;
py_newint(py_retval(), r);
return true;
}
void pk__add_module_math() {
py_Ref mod = py_newmodule("math");
py_newfloat(py_emplacedict(mod, py_name("pi")), 3.1415926535897932384);
py_newfloat(py_emplacedict(mod, py_name("e")), 2.7182818284590452354);
py_newfloat(py_emplacedict(mod, py_name("inf")), 1.0 / 0.0);
py_newfloat(py_emplacedict(mod, py_name("nan")), 0.0 / 0.0);
py_bindfunc(mod, "ceil", math_ceil);
py_bindfunc(mod, "fabs", math_fabs);
py_bindfunc(mod, "floor", math_floor);
py_bindfunc(mod, "trunc", math_trunc);
py_bindfunc(mod, "fsum", math_fsum);
py_bindfunc(mod, "gcd", math_gcd);
py_bindfunc(mod, "isfinite", math_isfinite);
py_bindfunc(mod, "isinf", math_isinf);
py_bindfunc(mod, "isnan", math_isnan);
py_bindfunc(mod, "isclose", math_isclose);
py_bindfunc(mod, "exp", math_exp);
py_bindfunc(mod, "log", math_log);
py_bindfunc(mod, "log2", math_log2);
py_bindfunc(mod, "log10", math_log10);
py_bindfunc(mod, "pow", math_pow);
py_bindfunc(mod, "sqrt", math_sqrt);
py_bindfunc(mod, "acos", math_acos);
py_bindfunc(mod, "asin", math_asin);
py_bindfunc(mod, "atan", math_atan);
py_bindfunc(mod, "cos", math_cos);
py_bindfunc(mod, "sin", math_sin);
py_bindfunc(mod, "tan", math_tan);
py_bindfunc(mod, "atan2", math_atan2);
py_bindfunc(mod, "degrees", math_degrees);
py_bindfunc(mod, "radians", math_radians);
py_bindfunc(mod, "modf", math_modf);
py_bindfunc(mod, "factorial", math_factorial);
}

49
src/modules/os.c Normal file
View File

@ -0,0 +1,49 @@
#include "pocketpy/pocketpy.h"
#include "pocketpy/common/utils.h"
#include "pocketpy/objects/object.h"
#include "pocketpy/common/sstream.h"
#include "pocketpy/interpreter/vm.h"
#if _WIN32
#include <direct.h>
int platform_chdir(const char* path) { return _chdir(path); }
bool platform_getcwd(char* buf, size_t size) { return _getcwd(buf, size) != NULL; }
#elif __linux__
#include <unistd.h>
int platform_chdir(const char* path) { return chdir(path); }
bool platform_getcwd(char* buf, size_t size) { return getcwd(buf, size) != NULL; }
#else
int platform_chdir(const char* path) { return -1; }
bool platform_getcwd(char* buf, size_t size) { return false; }
#endif
static bool os_chdir(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
PY_CHECK_ARG_TYPE(0, tp_str);
const char* path = py_tostr(py_arg(0));
int code = platform_chdir(path);
if(code != 0) return OSError("chdir() failed: %d", code);
return true;
}
static bool os_getcwd(int argc, py_Ref argv) {
char buf[1024];
if(!platform_getcwd(buf, sizeof(buf))) return OSError("getcwd() failed");
py_newstr(py_retval(), buf);
return true;
}
void pk__add_module_os() {
py_Ref mod = py_newmodule("os");
py_bindfunc(mod, "chdir", os_chdir);
py_bindfunc(mod, "getcwd", os_getcwd);
}

View File

@ -19,7 +19,7 @@ bool py_castfloat(py_Ref self, double* out) {
switch(self->type) { switch(self->type) {
case tp_int: *out = (double)self->_i64; return true; case tp_int: *out = (double)self->_i64; return true;
case tp_float: *out = self->_f64; return true; case tp_float: *out = self->_f64; return true;
default: return false; default: return TypeError("expected int or float, got %t", self->type);
} }
} }
@ -46,9 +46,7 @@ bool py_checktype(py_Ref self, py_Type type) {
return TypeError("expected %t, got %t", type, self->type); return TypeError("expected %t, got %t", type, self->type);
} }
bool py_isinstance(py_Ref obj, py_Type type){ bool py_isinstance(py_Ref obj, py_Type type) { return py_issubclass(obj->type, type); }
return py_issubclass(obj->type, type);
}
bool py_issubclass(py_Type derived, py_Type base) { bool py_issubclass(py_Type derived, py_Type base) {
pk_TypeInfo* types = pk_current_vm->types.data; pk_TypeInfo* types = pk_current_vm->types.data;

View File

@ -52,21 +52,53 @@ py_Ref py_newmodule(const char* path) {
return py_getmodule(path); return py_getmodule(path);
} }
bool py_import(const char* path_cstr) { int py_import(const char* path_cstr) {
// printf("importing %s\n", path_cstr);
pk_VM* vm = pk_current_vm; pk_VM* vm = pk_current_vm;
c11_sv path = {path_cstr, strlen(path_cstr)}; c11_sv path = {path_cstr, strlen(path_cstr)};
if(path.size == 0) return ValueError("empty module name"); if(path.size == 0) return ValueError("empty module name");
if(path.data[0] == '.') { if(path.data[0] == '.') {
// try relative import // try relative import
py_Ref package = py_getdict(&vm->top_frame->module, __package__); int dot_count = 1;
while(dot_count < path.size && path.data[dot_count] == '.')
dot_count++;
c11_sv top_filename = c11_string__sv(vm->top_frame->co->src->filename);
int is_init = c11_sv__endswith(top_filename, (c11_sv){"__init__.py", 11});
py_Ref package = py_getdict(&vm->top_frame->module, __path__);
c11_sv package_sv = py_tosv(package); c11_sv package_sv = py_tosv(package);
if(package_sv.size == 0) if(package_sv.size == 0) {
return ImportError("relative import %q with no known parent package", path); return ImportError("attempted relative import with no known parent package");
c11_string* new_path = c11_string__new3("%v.%v", package_sv, path); }
bool ok = py_import(new_path->data);
c11_vector /* T=c11_sv */ cpnts = c11_sv__split(package_sv, '.');
for(int i = is_init; i < dot_count; i++) {
if(cpnts.count == 0)
return ImportError("attempted relative import beyond top-level package");
c11_vector__pop(&cpnts);
}
if(dot_count < path.size) {
c11_sv last_cpnt = c11_sv__slice(path, dot_count);
c11_vector__push(c11_sv, &cpnts, last_cpnt);
}
// join cpnts
c11_sbuf buf;
c11_sbuf__ctor(&buf);
for(int i = 0; i < cpnts.count; i++) {
if(i > 0) c11_sbuf__write_char(&buf, '.');
c11_sbuf__write_sv(&buf, c11__getitem(c11_sv, &cpnts, i));
}
c11_vector__dtor(&cpnts);
c11_string* new_path = c11_sbuf__submit(&buf);
int res = py_import(new_path->data);
c11_string__delete(new_path); c11_string__delete(new_path);
return ok; return res;
} }
assert(path.data[0] != '.' && path.data[path.size - 1] != '.'); assert(path.data[0] != '.' && path.data[path.size - 1] != '.');
@ -74,17 +106,10 @@ bool py_import(const char* path_cstr) {
// check existing module // check existing module
py_TmpRef ext_mod = py_getmodule(path.data); py_TmpRef ext_mod = py_getmodule(path.data);
if(ext_mod) { 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); py_assign(py_retval(), ext_mod);
return true; 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 // try import
c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP); c11_string* slashed_path = c11_sv__replace(path, '.', PK_PLATFORM_SEP);
c11_string* filename = c11_string__new3("%s.py", slashed_path->data); c11_string* filename = c11_string__new3("%s.py", slashed_path->data);
@ -96,33 +121,29 @@ bool py_import(const char* path_cstr) {
goto __SUCCESS; goto __SUCCESS;
} }
c11_string__delete(filename); data = vm->import_file(filename->data);
filename = c11_string__new3("%s.py", slashed_path->data);
data = vm->import_file(slashed_path->data);
if(data != NULL) goto __SUCCESS; if(data != NULL) goto __SUCCESS;
c11_string__delete(filename); c11_string__delete(filename);
filename = c11_string__new3("%s/__init__.py", slashed_path->data); filename = c11_string__new3("%s/__init__.py", slashed_path->data);
data = vm->import_file(slashed_path->data); data = vm->import_file(filename->data);
if(data != NULL) goto __SUCCESS; if(data != NULL) goto __SUCCESS;
c11_string__delete(filename); c11_string__delete(filename);
c11_string__delete(slashed_path); c11_string__delete(slashed_path);
return ImportError("module %q not found", path); return 0;
__SUCCESS: __SUCCESS:
py_push(py_newmodule(path_cstr)); py_push(py_newmodule(path_cstr));
py_Ref mod = py_peek(-1); 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); bool ok = py_exec((const char*)data, filename->data, EXEC_MODE, mod);
py_deldict(mod, __module_is_pending__);
py_assign(py_retval(), mod); py_assign(py_retval(), mod);
py_pop(); py_pop();
c11_string__delete(filename); c11_string__delete(filename);
c11_string__delete(slashed_path); c11_string__delete(slashed_path);
if(need_free) free((void*)data); if(need_free) free((void*)data);
return ok; return ok ? 1 : -1;
} }
////////////////////////// //////////////////////////

View File

@ -136,6 +136,21 @@ bool py_getattr(py_Ref self, py_Name name) {
} }
} }
if(self->type == tp_module) {
py_Ref path = py_getdict(self, __path__);
c11_sbuf buf;
c11_sbuf__ctor(&buf);
pk_sprintf(&buf, "%v.%n", py_tosv(path), name);
c11_string* new_path = c11_sbuf__submit(&buf);
int res = py_import(new_path->data);
c11_string__delete(new_path);
if(res == -1) {
return false;
} else if(res == 1) {
return true;
}
}
return AttributeError(self, name); return AttributeError(self, name);
} }

View File

@ -247,9 +247,7 @@ static bool _py_str__startswith(int argc, py_Ref argv) {
c11_string* self = py_touserdata(&argv[0]); c11_string* self = py_touserdata(&argv[0]);
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
c11_string* other = py_touserdata(&argv[1]); c11_string* other = py_touserdata(&argv[1]);
c11_sv _0 = c11_sv__slice2(c11_string__sv(self), 0, other->size); py_newbool(py_retval(), c11_sv__startswith(c11_string__sv(self), c11_string__sv(other)));
c11_sv _1 = c11_string__sv(other);
py_newbool(py_retval(), c11__sveq(_0, _1));
return true; return true;
} }
@ -258,9 +256,7 @@ static bool _py_str__endswith(int argc, py_Ref argv) {
c11_string* self = py_touserdata(&argv[0]); c11_string* self = py_touserdata(&argv[0]);
PY_CHECK_ARG_TYPE(1, tp_str); PY_CHECK_ARG_TYPE(1, tp_str);
c11_string* other = py_touserdata(&argv[1]); c11_string* other = py_touserdata(&argv[1]);
c11_sv _0 = c11_sv__slice2(c11_string__sv(self), self->size - other->size, self->size); py_newbool(py_retval(), c11_sv__endswith(c11_string__sv(self), c11_string__sv(other)));
c11_sv _1 = c11_string__sv(other);
py_newbool(py_retval(), c11__sveq(_0, _1));
return true; return true;
} }
@ -538,10 +534,6 @@ bool py_str(py_Ref val) {
return py_call(tmp, 1, val); return py_call(tmp, 1, val);
} }
bool py_repr(py_Ref val) { bool py_repr(py_Ref val) { return pk_callmagic(__repr__, 1, val); }
return pk_callmagic(__repr__, 1, val);
}
bool py_len(py_Ref val){ bool py_len(py_Ref val) { return pk_callmagic(__len__, 1, val); }
return pk_callmagic(__len__, 1, val);
}

View File

@ -29,6 +29,11 @@ void py_setdict(py_Ref self, py_Name name, py_Ref val) {
} }
} }
py_TmpRef py_emplacedict(py_Ref self, py_Name name){
py_setdict(self, name, py_NIL);
return py_getdict(self, name);
}
bool py_deldict(py_Ref self, py_Name name) { bool py_deldict(py_Ref self, py_Name name) {
assert(self && self->is_ptr); assert(self && self->is_ptr);
if(!py_ismagicname(name) || self->type != tp_type) { if(!py_ismagicname(name) || self->type != tp_type) {

View File

@ -4,6 +4,7 @@ except ImportError:
exit(0) exit(0)
os.chdir('tests') os.chdir('tests')
assert os.getcwd().endswith('tests')
import test1 import test1