1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 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)
|