summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPiotr Fusik <piotr@fusion-lang.org>2024-02-27 21:19:53 +0100
committerPiotr Fusik <piotr@fusion-lang.org>2024-02-27 21:29:04 +0100
commitab20aa74118dbafe42ab8320eaf22859b556e259 (patch)
treeb6965a8343f662402030ba6181905823895ffc9e
parent52501bb91457f93a873b532eff2bbdbb3617902f (diff)
[json] Pure Fusion implementation.
#140
-rw-r--r--test/JsonElement.fu352
1 files changed, 351 insertions, 1 deletions
diff --git a/test/JsonElement.fu b/test/JsonElement.fu
index 8118434..9393be3 100644
--- a/test/JsonElement.fu
+++ b/test/JsonElement.fu
@@ -1,8 +1,358 @@
+#if CPP
+abstract class JsonElement
+{
+ public virtual bool IsObject() => false;
+ public virtual bool IsArray() => false;
+ public virtual bool IsString() => false;
+ public virtual bool IsNumber() => false;
+ public virtual bool IsBoolean() => false;
+ public virtual bool IsNull() => false;
+
+ public virtual Dictionary<string(), JsonElement#> GetObject()
+ {
+ assert false;
+ }
+
+ public virtual List<JsonElement#> GetArray()
+ {
+ assert false;
+ }
+
+ public virtual string GetString()
+ {
+ assert false;
+ }
+
+ public virtual double GetDouble()
+ {
+ assert false;
+ }
+
+ public virtual bool GetBoolean()
+ {
+ assert false;
+ }
+
+ public static JsonElement# Parse(string s)
+ {
+ JsonParser() parser;
+ return parser.TryParse(s);
+ }
+}
+
+class JsonObject : JsonElement
+{
+ internal Dictionary<string(), JsonElement#>() Value;
+ public override bool IsObject() => true;
+ public override Dictionary<string(), JsonElement#> GetObject() => Value;
+}
+
+class JsonArray : JsonElement
+{
+ internal List<JsonElement#>() Value;
+ public override bool IsArray() => true;
+ public override List<JsonElement#> GetArray() => Value;
+}
+
+class JsonString : JsonElement
+{
+ internal string() Value;
+ public override bool IsString() => true;
+ public override string GetString() => Value;
+}
+
+class JsonNumber : JsonElement
+{
+ internal double Value;
+ public override bool IsNumber() => true;
+ public override double GetDouble() => Value;
+}
+
+class JsonBoolean : JsonElement
+{
+ public override bool IsBoolean() => true;
+ public override bool GetBoolean() => false;
+}
+
+class JsonTrue : JsonBoolean
+{
+ public override bool GetBoolean() => true;
+}
+
+class JsonNull : JsonElement
+{
+ public override bool IsNull() => true;
+}
+
+class JsonParser
+{
+ string Input;
+ int Offset;
+ int InputLength;
+
+ bool SkipWhitespace!()
+ {
+ while (Offset < InputLength) {
+ switch (Input[Offset]) {
+ case '\t':
+ case '\n':
+ case '\r':
+ case ' ':
+ break;
+ default:
+ return true;
+ }
+ Offset++;
+ }
+ return false;
+ }
+
+ JsonObject#? ParseObject!()
+ {
+ Offset++;
+ if (!SkipWhitespace())
+ return null;
+ JsonObject# result = new JsonObject();
+ if (Input[Offset] == '}') {
+ Offset++;
+ return result;
+ }
+ while (Input[Offset] == '"') {
+ JsonString#? key = ParseString();
+ if (key == null || !SkipWhitespace() || Input[Offset] != ':')
+ return null;
+ Offset++;
+ JsonElement#? value = ParseWhitespaceAndElement();
+ if (value == null || !SkipWhitespace())
+ return null;
+ result.Value[key.Value] = value;
+ switch (Input[Offset++]) {
+ case ',':
+ break;
+ case '}':
+ return result;
+ default:
+ return null;
+ }
+ if (!SkipWhitespace())
+ return null;
+ }
+ return null;
+ }
+
+ JsonArray#? ParseArray!()
+ {
+ Offset++;
+ if (!SkipWhitespace())
+ return null;
+ JsonArray# result = new JsonArray();
+ if (Input[Offset] == ']') {
+ Offset++;
+ return result;
+ }
+ do {
+ JsonElement#? element = ParseElement();
+ if (element == null || !SkipWhitespace())
+ return null;
+ result.Value.Add(element);
+ switch (Input[Offset++]) {
+ case ',':
+ break;
+ case ']':
+ return result;
+ default:
+ return null;
+ }
+ } while (SkipWhitespace());
+ return null;
+ }
+
+ JsonString#? ParseString!()
+ {
+ Offset++;
+ StringWriter() result;
+ int startOffset = Offset;
+ while (Offset < InputLength) {
+ switch (Input[Offset]) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ return null;
+ case '"':
+ result.Write(Input.Substring(startOffset, Offset++ - startOffset));
+ return new JsonString { Value = result.ToString() };
+ case '\\':
+ result.Write(Input.Substring(startOffset, Offset++ - startOffset));
+ if (Offset >= InputLength)
+ return null;
+ switch (Input[Offset]) {
+ case '"':
+ case '\\':
+ case '/':
+ startOffset = Offset++;
+ continue;
+ case 'b':
+ result.WriteChar(8);
+ break;
+ case 'f':
+ result.WriteChar(12);
+ break;
+ case 'n':
+ result.WriteChar('\n');
+ break;
+ case 'r':
+ result.WriteChar('\r');
+ break;
+ case 't':
+ result.WriteChar('\t');
+ break;
+ case 'u':
+ if (Offset + 5 >= InputLength)
+ return null;
+ int c;
+ if (!c.TryParse(Input.Substring(Offset + 1, 4), 16))
+ return null;
+ result.WriteCodePoint(c);
+ Offset += 4;
+ break;
+ default:
+ return null;
+ }
+ startOffset = ++Offset;
+ break;
+ default:
+ Offset++;
+ break;
+ }
+ }
+ return null;
+ }
+
+ bool SeeDigit() => Offset < InputLength && Input[Offset] >= '0' && Input[Offset] <= '9';
+
+ void ParseDigits!()
+ {
+ while (SeeDigit())
+ Offset++;
+ }
+
+ JsonNumber#? ParseNumber!()
+ {
+ int startOffset = Offset;
+ if (Input[Offset] == '-')
+ Offset++;
+ if (!SeeDigit())
+ return null;
+ if (Input[Offset++] > '0')
+ ParseDigits();
+ if (Offset < InputLength && Input[Offset] == '.') {
+ Offset++;
+ if (!SeeDigit())
+ return null;
+ ParseDigits();
+ }
+ if (Offset < InputLength && (Input[Offset] | 0x20) == 'e') {
+ if (++Offset < InputLength && (Input[Offset] == '+' || Input[Offset] == '-'))
+ Offset++;
+ if (!SeeDigit())
+ return null;
+ ParseDigits();
+ }
+ double d;
+ if (!d.TryParse(Input.Substring(startOffset, Offset - startOffset)))
+ return null;
+ return new JsonNumber { Value = d };
+ }
+
+ bool ParseKeyword!(string s)
+ {
+ foreach (int c in s) {
+ if (++Offset >= InputLength || Input[Offset] != c)
+ return false;
+ }
+ Offset++;
+ return true;
+ }
+
+ JsonElement#? ParseElement!()
+ {
+ switch (Input[Offset]) {
+ case '{':
+ return ParseObject();
+ case '[':
+ return ParseArray();
+ case '"':
+ return ParseString();
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return ParseNumber();
+ case 't':
+ return ParseKeyword("rue") ? new JsonTrue() : null;
+ case 'f':
+ return ParseKeyword("alse") ? new JsonBoolean() : null;
+ case 'n':
+ return ParseKeyword("ull") ? new JsonNull() : null;
+ default:
+ return null;
+ }
+ }
+
+ JsonElement#? ParseWhitespaceAndElement!() => SkipWhitespace() ? ParseElement() : null;
+
+ internal JsonElement#? TryParse!(string s)
+ {
+ Input = s;
+ Offset = 0;
+ InputLength = s.Length;
+ JsonElement#? result = ParseWhitespaceAndElement();
+ return SkipWhitespace() ? null : result;
+ }
+}
+#endif
+
public static class Test
{
public static bool Run()
{
- JsonElement# json; //FAIL: c cpp java swift TODO; cl
+ JsonElement# json; //FAIL: c java swift TODO; cl
json = JsonElement.Parse("\"foo\"");
if (!json.IsString() || json.GetString() != "foo")
return false;