Skip to content

Commit

Permalink
Support string interpolation with named holes
Browse files Browse the repository at this point in the history
  • Loading branch information
jwosty committed Dec 4, 2024
1 parent 5abde0a commit 3315d1b
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 5 deletions.
14 changes: 9 additions & 5 deletions src/Fable.FSharp.Logf/logf.fs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@ type StringFormat<'T, 'Result, 'Tuple> = Format<'T, unit, string, 'Result, 'Tupl
// filing an issue would be great!
let printfFmtSpecPattern =
"""%"""
+ """(0|-|\+| )*""" // flags
+ """[0-9]*""" // width
+ """(\.\d+)?""" // precision
+ """[a-zA-Z]""" // type
// flags
+ """(0|-|\+| )*"""
// width
+ """[0-9]*"""
// precision
+ """(\.\d+)?"""
// type (interpolated string holes are special -- they show up as "%P()" -- note the extra parens)
+ """(P\(\)|[a-zA-Z])"""

let netMsgHolePattern =
"""(?<start>"""
Expand Down Expand Up @@ -200,7 +204,7 @@ type private LogfEnv<'Result>(continuation: string -> obj[] -> 'Result) =
// Valid format specifiers will be captured by the named capture group "a", and lone curly braces will be captured
// by the named capture group "b". Later, using the replacement pattern "${a}${b}${b}" causes any occurrences of "a"
// (valid format specifiers) to be placed back into the string as-is, while occurrences of "b" will be doubled (having
// the effect of escaping those lone curly braces.
// the effect of escaping those lone curly braces).
// Examples:
// * Input: "%s{foo}"
// * 1st match: "a" = "%s{foo}", "b" = "", "${a}${b}${b}" = "$s{foo}"
Expand Down
22 changes: 22 additions & 0 deletions tests/FSharp.Logf.Tests/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,28 @@ let allTests =
$"Hello, {Person}"
[]
)
testCase "Interpolated string with one named hole" (fun () ->
let Person = "Sam"
(fun l ->
logfi l $"Hello, {Person}{{Person}}")
|> assertEquivalent
$"Hello, {Person}"
["Person", "Sam"]
)
testCase "Interpolated string with many unnamed parameters" (fun () ->
let A, B, C = "foo", 42, false
(fun l -> logfi l $"A is %s{A}, B is %d{B}, C is %b{C}")
|> assertEquivalent
(sprintf $"A is %s{A}, B is %d{B}, C is %b{C}")
[]
)
testCase "Interpolated string with many named and unnamed parameters" (fun () ->
let A, B, C, D = "foo", 42, false, "bar"
(fun l -> logfi l $"A is %s{A}{{A}}, B is %d{B}, C is %b{C}{{C}}, D is %s{D}")
|> assertEquivalent
$"A is %s{A}, B is %d{B}, C is %b{C}, D is %s{D}"
["A", "foo"; "C", false]
)
let valuesF = caseData [ 5. / 3.; 50. / 3.; 500. / 3.; -(5. / 3.); -42.; 0.; -0.; 42.; Math.PI * 1_000_000.; -Math.PI * 1_000_000.; Math.PI / 1_000_000.; -Math.PI / 1_000_000. ]
let valuesD = caseData [ 0m; 12345.98m; -10m; 0.012m ]
let valuesI = caseData [ 0xdeadbeef; 42 ]
Expand Down

0 comments on commit 3315d1b

Please sign in to comment.