added escaped string parsing to json module
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 17 Jun 2021 19:45:44 +0000 (14:45 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 17 Jun 2021 19:45:44 +0000 (14:45 -0500)
modules/json/example.onyx
modules/json/parser.onyx

index 189a5c89188f71569b31eacabfdd9feb87de9c46..96ba62d4864400e38de92313c396a7a2470073e9 100644 (file)
@@ -5,28 +5,30 @@
 use package core
 json :: package json
 
-json_string := "{ \"test\": \"Hello, World!\", \"array\": [1,2,3,4,5,1423], \"sub\": { \"mem\": true } }";
+json_string := "{ \"test\": \"\\tHello,\\nWorld!\", \"array\": [1,2,3,4,5,1423], \"sub\": { \"mem\": true } }";
 
 main :: (args: [] cstr) {
     arena := alloc.arena.make(context.allocator, 4096);
     defer alloc.arena.free(^arena);
 
-    decoded_json := json.decode(#file_contents "./dummy.json", alloc.arena.make_allocator(^arena));
-    // decoded_json := json.decode(json_string, alloc.arena.make_allocator(^arena));
+    // decoded_json := json.decode(#file_contents "./dummy.json", alloc.arena.make_allocator(^arena));
+    decoded_json := json.decode(json_string, alloc.arena.make_allocator(^arena));
     defer json.free(decoded_json);
 
-    root := decoded_json.root;
-    for v: root->as_array() {
-        println(v["friends"][1]["name"]->as_str());
-    }
+    // root := decoded_json.root;
+    // for v: root->as_array() {
+    //     println(v["friends"][1]["name"]->as_str());
+    // }
 
-    #if false {
+    #if true {
         value := decoded_json.root["array"];
         for v: value->as_array() {
             println(v->as_int());
         }
         test_str := decoded_json.root["sub"]["mem"]->as_bool();
         println(test_str);
+
+        decoded_json.root["test"]->as_str() |> println();
     }
 }
     
\ No newline at end of file
index b505b617e5a49880a9b48ef4ac280ca0406ec66f..25741d235bfe8232d8c75d033e5901cd71238bd3 100644 (file)
@@ -90,8 +90,7 @@ parse_value :: (use parser: ^Parser) -> (^Value, Error) {
 
         case .String {
             value := new(Value_String, allocator);
-            @Todo // parse escaped strings
-            value.str_ = string.alloc_copy(current.text.data[1 .. current.text.count - 1], allocator);
+            value.str_ = unescape_string(current, allocator);
 
             consume_token(parser);
             return_value = value;
@@ -182,7 +181,7 @@ parse_object :: (use parser: ^Parser) -> (^Value_Object, Error) {
             return value, err;
         }
 
-        key := string.alloc_copy(key_token.text.data[1 .. key_token.text.count - 1], allocator);
+        key := unescape_string(key_token, allocator);
 
         _, colon_err := expect_token(parser, .Colon);
         if colon_err != .None {
@@ -224,4 +223,102 @@ parse_object :: (use parser: ^Parser) -> (^Value_Object, Error) {
     }
 
     return value, err;
+}
+
+
+#private_file
+unescape_string :: (token: Token, allocator: Allocator) -> str {
+    if token.kind != .String do return "";
+
+    s := token.text;
+    if s.count <= 2 do return "";
+
+    s = s.data[1 .. s.count - 1];
+
+    i := 0;
+    for c: s {
+        if c == #char "\\" || c == #char "\"" || c < #char " " {
+            break;
+        }
+
+        i += 1;
+    }
+
+    if i == s.count {
+        return string.alloc_copy(s, allocator);
+    }
+
+    buffer := memory.make_slice(u8, s.count, allocator=allocator);
+    string.copy(s.data[0 .. i], buffer);
+    buffer_write := i;
+
+    while i < s.count {
+        c := s[i];
+
+        switch c {
+            case #char "\\" {
+                i += 1;
+                if i >= s.count do break break;
+
+                switch s[i] {
+                    case #char "\"", #char "'", #char "\\",  #char "/" {
+                        buffer[buffer_write] = s[i];
+                        i += 1;
+                        buffer_write += 1;
+                    }
+
+                    case #char "n" {
+                        buffer[buffer_write] = #char "\n";
+                        i += 1;
+                        buffer_write += 1;
+                    }
+
+                    case #char "t" {
+                        buffer[buffer_write] = #char "\t";
+                        i += 1;
+                        buffer_write += 1;
+                    }
+
+                    case #char "r" {
+                        buffer[buffer_write] = #char "\r";
+                        i += 1;
+                        buffer_write += 1;
+                    }
+
+                    case #char "b" {
+                        buffer[buffer_write] = #char "\b";
+                        i += 1;
+                        buffer_write += 1;
+                    }
+
+                    case #char "f" {
+                        buffer[buffer_write] = #char "\f";
+                        i += 1;
+                        buffer_write += 1;
+                    }
+
+                    case #char "v" {
+                        buffer[buffer_write] = #char "\v";
+                        i += 1;
+                        buffer_write += 1;
+                    }
+
+                    case #char "0" {
+                        buffer[buffer_write] = #char "\0";
+                        i += 1;
+                        buffer_write += 1;
+                    }
+                }
+            }
+
+            case #default {
+                buffer[buffer_write] = c;
+                i += 1;
+                buffer_write += 1;
+            }
+        }
+    }
+
+    buffer.count = buffer_write;
+    return buffer;
 }
\ No newline at end of file