Merge pull request #2428 from arnetheduck/comp-lib-ropes
Comp lib ropes
This commit is contained in:
commit
99e0fb90e0
15 changed files with 200 additions and 189 deletions
|
|
@ -452,17 +452,16 @@ proc debug(n: PSym) =
|
||||||
elif n.kind == skUnknown:
|
elif n.kind == skUnknown:
|
||||||
msgWriteln("skUnknown")
|
msgWriteln("skUnknown")
|
||||||
else:
|
else:
|
||||||
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
|
#writeln(stdout, $symToYaml(n, 0, 1))
|
||||||
msgWriteln("$1_$2: $3, $4, $5, $6" % [
|
msgWriteln("$1_$2: $3, $4, $5, $6" % [
|
||||||
n.name.s, $n.id, flagsToStr(n.flags).ropeToStr,
|
n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
|
||||||
flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr,
|
$lineInfoToStr(n.info), $n.kind])
|
||||||
$n.kind])
|
|
||||||
|
|
||||||
proc debug(n: PType) =
|
proc debug(n: PType) =
|
||||||
msgWriteln(ropeToStr(debugType(n)))
|
msgWriteln($debugType(n))
|
||||||
|
|
||||||
proc debug(n: PNode) =
|
proc debug(n: PNode) =
|
||||||
msgWriteln(ropeToStr(debugTree(n, 0, 100)))
|
msgWriteln($debugTree(n, 0, 100))
|
||||||
|
|
||||||
const
|
const
|
||||||
EmptySeq = @[]
|
EmptySeq = @[]
|
||||||
|
|
|
||||||
|
|
@ -259,7 +259,7 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
||||||
pushType(w, loc.t)
|
pushType(w, loc.t)
|
||||||
if loc.r != nil:
|
if loc.r != nil:
|
||||||
add(result, '!')
|
add(result, '!')
|
||||||
encodeStr(ropeToStr(loc.r), result)
|
encodeStr($loc.r, result)
|
||||||
if loc.a != 0:
|
if loc.a != 0:
|
||||||
add(result, '?')
|
add(result, '?')
|
||||||
encodeVInt(loc.a, result)
|
encodeVInt(loc.a, result)
|
||||||
|
|
@ -317,7 +317,7 @@ proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
|
||||||
add(result, '|')
|
add(result, '|')
|
||||||
encodeVInt(ord(lib.kind), result)
|
encodeVInt(ord(lib.kind), result)
|
||||||
add(result, '|')
|
add(result, '|')
|
||||||
encodeStr(ropeToStr(lib.name), result)
|
encodeStr($lib.name, result)
|
||||||
add(result, '|')
|
add(result, '|')
|
||||||
encodeNode(w, info, lib.path, result)
|
encodeNode(w, info, lib.path, result)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -413,7 +413,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
assert(typ.kind == tyProc)
|
assert(typ.kind == tyProc)
|
||||||
var length = sonsLen(ri)
|
var length = sonsLen(ri)
|
||||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||||
# don't call 'ropeToStr' here for efficiency:
|
# don't call '$' here for efficiency:
|
||||||
let pat = ri.sons[0].sym.loc.r.data
|
let pat = ri.sons[0].sym.loc.r.data
|
||||||
internalAssert pat != nil
|
internalAssert pat != nil
|
||||||
if pat.contains({'#', '(', '@', '\''}):
|
if pat.contains({'#', '(', '@', '\''}):
|
||||||
|
|
@ -462,7 +462,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||||
var length = sonsLen(ri)
|
var length = sonsLen(ri)
|
||||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||||
|
|
||||||
# don't call 'ropeToStr' here for efficiency:
|
# don't call '$' here for efficiency:
|
||||||
let pat = ri.sons[0].sym.loc.r.data
|
let pat = ri.sons[0].sym.loc.r.data
|
||||||
internalAssert pat != nil
|
internalAssert pat != nil
|
||||||
var start = 3
|
var start = 3
|
||||||
|
|
|
||||||
|
|
@ -1730,7 +1730,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
mParseBiggestFloat:
|
mParseBiggestFloat:
|
||||||
var opr = e.sons[0].sym
|
var opr = e.sons[0].sym
|
||||||
if lfNoDecl notin opr.loc.flags:
|
if lfNoDecl notin opr.loc.flags:
|
||||||
discard cgsym(p.module, opr.loc.r.ropeToStr)
|
discard cgsym(p.module, $opr.loc.r)
|
||||||
genCall(p, e, d)
|
genCall(p, e, d)
|
||||||
of mReset: genReset(p, e)
|
of mReset: genReset(p, e)
|
||||||
of mEcho: genEcho(p, e[1].skipConv)
|
of mEcho: genEcho(p, e[1].skipConv)
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ proc writeTypeCache(a: TIdTable, s: var string) =
|
||||||
s.add(' ')
|
s.add(' ')
|
||||||
encodeVInt(id, s)
|
encodeVInt(id, s)
|
||||||
s.add(':')
|
s.add(':')
|
||||||
encodeStr(PRope(value).ropeToStr, s)
|
encodeStr($PRope(value), s)
|
||||||
inc i
|
inc i
|
||||||
s.add('}')
|
s.add('}')
|
||||||
|
|
||||||
|
|
@ -280,11 +280,11 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
|
||||||
proc mergeRequired*(m: BModule): bool =
|
proc mergeRequired*(m: BModule): bool =
|
||||||
for i in cfsHeaders..cfsProcs:
|
for i in cfsHeaders..cfsProcs:
|
||||||
if m.s[i] != nil:
|
if m.s[i] != nil:
|
||||||
#echo "not empty: ", i, " ", ropeToStr(m.s[i])
|
#echo "not empty: ", i, " ", m.s[i]
|
||||||
return true
|
return true
|
||||||
for i in low(TCProcSection)..high(TCProcSection):
|
for i in low(TCProcSection)..high(TCProcSection):
|
||||||
if m.initProc.s(i) != nil:
|
if m.initProc.s(i) != nil:
|
||||||
#echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i])
|
#echo "not empty: ", i, " ", m.initProc.s[i]
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc mergeFiles*(cfilename: string, m: BModule) =
|
proc mergeFiles*(cfilename: string, m: BModule) =
|
||||||
|
|
|
||||||
|
|
@ -936,7 +936,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
|
||||||
if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}:
|
if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, t.sons[i], a)
|
initLocExpr(p, t.sons[i], a)
|
||||||
res.add(rdLoc(a).ropeToStr)
|
res.add($rdLoc(a))
|
||||||
else:
|
else:
|
||||||
var r = sym.loc.r
|
var r = sym.loc.r
|
||||||
if r == nil:
|
if r == nil:
|
||||||
|
|
@ -944,7 +944,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
|
||||||
# it doesn't matter much:
|
# it doesn't matter much:
|
||||||
r = mangleName(sym)
|
r = mangleName(sym)
|
||||||
sym.loc.r = r # but be consequent!
|
sym.loc.r = r # but be consequent!
|
||||||
res.add(r.ropeToStr)
|
res.add($r)
|
||||||
else: internalError(t.sons[i].info, "genAsmOrEmitStmt()")
|
else: internalError(t.sons[i].info, "genAsmOrEmitStmt()")
|
||||||
|
|
||||||
if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
|
if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
|
||||||
|
|
|
||||||
|
|
@ -77,13 +77,13 @@ proc mangleName(s: PSym): PRope =
|
||||||
# These are not properly scoped now - we need to add blocks
|
# These are not properly scoped now - we need to add blocks
|
||||||
# around for loops in transf
|
# around for loops in transf
|
||||||
if keepOrigName:
|
if keepOrigName:
|
||||||
result = s.name.s.mangle.newRope
|
result = s.name.s.mangle.toRope
|
||||||
else:
|
else:
|
||||||
app(result, newRope(mangle(s.name.s)))
|
app(result, toRope(mangle(s.name.s)))
|
||||||
app(result, ~"_")
|
app(result, ~"_")
|
||||||
app(result, toRope(s.id))
|
app(result, toRope(s.id))
|
||||||
else:
|
else:
|
||||||
app(result, newRope(mangle(s.name.s)))
|
app(result, toRope(mangle(s.name.s)))
|
||||||
app(result, ~"_")
|
app(result, ~"_")
|
||||||
app(result, toRope(s.id))
|
app(result, toRope(s.id))
|
||||||
s.loc.r = result
|
s.loc.r = result
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||||
while frmt[i] in Digits:
|
while frmt[i] in Digits:
|
||||||
j = (j * 10) + ord(frmt[i]) - ord('0')
|
j = (j * 10) + ord(frmt[i]) - ord('0')
|
||||||
inc(i)
|
inc(i)
|
||||||
app(result, cgsym(m, args[j-1].ropeToStr))
|
app(result, cgsym(m, $args[j-1]))
|
||||||
var start = i
|
var start = i
|
||||||
while i < length:
|
while i < length:
|
||||||
if frmt[i] != '$' and frmt[i] != '#': inc(i)
|
if frmt[i] != '$' and frmt[i] != '#': inc(i)
|
||||||
|
|
@ -555,8 +555,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||||
params.app(rdLoc(a))
|
params.app(rdLoc(a))
|
||||||
params.app(", ")
|
params.app(", ")
|
||||||
let load = ropef("\t$1 = ($2) ($3$4));$n",
|
let load = ropef("\t$1 = ($2) ($3$4));$n",
|
||||||
[tmp, getTypeDesc(m, sym.typ),
|
[tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)])
|
||||||
params, makeCString(ropeToStr(extname))])
|
|
||||||
var last = lastSon(n)
|
var last = lastSon(n)
|
||||||
if last.kind == nkHiddenStdConv: last = last.sons[1]
|
if last.kind == nkHiddenStdConv: last = last.sons[1]
|
||||||
internalAssert(last.kind == nkStrLit)
|
internalAssert(last.kind == nkStrLit)
|
||||||
|
|
@ -570,8 +569,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||||
else:
|
else:
|
||||||
appcg(m, m.s[cfsDynLibInit],
|
appcg(m, m.s[cfsDynLibInit],
|
||||||
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
|
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
|
||||||
[tmp, getTypeDesc(m, sym.typ),
|
[tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
|
||||||
lib.name, makeCString(ropeToStr(extname))])
|
|
||||||
appf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
appf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
||||||
|
|
||||||
proc varInDynamicLib(m: BModule, sym: PSym) =
|
proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||||
|
|
@ -584,8 +582,7 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||||
inc(m.labels, 2)
|
inc(m.labels, 2)
|
||||||
appcg(m, m.s[cfsDynLibInit],
|
appcg(m, m.s[cfsDynLibInit],
|
||||||
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
|
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
|
||||||
[tmp, getTypeDesc(m, sym.typ),
|
[tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
|
||||||
lib.name, makeCString(ropeToStr(extname))])
|
|
||||||
appf(m.s[cfsVars], "$2* $1;$n",
|
appf(m.s[cfsVars], "$2* $1;$n",
|
||||||
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
||||||
|
|
||||||
|
|
@ -1255,7 +1252,7 @@ proc writeModule(m: BModule, pending: bool) =
|
||||||
var code = genModule(m, cfile)
|
var code = genModule(m, cfile)
|
||||||
when hasTinyCBackend:
|
when hasTinyCBackend:
|
||||||
if gCmd == cmdRun:
|
if gCmd == cmdRun:
|
||||||
tccgen.compileCCode(ropeToStr(code))
|
tccgen.compileCCode($code)
|
||||||
return
|
return
|
||||||
|
|
||||||
if shouldRecompile(code, cfile):
|
if shouldRecompile(code, cfile):
|
||||||
|
|
|
||||||
|
|
@ -436,7 +436,7 @@ proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
||||||
if not isVisible(nameNode): return
|
if not isVisible(nameNode): return
|
||||||
var
|
var
|
||||||
name = getName(d, nameNode)
|
name = getName(d, nameNode)
|
||||||
comm = genRecComment(d, n).ropeToStr()
|
comm = $genRecComment(d, n)
|
||||||
r: TSrcGen
|
r: TSrcGen
|
||||||
|
|
||||||
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
|
||||||
|
|
@ -635,7 +635,7 @@ proc commandJSON*() =
|
||||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||||
d.hasToc = true
|
d.hasToc = true
|
||||||
var json = generateJson(d, ast)
|
var json = generateJson(d, ast)
|
||||||
var content = newRope(pretty(json))
|
var content = toRope(pretty(json))
|
||||||
|
|
||||||
if optStdout in gGlobalOptions:
|
if optStdout in gGlobalOptions:
|
||||||
writeRope(stdout, content)
|
writeRope(stdout, content)
|
||||||
|
|
|
||||||
|
|
@ -874,7 +874,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
|
if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
|
||||||
var f = b.sons[1].sym
|
var f = b.sons[1].sym
|
||||||
if f.loc.r == nil: f.loc.r = mangleName(f)
|
if f.loc.r == nil: f.loc.r = mangleName(f)
|
||||||
r.res = makeJSString(ropeToStr(f.loc.r))
|
r.res = makeJSString($f.loc.r)
|
||||||
internalAssert a.typ != etyBaseIndex
|
internalAssert a.typ != etyBaseIndex
|
||||||
r.address = a.res
|
r.address = a.res
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
|
||||||
|
|
@ -494,20 +494,16 @@ proc toCChar*(c: char): string =
|
||||||
else: result = $(c)
|
else: result = $(c)
|
||||||
|
|
||||||
proc makeCString*(s: string): PRope =
|
proc makeCString*(s: string): PRope =
|
||||||
# BUGFIX: We have to split long strings into many ropes. Otherwise
|
|
||||||
# this could trigger an internalError(). See the ropes module for
|
|
||||||
# further information.
|
|
||||||
const
|
const
|
||||||
MaxLineLength = 64
|
MaxLineLength = 64
|
||||||
result = nil
|
result = nil
|
||||||
var res = "\""
|
var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
|
||||||
|
add(res, "\"")
|
||||||
for i in countup(0, len(s) - 1):
|
for i in countup(0, len(s) - 1):
|
||||||
if (i + 1) mod MaxLineLength == 0:
|
if (i + 1) mod MaxLineLength == 0:
|
||||||
add(res, '\"')
|
add(res, '\"')
|
||||||
add(res, tnl)
|
add(res, tnl)
|
||||||
app(result, toRope(res)) # reset:
|
add(res, '\"')
|
||||||
setLen(res, 1)
|
|
||||||
res[0] = '\"'
|
|
||||||
add(res, toCChar(s[i]))
|
add(res, toCChar(s[i]))
|
||||||
add(res, '\"')
|
add(res, '\"')
|
||||||
app(result, toRope(res))
|
app(result, toRope(res))
|
||||||
|
|
@ -776,7 +772,7 @@ proc rawMessage*(msg: TMsgKind, arg: string) =
|
||||||
|
|
||||||
proc writeSurroundingSrc(info: TLineInfo) =
|
proc writeSurroundingSrc(info: TLineInfo) =
|
||||||
const indent = " "
|
const indent = " "
|
||||||
msgWriteln(indent & info.sourceLine.ropeToStr)
|
msgWriteln(indent & $info.sourceLine)
|
||||||
msgWriteln(indent & spaces(info.col) & '^')
|
msgWriteln(indent & spaces(info.col) & '^')
|
||||||
|
|
||||||
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||||
|
|
@ -877,8 +873,6 @@ ropes.errorHandler = proc (err: TRopesError, msg: string, useWarning: bool) =
|
||||||
case err
|
case err
|
||||||
of rInvalidFormatStr:
|
of rInvalidFormatStr:
|
||||||
internalError("ropes: invalid format string: " & msg)
|
internalError("ropes: invalid format string: " & msg)
|
||||||
of rTokenTooLong:
|
|
||||||
internalError("ropes: token too long: " & msg)
|
|
||||||
of rCannotOpenFile:
|
of rCannotOpenFile:
|
||||||
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
|
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ proc validateExternCName(s: PSym, info: TLineInfo) =
|
||||||
## Valid identifiers are those alphanumeric including the underscore not
|
## Valid identifiers are those alphanumeric including the underscore not
|
||||||
## starting with a number. If the check fails, a generic error will be
|
## starting with a number. If the check fails, a generic error will be
|
||||||
## displayed to the user.
|
## displayed to the user.
|
||||||
let target = ropeToStr(s.loc.r)
|
let target = $s.loc.r
|
||||||
if target.len < 1 or target[0] notin IdentStartChars or
|
if target.len < 1 or target[0] notin IdentStartChars or
|
||||||
not target.allCharsInSet(IdentChars):
|
not target.allCharsInSet(IdentChars):
|
||||||
localError(info, errGenerated, "invalid exported symbol")
|
localError(info, errGenerated, "invalid exported symbol")
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
||||||
pushType(w, loc.t)
|
pushType(w, loc.t)
|
||||||
if loc.r != nil:
|
if loc.r != nil:
|
||||||
add(result, '!')
|
add(result, '!')
|
||||||
encodeStr(ropeToStr(loc.r), result)
|
encodeStr($loc.r, result)
|
||||||
if oldLen + 1 == result.len:
|
if oldLen + 1 == result.len:
|
||||||
# no data was necessary, so remove the '<' again:
|
# no data was necessary, so remove the '<' again:
|
||||||
setLen(result, oldLen)
|
setLen(result, oldLen)
|
||||||
|
|
@ -241,7 +241,7 @@ proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
|
||||||
add(result, '|')
|
add(result, '|')
|
||||||
encodeVInt(ord(lib.kind), result)
|
encodeVInt(ord(lib.kind), result)
|
||||||
add(result, '|')
|
add(result, '|')
|
||||||
encodeStr(ropeToStr(lib.name), result)
|
encodeStr($lib.name, result)
|
||||||
add(result, '|')
|
add(result, '|')
|
||||||
encodeNode(w, info, lib.path, result)
|
encodeNode(w, info, lib.path, result)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,77 +56,63 @@
|
||||||
# To cache them they are inserted in a `cache` array.
|
# To cache them they are inserted in a `cache` array.
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, platform, hashes, crc, options
|
platform, hashes
|
||||||
|
|
||||||
type
|
type
|
||||||
TFormatStr* = string # later we may change it to CString for better
|
FormatStr* = string # later we may change it to CString for better
|
||||||
# performance of the code generator (assignments
|
# performance of the code generator (assignments
|
||||||
# copy the format strings
|
# copy the format strings
|
||||||
# though it is not necessary)
|
# though it is not necessary)
|
||||||
PRope* = ref TRope
|
Rope* = ref RopeObj
|
||||||
TRope*{.acyclic.} = object of RootObj # the empty rope is represented
|
RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
|
||||||
# by nil to safe space
|
# by nil to safe space
|
||||||
left*, right*: PRope
|
left*, right*: Rope
|
||||||
length*: int
|
length*: int
|
||||||
data*: string # != nil if a leaf
|
data*: string # != nil if a leaf
|
||||||
|
|
||||||
TRopeSeq* = seq[PRope]
|
RopeSeq* = seq[Rope]
|
||||||
|
|
||||||
TRopesError* = enum
|
RopesError* = enum
|
||||||
rCannotOpenFile
|
rCannotOpenFile
|
||||||
rInvalidFormatStr
|
rInvalidFormatStr
|
||||||
rTokenTooLong
|
|
||||||
|
|
||||||
proc con*(a, b: PRope): PRope
|
{.deprecated: [TFormatStr: FormatStr].}
|
||||||
proc con*(a: PRope, b: string): PRope
|
{.deprecated: [PRope: Rope].}
|
||||||
proc con*(a: string, b: PRope): PRope
|
{.deprecated: [TRopeSeq: RopeSeq].}
|
||||||
proc con*(a: varargs[PRope]): PRope
|
{.deprecated: [TRopesError: RopesError].}
|
||||||
proc app*(a: var PRope, b: PRope)
|
|
||||||
proc app*(a: var PRope, b: string)
|
|
||||||
proc prepend*(a: var PRope, b: PRope)
|
|
||||||
proc toRope*(s: string): PRope
|
|
||||||
proc toRope*(i: BiggestInt): PRope
|
|
||||||
proc ropeLen*(a: PRope): int
|
|
||||||
proc writeRopeIfNotEqual*(r: PRope, filename: string): bool
|
|
||||||
proc ropeToStr*(p: PRope): string
|
|
||||||
proc ropef*(frmt: TFormatStr, args: varargs[PRope]): PRope
|
|
||||||
proc appf*(c: var PRope, frmt: TFormatStr, args: varargs[PRope])
|
|
||||||
proc ropeEqualsFile*(r: PRope, f: string): bool
|
|
||||||
# returns true if the rope r is the same as the contents of file f
|
|
||||||
proc ropeInvariant*(r: PRope): bool
|
|
||||||
# exported for debugging
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
var errorHandler*: proc(err: TRopesError, msg: string, useWarning = false)
|
var errorHandler*: proc(err: RopesError, msg: string, useWarning = false)
|
||||||
# avoid dependency on msgs.nim
|
# avoid dependency on msgs.nim
|
||||||
|
|
||||||
proc ropeLen(a: PRope): int =
|
proc len*(a: Rope): int =
|
||||||
if a == nil: result = 0
|
if a == nil: result = 0
|
||||||
else: result = a.length
|
else: result = a.length
|
||||||
|
|
||||||
proc newRope*(data: string = nil): PRope =
|
proc newRope(data: string = nil): Rope =
|
||||||
new(result)
|
new(result)
|
||||||
if data != nil:
|
if data != nil:
|
||||||
result.length = len(data)
|
result.length = len(data)
|
||||||
result.data = data
|
result.data = data
|
||||||
|
|
||||||
proc newMutableRope*(capacity = 30): PRope =
|
proc newMutableRope*(capacity = 30): Rope =
|
||||||
## creates a new rope that supports direct modifications of the rope's
|
## creates a new rope that supports direct modifications of the rope's
|
||||||
## 'data' and 'length' fields.
|
## 'data' and 'length' fields.
|
||||||
new(result)
|
new(result)
|
||||||
result.data = newStringOfCap(capacity)
|
result.data = newStringOfCap(capacity)
|
||||||
|
|
||||||
proc freezeMutableRope*(r: PRope) {.inline.} =
|
proc freezeMutableRope*(r: Rope) {.inline.} =
|
||||||
r.length = r.data.len
|
r.length = r.data.len
|
||||||
|
|
||||||
var
|
var
|
||||||
cache: array[0..2048*2 - 1, PRope]
|
cache: array[0..2048*2 - 1, Rope]
|
||||||
|
|
||||||
proc resetRopeCache* =
|
proc resetRopeCache* =
|
||||||
for i in low(cache)..high(cache):
|
for i in low(cache)..high(cache):
|
||||||
cache[i] = nil
|
cache[i] = nil
|
||||||
|
|
||||||
proc ropeInvariant(r: PRope): bool =
|
proc ropeInvariant(r: Rope): bool =
|
||||||
if r == nil:
|
if r == nil:
|
||||||
result = true
|
result = true
|
||||||
else:
|
else:
|
||||||
|
|
@ -143,7 +129,7 @@ var gCacheTries* = 0
|
||||||
var gCacheMisses* = 0
|
var gCacheMisses* = 0
|
||||||
var gCacheIntTries* = 0
|
var gCacheIntTries* = 0
|
||||||
|
|
||||||
proc insertInCache(s: string): PRope =
|
proc insertInCache(s: string): Rope =
|
||||||
inc gCacheTries
|
inc gCacheTries
|
||||||
var h = hash(s) and high(cache)
|
var h = hash(s) and high(cache)
|
||||||
result = cache[h]
|
result = cache[h]
|
||||||
|
|
@ -152,14 +138,27 @@ proc insertInCache(s: string): PRope =
|
||||||
result = newRope(s)
|
result = newRope(s)
|
||||||
cache[h] = result
|
cache[h] = result
|
||||||
|
|
||||||
proc toRope(s: string): PRope =
|
proc rope*(s: string): Rope =
|
||||||
if s.len == 0:
|
if s.len == 0:
|
||||||
result = nil
|
result = nil
|
||||||
else:
|
else:
|
||||||
result = insertInCache(s)
|
result = insertInCache(s)
|
||||||
assert(ropeInvariant(result))
|
assert(ropeInvariant(result))
|
||||||
|
|
||||||
proc ropeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) =
|
proc rope*(i: BiggestInt): Rope =
|
||||||
|
inc gCacheIntTries
|
||||||
|
result = rope($i)
|
||||||
|
|
||||||
|
proc rope*(f: BiggestFloat): Rope =
|
||||||
|
result = rope($f)
|
||||||
|
|
||||||
|
# TODO Old names - change invokations to rope
|
||||||
|
proc toRope*(s: string): Rope {.deprecated.} =
|
||||||
|
result = rope(s)
|
||||||
|
proc toRope*(i: BiggestInt): Rope {.deprecated.} =
|
||||||
|
result = rope(i)
|
||||||
|
|
||||||
|
proc ropeSeqInsert(rs: var RopeSeq, r: Rope, at: Natural) =
|
||||||
var length = len(rs)
|
var length = len(rs)
|
||||||
if at > length:
|
if at > length:
|
||||||
setLen(rs, at + 1)
|
setLen(rs, at + 1)
|
||||||
|
|
@ -169,7 +168,7 @@ proc ropeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) =
|
||||||
rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
|
rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
|
||||||
rs[at] = r
|
rs[at] = r
|
||||||
|
|
||||||
proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) =
|
proc newRecRopeToStr(result: var string, resultLen: var int, r: Rope) =
|
||||||
var stack = @[r]
|
var stack = @[r]
|
||||||
while len(stack) > 0:
|
while len(stack) > 0:
|
||||||
var it = pop(stack)
|
var it = pop(stack)
|
||||||
|
|
@ -181,7 +180,33 @@ proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) =
|
||||||
inc(resultLen, it.length)
|
inc(resultLen, it.length)
|
||||||
assert(resultLen <= len(result))
|
assert(resultLen <= len(result))
|
||||||
|
|
||||||
proc ropeToStr(p: PRope): string =
|
proc `&`*(a, b: Rope): Rope =
|
||||||
|
if a == nil:
|
||||||
|
result = b
|
||||||
|
elif b == nil:
|
||||||
|
result = a
|
||||||
|
else:
|
||||||
|
result = newRope()
|
||||||
|
result.length = a.length + b.length
|
||||||
|
result.left = a
|
||||||
|
result.right = b
|
||||||
|
|
||||||
|
proc `&`*(a: Rope, b: string): Rope =
|
||||||
|
result = a & rope(b)
|
||||||
|
|
||||||
|
proc `&`*(a: string, b: Rope): Rope =
|
||||||
|
result = rope(a) & b
|
||||||
|
|
||||||
|
proc `&`*(a: openArray[Rope]): Rope =
|
||||||
|
for i in countup(0, high(a)): result = result & a[i]
|
||||||
|
|
||||||
|
proc add*(a: var Rope, b: Rope) =
|
||||||
|
a = a & b
|
||||||
|
|
||||||
|
proc add*(a: var Rope, b: string) =
|
||||||
|
a = a & b
|
||||||
|
|
||||||
|
proc `$`*(p: Rope): string =
|
||||||
if p == nil:
|
if p == nil:
|
||||||
result = ""
|
result = ""
|
||||||
else:
|
else:
|
||||||
|
|
@ -189,34 +214,24 @@ proc ropeToStr(p: PRope): string =
|
||||||
var resultLen = 0
|
var resultLen = 0
|
||||||
newRecRopeToStr(result, resultLen, p)
|
newRecRopeToStr(result, resultLen, p)
|
||||||
|
|
||||||
proc con(a, b: PRope): PRope =
|
# TODO Old names - change invokations to `&`
|
||||||
if a == nil: result = b
|
proc con*(a, b: Rope): Rope {.deprecated.} = a & b
|
||||||
elif b == nil: result = a
|
proc con*(a: Rope, b: string): Rope {.deprecated.} = a & b
|
||||||
else:
|
proc con*(a: string, b: Rope): Rope {.deprecated.} = a & b
|
||||||
result = newRope()
|
proc con*(a: varargs[Rope]): Rope {.deprecated.} = `&`(a)
|
||||||
result.length = a.length + b.length
|
|
||||||
result.left = a
|
|
||||||
result.right = b
|
|
||||||
|
|
||||||
proc con(a: PRope, b: string): PRope = result = con(a, toRope(b))
|
proc ropeConcat*(a: varargs[Rope]): Rope =
|
||||||
proc con(a: string, b: PRope): PRope = result = con(toRope(a), b)
|
|
||||||
|
|
||||||
proc con(a: varargs[PRope]): PRope =
|
|
||||||
for i in countup(0, high(a)): result = con(result, a[i])
|
|
||||||
|
|
||||||
proc ropeConcat*(a: varargs[PRope]): PRope =
|
|
||||||
# not overloaded version of concat to speed-up `rfmt` a little bit
|
# not overloaded version of concat to speed-up `rfmt` a little bit
|
||||||
for i in countup(0, high(a)): result = con(result, a[i])
|
for i in countup(0, high(a)): result = con(result, a[i])
|
||||||
|
|
||||||
proc toRope(i: BiggestInt): PRope =
|
# TODO Old names - change invokations to add
|
||||||
inc gCacheIntTries
|
proc app*(a: var Rope, b: Rope) {.deprecated.} = add(a, b)
|
||||||
result = toRope($i)
|
proc app*(a: var Rope, b: string) {.deprecated.} = add(a, b)
|
||||||
|
|
||||||
proc app(a: var PRope, b: PRope) = a = con(a, b)
|
proc prepend*(a: var Rope, b: Rope) = a = b & a
|
||||||
proc app(a: var PRope, b: string) = a = con(a, b)
|
proc prepend*(a: var Rope, b: string) = a = b & a
|
||||||
proc prepend(a: var PRope, b: PRope) = a = con(b, a)
|
|
||||||
|
|
||||||
proc writeRope*(f: File, c: PRope) =
|
proc writeRope*(f: File, c: Rope) =
|
||||||
var stack = @[c]
|
var stack = @[c]
|
||||||
while len(stack) > 0:
|
while len(stack) > 0:
|
||||||
var it = pop(stack)
|
var it = pop(stack)
|
||||||
|
|
@ -227,7 +242,7 @@ proc writeRope*(f: File, c: PRope) =
|
||||||
assert(it.data != nil)
|
assert(it.data != nil)
|
||||||
write(f, it.data)
|
write(f, it.data)
|
||||||
|
|
||||||
proc writeRope*(head: PRope, filename: string, useWarning = false) =
|
proc writeRope*(head: Rope, filename: string, useWarning = false) =
|
||||||
var f: File
|
var f: File
|
||||||
if open(f, filename, fmWrite):
|
if open(f, filename, fmWrite):
|
||||||
if head != nil: writeRope(f, head)
|
if head != nil: writeRope(f, head)
|
||||||
|
|
@ -239,38 +254,52 @@ var
|
||||||
rnl* = tnl.newRope
|
rnl* = tnl.newRope
|
||||||
softRnl* = tnl.newRope
|
softRnl* = tnl.newRope
|
||||||
|
|
||||||
proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
|
proc `%`*(frmt: TFormatStr, args: openArray[Rope]): Rope =
|
||||||
var i = 0
|
var i = 0
|
||||||
var length = len(frmt)
|
var length = len(frmt)
|
||||||
result = nil
|
result = nil
|
||||||
var num = 0
|
var num = 0
|
||||||
while i <= length - 1:
|
while i < length:
|
||||||
if frmt[i] == '$':
|
if frmt[i] == '$':
|
||||||
inc(i) # skip '$'
|
inc(i) # skip '$'
|
||||||
case frmt[i]
|
case frmt[i]
|
||||||
of '$':
|
of '$':
|
||||||
app(result, "$")
|
add(result, "$")
|
||||||
inc(i)
|
inc(i)
|
||||||
of '#':
|
of '#':
|
||||||
inc(i)
|
inc(i)
|
||||||
app(result, args[num])
|
add(result, args[num])
|
||||||
inc(num)
|
inc(num)
|
||||||
of '0'..'9':
|
of '0'..'9':
|
||||||
var j = 0
|
var j = 0
|
||||||
while true:
|
while true:
|
||||||
j = (j * 10) + ord(frmt[i]) - ord('0')
|
j = j * 10 + ord(frmt[i]) - ord('0')
|
||||||
inc(i)
|
inc(i)
|
||||||
if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
|
if frmt[i] notin {'0'..'9'}: break
|
||||||
num = j
|
num = j
|
||||||
if j > high(args) + 1:
|
if j > high(args) + 1:
|
||||||
errorHandler(rInvalidFormatStr, $(j))
|
errorHandler(rInvalidFormatStr, $(j))
|
||||||
else:
|
else:
|
||||||
app(result, args[j - 1])
|
add(result, 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: errorHandler(rInvalidFormatStr, $(frmt[i]))
|
||||||
|
|
||||||
|
if j > high(args) + 1:
|
||||||
|
errorHandler(rInvalidFormatStr, $(j))
|
||||||
|
else:
|
||||||
|
add(result, args[j-1])
|
||||||
of 'n':
|
of 'n':
|
||||||
app(result, softRnl)
|
add(result, softRnl)
|
||||||
inc i
|
inc(i)
|
||||||
of 'N':
|
of 'N':
|
||||||
app(result, rnl)
|
add(result, rnl)
|
||||||
inc(i)
|
inc(i)
|
||||||
else:
|
else:
|
||||||
errorHandler(rInvalidFormatStr, $(frmt[i]))
|
errorHandler(rInvalidFormatStr, $(frmt[i]))
|
||||||
|
|
@ -279,83 +308,74 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||||
if frmt[i] != '$': inc(i)
|
if frmt[i] != '$': inc(i)
|
||||||
else: break
|
else: break
|
||||||
if i - 1 >= start:
|
if i - 1 >= start:
|
||||||
app(result, substr(frmt, start, i - 1))
|
add(result, substr(frmt, start, i - 1))
|
||||||
assert(ropeInvariant(result))
|
assert(ropeInvariant(result))
|
||||||
|
|
||||||
|
proc addf*(c: var Rope, frmt: TFormatStr, args: openArray[Rope]) =
|
||||||
|
add(c, frmt % args)
|
||||||
|
|
||||||
|
# TODO Compatibility names
|
||||||
|
proc ropef*(frmt: TFormatStr, args: varargs[Rope]): Rope {.deprecated.} =
|
||||||
|
result = frmt % args
|
||||||
|
proc appf*(c: var Rope, frmt: TFormatStr, args: varargs[Rope]) {.deprecated.} =
|
||||||
|
addf(c, frmt, args)
|
||||||
|
|
||||||
when true:
|
when true:
|
||||||
template `~`*(r: string): PRope = r.ropef
|
template `~`*(r: string): Rope = r.ropef
|
||||||
else:
|
else:
|
||||||
{.push stack_trace: off, line_trace: off.}
|
{.push stack_trace: off, line_trace: off.}
|
||||||
proc `~`*(r: static[string]): PRope =
|
proc `~`*(r: static[string]): Rope =
|
||||||
# this is the new optimized "to rope" operator
|
# this is the new optimized "to rope" operator
|
||||||
# the mnemonic is that `~` looks a bit like a rope :)
|
# the mnemonic is that `~` looks a bit like a rope :)
|
||||||
var r {.global.} = r.ropef
|
var r {.global.} = r.ropef
|
||||||
return r
|
return r
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
|
|
||||||
app(c, ropef(frmt, args))
|
|
||||||
|
|
||||||
const
|
const
|
||||||
bufSize = 1024 # 1 KB is reasonable
|
bufSize = 1024 # 1 KB is reasonable
|
||||||
|
|
||||||
proc auxRopeEqualsFile(r: PRope, bin: var File, buf: pointer): bool =
|
proc auxEqualsFile(r: Rope, f: File, buf: var array[bufSize, char],
|
||||||
|
bpos, blen: var int): bool =
|
||||||
if r.data != nil:
|
if r.data != nil:
|
||||||
if r.length > bufSize:
|
var dpos = 0
|
||||||
errorHandler(rTokenTooLong, r.data)
|
let dlen = r.data.len
|
||||||
return
|
while dpos < dlen:
|
||||||
var readBytes = readBuffer(bin, buf, r.length)
|
if bpos == blen:
|
||||||
result = readBytes == r.length and
|
# Read more data
|
||||||
equalMem(buf, addr(r.data[0]), r.length) # BUGFIX
|
bpos = 0
|
||||||
|
blen = readBuffer(f, addr(buf[0]), buf.len)
|
||||||
|
if blen == 0: # no more data in file
|
||||||
|
result = false
|
||||||
|
return
|
||||||
|
let n = min(blen - bpos, dlen - dpos)
|
||||||
|
if not equalMem(addr(buf[bpos]), addr(r.data[dpos]), n):
|
||||||
|
result = false
|
||||||
|
return
|
||||||
|
dpos += n
|
||||||
|
bpos += n
|
||||||
|
result = true
|
||||||
else:
|
else:
|
||||||
result = auxRopeEqualsFile(r.left, bin, buf)
|
result = auxEqualsFile(r.left, f, buf, bpos, blen) and
|
||||||
if result: result = auxRopeEqualsFile(r.right, bin, buf)
|
auxEqualsFile(r.right, f, buf, bpos, blen)
|
||||||
|
|
||||||
proc ropeEqualsFile(r: PRope, f: string): bool =
|
proc equalsFile*(r: Rope, f: File): bool =
|
||||||
var bin: File
|
var
|
||||||
result = open(bin, f)
|
buf: array[bufSize, char]
|
||||||
if not result:
|
bpos = bufSize
|
||||||
return # not equal if file does not exist
|
blen = bufSize
|
||||||
var buf = alloc(bufSize)
|
result = auxEqualsFile(r, f, buf, bpos, blen) and
|
||||||
result = auxRopeEqualsFile(r, bin, buf)
|
readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all
|
||||||
|
|
||||||
|
proc equalsFile*(r: Rope, filename: string): bool =
|
||||||
|
var f: File
|
||||||
|
result = open(f, filename)
|
||||||
if result:
|
if result:
|
||||||
result = readBuffer(bin, buf, bufSize) == 0 # really at the end of file?
|
result = equalsFile(r, f)
|
||||||
dealloc(buf)
|
close(f)
|
||||||
close(bin)
|
|
||||||
|
|
||||||
proc crcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 =
|
proc writeRopeIfNotEqual*(r: Rope, filename: string): bool =
|
||||||
if r.data != nil:
|
|
||||||
result = startVal
|
|
||||||
for i in countup(0, len(r.data) - 1):
|
|
||||||
result = updateCrc32(r.data[i], result)
|
|
||||||
else:
|
|
||||||
result = crcFromRopeAux(r.left, startVal)
|
|
||||||
result = crcFromRopeAux(r.right, result)
|
|
||||||
|
|
||||||
proc newCrcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 =
|
|
||||||
# XXX profiling shows this is actually expensive
|
|
||||||
var stack: TRopeSeq = @[r]
|
|
||||||
result = startVal
|
|
||||||
while len(stack) > 0:
|
|
||||||
var it = pop(stack)
|
|
||||||
while it.data == nil:
|
|
||||||
add(stack, it.right)
|
|
||||||
it = it.left
|
|
||||||
assert(it.data != nil)
|
|
||||||
var i = 0
|
|
||||||
var L = len(it.data)
|
|
||||||
while i < L:
|
|
||||||
result = updateCrc32(it.data[i], result)
|
|
||||||
inc(i)
|
|
||||||
|
|
||||||
proc crcFromRope(r: PRope): TCrc32 =
|
|
||||||
result = newCrcFromRopeAux(r, InitCrc32)
|
|
||||||
|
|
||||||
proc writeRopeIfNotEqual(r: PRope, filename: string): bool =
|
|
||||||
# returns true if overwritten
|
# returns true if overwritten
|
||||||
var c: TCrc32
|
if not equalsFile(r, filename):
|
||||||
c = crcFromFile(filename)
|
|
||||||
if c != crcFromRope(r):
|
|
||||||
writeRope(r, filename)
|
writeRope(r, filename)
|
||||||
result = true
|
result = true
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -325,6 +325,7 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
|
||||||
inc(i)
|
inc(i)
|
||||||
if frmt[i] == '}': inc(i)
|
if frmt[i] == '}': inc(i)
|
||||||
else: raise newException(ValueError, "invalid format string")
|
else: raise newException(ValueError, "invalid format string")
|
||||||
|
|
||||||
add(result, args[j-1])
|
add(result, args[j-1])
|
||||||
else: raise newException(ValueError, "invalid format string")
|
else: raise newException(ValueError, "invalid format string")
|
||||||
var start = i
|
var start = i
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue