diff --git a/amalgamate.py b/amalgamate.py index 05e2bc6e..e412ed45 100644 --- a/amalgamate.py +++ b/amalgamate.py @@ -4,7 +4,7 @@ with open("src/opcodes.h", "rt", encoding='utf-8') as f: pipeline = [ ["hash_table8.hpp", "common.h", "memory.h", "str.h", "safestl.h", "builtins.h", "error.h"], ["obj.h", "parser.h", "ref.h", "codeobject.h", "frame.h"], - ["vm.h", "compiler.h", "repl.h"], + ["vm.h", "ceval.h", "compiler.h", "repl.h"], ["iter.h", "pocketpy.h"] ] diff --git a/src/builtins.h b/src/builtins.h index 838d9eb9..690f85d8 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -404,7 +404,7 @@ class set: def __repr__(self): if len(self) == 0: return 'set()' - return '{'+ ', '.join(self._a.keys()) + '}' + return '{'+ ', '.join([repr(i) for i in self._a.keys()]) + '}' def __iter__(self): return self._a.keys() diff --git a/src/ceval.h b/src/ceval.h new file mode 100644 index 00000000..50e9bdde --- /dev/null +++ b/src/ceval.h @@ -0,0 +1,320 @@ +#pragma once + +#include "vm.h" + +PyVar VM::run_frame(Frame* frame){ + while(frame->has_next_bytecode()){ + const Bytecode& byte = frame->next_bytecode(); + // if(true || frame->_module != builtins){ + // printf("%d: %s (%d) %s\n", frame->_ip, OP_NAMES[byte.op], byte.arg, frame->stack_info().c_str()); + // } + switch (byte.op) + { + case OP_NO_OP: break; // do nothing + case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); break; + case OP_LOAD_LAMBDA: { + PyVar obj = frame->co->consts[byte.arg]; + setattr(obj, __module__, frame->_module); + frame->push(obj); + } break; + case OP_LOAD_NAME_REF: { + frame->push(PyRef(NameRef(frame->co->names[byte.arg]))); + } break; + case OP_LOAD_NAME: { + frame->push(NameRef(frame->co->names[byte.arg]).get(this, frame)); + } break; + case OP_STORE_NAME: { + auto& p = frame->co->names[byte.arg]; + NameRef(p).set(this, frame, frame->pop_value(this)); + } break; + case OP_BUILD_ATTR: { + int name = byte.arg >> 1; + bool _rvalue = byte.arg % 2 == 1; + auto& attr = frame->co->names[name]; + PyVar obj = frame->pop_value(this); + AttrRef ref = AttrRef(obj, NameRef(attr)); + if(_rvalue) frame->push(ref.get(this, frame)); + else frame->push(PyRef(ref)); + } break; + case OP_BUILD_INDEX: { + PyVar index = frame->pop_value(this); + auto ref = IndexRef(frame->pop_value(this), index); + if(byte.arg == 0) frame->push(PyRef(ref)); + else frame->push(ref.get(this, frame)); + } break; + case OP_STORE_REF: { + PyVar obj = frame->pop_value(this); + PyVarRef r = frame->pop(); + PyRef_AS_C(r)->set(this, frame, std::move(obj)); + } break; + case OP_DELETE_REF: { + PyVarRef r = frame->pop(); + PyRef_AS_C(r)->del(this, frame); + } break; + case OP_BUILD_SMART_TUPLE: + { + pkpy::Args items = frame->pop_n_reversed(byte.arg); + bool done = false; + for(int i=0; iis_type(tp_ref)) { + done = true; + for(int j=i; jtry_deref(this, items[j]); + frame->push(PyTuple(std::move(items))); + break; + } + } + if(done) break; + frame->push(PyRef(TupleRef(std::move(items)))); + } break; + case OP_BUILD_STRING: + { + pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg); + StrStream ss; + for(int i=0; ipush(PyStr(ss.str())); + } break; + case OP_LOAD_EVAL_FN: { + frame->push(builtins->attr(m_eval)); + } break; + case OP_LIST_APPEND: { + pkpy::Args args(2); + args[1] = frame->pop_value(this); // obj + args[0] = frame->top_value_offset(this, -2); // list + fast_call(m_append, std::move(args)); + } break; + case OP_STORE_FUNCTION: + { + PyVar obj = frame->pop_value(this); + const pkpy::Function_& fn = PyFunction_AS_C(obj); + setattr(obj, __module__, frame->_module); + frame->f_globals()[fn->name] = obj; + } break; + case OP_BUILD_CLASS: + { + const Str& clsName = frame->co->names[byte.arg].first; + PyVar clsBase = frame->pop_value(this); + if(clsBase == None) clsBase = _t(tp_object); + check_type(clsBase, tp_type); + PyVar cls = new_type_object(frame->_module, clsName, clsBase); + while(true){ + PyVar fn = frame->pop_value(this); + if(fn == None) break; + const pkpy::Function_& f = PyFunction_AS_C(fn); + setattr(fn, __module__, frame->_module); + setattr(cls, f->name, fn); + } + } break; + case OP_RETURN_VALUE: return frame->pop_value(this); + case OP_PRINT_EXPR: + { + const PyVar expr = frame->top_value(this); + if(expr == None) break; + *_stdout << PyStr_AS_C(asRepr(expr)) << '\n'; + } break; + case OP_POP_TOP: frame->_pop(); break; + case OP_BINARY_OP: + { + pkpy::Args args(2); + args[1] = frame->pop_value(this); + args[0] = frame->top_value(this); + frame->top() = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args)); + } break; + case OP_BITWISE_OP: + { + frame->push( + fast_call(BITWISE_SPECIAL_METHODS[byte.arg], + frame->pop_n_values_reversed(this, 2)) + ); + } break; + case OP_COMPARE_OP: + { + pkpy::Args args(2); + args[1] = frame->pop_value(this); + args[0] = frame->top_value(this); + frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args)); + } break; + case OP_IS_OP: + { + PyVar rhs = frame->pop_value(this); + bool ret_c = rhs == frame->top_value(this); + if(byte.arg == 1) ret_c = !ret_c; + frame->top() = PyBool(ret_c); + } break; + case OP_CONTAINS_OP: + { + PyVar rhs = frame->pop_value(this); + bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::one_arg(frame->pop_value(this)))); + if(byte.arg == 1) ret_c = !ret_c; + frame->push(PyBool(ret_c)); + } break; + case OP_UNARY_NEGATIVE: + frame->top() = num_negated(frame->top_value(this)); + break; + case OP_UNARY_NOT: + { + PyVar obj = frame->pop_value(this); + const PyVar& obj_bool = asBool(obj); + frame->push(PyBool(!PyBool_AS_C(obj_bool))); + } break; + case OP_POP_JUMP_IF_FALSE: + if(!PyBool_AS_C(asBool(frame->pop_value(this)))) frame->jump_abs(byte.arg); + break; + case OP_LOAD_NONE: frame->push(None); break; + case OP_LOAD_TRUE: frame->push(True); break; + case OP_LOAD_FALSE: frame->push(False); break; + case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); break; + case OP_ASSERT: + { + PyVar _msg = frame->pop_value(this); + Str msg = PyStr_AS_C(asStr(_msg)); + PyVar expr = frame->pop_value(this); + if(asBool(expr) != True) _error("AssertionError", msg); + } break; + case OP_EXCEPTION_MATCH: + { + const auto& _e = PyException_AS_C(frame->top()); + Str name = frame->co->names[byte.arg].first; + frame->push(PyBool(_e.match_type(name))); + } break; + case OP_RAISE: + { + PyVar obj = frame->pop_value(this); + Str msg = obj == None ? "" : PyStr_AS_C(asStr(obj)); + Str type = frame->co->names[byte.arg].first; + _error(type, msg); + } break; + case OP_RE_RAISE: _raise(); break; + case OP_BUILD_LIST: + frame->push(PyList( + frame->pop_n_values_reversed(this, byte.arg).to_list())); + break; + case OP_BUILD_MAP: + { + pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg*2); + PyVar obj = call(builtins->attr("dict")); + for(int i=0; ipush(obj); + } break; + case OP_BUILD_SET: + { + PyVar list = PyList( + frame->pop_n_values_reversed(this, byte.arg).to_list() + ); + PyVar obj = call(builtins->attr("set"), pkpy::one_arg(list)); + frame->push(obj); + } break; + case OP_DUP_TOP: frame->push(frame->top_value(this)); break; + case OP_CALL: + { + int ARGC = byte.arg & 0xFFFF; + int KWARGC = (byte.arg >> 16) & 0xFFFF; + pkpy::Args kwargs(0); + if(KWARGC > 0) kwargs = frame->pop_n_values_reversed(this, KWARGC*2); + pkpy::Args args = frame->pop_n_values_reversed(this, ARGC); + PyVar callable = frame->pop_value(this); + PyVar ret = call(callable, std::move(args), kwargs, true); + if(ret == _py_op_call) return ret; + frame->push(std::move(ret)); + } break; + case OP_JUMP_ABSOLUTE: frame->jump_abs(byte.arg); break; + case OP_SAFE_JUMP_ABSOLUTE: frame->jump_abs_safe(byte.arg); break; + case OP_GOTO: { + const Str& label = frame->co->names[byte.arg].first; + int* target = frame->co->labels.try_get(label); + if(target == nullptr) _error("KeyError", "label '" + label + "' not found"); + frame->jump_abs_safe(*target); + } break; + case OP_GET_ITER: + { + PyVar obj = frame->pop_value(this); + PyVar iter_obj = asIter(obj); + PyVarRef var = frame->pop(); + check_type(var, tp_ref); + PyIter_AS_C(iter_obj)->var = var; + frame->push(std::move(iter_obj)); + } break; + case OP_FOR_ITER: + { + // top() must be PyIter, so no need to try_deref() + auto& it = PyIter_AS_C(frame->top()); + PyVar obj = it->next(); + if(obj != nullptr){ + PyRef_AS_C(it->var)->set(this, frame, std::move(obj)); + }else{ + int blockEnd = frame->co->blocks[byte.block].end; + frame->jump_abs_safe(blockEnd); + } + } break; + case OP_LOOP_CONTINUE: + { + int blockStart = frame->co->blocks[byte.block].start; + frame->jump_abs(blockStart); + } break; + case OP_LOOP_BREAK: + { + int blockEnd = frame->co->blocks[byte.block].end; + frame->jump_abs_safe(blockEnd); + } break; + case OP_JUMP_IF_FALSE_OR_POP: + { + const PyVar expr = frame->top_value(this); + if(asBool(expr)==False) frame->jump_abs(byte.arg); + else frame->pop_value(this); + } break; + case OP_JUMP_IF_TRUE_OR_POP: + { + const PyVar expr = frame->top_value(this); + if(asBool(expr)==True) frame->jump_abs(byte.arg); + else frame->pop_value(this); + } break; + case OP_BUILD_SLICE: + { + PyVar stop = frame->pop_value(this); + PyVar start = frame->pop_value(this); + pkpy::Slice s; + if(start != None) {check_type(start, tp_int); s.start = (int)PyInt_AS_C(start);} + if(stop != None) {check_type(stop, tp_int); s.stop = (int)PyInt_AS_C(stop);} + frame->push(PySlice(s)); + } break; + case OP_IMPORT_NAME: + { + const Str& name = frame->co->names[byte.arg].first; + auto it = _modules.find(name); + if(it == _modules.end()){ + auto it2 = _lazy_modules.find(name); + if(it2 == _lazy_modules.end()){ + _error("ImportError", "module '" + name + "' not found"); + }else{ + const Str& source = it2->second; + CodeObject_ code = compile(source, name, EXEC_MODE); + PyVar _m = new_module(name); + _exec(code, _m, pkpy::make_shared()); + frame->push(_m); + _lazy_modules.erase(it2); + } + }else{ + frame->push(it->second); + } + } break; + case OP_YIELD_VALUE: return _py_op_yield; + // TODO: using "goto" inside with block may cause __exit__ not called + case OP_WITH_ENTER: call(frame->pop_value(this), __enter__); break; + case OP_WITH_EXIT: call(frame->pop_value(this), __exit__); break; + case OP_TRY_BLOCK_ENTER: frame->on_try_block_enter(); break; + case OP_TRY_BLOCK_EXIT: frame->on_try_block_exit(); break; + default: + throw std::runtime_error(Str("opcode ") + OP_NAMES[byte.op] + " is not implemented"); + break; + } + } + + if(frame->co->src->mode == EVAL_MODE || frame->co->src->mode == JSON_MODE){ + if(frame->_data.size() != 1) throw std::runtime_error("_data.size() != 1 in EVAL/JSON_MODE"); + return frame->pop_value(this); + } + + if(!frame->_data.empty()) throw std::runtime_error("_data.size() != 0 in EXEC_MODE"); + return None; +} diff --git a/src/compiler.h b/src/compiler.h index 1d6e7ecf..dba04388 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -2,7 +2,7 @@ #include "parser.h" #include "error.h" -#include "vm.h" +#include "ceval.h" class Compiler; diff --git a/src/iter.h b/src/iter.h index a3102e33..88a2e34c 100644 --- a/src/iter.h +++ b/src/iter.h @@ -1,6 +1,6 @@ #pragma once -#include "vm.h" +#include "ceval.h" class RangeIter : public BaseIter { i64 current; diff --git a/src/pocketpy.h b/src/pocketpy.h index ee361ece..9ec18e8a 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -1,6 +1,6 @@ #pragma once -#include "vm.h" +#include "ceval.h" #include "compiler.h" #include "repl.h" #include "iter.h" @@ -369,20 +369,11 @@ void init_builtins(VM* _vm) { _vm->bind_method<1>("str", "join", [](VM* vm, pkpy::Args& args) { const Str& self = vm->PyStr_AS_C(args[0]); StrStream ss; - if(args[1]->is_type(vm->tp_list)){ - const pkpy::List& a = vm->PyList_AS_C(args[1]); - for(int i = 0; i < a.size(); i++){ - if(i > 0) ss << self; - ss << vm->PyStr_AS_C(vm->asStr(a[i])); - } - }else if(args[1]->is_type(vm->tp_tuple)){ - const pkpy::Tuple& a = vm->PyTuple_AS_C(args[1]); - for(int i = 0; i < a.size(); i++){ - if(i > 0) ss << self; - ss << vm->PyStr_AS_C(vm->asStr(a[i])); - } - }else{ - vm->TypeError("can only join a list or tuple"); + PyVar obj = vm->asList(args[1]); + const pkpy::List& list = vm->PyList_AS_C(obj); + for (int i = 0; i < list.size(); ++i) { + if (i > 0) ss << self; + ss << vm->PyStr_AS_C(list[i]); } return vm->PyStr(ss.str()); }); @@ -411,11 +402,11 @@ void init_builtins(VM* _vm) { _vm->bind_method<2>("list", "insert", [](VM* vm, pkpy::Args& args) { pkpy::List& _self = vm->PyList_AS_C(args[0]); - int _index = (int)vm->PyInt_AS_C(args[1]); - if(_index < 0) _index += _self.size(); - if(_index < 0) _index = 0; - if(_index > _self.size()) _index = _self.size(); - _self.insert(_self.begin() + _index, args[2]); + int index = (int)vm->PyInt_AS_C(args[1]); + if(index < 0) index += _self.size(); + if(index < 0) index = 0; + if(index > _self.size()) index = _self.size(); + _self.insert(_self.begin() + index, args[2]); return vm->None; }); @@ -424,21 +415,19 @@ void init_builtins(VM* _vm) { return vm->None; }); - _vm->bind_method<0>("list", "copy", [](VM* vm, pkpy::Args& args) { - return vm->PyList(vm->PyList_AS_C(args[0])); - }); + _vm->bind_method<0>("list", "copy", CPP_LAMBDA(vm->PyList(vm->PyList_AS_C(args[0])))); _vm->bind_method<1>("list", "__add__", [](VM* vm, pkpy::Args& args) { - const pkpy::List& _self = vm->PyList_AS_C(args[0]); - const pkpy::List& _obj = vm->PyList_AS_C(args[1]); - pkpy::List _new_list = _self; - _new_list.insert(_new_list.end(), _obj.begin(), _obj.end()); - return vm->PyList(_new_list); + const pkpy::List& self = vm->PyList_AS_C(args[0]); + const pkpy::List& obj = vm->PyList_AS_C(args[1]); + pkpy::List new_list = self; + new_list.insert(new_list.end(), obj.begin(), obj.end()); + return vm->PyList(new_list); }); _vm->bind_method<0>("list", "__len__", [](VM* vm, pkpy::Args& args) { - const pkpy::List& _self = vm->PyList_AS_C(args[0]); - return vm->PyInt(_self.size()); + const pkpy::List& self = vm->PyList_AS_C(args[0]); + return vm->PyInt(self.size()); }); _vm->bind_method<0>("list", "__iter__", [](VM* vm, pkpy::Args& args) { @@ -462,25 +451,25 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<2>("list", "__setitem__", [](VM* vm, pkpy::Args& args) { - pkpy::List& _self = vm->PyList_AS_C(args[0]); - int _index = (int)vm->PyInt_AS_C(args[1]); - _index = vm->normalized_index(_index, _self.size()); - _self[_index] = args[2]; + pkpy::List& self = vm->PyList_AS_C(args[0]); + int index = (int)vm->PyInt_AS_C(args[1]); + index = vm->normalized_index(index, self.size()); + self[index] = args[2]; return vm->None; }); _vm->bind_method<1>("list", "__delitem__", [](VM* vm, pkpy::Args& args) { - pkpy::List& _self = vm->PyList_AS_C(args[0]); - int _index = (int)vm->PyInt_AS_C(args[1]); - _index = vm->normalized_index(_index, _self.size()); - _self.erase(_self.begin() + _index); + pkpy::List& self = vm->PyList_AS_C(args[0]); + int index = (int)vm->PyInt_AS_C(args[1]); + index = vm->normalized_index(index, self.size()); + self.erase(self.begin() + index); return vm->None; }); /************ PyTuple ************/ _vm->bind_static_method<1>("tuple", "__new__", [](VM* vm, pkpy::Args& args) { - pkpy::List _list = vm->PyList_AS_C(vm->call(vm->builtins->attr("list"), args)); - return vm->PyTuple(std::move(_list)); + pkpy::List list = vm->PyList_AS_C(vm->asList(args[0])); + return vm->PyTuple(std::move(list)); }); _vm->bind_method<0>("tuple", "__iter__", [](VM* vm, pkpy::Args& args) { @@ -522,9 +511,9 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<1>("bool", "__xor__", [](VM* vm, pkpy::Args& args) { - bool _self = vm->PyBool_AS_C(args[0]); - bool _obj = vm->PyBool_AS_C(args[1]); - return vm->PyBool(_self ^ _obj); + bool self = vm->PyBool_AS_C(args[0]); + bool other = vm->PyBool_AS_C(args[1]); + return vm->PyBool(self ^ other); }); _vm->bind_method<0>("ellipsis", "__repr__", CPP_LAMBDA(vm->PyStr("Ellipsis"))); @@ -557,10 +546,10 @@ void add_module_sys(VM* vm){ vm->setattr(mod, "version", vm->PyStr(PK_VERSION)); vm->bind_func<1>(mod, "getrefcount", CPP_LAMBDA(vm->PyInt(args[0].use_count()))); - vm->bind_func<0>(mod, "getrecursionlimit", CPP_LAMBDA(vm->PyInt(vm->maxRecursionDepth))); + vm->bind_func<0>(mod, "getrecursionlimit", CPP_LAMBDA(vm->PyInt(vm->recursionlimit))); vm->bind_func<1>(mod, "setrecursionlimit", [](VM* vm, pkpy::Args& args) { - vm->maxRecursionDepth = (int)vm->PyInt_AS_C(args[0]); + vm->recursionlimit = (int)vm->PyInt_AS_C(args[0]); return vm->None; }); } diff --git a/src/repl.h b/src/repl.h index 85c1354b..ae38676a 100644 --- a/src/repl.h +++ b/src/repl.h @@ -1,7 +1,7 @@ #pragma once #include "compiler.h" -#include "vm.h" +#include "ceval.h" class REPL { protected: diff --git a/src/vm.h b/src/vm.h index 7428f12c..302c5083 100644 --- a/src/vm.h +++ b/src/vm.h @@ -18,333 +18,10 @@ public: std::stack< std::unique_ptr > callstack; PyVar _py_op_call; PyVar _py_op_yield; + std::vector _all_types; // PyVar _ascii_str_pool[128]; - PyVar run_frame(Frame* frame){ - while(frame->has_next_bytecode()){ - const Bytecode& byte = frame->next_bytecode(); - // if(true || frame->_module != builtins){ - // printf("%d: %s (%d) %s\n", frame->_ip, OP_NAMES[byte.op], byte.arg, frame->stack_info().c_str()); - // } - switch (byte.op) - { - case OP_NO_OP: break; // do nothing - case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); break; - case OP_LOAD_LAMBDA: { - PyVar obj = frame->co->consts[byte.arg]; - setattr(obj, __module__, frame->_module); - frame->push(obj); - } break; - case OP_LOAD_NAME_REF: { - frame->push(PyRef(NameRef(frame->co->names[byte.arg]))); - } break; - case OP_LOAD_NAME: { - frame->push(NameRef(frame->co->names[byte.arg]).get(this, frame)); - } break; - case OP_STORE_NAME: { - auto& p = frame->co->names[byte.arg]; - NameRef(p).set(this, frame, frame->pop_value(this)); - } break; - case OP_BUILD_ATTR: { - int name = byte.arg >> 1; - bool _rvalue = byte.arg % 2 == 1; - auto& attr = frame->co->names[name]; - PyVar obj = frame->pop_value(this); - AttrRef ref = AttrRef(obj, NameRef(attr)); - if(_rvalue) frame->push(ref.get(this, frame)); - else frame->push(PyRef(ref)); - } break; - case OP_BUILD_INDEX: { - PyVar index = frame->pop_value(this); - auto ref = IndexRef(frame->pop_value(this), index); - if(byte.arg == 0) frame->push(PyRef(ref)); - else frame->push(ref.get(this, frame)); - } break; - case OP_STORE_REF: { - PyVar obj = frame->pop_value(this); - PyVarRef r = frame->pop(); - PyRef_AS_C(r)->set(this, frame, std::move(obj)); - } break; - case OP_DELETE_REF: { - PyVarRef r = frame->pop(); - PyRef_AS_C(r)->del(this, frame); - } break; - case OP_BUILD_SMART_TUPLE: - { - pkpy::Args items = frame->pop_n_reversed(byte.arg); - bool done = false; - for(int i=0; iis_type(tp_ref)) { - done = true; - for(int j=i; jtry_deref(this, items[j]); - frame->push(PyTuple(std::move(items))); - break; - } - } - if(done) break; - frame->push(PyRef(TupleRef(std::move(items)))); - } break; - case OP_BUILD_STRING: - { - pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg); - StrStream ss; - for(int i=0; ipush(PyStr(ss.str())); - } break; - case OP_LOAD_EVAL_FN: { - frame->push(builtins->attr(m_eval)); - } break; - case OP_LIST_APPEND: { - pkpy::Args args(2); - args[1] = frame->pop_value(this); // obj - args[0] = frame->top_value_offset(this, -2); // list - fast_call(m_append, std::move(args)); - } break; - case OP_STORE_FUNCTION: - { - PyVar obj = frame->pop_value(this); - const pkpy::Function_& fn = PyFunction_AS_C(obj); - setattr(obj, __module__, frame->_module); - frame->f_globals()[fn->name] = obj; - } break; - case OP_BUILD_CLASS: - { - const Str& clsName = frame->co->names[byte.arg].first; - PyVar clsBase = frame->pop_value(this); - if(clsBase == None) clsBase = _t(tp_object); - check_type(clsBase, tp_type); - PyVar cls = new_type_object(frame->_module, clsName, clsBase); - while(true){ - PyVar fn = frame->pop_value(this); - if(fn == None) break; - const pkpy::Function_& f = PyFunction_AS_C(fn); - setattr(fn, __module__, frame->_module); - setattr(cls, f->name, fn); - } - } break; - case OP_RETURN_VALUE: return frame->pop_value(this); - case OP_PRINT_EXPR: - { - const PyVar expr = frame->top_value(this); - if(expr == None) break; - *_stdout << PyStr_AS_C(asRepr(expr)) << '\n'; - } break; - case OP_POP_TOP: frame->_pop(); break; - case OP_BINARY_OP: - { - pkpy::Args args(2); - args[1] = frame->pop_value(this); - args[0] = frame->top_value(this); - frame->top() = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args)); - } break; - case OP_BITWISE_OP: - { - frame->push( - fast_call(BITWISE_SPECIAL_METHODS[byte.arg], - frame->pop_n_values_reversed(this, 2)) - ); - } break; - case OP_COMPARE_OP: - { - pkpy::Args args(2); - args[1] = frame->pop_value(this); - args[0] = frame->top_value(this); - frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args)); - } break; - case OP_IS_OP: - { - PyVar rhs = frame->pop_value(this); - bool ret_c = rhs == frame->top_value(this); - if(byte.arg == 1) ret_c = !ret_c; - frame->top() = PyBool(ret_c); - } break; - case OP_CONTAINS_OP: - { - PyVar rhs = frame->pop_value(this); - bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::one_arg(frame->pop_value(this)))); - if(byte.arg == 1) ret_c = !ret_c; - frame->push(PyBool(ret_c)); - } break; - case OP_UNARY_NEGATIVE: - frame->top() = num_negated(frame->top_value(this)); - break; - case OP_UNARY_NOT: - { - PyVar obj = frame->pop_value(this); - const PyVar& obj_bool = asBool(obj); - frame->push(PyBool(!PyBool_AS_C(obj_bool))); - } break; - case OP_POP_JUMP_IF_FALSE: - if(!PyBool_AS_C(asBool(frame->pop_value(this)))) frame->jump_abs(byte.arg); - break; - case OP_LOAD_NONE: frame->push(None); break; - case OP_LOAD_TRUE: frame->push(True); break; - case OP_LOAD_FALSE: frame->push(False); break; - case OP_LOAD_ELLIPSIS: frame->push(Ellipsis); break; - case OP_ASSERT: - { - PyVar _msg = frame->pop_value(this); - Str msg = PyStr_AS_C(asStr(_msg)); - PyVar expr = frame->pop_value(this); - if(asBool(expr) != True) _error("AssertionError", msg); - } break; - case OP_EXCEPTION_MATCH: - { - const auto& _e = PyException_AS_C(frame->top()); - Str name = frame->co->names[byte.arg].first; - frame->push(PyBool(_e.match_type(name))); - } break; - case OP_RAISE: - { - PyVar obj = frame->pop_value(this); - Str msg = obj == None ? "" : PyStr_AS_C(asStr(obj)); - Str type = frame->co->names[byte.arg].first; - _error(type, msg); - } break; - case OP_RE_RAISE: _raise(); break; - case OP_BUILD_LIST: - frame->push(PyList( - frame->pop_n_values_reversed(this, byte.arg).to_list())); - break; - case OP_BUILD_MAP: - { - pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg*2); - PyVar obj = call(builtins->attr("dict")); - for(int i=0; ipush(obj); - } break; - case OP_BUILD_SET: - { - PyVar list = PyList( - frame->pop_n_values_reversed(this, byte.arg).to_list() - ); - PyVar obj = call(builtins->attr("set"), pkpy::one_arg(list)); - frame->push(obj); - } break; - case OP_DUP_TOP: frame->push(frame->top_value(this)); break; - case OP_CALL: - { - int ARGC = byte.arg & 0xFFFF; - int KWARGC = (byte.arg >> 16) & 0xFFFF; - pkpy::Args kwargs(0); - if(KWARGC > 0) kwargs = frame->pop_n_values_reversed(this, KWARGC*2); - pkpy::Args args = frame->pop_n_values_reversed(this, ARGC); - PyVar callable = frame->pop_value(this); - PyVar ret = call(callable, std::move(args), kwargs, true); - if(ret == _py_op_call) return ret; - frame->push(std::move(ret)); - } break; - case OP_JUMP_ABSOLUTE: frame->jump_abs(byte.arg); break; - case OP_SAFE_JUMP_ABSOLUTE: frame->jump_abs_safe(byte.arg); break; - case OP_GOTO: { - const Str& label = frame->co->names[byte.arg].first; - int* target = frame->co->labels.try_get(label); - if(target == nullptr) _error("KeyError", "label '" + label + "' not found"); - frame->jump_abs_safe(*target); - } break; - case OP_GET_ITER: - { - PyVar obj = frame->pop_value(this); - PyVar iter_obj = nullptr; - if(!obj->is_type(tp_native_iterator)){ - PyVarOrNull iter_f = getattr(obj, __iter__, false); - if(iter_f != nullptr) iter_obj = call(iter_f); - }else{ - iter_obj = obj; - } - if(iter_obj == nullptr){ - TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable"); - } - PyVarRef var = frame->pop(); - check_type(var, tp_ref); - PyIter_AS_C(iter_obj)->var = var; - frame->push(std::move(iter_obj)); - } break; - case OP_FOR_ITER: - { - // top() must be PyIter, so no need to try_deref() - auto& it = PyIter_AS_C(frame->top()); - PyVar obj = it->next(); - if(obj != nullptr){ - PyRef_AS_C(it->var)->set(this, frame, std::move(obj)); - }else{ - int blockEnd = frame->co->blocks[byte.block].end; - frame->jump_abs_safe(blockEnd); - } - } break; - case OP_LOOP_CONTINUE: - { - int blockStart = frame->co->blocks[byte.block].start; - frame->jump_abs(blockStart); - } break; - case OP_LOOP_BREAK: - { - int blockEnd = frame->co->blocks[byte.block].end; - frame->jump_abs_safe(blockEnd); - } break; - case OP_JUMP_IF_FALSE_OR_POP: - { - const PyVar expr = frame->top_value(this); - if(asBool(expr)==False) frame->jump_abs(byte.arg); - else frame->pop_value(this); - } break; - case OP_JUMP_IF_TRUE_OR_POP: - { - const PyVar expr = frame->top_value(this); - if(asBool(expr)==True) frame->jump_abs(byte.arg); - else frame->pop_value(this); - } break; - case OP_BUILD_SLICE: - { - PyVar stop = frame->pop_value(this); - PyVar start = frame->pop_value(this); - pkpy::Slice s; - if(start != None) {check_type(start, tp_int); s.start = (int)PyInt_AS_C(start);} - if(stop != None) {check_type(stop, tp_int); s.stop = (int)PyInt_AS_C(stop);} - frame->push(PySlice(s)); - } break; - case OP_IMPORT_NAME: - { - const Str& name = frame->co->names[byte.arg].first; - auto it = _modules.find(name); - if(it == _modules.end()){ - auto it2 = _lazy_modules.find(name); - if(it2 == _lazy_modules.end()){ - _error("ImportError", "module '" + name + "' not found"); - }else{ - const Str& source = it2->second; - CodeObject_ code = compile(source, name, EXEC_MODE); - PyVar _m = new_module(name); - _exec(code, _m, pkpy::make_shared()); - frame->push(_m); - _lazy_modules.erase(it2); - } - }else{ - frame->push(it->second); - } - } break; - case OP_YIELD_VALUE: return _py_op_yield; - // TODO: using "goto" inside with block may cause __exit__ not called - case OP_WITH_ENTER: call(frame->pop_value(this), __enter__); break; - case OP_WITH_EXIT: call(frame->pop_value(this), __exit__); break; - case OP_TRY_BLOCK_ENTER: frame->on_try_block_enter(); break; - case OP_TRY_BLOCK_EXIT: frame->on_try_block_exit(); break; - default: - throw std::runtime_error(Str("opcode ") + OP_NAMES[byte.op] + " is not implemented"); - break; - } - } - - if(frame->co->src->mode == EVAL_MODE || frame->co->src->mode == JSON_MODE){ - if(frame->_data.size() != 1) throw std::runtime_error("_data.size() != 1 in EVAL/JSON_MODE"); - return frame->pop_value(this); - } - - if(!frame->_data.empty()) throw std::runtime_error("_data.size() != 0 in EXEC_MODE"); - return None; - } + PyVar run_frame(Frame* frame); pkpy::NameDict _types; pkpy::NameDict _modules; // loaded modules @@ -358,7 +35,7 @@ public: PyVar builtins; // builtins module PyVar _main; // __main__ module - int maxRecursionDepth = 1000; + int recursionlimit = 1000; VM(bool use_stdio){ this->use_stdio = use_stdio; @@ -403,6 +80,19 @@ public: return True; } + PyVar asIter(const PyVar& obj){ + if(obj->is_type(tp_native_iterator)) return obj; + PyVarOrNull iter_f = getattr(obj, __iter__, false); + if(iter_f != nullptr) return call(iter_f); + TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable"); + return nullptr; + } + + PyVar asList(const PyVar& iterable){ + if(iterable->is_type(tp_list)) return iterable; + return call(_t(tp_list), pkpy::one_arg(iterable)); + } + PyVar fast_call(const Str& name, pkpy::Args&& args){ PyObject* cls = _t(args[0]).get(); while(cls != None.get()) { @@ -542,7 +232,7 @@ public: template inline std::unique_ptr _new_frame(Args&&... args){ - if(callstack.size() > maxRecursionDepth){ + if(callstack.size() > recursionlimit){ _error("RecursionError", "maximum recursion depth exceeded"); } return std::make_unique(std::forward(args)...); @@ -596,8 +286,6 @@ public: } } - std::vector _all_types; - PyVar new_type_object(PyVar mod, Str name, PyVar base){ if(!base->is_type(tp_type)) UNREACHABLE(); PyVar obj = pkpy::make_shared>(tp_type, _all_types.size()); @@ -908,8 +596,8 @@ public: this->False = new_object(tp_bool, false); this->builtins = new_module("builtins"); this->_main = new_module("__main__"); - this->_py_op_call = new_object(_new_type_object("_internal"), DUMMY_VAL); - this->_py_op_yield = new_object(_new_type_object("_internal"), DUMMY_VAL); + this->_py_op_call = new_object(_new_type_object("_py_op_call"), DUMMY_VAL); + this->_py_op_yield = new_object(_new_type_object("_py_op_yield"), DUMMY_VAL); setattr(_t(tp_type), __base__, _t(tp_object)); setattr(_t(tp_object), __base__, None); @@ -918,8 +606,8 @@ public: setattr(type, __name__, PyStr(name)); } - std::vector publicTypes = {"type", "object", "bool", "int", "float", "str", "list", "tuple", "range"}; - for (auto& name : publicTypes) { + std::vector pb_types = {"type", "object", "bool", "int", "float", "str", "list", "tuple", "range"}; + for (auto& name : pb_types) { setattr(builtins, name, _types[name]); } } diff --git a/tests/_builtin_ty.py b/tests/_builtin_ty.py index 7e69b01b..723ccf59 100644 --- a/tests/_builtin_ty.py +++ b/tests/_builtin_ty.py @@ -19,31 +19,31 @@ assert b == c s = "football" q = "abcd" r = "zoo" -str = "this is string example....wow!!!" +t = "this is string example....wow!!!" assert s[0] == 'f' assert s[1:4] == 'oot' assert s[:-1] == 'footbal' assert s[:10] == 'football' assert s[-3] == 'a' -assert str[-5:] == 'ow!!!' -assert str[3:-3] == 's is string example....wow' +assert t[-5:] == 'ow!!!' +assert t[3:-3] == 's is string example....wow' assert s > q;assert s < r assert s.replace("foo","ball") == "balltball" assert s.startswith('f') == True;assert s.endswith('o') == False -assert str.startswith('this') == True; +assert t.startswith('this') == True; -assert str.split('w') == ['this is string example....', 'o', '!!!'] +assert t.split('w') == ['this is string example....', 'o', '!!!'] assert "a,b,c".split(',') == ['a', 'b', 'c'] assert 'a,'.split(',') == ['a', ''] assert 'foo!!bar!!baz'.split('!!') == ['foo', 'bar', 'baz'] -str = "*****this is **string** example....wow!!!*****" +t = "*****this is **string** example....wow!!!*****" s = "123abcrunoob321" -# assert str.strip( '*' ) == "this is **string** example....wow!!!" -# assert s.strip( '12' ) == "3abcrunoob3" +assert t.strip( '*' ) == "this is **string** example....wow!!!" +assert s.strip( '12' ) == "3abcrunoob3" -assert str.strip( '*' ) == "this is **string** example....wow!!!" +assert t.strip( '*' ) == "this is **string** example....wow!!!" assert s.strip( '12' ) == "3abcrunoob3" s = ' asd\n asd \n' @@ -59,10 +59,13 @@ def test(*seq): return s1.join(seq) assert test("r", "u", "n", "o", "o", "b") == "r-u-n-o-o-b" +def f(): + for i in range(5): + yield str(i) +assert '|'.join(f()) == '0|1|2|3|4' -##num = 6 -##assert str(num) == '6' TypeError: 'str' object is not callable - +num = 6 +assert str(num) == '6' ############################################## ##Lists