Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Example for Semantic Refactoring
Example for Semantic Refactoring [message #1796284] Tue, 09 October 2018 14:34 Go to next message
Lukas Schaus is currently offline Lukas SchausFriend
Messages: 37
Registered: October 2016
Member
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 15:05 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
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


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Example for Semantic Refactoring [message #1796288 is a reply to message #1796286] Tue, 09 October 2018 15:54 Go to previous messageGo to next message
Lukas Schaus is currently offline Lukas SchausFriend
Messages: 37
Registered: October 2016
Member
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 15:57]

Report message to a moderator

Re: Example for Semantic Refactoring [message #1796289 is a reply to message #1796288] Tue, 09 October 2018 15:58 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
please have a look what lsp does. do the same in your java main. done.

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Example for Semantic Refactoring [message #1796351 is a reply to message #1796289] Thu, 11 October 2018 13:03 Go to previous messageGo to next message
Lukas Schaus is currently offline Lukas SchausFriend
Messages: 37
Registered: October 2016
Member
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 14:50 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
why do you need a workspace manager?

the idea is:

- start recording
- do the changes
- calculate changes
- apply changes to file


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Example for Semantic Refactoring [message #1796362 is a reply to message #1796357] Thu, 11 October 2018 15:37 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
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)
	}
	
	
}



Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Example for Semantic Refactoring [message #1796392 is a reply to message #1796362] Fri, 12 October 2018 09:53 Go to previous messageGo to next message
Lukas Schaus is currently offline Lukas SchausFriend
Messages: 37
Registered: October 2016
Member
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 10:32 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Simply add the binding to runtime module
It create a injector provider that uses idemodule too


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de

[Updated on: Fri, 12 October 2018 10:44]

Report message to a moderator

Re: Example for Semantic Refactoring [message #1796495 is a reply to message #1796395] Mon, 15 October 2018 10:34 Go to previous messageGo to next message
Lukas Schaus is currently offline Lukas SchausFriend
Messages: 37
Registered: October 2016
Member
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 13:25 Go to previous message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
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.


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de

[Updated on: Mon, 15 October 2018 13:26]

Report message to a moderator

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


Current Time: Thu Apr 25 01:02:08 GMT 2024

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

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

Back to the top