mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-06 20:04:18 +00:00
[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>
This commit is contained in:
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user