diff --git a/src/obj.h b/src/obj.h index 5d896059..2dbd7e3e 100644 --- a/src/obj.h +++ b/src/obj.h @@ -57,6 +57,13 @@ struct Range { i64 step = 1; }; +struct Bytes{ + std::string _data; + + int size() const noexcept { return _data.size(); } + int operator[](int i) const noexcept { return (int)(uint8_t)_data[i]; } +}; + using Super = std::pair; // TODO: re-examine the design of Slice diff --git a/src/pocketpy.h b/src/pocketpy.h index 555e332e..6bd1bf44 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -412,6 +412,11 @@ inline void init_builtins(VM* _vm) { return VAR(ok); }); + _vm->bind_method<0>("str", "encode", [](VM* vm, ArgsView args) { + const Str& self = CAST(Str&, args[0]); + return VAR(Bytes{self.str()}); + }); + _vm->bind_method<1>("str", "join", [](VM* vm, ArgsView args) { const Str& self = CAST(Str&, args[0]); FastStrStream ss; @@ -551,7 +556,7 @@ inline void init_builtins(VM* _vm) { return VAR(self.size()); }); - /************ PyBool ************/ + /************ bool ************/ _vm->bind_static_method<1>("bool", "__new__", CPP_LAMBDA(VAR(vm->asBool(args[0])))); _vm->bind_method<0>("bool", "__repr__", [](VM* vm, ArgsView args) { @@ -571,6 +576,39 @@ inline void init_builtins(VM* _vm) { }); _vm->bind_method<0>("ellipsis", "__repr__", CPP_LAMBDA(VAR("Ellipsis"))); + + /************ bytes ************/ + _vm->bind_static_method<1>("bytes", "__new__", CPP_NOT_IMPLEMENTED()); + + _vm->bind_method<1>("bytes", "__getitem__", [](VM* vm, ArgsView args) { + const Bytes& self = CAST(Bytes&, args[0]); + int index = CAST(int, args[1]); + index = vm->normalized_index(index, self.size()); + return VAR(self[index]); + }); + + _vm->bind_method<0>("bytes", "__repr__", [](VM* vm, ArgsView args) { + const Bytes& self = CAST(Bytes&, args[0]); + std::stringstream ss; + ss << "b'"; + for(int i=0; ibind_method<0>("bytes", "__len__", [](VM* vm, ArgsView args) { + const Bytes& self = CAST(Bytes&, args[0]); + return VAR(self.size()); + }); + + _vm->bind_method<0>("bytes", "decode", [](VM* vm, ArgsView args) { + const Bytes& self = CAST(Bytes&, args[0]); + // TODO: check encoding is utf-8 + return VAR(Str(self._data)); + }); + } #ifdef _WIN32 diff --git a/src/str.h b/src/str.h index 2232c86d..a384ab8a 100644 --- a/src/str.h +++ b/src/str.h @@ -207,11 +207,10 @@ struct Str{ case '\r': ss << "\\r"; break; case '\t': ss << "\\t"; break; default: - if ('\x00' <= c && c <= '\x1f') { - ss << "\\u" - << std::hex << std::setw(4) << std::setfill('0') << static_cast(c); - } else { + if (c >= 32 && c <= 126) { ss << c; + } else { + ss << "\\x" << std::hex << std::setw(2) << std::setfill('0') << (int)(uint8_t)c; } } } diff --git a/src/vm.h b/src/vm.h index 1a4b2d8a..a79499bf 100644 --- a/src/vm.h +++ b/src/vm.h @@ -102,7 +102,7 @@ public: Type tp_list, tp_tuple; Type tp_function, tp_native_func, tp_iterator, tp_bound_method; Type tp_slice, tp_range, tp_module; - Type tp_super, tp_exception; + Type tp_super, tp_exception, tp_bytes; VM(bool use_stdio) : heap(this){ this->vm = this; @@ -412,6 +412,7 @@ DEF_NATIVE_2(BoundMethod, tp_bound_method) DEF_NATIVE_2(Range, tp_range) DEF_NATIVE_2(Slice, tp_slice) DEF_NATIVE_2(Exception, tp_exception) +DEF_NATIVE_2(Bytes, tp_bytes) #define PY_CAST_INT(T) \ template<> inline T py_cast(VM* vm, PyObject* obj){ \ @@ -737,6 +738,7 @@ inline void VM::init_builtin_types(){ tp_bound_method = _new_type_object("bound_method"); tp_super = _new_type_object("super"); tp_exception = _new_type_object("Exception"); + tp_bytes = _new_type_object("bytes"); this->None = heap._new(_new_type_object("NoneType"), {}); this->Ellipsis = heap._new(_new_type_object("ellipsis"), {}); @@ -757,6 +759,7 @@ inline void VM::init_builtin_types(){ builtins->attr().set("list", _t(tp_list)); builtins->attr().set("tuple", _t(tp_tuple)); builtins->attr().set("range", _t(tp_range)); + builtins->attr().set("bytes", _t(tp_bytes)); builtins->attr().set("StopIteration", StopIteration); post_init();