groovy-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Anto Aravinth <anto.aravinth....@gmail.com>
Subject Re: Add closures to class via AST
Date Sat, 22 Aug 2015 11:34:27 GMT
Hey Cedric, apologize for multiple mails.

So this is what I was trying to achieve, generate a method, with some
meaningful domain specific name, which behinds the scenes
calls "with" method of Groovy.

So thats the reason, I tried to create a method like helloTest, which takes
the param and behind the scenes calls the delegate's with, which should
work as expected (I guess it should work as expected).

So class looks like this:

@Transform
class Dummy{
public String test = "hellow worrld";
}

def a = new Dummy()
a.helloTest({
println test
})

And given the AST looks like this:

@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
. . .
void visit(ASTNode[] nodes, SourceUnit source) {
        init(nodes, source);
        AnnotatedNode parent = (AnnotatedNode) nodes[1];

        if (parent instanceof ClassNode) {

            List<ASTNode> closure = new AstBuilder().buildFromCode {
                { ->
                    println delegate
                    delegate.with{
                        param()
                    }
                }.call()
            }
            cNode.addMethod(new MethodNode('helloTest', ACC_PUBLIC,
ClassHelper.DYNAMIC_TYPE,[new Parameter(ClassHelper.OBJECT_TYPE, "param")]
as Parameter[], ClassNode.EMPTY_ARRAY, closure[0]));
        }
    }


 Now the closure getting called, but it says :

 Caught: groovy.lang.MissingPropertyException: No such property: test for
class: Script1

 Looks like now with delegate the call to Script1, rather than Dummy (as
thats what "with" should do right?)

 And I was thinking, whether I can run the closure by setting delegate to
different class. Is this also possible?

 I'm not sure,whether this is an good approach or not; But this is what I
was expected to achieve.

Thanks for the help.

On Sat, Aug 22, 2015 at 1:36 PM, C├ędric Champeau <cedric.champeau@gmail.com>
wrote:

> Hi Anto,
>
> (first of all, I don't think you will get more answers by sending multiple
> mails in a single day, we all have our respective jobs).
>
> I'm not sure if your closure code makes a lot of sense, however, `param`
> is indeed null. What you generate is:
>
> def helloTest(def param) {
>     { param ->
>         // why delegate.with?
>         delegate.with {
>             println delegate
>             param()
>         }
>
>     }.call()
> }
>
>
> So you can already see that you have a conflict between the method
> parameter name and the closure parameter. Regular code will not let you do
> this, if you do AST xforms, you have to care about it yourself and make
> sure you don't mix things up. So imagine that you rename the method param
> name to `p` and call the method. -> NPE, because you call the closure with
> no arguments, which will cause param to be `null`. That's what is
> happening. On the other hand, if you create a closure that takes *no*
> argument and refers to the parameter like this:
>
> def helloTest(def param) {
>     { ->
>         delegate.with {
>             println delegate
>             param()
>         }
>     }.call()
> }
>
>
> Then it works as you expect. Last but not least, you may have to call the
> VariableScopeVisitor yourself depending on the compiler phase your AST
> transform works.
>
> Best regards,
>
> 2015-08-22 1:05 GMT+02:00 Anto Aravinth <anto.aravinth.cse@gmail.com>:
>
>> Any ideas will greatly helps!!
>> On 21 Aug 2015 16:57, "Anto Aravinth" <anto.aravinth.cse@gmail.com>
>> wrote:
>>
>>> Hi All,
>>>
>>> Any solutions?
>>> On 21 Aug 2015 09:21, "Anto Aravinth" <anto.aravinth.cse@gmail.com>
>>> wrote:
>>>
>>>> Hi all,
>>>>
>>>>
>>>>
>>>> I'm trying to add an closure to my classNode via AST transformation. My
>>>> code looks something like this:
>>>>
>>>>
>>>>
>>>> List<ASTNode> closure = new AstBuilder().buildFromCode {
>>>>
>>>>                 { param ->
>>>>
>>>>                     delegate.with {
>>>>
>>>>                         param()
>>>>
>>>>                     }
>>>>
>>>>                 }
>>>>
>>>>             }
>>>>
>>>>
>>>>
>>>>             cNode.addMethod(new MethodNode('helloTest', ACC_PUBLIC,
>>>> ClassHelper.DYNAMIC_TYPE,[new Parameter(ClassHelper.OBJECT_TYPE, "param")]
>>>> as Parameter[], ClassNode.EMPTY_ARRAY, closure[0]));
>>>>
>>>>
>>>>
>>>> And running AST transformation, on the test class:
>>>>
>>>>
>>>>
>>>> @AddMethod
>>>>
>>>> class Test{
>>>>
>>>> }
>>>>
>>>>
>>>>
>>>> def a = new Test()
>>>>
>>>> a.helloTest({
>>>>
>>>>         println "Works great!";
>>>>
>>>> })
>>>>
>>>>
>>>>
>>>> Now no errors nothing. The code works fine, but since I have passed an
>>>> println to the helloTest closure, I expect it to print on my console, which
>>>> didn't happen. Looks like my closure itself didn't ran. Then I called the
>>>> closure myself, something like this:
>>>>
>>>>
>>>>
>>>>             List<ASTNode> closure = new AstBuilder().buildFromCode
{
>>>>
>>>>                 { param ->
>>>>
>>>>                     delegate.with {
>>>>
>>>>                         println delegate
>>>>
>>>>                         param()
>>>>
>>>>                     }
>>>>
>>>>                 }.call()
>>>>
>>>>             }
>>>>
>>>>
>>>>
>>>> Now this gives NPE, saying param is null. Looks now the parameter is
>>>> not getting binded. Delegate is getting printed as expected.
>>>>
>>>>
>>>>
>>>> Also I'm not sure, the way I have added the closure to my class is
>>>> right or not. Any help would be great!
>>>>
>>>
>

Mime
View raw message