Yes this is cool.
I was wondering what if you try and modify the Meta-Link architecture
itself, but my brain did not reach this second meta level...

2018-04-04 21:50 GMT+02:00 Sven Van Caekenberghe <s...@stfx.eu>:

> Very cool. Impressive combination of unique Pharo features.
>
> > On 4 Apr 2018, at 18:02, Marcus Denker <marcus.den...@inria.fr> wrote:
> >
> > Hi,
> >
> > Some code is very “active”, executed all the time, e.g. collections,
> graphics… or imagine if you work on the compiler or debugger.
> >
> > It would really be nice if we could test a change before accepting it.
> Something like “Accept for Test” where magically the original method
> > does not change, yet, when running tests, the version of the code we
> accepted for testing is executed.
> >
> > So how do we implement that?
> >
> > 1) menu in the browser. I did a quick hack, a Suggestions AST menu shows
> for all nodes (to be replaced with the “correct” way later).
> >
> > SugsSuggestion subclass: #SugsAcceptForTest
> >       instanceVariableNames: ''
> >       classVariableNames: ''
> >       package: 'SmartSuggestions-Suggestion’
> >
> > label
> >       ^'Accept for test’
> >
> > So, now we can do everything in the #execute method.
> >
> > What do we need?
> >
> > 1) How we know that we are in a test?  —> CurrentExecutionEnvironment
> value isTest
> > 2) can we compile the buffer even if there are syntax errors (kind of
> what I expect to happen in non-accepted code)?
> >       —> yes, remember, we use the same Parser for syntax highlighting
> and we extended code-generation for SyntaxError Nodes
> >               in the past (it raises a syntax error at runtime, isn’t
> that kind off odd in a fun way?).
> >
> >       newMethod := context selectedClass compiler
> >               source: context code;
> >               options: #(+ optionParseErrors);
> >               compile.
> >
> > 3) Now how to we “hook into” the execution of the original unchanged
> method? We use a MetaLink. We install it as a before link on
> >    the RBMethodNode, the meta-object is a block. This block gets as
> arguments the thisContext and the arguments of the original method
> >   and then just does what you want it do do: if we are in test, return
> the result of the execution of the method we just compiled.
> >   (Closures are fun, we can just reference the outer temp newMethod, no
> need to store it anywhere else explicitly):
> >
> >                [ :aContext :args |
> >                       CurrentExecutionEnvironment value isTest
> >                               ifTrue: [ aContext return: (newMethod
> valueWithReceiver: aContext receiver arguments: args) ] ];
> >
> > Thus, all the code is this:
> >
> > execute
> >       | newMethod metaLink |
> >       “we compile a new method from the not-accepted text editor. Allow
> syntax errors"
> >       newMethod := context selectedClass compiler
> >               source: context code;
> >               options: #(+ optionParseErrors);
> >               compile.
> >       "the link executes the method we just created and returns"
> >       metaLink := MetaLink new
> >               metaObject: [ :aContext :args |
> >                       CurrentExecutionEnvironment value isTest
> >                               ifTrue: [ aContext return: (newMethod
> valueWithReceiver: aContext receiver arguments: args) ] ];
> >               selector: #value:value:;
> >               arguments: #(context arguments).
> >       context selectedMethod ast link: metaLink
> >
> > Cleanup we do not care as everything will be GCed as soon as we accept
> the method for real.
> >
> > And it works! I did not test it too much, but it seems to do what it is
> supposed to do. (but more tests and testing are for sure needed)
> > https://github.com/pharo-project/pharo/pull/1182
> >
> > Next step: move it to a better place in the menu.
> >
> >       Marcus
> >
> >
>
>
>

Reply via email to