Very cool. Impressive combination of unique Pharo features.
> On 4 Apr 2018, at 18:02, Marcus Denker <marcus.denker@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
>
>