summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAndreas Rumpf <ar@kimeta.de>2014-04-13 00:40:17 +0200
committerAndreas Rumpf <ar@kimeta.de>2014-04-13 00:40:17 +0200
commit2e9950afe8911f27560c32d2f26d2d5c6d6e6cd3 (patch)
treeff8c11fdc144ffda92f7e83cbde7e655903d2380 /lib
parentfe387888bdd0ae26fe88e886604f9e101634633d (diff)
parente333b8bc1ef27014066172c04881df191a4971fe (diff)
downloadNim-2e9950afe8911f27560c32d2f26d2d5c6d6e6cd3.tar.gz
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/json.nim111
-rw-r--r--lib/pure/math.nim4
-rw-r--r--lib/pure/streams.nim80
-rw-r--r--lib/pure/strutils.nim20
-rw-r--r--lib/system/jssys.nim54
5 files changed, 188 insertions, 81 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)
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index d258e9a7c..3997b059f 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -19,8 +19,8 @@
 
 when defined(Posix) and not defined(haiku):
   {.passl: "-lm".}
-
-import times
+when not defined(js):
+  import times
 
 const
   PI* = 3.1415926535897932384626433 ## the circle constant PI (Ludolph's number)
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index e944dd2fc..3b6dc87a5 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -239,45 +239,47 @@ proc newStringStream*(s: string = ""): PStringStream =
   result.readDataImpl = ssReadData
   result.writeDataImpl = ssWriteData
 
-type
-  PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile`
-  TFileStream* = object of TStream
-    f: TFile
-
-proc fsClose(s: PStream) =
-  if PFileStream(s).f != nil:
-    close(PFileStream(s).f)
-    PFileStream(s).f = nil
-proc fsFlush(s: PStream) = flushFile(PFileStream(s).f)
-proc fsAtEnd(s: PStream): bool = return endOfFile(PFileStream(s).f)
-proc fsSetPosition(s: PStream, pos: int) = setFilePos(PFileStream(s).f, pos)
-proc fsGetPosition(s: PStream): int = return int(getFilePos(PFileStream(s).f))
-
-proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int = 
-  result = readBuffer(PFileStream(s).f, buffer, bufLen)
-  
-proc fsWriteData(s: PStream, buffer: pointer, bufLen: int) = 
-  if writeBuffer(PFileStream(s).f, buffer, bufLen) != bufLen: 
-    raise newEIO("cannot write to stream")
-
-proc newFileStream*(f: TFile): PFileStream = 
-  ## creates a new stream from the file `f`.
-  new(result)
-  result.f = f
-  result.closeImpl = fsClose
-  result.atEndImpl = fsAtEnd
-  result.setPositionImpl = fsSetPosition
-  result.getPositionImpl = fsGetPosition
-  result.readDataImpl = fsReadData
-  result.writeDataImpl = fsWriteData
-  result.flushImpl = fsFlush
-
-proc newFileStream*(filename: string, mode: TFileMode): PFileStream = 
-  ## creates a new stream from the file named `filename` with the mode `mode`.
-  ## If the file cannot be opened, nil is returned. See the `system
-  ## <system.html>`_ module for a list of available TFileMode enums.
-  var f: TFile
-  if open(f, filename, mode): result = newFileStream(f)
+when not defined(js):
+
+  type
+    PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile`
+    TFileStream* = object of TStream
+      f: TFile
+
+  proc fsClose(s: PStream) =
+    if PFileStream(s).f != nil:
+      close(PFileStream(s).f)
+      PFileStream(s).f = nil
+  proc fsFlush(s: PStream) = flushFile(PFileStream(s).f)
+  proc fsAtEnd(s: PStream): bool = return endOfFile(PFileStream(s).f)
+  proc fsSetPosition(s: PStream, pos: int) = setFilePos(PFileStream(s).f, pos)
+  proc fsGetPosition(s: PStream): int = return int(getFilePos(PFileStream(s).f))
+
+  proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int =
+    result = readBuffer(PFileStream(s).f, buffer, bufLen)
+
+  proc fsWriteData(s: PStream, buffer: pointer, bufLen: int) =
+    if writeBuffer(PFileStream(s).f, buffer, bufLen) != bufLen:
+      raise newEIO("cannot write to stream")
+
+  proc newFileStream*(f: TFile): PFileStream =
+    ## creates a new stream from the file `f`.
+    new(result)
+    result.f = f
+    result.closeImpl = fsClose
+    result.atEndImpl = fsAtEnd
+    result.setPositionImpl = fsSetPosition
+    result.getPositionImpl = fsGetPosition
+    result.readDataImpl = fsReadData
+    result.writeDataImpl = fsWriteData
+    result.flushImpl = fsFlush
+
+  proc newFileStream*(filename: string, mode: TFileMode): PFileStream =
+    ## creates a new stream from the file named `filename` with the mode `mode`.
+    ## If the file cannot be opened, nil is returned. See the `system
+    ## <system.html>`_ module for a list of available TFileMode enums.
+    var f: TFile
+    if open(f, filename, mode): result = newFileStream(f)
 
 
 when true:
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index b63224cec..bd6814dcc 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -264,6 +264,19 @@ iterator split*(s: string, sep: char): string =
       yield substr(s, first, last-1)
       inc(last)
 
