summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorClyybber <darkmine956@gmail.com>2019-09-29 22:20:00 +0200
committerAndreas Rumpf <rumpf_a@web.de>2019-09-29 22:20:00 +0200
commit16c39f9b2edc963655889cfd33e165bfae91c96d (patch)
tree9da74d03a757de874d9f01a8a055875643bbfbb2
parent85db42ad8c1a19ea47bd5826d8639e8974cc9042 (diff)
downloadNim-16c39f9b2edc963655889cfd33e165bfae91c96d.tar.gz
More of StringStream now works at compile time (#12284)
* readLine of StringStream now works at compile time
* Work for js backend only at compile time
* readAll now works at CT
* readAll works in js ct now
* Add test
-rw-r--r--lib/pure/streams.nim131
-rw-r--r--tests/stdlib/tstreams3.nim11
2 files changed, 114 insertions, 28 deletions
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 0a187cea2..61aa520d1 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -251,16 +251,29 @@ when not defined(js):
       strm.close()
 
     const bufferSize = 1024
-    var buffer {.noinit.}: array[bufferSize, char]
-    while true:
-      let readBytes = readData(s, addr(buffer[0]), bufferSize)
-      if readBytes == 0:
-        break
-      let prevLen = result.len
-      result.setLen(prevLen + readBytes)
-      copyMem(addr(result[prevLen]), addr(buffer[0]), readBytes)
-      if readBytes < bufferSize:
-        break
+    when nimvm:
+      var buffer2: string
+      buffer2.setLen(bufferSize)
+      while true:
+        let readBytes = readDataStr(s, buffer2, 0..<bufferSize)
+        if readBytes == 0:
+          break
+        let prevLen = result.len
+        result.setLen(prevLen + readBytes)
+        result[prevLen..<prevLen+readBytes] = buffer2[0..<readBytes]
+        if readBytes < bufferSize:
+          break
+    else:
+      var buffer {.noinit.}: array[bufferSize, char]
+      while true:
+        let readBytes = readData(s, addr(buffer[0]), bufferSize)
+        if readBytes == 0:
+          break
+        let prevLen = result.len
+        result.setLen(prevLen + readBytes)
+        copyMem(addr(result[prevLen]), addr(buffer[0]), readBytes)
+        if readBytes < bufferSize:
+          break
 
 proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
   ## Low level proc that reads data into an untyped `buffer` of `bufLen` size
@@ -399,7 +412,12 @@ proc readChar*(s: Stream): char =
     doAssert strm.readChar() == '\x00'
     strm.close()
 
-  if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
+  when nimvm:
+    var str = " "
+    if readDataStr(s, str, 0..<sizeof(result)) != 1: result = '\0'
+    else: result = str[0]
+  else:
+    if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
 
 proc peekChar*(s: Stream): char =
   ## Peeks a char from the stream `s`. Raises `IOError` if an error occurred.
@@ -884,7 +902,10 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
     result = s.readLineImpl(s, line)
   else:
     # fallback
-    line.string.setLen(0)
+    when nimvm: #Bug #12282
+      line.setLen(0)
+    else:
+      line.string.setLen(0)
     while true:
       var c = readChar(s)
       if c == '\c':
@@ -894,7 +915,10 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
       elif c == '\0':
         if line.len > 0: break
         else: return false
-      line.string.add(c)
+      when nimvm: #Bug #12282
+        line.add(c)
+      else:
+        line.string.add(c)
     result = true
 
 proc peekLine*(s: Stream, line: var TaintedString): bool =
@@ -999,21 +1023,73 @@ iterator lines*(s: Stream): TaintedString =
   while s.readLine(line):
     yield line
 
-when not defined(js):
+type
+  StringStream* = ref StringStreamObj
+    ## A stream that encapsulates a string.
+    ##
+    ## **Note:** Not available for JS backend.
+  StringStreamObj* = object of StreamObj
+    ## A string stream object.
+    ##
+    ## **Note:** Not available for JS backend.
+    data*: string ## A string data.
+                  ## This is updated when called `writeLine` etc.
+    pos: int
 
-  type
-    StringStream* = ref StringStreamObj
-      ## A stream that encapsulates a string.
-      ##
-      ## **Note:** Not available for JS backend.
-    StringStreamObj* = object of StreamObj
-      ## A string stream object.
-      ##
-      ## **Note:** Not available for JS backend.
-      data*: string ## A string data.
-                    ## This is updated when called `writeLine` etc.
-      pos: int
+when defined(js): #This section exists so that string streams work at compile time for the js backend
+  proc ssAtEnd(s: Stream): bool {.compileTime.} =
+    var s = StringStream(s)
+    return s.pos >= s.data.len
+
+  proc ssSetPosition(s: Stream, pos: int) {.compileTime.} =
+    var s = StringStream(s)
+    s.pos = clamp(pos, 0, s.data.len)
+
+  proc ssGetPosition(s: Stream): int {.compileTime.} =
+    var s = StringStream(s)
+    return s.pos
+
+  proc ssReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int {.compileTime.} =
+    var s = StringStream(s)
+    result = min(slice.b + 1 - slice.a, s.data.len - s.pos)
+    if result > 0:
+      buffer[slice.a..<slice.a+result] = s.data[s.pos..<s.pos+result]
+      inc(s.pos, result)
+    else:
+      result = 0
+
+  proc ssClose(s: Stream) {.compileTime.} =
+    var s = StringStream(s)
+    when defined(nimNoNilSeqs):
+      s.data = ""
+    else:
+      s.data = nil
+
+  proc newStringStream*(s: string = ""): owned StringStream {.compileTime.} =
+    new(result)
+    result.data = s
+    result.pos = 0
+    result.closeImpl = ssClose
+    result.atEndImpl = ssAtEnd
+    result.setPositionImpl = ssSetPosition
+    result.getPositionImpl = ssGetPosition
+    result.readDataStrImpl = ssReadDataStr
+
+  proc readAll*(s: Stream): string {.compileTime.} =
+    const bufferSize = 1024
+    var bufferr: string
+    bufferr.setLen(bufferSize)
+    while true:
+      let readBytes = readDataStr(s, bufferr, 0..<bufferSize)
+      if readBytes == 0:
+        break
+      let prevLen = result.len
+      result.setLen(prevLen + readBytes)
+      result[prevLen..<prevLen+readBytes] = bufferr[0..<readBytes]
+      if readBytes < bufferSize:
+        break
 
+else:
   proc ssAtEnd(s: Stream): bool =
     var s = StringStream(s)
     return s.pos >= s.data.len
@@ -1031,8 +1107,7 @@ when not defined(js):
     result = min(slice.b + 1 - slice.a, s.data.len - s.pos)
     if result > 0:
       when nimvm:
-        for i in 0 ..< result: # sorry, but no fast string splicing on the vm.
-          buffer[slice.a + i] = s.data[s.pos + i]
+        buffer[slice.a..<slice.a+result] = s.data[s.pos..<s.pos+result]
       else:
         copyMem(unsafeAddr buffer[slice.a], addr s.data[s.pos], result)
       inc(s.pos, result)
diff --git a/tests/stdlib/tstreams3.nim b/tests/stdlib/tstreams3.nim
index e3b395e05..89f45f275 100644
--- a/tests/stdlib/tstreams3.nim
+++ b/tests/stdlib/tstreams3.nim
@@ -1,5 +1,10 @@
 discard """
   output: "threw exception"
+  nimout: '''
+I
+AM
+GROOT
+'''
 """
 import streams
 
@@ -7,3 +12,9 @@ try:
   var fs = openFileStream("shouldneverexist.txt")
 except IoError:
   echo "threw exception"
+
+static:
+  var s = newStringStream("I\nAM\nGROOT")
+  for line in s.lines:
+    echo line
+  s.close