summary refs log tree commit diff stats
path: root/compiler/ropes.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/ropes.nim')
-rw-r--r--compiler/ropes.nim158
1 files changed, 158 insertions, 0 deletions
diff --git a/compiler/ropes.nim b/compiler/ropes.nim
new file mode 100644
index 000000000..e0d5aa0d3
--- /dev/null
+++ b/compiler/ropes.nim
@@ -0,0 +1,158 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Ropes for the C code generator. Ropes are mapped to `string` directly nowadays.
+
+from pathutils import AbsoluteFile
+
+when defined(nimPreviewSlimSystem):
+  import std/[assertions, syncio, formatfloat]
+
+type
+  FormatStr* = string  # later we may change it to CString for better
+                       # performance of the code generator (assignments
+                       # copy the format strings
+                       # though it is not necessary)
+  Rope* = string
+
+proc newRopeAppender*(cap = 80): string {.inline.} =
+  result = newStringOfCap(cap)
+
+proc freeze*(r: Rope) {.inline.} = discard
+
+proc resetRopeCache* = discard
+
+template rope*(s: string): string = s
+
+proc rope*(i: BiggestInt): Rope =
+  ## Converts an int to a rope.
+  result = rope($i)
+
+proc rope*(f: BiggestFloat): Rope =
+  ## Converts a float to a rope.
+  result = rope($f)
+
+proc writeRope*(f: File, r: Rope) =
+  ## writes a rope to a file.
+  write(f, r)
+
+proc writeRope*(head: Rope, filename: AbsoluteFile): bool =
+  var f: File = default(File)
+  if open(f, filename.string, fmWrite):
+    writeRope(f, head)
+    close(f)
+    result = true
+  else:
+    result = false
+
+proc prepend*(a: var Rope, b: string) = a = b & a
+
+proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
+  var i = 0
+  result = newRopeAppender()
+  var num = 0
+  while i < frmt.len:
+    if frmt[i] == '$':
+      inc(i)                  # skip '$'
+      case frmt[i]
+      of '$':
+        result.add("$")
+        inc(i)
+      of '#':
+        inc(i)
+        result.add(args[num])
+        inc(num)
+      of '0'..'9':
+        var j = 0
+        while true:
+          j = j * 10 + ord(frmt[i]) - ord('0')
+          inc(i)
+          if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
+        num = j
+        if j > high(args) + 1:
+          raiseAssert "invalid format string: " & frmt
+        else:
+          result.add(args[j-1])
+      of '{':
+        inc(i)
+        var j = 0
+        while frmt[i] in {'0'..'9'}:
+          j = j * 10 + ord(frmt[i]) - ord('0')
+          inc(i)
+        num = j
+        if frmt[i] == '}': inc(i)
+        else:
+          raiseAssert "invalid format string: " & frmt
+
+        if j > high(args) + 1:
+          raiseAssert "invalid format string: " & frmt
+        else:
+          result.add(args[j-1])
+      of 'n':
+        result.add("\n")
+        inc(i)
+      of 'N':
+        result.add("\n")
+        inc(i)
+      else:
+        raiseAssert "invalid format string: " & frmt
+    else:
+      result.add(frmt[i])
+      inc(i)
+
+proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope =
+  runtimeFormat(frmt, args)
+
+template addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
+  ## shortcut for ``add(c, frmt % args)``.
+  c.add(frmt % args)
+
+const
+  bufSize = 1024              # 1 KB is reasonable
+
+proc equalsFile*(s: Rope, f: File): bool =
+  ## returns true if the contents of the file `f` equal `r`.
+  var
+    buf: array[bufSize, char] = default(array[bufSize, char])
+    bpos = buf.len
+    blen = buf.len
+    btotal = 0
+    rtotal = 0
+
+  when true:
+    var spos = 0
+    rtotal += s.len
+    while spos < s.len:
+      if bpos == blen:
+        # Read more data
+        bpos = 0
+        blen = readBuffer(f, addr(buf[0]), buf.len)
+        btotal += blen
+        if blen == 0:  # no more data in file
+          result = false
+          return
+      let n = min(blen - bpos, s.len - spos)
+      # TODO There's gotta be a better way of comparing here...
+      if not equalMem(addr(buf[bpos]), cast[pointer](cast[int](cstring(s))+spos), n):
+        result = false
+        return
+      spos += n
+      bpos += n
+
+  result = readBuffer(f, addr(buf[0]), 1) == 0 and
+      btotal == rtotal # check that we've read all
+
+proc equalsFile*(r: Rope, filename: AbsoluteFile): bool =
+  ## returns true if the contents of the file `f` equal `r`. If `f` does not
+  ## exist, false is returned.
+  var f: File = default(File)
+  result = open(f, filename.string)
+  if result:
+    result = equalsFile(r, f)
+    close(f)