バグの修正
諏訪子 <suwako@076.moe>、2026-06-30 02:46
コミット 1f5a4bfaa729db76cba37c86927482f34d75398f
・親 87be4c0
・ファイルを見る
4個のファイル、+114 -45
| @@ -69,6 +69,9 @@ | ||
| 69 | 69 | public: |
| 70 | 70 | Object() = default; |
| 71 | 71 | |
| 72 | + Value &operator[](std::string_view key); | |
| 73 | + const Value &operator[](std::string_view key) const; | |
| 74 | + | |
| 72 | 75 | void insert(string key, Value value); |
| 73 | 76 | Value *get(std::string_view key); |
| 74 | 77 | const Value *get(std::string_view key) const; |
| @@ -102,6 +105,27 @@ | ||
| 102 | 105 | Object |
| 103 | 106 | >; |
| 104 | 107 | |
| 108 | + // 配列 | |
| 109 | + Value &operator[](size_t index) { | |
| 110 | + if (!is_array()) as_array() = Array{}; | |
| 111 | + | |
| 112 | + auto &arr = as_array(); | |
| 113 | + if (index >= arr.size()) arr.resize(index + 1); | |
| 114 | + return arr[index]; | |
| 115 | + } | |
| 116 | + | |
| 117 | + // オブジェクト | |
| 118 | + Value &operator[](std::string_view key) { | |
| 119 | + if (!is_object()) as_object() = Object{}; | |
| 120 | + | |
| 121 | + auto *val = as_object().get(key); | |
| 122 | + if (!val) { | |
| 123 | + as_object().insert(string(key), Value{}); | |
| 124 | + val = as_object().get(key); | |
| 125 | + } | |
| 126 | + return *val; | |
| 127 | + } | |
| 128 | + | |
| 105 | 129 | public: |
| 106 | 130 | Value() = default; |
| 107 | 131 | Value(std::nullptr_t) : m_Value(std::monostate{}) {} |
| @@ -140,9 +164,6 @@ | ||
| 140 | 164 | std::optional<f64> get_number() const; |
| 141 | 165 | std::optional<string> get_string() const; |
| 142 | 166 | |
| 143 | - Value &operator[](size_t index); // 配列 | |
| 144 | - Value &operator[](std::string_view); // オブジェクト | |
| 145 | - | |
| 146 | 167 | public: |
| 147 | 168 | static ParseResult parse(std::string_view jsonText); |
| 148 | 169 | |
| @@ -181,9 +202,22 @@ | ||
| 181 | 202 | ParseResult parse_value(); |
| 182 | 203 | ParseResult parse_object(); |
| 183 | 204 | ParseResult parse_array(); |
| 184 | - std::optional<string> parse_string(); | |
| 205 | + ParseResult parse_string(); | |
| 185 | 206 | std::optional<f64> parse_number(); |
| 186 | 207 | }; // class Parser |
| 187 | 208 | } // namespace json |
| 209 | + | |
| 210 | +inline std::ostream &operator<<(std::ostream &os, const json::Value &v) { | |
| 211 | + os << v.serialize(); | |
| 212 | + return os; | |
| 213 | +} | |
| 214 | + | |
| 215 | +inline json::Value &json::Object::operator[](std::string_view key) { | |
| 216 | + return *get(key); | |
| 217 | +} | |
| 218 | + | |
| 219 | +inline const json::Value &json::Object::operator[](std::string_view key) const { | |
| 220 | + return *get(key); | |
| 221 | +} | |
| 188 | 222 | |
| 189 | 223 | #endif // JSON_HH |
変更
src/file.cc
| @@ -27,9 +27,9 @@ | ||
| 27 | 27 | #include <fstream> |
| 28 | 28 | |
| 29 | 29 | vector<u8> read_file(const string &filename, bool binary) { |
| 30 | - std::ios::openmode flags = std::ios::in | std::ios::ate; | |
| 31 | - //if (binary) flags |= std::ios::binary; | |
| 32 | - flags |= std::ios::binary; | |
| 30 | + std::ios::openmode flags = std::ios::in | |
| 31 | + | std::ios::ate | |
| 32 | + | std::ios::binary; | |
| 33 | 33 | |
| 34 | 34 | std::ifstream file(filename, flags); |
| 35 | 35 | if (!file) { |
変更
src/json.cc
| @@ -67,8 +67,8 @@ | ||
| 67 | 67 | if (c == '[') return parse_array(); |
| 68 | 68 | if (c == '"') { |
| 69 | 69 | auto str = parse_string(); |
| 70 | - if (!str) return make_error(Error::UnterminatedString); | |
| 71 | - return { std::make_unique<Value>(std::move(*str)) }; | |
| 70 | + if (!str.ok()) return str; | |
| 71 | + return str; | |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | 74 | if (m_Text.substr(m_Pos, 4) == "true") { |
| @@ -108,8 +108,8 @@ | ||
| 108 | 108 | |
| 109 | 109 | while (true) { |
| 110 | 110 | skip_whitespace(); |
| 111 | - auto keyopt = parse_string(); | |
| 112 | - if (!keyopt) return make_error(Error::SyntaxError); | |
| 111 | + auto keyres = parse_string(); | |
| 112 | + if (!keyres.ok()) return keyres; | |
| 113 | 113 | |
| 114 | 114 | skip_whitespace(); |
| 115 | 115 | if (!expect(':')) return make_error(Error::SyntaxError); |
| @@ -117,7 +117,10 @@ | ||
| 117 | 117 | auto valres = parse_value(); |
| 118 | 118 | if (!valres.ok()) return valres; |
| 119 | 119 | |
| 120 | - obj.insert(std::move(*keyopt), std::move(*valres.value)); | |
| 120 | + obj.insert( | |
| 121 | + std::move(keyres.value->as_string()), | |
| 122 | + std::move(*valres.value) | |
| 123 | + ); | |
| 121 | 124 | |
| 122 | 125 | skip_whitespace(); |
| 123 | 126 | if (peek() == '}') { |
| @@ -157,17 +160,17 @@ | ||
| 157 | 160 | return { std::make_unique<Value>(std::move(arr)) }; |
| 158 | 161 | } |
| 159 | 162 | |
| 160 | - std::optional<string> Parser::parse_string() { | |
| 161 | - if (!expect('"')) return std::nullopt; | |
| 163 | + ParseResult Parser::parse_string() { | |
| 164 | + if (!expect('"')) return make_error(Error::SyntaxError); | |
| 162 | 165 | |
| 163 | 166 | string res; |
| 164 | 167 | res.reserve(32); |
| 165 | 168 | |
| 166 | 169 | while (m_Pos < m_Text.size()) { |
| 167 | 170 | char c = consume(); |
| 168 | - if (c == '"') return res; | |
| 171 | + if (c == '"') return { std::make_unique<Value>(std::move(res)) }; | |
| 169 | 172 | if (c == '\\') { |
| 170 | - if (m_Pos >= m_Text.size()) return std::nullopt; | |
| 173 | + if (m_Pos >= m_Text.size()) make_error(Error::UnterminatedString); | |
| 171 | 174 | char esc = consume(); |
| 172 | 175 | switch (esc) { |
| 173 | 176 | case '"': res += '"'; break; |
| @@ -178,14 +181,27 @@ | ||
| 178 | 181 | case 'n': res += '\n'; break; |
| 179 | 182 | case 'r': res += '\r'; break; |
| 180 | 183 | case 't': res += '\t'; break; |
| 181 | - default: res += esc; | |
| 184 | + case 'u': { | |
| 185 | + for (int i = 0; i < 4; ++i) { | |
| 186 | + if (m_Pos >= m_Text.size()) | |
| 187 | + return make_error(Error::UnterminatedString); | |
| 188 | + | |
| 189 | + char h = consume(); | |
| 190 | + | |
| 191 | + if (!std::isxdigit((unsigned char)h)) | |
| 192 | + return make_error(Error::SyntaxError); | |
| 193 | + } | |
| 194 | + | |
| 195 | + break; | |
| 196 | + } | |
| 197 | + default: return make_error(Error::SyntaxError); | |
| 182 | 198 | } |
| 183 | 199 | } else { |
| 184 | 200 | res += c; |
| 185 | 201 | } |
| 186 | 202 | } |
| 187 | 203 | |
| 188 | - return std::nullopt; | |
| 204 | + return make_error(Error::UnterminatedString); | |
| 189 | 205 | } |
| 190 | 206 | |
| 191 | 207 | std::optional<f64> Parser::parse_number() { |
| @@ -365,24 +381,5 @@ | ||
| 365 | 381 | std::optional<string> Value::get_string() const { |
| 366 | 382 | if (auto *b = std::get_if<string>(&m_Value)) return *b; |
| 367 | 383 | return std::nullopt; |
| 368 | - } | |
| 369 | - | |
| 370 | - Value &Value::operator[](size_t index) { | |
| 371 | - if (!is_array()) as_array() = Array{}; | |
| 372 | - | |
| 373 | - auto &arr = as_array(); | |
| 374 | - if (index >= arr.size()) arr.resize(index + 1); | |
| 375 | - return arr[index]; | |
| 376 | - } | |
| 377 | - | |
| 378 | - Value &Value::operator[](std::string_view key) { | |
| 379 | - if (!is_object()) as_object() = Object{}; | |
| 380 | - | |
| 381 | - auto *val = as_object().get(key); | |
| 382 | - if (!val) { | |
| 383 | - as_object().insert(string(key), Value{}); | |
| 384 | - val = as_object().get(key); | |
| 385 | - } | |
| 386 | - return *val; | |
| 387 | 384 | } |
| 388 | 385 | } // namespace json |
| @@ -23,6 +23,8 @@ | ||
| 23 | 23 | assert(res.value->is_object()); |
| 24 | 24 | |
| 25 | 25 | auto &root = res.value->as_object(); |
| 26 | + std::cout << root["name"] << std::endl; | |
| 27 | + assert(root.contains("kero")); | |
| 26 | 28 | assert(root.get("name")->as_string() == "諏訪子"); |
| 27 | 29 | assert(root.get("kero")->as_string() == "🐸"); |
| 28 | 30 | assert(root.get("age")->as_number() == 2300); |
| @@ -265,15 +267,51 @@ | ||
| 265 | 267 | std::cout << "ActivityPub OK" << std::endl; |
| 266 | 268 | } |
| 267 | 269 | |
| 268 | - //{ | |
| 269 | - // const string src = R"({ | |
| 270 | - // "a": [,,,])"; | |
| 270 | + { | |
| 271 | + { | |
| 272 | + const string src = R"({ | |
| 273 | + "a": [,,,])"; | |
| 274 | + auto res = json::Parser(src).parse(); | |
| 275 | + assert(res.error == json::Error::InvalidValue); | |
| 276 | + } | |
| 277 | + { | |
| 278 | + const string src = R"({"x":"\q"})"; | |
| 279 | + auto res = json::Parser(src).parse(); | |
| 280 | + assert(res.error == json::Error::SyntaxError); | |
| 281 | + } | |
| 282 | + { | |
| 283 | + const string src = R"({"x":1.2345g})"; | |
| 284 | + auto res = json::Parser(src).parse(); | |
| 285 | + assert(res.error == json::Error::SyntaxError); | |
| 286 | + } | |
| 287 | + { | |
| 288 | + const string src = R"({"x":"suwa})"; | |
| 289 | + auto res = json::Parser(src).parse(); | |
| 290 | + assert(res.error == json::Error::UnterminatedString); | |
| 291 | + } | |
| 292 | + { | |
| 293 | + const string src = R"({"x":tru})"; | |
| 294 | + auto res = json::Parser(src).parse(); | |
| 295 | + assert(res.error == json::Error::InvalidValue); | |
| 296 | + } | |
| 297 | + { | |
| 298 | + const string src = R"([[[[[[[[[[[]]]]]]]]]]])"; | |
| 299 | + auto res = json::Parser(src).parse(); | |
| 300 | + assert(res.error == json::Error::None); | |
| 301 | + } | |
| 302 | + { | |
| 303 | + const string src = R"([[[[[[[[[[[[]]]]]]]]]]])"; | |
| 304 | + auto res = json::Parser(src).parse(); | |
| 305 | + assert(res.error == json::Error::SyntaxError); | |
| 306 | + } | |
| 307 | + { | |
| 308 | + const string src = R"({"x":"\uXXXX"})"; | |
| 309 | + auto res = json::Parser(src).parse(); | |
| 310 | + assert(res.error == json::Error::SyntaxError); | |
| 311 | + } | |
| 271 | 312 | |
| 272 | - // auto res = json::Parser(src).parse(); | |
| 273 | - // assert(res.error == json::Error::SyntaxError); | |
| 274 | - | |
| 275 | - // std::cout << "Bad OK" << std::endl; | |
| 276 | - //} | |
| 313 | + std::cout << "Bad OK" << std::endl; | |
| 314 | + } | |
| 277 | 315 | |
| 278 | 316 | return 0; |
| 279 | 317 | } |