[Pharo-dev] String Interpolation

Igor Stasenko siguctua at gmail.com
Wed Oct 4 05:36:13 EDT 2017


IMO, best would be to make it via compiler plugin.

Same, as i proposed for object literals,
a compiler could detect a pattern  <string literal> interpolate
and replace it  at compile time to produce/expand it into proper
context-aware semantic, something like this:

{'a' . x . 'b' . y. 'c' .z } gather: #asString

That will allow to eliminate run-time security risk(due to #evaluate:), as
well as run-time execution cost,
and allows a nice and convenient and clean syntax.

Without compiler modification, it's hard to reach best security &
performance & convenience ideals.



On 4 October 2017 at 11:06, Thierry Goubier <thierry.goubier at gmail.com>
wrote:

>
>
> 2017-10-04 9:50 GMT+02:00 Guillermo Polito <guillermopolito at gmail.com>:
>
>> if the compiler plugin correctly models such special syntax with special
>> AST nodes, that could be even possible without much effort
>>
>
> Interesting. Would that imply that by having those special ast nodes, we
> would get the decompilation working for the debugger?
>
> Thierry
>
>
>
>
>>
>> On Tue, Oct 3, 2017 at 5:42 PM, Denis Kudriashov <dionisiydk at gmail.com>
>> wrote:
>>
>>>
>>> 2017-10-03 17:39 GMT+02:00 Denis Kudriashov <dionisiydk at gmail.com>:
>>>
>>>> Hi.
>>>>
>>>> While idea looks cool it will require a lot of tool support. Senders,
>>>> var/class references, rename refactorings should be aware of it
>>>>
>>>
>>> And I forgot debugger. It should be possible to step over "interpolated
>>> expressions"
>>>
>>>
>>>>
>>>> 2017-10-03 17:29 GMT+02:00 Damien Pollet <damien.pollet at gmail.com>:
>>>>
>>>>> On 3 October 2017 at 14:07, Guillermo Polito <
>>>>> guillermopolito at gmail.com> wrote:
>>>>>
>>>>>> Why not having an opal plugin?
>>>>>>
>>>>>> The opal plugin may read strings in the form:
>>>>>>
>>>>>> "lalala {some expression} lololo"
>>>>>>
>>>>>> and replace at compile time that by:
>>>>>>
>>>>>> "lalala {1} lololo" format { some expression }
>>>>>>
>>>>>
>>>>> If we're going to extend the compiler, we might as avoid parsing at
>>>>> runtime by desugaring more like:
>>>>>
>>>>> String streamContents: [:str |
>>>>>     str
>>>>>         nextPutAll: 'lalala ';
>>>>>         nextPutAll: (some expression) printString;
>>>>>         nextPutAll: ' lololo' ]
>>>>>
>>>>> The thing to think about is what is the delimiter for {some
>>>>>> expression}.
>>>>>>  - a too used one may break lots of existing code.
>>>>>>
>>>>>
>>>>> …or we could change the string quotes to mean "dynamic string in which
>>>>> interpolations can be used" and keep single quotes for literal strings only.
>>>>>
>>>>>  - and we should escape it
>>>>>>
>>>>>
>>>>> indeed
>>>>>
>>>>>
>>>>>> On Fri, Sep 29, 2017 at 5:40 AM, Sven Van Caekenberghe <sven at stfx.eu>
>>>>>> wrote:
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> > On 29 Sep 2017, at 08:54, Pavel Krivanek <pavel.krivanek at gmail.com>
>>>>>>> wrote:
>>>>>>> >
>>>>>>> > This solution will not work for environments without sources too
>>>>>>> where names like t1, t2 are used for temporary variables.
>>>>>>>
>>>>>>> That is true.
>>>>>>>
>>>>>>> I often wonder why we can't keep at least the variables names, it
>>>>>>> would not be that expensive. There was this problem with FFI that needed
>>>>>>> source code access as well. It would also help the debugger and make the
>>>>>>> decompiler more powerful.
>>>>>>>
>>>>>>> > Anyway, nice idea.
>>>>>>> >
>>>>>>> > -- Pavel
>>>>>>> >
>>>>>>> > Dne čtvrtek 28. září 2017 Sven Van Caekenberghe <sven at stfx.eu>
>>>>>>> napsal(a):
>>>>>>> > 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
>>>>>>> >
>>>>>>> >
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>>
>>>>>>
>>>>>>
>>>>>> Guille Polito
>>>>>>
>>>>>> Research Engineer
>>>>>>
>>>>>> Centre de Recherche en Informatique, Signal et Automatique de Lille
>>>>>>
>>>>>> CRIStAL - UMR 9189
>>>>>>
>>>>>> French National Center for Scientific Research - *http://www.cnrs.fr
>>>>>> <http://www.cnrs.fr>*
>>>>>>
>>>>>>
>>>>>> *Web:* *http://guillep.github.io* <http://guillep.github.io>
>>>>>>
>>>>>> *Phone: *+33 06 52 70 66 13 <+33%206%2052%2070%2066%2013>
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Damien Pollet
>>>>> type less, do more [ | ] http://people.untyped.org/damien.pollet
>>>>>
>>>>
>>>>
>>>
>>
>>
>> --
>>
>>
>>
>> Guille Polito
>>
>> Research Engineer
>>
>> Centre de Recherche en Informatique, Signal et Automatique de Lille
>>
>> CRIStAL - UMR 9189
>>
>> French National Center for Scientific Research - *http://www.cnrs.fr
>> <http://www.cnrs.fr>*
>>
>>
>> *Web:* *http://guillep.github.io* <http://guillep.github.io>
>>
>> *Phone: *+33 06 52 70 66 13 <+33%206%2052%2070%2066%2013>
>>
>
>


-- 
Best regards,
Igor Stasenko.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.pharo.org/pipermail/pharo-dev_lists.pharo.org/attachments/20171004/4a3fcd50/attachment-0002.html>


More information about the Pharo-dev mailing list