Skip to main content



      Home
Home » Modeling » TMF (Xtext) » Recursive cross-references
Recursive cross-references [message #61962] Tue, 21 July 2009 12:29 Go to next message
Eclipse UserFriend
Originally posted by: panajotes.gmx.de

Hi,

I am completly new to Xtext and EMF and just played around with it a bit
inspired by the great webinar. So I tried to write a DSL that is similar to
the EMF Library example[1]. My grammar for that looks like this:
_______
grammar org.xtext.example.Library with org.eclipse.xtext.common.Terminals

generate library "http://www.xtext.org/example/Library"

Model:
(library+=Library)*
(writers+=Writer)*
(books+=Book)*;

Library:
'library' name=STRING '{'
'author' (writers+=[Writer])*
'book' (books+=[Book])*
'}';

Writer:
'writer' name=STRING '{'
'book' (books+=[Book])*
'}';

Book:
'book' title=STRING '{'
'pages' pages=INT
'author' author=[Writer]
'category' category=[BookCategory]
'}';

enum BookCategory:
Mystery | ScienceFiction | Biography;
______

The resulting ecore model looks pretty much like the example. The problem
is, that there are some issues with the generated editor:

1. I modeled the names of writers and books as STRINGs and not IDs because I
want to allow whitespaces here. My problem now is that the cross-references
seems to expect values of type ID. Is there a way to change that? Does this
make sense?

2. Because of the recursive dependency between writer and book, in order to
create a book I need to create a writer before and vice versa:

book book1{
author author1
}

author author1 {
book book1
}

So is it possible to reference an object which has not been created before
in the file?

Thanks in advance and Regards,
Thomas.


[1]
http://help.eclipse.org/ganymede/index.jsp?topic=/org.eclips e.emf.doc/references/overview/EMF.html
Re: Recursive cross-references [message #62012 is a reply to message #61962] Tue, 21 July 2009 12:44 Go to previous messageGo to next message
Eclipse UserFriend
Welcome, Thomas,

please see below.

Am 21.07.2009 18:29 Uhr, schrieb Thomas:
> Hi,
>
> I am completly new to Xtext and EMF and just played around with it a bit
> inspired by the great webinar.
> So I tried to write a DSL that is similar
> to the EMF Library example[1]. My grammar for that looks like this:
> _______
> grammar org.xtext.example.Library with org.eclipse.xtext.common.Terminals
>
> generate library "http://www.xtext.org/example/Library"
>
> Model:
> (library+=Library)*
> (writers+=Writer)*
> (books+=Book)*;
>
> Library:
> 'library' name=STRING '{'
> 'author' (writers+=[Writer])*
> 'book' (books+=[Book])*
> '}';
>
> Writer:
> 'writer' name=STRING '{'
> 'book' (books+=[Book])*
> '}';
>
> Book:
> 'book' title=STRING '{'
> 'pages' pages=INT
> 'author' author=[Writer]
> 'category' category=[BookCategory]
> '}';
>
> enum BookCategory:
> Mystery | ScienceFiction | Biography;
> ______
>
> The resulting ecore model looks pretty much like the example. The
> problem is, that there are some issues with the generated editor:
>
> 1. I modeled the names of writers and books as STRINGs and not IDs
> because I want to allow whitespaces here. My problem now is that the
> cross-references seems to expect values of type ID. Is there a way to
> change that? Does this make sense?

You can use strings as concrete syntax elements for cross references as
well:

author=[Writer] is the default and has the same meaning as
author=[Writer|ID]. So you are free to use author=[Writer|STRING].

Btw: Have you had a look at the reference documentation at
http://www.xtext.org ?

>
> 2. Because of the recursive dependency between writer and book, in order
> to create a book I need to create a writer before and vice versa:
>
> book book1{
> author author1
> }
>
> author author1 {
> book book1
> }
>
> So is it possible to reference an object which has not been created
> before in the file?

This should work out of the box as Xtext is not sensitive to the
declaration order of elements by default. However, Xtext will not detect
the bidirectionality of the author and book cross references. Therefor
you have to use a post processor for the meta model inference (see the
docs). Please note that there is an open issue for this use case which
is likely to be fixed in the next service release 0.7.2.

>
> Thanks in advance and Regards,
> Thomas.
>
>
> [1]
> http://help.eclipse.org/ganymede/index.jsp?topic=/org.eclips e.emf.doc/references/overview/EMF.html
>

Hope that helps,
Sebastian
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
Re: Recursive cross-references [message #62799 is a reply to message #62012] Wed, 22 July 2009 11:56 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: panajotes.gmx.de

Hi Sebastian,

thanks for your help. I read the docs but must have missed the
cross-reference terminal thing :-)

I followed your suggestion to implement bidrectional references by using the
post processor, but the solution I came up with is pretty ugly I guess.
First time Xtend: yet another language :-) Especially the "addEOpposites"
method is really bad:
_____________________________________
process(ecore::EPackage this):
addEOpposites(allReferences())
;

Set[EReference] allReferences(ecore::EPackage this):
let result = {}.toSet() :
this.eAllContents.typeSelect(EClass).collect(e|
result.addAll(((EClass)e).allReferences())) ->
result
;

Set[EReference] allReferences(ecore::EClass this):
let result = {}.toSet() :
eReferences.collect(e|result.add(e)) ->
result
;

cached EReference getReference(Set[EReference] this, String className,
String refName):
select(e|((EClass)e.eContainer).name == className && e.name ==
refName).flatten().get(0)
;

addEOpposites(ecore::EPackage this, Set[EReference] features):
features.getReference("Writer","books").setEOpposite(features.getReference( "Book","author")) -> features.getReference("Book","author").setEOpposite(features.getReference( "Writer","books")) ;________________________________Is there a leaner way to do this? In "addEOpposites" I would like to havelocal variables for both references instead of having to call "getReference"over and over again. While reading the Xtend docs I only came across the"let" statement but do not fully understand it. Do I really have to create anew EReference object and copy the attributes I need to it in order to storethe result from the "getReference" call?Thanks,Thomas."Sebastian Zarnekow" <Sebastian.Zarnekow@itemis.de> wrote in messagenews:h44raa$vqg$1@build.eclipse.org...> Welcome, Thomas,>> please see below.>> Am 21.07.2009 18:29 Uhr, schrieb Thomas:>> Hi,>>>> I am completly new to Xtext and EMF and just played around with it a bit>> inspired by the great webinar.>> So I tried to write a DSL that is similar>> to the EMF Library example[1]. My grammar for that looks like this:>> _______>> grammar org.xtext.example.Library with org.eclipse.xtext.common.Terminals>>>> generate library "http://www.xtext.org/example/Library">>>> Model:>> (library+=Library)*>> (writers+=Writer)*>> (books+=Book)*;>>>> Library:>> 'library' name=STRING '{'>> 'author' (writers+=[Writer])*>> 'book' (books+=[Book])*>> '}';>>>> Writer:>> 'writer' name=STRING '{'>> 'book' (books+=[Book])*>> '}';>>>> Book:>> 'book' title=STRING '{'>> 'pages' pages=INT>> 'author' author=[Writer]>> 'category' category=[BookCategory]>> '}';>>>> enum BookCategory:>> Mystery | ScienceFiction | Biography;>> ______>>>> The resulting ecore model looks pretty much like the example. The>> problem is, that there are some issues with the generated editor:>>>> 1. I modeled the names of writers and books as STRINGs and not IDs>> because I want to allow whitespaces here. My problem now is that the>> cross-references seems to expect values of type ID. Is there a way to>> change that? Does this make sense?>> You can use strings as concrete syntax elements for cross references aswell:>> author=[Writer] is the default and has the same meaning as> author=[Writer|ID]. So you are free to use author=[Writer|STRING].>> Btw: Have you had a look at the reference documentation athttp://www.xtext.org ?>>>>> 2. Because of the recursive dependency between writer and book, in order>> to create a book I need to create a writer before and vice versa:>>>> book book1{>> author author1>> }>>>> author author1 {>> book book1>> }>>>> So is it possible to reference an object which has not been created>> before in the file?>> This should work out of the box as Xtext is not sensitive to thedeclaration order of elements by default. However, Xtext will not detect thebidirectionality of the author and book cross references. Therefor you haveto use a post processor for the meta model inference (see the docs). Pleasenote that there is an open issue for this use case which is likely to befixed in the next service release 0.7.2.>>>>> Thanks in advance and Regards,>> Thomas.>>>>>> [1]>> http://help.eclipse.org/ganymede/index.jsp?topic=/org.eclips e.emf.doc/references/overview/EMF.html>>>> Hope that helps,> Sebastian> --> Need professional support for Eclipse Modeling?> Go visit: http://xtext.itemis.com
Re: Recursive cross-references [message #62813 is a reply to message #62799] Wed, 22 July 2009 12:19 Go to previous messageGo to next message
Eclipse UserFriend
Hi Thomas,

your Xtend code looks fine so far.
Using LET you could have written something like (not tested and probably
wrong syntax):

addEOpposites(ecore::EPackage this, Set[EReference] features):
let thisSide = features.getReference("Writer", "books") :
let otherSide = features.getReference("Book", "author") :
thisSide.setEOpposite(otherSide) ->
otherSide.setEOpposite(thisSide) -> Void;

I guess this would work.

You can even use ePackage.getEClassifier(name) and
eClass.getEStructuralFeature(name).

Regards,
Sebastian

Am 22.07.2009 17:56 Uhr, schrieb Thomas:
> Hi Sebastian,
>
> thanks for your help. I read the docs but must have missed the
> cross-reference terminal thing :-)
>
> I followed your suggestion to implement bidrectional references by using
> the post processor, but the solution I came up with is pretty ugly I
> guess. First time Xtend: yet another language :-) Especially the
> "addEOpposites" method is really bad:
> _____________________________________
> process(ecore::EPackage this):
> addEOpposites(allReferences())
> ;
>
> Set[EReference] allReferences(ecore::EPackage this):
> let result = {}.toSet() :
> this.eAllContents.typeSelect(EClass).collect(e|
> result.addAll(((EClass)e).allReferences())) ->
> result
> ;
>
> Set[EReference] allReferences(ecore::EClass this):
> let result = {}.toSet() :
> eReferences.collect(e|result.add(e)) ->
> result
> ;
>
> cached EReference getReference(Set[EReference] this, String className,
> String refName):
> select(e|((EClass)e.eContainer).name == className && e.name ==
> refName).flatten().get(0)
> ;
>
> addEOpposites(ecore::EPackage this, Set[EReference] features):
> features.getReference("Writer","books").setEOpposite(features.getReference( "Book","author"))
> ->
> features.getReference("Book","author").setEOpposite(features.getReference( "Writer","books"))
> ;________________________________Is there a leaner way to do this? In
> "addEOpposites" I would like to havelocal variables for both references
> instead of having to call "getReference"over and over again. While
> reading the Xtend docs I only came across the"let" statement but do not
> fully understand it. Do I really have to create anew EReference object
> and copy the attributes I need to it in order to storethe result from
> the "getReference" call?Thanks,Thomas."Sebastian Zarnekow"
> <Sebastian.Zarnekow@itemis.de> wrote in
> messagenews:h44raa$vqg$1@build.eclipse.org...> Welcome, Thomas,>> please
> see below.>> Am 21.07.2009 18:29 Uhr, schrieb Thomas:>> Hi,>>>> I am
> completly new to Xtext and EMF and just played around with it a bit>>
> inspired by the great webinar.>> So I tried to write a DSL that is
> similar>> to the EMF Library example[1]. My grammar for that looks like
> this:>> _______>> grammar org.xtext.example.Library with
> org.eclipse.xtext.common.Terminals>>>> generate library
> "http://www.xtext.org/example/Library">>>> Model:>>
> (library+=Library)*>> (writers+=Writer)*>> (books+=Book)*;>>>>
> Library:>> 'library' name=STRING '{'>> 'author' (writers+=[Writer])*>>
> 'book' (books+=[Book])*>> '}';>>>> Writer:>> 'writer' name=STRING '{'>>
> 'book' (books+=[Book])*>> '}';>>>> Book:>> 'book' title=STRING '{'>>
> 'pages' pages=INT>> 'author' author=[Writer]>> 'category'
> category=[BookCategory]>> '}';>>>> enum BookCategory:>> Mystery |
> ScienceFiction | Biography;>> ______>>>> The resulting ecore model looks
> pretty much like the example. The>> problem is, that there are some
> issues with the generated editor:>>>> 1. I modeled the names of writers
> and books as STRINGs and not IDs>> because I want to allow whitespaces
> here. My problem now is that the>> cross-references seems to expect
> values of type ID. Is there a way to>> change that? Does this make
> sense?>> You can use strings as concrete syntax elements for cross
> references aswell:>> author=[Writer] is the default and has the same
> meaning as> author=[Writer|ID]. So you are free to use
> author=[Writer|STRING].>> Btw: Have you had a look at the reference
> documentation athttp://www.xtext.org ?>>>>> 2. Because of the recursive
> dependency between writer and book, in order>> to create a book I need
> to create a writer before and vice versa:>>>> book book1{>> author
> author1>> }>>>> author author1 {>> book book1>> }>>>> So is it possible
> to reference an object which has not been created>> before in the
> file?>> This should work out of the box as Xtext is not sensitive to
> thedeclaration order of elements by default. However, Xtext will not
> detect thebidirectionality of the author and book cross references.
> Therefor you haveto use a post processor for the meta model inference
> (see the docs). Pleasenote that there is an open issue for this use case
> which is likely to befixed in the next service release 0.7.2.>>>>>
> Thanks in advance and Regards,>> Thomas.>>>>>>
> [1]>> http://help.eclipse.org/ganymede/index.jsp?topic=/org.eclips e.emf.doc/references/overview/EMF.html>>>>
> Hope that helps,> Sebastian> --> Need professional support for Eclipse
> Modeling?> Go visit: http://xtext.itemis.com


