Ahh I believe I see it now.

filterArguments starts with the first filter, and wraps the incoming target
handle with each in turn. However, because it's starting at the target, you
get the filters stacked up in reverse order:

filter(target, 0, a, b, c, d)

ends up as


And so naturally when invoked, they execute in reverse order.

This seems I am surprised we have not run into this as a problem, but I
believe most of my uses of filter in JRuby have been pure functions where
order was not important (except for error conditions).

Now in looking for a fix, I've run into the nasty workaround required to
get filters to execute in the correct order: you have to reverse the
filters, and then reverse the results again. This is far from desirable,
since it requires at least one permute to put the results back in proper

Is there a good justification for doing it this way, rather than having
filterArguments start with the *last* filter nearest the target?

- Charlie

On Tue, Jan 2, 2018 at 2:17 PM Charles Oliver Nutter <head...@headius.com>

> Hello all, long time no write!
> I'm finally playing with writing a "compiler" for JRuby that uses only
> method handles to represent code structure. For most simple expressions,
> this obviously works well. However I'm having trouble with blocks of code
> that contain multiple expressions.
> Starting with the standard call signature through the handle tree, we have
> a basic (Object[])Object type. The Object[] contains local variable state
> for the script, and will be as wide as there are local variables. AST nodes
> are basically compiled into little functions that take in the variable
> state and produce a value. In this way, every expression in the tree can be
> compiled, including local variable sets and gets, loops, and so on.
> Now the tricky bit...
> The root node for a given script contains one or more expressions that
> should be executed in sequence, with the final result being returned. The
> way I'm handling this in method handles is as follows (invokebinder code
> but hopefully easy to read):
> MethodHandle[] handles =
>         Arrays
>                 .stream(rootNode.children())
>                 .map(node -> compile(node))
>                 .toArray(n -> new MethodHandle[n]);
> return Binder.from(Object.class, Object[].class)
>         .permute(new int[handles.length])
>         .filter(0, handles)
>         .drop(0, handles.length - 1)
>         .identity();
> In pseudo-code, this basically duplicates the Object[] as many times as
> there are lines of code to execute, and then uses filterArguments to
> evaluate each in turn. Then everything but the last result is culled and
> the final result is returned.
> Unfortunately, this doesn't work right: filterArguments appears to execute
> in reverse order. When I try to run a simple script like "a = 1; a" the "a"
> value comes back null, because it is executed first.
> Is this expected? Do filters, when executed, actually process from the
> last argument back, rather than the first argument forward?
> Note: I know this would be possible to do with guaranteed ordering using
> the new loop combinators in 9. I'm working up to that for examples for a
> talk.
> - Charlie
mlvm-dev mailing list

Reply via email to