mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
fix bugs
This commit is contained in:
parent
360efc0805
commit
c680da3154
@ -150,4 +150,20 @@ PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i);
|
|||||||
|
|
||||||
```
|
```
|
||||||
[value] -> [repr(value)]
|
[value] -> [repr(value)]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
+ `bool pkpy_py_str(pkpy_vm*)`
|
||||||
|
|
||||||
|
Get the str of the value at the top of the stack.
|
||||||
|
|
||||||
|
```
|
||||||
|
[value] -> [str(value)]
|
||||||
|
```
|
||||||
|
|
||||||
|
+ `bool pkpy_py_import(pkpy_vm*, const char* name)`
|
||||||
|
|
||||||
|
Import a module and push it onto the stack.
|
||||||
|
|
||||||
|
```
|
||||||
|
[] -> [module]
|
||||||
|
```
|
||||||
|
@ -75,6 +75,14 @@ struct ValueStack {
|
|||||||
ValueStack& operator=(ValueStack&&) = delete;
|
ValueStack& operator=(ValueStack&&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct UnwindTarget{
|
||||||
|
UnwindTarget* next;
|
||||||
|
int iblock;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
UnwindTarget(int iblock, int offset): next(nullptr), iblock(iblock), offset(offset) {}
|
||||||
|
};
|
||||||
|
|
||||||
struct Frame {
|
struct Frame {
|
||||||
const Bytecode* _ip;
|
const Bytecode* _ip;
|
||||||
// This is for unwinding only, use `actual_sp_base()` for value stack access
|
// This is for unwinding only, use `actual_sp_base()` for value stack access
|
||||||
@ -85,21 +93,24 @@ struct Frame {
|
|||||||
PyVar _callable; // a function object or nullptr (global scope)
|
PyVar _callable; // a function object or nullptr (global scope)
|
||||||
FastLocals _locals;
|
FastLocals _locals;
|
||||||
|
|
||||||
|
// This list will be freed in __pop_frame
|
||||||
|
UnwindTarget* _uw_list;
|
||||||
|
|
||||||
NameDict& f_globals() { return _module->attr(); }
|
NameDict& f_globals() { return _module->attr(); }
|
||||||
PyVar f_closure_try_get(StrName name);
|
PyVar f_closure_try_get(StrName name);
|
||||||
int ip() const { return _ip - co->codes.data(); }
|
int ip() const { return _ip - co->codes.data(); }
|
||||||
|
|
||||||
// function scope
|
// function scope
|
||||||
Frame(PyVar* p0, const CodeObject* co, PyVar _module, PyVar _callable, PyVar* _locals_base)
|
Frame(PyVar* p0, const CodeObject* co, PyVar _module, PyVar _callable, PyVar* _locals_base)
|
||||||
: _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, _locals_base) { }
|
: _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, _locals_base), _uw_list(nullptr) { }
|
||||||
|
|
||||||
// exec/eval
|
// exec/eval
|
||||||
Frame(PyVar* p0, const CodeObject* co, PyVar _module, PyVar _callable, FastLocals _locals)
|
Frame(PyVar* p0, const CodeObject* co, PyVar _module, PyVar _callable, FastLocals _locals)
|
||||||
: _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals) { }
|
: _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals), _uw_list(nullptr) { }
|
||||||
|
|
||||||
// global scope
|
// global scope
|
||||||
Frame(PyVar* p0, const CodeObject_& co, PyVar _module)
|
Frame(PyVar* p0, const CodeObject_& co, PyVar _module)
|
||||||
: _ip(co->codes.data()-1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0) {}
|
: _ip(co->codes.data()-1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0), _uw_list(nullptr) { }
|
||||||
|
|
||||||
PyVar* actual_sp_base() const { return _locals.a; }
|
PyVar* actual_sp_base() const { return _locals.a; }
|
||||||
ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); }
|
ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); }
|
||||||
@ -116,6 +127,10 @@ struct Frame {
|
|||||||
|
|
||||||
int curr_lineno() const { return co->lines[ip()].lineno; }
|
int curr_lineno() const { return co->lines[ip()].lineno; }
|
||||||
|
|
||||||
|
void set_unwind_target(PyVar* _sp);
|
||||||
|
UnwindTarget* find_unwind_target(int iblock);
|
||||||
|
void free_unwind_target();
|
||||||
|
|
||||||
void _gc_mark(VM* vm) const;
|
void _gc_mark(VM* vm) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,6 +140,7 @@ OPCODE(ADD_CLASS_ANNOTATION)
|
|||||||
OPCODE(WITH_ENTER)
|
OPCODE(WITH_ENTER)
|
||||||
OPCODE(WITH_EXIT)
|
OPCODE(WITH_EXIT)
|
||||||
/**************************/
|
/**************************/
|
||||||
|
OPCODE(TRY_ENTER)
|
||||||
OPCODE(EXCEPTION_MATCH)
|
OPCODE(EXCEPTION_MATCH)
|
||||||
OPCODE(RAISE)
|
OPCODE(RAISE)
|
||||||
OPCODE(RAISE_ASSERT)
|
OPCODE(RAISE_ASSERT)
|
||||||
|
@ -77,6 +77,7 @@ PK_EXPORT bool pkpy_unpack_sequence(pkpy_vm*, int size);
|
|||||||
PK_EXPORT bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName name);
|
PK_EXPORT bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName name);
|
||||||
PK_EXPORT bool pkpy_py_repr(pkpy_vm*);
|
PK_EXPORT bool pkpy_py_repr(pkpy_vm*);
|
||||||
PK_EXPORT bool pkpy_py_str(pkpy_vm*);
|
PK_EXPORT bool pkpy_py_str(pkpy_vm*);
|
||||||
|
PK_EXPORT bool pkpy_py_import(pkpy_vm*, pkpy_CString name);
|
||||||
|
|
||||||
/* Error Handling */
|
/* Error Handling */
|
||||||
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, pkpy_CString msg);
|
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, pkpy_CString msg);
|
||||||
|
@ -986,6 +986,10 @@ __NEXT_STEP:
|
|||||||
POP();
|
POP();
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
|
case OP_TRY_ENTER: {
|
||||||
|
frame->set_unwind_target(s_data._sp);
|
||||||
|
DISPATCH()
|
||||||
|
}
|
||||||
case OP_EXCEPTION_MATCH: {
|
case OP_EXCEPTION_MATCH: {
|
||||||
PyVar assumed_type = POPX();
|
PyVar assumed_type = POPX();
|
||||||
check_type(assumed_type, tp_type);
|
check_type(assumed_type, tp_type);
|
||||||
|
@ -703,6 +703,7 @@ __EAT_DOTS_END:
|
|||||||
|
|
||||||
void Compiler::compile_try_except() {
|
void Compiler::compile_try_except() {
|
||||||
ctx()->enter_block(CodeBlockType::TRY_EXCEPT);
|
ctx()->enter_block(CodeBlockType::TRY_EXCEPT);
|
||||||
|
ctx()->emit_(OP_TRY_ENTER, BC_NOARG, prev().line);
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
small_vector_2<int, 6> patches;
|
small_vector_2<int, 6> patches;
|
||||||
patches.push_back(
|
patches.push_back(
|
||||||
|
@ -24,15 +24,17 @@ namespace pkpy{
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Frame::prepare_jump_exception_handler(ValueStack* _s){
|
int Frame::prepare_jump_exception_handler(ValueStack* _s){
|
||||||
PyVar obj = _s->popx();
|
|
||||||
// try to find a parent try block
|
// try to find a parent try block
|
||||||
int i = co->lines[ip()].iblock;
|
int i = co->lines[ip()].iblock;
|
||||||
while(i >= 0){
|
while(i >= 0){
|
||||||
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break;
|
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break;
|
||||||
i = _exit_block(_s, i);
|
i = co->blocks[i].parent;
|
||||||
}
|
}
|
||||||
_s->push(obj);
|
|
||||||
if(i < 0) return -1;
|
if(i < 0) return -1;
|
||||||
|
PyVar obj = _s->popx(); // pop exception object
|
||||||
|
UnwindTarget* uw = find_unwind_target(i);
|
||||||
|
_s->reset(actual_sp_base() + uw->offset); // unwind the stack
|
||||||
|
_s->push(obj); // push it back
|
||||||
return co->blocks[i].end;
|
return co->blocks[i].end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,4 +71,32 @@ namespace pkpy{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Frame::set_unwind_target(PyVar* _sp){
|
||||||
|
int iblock = co->lines[ip()].iblock;
|
||||||
|
UnwindTarget* existing = find_unwind_target(iblock);
|
||||||
|
if(existing){
|
||||||
|
existing->offset = _sp - actual_sp_base();
|
||||||
|
}else{
|
||||||
|
UnwindTarget* prev = _uw_list;
|
||||||
|
_uw_list = new UnwindTarget(iblock, _sp - actual_sp_base());
|
||||||
|
_uw_list->next = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnwindTarget* Frame::find_unwind_target(int iblock){
|
||||||
|
UnwindTarget* p;
|
||||||
|
for(p=_uw_list; p!=nullptr; p=p->next){
|
||||||
|
if(p->iblock == iblock) return p;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Frame::free_unwind_target(){
|
||||||
|
while(_uw_list != nullptr){
|
||||||
|
UnwindTarget* p = _uw_list;
|
||||||
|
_uw_list = p->next;
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
11
src/iter.cpp
11
src/iter.cpp
@ -55,6 +55,17 @@ namespace pkpy{
|
|||||||
frame._locals.a = vm->s_data._sp;
|
frame._locals.a = vm->s_data._sp;
|
||||||
// restore the context
|
// restore the context
|
||||||
for(PyVar obj: s_backup) vm->s_data.push(obj);
|
for(PyVar obj: s_backup) vm->s_data.push(obj);
|
||||||
|
// relocate stack objects (their addresses become invalid)
|
||||||
|
for(PyVar* p=frame.actual_sp_base(); p!=vm->s_data.end(); p++){
|
||||||
|
if(p->type == VM::tp_stack_memory){
|
||||||
|
// TODO: refactor this
|
||||||
|
int count = p->as<StackMemory>().count;
|
||||||
|
if(count < 0){
|
||||||
|
void* new_p = p + count;
|
||||||
|
p[1]._1 = reinterpret_cast<i64>(new_p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
s_backup.clear();
|
s_backup.clear();
|
||||||
vm->callstack.emplace(std::move(frame));
|
vm->callstack.emplace(std::move(frame));
|
||||||
|
|
||||||
|
@ -489,6 +489,16 @@ bool pkpy_py_str(pkpy_vm* vm_handle) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pkpy_py_import(pkpy_vm* vm_handle, pkpy_CString name) {
|
||||||
|
VM* vm = (VM*) vm_handle;
|
||||||
|
PK_ASSERT_NO_ERROR()
|
||||||
|
PK_PROTECTED(
|
||||||
|
PyVar module = vm->py_import(name);
|
||||||
|
vm->s_data.push(module);
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Error Handling */
|
/* Error Handling */
|
||||||
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;
|
||||||
|
@ -1644,7 +1644,9 @@ void NextBreakpoint::_step(VM* vm){
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void VM::__pop_frame(){
|
void VM::__pop_frame(){
|
||||||
s_data.reset(callstack.top()._sp_base);
|
Frame& frame = callstack.top();
|
||||||
|
s_data.reset(frame._sp_base);
|
||||||
|
frame.free_unwind_target();
|
||||||
callstack.pop();
|
callstack.pop();
|
||||||
|
|
||||||
#if PK_ENABLE_PROFILER
|
#if PK_ENABLE_PROFILER
|
||||||
|
@ -65,7 +65,7 @@ int main(int argc, char** argv){
|
|||||||
pkpy_vm* vm = pkpy_new_vm(true);
|
pkpy_vm* vm = pkpy_new_vm(true);
|
||||||
|
|
||||||
pkpy_push_function(vm, "input(prompt=None) -> str", f_input);
|
pkpy_push_function(vm, "input(prompt=None) -> str", f_input);
|
||||||
pkpy_eval(vm, "__import__('builtins')");
|
pkpy_py_import(vm, "builtins");
|
||||||
pkpy_setattr(vm, pkpy_name("input"));
|
pkpy_setattr(vm, pkpy_name("input"));
|
||||||
|
|
||||||
if(argc == 1){
|
if(argc == 1){
|
||||||
|
@ -203,6 +203,11 @@ bool pkpy_py_str(pkpy_vm* vm) {
|
|||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pkpy_py_import(pkpy_vm* vm, pkpy_CString name) {
|
||||||
|
bool returnValue;
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
bool pkpy_error(pkpy_vm* vm, const char* name, pkpy_CString msg) {
|
bool pkpy_error(pkpy_vm* vm, const char* name, pkpy_CString msg) {
|
||||||
bool returnValue;
|
bool returnValue;
|
||||||
return returnValue;
|
return returnValue;
|
||||||
|
@ -210,9 +210,12 @@ for e in [d, deque('abc'), deque('ab'), deque(), list(d)]:
|
|||||||
assertEqual(d == e, type(d) == type(e) and list(d) == list(e))
|
assertEqual(d == e, type(d) == type(e) and list(d) == list(e))
|
||||||
assertEqual(d != e, not (type(d) == type(e) and list(d) == list(e)))
|
assertEqual(d != e, not (type(d) == type(e) and list(d) == list(e)))
|
||||||
|
|
||||||
args = map(deque, ('', 'a', 'b', 'ab', 'ba', 'abc', 'xba', 'xabc', 'cba'))
|
def get_args():
|
||||||
for x in args:
|
args = map(deque, ('', 'a', 'b', 'ab', 'ba', 'abc', 'xba', 'xabc', 'cba'))
|
||||||
for y in args:
|
return args
|
||||||
|
|
||||||
|
for x in get_args():
|
||||||
|
for y in get_args():
|
||||||
assertEqual(x == y, list(x) == list(y))
|
assertEqual(x == y, list(x) == list(y))
|
||||||
assertEqual(x != y, list(x) != list(y))
|
assertEqual(x != y, list(x) != list(y))
|
||||||
# assertEqual(x < y, list(x) < list(y)) # not currently supported
|
# assertEqual(x < y, list(x) < list(y)) # not currently supported
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
# multi-loop generator
|
||||||
|
out = []
|
||||||
|
args = map(lambda x: x+1, [1, 2, 3])
|
||||||
|
for x in args:
|
||||||
|
for y in args:
|
||||||
|
out.append((x, y))
|
||||||
|
assert out == [(2, 3), (2, 4)]
|
||||||
|
|
||||||
# multi loop bug
|
# multi loop bug
|
||||||
out = []
|
out = []
|
||||||
a = [1, 2]
|
a = [1, 2]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user