diff options
author | shirleyquirk <31934565+shirleyquirk@users.noreply.github.com> | 2021-04-11 12:07:23 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-11 13:07:23 +0200 |
commit | a5b30c94c2dcd0f17b37685d9ce96eee959ba554 (patch) | |
tree | 11574c4f4aa4157ce48077b1768b3f4d4357d397 | |
parent | 3aaec0647b6c924ea1da18e8427f13289ebab980 (diff) | |
download | Nim-a5b30c94c2dcd0f17b37685d9ce96eee959ba554.tar.gz |
[feature] add arbitrary code execution to strformat (#17694)
* changed parser to ignore ':' within parens * Update strformat.nim * Update lib/pure/strformat.nim Co-authored-by: flywind <xzsflywind@gmail.com> Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
-rw-r--r-- | lib/pure/strformat.nim | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim index 7ab359038..c232c8a46 100644 --- a/lib/pure/strformat.nim +++ b/lib/pure/strformat.nim @@ -74,6 +74,20 @@ runnableExamples: assert fmt"{123.456:13e}" == " 1.234560e+02" ##[ +# Expressions +]## +runnableExamples: + let x = 3.14 + assert fmt"{(if x!=0: 1.0/x else: 0):.5}" == "0.31847" + assert fmt"""{(block: + var res: string + for i in 1..15: + res.add (if i mod 15 == 0: "FizzBuzz" + elif i mod 5 == 0: "Buzz" + elif i mod 3 == 0: "Fizz" + else: $i) & " " + res)}""" == "1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz " +##[ # Debugging strings `fmt"{expr=}"` expands to `fmt"expr={expr}"` namely the text of the expression, @@ -557,7 +571,7 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = # XXX: https://github.com/nim-lang/Nim/issues/8405 # When compiling with -d:useNimRtl, certain procs such as `count` from the strutils # module are not accessible at compile-time: - let expectedGrowth = when defined(useNimRtl): 0 else: count(f, '{') * 10 + let expectedGrowth = when defined(useNimRtl): 0 else: count(f, openChar) * 10 result.add newVarStmt(res, newCall(bindSym"newStringOfCap", newLit(f.len + expectedGrowth))) var strlit = "" @@ -573,8 +587,12 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = strlit = "" var subexpr = "" - while i < f.len and f[i] != closeChar and f[i] != ':': - if f[i] == '=': + var inParens = 0 + while i < f.len and f[i] != closeChar and (f[i] != ':' or inParens!=0): + case f[i] + of '(': inc inParens + of ')': dec inParens + of '=': let start = i inc i i += f.skipWhitespace(i) @@ -582,10 +600,11 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = result.add newCall(bindSym"add", res, newLit(subexpr & f[start ..< i])) else: subexpr.add f[start ..< i] - else: - subexpr.add f[i] - inc i - + continue + else: discard + subexpr.add f[i] + inc i + var x: NimNode try: x = parseExpr(subexpr) @@ -608,11 +627,11 @@ proc strformatImpl(pattern: NimNode; openChar, closeChar: char): NimNode = doAssert false, "invalid format string: missing '}'" result.add newCall(formatSym, res, x, newLit(options)) elif f[i] == closeChar: - if f[i+1] == closeChar: + if i<f.len-1 and f[i+1] == closeChar: strlit.add closeChar inc i, 2 else: - doAssert false, "invalid format string: '}' instead of '}}'" + doAssert false, "invalid format string: '$1' instead of '$1$1'" % $closeChar inc i else: strlit.add f[i] |