master
ブランチ master
LibJson / src / json.cc
9.5 KB、379行 生 Blame 履歴
1/*
2# 076 Free License
3
4Copyright (c) テクニカル諏訪子
5
6Permission is hereby granted to any person obtaining a copy of the software
7LibJson (the "Software") to use, modify, merge, copy, publish, distribute,
8sublicense, and/or sell copies of the Software, subject to the following conditions:
9
10 1. **Origin Attribution**:
11 - You must not misrepresent the origin of the Software; you must not claim
12 you created the original Software.
13 2. **Notice Preservation**:
14 - This license and the above copyright notice must remain intact in all copies
15 of the source code.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
18INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
19PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
22OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23*/
24#include <suwa/json.hh>
25#include <charconv>
26#include <utility>
27#include <cassert>
28#include <sstream>
29
30namespace 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 // 公開API
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} // namespace json