diff --git a/include/pocketpy/common/config.h b/include/pocketpy/common/config.h index 48dbe861..10ac5a8d 100644 --- a/include/pocketpy/common/config.h +++ b/include/pocketpy/common/config.h @@ -10,7 +10,7 @@ // Whether to compile os-related modules or not #ifndef PK_ENABLE_OS // can be overridden by cmake -#define PK_ENABLE_OS 0 +#define PK_ENABLE_OS 1 #endif // Enable `line_profiler` module and `breakpoint()` function diff --git a/include/pocketpy/common/str.h b/include/pocketpy/common/str.h index d64ab935..5b9eb776 100644 --- a/include/pocketpy/common/str.h +++ b/include/pocketpy/common/str.h @@ -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__index2(c11_sv self, c11_sv sub, int start); 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__replace2(c11_sv self, c11_sv old, c11_sv new_); diff --git a/include/pocketpy/interpreter/modules.h b/include/pocketpy/interpreter/modules.h new file mode 100644 index 00000000..b8edfb7b --- /dev/null +++ b/include/pocketpy/interpreter/modules.h @@ -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 \ No newline at end of file diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index e1b178e6..230b3831 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -4,6 +4,7 @@ #include "pocketpy/pocketpy.h" #include "pocketpy/interpreter/gc.h" #include "pocketpy/interpreter/frame.h" +#include "pocketpy/interpreter/modules.h" #ifdef __cplusplus extern "C" { @@ -124,8 +125,6 @@ py_Type pk_Exception__register(); py_TValue pk_builtins__register(); -void pk__add_module_pkpy(); - #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 197246e8..23306d04 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -7,6 +7,10 @@ #include "pocketpy/common/config.h" #include "pocketpy/common/export.h" +#ifdef __cplusplus +extern "C" { +#endif + /************* Public Types *************/ typedef struct py_TValue py_TValue; typedef uint16_t py_Name; @@ -121,7 +125,7 @@ void* py_newobject(py_Ref out, py_Type type, int slots, int udsize); /************* Type Cast *************/ py_i64 py_toint(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); py_Type py_totype(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); void py_setdict(py_Ref self, py_Name name, py_Ref val); 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. /// 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. /// 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 *************/ /// Raise an exception by name and message. Always returns false. @@ -280,6 +286,8 @@ bool py_checkexc(); /// Clear the current exception. 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 TypeError(...) py_exception("TypeError", __VA_ARGS__) #define RuntimeError(...) py_exception("RuntimeError", __VA_ARGS__) diff --git a/include/pocketpy/xmacros/magics.h b/include/pocketpy/xmacros/magics.h index 51a1a2a7..7e8730c1 100644 --- a/include/pocketpy/xmacros/magics.h +++ b/include/pocketpy/xmacros/magics.h @@ -56,7 +56,6 @@ MAGIC_METHOD(__exit__) MAGIC_METHOD(__name__) MAGIC_METHOD(__all__) MAGIC_METHOD(__package__) -MAGIC_METHOD(__module_is_pending__) MAGIC_METHOD(__path__) MAGIC_METHOD(__class__) MAGIC_METHOD(__abs__) diff --git a/src/common/str.c b/src/common/str.c index 17d84710..a8b885b2 100644 --- a/src/common/str.c +++ b/src/common/str.c @@ -165,6 +165,16 @@ int c11_sv__count(c11_sv self, c11_sv sub) { 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 retval; c11_vector__ctor(&retval, sizeof(c11_sv)); diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 8dfcf398..47233cf0 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -257,6 +257,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { // fallback to getattr if(py_getattr(TOP(), byte.arg)) { py_assign(TOP(), py_retval()); + py_newnil(SP()++); } else { goto __ERROR; } @@ -757,8 +758,13 @@ 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; + const char* path = py_tostr(path_object); + int res = py_import(path); + if(res == -1) goto __ERROR; + if(res == 0) { + ImportError("module '%s' not found", path); + goto __ERROR; + } PUSH(py_retval()); DISPATCH(); } diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 4327eaf5..f266df72 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -6,7 +6,22 @@ #include "pocketpy/common/_generated.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); } @@ -147,6 +162,7 @@ void pk_VM__ctor(pk_VM* self) { const char** builtin_exceptions = (const char*[]){ "StackOverflowError", "IOError", + "OSError", "NotImplementedError", "TypeError", "IndexError", @@ -174,6 +190,8 @@ void pk_VM__ctor(pk_VM* self) { // add modules pk__add_module_pkpy(); + pk__add_module_os(); + pk__add_module_math(); 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) { - // return; + return; if(frame == NULL) return; 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)); break; } + case tp_module: { + py_Ref path = py_getdict(p, __path__); + pk_sprintf(&buf, "", py_tosv(path)); + break; + } default: { pk_sprintf(&buf, "(%t)", p->type); break; diff --git a/src/modules/math.c b/src/modules/math.c new file mode 100644 index 00000000..5cbde53e --- /dev/null +++ b/src/modules/math.c @@ -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 + +#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); +} \ No newline at end of file diff --git a/src/modules/os.c b/src/modules/os.c new file mode 100644 index 00000000..ddc53fda --- /dev/null +++ b/src/modules/os.c @@ -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 + +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 + +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); +} \ No newline at end of file diff --git a/src/public/pkpy.c b/src/modules/pkpy.c similarity index 100% rename from src/public/pkpy.c rename to src/modules/pkpy.c diff --git a/src/public/cast.c b/src/public/cast.c index f8cbbc16..788a1704 100644 --- a/src/public/cast.c +++ b/src/public/cast.c @@ -19,7 +19,7 @@ bool py_castfloat(py_Ref self, double* out) { switch(self->type) { case tp_int: *out = (double)self->_i64; 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,11 +46,9 @@ bool py_checktype(py_Ref self, py_Type type) { return TypeError("expected %t, got %t", type, self->type); } -bool py_isinstance(py_Ref obj, py_Type type){ - return py_issubclass(obj->type, type); -} +bool py_isinstance(py_Ref obj, py_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; do { if(derived == base) return true; diff --git a/src/public/modules.c b/src/public/modules.c index fb6ca331..5fbf3ddd 100644 --- a/src/public/modules.c +++ b/src/public/modules.c @@ -52,21 +52,53 @@ py_Ref py_newmodule(const char* 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; 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__); + 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); - 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); + if(package_sv.size == 0) { + return ImportError("attempted relative import with no known parent package"); + } + + 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); - return ok; + return res; } assert(path.data[0] != '.' && path.data[path.size - 1] != '.'); @@ -74,17 +106,10 @@ bool py_import(const char* path_cstr) { // 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 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("%s.py", slashed_path->data); @@ -96,33 +121,29 @@ bool py_import(const char* path_cstr) { goto __SUCCESS; } - c11_string__delete(filename); - filename = c11_string__new3("%s.py", slashed_path->data); - data = vm->import_file(slashed_path->data); + data = vm->import_file(filename->data); 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); + data = vm->import_file(filename->data); if(data != NULL) goto __SUCCESS; c11_string__delete(filename); c11_string__delete(slashed_path); - return ImportError("module %q not found", path); + return 0; __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); if(need_free) free((void*)data); - return ok; + return ok ? 1 : -1; } ////////////////////////// diff --git a/src/public/py_ops.c b/src/public/py_ops.c index ca6e38af..ef617caa 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -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); } diff --git a/src/public/py_str.c b/src/public/py_str.c index 2eebc86d..d1944cd0 100644 --- a/src/public/py_str.c +++ b/src/public/py_str.c @@ -247,9 +247,7 @@ static bool _py_str__startswith(int argc, py_Ref argv) { c11_string* self = py_touserdata(&argv[0]); PY_CHECK_ARG_TYPE(1, tp_str); c11_string* other = py_touserdata(&argv[1]); - c11_sv _0 = c11_sv__slice2(c11_string__sv(self), 0, other->size); - c11_sv _1 = c11_string__sv(other); - py_newbool(py_retval(), c11__sveq(_0, _1)); + py_newbool(py_retval(), c11_sv__startswith(c11_string__sv(self), c11_string__sv(other))); return true; } @@ -258,9 +256,7 @@ static bool _py_str__endswith(int argc, py_Ref argv) { c11_string* self = py_touserdata(&argv[0]); PY_CHECK_ARG_TYPE(1, tp_str); c11_string* other = py_touserdata(&argv[1]); - c11_sv _0 = c11_sv__slice2(c11_string__sv(self), self->size - other->size, self->size); - c11_sv _1 = c11_string__sv(other); - py_newbool(py_retval(), c11__sveq(_0, _1)); + py_newbool(py_retval(), c11_sv__endswith(c11_string__sv(self), c11_string__sv(other))); return true; } @@ -538,10 +534,6 @@ bool py_str(py_Ref val) { return py_call(tmp, 1, val); } -bool py_repr(py_Ref val) { - return pk_callmagic(__repr__, 1, val); -} +bool py_repr(py_Ref val) { return pk_callmagic(__repr__, 1, val); } -bool py_len(py_Ref val){ - return pk_callmagic(__len__, 1, val); -} \ No newline at end of file +bool py_len(py_Ref val) { return pk_callmagic(__len__, 1, val); } \ No newline at end of file diff --git a/src/public/stack_ops.c b/src/public/stack_ops.c index 4178b10d..04d9477a 100644 --- a/src/public/stack_ops.c +++ b/src/public/stack_ops.c @@ -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) { assert(self && self->is_ptr); if(!py_ismagicname(name) || self->type != tp_type) { diff --git a/tests/30_import.py b/tests/30_import.py index 25da33a1..f6af527f 100644 --- a/tests/30_import.py +++ b/tests/30_import.py @@ -4,6 +4,7 @@ except ImportError: exit(0) os.chdir('tests') +assert os.getcwd().endswith('tests') import test1 diff --git a/tests/40_class_ex.py b/tests/41_class_ex.py similarity index 100% rename from tests/40_class_ex.py rename to tests/41_class_ex.py diff --git a/tests/42_closure_ex.py b/tests/43_closure_ex.py similarity index 100% rename from tests/42_closure_ex.py rename to tests/43_closure_ex.py diff --git a/tests/43_eval.py b/tests/44_eval.py similarity index 100% rename from tests/43_eval.py rename to tests/44_eval.py diff --git a/tests/34_context.py b/tests/67_context.py similarity index 100% rename from tests/34_context.py rename to tests/67_context.py