Skip to main content



      Home
Home » Modeling » TMF (Xtext) » Example for Semantic Refactoring
Example for Semantic Refactoring [message #1796284] Tue, 09 October 2018 10:34 Go to next message
Eclipse UserFriend
Hello Everyone,

Since Xtext 2.13 there is the new interface for semantic editing that is described in this blog post: https://typefox.io/xtext-2-13-0-released-semantic-editing-made-easy

In my project I have to do some renaming so i wanted to give it a try. Are there any demo Project where I can see how to use the mechanism?

I want to create an API that can be called headlessly (without eclipse). It should for instance be able to find specific elements with specific names and rename them and all the cross references to that element in other files too.

Without an example I am completely lost.

It would be awesome if somebody could point me to a working example or could elaborate the steps necessary in order to achieve my goal.

All the best,

Lukas
Re: Example for Semantic Refactoring [message #1796286 is a reply to message #1796284] Tue, 09 October 2018 11:05 Go to previous messageGo to next message
Eclipse UserFriend
am not sure what you mean by "rename"
this is a out of the box usecase.
see e.g.
org.eclipse.xtext.ide.server.LanguageServerImpl.rename(RenameParams)
org.eclipse.xtext.ide.server.rename.RenameService
Re: Example for Semantic Refactoring [message #1796288 is a reply to message #1796286] Tue, 09 October 2018 11:54 Go to previous messageGo to next message
Eclipse UserFriend
Thank you for your fast reply.
I know that I can rename elements using alt + shift + r in the editor and I guess that somehow the Methods in the classes you pointed me to are called.

But I would like to develop an api that I will call headlessly.

i tryed to develop a minimal working example:
Consider this Grammar
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"


Model:
	person+=Person*
	groups+= Group*;
	
Person:
	Student | Teacher
;

Group:
	StudentGroup | TeacherGroup
;
	
Student:
	'student' name=ID 
;

Teacher:
	'teacher' name=ID
 ;
	
StudentGroup:
	'students' name=ID '{' members+=[Student|ID] (',' members+=[Student|ID])* '}' 
;

TeacherGroup:
	'teachers' name=ID '{' members+=[Teacher|ID] (',' members+=[Teacher|ID])* '}' 
;


And these .mydsl files:

a.mydsl
student Paule
student /*here is a comment*/ Asterix
teacher Asterix

students allStudents {
	Paule,
	Asterix,
	Miracolix
}

teachers allTeachers {
	Asterix
}


b.mydsl
student Miracolix


Now I want to have a java function that takes a number of resources and performs renaming of students

so calling renameStudents('a.mydsl', 'b.mydsl', 'Asterix', 'Obelix')

The function should modify the given resources and the files should look like this

a_new.mydsl
student Paule
student /*here is a comment*/ Obelix
teacher Asterix

students allStudents {
	Paule,
	Obelix,
	Miracolix
}

teachers allTeachers {
	Asterix
}


b.mydsl
student Miracolix


Also i could imagine more semantic adjustments that are a little more complex than renaming.

[Updated on: Tue, 09 October 2018 11:57] by Moderator

Re: Example for Semantic Refactoring [message #1796289 is a reply to message #1796288] Tue, 09 October 2018 11:58 Go to previous messageGo to next message
Eclipse UserFriend
please have a look what lsp does. do the same in your java main. done.
Re: Example for Semantic Refactoring [message #1796351 is a reply to message #1796289] Thu, 11 October 2018 09:03 Go to previous messageGo to next message
Eclipse UserFriend
I am sorry Christian but I am still lost.

I have problems to understand what a WorkspaceManager is, how to get it or intantiate it. Do I need to implement it in the .ide project?

But maybe lets takeone step back.

Connsider this slightly changed grammar:
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"


Model:
	person+=Person*
	groups+= Group*;
	
Person:
	Student | Teacher 
;

Group:
	StudentGroup | TeacherGroup
;

enum Status:
	ACTIVE = 'active' | INACTIVE = 'inactive'
;
	
Student:
	'student' name=ID
;

Teacher:
	'teacher' name=ID
 ;
	
StudentGroup:
	'students' status=Status? name=ID '{' members+=[Student|ID] (',' members+=[Student|ID])* '}' 
;

TeacherGroup:
	'teachers' status=Status? name=ID '{' members+=[Teacher|ID] (',' members+=[Teacher|ID])* '}' 
;


Now i would like to toggle the status value. In my dreams al I have to do is something like the following:

	def toogleStatusInGroup(Resource resource, String groupID) {
		val model = resource as Model
		
		val selectedGroup = model.eAllContents.filter(StudentGroup).findFirst[group |
			group.name.equals(groupID)
		]
		
		switch (selectedGroup.status){
			case Status.ACTIVE: selectedGroup.eSet(selectedGroup.eClass.getEStructuralFeature(MyDslPackage.STUDENT_GROUP__STATUS) , Status.INACTIVE)
			case Status.INACTIVE: selectedGroup.eSet(selectedGroup.eClass.getEStructuralFeature(MyDslPackage.STUDENT_GROUP__STATUS) , Status.INACTIVE)
		}
		
		model.updateResourceFromEMF()
	}


If there is a possibility to do something like this I would be very glad to learn about it.

Thank you

Lukas
Re: Example for Semantic Refactoring [message #1796357 is a reply to message #1796351] Thu, 11 October 2018 10:50 Go to previous messageGo to next message
Eclipse UserFriend
why do you need a workspace manager?

the idea is:

- start recording
- do the changes
- calculate changes
- apply changes to file
Re: Example for Semantic Refactoring [message #1796362 is a reply to message #1796357] Thu, 11 October 2018 11:37 Go to previous messageGo to next message
Eclipse UserFriend
here is a very pure and incomplete example

Model:
	greetings+=Greeting*;
	
Greeting:
	'Hello' name=ID ('from' from=[Greeting]) ? '!';


package org.xtext.example.mydsl3.tests

import com.google.inject.Inject
import com.google.inject.Provider
import java.io.ByteArrayOutputStream
import org.apache.log4j.Logger
import org.eclipse.emf.common.util.URI
import org.eclipse.emf.ecore.EObject
import org.eclipse.emf.ecore.resource.ResourceSet
import org.eclipse.emf.ecore.util.EcoreUtil
import org.eclipse.xtext.ide.refactoring.IRenameStrategy2
import org.eclipse.xtext.ide.refactoring.RefactoringIssueAcceptor
import org.eclipse.xtext.ide.refactoring.RenameChange
import org.eclipse.xtext.ide.refactoring.RenameContext
import org.eclipse.xtext.ide.serializer.IChangeSerializer
import org.eclipse.xtext.ide.serializer.IEmfResourceChange
import org.eclipse.xtext.testing.InjectWith
import org.eclipse.xtext.testing.extensions.InjectionExtension
import org.eclipse.xtext.testing.util.ParseHelper
import org.eclipse.xtext.util.ITextRegion
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.^extension.ExtendWith
import org.xtext.example.mydsl3.myDsl.Model
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.resource.IResourceServiceProvider
import org.eclipse.xtext.ide.serializer.ITextDocumentChange

@ExtendWith(InjectionExtension)
@InjectWith(MyDslInjectorProvider)
class MyDslParsingTest {
	@Inject
	ParseHelper<Model> parseHelper

	@Inject
	Provider<IChangeSerializer> changeSerializerProvider

	@Inject
	IRenameStrategy2 renameStrategy
	
	@Inject
	IResourceServiceProvider.Registry registry

	@Test
	def void loadModel() {
		var model = '''
			Hello Xtext!
			Hello World from Xtext!
		'''
		val result = parseHelper.parse(model)
		Assertions.assertNotNull(result)
		val errors = result.eResource.errors
		val resourceSet = result.eResource.resourceSet
		Assertions.assertTrue(errors.isEmpty, '''Unexpected errors: ?errors.join(", ")?''')
		val g0 = result.greetings.head
		val RefactoringIssueAcceptor issueAcceptor = new RefactoringIssueAcceptor() {
			
			override add(Severity severity, String message, URI resourceUri) {
				throw new UnsupportedOperationException("TODO: auto-generated method stub")
			}	
			
			override add(Severity severity, String message, EObject element) {
				throw new UnsupportedOperationException("TODO: auto-generated method stub")
			}
			
			override add(Severity severity, String message, Object... params) {
				throw new UnsupportedOperationException("TODO: auto-generated method stub")
			}
			
			override add(Severity severity, String message, URI uri, ResourceSet resourceSet) {
				throw new UnsupportedOperationException("TODO: auto-generated method stub")
			}
			
			override add(Severity severity, String message, EObject element, ITextRegion region) {
				throw new UnsupportedOperationException("TODO: auto-generated method stub")
			}
			
			override add(Severity severity, String message, Exception exc, Logger log) {
				throw new UnsupportedOperationException("TODO: auto-generated method stub")
			}

			

		}

		val change = new RenameChange(g0.name + "2", EcoreUtil.getURI(g0))
		val changeSerializer = changeSerializerProvider.get
		val context = new RenameContext(#[change], resourceSet, changeSerializer, issueAcceptor)
		renameStrategy.applyRename(context)
		
		val model2 = new StringBuilder(model)
		changeSerializer.applyModifications [
			e|	println(e.class)
			if (e instanceof ITextDocumentChange) {
				for (r : e.replacements.sortBy[r|r.endOffset].reverse) {
					model2.replace(r.offset, r.offset+r.length, r.replacementText);
				}
			} else {
				//TODO handle this case. see org.eclipse.xtext.ide.server.rename.ChangeConverter._handleReplacements(IEmfResourceChange)
			}
			
		]
		println(model2)
	}
	
	
}

Re: Example for Semantic Refactoring [message #1796392 is a reply to message #1796362] Fri, 12 October 2018 05:53 Go to previous messageGo to next message
Eclipse UserFriend
Thank you for your detailed reply. I am starting to get the idea. Unfortunately i can not run your code. I am getting the following stacktrace:

com.google.inject.ConfigurationException: Guice configuration errors:

1) No implementation for org.eclipse.xtext.ide.refactoring.IRenameStrategy2 was bound.
  while locating org.eclipse.xtext.ide.refactoring.IRenameStrategy2
    for field at org.xtext.example.mydsl.tests.RenameTests.renameStrategy(Unknown Source)
  while locating org.xtext.example.mydsl.tests.RenameTests

1 error
	at com.google.inject.internal.InjectorImpl.getMembersInjector(InjectorImpl.java:952)
	at com.google.inject.internal.InjectorImpl.getMembersInjector(InjectorImpl.java:957)
	at com.google.inject.internal.InjectorImpl.injectMembers(InjectorImpl.java:943)
	at org.eclipse.xtext.testing.extensions.InjectionExtension.beforeEach(InjectionExtension.java:56)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeEachCallbacks$0(TestMethodTestDescriptor.java:129)
	at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:155)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeEachCallbacks(TestMethodTestDescriptor.java:128)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:107)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:112)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
	at java.util.stream.ReferencePipeline$2$1.accept(Unknown Source)
	at java.util.Iterator.forEachRemaining(Unknown Source)
	at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown Source)
	at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
	at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
	at java.util.stream.ReferencePipeline.forEach(Unknown Source)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
	at java.util.stream.ReferencePipeline$2$1.accept(Unknown Source)
	at java.util.Iterator.forEachRemaining(Unknown Source)
	at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown Source)
	at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
	at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
	at java.util.stream.ReferencePipeline.forEach(Unknown Source)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)


Do I need to add something to the dependencies? Eclipse is able to find the class. I am working on Xtext 2.15
Re: Example for Semantic Refactoring [message #1796395 is a reply to message #1796392] Fri, 12 October 2018 06:32 Go to previous messageGo to next message
Eclipse UserFriend
Simply add the binding to runtime module
It create a injector provider that uses idemodule too

[Updated on: Fri, 12 October 2018 06:44] by Moderator

Re: Example for Semantic Refactoring [message #1796495 is a reply to message #1796395] Mon, 15 October 2018 06:34 Go to previous messageGo to next message
Eclipse UserFriend
I can bind it in the IdeModule but it does not have any effect. In runtimeModule I get errors. I added a screenshot

https://www1.xup.in/exec/ximg.php?fid=17372580
Re: Example for Semantic Refactoring [message #1796506 is a reply to message #1796495] Mon, 15 October 2018 09:25 Go to previous message
Eclipse UserFriend
for my prototype i did no care about messing up dependencies. ....
sorry i thought you were either able to add all needed to runtimemodule/mydsl module
or create a new injector provider class that uses MyDslIdeModule too and use that class in the test.

[Updated on: Mon, 15 October 2018 09:26] by Moderator

Previous Topic:Xtext 2.15.0 released!
Next Topic:Access location of non-dsl files in workspace
Goto Forum:
  


Current Time: Tue Jun 17 01:32:23 EDT 2025

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

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

Back to the top