summary refs log tree commit diff stats
path: root/compiler/llstream.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/llstream.nim')
-rw-r--r--compiler/llstream.nim90
1 files changed, 48 insertions, 42 deletions
diff --git a/compiler/llstream.nim b/compiler/llstream.nim
index 42bbb7600..cc8148483 100644
--- a/compiler/llstream.nim
+++ b/compiler/llstream.nim
@@ -10,13 +10,20 @@
 ## Low-level streams for high performance.
 
 import
-  strutils
+  pathutils
 
-# support '-d:useGnuReadline' for backwards compatibility:
-when not defined(windows) and (defined(useGnuReadline) or defined(useLinenoise)):
-  import rdstdin
+when defined(nimPreviewSlimSystem):
+  import std/syncio
+
+# support `useGnuReadline`, `useLinenoise` for backwards compatibility
+const hasRstdin = (defined(nimUseLinenoise) or defined(useLinenoise) or defined(useGnuReadline)) and
+  not defined(windows)
+
+when hasRstdin: import std/rdstdin
 
 type
+  TLLRepl* = proc (s: PLLStream, buf: pointer, bufLen: int): int
+  OnPrompt* = proc() {.closure.}
   TLLStreamKind* = enum       # enum of different stream implementations
     llsNone,                  # null stream: reading and writing has no effect
     llsString,                # stream encapsulates a string
@@ -28,33 +35,27 @@ type
     s*: string
     rd*, wr*: int             # for string streams
     lineOffset*: int          # for fake stdin line numbers
+    repl*: TLLRepl            # gives stdin control to clients
+    onPrompt*: OnPrompt
 
   PLLStream* = ref TLLStream
 
-proc llStreamOpen*(data: string): PLLStream =
-  new(result)
-  result.s = data
-  result.kind = llsString
+proc llStreamOpen*(data: sink string): PLLStream =
+  PLLStream(kind: llsString, s: data)
 
 proc llStreamOpen*(f: File): PLLStream =
-  new(result)
-  result.f = f
-  result.kind = llsFile
+  PLLStream(kind: llsFile, f: f)
 
-proc llStreamOpen*(filename: string, mode: FileMode): PLLStream =
-  new(result)
-  result.kind = llsFile
-  if not open(result.f, filename, mode): result = nil
+proc llStreamOpen*(filename: AbsoluteFile, mode: FileMode): PLLStream =
+  result = PLLStream(kind: llsFile)
+  if not open(result.f, filename.string, mode): result = nil
 
 proc llStreamOpen*(): PLLStream =
-  new(result)
-  result.kind = llsNone
+  PLLStream(kind: llsNone)
 
-proc llStreamOpenStdIn*(): PLLStream =
-  new(result)
-  result.kind = llsStdIn
-  result.s = ""
-  result.lineOffset = -1
+proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int
+proc llStreamOpenStdIn*(r: TLLRepl = llReadFromStdin, onPrompt: OnPrompt = nil): PLLStream =
+  PLLStream(kind: llsStdIn, s: "", lineOffset: -1, repl: r, onPrompt: onPrompt)
 
 proc llStreamClose*(s: PLLStream) =
   case s.kind
@@ -67,6 +68,7 @@ when not declared(readLineFromStdin):
   # fallback implementation:
   proc readLineFromStdin(prompt: string, line: var string): bool =
     stdout.write(prompt)
+    stdout.flushFile()
     result = readLine(stdin, line)
     if not result:
       stdout.write("\n")
@@ -77,6 +79,8 @@ proc endsWith*(x: string, s: set[char]): bool =
   while i >= 0 and x[i] == ' ': dec(i)
   if i >= 0 and x[i] in s:
     result = true
+  else:
+    result = false
 
 const
   LineContinuationOprs = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^',
@@ -87,13 +91,14 @@ proc endsWithOpr*(x: string): bool =
   result = x.endsWith(LineContinuationOprs)
 
 proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
