Hi Ed,

I am wondering if categories would actually do what you want already without touching the AST. Groovy Categories are actually no syntactic construct and their scope is not lexical (thread local instead)... but maybe

Let us assume you have two Strings obj1 and obj2, then you can define a category:

class StringCategory {
static String plus(String obj1, String obj2) { "from StringCategory $obj1 $obj2" }
}

and code like this:

use (StringCategory) {
  assert "a"+"b" == "from StringCategory a b"
}

the construct supports nesting from inside out, that means the inner context wins over the outer context and the rightmost over the leftmost.

What this does not support is an instance based context.

Assuming you still want to do something like this with more... AST involvement...

My questions for you are,

     - is an AST the way to go?

first you have to decide what you want to compile to and then we can think about how the AST for that has to look like. So this is actually the last step. But assuming you have some kind of handler object you could compile a+b to handler.invoke("plus",a,b)... in other words you would replace almost any expression by a MethodCallExpression. Hint: ExpressonTransformer and helper classes.

     - I'm guessing that I can do the context nesting and composing by building 
on
       methodMissing (with ctx2 chaining to ctx3 chaining to Ctx1 above), but 
is there
       a better way?

I guess the code path for categories won´t help you here, since that is kind of special treated. You could create a special meta class and all the context methods to it, then use its mechanisms to select an appropriate method... hint getMetaMethod, init


     - what might I be breaking in Groovy by doing this?

that depends on how you do it.

     - what help/hints can I get from the compiler vs. doing this all at 
runtime?

worry about such things once you have come up with something that works ;)

original mail:
On 30.12.2016 20:02, Ed Clark wrote:
Happy New Year All!

As one of my New Year's resolutions, I'm going to try and implement a
programming
construct that I've been want to play with for a while - and I think a
Groovy AST just
might let me do it.

While the syntax part of this is straightforward (I think), I'm not as
clear on the
how of the method resolution logic that will be at the core.

The basic idea is that I'll be able to designate a section of code where
binary
operators would be resolved not against the neighbouring object's class,
but against
the surrounding context.  Perhaps some code will make my goal clearer....

My understanding of Groovy (and OO in general) is that an expression like
     obj1 + obj2
is interpreted as if it were written
     obj1.plus( obj2)

What I'd like to do is have something like
     withCtx( ctx1) {
         obj1 + obj2
     }
get interpreted as
     ctx1.plus( obj1, obj2)


If I squint at this, it kind of sort of looks to me a bit like how the
"with" construct
in Groovy works.  But, the with construct is an enhancement to the
existing OO
method resolution; this construct would go in a different direction.

(Actually, to be useful, the interior expression would probably be
something
like -- var1 = obj1 + obj2 -- but I want to focus on one step/method at
a time.)

With this idea, methods between objects (e.g. binary methods) don't
belong to the
class of (one of the) objects involved, but to the context within which
the objects
are being used.

And, just to make things more challenging, I'd like to be able to nest
and compose
contexts.

Consider
     withCtx( Ctx1) {
         withCtx( ctx2, ctx3) {
             obj1 + obj2
         }
     }

Here, the methods of ctx2 would be checked to see if there's a "plus"
that can take
arguments obj1 and obj2.  If not, then ctx3's methods will be check.  If
there's no
appropriate "plus" in ctx3, then Ctx1's methods will be checked.

Finally, if there are no appropriate context methods for "plus-ing"
these two
objects, then method resolution would fall back to the normal Groovy
approach.

To add yet another wrinkle, I'd like to be able to use either a Context
class or a context
instance when doing this.  So, in the above, if "Ctx1" is a class name
(note the cap C),
its static methods would be used.  But, assuming ctx2 and ctx3 are
context instances
(note the lower case c's), the appropriate instance methods would be used.

Hopefully this description makes my goal clearer.

My questions for you are,

     - is an AST the way to go?

     - I'm guessing that I can do the context nesting and composing by
building on
       methodMissing (with ctx2 chaining to ctx3 chaining to Ctx1
above), but is there
       a better way?

     - what might I be breaking in Groovy by doing this?

     - what help/hints can I get from the compiler vs. doing this all at
runtime?


Thanks for your time,

Ed Clark

Reply via email to