groovy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Leonard Brünings <groovy-...@bruenings-it.net>
Subject Re: Get reference to enclosing closure
Date Tue, 21 Nov 2017 20:43:33 GMT
Hi Jochen,

your first suggestion might do the trick and if closures disappear then 
there will be much more that doesn't work.

We currently do something like this:


   public void replaceImplicitThis(Expression invocation) {
     if (invocation instanceof MethodCallExpression) {
       MethodCallExpression methodCallExpression = 
(MethodCallExpression)invocation;
       if (methodCallExpression.isImplicitThis()) {

         Expression target = referenceToCurrentClosure();
         methodCallExpression.setObjectExpression(target);
       }
     }
   }

   private MethodCallExpression referenceToCurrentClosure() {
     return new MethodCallExpression(
       new VariableExpression("this"),
       new ConstantExpression("each"),
       new ArgumentListExpression(
         new PropertyExpression(
           new 
ClassExpression(ClassHelper.makeWithoutCaching(Closure.class)),
           new ConstantExpression("IDENTITY")
         )
       )
     );
   }

This looks a similar to your second suggestion.

Could you give me a hint on how to write a BytecodeExpersion for "ALOAD 
0"? Could I just use this in place of the other MethodCallExpression 
from referenceToCurrentClosure?

-Leo

Am 21.11.2017 um 19:32 schrieb Jochen Theodorou:
> I am not saying I am getting the question fully...
>
> but what you want is
>
> def c = { return XY }
> assert c() == c
>
> something like that? Extend BytecodeExpersion and do a "ALOAD 0". No 
> guarantees that this will work forever though. In the future there 
> might be no closure class anymore.
>
> Oh and if I got you wrong, and you want a reference to the enclosing 
> context, that would be the owner:
>
> def x = this
> def c = { return {owner}}
> assert c()() == c
> assert c.owner == x
>
> bye Jochen
>
> On 20.11.2017 21:27, Leonard Brünings wrote:
>> Hi,
>>
>> I'm Leonard from the Spock framework team. Guillaume suggested that I 
>> write to the dev-list with this problem.
>>
>> Some context:
>>
>> Spock has a method `with(Object, Closure)` in its Specification class 
>> that sets the object as the delegate of the closure and transforms,
>> every call inside the closure to an implicit assertion.
>>
>> given:
>>        def person = new Person(name: "Peter", age: 28)
>>
>> expect:
>>        with(person) {
>>            name == 'Peter'
>>            age == 28
>>        }
>>
>> This worked fine for properties, however for single methods like 
>> `contains` it didn't work.
>>
>> The initial problem is described here 
>> https://github.com/spockframework/spock/pull/606
>>
>> Here is the gist:
>>
>> This snippet
>>
>> d|ef list = [1, 2] with(list) { contains(1) } |
>>
>> transforms in AST (simplified) to
>>
>> |def list = [1, 2] with(list) { 
>> SpockRuntime.verifyMethodCondition(this, "contains", [1]) } |
>>
>> then when the AST is written to bytecode it gets transformed again
>>
>> |def list = [1, 2] with(list) { 
>> SpockRuntime.verifyMethodCondition(this.getThisObject(), "contains", 
>> [1]) }|
>>
>> The problem is that the `contains` is now invoked on the containing 
>> `Specification` instead of the `List`.
>>
>> With the aforementioned PR it was changed to this
>>
>> |def list = [1, 2] with(list) { 
>> SpockRuntime.verifyMethodCondition(this.each(groovy.lang.Closure.IDENTITY), 
>> "contains", [1]) } |
>>
>> This "fix" now broke the nesting of `with` blocks as described here: 
>> https://github.com/spockframework/spock/pull/782
>>
>> Do you have any ideas on how to fix this elegantly?
>>
>> - Cheers
>> Leonard
>>
>> ||||||
>>
>> ||
>>
>


Mime
View raw message