Home » Modeling » OCL » Problem about OCLinEcore(parser error, but it looks fine and I try it manually )
Problem about OCLinEcore [message #806288] |
Fri, 24 February 2012 14:50  |
Eclipse User |
|
|
|
I tried OCLInEcore in a small model. What i am trying to do is split a String into String[] according to a separator. Could anyone help me with the problem?
There is no error showing up. When I track the path, it shows that variables 'string' and 'char' in method 'split' is not valid typed, which causes a parse error.
module _'My.ecore'
{
class Graph
{
property nodes#graph : Node[*] { ordered composes };
property arrows#graph : Arrow[*] { ordered composes };
}
class Arrow extends NameElement
{
invariant noteq: source <> target;
invariant ads: not source.oclIsUndefined() and not target.oclIsUndefined();
property graph#arrows : Graph[?] { ordered };
property source#outgoings : Node[1] { ordered };
property target#incomings : Node[1] { ordered };
}
class Node extends NameElement
{
invariant x: true;
property graph#nodes : Graph[?] { ordered };
property incomings#target : Arrow[*] { ordered };
property outgoings#source : Arrow[*] { ordered };
}
class NameElement
{
invariant checkName: checkName;
attribute name : String[?] { ordered };
attribute charSequence : String[*] { ordered derived transient unsettable volatile }
{
derivation: split(name, '^');
}
attribute checkName : Boolean[?] { ordered derived transient unsettable volatile }
{
derivation: split(name, '^')->forAll(s : String | isAlpah(s));
}
operation isAlpah(string : String[1]) : Boolean[1]
{
body:
let seq : Sequence(String) = Sequence{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'} in charSequence(string.toLower())->forAll(a : String | seq->including(a));
}
operation charSequence(string : String[1]) : String[*]
{
body:
let seq : Sequence(Integer) = Sequence{1..string.size()} in seq->collectNested(i : Integer | string.substring(i, i));
}
operation index(string : String[1], char : String[1]) : ecore::EInt[1]
{
body:
let seq : Sequence(String) = charSequence(string) in if seq->count(char) > 0 then seq->indexOf(char) else 0 endif;
}
operation split(string : String[1], char : String[1]) : String[*]
{
body:
let index : Integer = index(string, char) in if index < 1 then Sequence{string} else let other : Sequence(String) = if index < 2 then Sequence{''} else Sequence{string.substring(1, index - 1)} endif in if index + 1 <= string.size() then other->union(split(string.substring(index + 1, string.size()), char)->asSequence()) else other endif endif;
}
}
}
Attachment: My.ecore
(Size: 6.74KB, Downloaded 373 times)
|
|
|
Re: Problem about OCLinEcore [message #806587 is a reply to message #806288] |
Sat, 25 February 2012 01:26   |
Eclipse User |
|
|
|
Hi
Your example has the package declaration missing, presumably a cut and
paste typo.
When I fix this I find a missing
import ecore : 'http://www.eclipse.org/emf/2002/Ecore#/';
and when I add this it parses for me. Using ecore::EInt isn't necessary
and makes the OCL less portable.
You may find the String::characters() operation useful.
For Juno, I've finally got around to adding regex String operations and
confirmed that adding library operations with Java bodies is now easy.
Regards
Ed Willink
On 24/02/2012 19:50, Missing name Mising name wrote:
> I tried OCLInEcore in a small model. What i am trying to do is split a String into String[] according to a separator. Could anyone help me with the problem?
> There is no error showing up. When I track the path, it shows that variables 'string' and 'char' in method 'split' is not valid typed, which causes a parse error.
> module _'My.ecore'
>
> {
> class Graph
> {
> property nodes#graph : Node[*] { ordered composes };
> property arrows#graph : Arrow[*] { ordered composes };
> }
> class Arrow extends NameElement
> {
> invariant noteq: source<> target;
> invariant ads: not source.oclIsUndefined() and not target.oclIsUndefined();
> property graph#arrows : Graph[?] { ordered };
> property source#outgoings : Node[1] { ordered };
> property target#incomings : Node[1] { ordered };
> }
> class Node extends NameElement
> {
> invariant x: true;
> property graph#nodes : Graph[?] { ordered };
> property incomings#target : Arrow[*] { ordered };
> property outgoings#source : Arrow[*] { ordered };
> }
> class NameElement
> {
> invariant checkName: checkName;
> attribute name : String[?] { ordered };
> attribute charSequence : String[*] { ordered derived transient unsettable volatile }
> {
> derivation: split(name, '^');
> }
> attribute checkName : Boolean[?] { ordered derived transient unsettable volatile }
> {
> derivation: split(name, '^')->forAll(s : String | isAlpah(s));
> }
> operation isAlpah(string : String[1]) : Boolean[1]
> {
> body:
> let seq : Sequence(String) = Sequence{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'} in charSequence(string.toLower())->forAll(a : String | seq->including(a));
> }
> operation charSequence(string : String[1]) : String[*]
> {
> body:
> let seq : Sequence(Integer) = Sequence{1..string.size()} in seq->collectNested(i : Integer | string.substring(i, i));
> }
> operation index(string : String[1], char : String[1]) : ecore::EInt[1]
> {
> body:
> let seq : Sequence(String) = charSequence(string) in if seq->count(char)> 0 then seq->indexOf(char) else 0 endif;
> }
> operation split(string : String[1], char : String[1]) : String[*]
> {
> body:
> let index : Integer = index(string, char) in if index< 1 then Sequence{string} else let other : Sequence(String) = if index< 2 then Sequence{''} else Sequence{string.substring(1, index - 1)} endif in if index + 1<= string.size() then other->union(split(string.substring(index + 1, string.size()), char)->asSequence()) else other endif endif;
> }
> }
> }
|
|
| | |
Re: Problem about OCLinEcore [message #813686 is a reply to message #808344] |
Mon, 05 March 2012 10:55   |
Eclipse User |
|
|
|
Hi,
Eclipse version : Indigo
OCL version: 3.1.0
XText version: 2.0.1
Right now, I can run the Junit test case. But still have problem when I call recursively in OCL. I trace down the call path and find bug when handling with collect method of Sequence.
operation split(string : String[1], a : String[1]) : String[*]
{
body:
let index : Integer = index(string, a) in if index = 0 then Sequence{string} else let other : Sequence(String) = if index = 1 then Sequence{''} else Sequence{string.substring(1, index - 1)} endif in if index + 1 <= string.size() then other->union(split(string.substring(index + 1, string.size()), a)->asSequence()) else other endif endif;
}
operation charSequence(string : String[1]) : String[*]
{
body:
let seq : Sequence(Integer) = Sequence{1..string.size()} in seq->collect(i : Integer | string.substring(i, i));
}
I tried split("adcab", "a"). The first result of invoking charSequence("adcab") is right, but the second invoking charSequence("dcab") returns Sequence{}.
public Value evaluate(EvaluationVisitor evaluationVisitor, CollectionValue sourceVal, LoopExp iteratorExp) {
ValueFactory valueFactory = evaluationVisitor.getValueFactory();
TypeManager typeManager = evaluationVisitor.getTypeManager();
Type sourceType = iteratorExp.getSource().getType();
boolean isOrdered = typeManager.isOrdered(sourceType);
CollectionValue.Accumulator accumulatorValue = createAccumulationValue(valueFactory, isOrdered, false);
return evaluateIteration(new IterationManager<CollectionValue.Accumulator>(evaluationVisitor,
iteratorExp, sourceVal, accumulatorValue));
}
I found when evaluateIteration function is called, for the first time, it has right iterator, but for the second, it only has a emtpy iterator.
Or there is no bug at all but somethings I did wrong causes my problem. Wish you can help.
|
|
|
Re: Problem about OCLinEcore [message #813866 is a reply to message #813686] |
Mon, 05 March 2012 14:57   |
Eclipse User |
|
|
|
Hi
An interesting and surprisingly horrible example.
I couldn't understand your code; it seemed very complicated, so I wrote
it my way; still complicated. I have four "if"'s; you have only three so
I suspect you missed one of the special cases.
package wang : pfx = 'platform:/resource/Wang/model/Wang.ecore'
{
class Wang
{
operation split(string : String, delimiter : String) :
String[*] { ordered !unique }
{
body: self.splitMore(Sequence{}, string, delimiter);
}
operation splitMore(prefixes : String[*] { ordered !unique },
tail : String, delimiter : String) : String[*] { ordered !unique }
{
body:
let startIndex : Integer = tail.indexOf(delimiter) in
if startIndex <= 0
then prefixes->append(tail)
else let newPrefixes : Sequence(String) =
if startIndex > 1
then prefixes->append(tail.substring(1, startIndex
- 1))
else if prefixes->notEmpty()
then prefixes->append('')
else prefixes
endif
endif in
let endIndex : Integer = startIndex +
delimiter.size() in
if endIndex < tail.size()
then
let newTail : String = tail.substring(endIndex,
tail.size()) in
self.splitMore(newPrefixes, newTail, delimiter)
else newPrefixes
endif
endif;
}
}
}
I tested it direct in the Xtext OCL Console after creating a Wang.xmi
with an instance of the Wang class.
Evaluating:
split('abaaba','a')
Results:
'b'
''
'b'
This was with the Juno development stream, for which I improved the
'Invalid variable' diagnostic to identify the variable and the chain of
invalidities; it was hard to debug. Particularly since the Console has
to be restarted after an Ecore edit. Seems ok on 3.7.2 too.
Your example is hard to understand primarily because the formatting got
lost and did not get reconstructed (Ctrl-Shift F helps). I'll see if I
can improve this.
I find recursion easier to manage as a tail recursion on the partial
solution and residual problem as in the example above. One day the OCL
code generator might even recognise tail recursion.
This code is so horrible that I think it's time to promote tokenize()
from the Acceleo library.
(https://bugs.eclipse.org/bugs/show_bug.cgi?id=373289).
Regards
Ed Willink
On 05/03/2012 15:56, XIAOLIANG WANG wrote:
> Hi, Eclipse version : Indigo
> OCL version: 3.1.0
> XText version: 2.0.1
> Right now, I can run the Junit test case. But still have problem when
> I call recursively in OCL. I trace down the call path and find bug
> when handling with collect method of Sequence.
> operation split(string : String[1], a : String[1]) : String[*]
> {
> body:
> let index : Integer = index(string, a) in if index = 0
> then Sequence{string} else let other : Sequence(String) = if index = 1
> then Sequence{''} else Sequence{string.substring(1, index - 1)} endif
> in if index + 1 <= string.size() then
> other->union(split(string.substring(index + 1, string.size()),
> a)->asSequence()) else other endif endif;
> }
>
> operation charSequence(string : String[1]) : String[*]
> {
> body:
> let seq : Sequence(Integer) =
> Sequence{1..string.size()} in seq->collect(i : Integer |
> string.substring(i, i));
> }
>
> I tried split("adcab", "a"). The first result of invoking
> charSequence("adcab") is right, but the second invoking
> charSequence("dcab") returns Sequence{}.
>
> public Value evaluate(EvaluationVisitor evaluationVisitor,
> CollectionValue sourceVal, LoopExp iteratorExp) {
> ValueFactory valueFactory = evaluationVisitor.getValueFactory();
> TypeManager typeManager = evaluationVisitor.getTypeManager();
> Type sourceType = iteratorExp.getSource().getType();
> boolean isOrdered = typeManager.isOrdered(sourceType);
> CollectionValue.Accumulator accumulatorValue =
> createAccumulationValue(valueFactory, isOrdered, false);
> return evaluateIteration(new
> IterationManager<CollectionValue.Accumulator>(evaluationVisitor,
> iteratorExp, sourceVal, accumulatorValue));
> }
> I found when evaluateIteration function is called, for the first time,
> it has right iterator, but for the second, it only has a emtpy iterator.
>
>
> Or there is no bug at all but somethings I did wrong causes my
> problem. Wish you can help.
|
|
|
Re: Problem about OCLinEcore [message #814393 is a reply to message #813866] |
Tue, 06 March 2012 06:49   |
Eclipse User |
|
|
|
Hi,Edward,
Thank you so much. The problem is solved.
But another problem happens. It is really weird. Is there any dependence between different ocl expression???
Here I give an example:
I define two functions in OCL
operation isAlpah(string : String[1]) : Boolean[1]
{
body:
let seq : Sequence(String) = Sequence{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}
in charSequence(string.toLower())->forAll(a : String | seq->includes(a));
}
operation charSequence(string : String[1]) : String[*]
{
body:
let seq : Sequence(Integer) = Sequence{1 .. string.size()}
in seq->collect(i : Integer | string.substring(i, i));
}
In the java file, the two functions will be following:
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public boolean isAlpah(String string) {
try {
return (Boolean)IS_ALPAH_STRING__EINVOCATION_DELEGATE.dynamicInvoke(this, new BasicEList.UnmodifiableEList<Object>(1, new Object[]{string}));
}
catch (InvocationTargetException ite) {
throw new WrappedException(ite);
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@SuppressWarnings("unchecked")
public EList<String> charSequence(String string) {
try {
return (EList<String>)CHAR_SEQUENCE_STRING__EINVOCATION_DELEGATE.dynamicInvoke(this, new BasicEList.UnmodifiableEList<Object>(1, new Object[]{string}));
}
catch (InvocationTargetException ite) {
throw new WrappedException(ite);
}
}
And then, I have a test case like this:
public void testGetCharSequence() {
getFixture().setName("sfiefj(^asdfs");
EList<String> result = getFixture().getCharSequence();
System.out.println(result);
assertTrue(result.size() == 2);
System.out.println(result.get(0));
assertFalse(getFixture().isAlpah(result.get(0)));
System.out.println(result.get(1));
assertTrue(getFixture().isAlpah(result.get(1)));
}
Right now, I run the test case, it turns out a failure, which is caused by
assertFalse(getFixture().isAlpah(result.get(0)));
After I change the isAlpah function in java file to this, which just print out charSequence result, the test case runs successfully.
public boolean isAlpah(String string) {
try {
for(String iter : charSequence(string)) // these two lines
System.out.println(iter); // are added.
return (Boolean)IS_ALPAH_STRING__EINVOCATION_DELEGATE.dynamicInvoke(this, new BasicEList.UnmodifiableEList<Object>(1, new Object[]{string}));
}
catch (InvocationTargetException ite) {
throw new WrappedException(ite);
}
}
[Updated on: Tue, 06 March 2012 06:51] by Moderator
|
|
|
Re: Problem about OCLinEcore [message #814417 is a reply to message #814393] |
Tue, 06 March 2012 07:21   |
Eclipse User |
|
|
|
Hi
There should be no function interactions.
At a quick glance, I suspect that your problem is that an empty string
crashes in one but not the other.
There is a String::characters() function that does what your
charSequence() does.
Regards
Ed Willink
On 06/03/2012 11:49, XIAOLIANG WANG wrote:
> Hi,Edward,
> Thank you so much. The problem is solved.
> But another problem happens. It is really weird. Is there any
> dependence between different ocl expression???
>
> Here I give an example:
>
> I define two functions in OCL
>
> operation isAlpah(string : String[1]) : Boolean[1]
> {
> body:
> let seq : Sequence(String) = Sequence{'a', 'b', 'c', 'd', 'e',
> 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
> 't', 'u', 'v', 'w', 'x', 'y', 'z'}
> in charSequence(string.toLower())->forAll(a : String |
> seq->includes(a));
> }
> operation charSequence(string : String[1]) : String[*]
> {
> body:
> let seq : Sequence(Integer) = Sequence{1 .. string.size()}
> in seq->collect(i : Integer | string.substring(i, i));
> }
>
> In the java file, the two functions will be following:
> /**
> * <!-- begin-user-doc -->
> * <!-- end-user-doc -->
> * @generated
> */
> public boolean isAlpah(String string) {
> try {
> return
> (Boolean)IS_ALPAH_STRING__EINVOCATION_DELEGATE.dynamicInvoke(this, new
> BasicEList.UnmodifiableEList<Object>(1, new Object[]{string}));
> }
> catch (InvocationTargetException ite) {
> throw new WrappedException(ite);
> }
> }
>
> /**
> * <!-- begin-user-doc -->
> * <!-- end-user-doc -->
> * @generated
> */
> @SuppressWarnings("unchecked")
> public EList<String> charSequence(String string) {
> try {
> return
> (EList<String>)CHAR_SEQUENCE_STRING__EINVOCATION_DELEGATE.dynamicInvoke(this,
> new BasicEList.UnmodifiableEList<Object>(1, new Object[]{string}));
> }
> catch (InvocationTargetException ite) {
> throw new WrappedException(ite);
> }
> }
>
> And then, I have a test case like this:
> public void testGetCharSequence() {
> getFixture().setName("sfiefj(^asdfs");
> EList<String> result = getFixture().getCharSequence();
> System.out.println(result);
> assertTrue(result.size() == 2);
> System.out.println(result.get(0));
> assertFalse(getFixture().isAlpah(result.get(0)));
> System.out.println(result.get(1));
> assertTrue(getFixture().isAlpah(result.get(1)));
> }
>
> Right now, I run the test case, it turns out a failure, which is
> caused by assertFalse(getFixture().isAlpah(result.get(0)));
>
> After I change the isAlpah function in java file to this, which just
> print out charSequence result, the test case runs successfully.
> public boolean isAlpah(String string) {
> try {
> for(String iter : charSequence(string))
> System.out.println(iter);
> return
> (Boolean)IS_ALPAH_STRING__EINVOCATION_DELEGATE.dynamicInvoke(this, new
> BasicEList.UnmodifiableEList<Object>(1, new Object[]{string}));
> }
> catch (InvocationTargetException ite) {
> throw new WrappedException(ite);
> }
> }
|
|
| | | | |
Re: Problem about OCLinEcore [message #831106 is a reply to message #831050] |
Wed, 28 March 2012 09:33  |
Eclipse User |
|
|
|
Hi
Yes. You should follow the OCLinEcore tutorial in the Help documentation.
Regards
Ed Willink
On 28/03/2012 07:57, Lucy Chan wrote:
> I'm just using the EMF to modeling and trying to define specification
> by OCL. I get the information from the website that the xxx.ecore can
> be verified by OCL, so I try to implement it.
|
|
|
Goto Forum:
Current Time: Fri Apr 18 20:08:18 EDT 2025
Powered by FUDForum. Page generated in 0.04014 seconds
|