|
|
@@ -88,524 +88,523 @@ FrameResult VM__run_top_frame(VM* self) {
|
|
|
py_Frame* frame = self->top_frame;
|
|
|
Bytecode* co_codes;
|
|
|
py_Name* co_names;
|
|
|
+ Bytecode byte;
|
|
|
|
|
|
const py_Frame* base_frame = frame;
|
|
|
|
|
|
- while(true) {
|
|
|
- Bytecode byte;
|
|
|
- __NEXT_FRAME:
|
|
|
- if(self->recursion_depth >= self->max_recursion_depth) {
|
|
|
- py_exception(tp_RecursionError, "maximum recursion depth exceeded");
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- RESET_CO_CACHE();
|
|
|
- frame->ip++;
|
|
|
-
|
|
|
- __NEXT_STEP:
|
|
|
- byte = co_codes[frame->ip];
|
|
|
-
|
|
|
- if(self->trace_info.func) {
|
|
|
- SourceLocation loc = Frame__source_location(frame);
|
|
|
- SourceLocation prev_loc = self->trace_info.prev_loc;
|
|
|
- if(loc.lineno != prev_loc.lineno || loc.src != prev_loc.src) {
|
|
|
- if(prev_loc.src) PK_DECREF(prev_loc.src);
|
|
|
- PK_INCREF(loc.src);
|
|
|
- self->trace_info.prev_loc = loc;
|
|
|
- self->trace_info.func(frame, TRACE_EVENT_LINE);
|
|
|
- }
|
|
|
+__NEXT_FRAME:
|
|
|
+ if(self->recursion_depth >= self->max_recursion_depth) {
|
|
|
+ py_exception(tp_RecursionError, "maximum recursion depth exceeded");
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ RESET_CO_CACHE();
|
|
|
+ frame->ip++;
|
|
|
+
|
|
|
+__NEXT_STEP:
|
|
|
+ byte = co_codes[frame->ip];
|
|
|
+
|
|
|
+ if(self->trace_info.func) {
|
|
|
+ SourceLocation loc = Frame__source_location(frame);
|
|
|
+ SourceLocation prev_loc = self->trace_info.prev_loc;
|
|
|
+ if(loc.lineno != prev_loc.lineno || loc.src != prev_loc.src) {
|
|
|
+ if(prev_loc.src) PK_DECREF(prev_loc.src);
|
|
|
+ PK_INCREF(loc.src);
|
|
|
+ self->trace_info.prev_loc = loc;
|
|
|
+ self->trace_info.func(frame, TRACE_EVENT_LINE);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
#if PK_ENABLE_WATCHDOG
|
|
|
- if(self->watchdog_info.max_reset_time > 0) {
|
|
|
- clock_t now = clock();
|
|
|
- if(now > self->watchdog_info.max_reset_time) {
|
|
|
- self->watchdog_info.max_reset_time = 0;
|
|
|
- TimeoutError("watchdog timeout");
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
+ if(self->watchdog_info.max_reset_time > 0) {
|
|
|
+ clock_t now = clock();
|
|
|
+ if(now > self->watchdog_info.max_reset_time) {
|
|
|
+ self->watchdog_info.max_reset_time = 0;
|
|
|
+ TimeoutError("watchdog timeout");
|
|
|
+ goto __ERROR;
|
|
|
}
|
|
|
+ }
|
|
|
#endif
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
- pk_print_stack(self, frame, byte);
|
|
|
+ pk_print_stack(self, frame, byte);
|
|
|
#endif
|
|
|
|
|
|
- switch((Opcode)byte.op) {
|
|
|
- case OP_NO_OP: DISPATCH();
|
|
|
- /*****************************************/
|
|
|
- case OP_POP_TOP: POP(); DISPATCH();
|
|
|
- case OP_DUP_TOP: PUSH(TOP()); DISPATCH();
|
|
|
- case OP_DUP_TOP_TWO:
|
|
|
- // [a, b]
|
|
|
- PUSH(SECOND()); // [a, b, a]
|
|
|
- PUSH(SECOND()); // [a, b, a, b]
|
|
|
- DISPATCH();
|
|
|
- case OP_ROT_TWO: {
|
|
|
- py_TValue tmp = *TOP();
|
|
|
- *TOP() = *SECOND();
|
|
|
- *SECOND() = tmp;
|
|
|
- DISPATCH();
|
|
|
+ switch((Opcode)byte.op) {
|
|
|
+ case OP_NO_OP: DISPATCH();
|
|
|
+ /*****************************************/
|
|
|
+ case OP_POP_TOP: POP(); DISPATCH();
|
|
|
+ case OP_DUP_TOP: PUSH(TOP()); DISPATCH();
|
|
|
+ case OP_DUP_TOP_TWO:
|
|
|
+ // [a, b]
|
|
|
+ PUSH(SECOND()); // [a, b, a]
|
|
|
+ PUSH(SECOND()); // [a, b, a, b]
|
|
|
+ DISPATCH();
|
|
|
+ case OP_ROT_TWO: {
|
|
|
+ py_TValue tmp = *TOP();
|
|
|
+ *TOP() = *SECOND();
|
|
|
+ *SECOND() = tmp;
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_ROT_THREE: {
|
|
|
+ // [a, b, c] -> [c, a, b]
|
|
|
+ py_TValue tmp = *TOP();
|
|
|
+ *TOP() = *SECOND();
|
|
|
+ *SECOND() = *THIRD();
|
|
|
+ *THIRD() = tmp;
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_PRINT_EXPR:
|
|
|
+ if(TOP()->type != tp_NoneType) {
|
|
|
+ bool ok = py_repr(TOP());
|
|
|
+ if(!ok) goto __ERROR;
|
|
|
+ self->callbacks.print(py_tostr(&self->last_retval));
|
|
|
+ self->callbacks.print("\n");
|
|
|
+ }
|
|
|
+ POP();
|
|
|
+ DISPATCH();
|
|
|
+ /*****************************************/
|
|
|
+ case OP_LOAD_CONST: {
|
|
|
+ PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg));
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_LOAD_NONE: {
|
|
|
+ py_newnone(SP()++);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_LOAD_TRUE: {
|
|
|
+ py_newbool(SP()++, true);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_LOAD_FALSE: {
|
|
|
+ py_newbool(SP()++, false);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ /*****************************************/
|
|
|
+ case OP_LOAD_SMALL_INT: {
|
|
|
+ py_newint(SP()++, (int16_t)byte.arg);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ /*****************************************/
|
|
|
+ case OP_LOAD_ELLIPSIS: {
|
|
|
+ py_newellipsis(SP()++);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_LOAD_FUNCTION: {
|
|
|
+ FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
|
|
|
+ Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function));
|
|
|
+ Function__ctor(ud, decl, frame->module, frame->globals);
|
|
|
+ if(decl->nested) {
|
|
|
+ if(frame->is_locals_special) {
|
|
|
+ RuntimeError("cannot create closure from special locals");
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ ud->closure = FastLocals__to_namedict(frame->locals, frame->co);
|
|
|
+ py_Name name = py_name(decl->code.name->data);
|
|
|
+ // capture itself to allow recursion
|
|
|
+ NameDict__set(ud->closure, name, SP());
|
|
|
}
|
|
|
- case OP_ROT_THREE: {
|
|
|
- // [a, b, c] -> [c, a, b]
|
|
|
- py_TValue tmp = *TOP();
|
|
|
- *TOP() = *SECOND();
|
|
|
- *SECOND() = *THIRD();
|
|
|
- *THIRD() = tmp;
|
|
|
+ SP()++;
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_LOAD_NULL:
|
|
|
+ py_newnil(SP()++);
|
|
|
+ DISPATCH();
|
|
|
+ /*****************************************/
|
|
|
+ case OP_LOAD_FAST: {
|
|
|
+ assert(!frame->is_locals_special);
|
|
|
+ py_Ref val = &frame->locals[byte.arg];
|
|
|
+ if(!py_isnil(val)) {
|
|
|
+ PUSH(val);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_PRINT_EXPR:
|
|
|
- if(TOP()->type != tp_NoneType) {
|
|
|
- bool ok = py_repr(TOP());
|
|
|
- if(!ok) goto __ERROR;
|
|
|
- self->callbacks.print(py_tostr(&self->last_retval));
|
|
|
- self->callbacks.print("\n");
|
|
|
+ py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);
|
|
|
+ UnboundLocalError(name);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ case OP_LOAD_NAME: {
|
|
|
+ assert(frame->is_locals_special);
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ // locals
|
|
|
+ switch(frame->locals->type) {
|
|
|
+ case tp_locals: {
|
|
|
+ py_Frame* noproxy = frame->locals->_ptr;
|
|
|
+ py_Ref slot = Frame__getlocal_noproxy(noproxy, name);
|
|
|
+ if(slot == NULL) break;
|
|
|
+ if(py_isnil(slot)) {
|
|
|
+ UnboundLocalError(name);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ PUSH(slot);
|
|
|
+ DISPATCH();
|
|
|
}
|
|
|
- POP();
|
|
|
- DISPATCH();
|
|
|
- /*****************************************/
|
|
|
- case OP_LOAD_CONST: {
|
|
|
- PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg));
|
|
|
- DISPATCH();
|
|
|
+ case tp_dict: {
|
|
|
+ int res = py_dict_getitem(frame->locals, py_name2ref(name));
|
|
|
+ if(res == 1) {
|
|
|
+ PUSH(&self->last_retval);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ if(res == 0) break;
|
|
|
+ assert(res == -1);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ case tp_nil: break;
|
|
|
+ default: c11__unreachable();
|
|
|
}
|
|
|
- case OP_LOAD_NONE: {
|
|
|
- py_newnone(SP()++);
|
|
|
+ // globals
|
|
|
+ int res = Frame__getglobal(frame, name);
|
|
|
+ if(res == 1) {
|
|
|
+ PUSH(&self->last_retval);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_LOAD_TRUE: {
|
|
|
- py_newbool(SP()++, true);
|
|
|
+ if(res == -1) goto __ERROR;
|
|
|
+ // builtins
|
|
|
+ py_Ref tmp = py_getdict(self->builtins, name);
|
|
|
+ if(tmp != NULL) {
|
|
|
+ PUSH(tmp);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_LOAD_FALSE: {
|
|
|
- py_newbool(SP()++, false);
|
|
|
+ NameError(name);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ case OP_LOAD_NONLOCAL: {
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ py_Ref tmp = Frame__getclosure(frame, name);
|
|
|
+ if(tmp != NULL) {
|
|
|
+ PUSH(tmp);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- /*****************************************/
|
|
|
- case OP_LOAD_SMALL_INT: {
|
|
|
- py_newint(SP()++, (int16_t)byte.arg);
|
|
|
+ int res = Frame__getglobal(frame, name);
|
|
|
+ if(res == 1) {
|
|
|
+ PUSH(&self->last_retval);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- /*****************************************/
|
|
|
- case OP_LOAD_ELLIPSIS: {
|
|
|
- py_newellipsis(SP()++);
|
|
|
+ if(res == -1) goto __ERROR;
|
|
|
+
|
|
|
+ tmp = py_getdict(self->builtins, name);
|
|
|
+ if(tmp != NULL) {
|
|
|
+ PUSH(tmp);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_LOAD_FUNCTION: {
|
|
|
- FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
|
|
|
- Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function));
|
|
|
- Function__ctor(ud, decl, frame->module, frame->globals);
|
|
|
- if(decl->nested) {
|
|
|
- if(frame->is_locals_special) {
|
|
|
- RuntimeError("cannot create closure from special locals");
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- ud->closure = FastLocals__to_namedict(frame->locals, frame->co);
|
|
|
- py_Name name = py_name(decl->code.name->data);
|
|
|
- // capture itself to allow recursion
|
|
|
- NameDict__set(ud->closure, name, SP());
|
|
|
- }
|
|
|
- SP()++;
|
|
|
+ NameError(name);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ case OP_LOAD_GLOBAL: {
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ int res = Frame__getglobal(frame, name);
|
|
|
+ if(res == 1) {
|
|
|
+ PUSH(&self->last_retval);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_LOAD_NULL:
|
|
|
- py_newnil(SP()++);
|
|
|
+ if(res == -1) goto __ERROR;
|
|
|
+ py_Ref tmp = py_getdict(self->builtins, name);
|
|
|
+ if(tmp != NULL) {
|
|
|
+ PUSH(tmp);
|
|
|
DISPATCH();
|
|
|
- /*****************************************/
|
|
|
- case OP_LOAD_FAST: {
|
|
|
- assert(!frame->is_locals_special);
|
|
|
- py_Ref val = &frame->locals[byte.arg];
|
|
|
- if(!py_isnil(val)) {
|
|
|
- PUSH(val);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);
|
|
|
- UnboundLocalError(name);
|
|
|
- goto __ERROR;
|
|
|
}
|
|
|
- case OP_LOAD_NAME: {
|
|
|
- assert(frame->is_locals_special);
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- // locals
|
|
|
- switch(frame->locals->type) {
|
|
|
- case tp_locals: {
|
|
|
- py_Frame* noproxy = frame->locals->_ptr;
|
|
|
- py_Ref slot = Frame__getlocal_noproxy(noproxy, name);
|
|
|
- if(slot == NULL) break;
|
|
|
- if(py_isnil(slot)) {
|
|
|
- UnboundLocalError(name);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- PUSH(slot);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case tp_dict: {
|
|
|
- int res = py_dict_getitem(frame->locals, py_name2ref(name));
|
|
|
- if(res == 1) {
|
|
|
- PUSH(&self->last_retval);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- if(res == 0) break;
|
|
|
- assert(res == -1);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- case tp_nil: break;
|
|
|
- default: c11__unreachable();
|
|
|
- }
|
|
|
- // globals
|
|
|
- int res = Frame__getglobal(frame, name);
|
|
|
- if(res == 1) {
|
|
|
- PUSH(&self->last_retval);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- if(res == -1) goto __ERROR;
|
|
|
- // builtins
|
|
|
- py_Ref tmp = py_getdict(self->builtins, name);
|
|
|
- if(tmp != NULL) {
|
|
|
- PUSH(tmp);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- NameError(name);
|
|
|
+ NameError(name);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ case OP_LOAD_ATTR: {
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ if(py_getattr(TOP(), name)) {
|
|
|
+ py_assign(TOP(), py_retval());
|
|
|
+ } else {
|
|
|
goto __ERROR;
|
|
|
}
|
|
|
- case OP_LOAD_NONLOCAL: {
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- py_Ref tmp = Frame__getclosure(frame, name);
|
|
|
- if(tmp != NULL) {
|
|
|
- PUSH(tmp);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- int res = Frame__getglobal(frame, name);
|
|
|
- if(res == 1) {
|
|
|
- PUSH(&self->last_retval);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- if(res == -1) goto __ERROR;
|
|
|
-
|
|
|
- tmp = py_getdict(self->builtins, name);
|
|
|
- if(tmp != NULL) {
|
|
|
- PUSH(tmp);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- NameError(name);
|
|
|
- goto __ERROR;
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_LOAD_CLASS_GLOBAL: {
|
|
|
+ assert(self->curr_class);
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ py_Ref tmp = py_getdict(self->curr_class, name);
|
|
|
+ if(tmp) {
|
|
|
+ PUSH(tmp);
|
|
|
+ DISPATCH();
|
|
|
}
|
|
|
- case OP_LOAD_GLOBAL: {
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- int res = Frame__getglobal(frame, name);
|
|
|
- if(res == 1) {
|
|
|
- PUSH(&self->last_retval);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- if(res == -1) goto __ERROR;
|
|
|
- py_Ref tmp = py_getdict(self->builtins, name);
|
|
|
- if(tmp != NULL) {
|
|
|
- PUSH(tmp);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- NameError(name);
|
|
|
- goto __ERROR;
|
|
|
+ // load global if attribute not found
|
|
|
+ int res = Frame__getglobal(frame, name);
|
|
|
+ if(res == 1) {
|
|
|
+ PUSH(&self->last_retval);
|
|
|
+ DISPATCH();
|
|
|
}
|
|
|
- case OP_LOAD_ATTR: {
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
+ if(res == -1) goto __ERROR;
|
|
|
+ tmp = py_getdict(self->builtins, name);
|
|
|
+ if(tmp) {
|
|
|
+ PUSH(tmp);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ NameError(name);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ case OP_LOAD_METHOD: {
|
|
|
+ // [self] -> [unbound, self]
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ bool ok = py_pushmethod(name);
|
|
|
+ if(!ok) {
|
|
|
+ // fallback to getattr
|
|
|
if(py_getattr(TOP(), name)) {
|
|
|
py_assign(TOP(), py_retval());
|
|
|
+ py_newnil(SP()++);
|
|
|
} else {
|
|
|
goto __ERROR;
|
|
|
}
|
|
|
+ }
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_LOAD_SUBSCR: {
|
|
|
+ // [a, b] -> a[b]
|
|
|
+ py_Ref magic = py_tpfindmagic(SECOND()->type, __getitem__);
|
|
|
+ if(magic) {
|
|
|
+ if(magic->type == tp_nativefunc) {
|
|
|
+ if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR;
|
|
|
+ POP();
|
|
|
+ py_assign(TOP(), py_retval());
|
|
|
+ } else {
|
|
|
+ INSERT_THIRD(); // [?, a, b]
|
|
|
+ *THIRD() = *magic; // [__getitem__, a, b]
|
|
|
+ vectorcall_opcall(1, 0);
|
|
|
+ }
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_LOAD_CLASS_GLOBAL: {
|
|
|
- assert(self->curr_class);
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- py_Ref tmp = py_getdict(self->curr_class, name);
|
|
|
- if(tmp) {
|
|
|
- PUSH(tmp);
|
|
|
+ TypeError("'%t' object is not subscriptable", SECOND()->type);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ case OP_STORE_FAST: {
|
|
|
+ assert(!frame->is_locals_special);
|
|
|
+ frame->locals[byte.arg] = POPX();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_STORE_NAME: {
|
|
|
+ assert(frame->is_locals_special);
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ switch(frame->locals->type) {
|
|
|
+ case tp_locals: {
|
|
|
+ py_Frame* noproxy = frame->locals->_ptr;
|
|
|
+ py_Ref slot = Frame__getlocal_noproxy(noproxy, name);
|
|
|
+ if(slot == NULL) {
|
|
|
+ UnboundLocalError(name);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ *slot = POPX();
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- // load global if attribute not found
|
|
|
- int res = Frame__getglobal(frame, name);
|
|
|
- if(res == 1) {
|
|
|
- PUSH(&self->last_retval);
|
|
|
+ case tp_dict: {
|
|
|
+ if(!py_dict_setitem(frame->locals, py_name2ref(name), TOP())) goto __ERROR;
|
|
|
+ POP();
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- if(res == -1) goto __ERROR;
|
|
|
- tmp = py_getdict(self->builtins, name);
|
|
|
- if(tmp) {
|
|
|
- PUSH(tmp);
|
|
|
+ case tp_nil: {
|
|
|
+ // globals
|
|
|
+ if(!Frame__setglobal(frame, name, TOP())) goto __ERROR;
|
|
|
+ POP();
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- NameError(name);
|
|
|
- goto __ERROR;
|
|
|
+ default: c11__unreachable();
|
|
|
}
|
|
|
- case OP_LOAD_METHOD: {
|
|
|
- // [self] -> [unbound, self]
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- bool ok = py_pushmethod(name);
|
|
|
- if(!ok) {
|
|
|
- // fallback to getattr
|
|
|
- if(py_getattr(TOP(), name)) {
|
|
|
- py_assign(TOP(), py_retval());
|
|
|
- py_newnil(SP()++);
|
|
|
- } else {
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
+ }
|
|
|
+ case OP_STORE_GLOBAL: {
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ if(!Frame__setglobal(frame, name, TOP())) goto __ERROR;
|
|
|
+ POP();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_STORE_ATTR: {
|
|
|
+ // [val, a] -> a.b = val
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ if(!py_setattr(TOP(), name, SECOND())) goto __ERROR;
|
|
|
+ STACK_SHRINK(2);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_STORE_SUBSCR: {
|
|
|
+ // [val, a, b] -> a[b] = val
|
|
|
+ py_Ref magic = py_tpfindmagic(SECOND()->type, __setitem__);
|
|
|
+ if(magic) {
|
|
|
+ PUSH(THIRD()); // [val, a, b, val]
|
|
|
+ if(magic->type == tp_nativefunc) {
|
|
|
+ if(!py_callcfunc(magic->_cfunc, 3, THIRD())) goto __ERROR;
|
|
|
+ STACK_SHRINK(4);
|
|
|
+ } else {
|
|
|
+ *FOURTH() = *magic; // [__setitem__, a, b, val]
|
|
|
+ if(!py_vectorcall(2, 0)) goto __ERROR;
|
|
|
}
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_LOAD_SUBSCR: {
|
|
|
- // [a, b] -> a[b]
|
|
|
- py_Ref magic = py_tpfindmagic(SECOND()->type, __getitem__);
|
|
|
- if(magic) {
|
|
|
- if(magic->type == tp_nativefunc) {
|
|
|
- if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR;
|
|
|
- POP();
|
|
|
- py_assign(TOP(), py_retval());
|
|
|
- } else {
|
|
|
- INSERT_THIRD(); // [?, a, b]
|
|
|
- *THIRD() = *magic; // [__getitem__, a, b]
|
|
|
- vectorcall_opcall(1, 0);
|
|
|
- }
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- TypeError("'%t' object is not subscriptable", SECOND()->type);
|
|
|
+ TypeError("'%t' object does not support item assignment", SECOND()->type);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ case OP_DELETE_FAST: {
|
|
|
+ assert(!frame->is_locals_special);
|
|
|
+ py_Ref tmp = &frame->locals[byte.arg];
|
|
|
+ if(py_isnil(tmp)) {
|
|
|
+ py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);
|
|
|
+ UnboundLocalError(name);
|
|
|
goto __ERROR;
|
|
|
}
|
|
|
- case OP_STORE_FAST: {
|
|
|
- assert(!frame->is_locals_special);
|
|
|
- frame->locals[byte.arg] = POPX();
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_STORE_NAME: {
|
|
|
- assert(frame->is_locals_special);
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- switch(frame->locals->type) {
|
|
|
- case tp_locals: {
|
|
|
- py_Frame* noproxy = frame->locals->_ptr;
|
|
|
- py_Ref slot = Frame__getlocal_noproxy(noproxy, name);
|
|
|
- if(slot == NULL) {
|
|
|
- UnboundLocalError(name);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- *slot = POPX();
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case tp_dict: {
|
|
|
- if(!py_dict_setitem(frame->locals, py_name2ref(name), TOP())) goto __ERROR;
|
|
|
- POP();
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case tp_nil: {
|
|
|
- // globals
|
|
|
- if(!Frame__setglobal(frame, name, TOP())) goto __ERROR;
|
|
|
- POP();
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- default: c11__unreachable();
|
|
|
- }
|
|
|
- }
|
|
|
- case OP_STORE_GLOBAL: {
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- if(!Frame__setglobal(frame, name, TOP())) goto __ERROR;
|
|
|
- POP();
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_STORE_ATTR: {
|
|
|
- // [val, a] -> a.b = val
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- if(!py_setattr(TOP(), name, SECOND())) goto __ERROR;
|
|
|
- STACK_SHRINK(2);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_STORE_SUBSCR: {
|
|
|
- // [val, a, b] -> a[b] = val
|
|
|
- py_Ref magic = py_tpfindmagic(SECOND()->type, __setitem__);
|
|
|
- if(magic) {
|
|
|
- PUSH(THIRD()); // [val, a, b, val]
|
|
|
- if(magic->type == tp_nativefunc) {
|
|
|
- if(!py_callcfunc(magic->_cfunc, 3, THIRD())) goto __ERROR;
|
|
|
- STACK_SHRINK(4);
|
|
|
- } else {
|
|
|
- *FOURTH() = *magic; // [__setitem__, a, b, val]
|
|
|
- if(!py_vectorcall(2, 0)) goto __ERROR;
|
|
|
+ py_newnil(tmp);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_DELETE_NAME: {
|
|
|
+ assert(frame->is_locals_special);
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ switch(frame->locals->type) {
|
|
|
+ case tp_locals: {
|
|
|
+ py_Frame* noproxy = frame->locals->_ptr;
|
|
|
+ py_Ref slot = Frame__getlocal_noproxy(noproxy, name);
|
|
|
+ if(slot == NULL || py_isnil(slot)) {
|
|
|
+ UnboundLocalError(name);
|
|
|
+ goto __ERROR;
|
|
|
}
|
|
|
+ py_newnil(slot);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- TypeError("'%t' object does not support item assignment", SECOND()->type);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- case OP_DELETE_FAST: {
|
|
|
- assert(!frame->is_locals_special);
|
|
|
- py_Ref tmp = &frame->locals[byte.arg];
|
|
|
- if(py_isnil(tmp)) {
|
|
|
- py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);
|
|
|
- UnboundLocalError(name);
|
|
|
+ case tp_dict: {
|
|
|
+ int res = py_dict_delitem(frame->locals, py_name2ref(name));
|
|
|
+ if(res == 1) DISPATCH();
|
|
|
+ if(res == 0) UnboundLocalError(name);
|
|
|
goto __ERROR;
|
|
|
}
|
|
|
- py_newnil(tmp);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_DELETE_NAME: {
|
|
|
- assert(frame->is_locals_special);
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- switch(frame->locals->type) {
|
|
|
- case tp_locals: {
|
|
|
- py_Frame* noproxy = frame->locals->_ptr;
|
|
|
- py_Ref slot = Frame__getlocal_noproxy(noproxy, name);
|
|
|
- if(slot == NULL || py_isnil(slot)) {
|
|
|
- UnboundLocalError(name);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- py_newnil(slot);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case tp_dict: {
|
|
|
- int res = py_dict_delitem(frame->locals, py_name2ref(name));
|
|
|
- if(res == 1) DISPATCH();
|
|
|
- if(res == 0) UnboundLocalError(name);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- case tp_nil: {
|
|
|
- // globals
|
|
|
- int res = Frame__delglobal(frame, name);
|
|
|
- if(res == 1) DISPATCH();
|
|
|
- if(res == 0) NameError(name);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- default: c11__unreachable();
|
|
|
+ case tp_nil: {
|
|
|
+ // globals
|
|
|
+ int res = Frame__delglobal(frame, name);
|
|
|
+ if(res == 1) DISPATCH();
|
|
|
+ if(res == 0) NameError(name);
|
|
|
+ goto __ERROR;
|
|
|
}
|
|
|
+ default: c11__unreachable();
|
|
|
}
|
|
|
- case OP_DELETE_GLOBAL: {
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- int res = Frame__delglobal(frame, name);
|
|
|
- if(res == 1) DISPATCH();
|
|
|
- if(res == -1) goto __ERROR;
|
|
|
- NameError(name);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
+ }
|
|
|
+ case OP_DELETE_GLOBAL: {
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ int res = Frame__delglobal(frame, name);
|
|
|
+ if(res == 1) DISPATCH();
|
|
|
+ if(res == -1) goto __ERROR;
|
|
|
+ NameError(name);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
|
|
|
- case OP_DELETE_ATTR: {
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- if(!py_delattr(TOP(), name)) goto __ERROR;
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
+ case OP_DELETE_ATTR: {
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ if(!py_delattr(TOP(), name)) goto __ERROR;
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
|
|
|
- case OP_DELETE_SUBSCR: {
|
|
|
- // [a, b] -> del a[b]
|
|
|
- py_Ref magic = py_tpfindmagic(SECOND()->type, __delitem__);
|
|
|
- if(magic) {
|
|
|
- if(magic->type == tp_nativefunc) {
|
|
|
- if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR;
|
|
|
- STACK_SHRINK(2);
|
|
|
- } else {
|
|
|
- INSERT_THIRD(); // [?, a, b]
|
|
|
- *THIRD() = *magic; // [__delitem__, a, b]
|
|
|
- if(!py_vectorcall(1, 0)) goto __ERROR;
|
|
|
- }
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- TypeError("'%t' object does not support item deletion", SECOND()->type);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- /*****************************************/
|
|
|
- case OP_BUILD_IMAG: {
|
|
|
- // [x]
|
|
|
- py_Ref f = py_getdict(self->builtins, py_name("complex"));
|
|
|
- assert(f != NULL);
|
|
|
- py_TValue tmp = *TOP();
|
|
|
- *TOP() = *f; // [complex]
|
|
|
- py_newnil(SP()++); // [complex, NULL]
|
|
|
- py_newint(SP()++, 0); // [complex, NULL, 0]
|
|
|
- *SP()++ = tmp; // [complex, NULL, 0, x]
|
|
|
- vectorcall_opcall(2, 0);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_BUILD_BYTES: {
|
|
|
- int size;
|
|
|
- py_Ref string = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
|
|
- const char* data = py_tostrn(string, &size);
|
|
|
- unsigned char* p = py_newbytes(SP()++, size);
|
|
|
- memcpy(p, data, size);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_BUILD_TUPLE: {
|
|
|
- py_TValue tmp;
|
|
|
- py_Ref p = py_newtuple(&tmp, byte.arg);
|
|
|
- py_TValue* begin = SP() - byte.arg;
|
|
|
- for(int i = 0; i < byte.arg; i++)
|
|
|
- p[i] = begin[i];
|
|
|
- SP() = begin;
|
|
|
- PUSH(&tmp);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_BUILD_LIST: {
|
|
|
- py_TValue tmp;
|
|
|
- py_newlistn(&tmp, byte.arg);
|
|
|
- py_TValue* begin = SP() - byte.arg;
|
|
|
- for(int i = 0; i < byte.arg; i++) {
|
|
|
- py_list_setitem(&tmp, i, begin + i);
|
|
|
- }
|
|
|
- SP() = begin;
|
|
|
- PUSH(&tmp);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_BUILD_DICT: {
|
|
|
- py_TValue* begin = SP() - byte.arg * 2;
|
|
|
- py_Ref tmp = py_pushtmp();
|
|
|
- py_newdict(tmp);
|
|
|
- for(int i = 0; i < byte.arg * 2; i += 2) {
|
|
|
- bool ok = py_dict_setitem(tmp, begin + i, begin + i + 1);
|
|
|
- if(!ok) goto __ERROR;
|
|
|
- }
|
|
|
- SP() = begin;
|
|
|
- PUSH(tmp);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_BUILD_SET: {
|
|
|
- py_TValue* begin = SP() - byte.arg;
|
|
|
- py_Ref typeobject_set = py_getdict(self->builtins, py_name("set"));
|
|
|
- assert(typeobject_set != NULL);
|
|
|
- py_push(typeobject_set);
|
|
|
- py_pushnil();
|
|
|
- if(!py_vectorcall(0, 0)) goto __ERROR;
|
|
|
- py_push(py_retval()); // empty set
|
|
|
- py_Name id_add = py_name("add");
|
|
|
- for(int i = 0; i < byte.arg; i++) {
|
|
|
- py_push(TOP());
|
|
|
- if(!py_pushmethod(id_add)) {
|
|
|
- c11__abort("OP_BUILD_SET: failed to load method 'add'");
|
|
|
- }
|
|
|
- py_push(begin + i);
|
|
|
+ case OP_DELETE_SUBSCR: {
|
|
|
+ // [a, b] -> del a[b]
|
|
|
+ py_Ref magic = py_tpfindmagic(SECOND()->type, __delitem__);
|
|
|
+ if(magic) {
|
|
|
+ if(magic->type == tp_nativefunc) {
|
|
|
+ if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR;
|
|
|
+ STACK_SHRINK(2);
|
|
|
+ } else {
|
|
|
+ INSERT_THIRD(); // [?, a, b]
|
|
|
+ *THIRD() = *magic; // [__delitem__, a, b]
|
|
|
if(!py_vectorcall(1, 0)) goto __ERROR;
|
|
|
}
|
|
|
- py_TValue tmp = *TOP();
|
|
|
- SP() = begin;
|
|
|
- PUSH(&tmp);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_BUILD_SLICE: {
|
|
|
- // [start, stop, step]
|
|
|
- py_TValue tmp;
|
|
|
- py_newslice(&tmp);
|
|
|
- py_setslot(&tmp, 0, THIRD());
|
|
|
- py_setslot(&tmp, 1, SECOND());
|
|
|
- py_setslot(&tmp, 2, TOP());
|
|
|
- STACK_SHRINK(3);
|
|
|
- PUSH(&tmp);
|
|
|
- DISPATCH();
|
|
|
+ TypeError("'%t' object does not support item deletion", SECOND()->type);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ /*****************************************/
|
|
|
+ case OP_BUILD_IMAG: {
|
|
|
+ // [x]
|
|
|
+ py_Ref f = py_getdict(self->builtins, py_name("complex"));
|
|
|
+ assert(f != NULL);
|
|
|
+ py_TValue tmp = *TOP();
|
|
|
+ *TOP() = *f; // [complex]
|
|
|
+ py_newnil(SP()++); // [complex, NULL]
|
|
|
+ py_newint(SP()++, 0); // [complex, NULL, 0]
|
|
|
+ *SP()++ = tmp; // [complex, NULL, 0, x]
|
|
|
+ vectorcall_opcall(2, 0);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_BUILD_BYTES: {
|
|
|
+ int size;
|
|
|
+ py_Ref string = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
|
|
+ const char* data = py_tostrn(string, &size);
|
|
|
+ unsigned char* p = py_newbytes(SP()++, size);
|
|
|
+ memcpy(p, data, size);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_BUILD_TUPLE: {
|
|
|
+ py_TValue tmp;
|
|
|
+ py_Ref p = py_newtuple(&tmp, byte.arg);
|
|
|
+ py_TValue* begin = SP() - byte.arg;
|
|
|
+ for(int i = 0; i < byte.arg; i++)
|
|
|
+ p[i] = begin[i];
|
|
|
+ SP() = begin;
|
|
|
+ PUSH(&tmp);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_BUILD_LIST: {
|
|
|
+ py_TValue tmp;
|
|
|
+ py_newlistn(&tmp, byte.arg);
|
|
|
+ py_TValue* begin = SP() - byte.arg;
|
|
|
+ for(int i = 0; i < byte.arg; i++) {
|
|
|
+ py_list_setitem(&tmp, i, begin + i);
|
|
|
+ }
|
|
|
+ SP() = begin;
|
|
|
+ PUSH(&tmp);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_BUILD_DICT: {
|
|
|
+ py_TValue* begin = SP() - byte.arg * 2;
|
|
|
+ py_Ref tmp = py_pushtmp();
|
|
|
+ py_newdict(tmp);
|
|
|
+ for(int i = 0; i < byte.arg * 2; i += 2) {
|
|
|
+ bool ok = py_dict_setitem(tmp, begin + i, begin + i + 1);
|
|
|
+ if(!ok) goto __ERROR;
|
|
|
}
|
|
|
- case OP_BUILD_STRING: {
|
|
|
- py_TValue* begin = SP() - byte.arg;
|
|
|
- c11_sbuf ss;
|
|
|
- c11_sbuf__ctor(&ss);
|
|
|
- for(int i = 0; i < byte.arg; i++) {
|
|
|
- if(!py_str(begin + i)) goto __ERROR;
|
|
|
- c11_sbuf__write_sv(&ss, py_tosv(&self->last_retval));
|
|
|
+ SP() = begin;
|
|
|
+ PUSH(tmp);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_BUILD_SET: {
|
|
|
+ py_TValue* begin = SP() - byte.arg;
|
|
|
+ py_Ref typeobject_set = py_getdict(self->builtins, py_name("set"));
|
|
|
+ assert(typeobject_set != NULL);
|
|
|
+ py_push(typeobject_set);
|
|
|
+ py_pushnil();
|
|
|
+ if(!py_vectorcall(0, 0)) goto __ERROR;
|
|
|
+ py_push(py_retval()); // empty set
|
|
|
+ py_Name id_add = py_name("add");
|
|
|
+ for(int i = 0; i < byte.arg; i++) {
|
|
|
+ py_push(TOP());
|
|
|
+ if(!py_pushmethod(id_add)) {
|
|
|
+ c11__abort("OP_BUILD_SET: failed to load method 'add'");
|
|
|
}
|
|
|
- SP() = begin;
|
|
|
- c11_sbuf__py_submit(&ss, SP()++);
|
|
|
- DISPATCH();
|
|
|
+ py_push(begin + i);
|
|
|
+ if(!py_vectorcall(1, 0)) goto __ERROR;
|
|
|
}
|
|
|
- /*****************************/
|
|
|
+ py_TValue tmp = *TOP();
|
|
|
+ SP() = begin;
|
|
|
+ PUSH(&tmp);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_BUILD_SLICE: {
|
|
|
+ // [start, stop, step]
|
|
|
+ py_TValue tmp;
|
|
|
+ py_newslice(&tmp);
|
|
|
+ py_setslot(&tmp, 0, THIRD());
|
|
|
+ py_setslot(&tmp, 1, SECOND());
|
|
|
+ py_setslot(&tmp, 2, TOP());
|
|
|
+ STACK_SHRINK(3);
|
|
|
+ PUSH(&tmp);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_BUILD_STRING: {
|
|
|
+ py_TValue* begin = SP() - byte.arg;
|
|
|
+ c11_sbuf ss;
|
|
|
+ c11_sbuf__ctor(&ss);
|
|
|
+ for(int i = 0; i < byte.arg; i++) {
|
|
|
+ if(!py_str(begin + i)) goto __ERROR;
|
|
|
+ c11_sbuf__write_sv(&ss, py_tosv(&self->last_retval));
|
|
|
+ }
|
|
|
+ SP() = begin;
|
|
|
+ c11_sbuf__py_submit(&ss, SP()++);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ /*****************************/
|
|
|
#define CASE_BINARY_OP(label, op, rop) \
|
|
|
case label: { \
|
|
|
if(!pk_stack_binaryop(self, op, rop)) goto __ERROR; \
|
|
|
@@ -613,642 +612,638 @@ FrameResult VM__run_top_frame(VM* self) {
|
|
|
*TOP() = self->last_retval; \
|
|
|
DISPATCH(); \
|
|
|
}
|
|
|
- CASE_BINARY_OP(OP_BINARY_ADD, __add__, __radd__)
|
|
|
- CASE_BINARY_OP(OP_BINARY_SUB, __sub__, __rsub__)
|
|
|
- CASE_BINARY_OP(OP_BINARY_MUL, __mul__, __rmul__)
|
|
|
- CASE_BINARY_OP(OP_BINARY_TRUEDIV, __truediv__, __rtruediv__)
|
|
|
- CASE_BINARY_OP(OP_BINARY_FLOORDIV, __floordiv__, __rfloordiv__)
|
|
|
- CASE_BINARY_OP(OP_BINARY_MOD, __mod__, __rmod__)
|
|
|
- CASE_BINARY_OP(OP_BINARY_POW, __pow__, __rpow__)
|
|
|
- CASE_BINARY_OP(OP_BINARY_LSHIFT, __lshift__, 0)
|
|
|
- CASE_BINARY_OP(OP_BINARY_RSHIFT, __rshift__, 0)
|
|
|
- CASE_BINARY_OP(OP_BINARY_AND, __and__, 0)
|
|
|
- CASE_BINARY_OP(OP_BINARY_OR, __or__, 0)
|
|
|
- CASE_BINARY_OP(OP_BINARY_XOR, __xor__, 0)
|
|
|
- CASE_BINARY_OP(OP_BINARY_MATMUL, __matmul__, 0)
|
|
|
- CASE_BINARY_OP(OP_COMPARE_LT, __lt__, __gt__)
|
|
|
- CASE_BINARY_OP(OP_COMPARE_LE, __le__, __ge__)
|
|
|
- CASE_BINARY_OP(OP_COMPARE_EQ, __eq__, __eq__)
|
|
|
- CASE_BINARY_OP(OP_COMPARE_NE, __ne__, __ne__)
|
|
|
- CASE_BINARY_OP(OP_COMPARE_GT, __gt__, __lt__)
|
|
|
- CASE_BINARY_OP(OP_COMPARE_GE, __ge__, __le__)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_ADD, __add__, __radd__)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_SUB, __sub__, __rsub__)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_MUL, __mul__, __rmul__)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_TRUEDIV, __truediv__, __rtruediv__)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_FLOORDIV, __floordiv__, __rfloordiv__)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_MOD, __mod__, __rmod__)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_POW, __pow__, __rpow__)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_LSHIFT, __lshift__, 0)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_RSHIFT, __rshift__, 0)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_AND, __and__, 0)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_OR, __or__, 0)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_XOR, __xor__, 0)
|
|
|
+ CASE_BINARY_OP(OP_BINARY_MATMUL, __matmul__, 0)
|
|
|
+ CASE_BINARY_OP(OP_COMPARE_LT, __lt__, __gt__)
|
|
|
+ CASE_BINARY_OP(OP_COMPARE_LE, __le__, __ge__)
|
|
|
+ CASE_BINARY_OP(OP_COMPARE_EQ, __eq__, __eq__)
|
|
|
+ CASE_BINARY_OP(OP_COMPARE_NE, __ne__, __ne__)
|
|
|
+ CASE_BINARY_OP(OP_COMPARE_GT, __gt__, __lt__)
|
|
|
+ CASE_BINARY_OP(OP_COMPARE_GE, __ge__, __le__)
|
|
|
#undef CASE_BINARY_OP
|
|
|
- case OP_IS_OP: {
|
|
|
- bool res = py_isidentical(SECOND(), TOP());
|
|
|
- POP();
|
|
|
- if(byte.arg) res = !res;
|
|
|
- py_newbool(TOP(), res);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_CONTAINS_OP: {
|
|
|
- // [b, a] -> b __contains__ a (a in b) -> [retval]
|
|
|
- py_Ref magic = py_tpfindmagic(SECOND()->type, __contains__);
|
|
|
- if(magic) {
|
|
|
- if(magic->type == tp_nativefunc) {
|
|
|
- if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR;
|
|
|
- STACK_SHRINK(2);
|
|
|
- } else {
|
|
|
- INSERT_THIRD(); // [?, b, a]
|
|
|
- *THIRD() = *magic; // [__contains__, a, b]
|
|
|
- if(!py_vectorcall(1, 0)) goto __ERROR;
|
|
|
- }
|
|
|
- bool res = py_tobool(py_retval());
|
|
|
- if(byte.arg) res = !res;
|
|
|
- py_newbool(SP()++, res);
|
|
|
- DISPATCH();
|
|
|
+ case OP_IS_OP: {
|
|
|
+ bool res = py_isidentical(SECOND(), TOP());
|
|
|
+ POP();
|
|
|
+ if(byte.arg) res = !res;
|
|
|
+ py_newbool(TOP(), res);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_CONTAINS_OP: {
|
|
|
+ // [b, a] -> b __contains__ a (a in b) -> [retval]
|
|
|
+ py_Ref magic = py_tpfindmagic(SECOND()->type, __contains__);
|
|
|
+ if(magic) {
|
|
|
+ if(magic->type == tp_nativefunc) {
|
|
|
+ if(!py_callcfunc(magic->_cfunc, 2, SECOND())) goto __ERROR;
|
|
|
+ STACK_SHRINK(2);
|
|
|
+ } else {
|
|
|
+ INSERT_THIRD(); // [?, b, a]
|
|
|
+ *THIRD() = *magic; // [__contains__, a, b]
|
|
|
+ if(!py_vectorcall(1, 0)) goto __ERROR;
|
|
|
}
|
|
|
- TypeError("'%t' type does not support '__contains__'", SECOND()->type);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- /*****************************************/
|
|
|
- case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
- case OP_POP_JUMP_IF_NOT_MATCH: {
|
|
|
- int res = py_equal(SECOND(), TOP());
|
|
|
- if(res < 0) goto __ERROR;
|
|
|
- STACK_SHRINK(2);
|
|
|
- if(!res) DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
+ bool res = py_tobool(py_retval());
|
|
|
+ if(byte.arg) res = !res;
|
|
|
+ py_newbool(SP()++, res);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_POP_JUMP_IF_FALSE: {
|
|
|
- int res = py_bool(TOP());
|
|
|
- if(res < 0) goto __ERROR;
|
|
|
+ TypeError("'%t' type does not support '__contains__'", SECOND()->type);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ /*****************************************/
|
|
|
+ case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
+ case OP_POP_JUMP_IF_NOT_MATCH: {
|
|
|
+ int res = py_equal(SECOND(), TOP());
|
|
|
+ if(res < 0) goto __ERROR;
|
|
|
+ STACK_SHRINK(2);
|
|
|
+ if(!res) DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_POP_JUMP_IF_FALSE: {
|
|
|
+ int res = py_bool(TOP());
|
|
|
+ if(res < 0) goto __ERROR;
|
|
|
+ POP();
|
|
|
+ if(!res) DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_POP_JUMP_IF_TRUE: {
|
|
|
+ int res = py_bool(TOP());
|
|
|
+ if(res < 0) goto __ERROR;
|
|
|
+ POP();
|
|
|
+ if(res) DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_JUMP_IF_TRUE_OR_POP: {
|
|
|
+ int res = py_bool(TOP());
|
|
|
+ if(res < 0) goto __ERROR;
|
|
|
+ if(res) {
|
|
|
+ DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
+ } else {
|
|
|
POP();
|
|
|
- if(!res) DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_POP_JUMP_IF_TRUE: {
|
|
|
- int res = py_bool(TOP());
|
|
|
- if(res < 0) goto __ERROR;
|
|
|
+ }
|
|
|
+ case OP_JUMP_IF_FALSE_OR_POP: {
|
|
|
+ int res = py_bool(TOP());
|
|
|
+ if(res < 0) goto __ERROR;
|
|
|
+ if(!res) {
|
|
|
+ DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
+ } else {
|
|
|
POP();
|
|
|
- if(res) DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_JUMP_IF_TRUE_OR_POP: {
|
|
|
- int res = py_bool(TOP());
|
|
|
- if(res < 0) goto __ERROR;
|
|
|
- if(res) {
|
|
|
- DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
- } else {
|
|
|
- POP();
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- }
|
|
|
- case OP_JUMP_IF_FALSE_OR_POP: {
|
|
|
- int res = py_bool(TOP());
|
|
|
- if(res < 0) goto __ERROR;
|
|
|
- if(!res) {
|
|
|
- DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
- } else {
|
|
|
- POP();
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- }
|
|
|
- case OP_SHORTCUT_IF_FALSE_OR_POP: {
|
|
|
- int res = py_bool(TOP());
|
|
|
- if(res < 0) goto __ERROR;
|
|
|
- if(!res) { // [b, False]
|
|
|
- STACK_SHRINK(2); // []
|
|
|
- py_newbool(SP()++, false); // [False]
|
|
|
- DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
- } else {
|
|
|
- POP(); // [b]
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- }
|
|
|
- case OP_LOOP_CONTINUE: {
|
|
|
- DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
- }
|
|
|
- case OP_LOOP_BREAK: {
|
|
|
+ }
|
|
|
+ case OP_SHORTCUT_IF_FALSE_OR_POP: {
|
|
|
+ int res = py_bool(TOP());
|
|
|
+ if(res < 0) goto __ERROR;
|
|
|
+ if(!res) { // [b, False]
|
|
|
+ STACK_SHRINK(2); // []
|
|
|
+ py_newbool(SP()++, false); // [False]
|
|
|
DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
- }
|
|
|
- /*****************************************/
|
|
|
- case OP_CALL: {
|
|
|
- ManagedHeap__collect_if_needed(&self->heap);
|
|
|
- vectorcall_opcall(byte.arg & 0xFF, byte.arg >> 8);
|
|
|
+ } else {
|
|
|
+ POP(); // [b]
|
|
|
DISPATCH();
|
|
|
}
|
|
|
- case OP_CALL_VARGS: {
|
|
|
- // [_0, _1, _2 | k1, v1, k2, v2]
|
|
|
- uint16_t argc = byte.arg & 0xFF;
|
|
|
- uint16_t kwargc = byte.arg >> 8;
|
|
|
-
|
|
|
- int n = 0;
|
|
|
- py_TValue* sp = SP();
|
|
|
- py_TValue* p1 = sp - kwargc * 2;
|
|
|
- py_TValue* base = p1 - argc;
|
|
|
- py_TValue* buf = self->vectorcall_buffer;
|
|
|
-
|
|
|
- for(py_TValue* curr = base; curr != p1; curr++) {
|
|
|
- if(curr->type != tp_star_wrapper) {
|
|
|
- buf[n++] = *curr;
|
|
|
- } else {
|
|
|
- py_TValue* args = py_getslot(curr, 0);
|
|
|
- py_TValue* p;
|
|
|
- int length = pk_arrayview(args, &p);
|
|
|
- if(length != -1) {
|
|
|
- for(int j = 0; j < length; j++) {
|
|
|
- buf[n++] = p[j];
|
|
|
- }
|
|
|
- argc += length - 1;
|
|
|
- } else {
|
|
|
- TypeError("*args must be a list or tuple, got '%t'", args->type);
|
|
|
- goto __ERROR;
|
|
|
+ }
|
|
|
+ case OP_LOOP_CONTINUE: {
|
|
|
+ DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
+ }
|
|
|
+ case OP_LOOP_BREAK: {
|
|
|
+ DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
+ }
|
|
|
+ /*****************************************/
|
|
|
+ case OP_CALL: {
|
|
|
+ ManagedHeap__collect_if_needed(&self->heap);
|
|
|
+ vectorcall_opcall(byte.arg & 0xFF, byte.arg >> 8);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_CALL_VARGS: {
|
|
|
+ // [_0, _1, _2 | k1, v1, k2, v2]
|
|
|
+ uint16_t argc = byte.arg & 0xFF;
|
|
|
+ uint16_t kwargc = byte.arg >> 8;
|
|
|
+
|
|
|
+ int n = 0;
|
|
|
+ py_TValue* sp = SP();
|
|
|
+ py_TValue* p1 = sp - kwargc * 2;
|
|
|
+ py_TValue* base = p1 - argc;
|
|
|
+ py_TValue* buf = self->vectorcall_buffer;
|
|
|
+
|
|
|
+ for(py_TValue* curr = base; curr != p1; curr++) {
|
|
|
+ if(curr->type != tp_star_wrapper) {
|
|
|
+ buf[n++] = *curr;
|
|
|
+ } else {
|
|
|
+ py_TValue* args = py_getslot(curr, 0);
|
|
|
+ py_TValue* p;
|
|
|
+ int length = pk_arrayview(args, &p);
|
|
|
+ if(length != -1) {
|
|
|
+ for(int j = 0; j < length; j++) {
|
|
|
+ buf[n++] = p[j];
|
|
|
}
|
|
|
+ argc += length - 1;
|
|
|
+ } else {
|
|
|
+ TypeError("*args must be a list or tuple, got '%t'", args->type);
|
|
|
+ goto __ERROR;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- for(py_TValue* curr = p1; curr != sp; curr += 2) {
|
|
|
- if(curr[1].type != tp_star_wrapper) {
|
|
|
- buf[n++] = curr[0];
|
|
|
- buf[n++] = curr[1];
|
|
|
+ for(py_TValue* curr = p1; curr != sp; curr += 2) {
|
|
|
+ if(curr[1].type != tp_star_wrapper) {
|
|
|
+ buf[n++] = curr[0];
|
|
|
+ buf[n++] = curr[1];
|
|
|
+ } else {
|
|
|
+ assert(py_toint(&curr[0]) == 0);
|
|
|
+ py_TValue* kwargs = py_getslot(&curr[1], 0);
|
|
|
+ if(kwargs->type == tp_dict) {
|
|
|
+ py_TValue* p = buf + n;
|
|
|
+ if(!py_dict_apply(kwargs, unpack_dict_to_buffer, &p)) goto __ERROR;
|
|
|
+ n = p - buf;
|
|
|
+ kwargc += py_dict_len(kwargs) - 1;
|
|
|
} else {
|
|
|
- assert(py_toint(&curr[0]) == 0);
|
|
|
- py_TValue* kwargs = py_getslot(&curr[1], 0);
|
|
|
- if(kwargs->type == tp_dict) {
|
|
|
- py_TValue* p = buf + n;
|
|
|
- if(!py_dict_apply(kwargs, unpack_dict_to_buffer, &p)) goto __ERROR;
|
|
|
- n = p - buf;
|
|
|
- kwargc += py_dict_len(kwargs) - 1;
|
|
|
- } else {
|
|
|
- TypeError("**kwargs must be a dict, got '%t'", kwargs->type);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
+ TypeError("**kwargs must be a dict, got '%t'", kwargs->type);
|
|
|
+ goto __ERROR;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- memcpy(base, buf, n * sizeof(py_TValue));
|
|
|
- SP() = base + n;
|
|
|
+ memcpy(base, buf, n * sizeof(py_TValue));
|
|
|
+ SP() = base + n;
|
|
|
|
|
|
- vectorcall_opcall(argc, kwargc);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_RETURN_VALUE: {
|
|
|
- CHECK_RETURN_FROM_EXCEPT_OR_FINALLY();
|
|
|
- if(byte.arg == BC_NOARG) {
|
|
|
- self->last_retval = POPX();
|
|
|
- } else {
|
|
|
- py_newnone(&self->last_retval);
|
|
|
- }
|
|
|
- VM__pop_frame(self);
|
|
|
- if(frame == base_frame) { // [ frameBase<- ]
|
|
|
- return RES_RETURN;
|
|
|
- } else {
|
|
|
- frame = self->top_frame;
|
|
|
- PUSH(&self->last_retval);
|
|
|
- goto __NEXT_FRAME;
|
|
|
- }
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_YIELD_VALUE: {
|
|
|
- CHECK_RETURN_FROM_EXCEPT_OR_FINALLY();
|
|
|
- if(byte.arg == 1) {
|
|
|
- py_newnone(py_retval());
|
|
|
- } else {
|
|
|
- py_assign(py_retval(), TOP());
|
|
|
- POP();
|
|
|
- }
|
|
|
- return RES_YIELD;
|
|
|
- }
|
|
|
- case OP_FOR_ITER_YIELD_VALUE: {
|
|
|
- CHECK_RETURN_FROM_EXCEPT_OR_FINALLY();
|
|
|
- int res = py_next(TOP());
|
|
|
- if(res == -1) goto __ERROR;
|
|
|
- if(res) {
|
|
|
- return RES_YIELD;
|
|
|
- } else {
|
|
|
- assert(self->last_retval.type == tp_StopIteration);
|
|
|
- py_ObjectRef value = py_getslot(&self->last_retval, 0);
|
|
|
- if(py_isnil(value)) value = py_None();
|
|
|
- *TOP() = *value; // [iter] -> [retval]
|
|
|
- DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
- }
|
|
|
- }
|
|
|
- /////////
|
|
|
- case OP_LIST_APPEND: {
|
|
|
- // [list, iter, value]
|
|
|
- py_list_append(THIRD(), TOP());
|
|
|
- POP();
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_DICT_ADD: {
|
|
|
- // [dict, iter, key, value]
|
|
|
- bool ok = py_dict_setitem(FOURTH(), SECOND(), TOP());
|
|
|
- if(!ok) goto __ERROR;
|
|
|
- STACK_SHRINK(2);
|
|
|
- DISPATCH();
|
|
|
+ vectorcall_opcall(argc, kwargc);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_RETURN_VALUE: {
|
|
|
+ CHECK_RETURN_FROM_EXCEPT_OR_FINALLY();
|
|
|
+ if(byte.arg == BC_NOARG) {
|
|
|
+ self->last_retval = POPX();
|
|
|
+ } else {
|
|
|
+ py_newnone(&self->last_retval);
|
|
|
}
|
|
|
- case OP_SET_ADD: {
|
|
|
- // [set, iter, value]
|
|
|
- py_push(THIRD()); // [| set]
|
|
|
- if(!py_pushmethod(py_name("add"))) {
|
|
|
- c11__abort("OP_SET_ADD: failed to load method 'add'");
|
|
|
- } // [|add() set]
|
|
|
- py_push(THIRD());
|
|
|
- if(!py_vectorcall(1, 0)) goto __ERROR;
|
|
|
+ VM__pop_frame(self);
|
|
|
+ if(frame == base_frame) { // [ frameBase<- ]
|
|
|
+ return RES_RETURN;
|
|
|
+ } else {
|
|
|
+ frame = self->top_frame;
|
|
|
+ PUSH(&self->last_retval);
|
|
|
+ goto __NEXT_FRAME;
|
|
|
+ }
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_YIELD_VALUE: {
|
|
|
+ CHECK_RETURN_FROM_EXCEPT_OR_FINALLY();
|
|
|
+ if(byte.arg == 1) {
|
|
|
+ py_newnone(py_retval());
|
|
|
+ } else {
|
|
|
+ py_assign(py_retval(), TOP());
|
|
|
POP();
|
|
|
- DISPATCH();
|
|
|
}
|
|
|
- /////////
|
|
|
- case OP_UNARY_NEGATIVE: {
|
|
|
- if(!pk_callmagic(__neg__, 1, TOP())) goto __ERROR;
|
|
|
- *TOP() = self->last_retval;
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_UNARY_NOT: {
|
|
|
- int res = py_bool(TOP());
|
|
|
- if(res < 0) goto __ERROR;
|
|
|
- py_newbool(TOP(), !res);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_UNARY_STAR: {
|
|
|
- py_TValue value = POPX();
|
|
|
- int* level = py_newobject(SP()++, tp_star_wrapper, 1, sizeof(int));
|
|
|
- *level = byte.arg;
|
|
|
- py_setslot(TOP(), 0, &value);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_UNARY_INVERT: {
|
|
|
- if(!pk_callmagic(__invert__, 1, TOP())) goto __ERROR;
|
|
|
- *TOP() = self->last_retval;
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- ////////////////
|
|
|
- case OP_GET_ITER: {
|
|
|
- if(!py_iter(TOP())) goto __ERROR;
|
|
|
- *TOP() = *py_retval();
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_FOR_ITER: {
|
|
|
- int res = py_next(TOP());
|
|
|
- if(res == -1) goto __ERROR;
|
|
|
- if(res) {
|
|
|
- PUSH(py_retval());
|
|
|
- DISPATCH();
|
|
|
- } else {
|
|
|
- assert(self->last_retval.type == tp_StopIteration);
|
|
|
- POP(); // [iter] -> []
|
|
|
- DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
- }
|
|
|
+ return RES_YIELD;
|
|
|
+ }
|
|
|
+ case OP_FOR_ITER_YIELD_VALUE: {
|
|
|
+ CHECK_RETURN_FROM_EXCEPT_OR_FINALLY();
|
|
|
+ int res = py_next(TOP());
|
|
|
+ if(res == -1) goto __ERROR;
|
|
|
+ if(res) {
|
|
|
+ return RES_YIELD;
|
|
|
+ } else {
|
|
|
+ assert(self->last_retval.type == tp_StopIteration);
|
|
|
+ py_ObjectRef value = py_getslot(&self->last_retval, 0);
|
|
|
+ if(py_isnil(value)) value = py_None();
|
|
|
+ *TOP() = *value; // [iter] -> [retval]
|
|
|
+ DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
}
|
|
|
- ////////
|
|
|
- case OP_IMPORT_PATH: {
|
|
|
- py_Ref path_object = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
|
|
- const char* path = py_tostr(path_object);
|
|
|
- int res = py_import(path);
|
|
|
- if(res == -1) goto __ERROR;
|
|
|
- if(res == 0) {
|
|
|
- ImportError("No module named '%s'", path);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
+ }
|
|
|
+ /////////
|
|
|
+ case OP_LIST_APPEND: {
|
|
|
+ // [list, iter, value]
|
|
|
+ py_list_append(THIRD(), TOP());
|
|
|
+ POP();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_DICT_ADD: {
|
|
|
+ // [dict, iter, key, value]
|
|
|
+ bool ok = py_dict_setitem(FOURTH(), SECOND(), TOP());
|
|
|
+ if(!ok) goto __ERROR;
|
|
|
+ STACK_SHRINK(2);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_SET_ADD: {
|
|
|
+ // [set, iter, value]
|
|
|
+ py_push(THIRD()); // [| set]
|
|
|
+ if(!py_pushmethod(py_name("add"))) {
|
|
|
+ c11__abort("OP_SET_ADD: failed to load method 'add'");
|
|
|
+ } // [|add() set]
|
|
|
+ py_push(THIRD());
|
|
|
+ if(!py_vectorcall(1, 0)) goto __ERROR;
|
|
|
+ POP();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ /////////
|
|
|
+ case OP_UNARY_NEGATIVE: {
|
|
|
+ if(!pk_callmagic(__neg__, 1, TOP())) goto __ERROR;
|
|
|
+ *TOP() = self->last_retval;
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_UNARY_NOT: {
|
|
|
+ int res = py_bool(TOP());
|
|
|
+ if(res < 0) goto __ERROR;
|
|
|
+ py_newbool(TOP(), !res);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_UNARY_STAR: {
|
|
|
+ py_TValue value = POPX();
|
|
|
+ int* level = py_newobject(SP()++, tp_star_wrapper, 1, sizeof(int));
|
|
|
+ *level = byte.arg;
|
|
|
+ py_setslot(TOP(), 0, &value);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_UNARY_INVERT: {
|
|
|
+ if(!pk_callmagic(__invert__, 1, TOP())) goto __ERROR;
|
|
|
+ *TOP() = self->last_retval;
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ ////////////////
|
|
|
+ case OP_GET_ITER: {
|
|
|
+ if(!py_iter(TOP())) goto __ERROR;
|
|
|
+ *TOP() = *py_retval();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_FOR_ITER: {
|
|
|
+ int res = py_next(TOP());
|
|
|
+ if(res == -1) goto __ERROR;
|
|
|
+ if(res) {
|
|
|
PUSH(py_retval());
|
|
|
DISPATCH();
|
|
|
+ } else {
|
|
|
+ assert(self->last_retval.type == tp_StopIteration);
|
|
|
+ POP(); // [iter] -> []
|
|
|
+ DISPATCH_JUMP((int16_t)byte.arg);
|
|
|
}
|
|
|
- case OP_POP_IMPORT_STAR: {
|
|
|
- // [module]
|
|
|
- NameDict* dict = PyObject__dict(TOP()->_obj);
|
|
|
- py_ItemRef all = NameDict__try_get(dict, __all__);
|
|
|
- if(all) {
|
|
|
- py_TValue* p;
|
|
|
- int length = pk_arrayview(all, &p);
|
|
|
- if(length == -1) {
|
|
|
- TypeError("'__all__' must be a list or tuple, got '%t'", all->type);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- for(int i = 0; i < length; i++) {
|
|
|
- py_Name name = py_namev(py_tosv(p + i));
|
|
|
- py_ItemRef value = NameDict__try_get(dict, name);
|
|
|
- if(value == NULL) {
|
|
|
- ImportError("cannot import name '%n'", name);
|
|
|
- goto __ERROR;
|
|
|
- } else {
|
|
|
- if(!Frame__setglobal(frame, name, value)) goto __ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- for(int i = 0; i < dict->capacity; i++) {
|
|
|
- NameDict_KV* kv = &dict->items[i];
|
|
|
- if(kv->key == NULL) continue;
|
|
|
- c11_sv name = py_name2sv(kv->key);
|
|
|
- if(name.size == 0 || name.data[0] == '_') continue;
|
|
|
- if(!Frame__setglobal(frame, kv->key, &kv->value)) goto __ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
- POP();
|
|
|
- DISPATCH();
|
|
|
+ }
|
|
|
+ ////////
|
|
|
+ case OP_IMPORT_PATH: {
|
|
|
+ py_Ref path_object = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
|
|
+ const char* path = py_tostr(path_object);
|
|
|
+ int res = py_import(path);
|
|
|
+ if(res == -1) goto __ERROR;
|
|
|
+ if(res == 0) {
|
|
|
+ ImportError("No module named '%s'", path);
|
|
|
+ goto __ERROR;
|
|
|
}
|
|
|
- ////////
|
|
|
- case OP_UNPACK_SEQUENCE: {
|
|
|
+ PUSH(py_retval());
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_POP_IMPORT_STAR: {
|
|
|
+ // [module]
|
|
|
+ NameDict* dict = PyObject__dict(TOP()->_obj);
|
|
|
+ py_ItemRef all = NameDict__try_get(dict, __all__);
|
|
|
+ if(all) {
|
|
|
py_TValue* p;
|
|
|
- int length;
|
|
|
-
|
|
|
- switch(TOP()->type) {
|
|
|
- case tp_tuple: {
|
|
|
- length = py_tuple_len(TOP());
|
|
|
- p = py_tuple_data(TOP());
|
|
|
- break;
|
|
|
- }
|
|
|
- case tp_list: {
|
|
|
- length = py_list_len(TOP());
|
|
|
- p = py_list_data(TOP());
|
|
|
- break;
|
|
|
- }
|
|
|
- case tp_vec2i: {
|
|
|
- length = 2;
|
|
|
- if(byte.arg != length) break;
|
|
|
- c11_vec2i val = py_tovec2i(TOP());
|
|
|
- POP();
|
|
|
- py_newint(SP()++, val.x);
|
|
|
- py_newint(SP()++, val.y);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case tp_vec2: {
|
|
|
- length = 2;
|
|
|
- if(byte.arg != length) break;
|
|
|
- c11_vec2 val = py_tovec2(TOP());
|
|
|
- POP();
|
|
|
- py_newfloat(SP()++, val.x);
|
|
|
- py_newfloat(SP()++, val.y);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case tp_vec3i: {
|
|
|
- length = 3;
|
|
|
- if(byte.arg != length) break;
|
|
|
- c11_vec3i val = py_tovec3i(TOP());
|
|
|
- POP();
|
|
|
- py_newint(SP()++, val.x);
|
|
|
- py_newint(SP()++, val.y);
|
|
|
- py_newint(SP()++, val.z);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case tp_vec3: {
|
|
|
- length = 3;
|
|
|
- if(byte.arg != length) break;
|
|
|
- c11_vec3 val = py_tovec3(TOP());
|
|
|
- POP();
|
|
|
- py_newfloat(SP()++, val.x);
|
|
|
- py_newfloat(SP()++, val.y);
|
|
|
- py_newfloat(SP()++, val.z);
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- default: {
|
|
|
- TypeError("expected list or tuple to unpack, got %t", TOP()->type);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
- if(length != byte.arg) {
|
|
|
- ValueError("expected %d values to unpack, got %d", byte.arg, length);
|
|
|
+ int length = pk_arrayview(all, &p);
|
|
|
+ if(length == -1) {
|
|
|
+ TypeError("'__all__' must be a list or tuple, got '%t'", all->type);
|
|
|
goto __ERROR;
|
|
|
}
|
|
|
- POP();
|
|
|
for(int i = 0; i < length; i++) {
|
|
|
- PUSH(p + i);
|
|
|
+ py_Name name = py_namev(py_tosv(p + i));
|
|
|
+ py_ItemRef value = NameDict__try_get(dict, name);
|
|
|
+ if(value == NULL) {
|
|
|
+ ImportError("cannot import name '%n'", name);
|
|
|
+ goto __ERROR;
|
|
|
+ } else {
|
|
|
+ if(!Frame__setglobal(frame, name, value)) goto __ERROR;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for(int i = 0; i < dict->capacity; i++) {
|
|
|
+ NameDict_KV* kv = &dict->items[i];
|
|
|
+ if(kv->key == NULL) continue;
|
|
|
+ c11_sv name = py_name2sv(kv->key);
|
|
|
+ if(name.size == 0 || name.data[0] == '_') continue;
|
|
|
+ if(!Frame__setglobal(frame, kv->key, &kv->value)) goto __ERROR;
|
|
|
}
|
|
|
- DISPATCH();
|
|
|
}
|
|
|
- case OP_UNPACK_EX: {
|
|
|
- py_TValue* p;
|
|
|
- int length = pk_arrayview(TOP(), &p);
|
|
|
- if(length == -1) {
|
|
|
- TypeError("expected list or tuple to unpack, got %t", TOP()->type);
|
|
|
- goto __ERROR;
|
|
|
+ POP();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ ////////
|
|
|
+ case OP_UNPACK_SEQUENCE: {
|
|
|
+ py_TValue* p;
|
|
|
+ int length;
|
|
|
+
|
|
|
+ switch(TOP()->type) {
|
|
|
+ case tp_tuple: {
|
|
|
+ length = py_tuple_len(TOP());
|
|
|
+ p = py_tuple_data(TOP());
|
|
|
+ break;
|
|
|
}
|
|
|
- int exceed = length - byte.arg;
|
|
|
- if(exceed < 0) {
|
|
|
- ValueError("not enough values to unpack");
|
|
|
- goto __ERROR;
|
|
|
+ case tp_list: {
|
|
|
+ length = py_list_len(TOP());
|
|
|
+ p = py_list_data(TOP());
|
|
|
+ break;
|
|
|
}
|
|
|
- POP();
|
|
|
- for(int i = 0; i < byte.arg; i++) {
|
|
|
- PUSH(p + i);
|
|
|
+ case tp_vec2i: {
|
|
|
+ length = 2;
|
|
|
+ if(byte.arg != length) break;
|
|
|
+ c11_vec2i val = py_tovec2i(TOP());
|
|
|
+ POP();
|
|
|
+ py_newint(SP()++, val.x);
|
|
|
+ py_newint(SP()++, val.y);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case tp_vec2: {
|
|
|
+ length = 2;
|
|
|
+ if(byte.arg != length) break;
|
|
|
+ c11_vec2 val = py_tovec2(TOP());
|
|
|
+ POP();
|
|
|
+ py_newfloat(SP()++, val.x);
|
|
|
+ py_newfloat(SP()++, val.y);
|
|
|
+ DISPATCH();
|
|
|
}
|
|
|
- py_newlistn(SP()++, exceed);
|
|
|
- for(int i = 0; i < exceed; i++) {
|
|
|
- py_list_setitem(TOP(), i, p + byte.arg + i);
|
|
|
+ case tp_vec3i: {
|
|
|
+ length = 3;
|
|
|
+ if(byte.arg != length) break;
|
|
|
+ c11_vec3i val = py_tovec3i(TOP());
|
|
|
+ POP();
|
|
|
+ py_newint(SP()++, val.x);
|
|
|
+ py_newint(SP()++, val.y);
|
|
|
+ py_newint(SP()++, val.z);
|
|
|
+ DISPATCH();
|
|
|
}
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- ///////////
|
|
|
- case OP_BEGIN_CLASS: {
|
|
|
- // [base]
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- py_Type base;
|
|
|
- if(py_isnone(TOP())) {
|
|
|
- base = tp_object;
|
|
|
- } else {
|
|
|
- if(!py_checktype(TOP(), tp_type)) goto __ERROR;
|
|
|
- base = py_totype(TOP());
|
|
|
+ case tp_vec3: {
|
|
|
+ length = 3;
|
|
|
+ if(byte.arg != length) break;
|
|
|
+ c11_vec3 val = py_tovec3(TOP());
|
|
|
+ POP();
|
|
|
+ py_newfloat(SP()++, val.x);
|
|
|
+ py_newfloat(SP()++, val.y);
|
|
|
+ py_newfloat(SP()++, val.z);
|
|
|
+ DISPATCH();
|
|
|
}
|
|
|
- POP();
|
|
|
-
|
|
|
- py_TypeInfo* base_ti = pk_typeinfo(base);
|
|
|
- if(base_ti->is_sealed) {
|
|
|
- TypeError("type '%t' is not an acceptable base type", base);
|
|
|
+ default: {
|
|
|
+ TypeError("expected list or tuple to unpack, got %t", TOP()->type);
|
|
|
goto __ERROR;
|
|
|
}
|
|
|
-
|
|
|
- py_Type type = pk_newtypewithmode(name,
|
|
|
- base,
|
|
|
- frame->module,
|
|
|
- NULL,
|
|
|
- base_ti->is_python,
|
|
|
- false,
|
|
|
- frame->co->src->mode);
|
|
|
- PUSH(py_tpobject(type));
|
|
|
- self->curr_class = TOP();
|
|
|
- DISPATCH();
|
|
|
}
|
|
|
- case OP_END_CLASS: {
|
|
|
- // [cls or decorated]
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- if(!Frame__setglobal(frame, name, TOP())) goto __ERROR;
|
|
|
-
|
|
|
- if(py_istype(TOP(), tp_type)) {
|
|
|
- // call on_end_subclass
|
|
|
- py_TypeInfo* ti = py_touserdata(TOP());
|
|
|
- if(ti->base != tp_object) {
|
|
|
- py_TypeInfo* base_ti = ti->base_ti;
|
|
|
- if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti);
|
|
|
- }
|
|
|
- py_TValue* slot_eq = py_getdict(&ti->self, __eq__);
|
|
|
- py_TValue* slot_ne = py_getdict(&ti->self, __ne__);
|
|
|
- if(slot_eq && !slot_ne) {
|
|
|
- TypeError("'%n' implements '__eq__' but not '__ne__'", ti->name);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
- // class with decorator is unsafe currently
|
|
|
- // it skips the above check
|
|
|
- POP();
|
|
|
- self->curr_class = NULL;
|
|
|
- DISPATCH();
|
|
|
+ if(length != byte.arg) {
|
|
|
+ ValueError("expected %d values to unpack, got %d", byte.arg, length);
|
|
|
+ goto __ERROR;
|
|
|
}
|
|
|
- case OP_STORE_CLASS_ATTR: {
|
|
|
- assert(self->curr_class);
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- // TOP() can be a function, classmethod or custom decorator
|
|
|
- py_Ref actual_func = TOP();
|
|
|
- if(actual_func->type == tp_classmethod) {
|
|
|
- actual_func = py_getslot(actual_func, 0);
|
|
|
- }
|
|
|
- if(actual_func->type == tp_function) {
|
|
|
- Function* ud = py_touserdata(actual_func);
|
|
|
- ud->clazz = self->curr_class->_obj;
|
|
|
- }
|
|
|
- py_setdict(self->curr_class, name, TOP());
|
|
|
- POP();
|
|
|
- DISPATCH();
|
|
|
+ POP();
|
|
|
+ for(int i = 0; i < length; i++) {
|
|
|
+ PUSH(p + i);
|
|
|
}
|
|
|
- case OP_ADD_CLASS_ANNOTATION: {
|
|
|
- assert(self->curr_class);
|
|
|
- // [type_hint string]
|
|
|
- py_TypeInfo* ti = py_touserdata(self->curr_class);
|
|
|
- if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations);
|
|
|
- py_Name name = co_names[byte.arg];
|
|
|
- bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(name), TOP());
|
|
|
- if(!ok) goto __ERROR;
|
|
|
- POP();
|
|
|
- DISPATCH();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_UNPACK_EX: {
|
|
|
+ py_TValue* p;
|
|
|
+ int length = pk_arrayview(TOP(), &p);
|
|
|
+ if(length == -1) {
|
|
|
+ TypeError("expected list or tuple to unpack, got %t", TOP()->type);
|
|
|
+ goto __ERROR;
|
|
|
}
|
|
|
- ///////////
|
|
|
- case OP_WITH_ENTER: {
|
|
|
- // [expr]
|
|
|
- py_push(TOP());
|
|
|
- if(!py_pushmethod(__enter__)) {
|
|
|
- TypeError("'%t' object does not support the context manager protocol",
|
|
|
- TOP()->type);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- vectorcall_opcall(0, 0);
|
|
|
- DISPATCH();
|
|
|
+ int exceed = length - byte.arg;
|
|
|
+ if(exceed < 0) {
|
|
|
+ ValueError("not enough values to unpack");
|
|
|
+ goto __ERROR;
|
|
|
}
|
|
|
- case OP_WITH_EXIT: {
|
|
|
- // [expr]
|
|
|
- py_push(TOP());
|
|
|
- if(!py_pushmethod(__exit__)) {
|
|
|
- TypeError("'%t' object does not support the context manager protocol",
|
|
|
- TOP()->type);
|
|
|
- goto __ERROR;
|
|
|
- }
|
|
|
- if(!py_vectorcall(0, 0)) goto __ERROR;
|
|
|
- POP();
|
|
|
- DISPATCH();
|
|
|
+ POP();
|
|
|
+ for(int i = 0; i < byte.arg; i++) {
|
|
|
+ PUSH(p + i);
|
|
|
}
|
|
|
- ///////////
|
|
|
- case OP_TRY_ENTER: {
|
|
|
- Frame__set_unwind_target(frame, SP());
|
|
|
- DISPATCH();
|
|
|
+ py_newlistn(SP()++, exceed);
|
|
|
+ for(int i = 0; i < exceed; i++) {
|
|
|
+ py_list_setitem(TOP(), i, p + byte.arg + i);
|
|
|
}
|
|
|
- case OP_EXCEPTION_MATCH: {
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ ///////////
|
|
|
+ case OP_BEGIN_CLASS: {
|
|
|
+ // [base]
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ py_Type base;
|
|
|
+ if(py_isnone(TOP())) {
|
|
|
+ base = tp_object;
|
|
|
+ } else {
|
|
|
if(!py_checktype(TOP(), tp_type)) goto __ERROR;
|
|
|
- bool ok = py_isinstance(&self->curr_exception, py_totype(TOP()));
|
|
|
- py_newbool(TOP(), ok);
|
|
|
- DISPATCH();
|
|
|
+ base = py_totype(TOP());
|
|
|
}
|
|
|
- case OP_RAISE: {
|
|
|
- // [exception]
|
|
|
- if(py_istype(TOP(), tp_type)) {
|
|
|
- if(!py_tpcall(py_totype(TOP()), 0, NULL)) goto __ERROR;
|
|
|
- py_assign(TOP(), py_retval());
|
|
|
+ POP();
|
|
|
+
|
|
|
+ py_TypeInfo* base_ti = pk_typeinfo(base);
|
|
|
+ if(base_ti->is_sealed) {
|
|
|
+ TypeError("type '%t' is not an acceptable base type", base);
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+
|
|
|
+ py_Type type = pk_newtypewithmode(name,
|
|
|
+ base,
|
|
|
+ frame->module,
|
|
|
+ NULL,
|
|
|
+ base_ti->is_python,
|
|
|
+ false,
|
|
|
+ frame->co->src->mode);
|
|
|
+ PUSH(py_tpobject(type));
|
|
|
+ self->curr_class = TOP();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_END_CLASS: {
|
|
|
+ // [cls or decorated]
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ if(!Frame__setglobal(frame, name, TOP())) goto __ERROR;
|
|
|
+
|
|
|
+ if(py_istype(TOP(), tp_type)) {
|
|
|
+ // call on_end_subclass
|
|
|
+ py_TypeInfo* ti = py_touserdata(TOP());
|
|
|
+ if(ti->base != tp_object) {
|
|
|
+ py_TypeInfo* base_ti = ti->base_ti;
|
|
|
+ if(base_ti->on_end_subclass) base_ti->on_end_subclass(ti);
|
|
|
}
|
|
|
- if(!py_isinstance(TOP(), tp_BaseException)) {
|
|
|
- TypeError("exceptions must derive from BaseException");
|
|
|
+ py_TValue* slot_eq = py_getdict(&ti->self, __eq__);
|
|
|
+ py_TValue* slot_ne = py_getdict(&ti->self, __ne__);
|
|
|
+ if(slot_eq && !slot_ne) {
|
|
|
+ TypeError("'%n' implements '__eq__' but not '__ne__'", ti->name);
|
|
|
goto __ERROR;
|
|
|
}
|
|
|
- py_raise(TOP());
|
|
|
+ }
|
|
|
+ // class with decorator is unsafe currently
|
|
|
+ // it skips the above check
|
|
|
+ POP();
|
|
|
+ self->curr_class = NULL;
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_STORE_CLASS_ATTR: {
|
|
|
+ assert(self->curr_class);
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ // TOP() can be a function, classmethod or custom decorator
|
|
|
+ py_Ref actual_func = TOP();
|
|
|
+ if(actual_func->type == tp_classmethod) { actual_func = py_getslot(actual_func, 0); }
|
|
|
+ if(actual_func->type == tp_function) {
|
|
|
+ Function* ud = py_touserdata(actual_func);
|
|
|
+ ud->clazz = self->curr_class->_obj;
|
|
|
+ }
|
|
|
+ py_setdict(self->curr_class, name, TOP());
|
|
|
+ POP();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_ADD_CLASS_ANNOTATION: {
|
|
|
+ assert(self->curr_class);
|
|
|
+ // [type_hint string]
|
|
|
+ py_TypeInfo* ti = py_touserdata(self->curr_class);
|
|
|
+ if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations);
|
|
|
+ py_Name name = co_names[byte.arg];
|
|
|
+ bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(name), TOP());
|
|
|
+ if(!ok) goto __ERROR;
|
|
|
+ POP();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ ///////////
|
|
|
+ case OP_WITH_ENTER: {
|
|
|
+ // [expr]
|
|
|
+ py_push(TOP());
|
|
|
+ if(!py_pushmethod(__enter__)) {
|
|
|
+ TypeError("'%t' object does not support the context manager protocol", TOP()->type);
|
|
|
goto __ERROR;
|
|
|
}
|
|
|
- case OP_RAISE_ASSERT: {
|
|
|
- if(byte.arg) {
|
|
|
- if(!py_str(TOP())) goto __ERROR;
|
|
|
- POP();
|
|
|
- py_exception(tp_AssertionError, "%s", py_tostr(py_retval()));
|
|
|
- } else {
|
|
|
- py_exception(tp_AssertionError, "");
|
|
|
- }
|
|
|
+ vectorcall_opcall(0, 0);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_WITH_EXIT: {
|
|
|
+ // [expr]
|
|
|
+ py_push(TOP());
|
|
|
+ if(!py_pushmethod(__exit__)) {
|
|
|
+ TypeError("'%t' object does not support the context manager protocol", TOP()->type);
|
|
|
goto __ERROR;
|
|
|
}
|
|
|
- case OP_RE_RAISE: {
|
|
|
- if(self->curr_exception.type) {
|
|
|
- assert(!self->is_curr_exc_handled);
|
|
|
- goto __ERROR_RE_RAISE;
|
|
|
- }
|
|
|
- DISPATCH();
|
|
|
+ if(!py_vectorcall(0, 0)) goto __ERROR;
|
|
|
+ POP();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ ///////////
|
|
|
+ case OP_TRY_ENTER: {
|
|
|
+ Frame__set_unwind_target(frame, SP());
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_EXCEPTION_MATCH: {
|
|
|
+ if(!py_checktype(TOP(), tp_type)) goto __ERROR;
|
|
|
+ bool ok = py_isinstance(&self->curr_exception, py_totype(TOP()));
|
|
|
+ py_newbool(TOP(), ok);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_RAISE: {
|
|
|
+ // [exception]
|
|
|
+ if(py_istype(TOP(), tp_type)) {
|
|
|
+ if(!py_tpcall(py_totype(TOP()), 0, NULL)) goto __ERROR;
|
|
|
+ py_assign(TOP(), py_retval());
|
|
|
+ }
|
|
|
+ if(!py_isinstance(TOP(), tp_BaseException)) {
|
|
|
+ TypeError("exceptions must derive from BaseException");
|
|
|
+ goto __ERROR;
|
|
|
}
|
|
|
- case OP_PUSH_EXCEPTION: {
|
|
|
- assert(self->curr_exception.type);
|
|
|
- PUSH(&self->curr_exception);
|
|
|
- DISPATCH();
|
|
|
+ py_raise(TOP());
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ case OP_RAISE_ASSERT: {
|
|
|
+ if(byte.arg) {
|
|
|
+ if(!py_str(TOP())) goto __ERROR;
|
|
|
+ POP();
|
|
|
+ py_exception(tp_AssertionError, "%s", py_tostr(py_retval()));
|
|
|
+ } else {
|
|
|
+ py_exception(tp_AssertionError, "");
|
|
|
}
|
|
|
- case OP_BEGIN_EXC_HANDLING: {
|
|
|
- assert(self->curr_exception.type);
|
|
|
- self->is_curr_exc_handled = true;
|
|
|
- DISPATCH();
|
|
|
+ goto __ERROR;
|
|
|
+ }
|
|
|
+ case OP_RE_RAISE: {
|
|
|
+ if(self->curr_exception.type) {
|
|
|
+ assert(!self->is_curr_exc_handled);
|
|
|
+ goto __ERROR_RE_RAISE;
|
|
|
}
|
|
|
- case OP_END_EXC_HANDLING: {
|
|
|
- assert(self->curr_exception.type);
|
|
|
- py_clearexc(NULL);
|
|
|
- DISPATCH();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_PUSH_EXCEPTION: {
|
|
|
+ assert(self->curr_exception.type);
|
|
|
+ PUSH(&self->curr_exception);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_BEGIN_EXC_HANDLING: {
|
|
|
+ assert(self->curr_exception.type);
|
|
|
+ self->is_curr_exc_handled = true;
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_END_EXC_HANDLING: {
|
|
|
+ assert(self->curr_exception.type);
|
|
|
+ py_clearexc(NULL);
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_BEGIN_FINALLY: {
|
|
|
+ if(self->curr_exception.type) {
|
|
|
+ assert(!self->is_curr_exc_handled);
|
|
|
+ // temporarily handle the exception if any
|
|
|
+ self->is_curr_exc_handled = true;
|
|
|
}
|
|
|
- case OP_BEGIN_FINALLY: {
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ case OP_END_FINALLY: {
|
|
|
+ if(byte.arg == BC_NOARG) {
|
|
|
if(self->curr_exception.type) {
|
|
|
- assert(!self->is_curr_exc_handled);
|
|
|
- // temporarily handle the exception if any
|
|
|
- self->is_curr_exc_handled = true;
|
|
|
- }
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- case OP_END_FINALLY: {
|
|
|
- if(byte.arg == BC_NOARG) {
|
|
|
- if(self->curr_exception.type) {
|
|
|
- assert(self->is_curr_exc_handled);
|
|
|
- // revert the exception handling if needed
|
|
|
- self->is_curr_exc_handled = false;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // break or continue inside finally block
|
|
|
- py_clearexc(NULL);
|
|
|
+ assert(self->is_curr_exc_handled);
|
|
|
+ // revert the exception handling if needed
|
|
|
+ self->is_curr_exc_handled = false;
|
|
|
}
|
|
|
- DISPATCH();
|
|
|
- }
|
|
|
- //////////////////
|
|
|
- case OP_FORMAT_STRING: {
|
|
|
- py_Ref spec = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
|
|
- bool ok = stack_format_object(self, py_tosv(spec));
|
|
|
- if(!ok) goto __ERROR;
|
|
|
- DISPATCH();
|
|
|
+ } else {
|
|
|
+ // break or continue inside finally block
|
|
|
+ py_clearexc(NULL);
|
|
|
}
|
|
|
- default: c11__unreachable();
|
|
|
+ DISPATCH();
|
|
|
+ }
|
|
|
+ //////////////////
|
|
|
+ case OP_FORMAT_STRING: {
|
|
|
+ py_Ref spec = c11__at(py_TValue, &frame->co->consts, byte.arg);
|
|
|
+ bool ok = stack_format_object(self, py_tosv(spec));
|
|
|
+ if(!ok) goto __ERROR;
|
|
|
+ DISPATCH();
|
|
|
}
|
|
|
+ default: c11__unreachable();
|
|
|
+ }
|
|
|
|
|
|
- c11__unreachable();
|
|
|
-
|
|
|
- __ERROR:
|
|
|
- py_BaseException__stpush(&self->curr_exception,
|
|
|
- frame->co->src,
|
|
|
- Frame__lineno(frame),
|
|
|
- !frame->is_locals_special ? frame->co->name->data : NULL);
|
|
|
- __ERROR_RE_RAISE:
|
|
|
- do {
|
|
|
- } while(0);
|
|
|
- int target = Frame__prepare_jump_exception_handler(frame, &self->stack);
|
|
|
- if(target >= 0) {
|
|
|
- // 1. Exception can be handled inside the current frame
|
|
|
- DISPATCH_JUMP_ABSOLUTE(target);
|
|
|
- } else {
|
|
|
- // 2. Exception need to be propagated to the upper frame
|
|
|
- bool is_base_frame_to_be_popped = frame == base_frame;
|
|
|
- VM__pop_frame(self);
|
|
|
- if(self->top_frame == NULL || is_base_frame_to_be_popped) {
|
|
|
- // propagate to the top level
|
|
|
- return RES_ERROR;
|
|
|
- }
|
|
|
- frame = self->top_frame;
|
|
|
- RESET_CO_CACHE();
|
|
|
- goto __ERROR;
|
|
|
+ c11__unreachable();
|
|
|
+
|
|
|
+__ERROR:
|
|
|
+ py_BaseException__stpush(&self->curr_exception,
|
|
|
+ frame->co->src,
|
|
|
+ Frame__lineno(frame),
|
|
|
+ !frame->is_locals_special ? frame->co->name->data : NULL);
|
|
|
+__ERROR_RE_RAISE:
|
|
|
+ do {
|
|
|
+ } while(0);
|
|
|
+
|
|
|
+ int target = Frame__prepare_jump_exception_handler(frame, &self->stack);
|
|
|
+ if(target >= 0) {
|
|
|
+ // 1. Exception can be handled inside the current frame
|
|
|
+ DISPATCH_JUMP_ABSOLUTE(target);
|
|
|
+ } else {
|
|
|
+ // 2. Exception need to be propagated to the upper frame
|
|
|
+ bool is_base_frame_to_be_popped = frame == base_frame;
|
|
|
+ VM__pop_frame(self);
|
|
|
+ if(self->top_frame == NULL || is_base_frame_to_be_popped) {
|
|
|
+ // propagate to the top level
|
|
|
+ return RES_ERROR;
|
|
|
}
|
|
|
+ frame = self->top_frame;
|
|
|
+ RESET_CO_CACHE();
|
|
|
+ goto __ERROR;
|
|
|
}
|
|
|
|
|
|
- return RES_RETURN;
|
|
|
+ c11__unreachable();
|
|
|
}
|
|
|
|
|
|
const char* pk_op2str(py_Name op) {
|