Home » Modeling » TMF (Xtext) » Custom scope provider
| |
Re: Custom scope provider [message #1859693 is a reply to message #1859692] |
Thu, 22 June 2023 17:57 |
Łukasz Grabski Messages: 10 Registered: June 2023 |
Junior Member |
|
|
Basically I'm rewriting this DSL: https://structurizr.com/dsl or at least trying ;)
I have a custom component I call IncludeResolver, I used it in both validator and scope provider, so in short the method that loads the included model looks like following:
public Model resolveInclude(IncludeNode include,
CircularIncludeGuard circularIncludeGuard,
ResourceSet resourceSet) throws IncludeError {
if (circularIncludeGuard.alreadyIncluded(include)) {
throw new IncludeError("Circular includes are forbidden!");
}
String importURI = include.getImportURI();
URI uri = URI.createURI(importURI);
try {
Resource resource = resourceSet.getResource(uri, true);
circularIncludeGuard.register(include);
for (EObject importedObject : resource.getContents()) {
if (importedObject instanceof Model includedModel) {
return includedModel;
}
}
throw new IncludeError("Unable to find model in included resource.");
} catch (Throwable throwable) {
throw new IncludeError(throwable);
}
}
CircularIncludeGuard is just checking if there are circular includes going on...
I'm including whole resolver code here:
public class IncludeResolver {
public Model resolveModel(Model originalModel) throws IncludeError {
ResourceSet resourceSet = originalModel.eResource().getResourceSet();
Model clonedModel = EcoreUtil.copy(originalModel);
doLinkingInModel(clonedModel, new CircularIncludeGuard(), resourceSet);
return clonedModel;
}
public Model resolveInclude(IncludeNode include,
CircularIncludeGuard circularIncludeGuard,
ResourceSet resourceSet) throws IncludeError {
if (circularIncludeGuard.alreadyIncluded(include)) {
throw new IncludeError("Circular includes are forbidden!");
}
String importURI = include.getImportURI();
URI uri = URI.createURI(importURI);
try {
Resource resource = resourceSet.getResource(uri, true);
circularIncludeGuard.register(include);
for (EObject importedObject : resource.getContents()) {
if (importedObject instanceof Model includedModel) {
return includedModel;
}
}
throw new IncludeError("Unable to find model in included resource.");
} catch (Throwable throwable) {
throw new IncludeError(throwable);
}
}
private void doLinkingInModel(Model model,
CircularIncludeGuard circularIncludeGuard,
ResourceSet resourceSet) throws IncludeError {
ArrayList<NodeType> nodeTypes = new ArrayList<>(model.getElements());
for (NodeType modelNode : nodeTypes) {
linkModelNode(model, modelNode, circularIncludeGuard, resourceSet);
}
}
private void linkModelNode(Model model,
EObject modelNode,
CircularIncludeGuard circularIncludeGuard,
ResourceSet resourceSet) throws IncludeError {
if (modelNode instanceof VariableDeclarationNode variableDeclaration) {
linkModelNode(model, variableDeclaration.getTarget(), circularIncludeGuard, resourceSet);
}
if (modelNode instanceof IncludeNode include) {
includeResource(new ModelIncludeTarget(model), include, circularIncludeGuard, resourceSet);
} else if (modelNode instanceof GroupNode group) {
doLinkingInGroup(group, circularIncludeGuard, resourceSet);
} else if (modelNode instanceof ContainerNode container) {
doLinkingInContainer(container, circularIncludeGuard, resourceSet);
} else if (modelNode instanceof SoftwareSystemNode softwareSystem) {
doLinkingInSoftwareSystem(softwareSystem, circularIncludeGuard, resourceSet);
}
}
private void doLinkingInGroup(GroupNode group,
CircularIncludeGuard circularIncludeGuard,
ResourceSet resourceSet) throws IncludeError {
List<NodeType> groupElements = new ArrayList<>(group.getElements());
for (NodeType groupElement : groupElements) {
if (groupElement instanceof IncludeNode include) {
includeResource(new GroupIncludeTarget(group), include, circularIncludeGuard, resourceSet);
} else if (groupElement instanceof GroupNode childGroup) {
doLinkingInGroup(childGroup, circularIncludeGuard, resourceSet);
}
}
}
private void doLinkingInContainer(ContainerNode container,
CircularIncludeGuard circularIncludeGuard,
ResourceSet resourceSet) throws IncludeError {
List<NodeType> containerElements = new ArrayList<>(container.getElements());
for (NodeType containerElement : containerElements) {
if (containerElement instanceof IncludeNode include) {
includeResource(new ContainerIncludeTarget(container), include, circularIncludeGuard, resourceSet);
} else if (containerElement instanceof GroupNode childGroup) {
doLinkingInGroup(childGroup, circularIncludeGuard, resourceSet);
}
}
}
private void doLinkingInSoftwareSystem(SoftwareSystemNode softwareSystem,
CircularIncludeGuard circularIncludeGuard,
ResourceSet resourceSet) throws IncludeError {
ArrayList<NodeType> softwareSystemElements = new ArrayList<>(softwareSystem.getElements());
for (NodeType softwareSystemElement : softwareSystemElements) {
if (softwareSystemElement instanceof IncludeNode include) {
includeResource(new SoftwareSystemIncludeTarget(softwareSystem), include, circularIncludeGuard, resourceSet);
} else if (softwareSystemElement instanceof GroupNode childGroup) {
doLinkingInGroup(childGroup, circularIncludeGuard, resourceSet);
}
}
}
private void includeResource(IncludeTarget includeTarget,
IncludeNode include,
CircularIncludeGuard circularIncludeGuard,
ResourceSet resourceSet) throws IncludeError {
Model includedModel = resolveInclude(include, circularIncludeGuard, resourceSet);
includeModel(includeTarget, includedModel, include, circularIncludeGuard, resourceSet);
}
private void includeModel(IncludeTarget includeTarget,
Model includedModel,
IncludeNode includeNode,
CircularIncludeGuard circularIncludeGuard,
ResourceSet resourceSet) throws IncludeError {
List<NodeType> newElements = new ArrayList<>(includeTarget.cloneElements());
int includeNodeIndex = newElements.indexOf(includeNode);
int includeElementIndex = includeNodeIndex;
for (NodeType includedNode : includedModel.getElements()) {
if (includedNode instanceof IncludeNode nestedInclude) {
Model nestedIncludedModel = resolveInclude(nestedInclude, circularIncludeGuard, resourceSet);
Model resolved = resolveModel(nestedIncludedModel);
for (NodeType nestedNode : resolved.getElements()) {
newElements.add(++includeElementIndex, nestedNode);
}
} else if (!newElements.contains(includedNode)) {
if (includeNodeIndex != -1) {
newElements.add(++includeElementIndex, includedNode);
} else {
newElements.add(includedNode);
}
}
}
if (includeNodeIndex != -1) {
newElements.remove(includeNodeIndex);
}
includeTarget.replaceElements(newElements);
}
}
|
|
| |
Re: Custom scope provider [message #1859695 is a reply to message #1859694] |
Thu, 22 June 2023 18:03 |
|
This looks totally unusual to me so you need to debug why it does not work on incremental builds
I assume you don't calculate a proper uri to load manually into the resource set or even just search it in the resource set where it won't be there on incremental, builds
Unfortunately I don't have time to debug big piles of code
But again I still won't understand why you do the imports yourself instead of using Xtexts ootb
I also have doubts classpath Uris work properly
In lsp
Maybe you can also write a test for incremental build in lsp to ease debugging
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Day Job: https://www.everest-systems.com
[Updated on: Thu, 22 June 2023 18:11] Report message to a moderator
|
|
| | | | |
Re: Custom scope provider [message #1859700 is a reply to message #1859699] |
Thu, 22 June 2023 19:03 |
|
did some experiments with an incremental build test
package org.xtext.example.mydsl.tests;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
import org.eclipse.lsp4j.DidOpenTextDocumentParams;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
import org.eclipse.lsp4j.TextDocumentItem;
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
import org.eclipse.xtext.ide.server.UriExtensions;
import org.eclipse.xtext.testing.AbstractLanguageServerTest;
import org.eclipse.xtext.util.Strings;
import org.eclipse.xtext.xbase.lib.Extension;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
public class DemoTest extends AbstractLanguageServerTest {
public DemoTest() {
super("mydsl");
}
@Inject
@Extension
private UriExtensions _uriExtensions;
@Test
public void testIncrementalBuild() {
String _uriString = this._uriExtensions.toUriString(this.root.toURI().normalize());
initialize();
open(_uriString + "a.mydsl", "Hello A!");
open(_uriString + "b.mydsl", "Hello B from A!");
List<Diagnostic> problems = problems();
Assertions.assertTrue(problems.size() == 0, problems.toString());
TextDocumentContentChangeEvent c1 = new TextDocumentContentChangeEvent();
c1.setRange(new Range(new Position(0, 0), new Position(0, 0)));
c1.setText("Hello C from B!");
ArrayList<TextDocumentContentChangeEvent> changes = Lists.newArrayList(c1);
change(_uriString + "b.mydsl", 2, changes);
problems = problems();
Assertions.assertTrue(problems.size() == 0, problems.toString());
TextDocumentContentChangeEvent c2 = new TextDocumentContentChangeEvent();
c2.setRange(new Range(new Position(0, 0), new Position(0, 0)));
c2.setText("Hello D from Does_Not_Exist!");
changes = Lists.newArrayList(c2);
change(_uriString + "b.mydsl", 3, changes);
problems = problems();
Assertions.assertTrue(problems.size() == 1, problems.toString());
System.out.println(problems.toString());
}
protected void change(final String fileUri, int v, List<TextDocumentContentChangeEvent> changes) {
DidChangeTextDocumentParams p = new DidChangeTextDocumentParams();
VersionedTextDocumentIdentifier i = new VersionedTextDocumentIdentifier();
i.setUri(fileUri);
i.setVersion(v);
p.setTextDocument(i);
p.setContentChanges(changes);
this.languageServer.didChange(p);
}
private List<Diagnostic> problems() {
return Lists.newArrayList(IterableExtensions.flatten(getDiagnostics().values()));
}
}
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Day Job: https://www.everest-systems.com
|
|
| | |
Goto Forum:
Current Time: Sat Dec 21 16:07:34 GMT 2024
Powered by FUDForum. Page generated in 0.04333 seconds
|