-  result = inTripleString or
-      line[0] == ' ' or
-      line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs)
+  result = inTripleString or line.len > 0 and (
+        line[0] == ' ' or
+        line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs))
 
 proc countTriples(s: string): int =
+  result = 0
   var i = 0
-  while i < s.len:
+  while i+2 < s.len:
     if s[i] == '"' and s[i+1] == '"' and s[i+2] == '"':
       inc result
       inc i, 2
@@ -105,12 +110,12 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
   var line = newStringOfCap(120)
   var triples = 0
   while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line):
-    add(s.s, line)
-    add(s.s, "\n")
+    s.s.add(line)
+    s.s.add("\n")
     inc triples, countTriples(line)
     if not continueLine(line, (triples and 1) == 1): break
   inc(s.lineOffset)
-  result = min(bufLen, len(s.s) - s.rd)
+  result = min(bufLen, s.s.len - s.rd)
   if result > 0:
     copyMem(buf, addr(s.s[s.rd]), result)
     inc(s.rd, result)
@@ -120,14 +125,15 @@ proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int =
   of llsNone:
     result = 0
   of llsString:
-    result = min(bufLen, len(s.s) - s.rd)
+    result = min(bufLen, s.s.len - s.rd)
     if result > 0:
       copyMem(buf, addr(s.s[0 + s.rd]), result)
       inc(s.rd, result)
   of llsFile:
     result = readBuffer(s.f, buf, bufLen)
   of llsStdIn:
-    result = llReadFromStdin(s, buf, bufLen)
+    if s.onPrompt!=nil: s.onPrompt()
+    result = s.repl(s, buf, bufLen)
 
 proc llStreamReadLine*(s: PLLStream, line: var string): bool =
   setLen(line, 0)
@@ -135,19 +141,19 @@ proc llStreamReadLine*(s: PLLStream, line: var string): bool =
   of llsNone:
     result = true
   of llsString:
-    while s.rd < len(s.s):
+    while s.rd < s.s.len:
       case s.s[s.rd]
-      of '\x0D':
+      of '\r':
         inc(s.rd)
-        if s.s[s.rd] == '\x0A': inc(s.rd)
+        if s.s[s.rd] == '\n': inc(s.rd)
         break
-      of '\x0A':
+      of '\n':
         inc(s.rd)
         break
       else:
-        add(line, s.s[s.rd])
+        line.add(s.s[s.rd])
         inc(s.rd)
-    result = line.len > 0 or s.rd < len(s.s)
+    result = line.len > 0 or s.rd < s.s.len
   of llsFile:
     result = readLine(s.f, line)
   of llsStdIn:
@@ -158,8 +164,8 @@ proc llStreamWrite*(s: PLLStream, data: string) =
   of llsNone, llsStdIn:
     discard
   of llsString:
-    add(s.s, data)
-    inc(s.wr, len(data))
+    s.s.add(data)
+    inc(s.wr, data.len)
   of llsFile:
     write(s.f, data)
 
@@ -173,7 +179,7 @@ proc llStreamWrite*(s: PLLStream, data: char) =
   of llsNone, llsStdIn:
     discard
   of llsString:
-    add(s.s, data)
+    s.s.add(data)
     inc(s.wr)
   of llsFile:
     c = data
@@ -185,7 +191,7 @@ proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int) =
     discard
   of llsString:
     if buflen > 0:
-      setLen(s.s, len(s.s) + buflen)
+      setLen(s.s, s.s.len + buflen)
       copyMem(addr(s.s[0 + s.wr]), buf, buflen)
       inc(s.wr, buflen)
   of llsFile:
@@ -200,7 +206,7 @@ proc llStreamReadAll*(s: PLLStream): string =
   of llsString:
     if s.rd == 0: result = s.s
     else: result = substr(s.s, s.rd)
-    s.rd = len(s.s)
+    s.rd = s.s.len
   of llsFile:
     result = newString(bufSize)
     var bytes = readBuffer(s.f, addr(result[0]), bufSize)