Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Parsing in-memory codes with crossrefs between resources in RCP application(I need to parse in-memory pseudocodes split into several chunks using Xtext. The chunks have crossreferences between each other. It works from an RCP application if the content is in files in the work)
Parsing in-memory codes with crossrefs between resources in RCP application [message #1795760] Fri, 28 September 2018 06:40 Go to next message
Daniel Darvas is currently offline Daniel DarvasFriend
Messages: 10
Registered: July 2014
Junior Member
Hello,

TL;DR: I need to parse in-memory pseudocodes split into several chunks using Xtext. The chunks have crossreferences between each other. It works from an RCP application if the content is in files in the workspace, also from a standalone application for in-memory pseudocodes (using 'createInjectorAndDoEMFRegistration'), but now I need to combine the two approaches, i.e. parsing in-memory pseudocodes in RCP app, but the crossreference resolution between resources do not work.

In my project I am parsing pseudocode split into several files using Xtext.
When executed as Eclipse RCP application, the crossreferences between files in the editor work as expected, this is nice.
When executed as a command line application, I follow the method described in the FAQ (https://wiki.eclipse.org/Xtext/FAQ#How_do_I_load_my_model_in_a_standalone_Java_application.C2.A0.3F): I use new MyLanguageStandaloneSetup().createInjectorAndDoEMFRegistration(); to get an injector, then inject a Provider<XtextResourceSet> resourceSetProvider, create an XtextResourceSet, set the OPTION_RESOLVE_ALL to true, then for each chunk of the pseudocode to be parsed I create a new resource in the resource set:
Resource resource = resourceSet.createResource(URI.createURI("dummy:/" + (i++) + ".ext");
InputStream inputStream = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
resource.load(inputStream, resourceSet.getLoadOptions());

This works well too, the crossreferences between the resources are resolved correctly.

Now I need to combine these two approaches. In my Eclipse RCP application I need to be able to parse files in the workspace, as well as pseudocodes that exist only in memory, i.e., not backed by any file in the workspace. Of course, the second approach described above is not expected to work out of the box, as it uses createInjectorAndDoEMFRegistration(). The parsing of in-memory pseudocodes work with that, but I get exceptions ("Passed org.eclipse.xtext.builder.clustering.CurrentDescriptions is not based on a resource set") and GUI glitches in the editor, as expected.
If instead of creating a new injector I fetch the injector used by the GUI (via the getInjector method of the Activator in my ui project), the crossreference resolution between different dummy:/ resources do not work, and I get "ERROR org.eclipse.xtext.linking.lazy.LazyLinkingResource - resolution of uriFragment '|30' failed." errors. If I use the activator's injector but with platform:/ URIs pointing to existing files, it seems to work.

What is different between the automatically created injector and the one created by createInjectorAndDoEMFRegistration that prevents me from parsing the dummy:/ resources properly, with crossreference resolution between different resources in the same resource set? May I fix it somehow or am I doing something stupid? Unfortunately the nicer, ExecutableExtensionFactory-based solution (as mentioned in http://koehnlein.blogspot.com/2012/11/xtext-tip-how-do-i-get-guice-injector.html) to get the injector is not an option, but I assume it would not make any difference as I'd get the same injector.


You can find an MWE attached. The key part of it is the following code (in org.xtext.example.mydsl.ui.CustomMydslActivator):
Injector injector = MydslActivator.getInstance().getInjector(ORG_XTEXT_EXAMPLE_MYDSL_MYDSL);
XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class);
resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);

Resource res1 = resourceSet.createResource(URI.createURI("dummy:/1.mydsl"));
res1.load(new ByteArrayInputStream("person A; Hello A! Hello B!".getBytes(StandardCharsets.UTF_8)), resourceSet.getLoadOptions());

Resource res2 = resourceSet.createResource(URI.createURI("dummy:/2.mydsl"));
res2.load(new ByteArrayInputStream("person B;".getBytes(StandardCharsets.UTF_8)), resourceSet.getLoadOptions());

EcoreUtil.resolveAll(resourceSet); // just in case

Model model1 = (Model)res1.getContents().get(0);
System.out.println(model1.getGreetings().get(1).getPerson()); // Prints: org.xtext.example.mydsl.myDsl.impl.PersonImpl@51038633 (eProxyURI: dummy:/1.mydsl#|1)
System.out.println(model1.getGreetings().get(1).getPerson().eIsProxy()); // Prints: true. Apparently, the proxy cannot be resolved.


Thanks a lot for any suggestion,
Daniel
Re: Parsing in-memory codes with crossrefs between resources in RCP application [message #1795772 is a reply to message #1795760] Fri, 28 September 2018 10:57 Go to previous messageGo to next message
Christian Dietrich is currently online Christian DietrichFriend
Messages: 14666
Registered: July 2009
Senior Member
hi,

- i wonder how you managed to create that broken zip file. (some bad mixing of windows paths inside the file nams)
- the usecase you describe is non xtext supports out of the box
- main problem is dummy uris. and containers. and visible containers. and indexing ......
- you might be able to cheat around that

public class CustomMydslActivator extends MydslActivator {
	@Override
	public void start(BundleContext context) throws Exception {
		super.start(context);

		// Yes, it really does not belong here, put here only for the purposes of the MWE.
		Injector injector = MydslActivator.getInstance().getInjector(ORG_XTEXT_EXAMPLE_MYDSL_MYDSL);
		
		XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class);

		resourceSet.addLoadOption("DUMMY", Boolean.TRUE);
		// this is a terrible bad idea
		// resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);
		
		Resource res1 = resourceSet.createResource(URI.createURI("dummy:/1.mydsl"));
		res1.load(new ByteArrayInputStream("person A; Hello A! Hello B!".getBytes(StandardCharsets.UTF_8)), resourceSet.getLoadOptions());
		System.out.println(res1.getErrors());
		Resource res2 = resourceSet.createResource(URI.createURI("dummy:/2.mydsl"));
		res2.load(new ByteArrayInputStream("person B;".getBytes(StandardCharsets.UTF_8)), resourceSet.getLoadOptions());
		System.out.println(res2.getErrors());
		
		EcoreUtil.resolveAll(resourceSet); // (not) just in case
		
		Model model1 = (Model)res1.getContents().get(0);
		System.out.println(model1.getGreetings().get(1).getPerson()); // Prints: org.xtext.example.mydsl.myDsl.impl.PersonImpl@51038633 (eProxyURI: dummy:/1.mydsl#|1)
		System.out.println(model1.getGreetings().get(1).getPerson().eIsProxy()); // Prints: true. Apparently the proxy cannot be resolved.
	}
}


class MyDslUiModule extends AbstractMyDslUiModule {

	def Class<? extends IResourceDescriptionsProvider> bindIResourceDescriptionsProvider() {
		CheatingResourceDescriptionsProvider
	}

	override Class<? extends IAllContainersState.Provider> bindIAllContainersState$Provider() {
		return CheatingContainerStateProvider
	}
}


public class CheatingResourceDescriptionsProvider extends ResourceDescriptionsProvider {
	
	public static class CheatingResourceSetBasedResourceDescriptions extends ResourceSetBasedResourceDescriptions {
		
	}
	
	@Inject
	private Provider<CheatingResourceSetBasedResourceDescriptions> resourceSetBasedResourceDescriptions;

	@Override
	public IResourceDescriptions getResourceDescriptions(ResourceSet resourceSet) {
		if (Boolean.TRUE.equals(resourceSet.getLoadOptions().get("DUMMY"))) {
			ResourceSetBasedResourceDescriptions d = resourceSetBasedResourceDescriptions.get();
			d.setContext(resourceSet);
			return d;
		}
		return super.getResourceDescriptions(resourceSet);
	}
	
}



public class CheatingContainerStateProvider extends ContainerStateProvider {
	
	@Inject
	private ResourceSetBasedAllContainersStateProvider containerStateProvider;
	
	@Override
	public IAllContainersState get(IResourceDescriptions context) {
		if (context instanceof CheatingResourceSetBasedResourceDescriptions) {
			return containerStateProvider.get(context);
		}
		return super.get(context);
	}

}



(no guarantees)


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Parsing in-memory codes with crossrefs between resources in RCP application [message #1795850 is a reply to message #1795772] Mon, 01 October 2018 11:48 Go to previous message
Daniel Darvas is currently offline Daniel DarvasFriend
Messages: 10
Registered: July 2014
Junior Member
Dear Christian,

Thank you very much for your swift help! I have adapted it to our real code and it seems to work like a charm.

> - i wonder how you managed to create that broken zip file. (some bad mixing of windows paths inside the file nams)
It was created with 7-Zip, sorry for the additional burden.

> - the usecase you describe is non xtext supports out of the box
I thought there were already use cases when some text somehow appearing in memory (e.g. from a SWT textbox or a file not in the workspace) needs to be parsed together with some other resources (e.g. loaded from file). Apparently I was mistaken.

Thanks again!

Cheers,
Daniel
Previous Topic:Formatter2 Warnings Everywhere: Discouraged access: The type IHiddenRegionFormatter
Next Topic:Testing: Different start symbol for parsing
Goto Forum:
  


Current Time: Fri Apr 26 16:34:25 GMT 2024

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

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

Back to the top