+iterator split*(s: string, sep: string): string =
+  ## Splits the string `s` into substrings using a string separator.
+  ##
+  ## Substrings are separated by the string `sep`.
+  var last = 0
+  if len(s) > 0:
+    while last <= len(s):
+      var first = last
+      while last < len(s) and s.substr(last, last + <sep.len) != sep:
+        inc(last)
+      yield substr(s, first, last-1)
+      inc(last, sep.len)
+
 iterator splitLines*(s: string): string =
   ## Splits the string `s` into its containing lines. Every newline
   ## combination (CR, LF, CR-LF) is supported. The result strings contain
@@ -329,6 +342,13 @@ proc split*(s: string, sep: char): seq[string] {.noSideEffect,
   ## of substrings.
   accumulateResult(split(s, sep))
 
+proc split*(s: string, sep: string): seq[string] {.noSideEffect,
+  rtl, extern: "nsuSplitString".} =
+  ## Splits the string `s` into substrings using a string separator.
+  ##
+  ## Substrings are separated by the string `sep`.
+  accumulateResult(split(s, sep))
+
 proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
   rtl, extern: "nsuToHex".} =
   ## Converts `x` to its hexadecimal representation. The resulting string
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 1720804c4..52f8873cf 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -12,7 +12,7 @@ when defined(nodejs):
 else:
   proc alert*(s: cstring) {.importc, nodecl.}
 
-proc log*(s: cstring) {.importc: "console.log", nodecl.}
+proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}
 
 type
   PSafePoint = ptr TSafePoint
@@ -27,11 +27,19 @@ type
     line: int # current line number
     filename: cstring
 
+  PJSError = ref object
+    columnNumber {.importc.}: int
+    fileName {.importc.}: cstring
+    lineNumber {.importc.}: int
+    message {.importc.}: cstring
+    stack {.importc.}: cstring
+
 var
   framePtr {.importc, nodecl, volatile.}: PCallFrame
   excHandler {.importc, nodecl, volatile.}: PSafePoint = nil
     # list of exception handlers
     # a global variable for the root of all try blocks
+  lastJSError {.importc, nodecl, volatile.}: PJSError = nil
 
 {.push stacktrace: off, profiler:off.}
 proc nimBoolToStr(x: bool): string {.compilerproc.} =
@@ -43,8 +51,12 @@ proc nimCharToStr(x: char): string {.compilerproc.} =
   result[0] = x
 
 proc getCurrentExceptionMsg*(): string =
-  if excHandler != nil: return $excHandler.exc.msg
-  return ""
+  if excHandler != nil and excHandler.exc != nil:
+    return $excHandler.exc.msg
+  elif lastJSError != nil:
+    return $lastJSError.message
+  else:
+    return ""
 
 proc auxWriteStackTrace(f: PCallFrame): string =
   type
@@ -77,11 +89,13 @@ proc auxWriteStackTrace(f: PCallFrame): string =
     add(result, "\n")
 
 proc rawWriteStackTrace(): string =
