experimental compile-time rope formatting code
This commit is contained in:
parent
e6f3f46cd9
commit
f644e3079f
3 changed files with 102 additions and 4 deletions
|
|
@ -106,10 +106,10 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||||
internalError("ropes: invalid format string $" & $j)
|
internalError("ropes: invalid format string $" & $j)
|
||||||
app(result, args[j-1])
|
app(result, args[j-1])
|
||||||
of 'n':
|
of 'n':
|
||||||
if optLineDir notin gOptions: app(result, tnl)
|
if optLineDir notin gOptions: app(result, rnl)
|
||||||
inc(i)
|
inc(i)
|
||||||
of 'N':
|
of 'N':
|
||||||
app(result, tnl)
|
app(result, rnl)
|
||||||
inc(i)
|
inc(i)
|
||||||
else: InternalError("ropes: invalid format string $" & frmt[i])
|
else: InternalError("ropes: invalid format string $" & frmt[i])
|
||||||
elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
|
elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
|
||||||
|
|
@ -133,6 +133,74 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||||
if i - 1 >= start:
|
if i - 1 >= start:
|
||||||
app(result, substr(frmt, start, i - 1))
|
app(result, substr(frmt, start, i - 1))
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
type TFmtFragmentKind = enum
|
||||||
|
ffSym,
|
||||||
|
ffLit,
|
||||||
|
ffParam
|
||||||
|
|
||||||
|
type TFragment = object
|
||||||
|
case kind: TFmtFragmentKind
|
||||||
|
of ffSym, ffLit:
|
||||||
|
value: string
|
||||||
|
of ffParam:
|
||||||
|
intValue: int
|
||||||
|
|
||||||
|
iterator fmtStringFragments(s: string): tuple[kind: TFmtFragmentKind,
|
||||||
|
value: string,
|
||||||
|
intValue: int] =
|
||||||
|
# This is a bit less featured version of the ropecg's algorithm
|
||||||
|
# (be careful when replacing ropecg calls)
|
||||||
|
var
|
||||||
|
i = 0
|
||||||
|
length = s.len
|
||||||
|
|
||||||
|
while i < length:
|
||||||
|
var start = i
|
||||||
|
case s[i]
|
||||||
|
of '$':
|
||||||
|
let n = s[i+1]
|
||||||
|
case n
|
||||||
|
of '$':
|
||||||
|
inc i, 2
|
||||||
|
of '0'..'9':
|
||||||
|
# XXX: use the new case object construction syntax when it's ready
|
||||||
|
yield (kind: ffParam, value: "", intValue: n.ord - ord('1'))
|
||||||
|
inc i, 2
|
||||||
|
start = i
|
||||||
|
else:
|
||||||
|
inc i
|
||||||
|
of '#':
|
||||||
|
inc i
|
||||||
|
var j = i
|
||||||
|
while s[i] in IdentChars: inc i
|
||||||
|
yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0)
|
||||||
|
start = i
|
||||||
|
else: nil
|
||||||
|
|
||||||
|
while i < length:
|
||||||
|
if s[i] != '$' and s[i] != '#': inc i
|
||||||
|
else: break
|
||||||
|
|
||||||
|
if i - 1 >= start:
|
||||||
|
yield (kind: ffLit, value: substr(s, start, i-1), intValue: 0)
|
||||||
|
|
||||||
|
macro rfmt(m: BModule, fmt: expr[string], args: varargs[PRope]): expr =
|
||||||
|
## Experimental optimized rope-formatting operator
|
||||||
|
## The run-time code it produces will be very fast, but will it speed up
|
||||||
|
## the compilation of nimrod itself or will the macro execution time
|
||||||
|
## offset the gains?
|
||||||
|
result = newCall(bindSym"ropeConcat")
|
||||||
|
for frag in fmtStringFragments(fmt.strVal):
|
||||||
|
case frag.kind
|
||||||
|
of ffSym:
|
||||||
|
result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value)))
|
||||||
|
of ffLit:
|
||||||
|
result.add(newCall(bindSym"~", newStrLitNode(frag.value)))
|
||||||
|
of ffParam:
|
||||||
|
result.add(args[frag.intValue])
|
||||||
|
|
||||||
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
|
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
|
||||||
args: varargs[PRope]) =
|
args: varargs[PRope]) =
|
||||||
app(c, ropecg(m, frmt, args))
|
app(c, ropecg(m, frmt, args))
|
||||||
|
|
@ -164,6 +232,10 @@ proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr,
|
||||||
args: varargs[PRope]) =
|
args: varargs[PRope]) =
|
||||||
app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
|
app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
|
||||||
|
|
||||||
|
template lineCg2(p: BProc, s: TCProcSection, frmt: TFormatStr,
|
||||||
|
args: varargs[PRope]) =
|
||||||
|
line(p, s, rfmt(p.module, frmt, args))
|
||||||
|
|
||||||
proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr,
|
proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr,
|
||||||
args: varargs[PRope]) =
|
args: varargs[PRope]) =
|
||||||
app(r, indentLine(p, ropecg(p.module, frmt, args)))
|
app(r, indentLine(p, ropecg(p.module, frmt, args)))
|
||||||
|
|
|
||||||
|
|
@ -501,3 +501,8 @@ proc MainCommand =
|
||||||
formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
|
formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
|
||||||
formatSize(getTotalMem())])
|
formatSize(getTotalMem())])
|
||||||
|
|
||||||
|
echo "rope cache stats: "
|
||||||
|
echo " tries : ", gCacheTries
|
||||||
|
echo " misses: ", gCacheMisses
|
||||||
|
echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float), ffDecimal, 3)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,10 +127,15 @@ proc RopeInvariant(r: PRope): bool =
|
||||||
# if result then result := ropeInvariant(r.right);
|
# if result then result := ropeInvariant(r.right);
|
||||||
# end
|
# end
|
||||||
|
|
||||||
|
var gCacheTries* = 0
|
||||||
|
var gCacheMisses* = 0
|
||||||
|
|
||||||
proc insertInCache(s: string): PRope =
|
proc insertInCache(s: string): PRope =
|
||||||
|
inc gCacheTries
|
||||||
var h = hash(s) and high(cache)
|
var h = hash(s) and high(cache)
|
||||||
result = cache[h]
|
result = cache[h]
|
||||||
if isNil(result) or result.data != s:
|
if isNil(result) or result.data != s:
|
||||||
|
inc gCacheMisses
|
||||||
result = newRope(s)
|
result = newRope(s)
|
||||||
cache[h] = result
|
cache[h] = result
|
||||||
|
|
||||||
|
|
@ -186,6 +191,10 @@ proc con(a: string, b: PRope): PRope = result = con(toRope(a), b)
|
||||||
proc con(a: varargs[PRope]): PRope =
|
proc con(a: varargs[PRope]): PRope =
|
||||||
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 ropeConcat*(a: varargs[PRope]): PRope =
|
||||||
|
# not overloaded version of concat to speed-up `rfmt` a little bit
|
||||||
|
for i in countup(0, high(a)): result = con(result, a[i])
|
||||||
|
|
||||||
proc toRope(i: BiggestInt): PRope = result = toRope($i)
|
proc toRope(i: BiggestInt): PRope = result = toRope($i)
|
||||||
|
|
||||||
proc app(a: var PRope, b: PRope) = a = con(a, b)
|
proc app(a: var PRope, b: PRope) = a = con(a, b)
|
||||||
|
|
@ -212,6 +221,10 @@ proc WriteRope*(head: PRope, filename: string, useWarning = false) =
|
||||||
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile,
|
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile,
|
||||||
filename)
|
filename)
|
||||||
|
|
||||||
|
var
|
||||||
|
rnl* = tnl.newRope
|
||||||
|
softRnl* = tnl.newRope
|
||||||
|
|
||||||
proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
|
proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||||
var i = 0
|
var i = 0
|
||||||
var length = len(frmt)
|
var length = len(frmt)
|
||||||
|
|
@ -240,10 +253,10 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||||
else:
|
else:
|
||||||
app(result, args[j - 1])
|
app(result, args[j - 1])
|
||||||
of 'n':
|
of 'n':
|
||||||
if optLineDir notin gOptions: app(result, tnl)
|
app(result, softRnl)
|
||||||
inc i
|
inc i
|
||||||
of 'N':
|
of 'N':
|
||||||
app(result, tnl)
|
app(result, rnl)
|
||||||
inc(i)
|
inc(i)
|
||||||
else: InternalError("ropes: invalid format string $" & frmt[i])
|
else: InternalError("ropes: invalid format string $" & frmt[i])
|
||||||
var start = i
|
var start = i
|
||||||
|
|
@ -254,6 +267,14 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||||
app(result, substr(frmt, start, i - 1))
|
app(result, substr(frmt, start, i - 1))
|
||||||
assert(RopeInvariant(result))
|
assert(RopeInvariant(result))
|
||||||
|
|
||||||
|
{.push stack_trace: off, line_trace: off.}
|
||||||
|
proc `~`*(r: expr[string]): PRope =
|
||||||
|
# this is the new optimized "to rope" operator
|
||||||
|
# the mnemonic is that `~` looks a bit like a rope :)
|
||||||
|
var r {.global.} = r.ropef
|
||||||
|
return r
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
|
proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
|
||||||
app(c, ropef(frmt, args))
|
app(c, ropef(frmt, args))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue