2018-04-18 7:41 GMT+02:00 Stephane Ducasse <stepharo.self@gmail.com>:
Now clement what is the difference with a plain AST interpreter?

Together with #evaluate we can also have #debug message. With interpreter approach it would be tricky to implement it with standard debugger.��
��


On Tue, Apr 17, 2018 at 6:57 PM, Cl��ment Bera <bera.clement@gmail.com> wrote:
Starting from here you can build a full AST interpreter that mutates a context instance that you create by interpreting MessageNode...

On Tue, Apr 17, 2018 at 5:45 PM, Marcus Denker <marcus.denker@inria.fr> wrote:
Hi,

This is fun experiment:

Every RBValueNode subclass evaluates to something. So why not implement a #evaluate method?

This is especially fun to do for a specific context, as this means that you could evaluate every RBVariableNode to see the value.

So lets implement a method in RBValueNode:

evaluateWithContext: aContext

| methodNode |

If we want to compile a method for it, we need to wrap it into a return and a method. Like when evaluating in the debugger, we create a #DoItIn: method that
will get the context as a parameter to read the values from (temps from the context, ivars from context receiver).

This works like this:

methodNode := RBMethodNode��
selector: #DoItIn:
arguments: { RBVariableNode named: 'ThisContext' }��
body: (RBReturnNode value: self) asSequenceNode.

to read temps from the context parameter, we use the rewrite method that is used by doits already:
methodNode rewriteTempsForContext: aContext.

and now we can execute:

^methodNode generate valueWithReceiver: aContext receiver arguments: {aContext}.

For testing, I put a #haltOnce into Rectangle>>#area and then use the inspector on the context to evaluate a AST node that is a temporary variable.
The screenshot shows executing

self method ast assignmentNodes first variable evaluateWithContext: self

and it returns correctly 104:




Of course there are simpler ways to read variables by name from a context (e.g. we added #lookupSymbol: ), but #evaluateWithContext: can be called on other Nodes, too.
E.g. just a #evaluate could be nice for creating Blocks programmatically (instead of calling the compiler on a Pretty-Print result like #createBlockFor: in the ParseTreeSearcher).

A version that does not take context and receiver into account is this:

evaluate
| methodNode |
methodNode := RBMethodNode��
selector: #DoIt
body: (RBReturnNode value: self) asSequenceNode.
^methodNode generate valueWithReceiver: nil arguments: #().


and then you can do things like

blockNode: = RBBlockNode
body: (RBLiteralNode value: 5) asSequenceNode

blockNode evaluate

to create blocks.


Marcus




--