1 // =================================
  2 // Copyright (c) 2024 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Collections;
  8 using System.Text;
  9 
 10 namespace System.Json
 11 {
 12     public abstract class JsonValue
 13     {
 14         public JsonValue()
 15         {
 16         }
 17         public virtual default ~JsonValue();
 18         [nodiscard]
 19         public abstract Result<string> ToString() const;
 20         [nodiscard]
 21         public virtual Result<bool> Write(CodeFormatter& formatter)
 22         {
 23             Result<string> toStringResult = ToString();
 24             if (toStringResult.Error())
 25             {
 26                 return Result<bool>(ErrorId(toStringResult.GetErrorId()));
 27             }
 28             auto result = formatter.Write(toStringResult.Value());
 29             if (result.Error()) return result;
 30             return Result<bool>(true);
 31         }
 32     }
 33 
 34     public class JsonNull : JsonValue
 35     {
 36         public JsonNull() : base()
 37         {
 38         }
 39         public override Result<string> ToString() const
 40         {
 41             return Result<string>("null");
 42         }
 43     }
 44 
 45     public class JsonNumber : JsonValue
 46     {
 47         public JsonNumber() : base()value(0.000000)
 48         {
 49         }
 50         public explicit JsonNumber(double value_) : value(value_)
 51         {
 52         }
 53         public override Result<string> ToString() const
 54         {
 55             if (value == cast<long>(value))
 56             {
 57                 long x = cast<long>(value);
 58                 return Result<string>(System.ToString(x));
 59             }
 60             return Result<string>(System.ToString(value));
 61         }
 62         public inline double Value() const
 63         {
 64             return value;
 65         }
 66         public inline void SetValue(double value_)
 67         {
 68             value = value_;
 69         }
 70         private double value;
 71     }
 72 
 73     public class JsonBool : JsonValue
 74     {
 75         public JsonBool() : base()value(false)
 76         {
 77         }
 78         public explicit JsonBool(bool value_) : base()value(value_)
 79         {
 80         }
 81         public override Result<string> ToString() const
 82         {
 83             return Result<string>(System.ToString(value));
 84         }
 85         public inline bool Value() const
 86         {
 87             return value;
 88         }
 89         public inline void SetValue(bool value_)
 90         {
 91             value = value_;
 92         }
 93         private bool value;
 94     }
 95 
 96     public class JsonString : JsonValue
 97     {
 98         public JsonString() : base()value()
 99         {
100         }
101         public JsonString(const ustring& value_) : base()value(value_)
102         {
103         }
104         public inline const ustring& Value() const
105         {
106             return value;
107         }
108         public inline void SetValue(const ustring& value_)
109         {
110             value = value_;
111         }
112         public JsonString& Append(uchar c)
113         {
114             value.Append(c);
115             return *this;
116         }
117         public JsonString& Append(const uchar* s)
118         {
119             value.Append(s);
120             return *this;
121         }
122         public JsonString& Append(const ustring& s)
123         {
124             value.Append(s);
125             return *this;
126         }
127         public override Result<string> ToString() const
128         {
129             wstring s = w'\"';
130             for (uchar c : value)
131             {
132                 auto jsonCharStrResult = JsonCharStr(c);
133                 if (jsonCharStrResult.Error()) return Result<string>(ErrorId(jsonCharStrResult.GetErrorId()));
134                 s.Append(Rvalue(jsonCharStrResult.Value()));
135             }
136             s.Append(w'\"');
137             auto result = ToUtf8(s);
138             if (result.Error()) return Result<string>(ErrorId(result.GetErrorId()));
139             return Result<string>(Rvalue(result.Value()));
140         }
141         private Result<wstring> JsonCharStr(uchar c)
142         {
143             wstring result;
144             ustring s(c);
145             auto utf16result = ToUtf16(s);
146             if (utf16result.Error()) return Result<wstring>(ErrorId(utf16result.GetErrorId()));
147             wstring t = utf16result.Value();
148             for (wchar x : t)
149             {
150                 switch (x)
151                 {
152                     case '\"':result.Append(w"\\\""); break;
153                     case '\\': result.Append(w"\\\\"); break;
154                     case '\b': result.Append(w"\\b"); break;
155                     case '\f': result.Append(w"\\f"); break;
156                     case '\n': result.Append(w"\\n"); break;
157                     case '\r': result.Append(w"\\r"); break;
158                     case '\t': result.Append(w"\\t"); break;
159                     default:
160                     {
161                         if (cast<ushort>(x) >= 32u && cast<ushort>(x) <= 126u)
162                         {
163                             result.Append(x);
164                         }
165                         else
166                         {
167                             auto hexStringResult = ToHexString(cast<ushort>(x));
168                             if (hexStringResult.Error())
169                             {
170                                 return Result<wstring>(ErrorId(hexStringResult.GetErrorId()));
171                             }
172                             auto utf16Result = ToUtf16(hexStringResult.Value());
173                             if (utf16Result.Error())
174                             {
175                                 return Result<wstring>(ErrorId(utf16Result.GetErrorId()));
176                             }
177                             const wstring& s = utf16Result.Value();
178                             result.Append(w"\\u").Append(s);
179                         }
180                         break;
181                     }
182                 }
183             }
184             return Result<wstring>(result);
185         }
186         private ustring value;
187     }
188 
189     public class JsonObject : JsonValue
190     {
191         public JsonObject() : base()fieldValues()fieldMap()
192         {
193         }
194         [nodiscard]
195         public Result<bool> AddField(const string& fieldNameUniquePtr<JsonValue>&& fieldValue)
196         {
197             auto utf32Result = ToUtf32(fieldName);
198             if (utf32Result.Error())
199             {
200                 return Result<bool>(ErrorId(utf32Result.GetErrorId()));
201             }
202             AddField(utf32Result.Value()Rvalue(fieldValue));
203             return Result<bool>(true);
204         }
205         [nodiscard]
206         public Result<bool> AddField(const wstring& fieldNameUniquePtr<JsonValue>&& fieldValue)
207         {
208             auto utf32Result = ToUtf32(fieldName);
209             if (utf32Result.Error())
210             {
211                 return Result<bool>(ErrorId(utf32Result.GetErrorId()));
212             }
213             AddField(utf32Result.Value()Rvalue(fieldValue));
214             return Result<bool>(true);
215         }
216         public void AddField(const ustring& fieldNameUniquePtr<JsonValue>&& fieldValue)
217         {
218             fieldMap[fieldName] = fieldValue.Get();
219             fieldValues.Add(Rvalue(fieldValue));
220         }
221         [nodiscard]
222         public Result<bool> AddField(const string& fieldNameJsonValue* fieldValue)
223         {
224             auto utf32Result = ToUtf32(fieldName);
225             if (utf32Result.Error())
226             {
227                 return Result<bool>(ErrorId(utf32Result.GetErrorId()));
228             }
229             AddField(utf32Result.Value()fieldValue);
230             return Result<bool>(true);
231         }
232         [nodiscard]
233         public Result<bool> AddField(const wstring& fieldNameJsonValue* fieldValue)
234         {
235             auto utf32Result = ToUtf32(fieldName);
236             if (utf32Result.Error())
237             {
238                 return Result<bool>(ErrorId(utf32Result.GetErrorId()));
239             }
240             AddField(utf32Result.Value()fieldValue);
241             return Result<bool>(true);
242         }
243         public void AddField(const ustring& fieldNameJsonValue* fieldValue)
244         {
245             fieldMap[fieldName] = fieldValue;
246             fieldValues.Add(UniquePtr<JsonValue>(fieldValue));
247         }
248         public Result<JsonValue*> GetField(const string& fieldName) const
249         {
250             auto utf32Result = ToUtf32(fieldName);
251             if (utf32Result.Error())
252             {
253                 return Result<JsonValue*>(ErrorId(utf32Result.GetErrorId()));
254             }
255             ustring ufieldName = Rvalue(utf32Result.Value());
256             Result<JsonValue*> fieldValue = GetField(ufieldName);
257             return fieldValue;
258         }
259         public Result<JsonValue*> GetField(const wstring& fieldName) const
260         {
261             auto utf32Result = ToUtf32(fieldName);
262             if (utf32Result.Error())
263             {
264                 return Result<JsonValue*>(ErrorId(utf32Result.GetErrorId()));
265             }
266             ustring ufieldName = Rvalue(utf32Result.Value());
267             Result<JsonValue*> fieldValue = GetField(ufieldName);
268             return fieldValue;
269         }
270         public JsonValue* GetField(const ustring& fieldName) const
271         {
272             auto i = fieldMap.Find(fieldName);
273             if (i != fieldMap.End())
274             {
275                 return i->second;
276             }
277             return null;
278         }
279         public const Map<ustringJsonValue*>& Fields() const
280         {
281             return fieldMap;
282         }
283         public Map<ustringJsonValue*>& Fields()
284         {
285             return fieldMap;
286         }
287         public override Result<string> ToString() const
288         {
289             string s = "{";
290             bool first = true;
291             for (const Pair<ustringJsonValue*>& p : fieldMap)
292             {
293                 JsonString fs = p.first;
294                 JsonValue* fv = p.second;
295                 if (first)
296                 {
297                     first = false;
298                 }
299                 else
300                 {
301                     s.Append(", ");
302                 }
303                 auto fsResult = fs.ToString();
304                 if (fsResult.Error())
305                 {
306                     return Result<string>(ErrorId(fsResult.GetErrorId()));
307                 }
308                 auto fvResult = fv->ToString();
309                 if (fvResult.Error())
310                 {
311                     return Result<string>(ErrorId(fvResult.GetErrorId()));
312                 }
313                 s.Append(fsResult.Value()).Append(":").Append(fvResult.Value());
314             }
315             s.Append("}");
316             return Result<string>(s);
317         }
318         [nodiscard]
319         public override Result<bool> Write(CodeFormatter& formatter)
320         {
321             auto result = formatter.WriteLine("{");
322             if (result.Error()) return result;
323             formatter.IncIndent();
324             bool first = true;
325             bool lastWasArrayOrObject = false;
326             for (const Pair<ustringJsonValue*>& p : fieldMap)
327             {
328                 JsonString s = p.first;
329                 JsonValue* v = p.second;
330                 if (first)
331                 {
332                     first = false;
333                 }
334                 else
335                 {
336                     result = formatter.WriteLine(", ");
337                     if (result.Error()) return result;
338                 }
339                 result = s.Write(formatter);
340                 if (result.Error()) return result;
341                 result = formatter.Write(" : ");
342                 if (result.Error()) return result;
343                 if ((v is JsonArray*) || (v is JsonObject*))
344                 {
345                     result = formatter.WriteLine();
346                     if (result.Error()) return result;
347                     lastWasArrayOrObject = true;
348                 }
349                 else
350                 {
351                     lastWasArrayOrObject = false;
352                 }
353                 result = v->Write(formatter);
354                 if (result.Error()) return result;
355             }
356             formatter.DecIndent();
357             if (!lastWasArrayOrObject)
358             {
359                 auto result = formatter.WriteLine();
360                 if (result.Error()) return result;
361             }
362             result = formatter.WriteLine("}");
363             if (result.Error()) return result;
364             return Result<bool>(true);
365         }
366         private List<UniquePtr<JsonValue>> fieldValues;
367         private Map<ustringJsonValue*> fieldMap;
368     }
369 
370     public class JsonArray : JsonValue
371     {
372         public JsonArray() : base()items()
373         {
374         }
375         public void AddItem(UniquePtr<JsonValue>&& item)
376         {
377             items.Add(Rvalue(item));
378         }
379         public void AddItem(JsonValue* item)
380         {
381             items.Add(UniquePtr<JsonValue>(item));
382         }
383         public JsonValue* GetItem(long index) const
384         {
385             return items[index].Get();
386         }
387         public JsonValue* operator[](long index) const
388         {
389             return items[index].Get();
390         }
391         public inline long Count() const
392         {
393             return items.Count();
394         }
395         public override Result<string> ToString() const
396         {
397             string s = "[";
398             bool first =  true;
399             for (const UniquePtr<JsonValue>& item : items)
400             {
401                 if (first)
402                 {
403                     first = false;
404                 }
405                 else
406                 {
407                     s.Append(", ");
408                 }
409                 auto itemResult = item->ToString();
410                 if (itemResult.Error())
411                 {
412                     return Result<string>(ErrorId(itemResult.GetErrorId()));
413                 }
414                 s.Append(itemResult.Value());
415             }
416             s.Append("]");
417             return Result<string>(s);
418         }
419         [nodiscard]
420         public override Result<bool> Write(CodeFormatter& formatter)
421         {
422             auto result = formatter.WriteLine("[");
423             if (result.Error()) return result;
424             formatter.IncIndent();
425             bool first = true;
426             bool lastWasArrayOrObject = false;
427             for (const UniquePtr<JsonValue>& item : items)
428             {
429                 if (first)
430                 {
431                     first = false;
432                 }
433                 else
434                 {
435                     result = formatter.WriteLine(", ");
436                     if (result.Error()) return result;
437                 }
438                 result = item->Write(formatter);
439                 if (result.Error()) return result;
440                 if ((item.Get() is JsonArray*) || (item.Get() is JsonObject*))
441                 {
442                     lastWasArrayOrObject = true;
443                 }
444                 else
445                 {
446                     lastWasArrayOrObject = false;
447                 }
448             }
449             formatter.DecIndent();
450             if (!lastWasArrayOrObject)
451             {
452                 result = formatter.WriteLine();
453                 if (result.Error()) return result;
454             }
455             result = formatter.WriteLine("]");
456             if (result.Error()) return result;
457             return Result<bool>(true);
458         }
459         private List<UniquePtr<JsonValue>> items;
460     }
461 
462     public Result<UniquePtr<JsonValue>> ParseJson(const string& jsonText)
463     {
464         auto utf32Result = ToUtf32(jsonText);
465         if (utf32Result.Error()) return Result<UniquePtr<JsonValue>>(ErrorId(utf32Result.GetErrorId()));
466         return ParseJson(utf32Result.Value());
467     }
468 
469     public Result<UniquePtr<JsonValue>> ParseJson(const wstring& jsonText)
470     {
471         auto utf32Result = ToUtf32(jsonText);
472         if (utf32Result.Error()) return Result<UniquePtr<JsonValue>>(ErrorId(utf32Result.GetErrorId()));
473         return ParseJson(utf32Result.Value());
474     }
475 
476     public Result<UniquePtr<JsonValue>> ParseJson(const ustring& jsonText)
477     {
478         JsonLexer jsonLexer(jsonText.Chars()jsonText.Chars() + jsonText.Length()"json");
479         Result<UniquePtr<JsonValue>> jsonValue = JsonParser<JsonLexer>.Parse(jsonLexer);
480         return Rvalue(jsonValue);
481     }