OCL closure operation [message #1852704] |
Wed, 01 June 2022 14:22 |
Yves BERNARD Messages: 173 Registered: July 2014 |
Senior Member |
|
|
Hello,
I didn't succeed in using the OCL closure operation in my ATL rule. Do I do something wrong or is it simply not implemented by SimpleOCL?
Thanks.
Yves
|
|
|
|
|
|
|
|
Re: OCL closure operation [message #1854509 is a reply to message #1852704] |
Tue, 23 August 2022 07:11 |
Yves BERNARD Messages: 173 Registered: July 2014 |
Senior Member |
|
|
Sorry for the late follow up on this, I had to switch to another task. I'm back on this topic now.
Actually the sample example does not run on my computer. Instead, I get the following error message:
org.eclipse.m2m.atl.emftvm.util.VMException: Error during module loading: Error during module loading: Module Helpers not found
I confirm that simpleOCL is installed (from Eclipse "Installed Software" dialog):
SimpleOCL 2.1.0.202001021418 org.eclipselabs.simpleocl.feature.feature.group EclipseLabs
Yves
[Updated on: Tue, 23 August 2022 07:11] Report message to a moderator
|
|
|
Re: OCL closure operation [message #1854550 is a reply to message #1854509] |
Wed, 24 August 2022 20:11 |
|
The SimpleOCL builder is a bit primitive, and does not kick in without editing the .simpleocl file first. If the Helpers.emftvm file is missing, you can try to edit the Helpers.simpleocl file a bit, and save the file to trigger the compiler as a workaround.
Cheers,
Dennis
|
|
|
|
|
Re: OCL closure operation [message #1866033 is a reply to message #1866006] |
Sun, 19 May 2024 18:40 |
|
Your code is correct, but there seems to be a bug in the SimpleOCL parser that prevents you from passing primitive types as function parameters, e.g. result.oclIsKindOf(Bag(OclAny)) .
Cheers,
Dennis
|
|
|
|
|
Re: OCL closure operation [message #1866126 is a reply to message #1866093] |
Tue, 21 May 2024 20:14 |
|
Indeed, I bumped into that one as well: there's another bug in the SimpleOCL compiler for ->iterate() expressions :-(.
Luckily, you can make it work without using iterate in this case (if I understood your code correctly):
module Extensions2;
context Bag(OclAny) def : closure(f : Lambda(OclAny): OclAny) : Bag(OclAny) =
let buffer: Bag(OclAny) = self->collect(e | f(e))->reject(e | e.oclIsUndefined())->flatten() in
if buffer->isEmpty() then
self
else
self->union(buffer->closure(f))
endif;
context Integer def : minusOne : Integer =
if self = 0 then
OclUndefined
else
self - 1
endif;
context Integer def : minusOnes : Bag(Integer) =
if self = 0 then
OclUndefined
else
let this : Integer = self - 1 in
Bag{this, this.minusOnes}->reject(e | e.oclIsUndefined())->flatten()
endif;
static def : test() : OclAny =
Bag{5,4,3,2,1}->closure(e | e.minusOne);
static def : test2() : OclAny =
Bag{5,4,3,2,1}->closure(e | e.minusOnes);
static def : main() : OclAny =
Sequence{Env::test(), Env::test2()}.debug();
Of course, this would not just run without triggering yet another bug, this time in the JIT compiler for EMFTVM when trying to compile closure invocations (unique to SimpleOCL) :-((. If you disable the JIT in the launch config, this will run...
Cheers,
Dennis
|
|
|
|
Re: OCL closure operation [message #1866174 is a reply to message #1866129] |
Wed, 22 May 2024 13:11 |
Yves BERNARD Messages: 173 Registered: July 2014 |
Senior Member |
|
|
Hi Dennis,
Thank you for your interest in this topic.
Unfortunately, there is no way around using iterate in the specific case where I want to use this closure operation. Indeed, the input collection is actually a Bag of Sequences and it is expected to get also a Bag of Sequences as a result. The point is that the flatten() operation will "smatch" everything on not only the first level, conversely to what the iterate can do.
However, based on your idea, I found a way to use the iterate without activating the bug. Unfortunately, it works in my specific case only, or more precisely in cases where the expected out put is a collection of collections, but not with a simple collection. Here is the code for those who are interested:
context Bag(OclAny) def: closure(f : Lambda(OclAny): Bag(OclAny)) : Bag(OclAny) =
let buffer1: Bag(OclAny) = self->collect(e | f(e))->reject(e | e.oclIsUndefined()) in
let buffer2: Bag(OclAny) = buffer1->iterate(e: OclAny; acc: Bag(OclAny) = Bag{} | acc->union(e->asBag())) in
if buffer2->isEmpty() then
self
else
self->union(buffer2->closure(f))
endif;
In order to make it fully generic (i.e. usable with any kind of collection), I need a way to test whether an element (i.e. OclAny) is a collection or not, but I didn't find how to do that so far.
Yves
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.05064 seconds