|
|
|
|
Re: Get the object containing the actual cross-reference [message #1768889 is a reply to message #1768857] |
Mon, 24 July 2017 15:25 |
Marc Schlegel Messages: 69 Registered: July 2009 |
Member |
|
|
Using the ECrossReferenceAdapter yields the same results as by navigating upwards with eContainer calls.
I assume my design might be broken a little.
I will try to explain my model using a simplified version. What I am modelling is a simple structure:
Data
- 1 -n Fields
- 1- n Groups
-- each Group can define 1-n Fields again
-- each Group can define 1-n Subgroups
Within the configuration I try to model we have lots of Fields which have to be specified in several Data blocks, so I want to define a common type which again defines 1-n Fields. Those common-fields are cross-referenced at each location where a field would be valid. The generator expands those types as though there would be n fields.
In order to keep everything as simple as possible I changed my model like this (skipping the groups and subgroups since it is the same as in the previous sample), so there should be no need for an additional Common-DSL.
Model
-Common
-- 1-n CommonField
--- 1-n Field
-Data
-- 1 -n Field | CommonField
-- 1- n Group
Basically starting a new dsl-file you have to choose if you are going to define a data-block or a common-block.
Example file for common declaration
Common {
CommonA{
Text A
Text B
Text C
Text D
}
CommonB{
Date X
Date Y
}
}
Putting it together
SomethingA
Fields {
Integer IntA
Integer IntB
type CommonB // <-- interesting
}
GroupA {
Fields {
Integer IntX
type CommonA // <-- the generator has to know that this cross-ref is inside GroupA
}
}
The grammar is modelled like this (skipped everything not relevant). The model is defined with Xcore
ModelRule returns Model:
"Common" "{" (commonFields+=CommonFieldsRule)+ "}" |data=DataRule
;
CommonFieldsRule returns CommonField:
name=ID "{"
(fields+=FieldRule)+
"}"
;
DataRule returns Data:
name=ID
("Fields" "{"
(fields+=FieldRule)+
"}")*
(groups+=GroupRule)+
;
GroupRule returns Group:
name=ID "{"
("Fields" "{"
(fields+=SingleFieldOrCommonFieldRefRule)+
"}")*
(groups+=GroupRule)*
"}"
;
SingleFieldOrCommonFieldRefRule returns Field:
CommonFieldRefRule | FieldRule
;
CommonFieldRefRule returns CommonFieldRef:
"type" fieldRef=[CommonField]
;
FieldRule returns SingleField:
name=ID
;
All this works as expected, except the one problem stated in the beginning. I cannot figure out if a cross-reference to a CommonField was specified within a (Sub-)Group or just within the Data-block.
Now I tried using the recommended ECrossReferenceAdapter in my Generator.
class DatenversorgungDslGenerator extends AbstractGenerator {
@Inject
private XtextResourceSet resourceSet;
val crossReferenceAdapter = new ECrossReferenceAdapter()
override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
resourceSet.eAdapters.add(crossReferenceAdapter)
... start codegen
}
...
def dispatch CharSequence printData(Group group)'''
<group.name»>
«FOR field : group.fields.filter[it.valid]»
«field.printData»
«ENDFOR»
«FOR subgroups : group.groups.filter[it.valid]»
«subgroups.printData»
«ENDFOR»
</group.name»>
'''
def dispatch CharSequence printData (CommonFieldRef commonFieldRef)'''
«FOR field : commonFieldRef.fieldRef.fields»
field.printData»
«ENDFOR»
'''
def dispatch CharSequence printData(SingleField field){
val sb = new StringBuilder("<")
... append some stuff
if(field.eContainer instanceof Group){
sb.append("group=\"" + (field.eContainer as Group).name + "\"")
}
else if (field.eContainer instanceof CommonField) {
// figure out if the CommonField was referenced from within a group
val settings = crossReferenceAdapter.getInverseReferences(field.eContainer, true) // eContainer of CommonField should be CommonFieldRef which contains the cross-ref
settings.forEach[
println(it.EObject)
val x = (it.EStructuralFeature) as EReference
if(x.equals(MyPackage.eINSTANCE.commonFieldRef_FieldRef)){
println(it.EObject)
}
]
}
return sb.toString
}
My problem in the last method is, no matter what I try with the EReference I get from the ECrossReferenceAdapter, the results are always within the "Common" branch of Model where I was hoping to navigate (inverse) to the Data-branch.
[Updated on: Mon, 24 July 2017 15:33] Report message to a moderator
|
|
|
Re: Get the object containing the actual cross-reference [message #1768895 is a reply to message #1768889] |
Mon, 24 July 2017 17:12 |
Marc Schlegel Messages: 69 Registered: July 2009 |
Member |
|
|
Oh oh...I think I just forgot to model the "opposite" direction in my xcore model.
EDIT: Using opposite declaration for cross-references doesnt work in my case because in Xtext they have to be modelled on both sides when crossing resource-boundaries (because the model needs to be reconstructed from the file).
I ended up changing my generator by passing down a possible group (if available) instead of trying to resolve the location of the cross-reference
Thanks for everyones help
[Updated on: Tue, 25 July 2017 09:29] Report message to a moderator
|
|
|
Powered by
FUDForum. Page generated in 0.03643 seconds