Skip to content

Instantly share code, notes, and snippets.

@milseman
Last active April 12, 2018 01:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milseman/b86e7ec89fbbd2cf1f189fcf75be8a54 to your computer and use it in GitHub Desktop.
Save milseman/b86e7ec89fbbd2cf1f189fcf75be8a54 to your computer and use it in GitHub Desktop.
ExpressiblyByStringInterpolation Alternative Formulation
protocol ESI {
// Interpolate a segment
mutating func addSegment<T>(_ t: T)
// Interpolate a literal
mutating func addLiteral(_ s: String)
// Compiler will produce closure to pass to this init. Closure will consist
// of calls to writeSegment and writeLiteral
init(performingInterpolation: (inout Self) -> ())
// Maybe: compiler can also give the literals and number of segments to the
// conformer so they can estimate a reserve capacity? Or just combined literal
// lengths? Too much?
init(
numSegments: Int,
literals: String...,
performingInterpolation: (inout Self) -> ()
)
}
extension ESI {
init(
numSegments: Int,
literals: String...,
performingInterpolation f: (inout Self) -> ()
) {
self.init(performingInterpolation: f)
}
}
extension ESI where Self: TextOutputStream {
mutating func addSegment<T>(_ t: T) {
print(t, terminator: "", to: &self)
}
mutating func addLiteral(_ s: String) {
write(s)
}
}
struct MyESI {
var value: String = ""
}
extension MyESI: TextOutputStream {
mutating func write(_ string: String) {
value.append(string)
}
}
extension MyESI: ESI {
// Let's say MyESI has some setup work it wants to do
init(forInterpolation:()) { /*...*/ }
// Let's say we have tear-down work we want to do
mutating func finalize() { /*...*/ }
init(performingInterpolation f: (inout MyESI) -> ()) {
var ret = MyESI(forInterpolation: ())
f(&ret)
ret.finalize()
self = ret
}
}
// Demonstrates what the compiler would produce for arbitary segments
func exampleCompilerOutput<T, U, V>(_ t: T, _ u: U, _ v: V) -> MyESI {
// return "abc\(t)def\(u)ghi\(v)jkl" as ESI
return MyESI(performingInterpolation: { (esi: inout MyESI) -> () in
esi.addLiteral("abc")
esi.addSegment(t)
esi.addLiteral("def")
esi.addSegment(u)
esi.addLiteral("ghi")
esi.addSegment(v)
esi.addLiteral("jkl")
})
// Alternatively: as above, but also passing in num segments and literals
}
print(exampleCompilerOutput(1,2.0,3).value) // abc1def2.0ghi3jkl
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment