diff options
author | Zahary Karadjov <zahary@gmail.com> | 2012-11-21 17:49:50 +0200 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2012-11-28 01:15:13 +0200 |
commit | f644e3079f451c1ee71376ada120a789c696423b (patch) | |
tree | f9bf8071693127ebe4bfb31eb4bca93140234618 /compiler | |
parent | e6f3f46cd94325253f9ade2e8fb39a494fce5072 (diff) | |
download | Nim-f644e3079f451c1ee71376ada120a789c696423b.tar.gz |
experimental compile-time rope formatting code
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/cgen.nim | 76 | ||||
-rwxr-xr-x | compiler/main.nim | 5 | ||||
-rwxr-xr-x | compiler/ropes.nim | 25 |
3 files changed, 102 insertions, 4 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 3a8df7bd8..0a903f95b 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -106,10 +106,10 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope = internalError("ropes: invalid format string $" & $j) app(result, args[j-1]) of 'n': - if optLineDir notin gOptions: app(result, tnl) + if optLineDir notin gOptions: app(result, rnl) inc(i) of 'N': - app(result, tnl) + app(result, rnl) inc(i) else: InternalError("ropes: invalid format string $" & frmt[i]) 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: 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, args: varargs[PRope]) = app(c, ropecg(m, frmt, args)) @@ -164,6 +232,10 @@ proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr, args: varargs[PRope]) = 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, args: varargs[PRope]) = app(r, indentLine(p, ropecg(p.module, frmt, args))) diff --git a/compiler/main.nim b/compiler/main.nim index 15fa8b4fb..96ebfc5ef 100755 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -501,3 +501,8 @@ proc MainCommand = formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3), formatSize(getTotalMem())]) + echo "rope cache stats: " + echo " tries : ", gCacheTries + echo " misses: ", gCacheMisses + echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float), ffDecimal, 3) + diff --git a/compiler/ropes.nim b/compiler/ropes.nim index 50c89e4d9..a539418ca 100755 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -127,10 +127,15 @@ proc RopeInvariant(r: PRope): bool = # if result then result := ropeInvariant(r.right); # end +var gCacheTries* = 0 +var gCacheMisses* = 0 + proc insertInCache(s: string): PRope = + inc gCacheTries var h = hash(s) and high(cache) result = cache[h] if isNil(result) or result.data != s: + inc gCacheMisses result = newRope(s) 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 = 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 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, filename) +var + rnl* = tnl.newRope + softRnl* = tnl.newRope + proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope = var i = 0 var length = len(frmt) @@ -240,10 +253,10 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope = else: app(result, args[j - 1]) of 'n': - if optLineDir notin gOptions: app(result, tnl) + app(result, softRnl) inc i of 'N': - app(result, tnl) + app(result, rnl) inc(i) else: InternalError("ropes: invalid format string $" & frmt[i]) var start = i @@ -254,6 +267,14 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope = app(result, substr(frmt, start, i - 1)) 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]) = app(c, ropef(frmt, args)) |