Thierry,

> On 28 Sep 2017, at 16:38, Thierry Goubier <[email protected]> wrote:
> 
> Hi Sven,
> 
> Jason and Andrew wrote a string interpolation implementation for Andrew's 
> language, Grace, in the parser. It works rather well and isn't too difficult 
> to implement...

Like I said, I wanted to add the feature without changing the language 
(syntax). Using thisContext and the compiler makes that possible.

> The equivalent would be to add it to RB Parser, and, security wise, it would 
> be as vulnerable as calling Compiler evaluate: 'an unsafe string'.

That is what I mean: it is an implicit #evaluate: call, the risk is comparable 
to an SQL injection attack if the attacker could write the template (not that 
likely though).

> Regards,
> 
> Thierry
> 
> 2017-09-28 16:20 GMT+02:00 Sven Van Caekenberghe <[email protected]>:
> Hi,
> 
> I got into a little office discussion about string interpolation as it is 
> done in different programming languages.
> 
> In Pharo we have String>>#format: which is pretty nice. It works as follows:
> 
> | x y |
> x := 123.
> y := #foo.
> 'x={1} and y={2}' format: { x. y }.
> 
> It is also possible to use a dictionary with keys, like this:
> 
> | x y |
> x := 123.
> y := #foo.
> 'x={x} and y={y}' format: { #x->x. #y->y } asDictionary.
> 
> But this is not true string interpolation as described in [ 
> https://en.wikipedia.org/wiki/String_interpolation ]. The idea is to write 
> the value generating expressions directly inside the strings.
> 
> Since in Pharo we add features not by extending the syntax but by adding 
> messages I wondered if it could be done for string interpolation. The goal is 
> to make the following work:
> 
> | x y |
> x := 123.
> y := #foo.
> 'It seems x equals {x} and y equals {y} while Pi is still {Float pi}' 
> interpolate.
> 
>  => 'It seems x equals 123 and y equals foo while Pi is still 
> 3.141592653589793'
> 
> Here is the implementation I came up with:
> 
> String>>#interpolate
>   "Format the receiver by interpolating the evaluation of expressions
>   in between curly brackets in the context of the sender as in the following 
> 3 oneline examples.
>   'Today is {Date today}' interpolate.
>   | x | x := 123. 'x equals {x} and pi equals {Float pi}' interpolate.
>   'In {#strings} you can escape \{ by prefixing it with \\' interpolate."
> 
>   | senderContext |
>   senderContext := thisContext sender.
>   ^ self class new: self size streamContents: [ :out | | stream |
>       stream := self readStream.
>       [ stream atEnd ] whileFalse: [ | currentChar |
>         (currentChar := stream next) == ${
>           ifTrue: [ | expression result |
>             expression := stream upTo: $}.
>             result := Compiler new
>               evaluate: expression in: senderContext to: nil notifying: nil 
> ifFail: [ ^ nil ] logged: false.
>             out nextPutAll: result asString ]
>           ifFalse: [
>             currentChar == $\
>               ifTrue: [ stream atEnd ifFalse: [ out nextPut: stream next ] ]
>               ifFalse: [ out nextPut: currentChar ] ] ] ]
> 
> It is a hack that could certainly be improved. And there is of course an 
> obvious security problem.
> 
> Thoughts ?
> 
> Sven
> 
> 
> 


Reply via email to