-  if framePtr == nil:
-    result = "No stack traceback available\n"
-  else:
-    result = "Traceback (most recent call last)\n"& auxWriteStackTrace(framePtr)
+  if framePtr != nil:
+    result = "Traceback (most recent call last)\n" & auxWriteStackTrace(framePtr)
     framePtr = nil
+  elif lastJSError != nil:
+    result = $lastJSError.stack
+  else:
+    result = "No stack traceback available\n"
 
 proc raiseException(e: ref E_Base, ename: cstring) {.
     compilerproc, asmNoStackFrame.} =
@@ -472,17 +486,17 @@ proc ze*(a: int): int {.compilerproc.} =
 proc ze64*(a: int64): int64 {.compilerproc.} =
   result = a
 
-proc ToU8(a: int): int8 {.asmNoStackFrame, compilerproc.} =
+proc toU8*(a: int): int8 {.asmNoStackFrame, compilerproc.} =
   asm """
     return `a`;
   """
 
-proc ToU16(a: int): int16 {.asmNoStackFrame, compilerproc.} =
+proc toU16*(a: int): int16 {.asmNoStackFrame, compilerproc.} =
   asm """
     return `a`;
   """
 
-proc ToU32(a: int): int32 {.asmNoStackFrame, compilerproc.} =
+proc toU32*(a: int64): int32 {.asmNoStackFrame, compilerproc.} =
   asm """
     return `a`;
   """
@@ -503,17 +517,17 @@ proc nimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
 
 proc nimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.compilerproc.} =
   case n.kind
-  of nkNone: sysAssert(false, "NimCopyAux")
+  of nkNone: sysAssert(false, "nimCopyAux")
   of nkSlot:
-    asm "`dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);"
+    asm "`dest`[`n`.offset] = nimCopy(`src`[`n`.offset], `n`.typ);"
   of nkList:
     for i in 0..n.len-1:
-      NimCopyAux(dest, src, n.sons[i])
+      nimCopyAux(dest, src, n.sons[i])
   of nkCase:
     asm """
-      `dest`[`n`.offset] = NimCopy(`src`[`n`.offset], `n`.typ);
+      `dest`[`n`.offset] = nimCopy(`src`[`n`.offset], `n`.typ);
       for (var i = 0; i < `n`.sons.length; ++i) {
-        NimCopyAux(`dest`, `src`, `n`.sons[i][1]);
+        nimCopyAux(`dest`, `src`, `n`.sons[i][1]);
       }
     """
 
@@ -534,17 +548,17 @@ proc nimCopy(x: pointer, ti: PNimType): pointer =
       for (var key in `x`) { `result`[key] = `x`[key]; }
     """
   of tyTuple, tyObject:
-    if ti.base != nil: result = NimCopy(x, ti.base)
+    if ti.base != nil: result = nimCopy(x, ti.base)
     elif ti.kind == tyObject:
       asm "`result` = {m_type: `ti`};"
     else:
       asm "`result` = {};"
-    NimCopyAux(result, x, ti.node)
+    nimCopyAux(result, x, ti.node)
   of tySequence, tyArrayConstr, tyOpenArray, tyArray:
     asm """
       `result` = new Array(`x`.length);
       for (var i = 0; i < `x`.length; ++i) {
-        `result`[i] = NimCopy(`x`[i], `ti`.base);
+        `result`[i] = nimCopy(`x`[i], `ti`.base);
       }
     """
   of tyString:
@@ -584,12 +598,12 @@ proc genericReset(x: Pointer, ti: PNimType): pointer {.compilerproc.} =
   else:
     result = nil
 
-proc ArrayConstr(len: int, value: pointer, typ: PNimType): pointer {.
+proc arrayConstr(len: int, value: pointer, typ: PNimType): pointer {.
                  asmNoStackFrame, compilerproc.} =
   # types are fake
   asm """
     var result = new Array(`len`);
-    for (var i = 0; i < `len`; ++i) result[i] = NimCopy(`value`, `typ`);
+    for (var i = 0; i < `len`; ++i) result[i] = nimCopy(`value`, `typ`);
     return result;
   """