diff --git a/src/pocketpy.h b/src/pocketpy.h index e4736b8d..21a157d1 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -301,14 +301,12 @@ void __initializeBuiltinFunctions(VM* _vm) { _vm->bindMethod("str", "__repr__", [](VM* vm, PyVarList args) { const _Str& _self = vm->PyStr_AS_C(args[0]); - // we just do a simple repr here, no escaping - return vm->PyStr("'" + _self.str() + "'"); + return vm->PyStr("'" + _self.__escape(true).str() + "'"); }); _vm->bindMethod("str", "__json__", [](VM* vm, PyVarList args) { const _Str& _self = vm->PyStr_AS_C(args[0]); - // we just do a simple repr here, no escaping - return vm->PyStr('"' + _self.str() + '"'); + return vm->PyStr("\"" + _self.__escape(false) + "\""); }); _vm->bindMethod("str", "__eq__", [](VM* vm, PyVarList args) { diff --git a/src/str.h b/src/str.h index ced560b7..4cd1b9e8 100644 --- a/src/str.h +++ b/src/str.h @@ -135,6 +135,34 @@ public: })); return _Str(copy); } + + _Str __escape(bool single_quote) const { + _StrStream ss; + for (auto c = _s.cbegin(); c != _s.cend(); c++) { + switch (*c) { + case '"': + if(!single_quote) ss << '\\'; + ss << '"'; + break; + case '\'': + if(single_quote) ss << '\\'; + ss << '\''; + break; + case '\\': ss << '\\' << '\\'; break; + case '\n': ss << "\\n"; break; + 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 { + ss << *c; + } + } + } + return ss.str(); + } };