| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | #include <suwa/json.hh> |
| 25 | #include <charconv> |
| 26 | #include <utility> |
| 27 | #include <cassert> |
| 28 | #include <sstream> |
| 29 | |
| 30 | namespace json { |
| 31 | ParseResult Parser::make_error(Error err) const { |
| 32 | return { std::make_unique<Value>(), err, m_Pos }; |
| 33 | } |
| 34 | |
| 35 | void Parser::skip_whitespace() { |
| 36 | while (m_Pos < m_Text.size()) { |
| 37 | char c = m_Text[m_Pos]; |
| 38 | if (c != ' ' && c != '\t' && c != '\n' && c != '\r') break; |
| 39 | ++m_Pos; |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | char Parser::peek() const { |
| 44 | return m_Pos < m_Text.size() ? m_Text[m_Pos] : '\0'; |
| 45 | } |
| 46 | |
| 47 | char Parser::consume() { |
| 48 | return m_Pos < m_Text.size() ? m_Text[m_Pos++] : '\0'; |
| 49 | } |
| 50 | |
| 51 | bool Parser::expect(char c) { |
| 52 | if (peek() == c) { |
| 53 | consume(); |
| 54 | return true; |
| 55 | } |
| 56 | |
| 57 | return false; |
| 58 | } |
| 59 | |
| 60 | ParseResult Parser::parse_value() { |
| 61 | skip_whitespace(); |
| 62 | if (m_Pos >= m_Text.size()) return make_error(Error::UnexpectedEnd); |
| 63 | |
| 64 | char c = peek(); |
| 65 | if (c == '{') return parse_object(); |
| 66 | if (c == '[') return parse_array(); |
| 67 | if (c == '"') { |
| 68 | auto str = parse_string(); |
| 69 | if (!str.ok()) return str; |
| 70 | return str; |
| 71 | } |
| 72 | |
| 73 | if (m_Text.substr(m_Pos, 4) == "true") { |
| 74 | m_Pos += 4; |
| 75 | return { std::make_unique<Value>(true) }; |
| 76 | } |
| 77 | |
| 78 | if (m_Text.substr(m_Pos, 5) == "false") { |
| 79 | m_Pos += 5; |
| 80 | return { std::make_unique<Value>(false) }; |
| 81 | } |
| 82 | |
| 83 | if (m_Text.substr(m_Pos, 4) == "null") { |
| 84 | m_Pos += 4; |
| 85 | return { std::make_unique<Value>(nullptr) }; |
| 86 | } |
| 87 | |
| 88 | if ((c >= '0' && c <= '9') || c == '-' || c == '+') { |
| 89 | auto num = parse_number(); |
| 90 | if (num) return { std::make_unique<Value>(*num) }; |
| 91 | return make_error(Error::InvalidNumber); |
| 92 | } |
| 93 | |
| 94 | return make_error(Error::InvalidValue); |
| 95 | } |
| 96 | |
| 97 | ParseResult Parser::parse_object() { |
| 98 | if (!expect('{')) return make_error(Error::SyntaxError); |
| 99 | |
| 100 | Object obj; |
| 101 | skip_whitespace(); |
| 102 | |
| 103 | if (peek() == '}') { |
| 104 | consume(); |
| 105 | return { std::make_unique<Value>(std::move(obj)) }; |
| 106 | } |
| 107 | |
| 108 | while (true) { |
| 109 | skip_whitespace(); |
| 110 | auto keyres = parse_string(); |
| 111 | if (!keyres.ok()) return keyres; |
| 112 | |
| 113 | skip_whitespace(); |
| 114 | if (!expect(':')) return make_error(Error::SyntaxError); |
| 115 | |
| 116 | auto valres = parse_value(); |
| 117 | if (!valres.ok()) return valres; |
| 118 | |
| 119 | obj.insert( |
| 120 | std::move(keyres.value->as_string()), |
| 121 | std::move(*valres.value) |
| 122 | ); |
| 123 | |
| 124 | skip_whitespace(); |
| 125 | if (peek() == '}') { |
| 126 | consume(); |
| 127 | break; |
| 128 | } |
| 129 | if (!expect(',')) return make_error(Error::SyntaxError); |
| 130 | } |
| 131 | |
| 132 | return { std::make_unique<Value>(std::move(obj)) }; |
| 133 | } |
| 134 | |
| 135 | ParseResult Parser::parse_array() { |
| 136 | if (!expect('[')) return make_error(Error::SyntaxError); |
| 137 | |
| 138 | Value::Array arr; |
| 139 | skip_whitespace(); |
| 140 | |
| 141 | if (peek() == ']') { |
| 142 | consume(); |
| 143 | return { std::make_unique<Value>(std::move(arr)) }; |
| 144 | } |
| 145 | |
| 146 | while (true) { |
| 147 | auto valres = parse_value(); |
| 148 | if (!valres.ok()) return valres; |
| 149 | arr.push_back(std::move(*valres.value)); |
| 150 | |
| 151 | skip_whitespace(); |
| 152 | if (peek() == ']') { |
| 153 | consume(); |
| 154 | break; |
| 155 | } |
| 156 | if (!expect(',')) return make_error(Error::SyntaxError); |
| 157 | } |
| 158 | |
| 159 | return { std::make_unique<Value>(std::move(arr)) }; |
| 160 | } |
| 161 | |
| 162 | ParseResult Parser::parse_string() { |
| 163 | if (!expect('"')) return make_error(Error::SyntaxError); |
| 164 | |
| 165 | string res; |
| 166 | res.reserve(32); |
| 167 | |
| 168 | while (m_Pos < m_Text.size()) { |
| 169 | char c = consume(); |
| 170 | if (c == '"') return { std::make_unique<Value>(std::move(res)) }; |
| 171 | if (c == '\\') { |
| 172 | if (m_Pos >= m_Text.size()) make_error(Error::UnterminatedString); |
| 173 | char esc = consume(); |
| 174 | switch (esc) { |
| 175 | case '"': res += '"'; break; |
| 176 | case '\\': res += '\\'; break; |
| 177 | case '/': res += '/'; break; |
| 178 | case 'b': res += '\b'; break; |
| 179 | case 'f': res += '\f'; break; |
| 180 | case 'n': res += '\n'; break; |
| 181 | case 'r': res += '\r'; break; |
| 182 | case 't': res += '\t'; break; |
| 183 | case 'u': { |
| 184 | for (int i = 0; i < 4; ++i) { |
| 185 | if (m_Pos >= m_Text.size()) |
| 186 | return make_error(Error::UnterminatedString); |
| 187 | |
| 188 | char h = consume(); |
| 189 | |
| 190 | if (!std::isxdigit((unsigned char)h)) |
| 191 | return make_error(Error::SyntaxError); |
| 192 | } |
| 193 | |
| 194 | break; |
| 195 | } |
| 196 | default: return make_error(Error::SyntaxError); |
| 197 | } |
| 198 | } else { |
| 199 | res += c; |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | return make_error(Error::UnterminatedString); |
| 204 | } |
| 205 | |
| 206 | std::optional<f64> Parser::parse_number() { |
| 207 | cstr start = m_Text.data() + m_Pos; |
| 208 | f64 num = 0.0; |
| 209 | char *end = nullptr; |
| 210 | num = std::strtod(start, &end); |
| 211 | |
| 212 | if (end == start) return std::nullopt; |
| 213 | |
| 214 | m_Pos += (end - start); |
| 215 | return num; |
| 216 | } |
| 217 | |
| 218 | |
| 219 | ParseResult Value::parse(std::string_view jsonText) { |
| 220 | Parser p(jsonText); |
| 221 | return p.parse(); |
| 222 | } |
| 223 | |
| 224 | ParseResult Parser::parse() { |
| 225 | skip_whitespace(); |
| 226 | ParseResult res = parse_value(); |
| 227 | if (!res.ok()) return res; |
| 228 | |
| 229 | skip_whitespace(); |
| 230 | if (m_Pos < m_Text.size()) { |
| 231 | assert(false && "JSON値の後でデータがある"); |
| 232 | } |
| 233 | |
| 234 | return res; |
| 235 | } |
| 236 | |
| 237 | string Value::serialize(const SerializeOptions &opts) const { |
| 238 | return serialize_impl(opts, 0); |
| 239 | } |
| 240 | |
| 241 | string Value::serialize_impl(const SerializeOptions &opts, size_t depth) const { |
| 242 | if (is_null()) return "null"; |
| 243 | if (is_bool()) return as_bool() ? "true" : "false"; |
| 244 | if (is_number()) { |
| 245 | std::ostringstream oss; |
| 246 | oss << as_number(); |
| 247 | return oss.str(); |
| 248 | } |
| 249 | if (is_string()) |
| 250 | return serialize_string(as_string()); |
| 251 | |
| 252 | if (is_array()) { |
| 253 | const auto &arr = as_array(); |
| 254 | |
| 255 | string out = "["; |
| 256 | if (opts.pretty && !arr.empty()) |
| 257 | out += "\n"; |
| 258 | |
| 259 | for (size_t i = 0; i < arr.size(); ++i) { |
| 260 | if (opts.pretty) |
| 261 | out += make_indent(depth + 1, opts.indent); |
| 262 | |
| 263 | out += arr[i].serialize_impl(opts, depth + 1); |
| 264 | |
| 265 | if (i + 1 < arr.size()) |
| 266 | out += ","; |
| 267 | |
| 268 | if (opts.pretty) |
| 269 | out += "\n"; |
| 270 | } |
| 271 | |
| 272 | if (opts.pretty && !arr.empty()) |
| 273 | out += make_indent(depth, opts.indent); |
| 274 | |
| 275 | out += "]"; |
| 276 | return out; |
| 277 | } |
| 278 | |
| 279 | if (is_object()) { |
| 280 | const auto &obj = as_object(); |
| 281 | |
| 282 | string out = "{"; |
| 283 | |
| 284 | if (opts.pretty && !obj.empty()) |
| 285 | out += "\n"; |
| 286 | |
| 287 | size_t i = 0; |
| 288 | for (const auto &[key, val] : obj) { |
| 289 | if (opts.pretty) |
| 290 | out += make_indent(depth + 1, opts.indent); |
| 291 | |
| 292 | out += serialize_string(key); |
| 293 | out += opts.pretty ? ": " : ":"; |
| 294 | out += val->serialize_impl(opts, depth + 1); |
| 295 | |
| 296 | if (++i < obj.size()) |
| 297 | out += ","; |
| 298 | |
| 299 | if (opts.pretty) |
| 300 | out += "\n"; |
| 301 | } |
| 302 | |
| 303 | if (opts.pretty && !obj.empty()) |
| 304 | out += make_indent(depth, opts.indent); |
| 305 | |
| 306 | out += "}"; |
| 307 | return out; |
| 308 | } |
| 309 | |
| 310 | return "null"; |
| 311 | } |
| 312 | |
| 313 | string Value::make_indent(size_t depth, size_t width) { |
| 314 | return string(depth * width, ' '); |
| 315 | } |
| 316 | |
| 317 | string Value::serialize_string(const string &s) { |
| 318 | string out = "\""; |
| 319 | |
| 320 | for (char c : s) { |
| 321 | switch (c) { |
| 322 | case '"': out += "\\\""; break; |
| 323 | case '\\': out += "\\\\"; break; |
| 324 | case '\b': out += "\\b"; break; |
| 325 | case '\f': out += "\\f"; break; |
| 326 | case '\n': out += "\\n"; break; |
| 327 | case '\r': out += "\\r"; break; |
| 328 | case '\t': out += "\\t"; break; |
| 329 | default: out += c; break; |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | out += "\""; |
| 334 | return out; |
| 335 | } |
| 336 | |
| 337 | void Object::insert(string key, Value value) { |
| 338 | auto ptr = std::make_unique<Value>(std::move(value)); |
| 339 | |
| 340 | auto it = m_Index.find(key); |
| 341 | if (it != m_Index.end()) { |
| 342 | m_Data[it->second].second = std::move(ptr); |
| 343 | } else { |
| 344 | m_Index[key] = m_Data.size(); |
| 345 | m_Data.emplace_back(std::move(key), std::move(ptr)); |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | Value *Object::get(std::string_view key) { |
| 350 | auto it = m_Index.find(key); |
| 351 | return it != m_Index.end() ? m_Data[it->second].second.get() : nullptr; |
| 352 | } |
| 353 | |
| 354 | const Value *Object::get(std::string_view key) const { |
| 355 | auto it = m_Index.find(key); |
| 356 | return it != m_Index.end() ? m_Data[it->second].second.get() : nullptr; |
| 357 | } |
| 358 | |
| 359 | bool Object::contains(std::string_view key) const { |
| 360 | return m_Index.contains(key); |
| 361 | } |
| 362 | |
| 363 | |
| 364 | |
| 365 | std::optional<bool> Value::get_bool() const { |
| 366 | if (auto *b = std::get_if<bool>(&m_Value)) return *b; |
| 367 | return std::nullopt; |
| 368 | } |
| 369 | |
| 370 | std::optional<f64> Value::get_number() const { |
| 371 | if (auto *b = std::get_if<f64>(&m_Value)) return *b; |
| 372 | return std::nullopt; |
| 373 | } |
| 374 | |
| 375 | std::optional<string> Value::get_string() const { |
| 376 | if (auto *b = std::get_if<string>(&m_Value)) return *b; |
| 377 | return std::nullopt; |
| 378 | } |
| 379 | } |