1 // =================================
  2 // Copyright (c) 2021 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 virtual default ~JsonValue();
 15         public abstract string ToString() const;
 16         public virtual void Write(CodeFormatter& formatter)
 17         {
 18             formatter.Write(ToString());
 19         }
 20     }
 21     
 22     public class JsonNull : JsonValue
 23     {
 24         public override string ToString() const
 25         {
 26             return "null";
 27         }
 28     }
 29     
 30     public class JsonNumber : JsonValue
 31     {
 32         public nothrow JsonNumber() : value(0.0)
 33         {
 34         }
 35         public explicit nothrow JsonNumber(double value_) : value(value_)
 36         {
 37         }
 38         public override string ToString() const
 39         {
 40             return System.ToString(value);
 41         }
 42         public inline nothrow double Value() const
 43         {
 44             return value;
 45         }
 46         public inline nothrow void SetValue(double value_)
 47         {
 48             value = value_;
 49         }
 50         private double value;
 51     }
 52     
 53     public class JsonBool : JsonValue
 54     {
 55         public nothrow JsonBool() : value(false)
 56         {
 57         }
 58         public explicit nothrow JsonBool(bool value_) : value(value_)
 59         {
 60         }
 61         public override string ToString() const
 62         {
 63             return System.ToString(value);
 64         }
 65         public inline nothrow bool Value() const
 66         {
 67             return value;
 68         }
 69         public inline nothrow void SetValue(bool value_)
 70         {
 71             value = value_;
 72         }
 73         private bool value;
 74     }
 75     
 76     public class JsonString : JsonValue
 77     {
 78         public nothrow JsonString() : value()
 79         {
 80         }
 81         public nothrow JsonString(const ustring& value_) : value(value_)
 82         {
 83         }
 84         public inline nothrow const ustring& Value() const
 85         {
 86             return value;
 87         }
 88         public inline nothrow void SetValue(const ustring& value_)
 89         {
 90             value = value_;
 91         }
 92         public nothrow JsonString& Append(uchar c)
 93         {
 94             value.Append(c);
 95             return *this;
 96         }
 97         public nothrow JsonString& Append(const uchar* s)
 98         {
 99             value.Append(s);
100             return *this;
101         }
102         public nothrow JsonString& Append(const ustring& s)
103         {
104             value.Append(s);
105             return *this;
106         }
107         public override string ToString() const
108         {
109             wstring s = w'"';
110             for (uchar c : value)
111             {
112                 s.Append(JsonCharStr(c));
113             }
114             s.Append(w'"');
115             return ToUtf8(s);
116         }
117         private wstring JsonCharStr(uchar c)
118         {
119             wstring result;
120             ustring s(c);
121             wstring t = ToUtf16(s);
122             for (wchar x : t)
123             {
124                 switch (x)
125                 {
126                     case '"': result.Append(w"\\\""); break;
127                     case '\\': result.Append(w"\\\\"); break;
128                     case '/': result.Append(w"\\/"); break;
129                     case '\b': result.Append(w"\\b"); break;
130                     case '\f': result.Append(w"\\f"); break;
131                     case '\n': result.Append(w"\\n"); break;
132                     case '\r': result.Append(w"\\r"); break;
133                     case '\t': result.Append(w"\\t"); break;
134                     default:
135                     {
136                         if (cast<ushort>(x) >= 32u && cast<ushort>(x) <= 126u)
137                         {
138                             result.Append(x);
139                         }
140                         else
141                         {
142                             result.Append(w"\\u").Append(ToUtf16(ToHexString(cast<ushort>(x))));
143                         }
144                         break;
145                     }
146                 }
147             }
148             return result;
149         }
150         private ustring value;
151     }
152     
153     public class JsonObject : JsonValue
154     {
155         public JsonObject() : fieldValues()fieldMap()
156         {
157         }
158         public void AddField(const string& fieldNameUniquePtr<JsonValue>&& fieldValue)
159         {
160             AddField(ToUtf32(fieldName)fieldValue);
161         }
162         public void AddField(const wstring& fieldNameUniquePtr<JsonValue>&& fieldValue)
163         {
164             AddField(ToUtf32(fieldName)fieldValue);
165         }
166         public void AddField(const ustring& fieldNameUniquePtr<JsonValue>&& fieldValue)
167         {
168             fieldMap[fieldName] = fieldValue.Get();
169             fieldValues.Add(Rvalue(fieldValue));
170         }
171         public void AddField(const string& fieldNameJsonValue* fieldValue)
172         {
173             AddField(ToUtf32(fieldName)fieldValue);
174         }
175         public void AddField(const wstring& fieldNameJsonValue* fieldValue)
176         {
177             AddField(ToUtf32(fieldName)fieldValue);
178         }
179         public void AddField(const ustring& fieldNameJsonValue* fieldValue)
180         {
181             fieldMap[fieldName] = fieldValue;
182             fieldValues.Add(UniquePtr<JsonValue>(fieldValue));
183         }
184         public JsonValue* GetField(const string& fieldName) const
185         {
186             return GetField(ToUtf32(fieldName));
187         }
188         public JsonValue* GetField(const wstring& fieldName) const
189         {
190             return GetField(ToUtf32(fieldName));
191         }
192         public JsonValue* GetField(const ustring& fieldName) const
193         {
194             Map<ustringJsonValue*>.ConstIterator i = fieldMap.CFind(fieldName);
195             if (i != fieldMap.CEnd())
196             {
197                 return i->second;
198             }
199             return null;
200         }
201         public nothrow const Map<ustringJsonValue*>& Fields() const
202         {
203             return fieldMap;
204         }
205         public nothrow Map<ustringJsonValue*>& Fields()
206         {
207             return fieldMap;
208         }
209         public override string ToString() const
210         {
211             string s = "{";
212             bool first = true;
213             for (const Pair<ustringJsonValue*>& p : fieldMap)
214             {
215                 JsonString fs = p.first;
216                 JsonValue* fv = p.second;
217                 if (first)
218                 {
219                     first = false;
220                 }
221                 else
222                 {
223                     s.Append(", ");
224                 }
225                 s.Append(fs.ToString()).Append(":").Append(fv->ToString());
226             }
227             s.Append("}");
228             return s;
229         }
230         public override void Write(CodeFormatter& formatter)
231         {
232             formatter.WriteLine("{");
233             formatter.IncIndent();
234             bool first = true;
235             bool lastWasArrayOrObject = false;
236             for (const Pair<ustringJsonValue*>& p : fieldMap)
237             {
238                 JsonString s(p.first);
239                 JsonValue* v(p.second);
240                 if (first)
241                 {
242                     first = false;
243                 }
244                 else
245                 {
246                     formatter.WriteLine(", ");
247                 }
248                 s.Write(formatter);
249                 formatter.Write(" : ");
250                 if ((v is JsonArray*) || (v is JsonObject*))
251                 {
252                     formatter.WriteLine();
253                     lastWasArrayOrObject = true;
254                 }
255                 else
256                 {
257                     lastWasArrayOrObject = false;
258                 }
259                 v->Write(formatter);
260             }
261             formatter.DecIndent();
262             if (!lastWasArrayOrObject)
263             {
264                 formatter.WriteLine();
265             }
266             formatter.WriteLine("}");
267         }
268         private List<UniquePtr<JsonValue>> fieldValues;
269         private Map<ustringJsonValue*> fieldMap;
270     }
271     
272     public class JsonArray : JsonValue
273     {
274         public nothrow JsonArray() : items()
275         {
276         }
277         public void AddItem(UniquePtr<JsonValue>&& item)
278         {
279             items.Add(Rvalue(item));
280         }
281         public void AddItem(JsonValue* item)
282         {
283             items.Add(UniquePtr<JsonValue>(item));
284         }
285         public JsonValue* operator[](long index) const
286         {
287             return items[index].Get();
288         }
289         public inline nothrow long Count() const
290         {
291             return items.Count();
292         }
293         public override string ToString() const
294         {
295             string s = "[";
296             bool first =  true;
297             for (const UniquePtr<JsonValue>& item : items)
298             {
299                 if (first)
300                 {
301                     first = false;
302                 }
303                 else
304                 {
305                     s.Append(", ");
306                 }
307                 s.Append(item->ToString());
308             }
309             s.Append("]");
310             return s;
311         }
312         public override void Write(CodeFormatter& formatter)
313         {
314             formatter.WriteLine("[");
315             formatter.IncIndent();
316             bool first = true;
317             bool lastWasArrayOrObject = false;
318             for (const UniquePtr<JsonValue>& item : items)
319             {
320                 if (first)
321                 {
322                     first = false;
323                 }
324                 else
325                 {
326                     formatter.WriteLine(", ");
327                 }
328                 item->Write(formatter);
329                 if ((item.Get() is JsonArray*) || (item.Get() is JsonObject*))
330                 {
331                     lastWasArrayOrObject = true;
332                 }
333                 else
334                 {
335                     lastWasArrayOrObject = false;
336                 }
337             }
338             formatter.DecIndent();
339             if (!lastWasArrayOrObject)
340             {
341                 formatter.WriteLine();
342             }
343             formatter.WriteLine("]");
344         }
345         private List<UniquePtr<JsonValue>> items;
346     }
347     
348     public UniquePtr<JsonValue> ParseJson(const string& jsonText)
349     {
350         return ParseJson(ToUtf32(jsonText));
351     }
352     
353     public UniquePtr<JsonValue> ParseJson(const wstring& jsonText)
354     {
355         return ParseJson(ToUtf32(jsonText));
356     }
357     
358     public UniquePtr<JsonValue> ParseJson(const ustring& jsonText)
359     {
360         JsonLexer jsonLexer(jsonText""0);
361         UniquePtr<JsonValue> jsonValue = JsonParser.Parse(jsonLexer);
362         return jsonValue;
363     }
364 }