diff --git a/src/ceval.h b/src/ceval.h index d54a7fff..edad3433 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -33,7 +33,7 @@ __NEXT_STEP:; case OP_ROT_TWO: std::swap(frame->top(), frame->top_1()); DISPATCH(); case OP_PRINT_EXPR: { PyObject* obj = frame->top(); // use top() to avoid accidental gc - if(obj != None) *_stdout << CAST(Str, asRepr(obj)) << '\n'; + if(obj != None) *_stdout << CAST(Str&, asRepr(obj)) << '\n'; frame->pop(); } DISPATCH(); /*****************************************/ @@ -168,7 +168,7 @@ __NEXT_STEP:; frame->push(VAR(std::move(items))); } DISPATCH(); case OP_BUILD_STRING: { - StrStream ss; // asStr() may run extra bytecode + std::stringstream ss; // asStr() may run extra bytecode for(int i=byte.arg-1; i>=0; i--) ss << CAST(Str&, asStr(frame->top_n(i))); frame->pop_n(byte.arg); frame->push(VAR(ss.str())); @@ -232,7 +232,7 @@ __NEXT_STEP:; case OP_GOTO: { StrName label = frame->co->names[byte.arg]; auto it = frame->co->labels.find(label); - if(it == frame->co->labels.end()) _error("KeyError", "label " + label.str().escape(true) + " not found"); + if(it == frame->co->labels.end()) _error("KeyError", fmt("label ", label.escape(), " not found")); frame->jump_abs_break(it->second); } DISPATCH(); /*****************************************/ @@ -317,13 +317,13 @@ __NEXT_STEP:; auto it = _lazy_modules.find(name); if(it == _lazy_modules.end()){ bool ok = false; - source = _read_file_cwd(name.str() + ".py", &ok); - if(!ok) _error("ImportError", "module " + name.str().escape(true) + " not found"); + source = _read_file_cwd(fmt(name, ".py"), &ok); + if(!ok) _error("ImportError", fmt("module ", name.escape(), " not found")); }else{ source = it->second; _lazy_modules.erase(it); } - CodeObject_ code = compile(source, name.str(), EXEC_MODE); + CodeObject_ code = compile(source, name.sv(), EXEC_MODE); PyObject* new_mod = new_module(name); _exec(code, new_mod); new_mod->attr()._try_perfect_rehash(); @@ -335,7 +335,7 @@ __NEXT_STEP:; case OP_IMPORT_STAR: { PyObject* obj = frame->popx(); for(auto& [name, value]: obj->attr().items()){ - Str s = name.str(); + std::string_view s = name.sv(); if(s.empty() || s[0] == '_') continue; frame->f_globals().set(name, value); } @@ -416,7 +416,7 @@ __NEXT_STEP:; _error(type, msg); } DISPATCH(); case OP_RE_RAISE: _raise(); DISPATCH(); - default: throw std::runtime_error(OP_NAMES[byte.op] + std::string(" is not implemented")); + default: throw std::runtime_error(fmt(OP_NAMES[byte.op], " is not implemented")); } UNREACHABLE(); } diff --git a/src/cffi.h b/src/cffi.h index 117d1248..7e532117 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -131,14 +131,14 @@ struct TypeDB{ return index == 0 ? nullptr : &_by_index[index-1]; } - const TypeInfo* get(const char name[]) const { + const TypeInfo* get(std::string_view name) const { auto it = _by_name.find(name); if(it == _by_name.end()) return nullptr; return get(it->second); } const TypeInfo* get(const Str& s) const { - return get(s.c_str()); + return get(s.sv()); } template @@ -203,7 +203,7 @@ struct Pointer{ vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) { Pointer& self = CAST(Pointer&, args[0]); - StrStream ss; + std::stringstream ss; ss << "<" << self.ctype->name; for(int i=0; i"; @@ -319,7 +319,7 @@ struct Pointer{ Pointer _to(VM* vm, StrName name){ auto it = ctype->members.find(name); if(it == ctype->members.end()){ - vm->AttributeError(Str("struct '") + ctype->name + "' has no member " + name.str().escape(true)); + vm->AttributeError(fmt("struct '", ctype->name, "' has no member ", name.escape())); } const MemberInfo& info = it->second; return {info.type, level, ptr+info.offset}; @@ -390,7 +390,7 @@ struct CType{ vm->bind_static_method<1>(type, "__new__", [](VM* vm, Args& args) { const Str& name = CAST(Str&, args[0]); const TypeInfo* type = _type_db.get(name); - if(type == nullptr) vm->TypeError("unknown type: " + name.escape(true)); + if(type == nullptr) vm->TypeError("unknown type: " + name.escape()); return VAR_T(CType, type); }); @@ -432,22 +432,22 @@ inline void add_module_c(VM* vm){ Pointer& self = CAST(Pointer&, args[0]); const Str& name = CAST(Str&, args[1]); int level = 0; - for(int i=name.size()-1; i>=0; i--){ + for(int i=name.length()-1; i>=0; i--){ if(name[i] == '*') level++; else break; } if(level == 0) vm->TypeError("expect a pointer type, such as 'int*'"); - Str type_s = name.substr(0, name.size()-level); + Str type_s = name.substr(0, name.length()-level); const TypeInfo* type = _type_db.get(type_s); - if(type == nullptr) vm->TypeError("unknown type: " + type_s.escape(true)); + if(type == nullptr) vm->TypeError("unknown type: " + type_s.escape()); return VAR_T(Pointer, type, level, self.ptr); }); vm->bind_func<1>(mod, "sizeof", [](VM* vm, Args& args) { const Str& name = CAST(Str&, args[0]); - if(name.find('*') != Str::npos) return VAR(sizeof(void*)); + if(name.index("*") != -1) return VAR(sizeof(void*)); const TypeInfo* type = _type_db.get(name); - if(type == nullptr) vm->TypeError("unknown type: " + name.escape(true)); + if(type == nullptr) vm->TypeError("unknown type: " + name.escape()); return VAR(type->size); }); diff --git a/src/compiler.h b/src/compiler.h index 6175d1c0..77d33c3f 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -112,9 +112,9 @@ class Compiler { void consume(TokenIndex expected) { if (!match(expected)){ - StrStream ss; - ss << "expected '" << TK_STR(expected) << "', but got '" << TK_STR(curr().type) << "'"; - SyntaxError(ss.str()); + SyntaxError( + fmt("expected '", TK_STR(expected), "', but got '", TK_STR(curr().type), "'") + ); } } @@ -190,7 +190,7 @@ class Compiler { _compile_f_args(e->decl, false); consume(TK(":")); } - e->decl->code = push_context(lexer->src, e->decl->name.str()); + e->decl->code = push_context(lexer->src, e->decl->name.sv()); EXPR(false); // https://github.com/blueloveTH/pocketpy/issues/37 ctx()->emit(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); pop_context(); @@ -775,7 +775,7 @@ __SUBSCR_END: if(mode()!=EXEC_MODE) SyntaxError("'label' is only available in EXEC_MODE"); consume(TK(".")); consume(TK("@id")); bool ok = ctx()->add_label(prev().str()); - if(!ok) SyntaxError("label " + prev().str().escape(true) + " already exists"); + if(!ok) SyntaxError("label " + prev().str().escape() + " already exists"); consume_end_stmt(); } break; case TK("goto"): @@ -877,7 +877,7 @@ __SUBSCR_END: if(match(TK("->"))){ if(!match(TK("None"))) consume(TK("@id")); } - decl->code = push_context(lexer->src, decl->name.str()); + decl->code = push_context(lexer->src, decl->name.sv()); compile_block_body(); pop_context(); ctx()->emit(OP_LOAD_FUNCTION, ctx()->add_func_decl(decl), prev().line); @@ -928,7 +928,7 @@ __SUBSCR_END: void IndentationError(Str msg){ lexer->throw_err("IndentationError", msg, curr().line, curr().start); } public: - Compiler(VM* vm, const char* source, Str filename, CompileMode mode){ + Compiler(VM* vm, const Str& source, const Str& filename, CompileMode mode){ this->vm = vm; this->used = false; this->lexer = std::make_unique( diff --git a/src/error.h b/src/error.h index 6a82967e..bd7182cd 100644 --- a/src/error.h +++ b/src/error.h @@ -38,14 +38,15 @@ struct SourceData { return {_start, i}; } - SourceData(const char* source, Str filename, CompileMode mode) { + SourceData(const Str& source, const Str& filename, CompileMode mode) { + int index = 0; // Skip utf8 BOM if there is any. - if (strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3; + if (strncmp(source.begin(), "\xEF\xBB\xBF", 3) == 0) index += 3; // Remove all '\r' - StrStream ss; - while(*source != '\0'){ - if(*source != '\r') ss << *source; - source++; + std::stringstream ss; + while(index < source.length()){ + if(source[index] != '\r') ss << source[index]; + index++; } this->filename = filename; @@ -55,14 +56,14 @@ struct SourceData { } Str snapshot(int lineno, const char* cursor=nullptr){ - StrStream ss; + std::stringstream ss; ss << " " << "File \"" << filename << "\", line " << lineno << '\n'; std::pair pair = get_line(lineno); Str line = ""; int removed_spaces = 0; if(pair.first && pair.second){ line = Str(pair.first, pair.second-pair.first).lstrip(); - removed_spaces = pair.second - pair.first - line.size(); + removed_spaces = pair.second - pair.first - line.length(); if(line.empty()) line = ""; } ss << " " << line; @@ -91,11 +92,11 @@ public: Str summary() const { StackTrace st(stacktrace); - StrStream ss; + std::stringstream ss; if(is_re) ss << "Traceback (most recent call last):\n"; while(!st.empty()) { ss << st.top() << '\n'; st.pop(); } - if (!msg.empty()) ss << type.str() << ": " << msg; - else ss << type.str(); + if (!msg.empty()) ss << type.sv() << ": " << msg; + else ss << type.sv(); return ss.str(); } }; diff --git a/src/expr.h b/src/expr.h index ece07980..6a337824 100644 --- a/src/expr.h +++ b/src/expr.h @@ -15,7 +15,7 @@ struct Expr{ int line = 0; virtual ~Expr() = default; virtual void emit(CodeEmitContext* ctx) = 0; - virtual Str str() const = 0; + virtual std::string str() const = 0; virtual bool is_starred() const { return false; } virtual bool is_literal() const { return false; } @@ -23,7 +23,7 @@ struct Expr{ virtual bool is_attrib() const { return false; } // for OP_DELETE_XXX - virtual bool emit_del(CodeEmitContext* ctx) { return false; } + [[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; } // for OP_STORE_XXX [[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) { return false; } @@ -64,8 +64,8 @@ struct CodeEmitContext{ expr->emit(this); } - Str _log_s_expr(){ - StrStream ss; + std::string _log_s_expr(){ + std::stringstream ss; for(auto& e: s_expr.data()) ss << e->str() << " "; return ss.str(); } @@ -118,7 +118,7 @@ struct NameExpr: Expr{ NameScope scope; NameExpr(StrName name, NameScope scope): name(name), scope(scope) {} - Str str() const override { return "$" + name.str(); } + std::string str() const override { return fmt("Name(", name.escape(), ")"); } void emit(CodeEmitContext* ctx) override { int index = ctx->add_name(name); @@ -161,7 +161,7 @@ struct NameExpr: Expr{ struct StarredExpr: Expr{ Expr_ child; StarredExpr(Expr_&& child): child(std::move(child)) {} - Str str() const override { return "*"; } + std::string str() const override { return "Starred()"; } bool is_starred() const override { return true; } @@ -180,7 +180,7 @@ struct StarredExpr: Expr{ struct NotExpr: Expr{ Expr_ child; NotExpr(Expr_&& child): child(std::move(child)) {} - Str str() const override { return "not"; } + std::string str() const override { return "Not()"; } void emit(CodeEmitContext* ctx) override { child->emit(ctx); @@ -192,7 +192,7 @@ struct NotExpr: Expr{ struct AndExpr: Expr{ Expr_ lhs; Expr_ rhs; - Str str() const override { return "and"; } + std::string str() const override { return "And()"; } void emit(CodeEmitContext* ctx) override { lhs->emit(ctx); @@ -206,7 +206,7 @@ struct AndExpr: Expr{ struct OrExpr: Expr{ Expr_ lhs; Expr_ rhs; - Str str() const override { return "or"; } + std::string str() const override { return "Or()"; } void emit(CodeEmitContext* ctx) override { lhs->emit(ctx); @@ -220,7 +220,7 @@ struct OrExpr: Expr{ struct Literal0Expr: Expr{ TokenIndex token; Literal0Expr(TokenIndex token): token(token) {} - Str str() const override { return TK_STR(token); } + std::string str() const override { return TK_STR(token); } void emit(CodeEmitContext* ctx) override { switch (token) { @@ -239,7 +239,7 @@ struct Literal0Expr: Expr{ struct LiteralExpr: Expr{ TokenValue value; LiteralExpr(TokenValue value): value(value) {} - Str str() const override { + std::string str() const override { if(std::holds_alternative(value)){ return std::to_string(std::get(value)); } @@ -249,7 +249,8 @@ struct LiteralExpr: Expr{ } if(std::holds_alternative(value)){ - return std::get(value).escape(true); + Str s = std::get(value).escape(); + return s.str(); } UNREACHABLE(); @@ -285,7 +286,7 @@ struct LiteralExpr: Expr{ struct NegatedExpr: Expr{ Expr_ child; NegatedExpr(Expr_&& child): child(std::move(child)) {} - Str str() const override { return "-"; } + std::string str() const override { return "Negated()"; } void emit(CodeEmitContext* ctx) override { VM* vm = ctx->vm; @@ -318,7 +319,7 @@ struct SliceExpr: Expr{ Expr_ start; Expr_ stop; Expr_ step; - Str str() const override { return "slice()"; } + std::string str() const override { return "Slice()"; } void emit(CodeEmitContext* ctx) override { if(start){ @@ -346,7 +347,7 @@ struct SliceExpr: Expr{ struct DictItemExpr: Expr{ Expr_ key; Expr_ value; - Str str() const override { return "k:v"; } + std::string str() const override { return "DictItem()"; } void emit(CodeEmitContext* ctx) override { value->emit(ctx); @@ -368,7 +369,7 @@ struct SequenceExpr: Expr{ struct ListExpr: SequenceExpr{ using SequenceExpr::SequenceExpr; - Str str() const override { return "list()"; } + std::string str() const override { return "List()"; } Opcode opcode() const override { return OP_BUILD_LIST; } bool is_json_object() const override { return true; } @@ -376,7 +377,7 @@ struct ListExpr: SequenceExpr{ struct DictExpr: SequenceExpr{ using SequenceExpr::SequenceExpr; - Str str() const override { return "dict()"; } + std::string str() const override { return "Dict()"; } Opcode opcode() const override { return OP_BUILD_DICT; } bool is_json_object() const override { return true; } @@ -384,13 +385,13 @@ struct DictExpr: SequenceExpr{ struct SetExpr: SequenceExpr{ using SequenceExpr::SequenceExpr; - Str str() const override { return "set()"; } + std::string str() const override { return "Set()"; } Opcode opcode() const override { return OP_BUILD_SET; } }; struct TupleExpr: SequenceExpr{ using SequenceExpr::SequenceExpr; - Str str() const override { return "tuple()"; } + std::string str() const override { return "Tuple()"; } Opcode opcode() const override { return OP_BUILD_TUPLE; } bool emit_store(CodeEmitContext* ctx) override { @@ -467,25 +468,25 @@ struct CompExpr: Expr{ struct ListCompExpr: CompExpr{ Opcode op0() override { return OP_BUILD_LIST; } Opcode op1() override { return OP_LIST_APPEND; } - Str str() const override { return "listcomp()"; } + std::string str() const override { return "ListComp()"; } }; struct DictCompExpr: CompExpr{ Opcode op0() override { return OP_BUILD_DICT; } Opcode op1() override { return OP_DICT_ADD; } - Str str() const override { return "dictcomp()"; } + std::string str() const override { return "DictComp()"; } }; struct SetCompExpr: CompExpr{ Opcode op0() override { return OP_BUILD_SET; } Opcode op1() override { return OP_SET_ADD; } - Str str() const override { return "setcomp()"; } + std::string str() const override { return "SetComp()"; } }; struct LambdaExpr: Expr{ FuncDecl_ decl; NameScope scope; - Str str() const override { return ""; } + std::string str() const override { return "Lambda()"; } LambdaExpr(NameScope scope){ this->decl = make_sp(); @@ -502,21 +503,21 @@ struct LambdaExpr: Expr{ struct FStringExpr: Expr{ Str src; FStringExpr(const Str& src): src(src) {} - Str str() const override { - return "f" + src.escape(true); + std::string str() const override { + return fmt("f", src.escape()); } void emit(CodeEmitContext* ctx) override { VM* vm = ctx->vm; static const std::regex pattern(R"(\{(.*?)\})"); - std::sregex_iterator begin(src.begin(), src.end(), pattern); - std::sregex_iterator end; + std::cregex_iterator begin(src.begin(), src.end(), pattern); + std::cregex_iterator end; int size = 0; int i = 0; for(auto it = begin; it != end; it++) { - std::smatch m = *it; + std::cmatch m = *it; if (i < m.position()) { - std::string literal = src.substr(i, m.position() - i); + Str literal = src.substr(i, m.position() - i); ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(literal)), line); size++; } @@ -527,8 +528,8 @@ struct FStringExpr: Expr{ size++; i = (int)(m.position() + m.length()); } - if (i < src.size()) { - std::string literal = src.substr(i, src.size() - i); + if (i < src.length()) { + Str literal = src.substr(i, src.length() - i); ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(literal)), line); size++; } @@ -539,7 +540,7 @@ struct FStringExpr: Expr{ struct SubscrExpr: Expr{ Expr_ a; Expr_ b; - Str str() const override { return "a[b]"; } + std::string str() const override { return "Subscr()"; } void emit(CodeEmitContext* ctx) override{ a->emit(ctx); @@ -567,7 +568,7 @@ struct AttribExpr: Expr{ Str b; AttribExpr(Expr_ a, const Str& b): a(std::move(a)), b(b) {} AttribExpr(Expr_ a, Str&& b): a(std::move(a)), b(std::move(b)) {} - Str str() const override { return "a.b"; } + std::string str() const override { return "Attrib()"; } void emit(CodeEmitContext* ctx) override{ a->emit(ctx); @@ -603,7 +604,7 @@ struct CallExpr: Expr{ Expr_ callable; std::vector args; std::vector> kwargs; - Str str() const override { return "call(...)"; } + std::string str() const override { return "Call()"; } bool need_unpack() const { for(auto& item: args) if(item->is_starred()) return true; @@ -643,7 +644,7 @@ struct BinaryExpr: Expr{ TokenIndex op; Expr_ lhs; Expr_ rhs; - Str str() const override { return TK_STR(op); } + std::string str() const override { return TK_STR(op); } void emit(CodeEmitContext* ctx) override { lhs->emit(ctx); @@ -683,10 +684,7 @@ struct TernaryExpr: Expr{ Expr_ cond; Expr_ true_expr; Expr_ false_expr; - - Str str() const override { - return "cond ? t : f"; - } + std::string str() const override { return "Ternary()"; } void emit(CodeEmitContext* ctx) override { cond->emit(ctx); diff --git a/src/frame.h b/src/frame.h index d63d9530..752e7cac 100644 --- a/src/frame.h +++ b/src/frame.h @@ -43,8 +43,8 @@ struct Frame { return co->src->snapshot(line); } - Str stack_info(){ - StrStream ss; + std::string stack_info(){ + std::stringstream ss; ss << id << " ["; for(int i=0; i<_data.size(); i++){ ss << (i64)_data[i]; diff --git a/src/gc.h b/src/gc.h index 74739fa2..752a18cb 100644 --- a/src/gc.h +++ b/src/gc.h @@ -37,7 +37,7 @@ struct ManagedHeap{ template PyObject* gcnew(Type type, T&& val){ using __T = Py_>; - PyObject* obj = new(pool128.alloc<__T>()) __T(type, std::forward(val)); + PyObject* obj = new(pool64.alloc<__T>()) __T(type, std::forward(val)); gen.push_back(obj); gc_counter++; return obj; @@ -46,7 +46,7 @@ struct ManagedHeap{ template PyObject* _new(Type type, T&& val){ using __T = Py_>; - PyObject* obj = new(pool128.alloc<__T>()) __T(type, std::forward(val)); + PyObject* obj = new(pool64.alloc<__T>()) __T(type, std::forward(val)); obj->gc.enabled = false; _no_gc.push_back(obj); return obj; @@ -57,7 +57,7 @@ struct ManagedHeap{ #endif ~ManagedHeap(){ - for(PyObject* obj: _no_gc) obj->~PyObject(), pool128.dealloc(obj); + for(PyObject* obj: _no_gc) obj->~PyObject(), pool64.dealloc(obj); #if DEBUG_GC_STATS for(auto& [type, count]: deleted){ std::cout << "GC: " << obj_type_name(vm, type) << "=" << count << std::endl; @@ -75,7 +75,7 @@ struct ManagedHeap{ #if DEBUG_GC_STATS deleted[obj->type] += 1; #endif - obj->~PyObject(), pool128.dealloc(obj); + obj->~PyObject(), pool64.dealloc(obj); } } diff --git a/src/lexer.h b/src/lexer.h index 6ed245ea..88698729 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -57,12 +57,13 @@ struct Token{ TokenValue value; Str str() const { return Str(start, length);} + std::string_view sv() const { return std::string_view(start, length);} - Str info() const { - StrStream ss; - Str raw = str(); - if (raw == Str("\n")) raw = "\\n"; - ss << line << ": " << TK_STR(type) << " '" << raw << "'"; + std::string info() const { + std::stringstream ss; + ss << line << ": " << TK_STR(type) << " '" << ( + sv()=="\n" ? "\\n" : sv() + ) << "'"; return ss.str(); } }; @@ -171,7 +172,7 @@ struct Lexer { curr_char--; while(true){ unsigned char c = peekchar(); - int u8bytes = utf8len(c); + int u8bytes = utf8len(c, true); if(u8bytes == 0) return 1; if(u8bytes == 1){ if(isalpha(c) || c=='_' || isdigit(c)) { diff --git a/src/namedict.h b/src/namedict.h index ba40eae6..5ea056cf 100644 --- a/src/namedict.h +++ b/src/namedict.h @@ -87,7 +87,7 @@ while(!_items[i].first.empty()) { \ PyObject* operator[](StrName key) const { bool ok; uint16_t i; HASH_PROBE(key, ok, i); - if(!ok) throw std::out_of_range("NameDict key not found: " + key.str()); + if(!ok) throw std::out_of_range(fmt("NameDict key not found: ", key)); return _items[i].second; } @@ -159,7 +159,7 @@ while(!_items[i].first.empty()) { \ void erase(StrName key){ bool ok; uint16_t i; HASH_PROBE(key, ok, i); - if(!ok) throw std::out_of_range("NameDict key not found: " + key.str()); + if(!ok) throw std::out_of_range(fmt("NameDict key not found: ", key)); _items[i].first = StrName(); _items[i].second = nullptr; _size--; diff --git a/src/pocketpy.h b/src/pocketpy.h index 3459c8e3..d1169135 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -12,7 +12,7 @@ namespace pkpy { inline CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) { - Compiler compiler(this, source.c_str(), filename, mode); + Compiler compiler(this, source, filename, mode); try{ return compiler.compile(); }catch(Exception& e){ @@ -71,7 +71,7 @@ inline void init_builtins(VM* _vm) { if(!vm->isinstance(args[1], type)){ Str _0 = obj_type_name(vm, OBJ_GET(Type, vm->_t(args[1]))); Str _1 = obj_type_name(vm, type); - vm->TypeError("super(): " + _0.escape(true) + " is not an instance of " + _1.escape(true)); + vm->TypeError("super(): " + _0.escape() + " is not an instance of " + _1.escape()); } Type base = vm->_all_types[type].base; return vm->heap.gcnew(vm->tp_super, Super(args[1], base)); @@ -150,7 +150,7 @@ inline void init_builtins(VM* _vm) { }); _vm->bind_builtin_func<1>("hex", [](VM* vm, Args& args) { - StrStream ss; + std::stringstream ss; ss << std::hex << CAST(i64, args[0]); return VAR("0x" + ss.str()); }); @@ -169,14 +169,14 @@ inline void init_builtins(VM* _vm) { std::vector keys = t_attr.keys(); names.insert(keys.begin(), keys.end()); List ret; - for (StrName name : names) ret.push_back(VAR(name.str())); + for (StrName name : names) ret.push_back(VAR(name.sv())); return VAR(std::move(ret)); }); _vm->bind_method<0>("object", "__repr__", [](VM* vm, Args& args) { PyObject* self = args[0]; if(is_tagged(self)) self = nullptr; - StrStream ss; + std::stringstream ss; ss << "<" << OBJ_NAME(vm->_t(self)) << " object at " << std::hex << self << ">"; return VAR(ss.str()); }); @@ -241,7 +241,7 @@ inline void init_builtins(VM* _vm) { if(parsed != s.length()) throw std::invalid_argument(""); return VAR(val); }catch(std::invalid_argument&){ - vm->ValueError("invalid literal for int(): " + s.escape(true)); + vm->ValueError("invalid literal for int(): " + s.escape()); } } vm->TypeError("int() argument must be a int, float, bool or str"); @@ -297,7 +297,7 @@ inline void init_builtins(VM* _vm) { _vm->bind_method<0>("float", "__repr__", [](VM* vm, Args& args) { f64 val = CAST(f64, args[0]); if(std::isinf(val) || std::isnan(val)) return VAR(std::to_string(val)); - StrStream ss; + std::stringstream ss; ss << std::setprecision(std::numeric_limits::max_digits10-1-2) << val; std::string s = ss.str(); if(std::all_of(s.begin()+1, s.end(), isdigit)) s += ".0"; @@ -335,7 +335,7 @@ inline void init_builtins(VM* _vm) { _vm->bind_method<0>("str", "__repr__", [](VM* vm, Args& args) { const Str& _self = CAST(Str&, args[0]); - return VAR(_self.escape(true)); + return VAR(_self.escape()); }); _vm->bind_method<0>("str", "__json__", [](VM* vm, Args& args) { @@ -405,7 +405,7 @@ inline void init_builtins(VM* _vm) { _vm->bind_method<1>("str", "join", [](VM* vm, Args& args) { const Str& self = CAST(Str&, args[0]); - StrStream ss; + FastStrStream ss; PyObject* obj = vm->asList(args[1]); const List& list = CAST(List&, obj); for (int i = 0; i < list.size(); ++i) { @@ -639,8 +639,8 @@ struct ReMatch { i64 start; i64 end; - std::smatch m; - ReMatch(i64 start, i64 end, std::smatch m) : start(start), end(end), m(m) {} + std::cmatch m; + ReMatch(i64 start, i64 end, std::cmatch m) : start(start), end(end), m(m) {} static void _register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_method<-1>(type, "__init__", CPP_NOT_IMPLEMENTED()); @@ -661,15 +661,13 @@ struct ReMatch { } }; -inline PyObject* _regex_search(const Str& _pattern, const Str& _string, bool fromStart, VM* vm){ - std::string pattern = _pattern.str(); - std::string string = _string.str(); - std::regex re(pattern); - std::smatch m; - if(std::regex_search(string, m, re)){ - if(fromStart && m.position() != 0) return vm->None; - i64 start = _string._u8_index(m.position()); - i64 end = _string._u8_index(m.position() + m.length()); +inline PyObject* _regex_search(const Str& pattern, const Str& string, bool from_start, VM* vm){ + std::regex re(pattern.begin(), pattern.end()); + std::cmatch m; + if(std::regex_search(string.begin(), string.end(), m, re)){ + if(from_start && m.position() != 0) return vm->None; + i64 start = string._byte_index_to_unicode(m.position()); + i64 end = string._byte_index_to_unicode(m.position() + m.length()); return VAR_T(ReMatch, start, end, m); } return vm->None; @@ -694,18 +692,17 @@ inline void add_module_re(VM* vm){ vm->bind_func<3>(mod, "sub", [](VM* vm, Args& args) { const Str& pattern = CAST(Str&, args[0]); const Str& repl = CAST(Str&, args[1]); - const Str& _string = CAST(Str&, args[2]); - std::regex re(pattern.str()); - std::string string = _string.str(); - return VAR(std::regex_replace(string, re, repl)); + const Str& string = CAST(Str&, args[2]); + std::regex re(pattern.begin(), pattern.end()); + return VAR(std::regex_replace(string.str(), re, repl.str())); }); vm->bind_func<2>(mod, "split", [](VM* vm, Args& args) { - std::string pattern = CAST(Str&, args[0]).str(); - std::string string = CAST(Str&, args[1]).str(); - std::regex re(pattern); - std::sregex_token_iterator it(string.begin(), string.end(), re, -1); - std::sregex_token_iterator end; + const Str& pattern = CAST(Str&, args[0]); + const Str& string = CAST(Str&, args[1]); + std::regex re(pattern.begin(), pattern.end()); + std::cregex_token_iterator it(string.begin(), string.end(), re, -1); + std::cregex_token_iterator end; List vec; for(; it != end; ++it){ vec.push_back(VAR(it->str())); @@ -863,8 +860,8 @@ extern "C" { pkpy::PyObject* val = vm->_main->attr().try_get(name); if(val == nullptr) return nullptr; try{ - pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(val)); - return strdup(repr.c_str()); + pkpy::Str repr = pkpy::CAST(pkpy::Str&, vm->asRepr(val)); + return repr.c_str_dup(); }catch(...){ return nullptr; } @@ -879,8 +876,8 @@ extern "C" { pkpy::PyObject* ret = vm->exec(source, "", pkpy::EVAL_MODE); if(ret == nullptr) return nullptr; try{ - pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(ret)); - return strdup(repr.c_str()); + pkpy::Str repr = pkpy::CAST(pkpy::Str&, vm->asRepr(ret)); + return repr.c_str_dup(); }catch(...){ return nullptr; } @@ -917,12 +914,12 @@ extern "C" { /// /// Return a json representing the result. char* pkpy_vm_read_output(pkpy::VM* vm){ - if(vm->use_stdio) return nullptr; - pkpy::StrStream* s_out = (pkpy::StrStream*)(vm->_stdout); - pkpy::StrStream* s_err = (pkpy::StrStream*)(vm->_stderr); + if(vm->is_stdio_used()) return nullptr; + std::stringstream* s_out = (std::stringstream*)(vm->_stdout); + std::stringstream* s_err = (std::stringstream*)(vm->_stderr); pkpy::Str _stdout = s_out->str(); pkpy::Str _stderr = s_err->str(); - pkpy::StrStream ss; + std::stringstream ss; ss << '{' << "\"stdout\": " << _stdout.escape(false); ss << ", " << "\"stderr\": " << _stderr.escape(false) << '}'; s_out->str(""); s_err->str(""); @@ -961,7 +958,7 @@ extern "C" { std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++); pkpy::PyObject* obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod); vm->bind_func<-1>(obj, name, [ret_code, f_header](pkpy::VM* vm, const pkpy::Args& args){ - pkpy::StrStream ss; + std::stringstream ss; ss << f_header; for(int i=0; i()(sv()); } + Str& operator=(const Str& other){ if(data!=nullptr) pool64.dealloc(data); size = other.size; @@ -86,18 +93,6 @@ struct Str{ if(data!=nullptr) pool64.dealloc(data); } - char operator[](int idx) const { - return data[idx]; - } - - int length() const { - return size; - } - - size_t hash() const{ - return std::hash()(sv()); - } - Str operator+(const Str& other) const { Str ret(size + other.size, is_ascii && other.is_ascii); memcpy(ret.data, data, size); @@ -116,7 +111,7 @@ struct Str{ } friend std::ostream& operator<<(std::ostream& os, const Str& str){ - os.write(str.data, str.size); + if(str.data!=nullptr) os.write(str.data, str.size); return os; } @@ -136,6 +131,16 @@ struct Str{ return size < other.size; } + bool operator<(const std::string_view& other) const { + int ret = strncmp(data, other.data(), std::min(size, (int)other.size())); + if(ret != 0) return ret < 0; + return size < (int)other.size(); + } + + friend bool operator<(const std::string_view& other, const Str& str){ + return str > other; + } + bool operator>(const Str& other) const { int ret = strncmp(data, other.data, std::min(size, other.size)); if(ret != 0) return ret > 0; @@ -176,7 +181,7 @@ struct Str{ } Str lstrip() const { - std::string copy = str(); + std::string copy(data, size); copy.erase(copy.begin(), std::find_if(copy.begin(), copy.end(), [](char c) { // std::isspace(c) does not working on windows (Debug) return c != ' ' && c != '\t' && c != '\r' && c != '\n'; @@ -184,8 +189,8 @@ struct Str{ return Str(copy); } - Str escape(bool single_quote) const { - StrStream ss; + Str escape(bool single_quote=true) const { + std::stringstream ss; ss << (single_quote ? '\'' : '"'); for (int i=0; ioperator[](i); @@ -215,31 +220,32 @@ struct Str{ return ss.str(); } - int index(const Str& sub) const { - auto p = std::search(data, data + size, sub.data, sub.data + sub.size); + int index(const Str& sub, int start=0) const { + auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size); if(p == data + size) return -1; return p - data; } Str replace(const Str& old, const Str& new_) const { - StrStream ss; - int i = 0; - while(i < size){ - int j = index(old); - if(j == -1){ - ss << substr(i, size - i); + std::stringstream ss; + int start = 0; + while(true){ + int i = index(old, start); + if(i == -1){ + ss << substr(start, size - start); break; } - ss << substr(i, j - i); + ss << substr(start, i - start); ss << new_; - i = j + old.size; + start = i + old.size; } return ss.str(); } /*************unicode*************/ - int _u8_index(int i) const{ + // TODO: check error + int _unicode_index_to_byte(int i) const{ if(is_ascii) return i; int j = 0; while(i > 0){ @@ -249,28 +255,39 @@ struct Str{ return j; } + int _byte_index_to_unicode(int n) const{ + if(is_ascii) return n; + int cnt = 0; + for(int i=0; i +inline std::string fmt(Args&&... args) { + std::stringstream ss; + (ss << ... << args); + return ss.str(); +} + const uint32_t kLoRangeA[] = {170,186,443,448,660,1488,1519,1568,1601,1646,1649,1749,1774,1786,1791,1808,1810,1869,1969,1994,2048,2112,2144,2208,2230,2308,2365,2384,2392,2418,2437,2447,2451,2474,2482,2486,2493,2510,2524,2527,2544,2556,2565,2575,2579,2602,2610,2613,2616,2649,2654,2674,2693,2703,2707,2730,2738,2741,2749,2768,2784,2809,2821,2831,2835,2858,2866,2869,2877,2908,2911,2929,2947,2949,2958,2962,2969,2972,2974,2979,2984,2990,3024,3077,3086,3090,3114,3133,3160,3168,3200,3205,3214,3218,3242,3253,3261,3294,3296,3313,3333,3342,3346,3389,3406,3412,3423,3450,3461,3482,3507,3517,3520,3585,3634,3648,3713,3716,3718,3724,3749,3751,3762,3773,3776,3804,3840,3904,3913,3976,4096,4159,4176,4186,4193,4197,4206,4213,4238,4352,4682,4688,4696,4698,4704,4746,4752,4786,4792,4800,4802,4808,4824,4882,4888,4992,5121,5743,5761,5792,5873,5888,5902,5920,5952,5984,5998,6016,6108,6176,6212,6272,6279,6314,6320,6400,6480,6512,6528,6576,6656,6688,6917,6981,7043,7086,7098,7168,7245,7258,7401,7406,7413,7418,8501,11568,11648,11680,11688,11696,11704,11712,11720,11728,11736,12294,12348,12353,12447,12449,12543,12549,12593,12704,12784,13312,19968,40960,40982,42192,42240,42512,42538,42606,42656,42895,42999,43003,43011,43015,43020,43072,43138,43250,43259,43261,43274,43312,43360,43396,43488,43495,43514,43520,43584,43588,43616,43633,43642,43646,43697,43701,43705,43712,43714,43739,43744,43762,43777,43785,43793,43808,43816,43968,44032,55216,55243,63744,64112,64285,64287,64298,64312,64318,64320,64323,64326,64467,64848,64914,65008,65136,65142,65382,65393,65440,65474,65482,65490,65498,65536,65549,65576,65596,65599,65616,65664,66176,66208,66304,66349,66370,66384,66432,66464,66504,66640,66816,66864,67072,67392,67424,67584,67592,67594,67639,67644,67647,67680,67712,67808,67828,67840,67872,67968,68030,68096,68112,68117,68121,68192,68224,68288,68297,68352,68416,68448,68480,68608,68864,69376,69415,69424,69600,69635,69763,69840,69891,69956,69968,70006,70019,70081,70106,70108,70144,70163,70272,70280,70282,70287,70303,70320,70405,70415,70419,70442,70450,70453,70461,70480,70493,70656,70727,70751,70784,70852,70855,71040,71128,71168,71236,71296,71352,71424,71680,71935,72096,72106,72161,72163,72192,72203,72250,72272,72284,72349,72384,72704,72714,72768,72818,72960,72968,72971,73030,73056,73063,73066,73112,73440,73728,74880,77824,82944,92160,92736,92880,92928,93027,93053,93952,94032,94208,100352,110592,110928,110948,110960,113664,113776,113792,113808,123136,123214,123584,124928,126464,126469,126497,126500,126503,126505,126516,126521,126523,126530,126535,126537,126539,126541,126545,126548,126551,126553,126555,126557,126559,126561,126564,126567,126572,126580,126585,126590,126592,126603,126625,126629,126635,131072,173824,177984,178208,183984,194560}; const uint32_t kLoRangeB[] = {170,186,443,451,660,1514,1522,1599,1610,1647,1747,1749,1775,1788,1791,1808,1839,1957,1969,2026,2069,2136,2154,2228,2237,2361,2365,2384,2401,2432,2444,2448,2472,2480,2482,2489,2493,2510,2525,2529,2545,2556,2570,2576,2600,2608,2611,2614,2617,2652,2654,2676,2701,2705,2728,2736,2739,2745,2749,2768,2785,2809,2828,2832,2856,2864,2867,2873,2877,2909,2913,2929,2947,2954,2960,2965,2970,2972,2975,2980,2986,3001,3024,3084,3088,3112,3129,3133,3162,3169,3200,3212,3216,3240,3251,3257,3261,3294,3297,3314,3340,3344,3386,3389,3406,3414,3425,3455,3478,3505,3515,3517,3526,3632,3635,3653,3714,3716,3722,3747,3749,3760,3763,3773,3780,3807,3840,3911,3948,3980,4138,4159,4181,4189,4193,4198,4208,4225,4238,4680,4685,4694,4696,4701,4744,4749,4784,4789,4798,4800,4805,4822,4880,4885,4954,5007,5740,5759,5786,5866,5880,5900,5905,5937,5969,5996,6000,6067,6108,6210,6264,6276,6312,6314,6389,6430,6509,6516,6571,6601,6678,6740,6963,6987,7072,7087,7141,7203,7247,7287,7404,7411,7414,7418,8504,11623,11670,11686,11694,11702,11710,11718,11726,11734,11742,12294,12348,12438,12447,12538,12543,12591,12686,12730,12799,19893,40943,40980,42124,42231,42507,42527,42539,42606,42725,42895,42999,43009,43013,43018,43042,43123,43187,43255,43259,43262,43301,43334,43388,43442,43492,43503,43518,43560,43586,43595,43631,43638,43642,43695,43697,43702,43709,43712,43714,43740,43754,43762,43782,43790,43798,43814,43822,44002,55203,55238,55291,64109,64217,64285,64296,64310,64316,64318,64321,64324,64433,64829,64911,64967,65019,65140,65276,65391,65437,65470,65479,65487,65495,65500,65547,65574,65594,65597,65613,65629,65786,66204,66256,66335,66368,66377,66421,66461,66499,66511,66717,66855,66915,67382,67413,67431,67589,67592,67637,67640,67644,67669,67702,67742,67826,67829,67861,67897,68023,68031,68096,68115,68119,68149,68220,68252,68295,68324,68405,68437,68466,68497,68680,68899,69404,69415,69445,69622,69687,69807,69864,69926,69956,70002,70006,70066,70084,70106,70108,70161,70187,70278,70280,70285,70301,70312,70366,70412,70416,70440,70448,70451,70457,70461,70480,70497,70708,70730,70751,70831,70853,70855,71086,71131,71215,71236,71338,71352,71450,71723,71935,72103,72144,72161,72163,72192,72242,72250,72272,72329,72349,72440,72712,72750,72768,72847,72966,72969,73008,73030,73061,73064,73097,73112,73458,74649,75075,78894,83526,92728,92766,92909,92975,93047,93071,94026,94032,100343,101106,110878,110930,110951,111355,113770,113788,113800,113817,123180,123214,123627,125124,126467,126495,126498,126500,126503,126514,126519,126521,126523,126530,126535,126537,126539,126543,126546,126548,126551,126553,126555,126557,126559,126562,126564,126570,126578,126583,126588,126590,126601,126619,126627,126633,126651,173782,177972,178205,183969,191456,195101}; @@ -289,15 +306,19 @@ struct StrName { StrName(uint16_t index): index(index) {} StrName(const char* s): index(get(s).index) {} StrName(const Str& s){ - if(s._cached_sn_index != 0){ - index = s._cached_sn_index; - } else { - index = get(s.sv()).index; - } + index = get(s.sv()).index; } - const Str& str() const { return _r_interned[index-1]; } + std::string_view sv() const { return _r_interned[index-1].sv(); } bool empty() const { return index == 0; } + friend std::ostream& operator<<(std::ostream& os, const StrName& sn){ + return os << sn.sv(); + } + + Str escape() const { + return _r_interned[index-1].escape(); + } + bool operator==(const StrName& other) const noexcept { return this->index == other.index; } @@ -327,6 +348,31 @@ struct StrName { } }; +struct FastStrStream{ + pod_vector parts; + + FastStrStream& operator<<(const Str& s){ + parts.push_back(&s); + return *this; + } + + Str str() const{ + int len = 0; + bool is_ascii = true; + for(auto& s: parts){ + len += s->length(); + is_ascii &= s->is_ascii; + } + Str result(len, is_ascii); + char* p = result.data; + for(auto& s: parts){ + memcpy(p, s->data, s->length()); + p += s->length(); + } + return result; + } +}; + inline std::map> StrName::_interned; inline std::vector StrName::_r_interned; diff --git a/src/vm.h b/src/vm.h index 5d2ce1c4..e294a538 100644 --- a/src/vm.h +++ b/src/vm.h @@ -58,8 +58,8 @@ public: PyObject* run_frame(Frame* frame); - NameDict _modules; // loaded modules - std::map _lazy_modules; // lazy loaded modules + NameDict _modules; // loaded modules + std::map _lazy_modules; // lazy loaded modules PyObject* _py_op_call; PyObject* _py_op_yield; @@ -71,7 +71,8 @@ public: PyObject* builtins; // builtins module PyObject* _main; // __main__ module - bool use_stdio; + std::stringstream _stdout_buffer; + std::stringstream _stderr_buffer; std::ostream* _stdout; std::ostream* _stderr; int recursionlimit = 1000; @@ -85,18 +86,13 @@ public: VM(bool use_stdio) : heap(this){ this->vm = this; - this->use_stdio = use_stdio; - if(use_stdio){ - this->_stdout = &std::cout; - this->_stderr = &std::cerr; - }else{ - this->_stdout = new StrStream(); - this->_stderr = new StrStream(); - } - + this->_stdout = use_stdio ? &std::cout : &_stdout_buffer; + this->_stderr = use_stdio ? &std::cerr : &_stderr_buffer; init_builtin_types(); } + bool is_stdio_used() const { return _stdout == &std::cout; } + Frame* top_frame() const { #if DEBUG_EXTRA_CHECK if(callstack.empty()) UNREACHABLE(); @@ -116,7 +112,7 @@ public: PyObject* self; PyObject* iter_f = get_unbound_method(obj, __iter__, &self, false); if(self != _py_null) return call(iter_f, Args{self}); - TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable"); + TypeError(OBJ_NAME(_t(obj)).escape() + " object is not iterable"); return nullptr; } @@ -210,7 +206,7 @@ public: PyTypeInfo info{ .obj = obj, .base = base, - .name = (mod!=nullptr && mod!=builtins) ? Str(OBJ_NAME(mod)+"."+name.str()): name.str() + .name = (mod!=nullptr && mod!=builtins) ? Str(OBJ_NAME(mod)+"."+name.sv()): name.sv() }; if(mod != nullptr) mod->attr().set(name, obj); _all_types.push_back(info); @@ -226,7 +222,7 @@ public: PyObject* obj = builtins->attr().try_get(type); if(obj == nullptr){ for(auto& t: _all_types) if(t.name == type) return t.obj; - throw std::runtime_error("type not found: " + type); + throw std::runtime_error(fmt("type not found: ", type)); } return obj; } @@ -293,18 +289,18 @@ public: void ZeroDivisionError(){ _error("ZeroDivisionError", "division by zero"); } void IndexError(const Str& msg){ _error("IndexError", msg); } void ValueError(const Str& msg){ _error("ValueError", msg); } - void NameError(StrName name){ _error("NameError", "name " + name.str().escape(true) + " is not defined"); } + void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); } void AttributeError(PyObject* obj, StrName name){ // OBJ_NAME calls getattr, which may lead to a infinite recursion - _error("AttributeError", "type " + OBJ_NAME(_t(obj)).escape(true) + " has no attribute " + name.str().escape(true)); + _error("AttributeError", fmt("type ", OBJ_NAME(_t(obj)).escape(), " has no attribute ", name.escape())); } void AttributeError(Str msg){ _error("AttributeError", msg); } void check_type(PyObject* obj, Type type){ if(is_type(obj, type)) return; - TypeError("expected " + OBJ_NAME(_t(type)).escape(true) + ", but got " + OBJ_NAME(_t(obj)).escape(true)); + TypeError("expected " + OBJ_NAME(_t(type)).escape() + ", but got " + OBJ_NAME(_t(obj)).escape()); } PyObject* _t(Type t){ @@ -317,13 +313,7 @@ public: return _all_types[OBJ_GET(Type, _t(obj->type)).index].obj; } - ~VM() { - heap.collect(); - if(!use_stdio){ - delete _stdout; - delete _stderr; - } - } + ~VM() { heap.collect(); } CodeObject_ compile(Str source, Str filename, CompileMode mode); PyObject* num_negated(PyObject* obj); @@ -363,14 +353,6 @@ inline void CodeObject::optimize(VM* vm){ uint32_t base_n = (uint32_t)(names.size() / kLocalsLoadFactor + 0.5); perfect_locals_capacity = find_next_capacity(base_n); perfect_hash_seed = find_perfect_hash_seed(perfect_locals_capacity, names); - - // pre-compute sn in co_consts - for(int i=0; itp_str)){ - Str& s = OBJ_GET(Str, consts[i]); - s._cached_sn_index = StrName::get(s.c_str()).index; - } - } } DEF_NATIVE_2(Str, tp_str) @@ -482,6 +464,10 @@ inline PyObject* py_var(VM* vm, std::string val){ return VAR(Str(std::move(val))); } +inline PyObject* py_var(VM* vm, std::string_view val){ + return VAR(Str(val)); +} + template void _check_py_class(VM* vm, PyObject* obj){ vm->check_type(obj, T::_type(vm)); @@ -493,7 +479,7 @@ inline PyObject* VM::num_negated(PyObject* obj){ }else if(is_float(obj)){ return VAR(-CAST(f64, obj)); } - TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape(true)); + TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape()); return nullptr; } @@ -503,7 +489,7 @@ inline f64 VM::num_to_float(PyObject* obj){ } else if (is_int(obj)){ return (f64)CAST(i64, obj); } - TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape(true)); + TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape()); return 0; } @@ -540,7 +526,7 @@ inline i64 VM::hash(PyObject* obj){ f64 val = CAST(f64, obj); return (i64)std::hash()(val); } - TypeError("unhashable type: " + OBJ_NAME(_t(obj)).escape(true)); + TypeError("unhashable type: " + OBJ_NAME(_t(obj)).escape()); return 0; } @@ -551,7 +537,7 @@ inline PyObject* VM::asRepr(PyObject* obj){ inline PyObject* VM::new_module(StrName name) { PyObject* obj = heap._new(tp_module, DummyModule()); - obj->attr().set(__name__, VAR(name.str())); + obj->attr().set(__name__, VAR(name.sv())); // we do not allow override in order to avoid memory leak // it is because Module objects are not garbage collected if(_modules.contains(name)) UNREACHABLE(); @@ -571,7 +557,7 @@ inline Str VM::disassemble(CodeObject_ co){ jumpTargets.push_back(byte.arg); } } - StrStream ss; + std::stringstream ss; int prev_line = -1; for(int i=0; icodes.size(); i++){ const Bytecode& byte = co->codes[i]; @@ -594,23 +580,23 @@ inline Str VM::disassemble(CodeObject_ co){ std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg); switch(byte.op){ case OP_LOAD_CONST: - argStr += " (" + CAST(Str, asRepr(co->consts[byte.arg])) + ")"; + argStr += fmt(" (", CAST(Str, asRepr(co->consts[byte.arg])), ")"); break; case OP_LOAD_NAME: case OP_LOAD_GLOBAL: case OP_STORE_LOCAL: case OP_STORE_GLOBAL: case OP_LOAD_ATTR: case OP_LOAD_METHOD: case OP_STORE_ATTR: case OP_DELETE_ATTR: case OP_IMPORT_NAME: case OP_BEGIN_CLASS: case OP_DELETE_LOCAL: case OP_DELETE_GLOBAL: - argStr += " (" + co->names[byte.arg].str() + ")"; + argStr += fmt(" (", co->names[byte.arg].sv(), ")"); break; case OP_BINARY_OP: - argStr += " (" + BINARY_SPECIAL_METHODS[byte.arg].str() + ")"; + argStr += fmt(" (", BINARY_SPECIAL_METHODS[byte.arg], ")"); break; case OP_COMPARE_OP: - argStr += " (" + COMPARE_SPECIAL_METHODS[byte.arg].str() + ")"; + argStr += fmt(" (", COMPARE_SPECIAL_METHODS[byte.arg], ")"); break; case OP_BITWISE_OP: - argStr += " (" + BITWISE_SPECIAL_METHODS[byte.arg].str() + ")"; + argStr += fmt(" (", BITWISE_SPECIAL_METHODS[byte.arg], ")"); break; } ss << pad(argStr, 40); // may overflow @@ -619,21 +605,21 @@ inline Str VM::disassemble(CodeObject_ co){ } #if !DEBUG_DIS_EXEC_MIN - StrStream consts; + std::stringstream consts; consts << "co_consts: "; - consts << CAST(Str, asRepr(VAR(co->consts))); + consts << CAST(Str&, asRepr(VAR(co->consts))); - StrStream names; + std::stringstream names; names << "co_names: "; List list; for(int i=0; inames.size(); i++){ - list.push_back(VAR(co->names[i].str())); + list.push_back(VAR(co->names[i].sv())); } names << CAST(Str, asRepr(VAR(list))); ss << '\n' << consts.str() << '\n' << names.str(); #endif for(auto& decl: co->func_decls){ - ss << "\n\n" << "Disassembly of " << decl->name.str() << ":\n"; + ss << "\n\n" << "Disassembly of " << decl->name << ":\n"; ss << disassemble(decl->code); } return Str(ss.str()); @@ -733,7 +719,7 @@ inline PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, boo locals->set(name, args[i++]); continue; } - TypeError("missing positional argument " + name.str().escape(true)); + TypeError(fmt("missing positional argument ", name.escape())); } locals->update(fn.decl->kwargs); @@ -756,7 +742,7 @@ inline PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, boo for(int i=0; ikwargs.contains(key)){ - TypeError(key.escape(true) + " is an invalid keyword argument for " + fn.decl->name.str() + "()"); + TypeError(fmt(key.escape(), " is an invalid keyword argument for ", fn.decl->name, "()")); } locals->set(key, kwargs[i+1]); } @@ -774,7 +760,7 @@ inline PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, boo args.extend_self(self); return call(call_f, std::move(args), kwargs, false); } - TypeError(OBJ_NAME(_t(callable)).escape(true) + " object is not callable"); + TypeError(OBJ_NAME(_t(callable)).escape() + " object is not callable"); return None; } @@ -880,7 +866,7 @@ inline void VM::setattr(PyObject* obj, StrName name, T&& value){ if(descr_set != nullptr){ call(descr_set, Args{cls_var, obj, std::forward(value)}); }else{ - TypeError("readonly attribute: " + name.str().escape(true)); + TypeError(fmt("readonly attribute: ", name.escape())); } return; }