mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-26 14:30:17 +00:00
Compare commits
4 Commits
04804ad410
...
50ec46fe83
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50ec46fe83 | ||
|
|
0c081ba912 | ||
|
|
7215f48007 | ||
|
|
aa3be3b63d |
@ -7,6 +7,7 @@ extern "C" {
|
||||
void pk__add_module_pkpy();
|
||||
void pk__add_module_os();
|
||||
void pk__add_module_math();
|
||||
void pk__add_module_dis();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -281,7 +281,7 @@ int py_import(const char* path) PY_RAISE;
|
||||
|
||||
/************* Errors *************/
|
||||
/// Raise an exception by name and message. Always returns false.
|
||||
bool py_exception(const char* name, const char* fmt, ...) PY_RAISE;
|
||||
bool py_exception(py_Type type, const char* fmt, ...) PY_RAISE;
|
||||
/// Raise an expection object. Always returns false.
|
||||
bool py_raise(py_Ref) PY_RAISE;
|
||||
/// Print the current exception.
|
||||
@ -290,22 +290,24 @@ void py_printexc();
|
||||
char* py_formatexc();
|
||||
/// Check if an exception is raised.
|
||||
bool py_checkexc();
|
||||
/// Check if the exception is an instance of the given type.
|
||||
bool py_matchexc(py_Type type);
|
||||
/// 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__)
|
||||
#define ValueError(...) py_exception("ValueError", __VA_ARGS__)
|
||||
#define IndexError(...) py_exception("IndexError", __VA_ARGS__)
|
||||
#define ImportError(...) py_exception("ImportError", __VA_ARGS__)
|
||||
#define NotImplementedError() py_exception("NotImplementedError", "")
|
||||
#define IOError(...) py_exception(tp_IOError, __VA_ARGS__)
|
||||
#define OSError(...) py_exception(tp_OSError, __VA_ARGS__)
|
||||
#define NameError(n) py_exception(tp_NameError, "name '%n' is not defined", (n))
|
||||
#define TypeError(...) py_exception(tp_TypeError, __VA_ARGS__)
|
||||
#define RuntimeError(...) py_exception(tp_RuntimeError, __VA_ARGS__)
|
||||
#define ValueError(...) py_exception(tp_ValueError, __VA_ARGS__)
|
||||
#define IndexError(...) py_exception(tp_IndexError, __VA_ARGS__)
|
||||
#define ImportError(...) py_exception(tp_ImportError, __VA_ARGS__)
|
||||
#define NotImplementedError() py_exception(tp_NotImplementedError, "")
|
||||
#define AttributeError(self, n) \
|
||||
py_exception("AttributeError", "'%t' object has no attribute '%n'", (self)->type, (n))
|
||||
py_exception(tp_AttributeError, "'%t' object has no attribute '%n'", (self)->type, (n))
|
||||
#define UnboundLocalError(n) \
|
||||
py_exception("UnboundLocalError", "local variable '%n' referenced before assignment", (n))
|
||||
py_exception(tp_UnboundLocalError, "local variable '%n' referenced before assignment", (n))
|
||||
|
||||
bool StopIteration();
|
||||
bool KeyError(py_Ref key) PY_RAISE;
|
||||
@ -429,6 +431,22 @@ enum py_PredefinedTypes {
|
||||
tp_ellipsis,
|
||||
tp_SyntaxError,
|
||||
tp_StopIteration,
|
||||
/* builtin exceptions */
|
||||
tp_StackOverflowError,
|
||||
tp_IOError,
|
||||
tp_OSError,
|
||||
tp_NotImplementedError,
|
||||
tp_TypeError,
|
||||
tp_IndexError,
|
||||
tp_ValueError,
|
||||
tp_RuntimeError,
|
||||
tp_ZeroDivisionError,
|
||||
tp_NameError,
|
||||
tp_UnboundLocalError,
|
||||
tp_AttributeError,
|
||||
tp_ImportError,
|
||||
tp_AssertionError,
|
||||
tp_KeyError,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -137,7 +137,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
Function__ctor(ud, decl, &frame->module);
|
||||
if(decl->nested) {
|
||||
ud->closure = FastLocals__to_namedict(frame->locals, frame->locals_co);
|
||||
py_Name name = py_namev(c11_string__sv(decl->code.name));
|
||||
py_Name name = py_name(decl->code.name->data);
|
||||
// capture itself to allow recursion
|
||||
NameDict__set(ud->closure, name, *SP());
|
||||
}
|
||||
@ -909,9 +909,9 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
if(byte.arg) {
|
||||
if(!py_str(TOP())) goto __ERROR;
|
||||
POP();
|
||||
py_exception("AssertionError", "%s", py_tostr(py_retval()));
|
||||
py_exception(tp_AssertionError, "%s", py_tostr(py_retval()));
|
||||
} else {
|
||||
py_exception("AssertionError", "");
|
||||
py_exception(tp_AssertionError, "");
|
||||
}
|
||||
goto __ERROR;
|
||||
}
|
||||
@ -1010,7 +1010,7 @@ bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop) {
|
||||
py_newbool(py_retval(), res);
|
||||
return true;
|
||||
}
|
||||
return py_exception("TypeError", "unsupported operand type(s) for '%n'", op);
|
||||
return TypeError("unsupported operand type(s) for '%n'", op);
|
||||
}
|
||||
|
||||
bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include "pocketpy/interpreter/frame.h"
|
||||
#include "pocketpy/objects/codeobject.h"
|
||||
#include "pocketpy/objects/object.h"
|
||||
|
||||
void ValueStack__ctor(ValueStack* self) {
|
||||
@ -131,9 +132,8 @@ void Frame__set_unwind_target(Frame* self, py_TValue* sp) {
|
||||
}
|
||||
|
||||
py_TValue* Frame__f_closure_try_get(Frame* self, py_Name name) {
|
||||
// if(self->function == NULL) return NULL;
|
||||
// pkpy::Function* fn = PyObject__as(pkpy::Function, self->function);
|
||||
// if(fn->_closure == nullptr) return nullptr;
|
||||
// return NameDict__try_get(fn->_closure, name);
|
||||
return NULL;
|
||||
if(self->function == NULL) return NULL;
|
||||
Function* ud = PyObject__userdata(self->function);
|
||||
if(ud->closure == NULL) return NULL;
|
||||
return NameDict__try_get(ud->closure, name);
|
||||
}
|
||||
@ -129,10 +129,36 @@ void VM__ctor(VM* self) {
|
||||
|
||||
validate(tp_SyntaxError, pk_newtype("SyntaxError", tp_Exception, NULL, NULL, false, true));
|
||||
validate(tp_StopIteration, pk_newtype("StopIteration", tp_Exception, NULL, NULL, false, true));
|
||||
#undef validate
|
||||
|
||||
self->builtins = pk_builtins__register();
|
||||
|
||||
// inject some builtin expections
|
||||
#define INJECT_BUILTIN_EXC(name) \
|
||||
do { \
|
||||
py_Type type = pk_newtype(#name, tp_Exception, &self->builtins, NULL, false, true); \
|
||||
py_setdict(&self->builtins, py_name(#name), py_tpobject(type)); \
|
||||
validate(tp_##name, type); \
|
||||
} while(0)
|
||||
|
||||
INJECT_BUILTIN_EXC(StackOverflowError);
|
||||
INJECT_BUILTIN_EXC(IOError);
|
||||
INJECT_BUILTIN_EXC(OSError);
|
||||
INJECT_BUILTIN_EXC(NotImplementedError);
|
||||
INJECT_BUILTIN_EXC(TypeError);
|
||||
INJECT_BUILTIN_EXC(IndexError);
|
||||
INJECT_BUILTIN_EXC(ValueError);
|
||||
INJECT_BUILTIN_EXC(RuntimeError);
|
||||
INJECT_BUILTIN_EXC(ZeroDivisionError);
|
||||
INJECT_BUILTIN_EXC(NameError);
|
||||
INJECT_BUILTIN_EXC(UnboundLocalError);
|
||||
INJECT_BUILTIN_EXC(AttributeError);
|
||||
INJECT_BUILTIN_EXC(ImportError);
|
||||
INJECT_BUILTIN_EXC(AssertionError);
|
||||
INJECT_BUILTIN_EXC(KeyError);
|
||||
|
||||
#undef INJECT_BUILTIN_EXC
|
||||
#undef validate
|
||||
|
||||
/* Setup Public Builtin Types */
|
||||
py_Type public_types[] = {tp_object, tp_type, tp_int, tp_float,
|
||||
tp_bool, tp_str, tp_list, tp_tuple,
|
||||
@ -146,40 +172,13 @@ void VM__ctor(VM* self) {
|
||||
py_setdict(&self->builtins, ti->name, py_tpobject(t));
|
||||
}
|
||||
|
||||
// inject some builtin expections
|
||||
const char** builtin_exceptions = (const char*[]){
|
||||
"StackOverflowError",
|
||||
"IOError",
|
||||
"OSError",
|
||||
"NotImplementedError",
|
||||
"TypeError",
|
||||
"IndexError",
|
||||
"ValueError",
|
||||
"RuntimeError",
|
||||
"ZeroDivisionError",
|
||||
"NameError",
|
||||
"UnboundLocalError",
|
||||
"AttributeError",
|
||||
"ImportError",
|
||||
"AssertionError",
|
||||
"KeyError",
|
||||
NULL, // sentinel
|
||||
};
|
||||
const char** it = builtin_exceptions;
|
||||
while(*it) {
|
||||
py_Type type = pk_newtype(*it, tp_Exception, &self->builtins, NULL, false, true);
|
||||
py_setdict(&self->builtins, py_name(*it), py_tpobject(type));
|
||||
it++;
|
||||
}
|
||||
|
||||
py_TValue tmp;
|
||||
py_newnotimplemented(&tmp);
|
||||
py_setdict(&self->builtins, py_name("NotImplemented"), &tmp);
|
||||
py_newnotimplemented(py_emplacedict(&self->builtins, py_name("NotImplemented")));
|
||||
|
||||
// add modules
|
||||
pk__add_module_pkpy();
|
||||
pk__add_module_os();
|
||||
pk__add_module_math();
|
||||
pk__add_module_dis();
|
||||
|
||||
self->main = *py_newmodule("__main__");
|
||||
}
|
||||
@ -386,7 +385,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
||||
/*****************_py_call*****************/
|
||||
// check stack overflow
|
||||
if(self->stack.sp > self->stack.end) {
|
||||
py_exception("StackOverflowError", "");
|
||||
py_exception(tp_StackOverflowError, "");
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
|
||||
127
src/modules/dis.c
Normal file
127
src/modules/dis.c
Normal file
@ -0,0 +1,127 @@
|
||||
#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 void disassemble(CodeObject* co) {
|
||||
c11_vector /*T=int*/ jumpTargets;
|
||||
c11_vector__ctor(&jumpTargets, sizeof(int));
|
||||
for(int i = 0; i < co->codes.count; i++) {
|
||||
Bytecode* bc = c11__at(Bytecode, &co->codes, i);
|
||||
if(Bytecode__is_forward_jump(bc)) {
|
||||
int target = (int16_t)bc->arg + i;
|
||||
c11_vector__push(int, &jumpTargets, target);
|
||||
}
|
||||
}
|
||||
|
||||
c11_sbuf ss;
|
||||
c11_sbuf__ctor(&ss);
|
||||
|
||||
int prev_line = -1;
|
||||
for(int i = 0; i < co->codes.count; i++) {
|
||||
Bytecode byte = c11__getitem(Bytecode, &co->codes, i);
|
||||
BytecodeEx ex = c11__getitem(BytecodeEx, &co->codes_ex, i);
|
||||
|
||||
char line[8] = "";
|
||||
if(ex.lineno == prev_line) {
|
||||
// do nothing
|
||||
} else {
|
||||
snprintf(line, sizeof(line), "%d", ex.lineno);
|
||||
if(prev_line != -1) c11_sbuf__write_char(&ss, '\n');
|
||||
prev_line = ex.lineno;
|
||||
}
|
||||
|
||||
char pointer[4] = "";
|
||||
c11__foreach(int, &jumpTargets, it) {
|
||||
if(*it == i) {
|
||||
snprintf(pointer, sizeof(pointer), "->");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%-8s%-3s%-3d ", line, pointer, i);
|
||||
c11_sbuf__write_cstr(&ss, buf);
|
||||
|
||||
c11_sbuf__write_cstr(&ss, pk_opname(byte.op));
|
||||
c11_sbuf__write_char(&ss, ex.is_virtual ? '*' : ' ');
|
||||
int padding = 24 - strlen(pk_opname(byte.op));
|
||||
for(int j = 0; j < padding; j++)
|
||||
c11_sbuf__write_char(&ss, ' ');
|
||||
|
||||
do {
|
||||
if(Bytecode__is_forward_jump(&byte)) {
|
||||
pk_sprintf(&ss, "%d (to %d)", (int16_t)byte.arg, (int16_t)byte.arg + i);
|
||||
break;
|
||||
}
|
||||
|
||||
c11_sbuf__write_int(&ss, byte.arg);
|
||||
switch(byte.op) {
|
||||
case OP_LOAD_CONST:
|
||||
case OP_FORMAT_STRING:
|
||||
case OP_IMPORT_PATH: {
|
||||
py_Ref path = c11__at(py_TValue, &co->consts, byte.arg);
|
||||
pk_sprintf(&ss, " (%q)", py_tosv(path));
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_NAME:
|
||||
case OP_LOAD_GLOBAL:
|
||||
case OP_LOAD_NONLOCAL:
|
||||
case OP_STORE_GLOBAL:
|
||||
case OP_LOAD_ATTR:
|
||||
case OP_LOAD_METHOD:
|
||||
case OP_STORE_ATTR:
|
||||
case OP_DELETE_ATTR:
|
||||
case OP_BEGIN_CLASS:
|
||||
case OP_GOTO:
|
||||
case OP_DELETE_GLOBAL:
|
||||
case OP_STORE_CLASS_ATTR: {
|
||||
pk_sprintf(&ss, " (%n)", byte.arg);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_FAST:
|
||||
case OP_STORE_FAST:
|
||||
case OP_DELETE_FAST: {
|
||||
py_Name name = c11__getitem(py_Name, &co->varnames, byte.arg);
|
||||
pk_sprintf(&ss, " (%n)", name);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_FUNCTION: {
|
||||
const FuncDecl* decl = c11__getitem(FuncDecl*, &co->func_decls, byte.arg);
|
||||
pk_sprintf(&ss, " (%s)", decl->code.name->data);
|
||||
break;
|
||||
}
|
||||
case OP_BINARY_OP: {
|
||||
py_Name name = byte.arg & 0xFF;
|
||||
pk_sprintf(&ss, " (%n)", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(0);
|
||||
|
||||
if(i != co->codes.count - 1) c11_sbuf__write_char(&ss, '\n');
|
||||
}
|
||||
|
||||
c11_string* output = c11_sbuf__submit(&ss);
|
||||
pk_current_vm->print(output->data);
|
||||
pk_current_vm->print("\n");
|
||||
c11_string__delete(output);
|
||||
c11_vector__dtor(&jumpTargets);
|
||||
}
|
||||
|
||||
static bool dis_dis(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_function);
|
||||
Function* ud = py_touserdata(argv);
|
||||
disassemble(&ud->decl->code);
|
||||
py_newnone(py_retval());
|
||||
return true;
|
||||
}
|
||||
|
||||
void pk__add_module_dis() {
|
||||
py_Ref mod = py_newmodule("dis");
|
||||
|
||||
py_bindfunc(mod, "dis", dis_dis);
|
||||
}
|
||||
@ -5,14 +5,14 @@
|
||||
#include "pocketpy/common/sstream.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
#if _WIN32
|
||||
#if PY_SYS_PLATFORM == 0
|
||||
#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__
|
||||
#elif PY_SYS_PLATFORM == 3 || PY_SYS_PLATFORM == 5
|
||||
#include <unistd.h>
|
||||
|
||||
int platform_chdir(const char* path) { return chdir(path); }
|
||||
|
||||
@ -77,119 +77,13 @@ const char* pk_opname(Opcode op) {
|
||||
return OP_NAMES[op];
|
||||
}
|
||||
|
||||
static void disassemble(CodeObject* co) {
|
||||
c11_vector /*T=int*/ jumpTargets;
|
||||
c11_vector__ctor(&jumpTargets, sizeof(int));
|
||||
for(int i = 0; i < co->codes.count; i++) {
|
||||
Bytecode* bc = c11__at(Bytecode, &co->codes, i);
|
||||
if(Bytecode__is_forward_jump(bc)) {
|
||||
int target = (int16_t)bc->arg + i;
|
||||
c11_vector__push(int, &jumpTargets, target);
|
||||
}
|
||||
}
|
||||
|
||||
c11_sbuf ss;
|
||||
c11_sbuf__ctor(&ss);
|
||||
|
||||
int prev_line = -1;
|
||||
for(int i = 0; i < co->codes.count; i++) {
|
||||
Bytecode byte = c11__getitem(Bytecode, &co->codes, i);
|
||||
BytecodeEx ex = c11__getitem(BytecodeEx, &co->codes_ex, i);
|
||||
|
||||
char line[8] = "";
|
||||
if(ex.lineno == prev_line) {
|
||||
// do nothing
|
||||
} else {
|
||||
snprintf(line, sizeof(line), "%d", ex.lineno);
|
||||
if(prev_line != -1) c11_sbuf__write_char(&ss, '\n');
|
||||
prev_line = ex.lineno;
|
||||
}
|
||||
|
||||
char pointer[4] = "";
|
||||
c11__foreach(int, &jumpTargets, it) {
|
||||
if(*it == i) {
|
||||
snprintf(pointer, sizeof(pointer), "->");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "%-8s%-3s%-3d ", line, pointer, i);
|
||||
c11_sbuf__write_cstr(&ss, buf);
|
||||
|
||||
c11_sbuf__write_cstr(&ss, pk_opname(byte.op));
|
||||
c11_sbuf__write_char(&ss, ex.is_virtual ? '*' : ' ');
|
||||
int padding = 24 - strlen(pk_opname(byte.op));
|
||||
for(int j = 0; j < padding; j++)
|
||||
c11_sbuf__write_char(&ss, ' ');
|
||||
|
||||
do {
|
||||
if(Bytecode__is_forward_jump(&byte)) {
|
||||
pk_sprintf(&ss, "%d (to %d)", (int16_t)byte.arg, (int16_t)byte.arg + i);
|
||||
break;
|
||||
}
|
||||
|
||||
c11_sbuf__write_int(&ss, byte.arg);
|
||||
switch(byte.op) {
|
||||
case OP_LOAD_CONST:
|
||||
case OP_FORMAT_STRING:
|
||||
case OP_IMPORT_PATH: {
|
||||
py_Ref path = c11__at(py_TValue, &co->consts, byte.arg);
|
||||
pk_sprintf(&ss, " (%q)", py_tosv(path));
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_NAME:
|
||||
case OP_LOAD_GLOBAL:
|
||||
case OP_LOAD_NONLOCAL:
|
||||
case OP_STORE_GLOBAL:
|
||||
case OP_LOAD_ATTR:
|
||||
case OP_LOAD_METHOD:
|
||||
case OP_STORE_ATTR:
|
||||
case OP_DELETE_ATTR:
|
||||
case OP_BEGIN_CLASS:
|
||||
case OP_GOTO:
|
||||
case OP_DELETE_GLOBAL:
|
||||
case OP_STORE_CLASS_ATTR: {
|
||||
pk_sprintf(&ss, " (%n)", byte.arg);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_FAST:
|
||||
case OP_STORE_FAST:
|
||||
case OP_DELETE_FAST: {
|
||||
py_Name name = c11__getitem(py_Name, &co->varnames, byte.arg);
|
||||
pk_sprintf(&ss, " (%n)", name);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_FUNCTION: {
|
||||
const FuncDecl* decl = c11__getitem(FuncDecl*, &co->func_decls, byte.arg);
|
||||
pk_sprintf(&ss, " (%s)", decl->code.name->data);
|
||||
break;
|
||||
}
|
||||
case OP_BINARY_OP: {
|
||||
py_Name name = byte.arg & 0xFF;
|
||||
pk_sprintf(&ss, " (%n)", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(0);
|
||||
|
||||
if(i != co->codes.count - 1) c11_sbuf__write_char(&ss, '\n');
|
||||
}
|
||||
|
||||
c11_string* output = c11_sbuf__submit(&ss);
|
||||
pk_current_vm->print(output->data);
|
||||
pk_current_vm->print("\n");
|
||||
c11_string__delete(output);
|
||||
c11_vector__dtor(&jumpTargets);
|
||||
}
|
||||
|
||||
bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) {
|
||||
VM* vm = pk_current_vm;
|
||||
CodeObject co;
|
||||
SourceData_ src = SourceData__rcnew(source, filename, mode, false);
|
||||
Error* err = pk_compile(src, &co);
|
||||
if(err) {
|
||||
py_exception("SyntaxError", err->msg);
|
||||
py_exception(tp_SyntaxError, err->msg);
|
||||
py_BaseException__stpush(&vm->curr_exception, src, err->lineno, NULL);
|
||||
|
||||
PK_DECREF(src);
|
||||
@ -197,7 +91,6 @@ bool py_exec(const char* source, const char* filename, enum py_CompileMode mode,
|
||||
return false;
|
||||
}
|
||||
|
||||
// disassemble(&co);
|
||||
if(!module) module = &vm->main;
|
||||
|
||||
Frame* frame = Frame__new(&co, module, NULL, vm->stack.sp, vm->stack.sp, &co);
|
||||
|
||||
@ -218,7 +218,7 @@ static bool builtins__next(int argc, py_Ref argv) {
|
||||
int res = py_next(argv);
|
||||
if(res == -1) return false;
|
||||
if(res) return true;
|
||||
return py_exception("StopIteration", "");
|
||||
return py_exception(tp_StopIteration, "");
|
||||
}
|
||||
|
||||
static bool builtins__sorted(int argc, py_Ref argv) {
|
||||
@ -355,6 +355,25 @@ static bool builtins__issubclass(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool builtins__getattr(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||
py_Name name = py_namev(py_tosv(py_arg(1)));
|
||||
if(argc == 2) {
|
||||
return py_getattr(py_arg(0), name);
|
||||
} else if(argc == 3) {
|
||||
py_StackRef p0 = py_peek(0);
|
||||
bool ok = py_getattr(py_arg(0), name);
|
||||
if(!ok && py_matchexc(tp_AttributeError)) {
|
||||
py_clearexc(p0);
|
||||
return py_arg(2); // default value
|
||||
}
|
||||
return ok;
|
||||
} else {
|
||||
return TypeError("getattr() expected 2 or 3 arguments");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
py_TValue pk_builtins__register() {
|
||||
py_Ref builtins = py_newmodule("builtins");
|
||||
py_bindfunc(builtins, "repr", builtins__repr);
|
||||
@ -377,14 +396,42 @@ py_TValue pk_builtins__register() {
|
||||
py_bindfunc(builtins, "isinstance", builtins__isinstance);
|
||||
py_bindfunc(builtins, "issubclass", builtins__issubclass);
|
||||
|
||||
py_bindfunc(builtins, "getattr", builtins__getattr);
|
||||
|
||||
// None __repr__
|
||||
py_bindmagic(tp_NoneType, __repr__, NoneType__repr__);
|
||||
return *builtins;
|
||||
}
|
||||
|
||||
static bool function__closure__getter(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
Function* ud = py_touserdata(argv);
|
||||
if(!ud->closure) {
|
||||
py_newnone(py_retval());
|
||||
return true;
|
||||
}
|
||||
py_Ref r0 = py_pushtmp();
|
||||
py_Ref retval = py_pushtmp();
|
||||
py_newdict(retval);
|
||||
c11__foreach(NameDict_KV, ud->closure, it) {
|
||||
// printf("%s -> %s\n", py_name2str(it->key), py_tpname(it->value.type));
|
||||
py_newstr(r0, py_name2str(it->key));
|
||||
py_dict__setitem(retval, r0, &it->value);
|
||||
if(py_checkexc()) {
|
||||
py_shrink(2);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
py_assign(py_retval(), retval);
|
||||
py_shrink(2);
|
||||
return true;
|
||||
}
|
||||
|
||||
py_Type pk_function__register() {
|
||||
py_Type type =
|
||||
pk_newtype("function", tp_object, NULL, (void (*)(void*))Function__dtor, false, true);
|
||||
|
||||
py_bindproperty(type, "__closure__", function__closure__getter, NULL);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
@ -115,6 +115,12 @@ bool py_checkexc() {
|
||||
return !py_isnil(&vm->curr_exception);
|
||||
}
|
||||
|
||||
bool py_matchexc(py_Type type) {
|
||||
VM* vm = pk_current_vm;
|
||||
if(py_isnil(&vm->curr_exception)) return false;
|
||||
return py_issubclass(vm->curr_exception.type, type);
|
||||
}
|
||||
|
||||
void py_clearexc(py_StackRef p0) {
|
||||
VM* vm = pk_current_vm;
|
||||
vm->last_retval = *py_NIL;
|
||||
@ -145,10 +151,10 @@ char* py_formatexc() {
|
||||
for(int i = ud->stacktrace.count - 1; i >= 0; i--) {
|
||||
BaseExceptionFrame* frame = c11__at(BaseExceptionFrame, &ud->stacktrace, i);
|
||||
SourceData__snapshot(frame->src,
|
||||
&ss,
|
||||
frame->lineno,
|
||||
NULL,
|
||||
frame->name ? frame->name->data : NULL);
|
||||
&ss,
|
||||
frame->lineno,
|
||||
NULL,
|
||||
frame->name ? frame->name->data : NULL);
|
||||
c11_sbuf__write_char(&ss, '\n');
|
||||
}
|
||||
|
||||
@ -169,7 +175,7 @@ char* py_formatexc() {
|
||||
return dup;
|
||||
}
|
||||
|
||||
bool py_exception(const char* name, const char* fmt, ...) {
|
||||
bool py_exception(py_Type type, const char* fmt, ...) {
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
va_list args;
|
||||
@ -180,9 +186,7 @@ bool py_exception(const char* name, const char* fmt, ...) {
|
||||
py_Ref message = py_pushtmp();
|
||||
c11_sbuf__py_submit(&buf, message);
|
||||
|
||||
py_Ref exc_type = py_getdict(&pk_current_vm->builtins, py_name(name));
|
||||
if(exc_type == NULL) c11__abort("py_exception(): '%s' not found", name);
|
||||
bool ok = py_call(exc_type, 1, message);
|
||||
bool ok = py_tpcall(type, 1, message);
|
||||
if(!ok) c11__abort("py_exception(): failed to create exception object");
|
||||
py_pop();
|
||||
|
||||
@ -197,8 +201,7 @@ bool py_raise(py_Ref exc) {
|
||||
}
|
||||
|
||||
bool KeyError(py_Ref key) {
|
||||
py_Ref cls = py_getdict(&pk_current_vm->builtins, py_name("KeyError"));
|
||||
bool ok = py_call(cls, 1, key);
|
||||
bool ok = py_tpcall(tp_KeyError, 1, key);
|
||||
if(!ok) return false;
|
||||
return py_raise(py_retval());
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user