--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
Re: Recursive cross-references [message #62830 is a reply to message #62813] Wed, 22 July 2009 12:41 Go to previous message
Eclipse UserFriend
Originally posted by: panajotes.gmx.de

Ah, that's it. Your code works like a charm.

Thanks and Regards,
Thomas.

"Sebastian Zarnekow" <Sebastian.Zarnekow@itemis.de> wrote in message
news:h47e7e$97r$1@build.eclipse.org...
> Hi Thomas,
>
> your Xtend code looks fine so far.
> Using LET you could have written something like (not tested and probably
> wrong syntax):
>
> addEOpposites(ecore::EPackage this, Set[EReference] features):
> let thisSide = features.getReference("Writer", "books") :
> let otherSide = features.getReference("Book", "author") :
> thisSide.setEOpposite(otherSide) ->
> otherSide.setEOpposite(thisSide) -> Void;
>
> I guess this would work.
>
> You can even use ePackage.getEClassifier(name) and
> eClass.getEStructuralFeature(name).
>
> Regards,
> Sebastian
>
> Am 22.07.2009 17:56 Uhr, schrieb Thomas:
>> Hi Sebastian,
>>
>> thanks for your help. I read the docs but must have missed the
>> cross-reference terminal thing :-)
>>
>> I followed your suggestion to implement bidrectional references by using
>> the post processor, but the solution I came up with is pretty ugly I
>> guess. First time Xtend: yet another language :-) Especially the
>> "addEOpposites" method is really bad:
>> _____________________________________
>> process(ecore::EPackage this):
>> addEOpposites(allReferences())
>> ;
>>
>> Set[EReference] allReferences(ecore::EPackage this):
>> let result = {}.toSet() :
>> this.eAllContents.typeSelect(EClass).collect(e|
>> result.addAll(((EClass)e).allReferences())) ->
>> result
>> ;
>>
>> Set[EReference] allReferences(ecore::EClass this):
>> let result = {}.toSet() :
>> eReferences.collect(e|result.add(e)) ->
>> result
>> ;
>>
>> cached EReference getReference(Set[EReference] this, String className,
>> String refName):
>> select(e|((EClass)e.eContainer).name == className && e.name ==
>> refName).flatten().get(0)
>> ;
>>
>> addEOpposites(ecore::EPackage this, Set[EReference] features):
>> features.getReference("Writer","books").setEOpposite(features.getReference( "Book","author"))
>> ->
>> features.getReference("Book","author").setEOpposite(features.getReference( "Writer","books"))
>> ;________________________________Is there a leaner way to do this? In
>> "addEOpposites" I would like to havelocal variables for both references
>> instead of having to call "getReference"over and over again. While
>> reading the Xtend docs I only came across the"let" statement but do not
>> fully understand it. Do I really have to create anew EReference object
>> and copy the attributes I need to it in order to storethe result from
>> the "getReference" call?Thanks,Thomas."Sebastian Zarnekow"
>> <Sebastian.Zarnekow@itemis.de> wrote in
>> messagenews:h44raa$vqg$1@build.eclipse.org...> Welcome, Thomas,>> please
>> see below.>> Am 21.07.2009 18:29 Uhr, schrieb Thomas:>> Hi,>>>> I am
>> completly new to Xtext and EMF and just played around with it a bit>>
>> inspired by the great webinar.>> So I tried to write a DSL that is
>> similar>> to the EMF Library example[1]. My grammar for that looks like
>> this:>> _______>> grammar org.xtext.example.Library with
>> org.eclipse.xtext.common.Terminals>>>> generate library
>> "http://www.xtext.org/example/Library">>>> Model:>>
>> (library+=Library)*>> (writers+=Writer)*>> (books+=Book)*;>>>>
>> Library:>> 'library' name=STRING '{'>> 'author' (writers+=[Writer])*>>
>> 'book' (books+=[Book])*>> '}';>>>> Writer:>> 'writer' name=STRING '{'>>
>> 'book' (books+=[Book])*>> '}';>>>> Book:>> 'book' title=STRING '{'>>
>> 'pages' pages=INT>> 'author' author=[Writer]>> 'category'
>> category=[BookCategory]>> '}';>>>> enum BookCategory:>> Mystery |
>> ScienceFiction | Biography;>> ______>>>> The resulting ecore model looks
>> pretty much like the example. The>> problem is, that there are some
>> issues with the generated editor:>>>> 1. I modeled the names of writers
>> and books as STRINGs and not IDs>> because I want to allow whitespaces
>> here. My problem now is that the>> cross-references seems to expect
>> values of type ID. Is there a way to>> change that? Does this make
>> sense?>> You can use strings as concrete syntax elements for cross
>> references aswell:>> author=[Writer] is the default and has the same
>> meaning as> author=[Writer|ID]. So you are free to use
>> author=[Writer|STRING].>> Btw: Have you had a look at the reference
>> documentation athttp://www.xtext.org ?>>>>> 2. Because of the recursive
>> dependency between writer and book, in order>> to create a book I need
>> to create a writer before and vice versa:>>>> book book1{>> author
>> author1>> }>>>> author author1 {>> book book1>> }>>>> So is it possible
>> to reference an object which has not been created>> before in the
>> file?>> This should work out of the box as Xtext is not sensitive to
>> thedeclaration order of elements by default. However, Xtext will not
>> detect thebidirectionality of the author and book cross references.
>> Therefor you haveto use a post processor for the meta model inference
>> (see the docs). Pleasenote that there is an open issue for this use case
>> which is likely to befixed in the next service release 0.7.2.>>>>>
>> Thanks in advance and Regards,>> Thomas.>>>>>>
>> [1]>> http://help.eclipse.org/ganymede/index.jsp?topic=/org.eclips e.emf.doc/references/overview/EMF.html>>>>
>> Hope that helps,> Sebastian> --> Need professional support for Eclipse
>> Modeling?> Go visit: http://xtext.itemis.com
>
>
> --
> Need professional support for Eclipse Modeling?
> Go visit: http://xtext.itemis.com
Previous Topic:[XText] cross reference ... lazy
Next Topic:[Xtext] Parsing example
Goto Forum:
  


Current Time: Sun Jun 01 00:05:41 EDT 2025

Powered by FUDForum. Page generated in 0.04232 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top