mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 12:00:18 +00:00
support real exceptions
This commit is contained in:
parent
c79cd6dca6
commit
c6ec028730
2
.gitignore
vendored
2
.gitignore
vendored
@ -35,3 +35,5 @@ libpocketpy.dylib
|
|||||||
|
|
||||||
.xmake/
|
.xmake/
|
||||||
|
|
||||||
|
libpocketpy.dylib.dSYM/
|
||||||
|
main.dSYM/
|
@ -6,9 +6,9 @@ with open("include/pocketpy/opcodes.h", "rt", encoding='utf-8') as f:
|
|||||||
OPCODES_TEXT = '\n' + f.read() + '\n'
|
OPCODES_TEXT = '\n' + f.read() + '\n'
|
||||||
|
|
||||||
pipeline = [
|
pipeline = [
|
||||||
["config.h", "export.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
|
["config.h", "export.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h"],
|
||||||
["obj.h", "dict.h", "codeobject.h", "frame.h"],
|
["obj.h", "dict.h", "codeobject.h", "frame.h"],
|
||||||
["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"],
|
["gc.h", "vm.h", "ceval.h", "lexer.h", "expr.h", "compiler.h", "repl.h"],
|
||||||
["_generated.h", "cffi.h", "bindings.h", "iter.h", "base64.h", "csv.h", "collections.h", "random.h", "re.h", "linalg.h", "easing.h", "io.h"],
|
["_generated.h", "cffi.h", "bindings.h", "iter.h", "base64.h", "csv.h", "collections.h", "random.h", "re.h", "linalg.h", "easing.h", "io.h"],
|
||||||
["pocketpy.h", "pocketpy_c.h"]
|
["pocketpy.h", "pocketpy_c.h"]
|
||||||
]
|
]
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
#define PK_VERSION "1.3.5"
|
#define PK_VERSION "1.3.6"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "export.h"
|
#include "export.h"
|
||||||
|
@ -56,14 +56,11 @@ struct Exception {
|
|||||||
|
|
||||||
int _ip_on_error;
|
int _ip_on_error;
|
||||||
void* _code_on_error;
|
void* _code_on_error;
|
||||||
|
|
||||||
|
PyObject* _self; // weak reference
|
||||||
|
|
||||||
stack<ExceptionLine> stacktrace;
|
stack<ExceptionLine> stacktrace;
|
||||||
|
Exception(StrName type): type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {}
|
||||||
Exception(StrName type, Str msg):
|
|
||||||
type(type), msg(msg), is_re(true), _ip_on_error(-1), _code_on_error(nullptr) {}
|
|
||||||
bool match_type(StrName t) const {
|
|
||||||
return this->type==t || t.sv()=="Exception";
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void st_push(Args&&... args){
|
void st_push(Args&&... args){
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
#include "obj.h"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
@ -100,6 +101,7 @@ enum Precedence {
|
|||||||
enum StringType { NORMAL_STRING, RAW_STRING, F_STRING, NORMAL_BYTES };
|
enum StringType { NORMAL_STRING, RAW_STRING, F_STRING, NORMAL_BYTES };
|
||||||
|
|
||||||
struct Lexer {
|
struct Lexer {
|
||||||
|
VM* vm;
|
||||||
std::shared_ptr<SourceData> src;
|
std::shared_ptr<SourceData> src;
|
||||||
const char* token_start;
|
const char* token_start;
|
||||||
const char* curr_char;
|
const char* curr_char;
|
||||||
@ -129,12 +131,12 @@ struct Lexer {
|
|||||||
bool lex_one_token();
|
bool lex_one_token();
|
||||||
|
|
||||||
/***** Error Reporter *****/
|
/***** Error Reporter *****/
|
||||||
void throw_err(Str type, Str msg);
|
void throw_err(StrName type, Str msg);
|
||||||
void throw_err(Str type, Str msg, int lineno, const char* cursor);
|
void throw_err(StrName type, Str msg, int lineno, const char* cursor);
|
||||||
void SyntaxError(Str msg){ throw_err("SyntaxError", msg); }
|
void SyntaxError(Str msg){ throw_err("SyntaxError", msg); }
|
||||||
void SyntaxError(){ throw_err("SyntaxError", "invalid syntax"); }
|
void SyntaxError(){ throw_err("SyntaxError", "invalid syntax"); }
|
||||||
void IndentationError(Str msg){ throw_err("IndentationError", msg); }
|
void IndentationError(Str msg){ throw_err("IndentationError", msg); }
|
||||||
Lexer(std::shared_ptr<SourceData> src);
|
Lexer(VM* vm, std::shared_ptr<SourceData> src);
|
||||||
std::vector<Token> run();
|
std::vector<Token> run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ inline void gc_mark_namedict(NameDict& t){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Str obj_type_name(VM* vm, Type type);
|
StrName obj_type_name(VM* vm, Type type);
|
||||||
|
|
||||||
#if PK_DEBUG_NO_BUILTINS
|
#if PK_DEBUG_NO_BUILTINS
|
||||||
#define OBJ_NAME(obj) Str("<?>")
|
#define OBJ_NAME(obj) Str("<?>")
|
||||||
|
@ -140,6 +140,7 @@ struct SStream{
|
|||||||
SStream& operator<<(const std::string& s);
|
SStream& operator<<(const std::string& s);
|
||||||
SStream& operator<<(std::string_view s);
|
SStream& operator<<(std::string_view s);
|
||||||
SStream& operator<<(char c);
|
SStream& operator<<(char c);
|
||||||
|
SStream& operator<<(StrName sn);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
SStream& operator<<(T val){
|
SStream& operator<<(T val){
|
||||||
|
@ -52,7 +52,7 @@ struct PyTypeInfo{
|
|||||||
PyObject* obj; // never be garbage collected
|
PyObject* obj; // never be garbage collected
|
||||||
Type base;
|
Type base;
|
||||||
PyObject* mod; // never be garbage collected
|
PyObject* mod; // never be garbage collected
|
||||||
Str name;
|
StrName name;
|
||||||
bool subclass_enabled;
|
bool subclass_enabled;
|
||||||
|
|
||||||
std::vector<StrName> annotated_fields;
|
std::vector<StrName> annotated_fields;
|
||||||
@ -219,7 +219,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true);
|
PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true);
|
||||||
Type _new_type_object(StrName name, Type base=0);
|
Type _new_type_object(StrName name, Type base=0, bool subclass_enabled=false);
|
||||||
PyObject* _find_type_object(const Str& type);
|
PyObject* _find_type_object(const Str& type);
|
||||||
|
|
||||||
Type _type(const Str& type);
|
Type _type(const Str& type);
|
||||||
@ -362,37 +362,36 @@ public:
|
|||||||
PyObject* py_next(PyObject* obj);
|
PyObject* py_next(PyObject* obj);
|
||||||
|
|
||||||
/***** Error Reporter *****/
|
/***** Error Reporter *****/
|
||||||
void _error(StrName name, const Str& msg){
|
|
||||||
_error(Exception(name, msg));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _raise(bool re_raise=false);
|
void _raise(bool re_raise=false);
|
||||||
|
|
||||||
void StackOverflowError() { _error("StackOverflowError", ""); }
|
void _builtin_error(StrName type);
|
||||||
void IOError(const Str& msg) { _error("IOError", msg); }
|
void _builtin_error(StrName type, PyObject* arg);
|
||||||
void NotImplementedError(){ _error("NotImplementedError", ""); }
|
void _builtin_error(StrName type, const Str& msg);
|
||||||
void TypeError(const Str& msg){ _error("TypeError", msg); }
|
|
||||||
void IndexError(const Str& msg){ _error("IndexError", msg); }
|
void StackOverflowError() { _builtin_error("StackOverflowError"); }
|
||||||
void ValueError(const Str& msg){ _error("ValueError", msg); }
|
void IOError(const Str& msg) { _builtin_error("IOError", msg); }
|
||||||
void RuntimeError(const Str& msg){ _error("RuntimeError", msg); }
|
void NotImplementedError(){ _builtin_error("NotImplementedError"); }
|
||||||
void ZeroDivisionError(const Str& msg){ _error("ZeroDivisionError", msg); }
|
void TypeError(const Str& msg){ _builtin_error("TypeError", msg); }
|
||||||
void ZeroDivisionError(){ _error("ZeroDivisionError", "division by zero"); }
|
void IndexError(const Str& msg){ _builtin_error("IndexError", msg); }
|
||||||
void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); }
|
void ValueError(const Str& msg){ _builtin_error("ValueError", msg); }
|
||||||
void UnboundLocalError(StrName name){ _error("UnboundLocalError", fmt("local variable ", name.escape() + " referenced before assignment")); }
|
void RuntimeError(const Str& msg){ _builtin_error("RuntimeError", msg); }
|
||||||
void KeyError(PyObject* obj){ _error("KeyError", PK_OBJ_GET(Str, py_repr(obj))); }
|
void ZeroDivisionError(const Str& msg){ _builtin_error("ZeroDivisionError", msg); }
|
||||||
|
void ZeroDivisionError(){ _builtin_error("ZeroDivisionError", "division by zero"); }
|
||||||
|
void NameError(StrName name){ _builtin_error("NameError", fmt("name ", name.escape() + " is not defined")); }
|
||||||
|
void UnboundLocalError(StrName name){ _builtin_error("UnboundLocalError", fmt("local variable ", name.escape() + " referenced before assignment")); }
|
||||||
|
void KeyError(PyObject* obj){ _builtin_error("KeyError", obj); }
|
||||||
void BinaryOptError(const char* op) { TypeError(fmt("unsupported operand type(s) for ", op)); }
|
void BinaryOptError(const char* op) { TypeError(fmt("unsupported operand type(s) for ", op)); }
|
||||||
void ImportError(const Str& msg){ _error("ImportError", msg); }
|
void ImportError(const Str& msg){ _builtin_error("ImportError", msg); }
|
||||||
|
|
||||||
void AttributeError(PyObject* obj, StrName name){
|
void AttributeError(PyObject* obj, StrName name){
|
||||||
// OBJ_NAME calls getattr, which may lead to a infinite recursion
|
// OBJ_NAME calls getattr, which may lead to a infinite recursion
|
||||||
if(isinstance(obj, vm->tp_type)){
|
if(isinstance(obj, vm->tp_type)){
|
||||||
_error("AttributeError", fmt("type object ", OBJ_NAME(obj).escape(), " has no attribute ", name.escape()));
|
_builtin_error("AttributeError", fmt("type object ", OBJ_NAME(obj).escape(), " has no attribute ", name.escape()));
|
||||||
}else{
|
}else{
|
||||||
_error("AttributeError", fmt(OBJ_NAME(_t(obj)).escape(), " object has no attribute ", name.escape()));
|
_builtin_error("AttributeError", fmt(OBJ_NAME(_t(obj)).escape(), " object has no attribute ", name.escape()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void AttributeError(const Str& msg){ _builtin_error("AttributeError", msg); }
|
||||||
void AttributeError(Str msg){ _error("AttributeError", msg); }
|
|
||||||
|
|
||||||
void check_type(PyObject* obj, Type type){
|
void check_type(PyObject* obj, Type type){
|
||||||
if(is_type(obj, type)) return;
|
if(is_type(obj, type)) return;
|
||||||
@ -471,7 +470,7 @@ public:
|
|||||||
PyObject* bind_method(PyObject*, Str, NativeFuncC);
|
PyObject* bind_method(PyObject*, Str, NativeFuncC);
|
||||||
template<int ARGC>
|
template<int ARGC>
|
||||||
PyObject* bind_func(PyObject*, Str, NativeFuncC);
|
PyObject* bind_func(PyObject*, Str, NativeFuncC);
|
||||||
void _error(Exception);
|
void _error(PyObject*);
|
||||||
PyObject* _run_top_frame();
|
PyObject* _run_top_frame();
|
||||||
void post_init();
|
void post_init();
|
||||||
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
|
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
|
||||||
|
@ -268,9 +268,6 @@ def help(obj):
|
|||||||
print(obj.__doc__)
|
print(obj.__doc__)
|
||||||
|
|
||||||
|
|
||||||
class Exception: pass
|
|
||||||
|
|
||||||
|
|
||||||
class classmethod:
|
class classmethod:
|
||||||
def __init__(self, f):
|
def __init__(self, f):
|
||||||
self.f = f
|
self.f = f
|
||||||
@ -287,3 +284,40 @@ def complex(*args, **kwargs):
|
|||||||
def long(*args, **kwargs):
|
def long(*args, **kwargs):
|
||||||
import _long
|
import _long
|
||||||
return _long.long(*args, **kwargs)
|
return _long.long(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
# builtin exceptions
|
||||||
|
class SyntaxError(Exception): pass
|
||||||
|
class IndentationError(SyntaxError): pass
|
||||||
|
|
||||||
|
class StackOverflowError(Exception): pass
|
||||||
|
class IOError(Exception): pass
|
||||||
|
class NotImplementedError(Exception): pass
|
||||||
|
class TypeError(Exception): pass
|
||||||
|
class IndexError(Exception): pass
|
||||||
|
class ValueError(Exception): pass
|
||||||
|
class RuntimeError(Exception): pass
|
||||||
|
class ZeroDivisionError(Exception): pass
|
||||||
|
class NameError(Exception): pass
|
||||||
|
class UnboundLocalError(Exception): pass
|
||||||
|
class AttributeError(Exception): pass
|
||||||
|
class ImportError(Exception): pass
|
||||||
|
class AssertionError(Exception): pass
|
||||||
|
|
||||||
|
class KeyError(Exception):
|
||||||
|
def __init__(self, key=...):
|
||||||
|
self.key = key
|
||||||
|
if key is ...:
|
||||||
|
super().__init__()
|
||||||
|
else:
|
||||||
|
super().__init__(repr(key))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.key is ...:
|
||||||
|
return ''
|
||||||
|
return str(self.key)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self.key is ...:
|
||||||
|
return 'KeyError()'
|
||||||
|
return f'KeyError({self.key!r})'
|
||||||
|
@ -568,7 +568,7 @@ __NEXT_STEP:;
|
|||||||
TARGET(GOTO) {
|
TARGET(GOTO) {
|
||||||
StrName _name(byte.arg);
|
StrName _name(byte.arg);
|
||||||
int index = co->labels.try_get_likely_found(_name);
|
int index = co->labels.try_get_likely_found(_name);
|
||||||
if(index < 0) _error("KeyError", fmt("label ", _name.escape(), " not found"));
|
if(index < 0) RuntimeError(fmt("label ", _name.escape(), " not found"));
|
||||||
frame->jump_abs_break(index);
|
frame->jump_abs_break(index);
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
@ -787,20 +787,28 @@ __NEXT_STEP:;
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
TARGET(EXCEPTION_MATCH) {
|
TARGET(EXCEPTION_MATCH) {
|
||||||
const auto& e = CAST(Exception&, TOP());
|
PyObject* assumed_type = POPX();
|
||||||
PUSH(VAR(e.match_type(StrName(byte.arg))));
|
check_non_tagged_type(assumed_type, tp_type);
|
||||||
|
PyObject* e_obj = TOP();
|
||||||
|
bool ok = isinstance(e_obj, PK_OBJ_GET(Type, assumed_type));
|
||||||
|
PUSH(VAR(ok));
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
TARGET(RAISE) {
|
TARGET(RAISE) {
|
||||||
PyObject* _0 = POPX();
|
if(is_non_tagged_type(TOP(), tp_type)){
|
||||||
Str msg = _0 == None ? "" : CAST(Str, py_str(_0));
|
TOP() = call(TOP());
|
||||||
_error(StrName(byte.arg), msg);
|
}
|
||||||
|
if(!isinstance(TOP(), tp_exception)){
|
||||||
|
_builtin_error("TypeError", "exceptions must derive from Exception");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
_error(POPX());
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
TARGET(RAISE_ASSERT)
|
TARGET(RAISE_ASSERT)
|
||||||
if(byte.arg){
|
if(byte.arg){
|
||||||
PyObject* _0 = py_str(POPX());
|
PyObject* _0 = py_str(POPX());
|
||||||
_error("AssertionError", CAST(Str, _0));
|
_builtin_error("AssertionError", CAST(Str, _0));
|
||||||
}else{
|
}else{
|
||||||
_error("AssertionError", "");
|
_builtin_error("AssertionError");
|
||||||
}
|
}
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
TARGET(RE_RAISE) _raise(true); DISPATCH();
|
TARGET(RE_RAISE) _raise(true); DISPATCH();
|
||||||
@ -853,8 +861,8 @@ __NEXT_STEP:;
|
|||||||
continue;
|
continue;
|
||||||
}catch(UnhandledException& e){
|
}catch(UnhandledException& e){
|
||||||
PK_UNUSED(e);
|
PK_UNUSED(e);
|
||||||
PyObject* obj = POPX();
|
PyObject* e_obj = POPX();
|
||||||
Exception& _e = CAST(Exception&, obj);
|
Exception& _e = PK_OBJ_GET(Exception, e_obj);
|
||||||
_pop_frame();
|
_pop_frame();
|
||||||
if(callstack.empty()){
|
if(callstack.empty()){
|
||||||
#if PK_DEBUG_FULL_EXCEPTION
|
#if PK_DEBUG_FULL_EXCEPTION
|
||||||
@ -863,7 +871,7 @@ __NEXT_STEP:;
|
|||||||
throw _e;
|
throw _e;
|
||||||
}
|
}
|
||||||
frame = top_frame();
|
frame = top_frame();
|
||||||
PUSH(obj);
|
PUSH(e_obj);
|
||||||
if(frame.index < base_id) throw ToBeRaisedException();
|
if(frame.index < base_id) throw ToBeRaisedException();
|
||||||
need_raise = true;
|
need_raise = true;
|
||||||
}catch(ToBeRaisedException& e){
|
}catch(ToBeRaisedException& e){
|
||||||
|
@ -38,14 +38,14 @@ namespace pkpy{
|
|||||||
SyntaxError("maximum number of local variables exceeded");
|
SyntaxError("maximum number of local variables exceeded");
|
||||||
}
|
}
|
||||||
if(ctx()->co->consts.size() > 65535){
|
if(ctx()->co->consts.size() > 65535){
|
||||||
std::map<std::string, int> counts;
|
// std::map<std::string_view, int> counts;
|
||||||
for(PyObject* c: ctx()->co->consts){
|
// for(PyObject* c: ctx()->co->consts){
|
||||||
std::string key = obj_type_name(vm, vm->_tp(c)).str();
|
// std::string_view key = obj_type_name(vm, vm->_tp(c)).sv();
|
||||||
counts[key] += 1;
|
// counts[key] += 1;
|
||||||
}
|
// }
|
||||||
for(auto pair: counts){
|
// for(auto pair: counts){
|
||||||
std::cout << pair.first << ": " << pair.second << std::endl;
|
// std::cout << pair.first << ": " << pair.second << std::endl;
|
||||||
}
|
// }
|
||||||
SyntaxError("maximum number of constants exceeded");
|
SyntaxError("maximum number of constants exceeded");
|
||||||
}
|
}
|
||||||
if(codes.size() > 65535 && ctx()->co->src->mode != JSON_MODE){
|
if(codes.size() > 65535 && ctx()->co->src->mode != JSON_MODE){
|
||||||
@ -684,8 +684,9 @@ __EAT_DOTS_END:
|
|||||||
do {
|
do {
|
||||||
StrName as_name;
|
StrName as_name;
|
||||||
consume(TK("except"));
|
consume(TK("except"));
|
||||||
if(match(TK("@id"))){
|
if(is_expression()){
|
||||||
ctx()->emit_(OP_EXCEPTION_MATCH, StrName(prev().sv()).index, prev().line);
|
EXPR(false); // push assumed type on to the stack
|
||||||
|
ctx()->emit_(OP_EXCEPTION_MATCH, BC_NOARG, prev().line);
|
||||||
if(match(TK("as"))){
|
if(match(TK("as"))){
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
as_name = StrName(prev().sv());
|
as_name = StrName(prev().sv());
|
||||||
@ -880,14 +881,8 @@ __EAT_DOTS_END:
|
|||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK("raise"): {
|
case TK("raise"): {
|
||||||
consume(TK("@id"));
|
EXPR(false);
|
||||||
int dummy_t = StrName(prev().sv()).index;
|
ctx()->emit_(OP_RAISE, BC_NOARG, kw_line);
|
||||||
if(match(TK("(")) && !match(TK(")"))){
|
|
||||||
EXPR(false); consume(TK(")"));
|
|
||||||
}else{
|
|
||||||
ctx()->emit_(OP_LOAD_NONE, BC_NOARG, kw_line);
|
|
||||||
}
|
|
||||||
ctx()->emit_(OP_RAISE, dummy_t, kw_line);
|
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
} break;
|
} break;
|
||||||
case TK("del"): {
|
case TK("del"): {
|
||||||
@ -1161,7 +1156,7 @@ __EAT_DOTS_END:
|
|||||||
this->used = false;
|
this->used = false;
|
||||||
this->unknown_global_scope = unknown_global_scope;
|
this->unknown_global_scope = unknown_global_scope;
|
||||||
this->lexer = std::make_unique<Lexer>(
|
this->lexer = std::make_unique<Lexer>(
|
||||||
std::make_shared<SourceData>(source, filename, mode)
|
vm, std::make_shared<SourceData>(source, filename, mode)
|
||||||
);
|
);
|
||||||
init_pratt_rules();
|
init_pratt_rules();
|
||||||
}
|
}
|
||||||
@ -1202,4 +1197,12 @@ __EAT_DOTS_END:
|
|||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: refactor this
|
||||||
|
void Lexer::throw_err(StrName type, Str msg, int lineno, const char* cursor){
|
||||||
|
PyObject* e_obj = vm->call(vm->builtins->attr(type), VAR(msg));
|
||||||
|
Exception& e = PK_OBJ_GET(Exception, e_obj);
|
||||||
|
e.st_push(src, lineno, cursor, "");
|
||||||
|
e._self = e_obj;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
@ -52,7 +52,7 @@ namespace pkpy{
|
|||||||
for(PyObject* obj: gen) { obj->~PyObject(); pool64_dealloc(obj); }
|
for(PyObject* obj: gen) { obj->~PyObject(); pool64_dealloc(obj); }
|
||||||
#if PK_DEBUG_GC_STATS
|
#if PK_DEBUG_GC_STATS
|
||||||
for(auto& [type, count]: deleted){
|
for(auto& [type, count]: deleted){
|
||||||
std::cout << "GC: " << obj_type_name(vm, type) << "=" << count << std::endl;
|
std::cout << "GC: " << obj_type_name(vm, type).sv() << "=" << count << std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -455,7 +455,7 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lexer::throw_err(Str type, Str msg){
|
void Lexer::throw_err(StrName type, Str msg){
|
||||||
int lineno = current_line;
|
int lineno = current_line;
|
||||||
const char* cursor = curr_char;
|
const char* cursor = curr_char;
|
||||||
if(peekchar() == '\n'){
|
if(peekchar() == '\n'){
|
||||||
@ -465,14 +465,7 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
|||||||
throw_err(type, msg, lineno, cursor);
|
throw_err(type, msg, lineno, cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lexer::throw_err(Str type, Str msg, int lineno, const char* cursor){
|
Lexer::Lexer(VM* vm, std::shared_ptr<SourceData> src) : vm(vm), src(src) {
|
||||||
Exception e(type, msg);
|
|
||||||
e.st_push(src, lineno, cursor, "");
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
Lexer::Lexer(std::shared_ptr<SourceData> src) {
|
|
||||||
this->src = src;
|
|
||||||
this->token_start = src->source.c_str();
|
this->token_start = src->source.c_str();
|
||||||
this->curr_char = src->source.c_str();
|
this->curr_char = src->source.c_str();
|
||||||
this->nexts.push_back(Token{TK("@sof"), token_start, 0, current_line, brackets_level});
|
this->nexts.push_back(Token{TK("@sof"), token_start, 0, current_line, brackets_level});
|
||||||
|
@ -73,8 +73,8 @@ void init_builtins(VM* _vm) {
|
|||||||
vm->check_non_tagged_type(class_arg, vm->tp_type);
|
vm->check_non_tagged_type(class_arg, vm->tp_type);
|
||||||
Type type = PK_OBJ_GET(Type, class_arg);
|
Type type = PK_OBJ_GET(Type, class_arg);
|
||||||
if(!vm->isinstance(self_arg, type)){
|
if(!vm->isinstance(self_arg, type)){
|
||||||
Str _0 = obj_type_name(vm, vm->_tp(self_arg));
|
StrName _0 = obj_type_name(vm, vm->_tp(self_arg));
|
||||||
Str _1 = obj_type_name(vm, type);
|
StrName _1 = obj_type_name(vm, type);
|
||||||
vm->TypeError("super(): " + _0.escape() + " is not an instance of " + _1.escape());
|
vm->TypeError("super(): " + _0.escape() + " is not an instance of " + _1.escape());
|
||||||
}
|
}
|
||||||
return vm->heap.gcnew<Super>(vm->tp_super, self_arg, vm->_all_types[type].base);
|
return vm->heap.gcnew<Super>(vm->tp_super, self_arg, vm->_all_types[type].base);
|
||||||
@ -1296,9 +1296,27 @@ void init_builtins(VM* _vm) {
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
// Exception
|
// Exception
|
||||||
|
_vm->bind_constructor<-1>("Exception", [](VM* vm, ArgsView args){
|
||||||
|
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||||
|
StrName cls_name = obj_type_name(vm, cls);
|
||||||
|
PyObject* e_obj = vm->heap.gcnew<Exception>(cls, cls_name);
|
||||||
|
e_obj->_enable_instance_dict();
|
||||||
|
return e_obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind(_vm->_t(_vm->tp_exception), "__init__(self, msg=...)", [](VM* vm, ArgsView args){
|
||||||
|
Exception& self = _CAST(Exception&, args[0]);
|
||||||
|
if(args[1] == vm->Ellipsis){
|
||||||
|
self.msg = "";
|
||||||
|
}else{
|
||||||
|
self.msg = CAST(Str, args[1]);
|
||||||
|
}
|
||||||
|
return vm->None;
|
||||||
|
});
|
||||||
|
|
||||||
_vm->bind__repr__(_vm->tp_exception, [](VM* vm, PyObject* obj) {
|
_vm->bind__repr__(_vm->tp_exception, [](VM* vm, PyObject* obj) {
|
||||||
Exception& self = _CAST(Exception&, obj);
|
Exception& self = _CAST(Exception&, obj);
|
||||||
return VAR(fmt(self.type.sv(), '(', self.msg.escape(), ')'));
|
return VAR(fmt(obj_type_name(vm, obj->type), '(', self.msg.escape(), ')'));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__str__(_vm->tp_exception, [](VM* vm, PyObject* obj) {
|
_vm->bind__str__(_vm->tp_exception, [](VM* vm, PyObject* obj) {
|
||||||
@ -1616,7 +1634,7 @@ void VM::post_init(){
|
|||||||
});
|
});
|
||||||
bind_property(_t(tp_type), "__name__", [](VM* vm, ArgsView args){
|
bind_property(_t(tp_type), "__name__", [](VM* vm, ArgsView args){
|
||||||
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
|
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
|
||||||
return VAR(info.name);
|
return VAR(info.name.sv());
|
||||||
});
|
});
|
||||||
bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args){
|
bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args){
|
||||||
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
|
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
|
||||||
@ -1675,7 +1693,7 @@ void VM::post_init(){
|
|||||||
this->_exec(code, this->builtins);
|
this->_exec(code, this->builtins);
|
||||||
code = compile(kPythonLibs["_set"], "<set>", EXEC_MODE);
|
code = compile(kPythonLibs["_set"], "<set>", EXEC_MODE);
|
||||||
this->_exec(code, this->builtins);
|
this->_exec(code, this->builtins);
|
||||||
}catch(Exception& e){
|
}catch(const Exception& e){
|
||||||
std::cerr << e.summary() << std::endl;
|
std::cerr << e.summary() << std::endl;
|
||||||
std::cerr << "failed to load builtins module!!" << std::endl;
|
std::cerr << "failed to load builtins module!!" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -1705,11 +1723,11 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode, bool unknown
|
|||||||
Compiler compiler(this, std::move(source), filename, mode, unknown_global_scope);
|
Compiler compiler(this, std::move(source), filename, mode, unknown_global_scope);
|
||||||
try{
|
try{
|
||||||
return compiler.compile();
|
return compiler.compile();
|
||||||
}catch(Exception& e){
|
}catch(const Exception& e){
|
||||||
#if PK_DEBUG_FULL_EXCEPTION
|
#if PK_DEBUG_FULL_EXCEPTION
|
||||||
std::cerr << e.summary() << std::endl;
|
std::cerr << e.summary() << std::endl;
|
||||||
#endif
|
#endif
|
||||||
_error(e);
|
_error(e._self);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,12 +44,12 @@ static PyObject* stack_item(VM* vm, int index){
|
|||||||
|
|
||||||
#define PK_PROTECTED(__B) \
|
#define PK_PROTECTED(__B) \
|
||||||
try{ __B } \
|
try{ __B } \
|
||||||
catch(Exception& e ) { \
|
catch(const Exception& e ) { \
|
||||||
vm->_c.error = py_var(vm, e); \
|
vm->_c.error = e._self; \
|
||||||
return false; \
|
return false; \
|
||||||
} catch(const std::exception& re){ \
|
} catch(const std::exception& re){ \
|
||||||
auto e = Exception("std::exception", re.what()); \
|
PyObject* e_t = vm->_t(vm->tp_exception); \
|
||||||
vm->_c.error = py_var(vm, e); \
|
vm->_c.error = vm->call(e_t, VAR(re.what())); \
|
||||||
return false; \
|
return false; \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,9 +338,9 @@ static PyObject* c_function_wrapper(VM* vm, ArgsView args) {
|
|||||||
|
|
||||||
// propagate_if_errored
|
// propagate_if_errored
|
||||||
if (vm->_c.error != nullptr){
|
if (vm->_c.error != nullptr){
|
||||||
Exception e = _py_cast<Exception&>(vm, vm->_c.error);
|
PyObject* e_obj = PK_OBJ_GET(Exception, vm->_c.error)._self;
|
||||||
vm->_c.error = nullptr;
|
vm->_c.error = nullptr;
|
||||||
vm->_error(e);
|
vm->_error(e_obj);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
PK_ASSERT(retc == vm->s_data._sp-curr_sp);
|
PK_ASSERT(retc == vm->s_data._sp-curr_sp);
|
||||||
@ -495,7 +495,8 @@ bool pkpy_py_str(pkpy_vm* vm_handle) {
|
|||||||
bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) {
|
bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*) vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
vm->_c.error = py_var(vm, Exception(name, Str(message.data, message.size)));
|
PyObject* e_t = vm->_t(vm->tp_exception);
|
||||||
|
vm->_c.error = vm->call(e_t, VAR(std::string_view(message.data, message.size)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,7 +509,7 @@ bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
|||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*) vm_handle;
|
||||||
// no error
|
// no error
|
||||||
if (vm->_c.error == nullptr) return false;
|
if (vm->_c.error == nullptr) return false;
|
||||||
Exception& e = _py_cast<Exception&>(vm, vm->_c.error);
|
Exception& e = PK_OBJ_GET(Exception, vm->_c.error);
|
||||||
if (message != nullptr)
|
if (message != nullptr)
|
||||||
*message = e.summary().c_str_dup();
|
*message = e.summary().c_str_dup();
|
||||||
else
|
else
|
||||||
|
@ -465,6 +465,10 @@ int utf8len(unsigned char c, bool suppress){
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SStream& SStream::operator<<(StrName sn){
|
||||||
|
return *this << sn.sv();
|
||||||
|
}
|
||||||
|
|
||||||
SStream& SStream::operator<<(i64 val){
|
SStream& SStream::operator<<(i64 val){
|
||||||
// str(-2**64).__len__() == 21
|
// str(-2**64).__len__() == 21
|
||||||
buffer.reserve(buffer.size() + 24);
|
buffer.reserve(buffer.size() + 24);
|
||||||
|
33
src/vm.cpp
33
src/vm.cpp
@ -1,4 +1,5 @@
|
|||||||
#include "pocketpy/vm.h"
|
#include "pocketpy/vm.h"
|
||||||
|
#include "pocketpy/error.h"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
@ -172,11 +173,15 @@ namespace pkpy{
|
|||||||
_stderr(sum.data, sum.size);
|
_stderr(sum.data, sum.size);
|
||||||
}
|
}
|
||||||
#if !PK_DEBUG_FULL_EXCEPTION
|
#if !PK_DEBUG_FULL_EXCEPTION
|
||||||
catch (const std::exception& e) {
|
catch(const std::exception& e) {
|
||||||
Str msg = "An std::exception occurred! It could be a bug.\n";
|
Str msg = "An std::exception occurred! It could be a bug.\n";
|
||||||
msg = msg + e.what() + "\n";
|
msg = msg + e.what() + "\n";
|
||||||
_stderr(msg.data, msg.size);
|
_stderr(msg.data, msg.size);
|
||||||
}
|
}
|
||||||
|
catch(...) {
|
||||||
|
Str msg = "An unknown exception occurred! It could be a bug. Please report it to @blueloveTH on GitHub.\n";
|
||||||
|
_stderr(msg.data, msg.size);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
callstack.clear();
|
callstack.clear();
|
||||||
s_data.clear();
|
s_data.clear();
|
||||||
@ -201,15 +206,15 @@ namespace pkpy{
|
|||||||
obj,
|
obj,
|
||||||
base,
|
base,
|
||||||
mod,
|
mod,
|
||||||
name.sv(),
|
name,
|
||||||
subclass_enabled,
|
subclass_enabled,
|
||||||
};
|
};
|
||||||
_all_types.push_back(info);
|
_all_types.push_back(info);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type VM::_new_type_object(StrName name, Type base) {
|
Type VM::_new_type_object(StrName name, Type base, bool subclass_enabled) {
|
||||||
PyObject* obj = new_type_object(nullptr, name, base, false);
|
PyObject* obj = new_type_object(nullptr, name, base, subclass_enabled);
|
||||||
return PK_OBJ_GET(Type, obj);
|
return PK_OBJ_GET(Type, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,7 +730,7 @@ void VM::init_builtin_types(){
|
|||||||
PK_ASSERT(tp_bound_method == _new_type_object("bound_method"));
|
PK_ASSERT(tp_bound_method == _new_type_object("bound_method"));
|
||||||
|
|
||||||
PK_ASSERT(tp_super == _new_type_object("super"));
|
PK_ASSERT(tp_super == _new_type_object("super"));
|
||||||
PK_ASSERT(tp_exception == _new_type_object("_Exception"));
|
PK_ASSERT(tp_exception == _new_type_object("Exception", 0, true));
|
||||||
PK_ASSERT(tp_bytes == _new_type_object("bytes"));
|
PK_ASSERT(tp_bytes == _new_type_object("bytes"));
|
||||||
PK_ASSERT(tp_mappingproxy == _new_type_object("mappingproxy"));
|
PK_ASSERT(tp_mappingproxy == _new_type_object("mappingproxy"));
|
||||||
PK_ASSERT(tp_dict == _new_type_object("dict"));
|
PK_ASSERT(tp_dict == _new_type_object("dict"));
|
||||||
@ -757,6 +762,7 @@ void VM::init_builtin_types(){
|
|||||||
builtins->attr().set("StopIteration", StopIteration);
|
builtins->attr().set("StopIteration", StopIteration);
|
||||||
builtins->attr().set("NotImplemented", NotImplemented);
|
builtins->attr().set("NotImplemented", NotImplemented);
|
||||||
builtins->attr().set("slice", _t(tp_slice));
|
builtins->attr().set("slice", _t(tp_slice));
|
||||||
|
builtins->attr().set("Exception", _t(tp_exception));
|
||||||
|
|
||||||
post_init();
|
post_init();
|
||||||
this->_main = new_module("__main__");
|
this->_main = new_module("__main__");
|
||||||
@ -964,7 +970,7 @@ __FAST_CALL:
|
|||||||
if(new_f == cached_object__new__) {
|
if(new_f == cached_object__new__) {
|
||||||
// fast path for object.__new__
|
// fast path for object.__new__
|
||||||
Type t = PK_OBJ_GET(Type, callable);
|
Type t = PK_OBJ_GET(Type, callable);
|
||||||
obj= vm->heap.gcnew<DummyInstance>(t);
|
obj = vm->heap.gcnew<DummyInstance>(t);
|
||||||
}else{
|
}else{
|
||||||
PUSH(new_f);
|
PUSH(new_f);
|
||||||
PUSH(PY_NULL);
|
PUSH(PY_NULL);
|
||||||
@ -1134,7 +1140,7 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
|
|||||||
try{
|
try{
|
||||||
// fn(a, b, *c, d=1) -> None
|
// fn(a, b, *c, d=1) -> None
|
||||||
co = compile("def " + Str(sig) + " : pass", "<bind>", EXEC_MODE);
|
co = compile("def " + Str(sig) + " : pass", "<bind>", EXEC_MODE);
|
||||||
}catch(Exception&){
|
}catch(const Exception&){
|
||||||
throw std::runtime_error("invalid signature: " + std::string(sig));
|
throw std::runtime_error("invalid signature: " + std::string(sig));
|
||||||
}
|
}
|
||||||
if(co->func_decls.size() != 1){
|
if(co->func_decls.size() != 1){
|
||||||
@ -1163,12 +1169,19 @@ PyObject* VM::bind_property(PyObject* obj, Str name, NativeFuncC fget, NativeFun
|
|||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VM::_error(Exception e){
|
void VM::_builtin_error(StrName type){ _error(call(builtins->attr(type))); }
|
||||||
|
void VM::_builtin_error(StrName type, PyObject* arg){ _error(call(builtins->attr(type), arg)); }
|
||||||
|
void VM::_builtin_error(StrName type, const Str& msg){ _builtin_error(type, VAR(msg)); }
|
||||||
|
|
||||||
|
void VM::_error(PyObject* e_obj){
|
||||||
|
PK_ASSERT(isinstance(e_obj, tp_exception))
|
||||||
|
Exception& e = PK_OBJ_GET(Exception, e_obj);
|
||||||
|
e._self = e_obj;
|
||||||
if(callstack.empty()){
|
if(callstack.empty()){
|
||||||
e.is_re = false;
|
e.is_re = false;
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
PUSH(VAR(std::move(e)));
|
PUSH(e_obj);
|
||||||
_raise();
|
_raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1203,7 +1216,7 @@ void ManagedHeap::mark() {
|
|||||||
for(auto [_, co]: vm->_cached_codes) co->_gc_mark();
|
for(auto [_, co]: vm->_cached_codes) co->_gc_mark();
|
||||||
}
|
}
|
||||||
|
|
||||||
Str obj_type_name(VM *vm, Type type){
|
StrName obj_type_name(VM *vm, Type type){
|
||||||
return vm->_all_types[type].name;
|
return vm->_all_types[type].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,25 +1,3 @@
|
|||||||
# 无法测试 -----------------------------------------------
|
|
||||||
# #####: 41:static dylib_entry_t load_dylib(const char* path){
|
|
||||||
# #####: 42: std::error_code ec;
|
|
||||||
# #####: 43: auto p = std::filesystem::absolute(path, ec);
|
|
||||||
# #####: 44: if(ec) return nullptr;
|
|
||||||
# #####: 45: void* handle = dlopen(p.c_str(), RTLD_LAZY);
|
|
||||||
# #####: 46: if(!handle) return nullptr;
|
|
||||||
# #####: 47: return (dylib_entry_t)dlsym(handle, "pkpy_module__init__");
|
|
||||||
# #####: 48:}
|
|
||||||
|
|
||||||
# -----------------------------------------------
|
|
||||||
# 128: 107: _vm->bind_builtin_func<2>("super", [](VM* vm, ArgsView args) {
|
|
||||||
# 8: 108: vm->check_non_tagged_type(args[0], vm->tp_type);
|
|
||||||
# 8: 109: Type type = PK_OBJ_GET(Type, args[0]);
|
|
||||||
# 8: 110: if(!vm->isinstance(args[1], type)){
|
|
||||||
# #####: 111: Str _0 = obj_type_name(vm, PK_OBJ_GET(Type, vm->_t(args[1])));
|
|
||||||
# #####: 112: Str _1 = obj_type_name(vm, type);
|
|
||||||
# #####: 113: vm->TypeError("super(): " + _0.escape() + " is not an instance of " + _1.escape());
|
|
||||||
# #####: 114: }
|
|
||||||
# 8: 115: Type base = vm->_all_types[type].base;
|
|
||||||
# 16: 116: return vm->heap.gcnew(vm->tp_super, Super(args[1], base));
|
|
||||||
# 8: 117: });
|
|
||||||
# test super:
|
# test super:
|
||||||
class TestSuperBase():
|
class TestSuperBase():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -29,7 +7,7 @@ class TestSuperBase():
|
|||||||
return self.base_attr
|
return self.base_attr
|
||||||
|
|
||||||
def error(self):
|
def error(self):
|
||||||
raise Expection('未能拦截错误')
|
raise Exception('未能拦截错误')
|
||||||
|
|
||||||
|
|
||||||
class TestSuperChild1(TestSuperBase):
|
class TestSuperChild1(TestSuperBase):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user