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 }; }
// 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] '}';
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); } }
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) } }
FSM{ ownedState { initial final State { name s1 outgoingTransition {Transition { input "did" output "aa" target s1 } }}, initial final State { name s2 } } }
FSM{ ownedState { initial final State { name s1 outgoingTransition {Transition { input "did" output "aa" target s2 } }}, initial final State { name s2 } } }
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 } }
java.lang.RuntimeException: Could not serialize State: State.incomingTransition violates the upper bound: It holds 1 values, but only 0 are allowed. Semantic Object: FSM.ownedState[0]->State's' URI: platform:/resource/fsm-examples/My.fsm Context: State returns State at org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic$ExceptionThrowingAcceptor.accept(ISerializationDiagnostic.java:131) at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.createSequence(BacktrackingSemanticSequencer.java:503) at org.xtext.example.fsm.serializer.FSMSemanticSequencer.sequence_State(FSMSemanticSequencer.java:69) at org.xtext.example.fsm.serializer.FSMSemanticSequencer.sequence(FSMSemanticSequencer.java:39) at org.eclipse.xtext.serializer.sequencer.AbstractSemanticSequencer.createSequence(AbstractSemanticSequencer.java:67) at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.acceptEObjectRuleCall(SequenceFeeder.java:325) at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.acceptRuleCall(SequenceFeeder.java:352) at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.accept(SequenceFeeder.java:263) at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.accept(BacktrackingSemanticSequencer.java:434) at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.createSequence(BacktrackingSemanticSequencer.java:501) at org.xtext.example.fsm.serializer.FSMSemanticSequencer.sequence_FSM(FSMSemanticSequencer.java:57) at org.xtext.example.fsm.serializer.FSMSemanticSequencer.sequence(FSMSemanticSequencer.java:36) at org.eclipse.xtext.serializer.sequencer.AbstractSemanticSequencer.createSequence(AbstractSemanticSequencer.java:67) at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:115) at org.eclipse.xtext.serializer.impl.Serializer.serializeToRegions(Serializer.java:136) at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:142) at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:189) at org.eclipse.xtext.resource.XtextResource.doSave(XtextResource.java:386) at org.eclipse.emf.ecore.resource.impl.ResourceImpl.save(ResourceImpl.java:1430) at org.eclipse.emf.ecore.resource.impl.ResourceImpl.saveOnlyIfChangedWithMemoryBuffer(ResourceImpl.java:1144) at org.eclipse.emf.ecore.resource.impl.ResourceImpl.save(ResourceImpl.java:985) at fsm.presentation.FsmEditor$18.execute(FsmEditor.java:1498) at org.eclipse.ui.actions.WorkspaceModifyOperation.lambda$0(WorkspaceModifyOperation.java:107) at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2240) at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2267) at org.eclipse.ui.actions.WorkspaceModifyOperation.run(WorkspaceModifyOperation.java:128) at org.eclipse.jface.operation.ModalContext$ModalContextThread.run(ModalContext.java:119)
/* * 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)) } }
FSM{ ownedState { initial final State { name s1 outgoingTransition {Transition { input "did" output "aa" target s2 } }}, initial final State { name s2 } } }
<?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>
<?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>
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); } }
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); } }
<?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>