summary refs log tree commit diff stats
path: root/lib/pure/json.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/json.nim')
-rw-r--r--lib/pure/json.nim111
1 files changed, 91 insertions, 20 deletions
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 7424bbae9..4250847e5 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -861,26 +861,97 @@ proc parseJson(p: var TJsonParser): PJsonNode =
   of tkError, tkCurlyRi, tkBracketRi, tkColon, tkComma, tkEof:
     raiseParseErr(p, "{")
 
-proc parseJson*(s: PStream, filename: string): PJsonNode =
-  ## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed
-  ## for nice error messages.
-  var p: TJsonParser
-  p.open(s, filename)
-  discard getTok(p) # read first token
-  result = p.parseJson()
-  p.close()
-
-proc parseJson*(buffer: string): PJsonNode = 
-  ## Parses JSON from `buffer`.
-  result = parseJson(newStringStream(buffer), "input")
-
-proc parseFile*(filename: string): PJsonNode =
-  ## Parses `file` into a `PJsonNode`.
-  var stream = newFileStream(filename, fmRead)
-  if stream == nil: 
-    raise newException(EIO, "cannot read from file: " & filename)
-  result = parseJson(stream, filename)
-  
+when not defined(js):
+  proc parseJson*(s: PStream, filename: string): PJsonNode =
+    ## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed
+    ## for nice error messages.
+    var p: TJsonParser
+    p.open(s, filename)
+    discard getTok(p) # read first token
+    result = p.parseJson()
+    p.close()
+
+  proc parseJson*(buffer: string): PJsonNode =
+    ## Parses JSON from `buffer`.
+    result = parseJson(newStringStream(buffer), "input")
+
+  proc parseFile*(filename: string): PJsonNode =
+    ## Parses `file` into a `PJsonNode`.
+    var stream = newFileStream(filename, fmRead)
+    if stream == nil:
+      raise newException(EIO, "cannot read from file: " & filename)
+    result = parseJson(stream, filename)
+else:
+  from math import `mod`
+  type
+    TJSObject = object
+  proc parseNativeJson(x: cstring): TJSObject {.importc: "JSON.parse".}
+
+  proc getVarType(x): TJsonNodeKind =
+    result = JNull
+    proc getProtoName(y): cstring
+      {.importc: "Object.prototype.toString.call".}
+    case $getProtoName(x) # TODO: Implicit returns fail here.
+    of "[object Array]": return JArray
+    of "[object Object]": return JObject
+    of "[object Number]":
+      if cast[float](x) mod 1.0 == 0:
+        return JInt
+      else:
+        return JFloat
+    of "[object Boolean]": return JBool
+    of "[object Null]": return JNull
+    of "[object String]": return JString
+    else: assert false
+
+  proc len(x: TJSObject): int =
+    assert x.getVarType == JArray
+    asm """
+      return `x`.length;
+    """
+
+  proc `[]`(x: TJSObject, y: string): TJSObject =
+    assert x.getVarType == JObject
+    asm """
+      return `x`[`y`];
+    """
+
+  proc `[]`(x: TJSObject, y: int): TJSObject =
+    assert x.getVarType == JArray
+    asm """
+      return `x`[`y`];
+    """
+
+  proc convertObject(x: TJSObject): PJsonNode =
+    case getVarType(x)
+    of JArray:
+      result = newJArray()
+      for i in 0 .. <x.len:
+        result.add(x[i].convertObject())
+    of JObject:
+      result = newJObject()
+      asm """for (property in `x`) {
+        if (`x`.hasOwnProperty(property)) {
+      """
+      var nimProperty: cstring
+      var nimValue: TJSObject
+      asm "`nimProperty` = property; `nimValue` = `x`[property];"
+      result[$nimProperty] = nimValue.convertObject()
+      asm "}}"
+    of JInt:
+      result = newJInt(cast[int](x))
+    of JFloat:
+      result = newJFloat(cast[float](x))
+    of JString:
+      result = newJString($cast[cstring](x))
+    of JBool:
+      result = newJBool(cast[bool](x))
+    of JNull:
+      result = newJNull()
+
+  proc parseJson*(buffer: string): PJsonNode =
+    return parseNativeJson(buffer).convertObject()
+
 when false:
   import os
   var s = newFileStream(ParamStr(1), fmRead)