ScopeProvider and Linker [message #1763891] |
Mon, 22 May 2017 16:38 |
Fy Za Messages: 245 Registered: March 2010 |
Senior Member |
|
|
Hi all
I have this metamodel
package fsm : fsm = 'http://fsm'
{
class FSM
{
property ownedState#owningFSM : State[*|1] { ordered composes };
}
class State
{
property owningFSM#ownedState : FSM[1];
attribute name : String[?];
property outgoingTransition#source : Transition[*|1] { ordered composes };
property incomingTransition#target : Transition[*|1] { ordered };
attribute initial : Boolean[1];
attribute final : Boolean[1];
}
class Transition
{
property source#outgoingTransition : State[1];
property target#incomingTransition : State[1];
attribute input : String[?];
attribute output : String[?];
}
primitive datatype _'String' : 'java.lang.String' { serializable };
}
I generate a Xtext grammar from this metamodel
// automatically generated by Xtext
grammar org.xtext.example.fsm.FSM with org.eclipse.xtext.common.Terminals
import "http://fsm"
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
FSM returns FSM:
{FSM}
'FSM'
'{'
('ownedState' '{' ownedState+=State ( "," ownedState+=State)* '}' )?
'}';
State returns State:
initial?='initial'
final?='final'
'State'
'{'
('name' name=ID)?
('outgoingTransition' '{' outgoingTransition+=Transition ( "," outgoingTransition+=Transition)* '}' )?
'}';
Transition returns Transition:
'Transition'
'{'
('input' input=STRING)?
('output' output=STRING)?
'target' target=[State|ID]
'}';
In order to manage the eopposite relation target <--> incomingTransition
I create a FSMLinker class
public class FSMLinker extends LazyLinker {
@Override
protected EObject createProxy(EObject obj, INode node, EReference eRef) {
State s = (State) ((Transition)obj).eContainer();
FSM fsm = (FSM) s.eContainer();
for (State state : fsm.getOwnedState())
if(state.getName().equals(node.getText())){
return state;
}
return super.createProxy(obj, node, eRef);
}
}
I manage also the scope provider by editing FSMScopeProvider
class FSMScopeProvider extends AbstractFSMScopeProvider {
override getScope(EObject object, EReference ref) {
if (object instanceof Transition) {
scope_Transition_target(object as Transition, ref)
}
}
def scope_Transition_target(Transition transition, EReference reference) {
var ArrayList<IEObjectDescription> res = new ArrayList<IEObjectDescription>
var State s = transition.eContainer as State
var FSM fsm = s.eContainer as FSM
for (state : fsm.ownedState) {
res.add(EObjectDescription.create(state.name, state))
}
return new SimpleScope(IScope.NULLSCOPE, res)
}
}
When I create a model like this
FSM{
ownedState
{
initial final State { name s1 outgoingTransition {Transition {
input "did" output "aa" target s1
}
}},
initial final State { name s2 }
}
}
no error is happened.
However, when i change the model to be like that
FSM{
ownedState
{
initial final State { name s1 outgoingTransition {Transition {
input "did" output "aa" target s2
}
}},
initial final State { name s2 }
}
}
An error appears
- The required feature 'target' of 'fsm.impl.TransitionImpl@58395231{platform:/resource/fsm/test.fsm#//@ownedState.0/@outgoingTransition.0}' must be set
Any suggestion?
|
|
|
|
|
Re: ScopeProvider and Linker [message #1763908 is a reply to message #1763896] |
Mon, 22 May 2017 19:07 |
|
well after installing and fiddling around with oclinecore the following seems to work
public class MyDslDerivedStateComputer implements IDerivedStateComputer {
@Inject
SyntheticLinkingSupport sls;
@Override
public void installDerivedState(DerivedStateAwareResource resource, boolean preLinkingPhase) {
if (!resource.getContents().isEmpty() && preLinkingPhase) {
FSM fsm = (FSM) resource.getContents().get(0);
for (State s : fsm.getOwnedState()) {
for (State ss : fsm.getOwnedState()) {
for (Transition t : ss.getOutgoingTransition()) {
List<INode> nodes = NodeModelUtils.findNodesForFeature(t, FsmPackage.Literals.TRANSITION__TARGET);
if (!nodes.isEmpty()) {
String text = nodes.get(0).getText().trim();
if (s.getName().equals(text)) {
final EObject proxy = EcoreUtil.create(FsmPackage.Literals.TRANSITION);
((InternalEObject) proxy).eSetProxyURI(EcoreUtil.getURI(t));
s.getIncomingTransition().add((Transition) proxy);
}
}
}
}
}
}
}
@Override
public void discardDerivedState(DerivedStateAwareResource resource) {
if (!resource.getContents().isEmpty()) {
FSM fsm = (FSM) resource.getContents().get(0);
for (State s : fsm.getOwnedState()) {
s.getIncomingTransition().clear();
}
}
}
}
class MyDslRuntimeModule extends AbstractMyDslRuntimeModule {
def Class<? extends IDerivedStateComputer> bindIDerivedStateComputer() {
MyDslDerivedStateComputer
}
def Class<? extends Manager> bindIResourceDescription$Manager() {
DerivedStateAwareResourceDescriptionManager
}
override Class<? extends XtextResource> bindXtextResource() {
DerivedStateAwareResource
}
}
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Day Job: https://www.everest-systems.com
|
|
|
|
|
|
Re: ScopeProvider and Linker [message #1763920 is a reply to message #1763919] |
Tue, 23 May 2017 03:11 |
|
and i my unit test it works fine
/*
* generated by Xtext 2.12.0-SNAPSHOT
*/
package org.xtext.example.mydsl.tests
import com.google.inject.Inject
import fsm.FSM
import org.eclipse.xtext.testing.InjectWith
import org.eclipse.xtext.testing.XtextRunner
import org.eclipse.xtext.testing.util.ParseHelper
import org.eclipse.xtext.testing.validation.ValidationTestHelper
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.eclipse.emf.ecore.EPackage
import fsm.FsmPackage
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl
import org.eclipse.emf.common.util.URI
import java.io.ByteArrayOutputStream
import java.nio.charset.StandardCharsets
@RunWith(XtextRunner)
@InjectWith(MyDslInjectorProvider)
class MyDslParsingTest {
@Inject
ParseHelper<FSM> parseHelper
@Inject extension ValidationTestHelper h
@Test
def void loadModel() {
EPackage.Registry.INSTANCE.put(FsmPackage.eNS_URI, FsmPackage::eINSTANCE)
val result = parseHelper.parse('''
FSM{
ownedState
{
initial final State { name s1 outgoingTransition {Transition {
input "did" output "aa" target s2
}
}},
initial final State { name s2 }
}
}
''')
Assert.assertNotNull(result)
Assert.assertTrue(result.eResource.errors.isEmpty)
println(result.validate)
println('''
«FOR s : result.ownedState»
«s.name»:
«FOR t : s.outgoingTransition»
«t.target.name»
«ENDFOR»
«s.name»: «s.incomingTransition»
«ENDFOR»
''')
val RS2 = new ResourceSetImpl
val r2 = RS2.createResource(URI.createURI("dummy.xmi"))
r2.contents.add(result)
val baos = new ByteArrayOutputStream
r2.save(baos, null)
println(new String(baos.toByteArray, StandardCharsets.UTF_8))
}
}
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Day Job: https://www.everest-systems.com
|
|
|
Re: ScopeProvider and Linker [message #1763946 is a reply to message #1763920] |
Tue, 23 May 2017 09:42 |
Fy Za Messages: 245 Registered: March 2010 |
Senior Member |
|
|
For me also the test is fine.
For the tested model
FSM{
ownedState
{
initial final State { name s1 outgoingTransition {Transition {
input "did" output "aa" target s2
}
}},
initial final State { name s2 }
}
}
when, I test parse it, I obtain the correct xmi
<?xml version="1.0" encoding="ASCII"?>
<fsm:FSM xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:fsm="http://fsm">
<ownedState name="s1" initial="true" final="true">
<outgoingTransition target="//@ownedState.1" input="did" output="aa"/>
</ownedState>
<ownedState name="s2" incomingTransition="//@ownedState.0/@outgoingTransition.0" initial="true" final="true"/>
</fsm:FSM>
However, when I Run my toxmi method
I obtain the following without incomingTransition
<?xml version="1.0" encoding="ASCII"?>
<fsm:FSM xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:fsm="http://fsm">
<ownedState name="s1" initial="true" final="true">
<outgoingTransition target="//@ownedState.1" input="did" output="aa"/>
</ownedState>
<ownedState name="s2" initial="true" final="true"/>
</fsm:FSM>
This is my code used to save as xmi.
public void run(IAction action) {
IFile file = getFile();
URI xtextURI = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
XtextResourceSet resourceSet = new XtextResourceSet();
Resource xtextResource = resourceSet.createResource(xtextURI);
System.out.println(xtextURI.toString());
if (xtextResource != null){
Map<String,Boolean> options = new HashMap<String,Boolean>();
options.put(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);
try {
xtextResource.load(options);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Resource xmiResource = new XMIResourceFactoryImpl().createResource(xtextURI.trimFileExtension().appendFileExtension("xmi"));
xmiResource.getContents().add(xtextResource.getContents().get(0));
EcoreUtil.resolveAll(resourceSet);
try {
xmiResource.save(null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
ModelStatus sts = new ModelStatus(IStatus.ERROR, "org.eclipse.xtext.toXmi", "http://fsm", "Impossible to load the selected file for xmi conversion.\n" +
"Maybe this file is not an XText instance ? Status");
ErrorDialog.openError(shell, "Error", "Impossible to load the selected file for xmi conversion.\n" +
"Maybe this file is not an XText instance ?", sts);
}
}
Is it correct, PLZ ?
|
|
|
|
Re: ScopeProvider and Linker [message #1763964 is a reply to message #1763952] |
Tue, 23 May 2017 12:49 |
Fy Za Messages: 245 Registered: March 2010 |
Senior Member |
|
|
I update my toXmi class
public void run(IAction action) {
IFile file = getFile();
Injector injector = FsmActivator.getInstance().getInjector("org.xtext.example.fsm.FSM");
XtextResourceSetProvider provider = injector.getInstance(XtextResourceSetProvider.class);
ResourceSet resourceSet = provider.get(file.getProject());
URI xtextURI = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
XtextResource xtextResource = (XtextResource) resourceSet.getResource(xtextURI, true);;
if (xtextResource != null){
Map<String,Boolean> options = new HashMap<String,Boolean>();
options.put(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);
try {
xtextResource.load(options);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Resource xmiResource = new XMIResourceFactoryImpl().createResource(xtextURI.trimFileExtension().appendFileExtension("xmi"));
xmiResource.getContents().add(xtextResource.getContents().get(0));
EcoreUtil.resolveAll(resourceSet);
try {
xmiResource.save(null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
ModelStatus sts = new ModelStatus(IStatus.ERROR, "org.eclipse.xtext.toXmi", "http://fsm", "Impossible to load the selected file for xmi conversion.\n" +
"Maybe this file is not an XText instance ? Status");
ErrorDialog.openError(shell, "Error", "Impossible to load the selected file for xmi conversion.\n" +
"Maybe this file is not an XText instance ?", sts);
}
}
I obtain that
<?xml version="1.0" encoding="ASCII"?>
<fsm:FSM xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:fsm="http://fsm">
<ownedState name="s1" initial="true" final="true">
<outgoingTransition input="did" output="aa">
<target href="My.fsm#|0"/>
</outgoingTransition>
</ownedState>
<ownedState name="s2" initial="true" final="true"/>
</fsm:FSM>
No IncomingTransition and target reference is not correct.
Plz, Christian, Does exist an example that can be followed to create my own toxmi module for my dsl?
best regards
|
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.10670 seconds