Xtext serializing model with references

980 views Asked by At

I have a hard time figuring out, what am I doing wrong. A simplified example, of what I'm trying to do:

The DSL:

Model: elements += ModelElement*;
ModelElement: Greeting | Person;
Person: 'person' name = ID;
Greeting: 'hello' person = [Person];

The code to serialize a model:

val factory = MyDslFactory.eINSTANCE

val model = factory.createModel

val bob = factory.createPerson
bob.name = "Bob"

val greetBob = factory.createGreeting
greetBob.person = bob

model.elements += bob
model.elements += greetBob

val injector = Guice.createInjector(new MyDslRuntimeModule)
val serializer = injector.getInstance(ISerializer)
// Error happens here:
val result = serializer.serialize(model)

Now when this code runs, the ImportedNamespaceAwareLocalScopeProvider kicks in, and throws the following exception:

java.lang.NullPointerException
    at org.eclipse.xtext.scoping.impl.ImportedNamespaceAwareLocalScopeProvider.getResourceScope(ImportedNamespaceAwareLocalScopeProvider.java:95)
    at org.eclipse.xtext.scoping.impl.ImportedNamespaceAwareLocalScopeProvider.getScope(ImportedNamespaceAwareLocalScopeProvider.java:89)
    at org.eclipse.xtext.scoping.impl.ImportedNamespaceAwareLocalScopeProvider.getScope(ImportedNamespaceAwareLocalScopeProvider.java:87)
    at org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider.delegateGetScope(AbstractDeclarativeScopeProvider.java:72)
    at org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider.getScope(AbstractDeclarativeScopeProvider.java:102)
    at org.eclipse.xtext.serializer.tokens.CrossReferenceSerializer.serializeCrossRef(CrossReferenceSerializer.java:84)
    at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.getToken(SequenceFeeder.java:454)
    at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.accept(SequenceFeeder.java:214)
    at test.serializer.MyDslSemanticSequencer.sequence_Greeting(MyDslSemanticSequencer.java:65)
    at test.serializer.MyDslSemanticSequencer.createSequence(MyDslSemanticSequencer.java:33)
    at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.acceptEObjectRuleCall(SequenceFeeder.java:299)
    at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.acceptRuleCall(SequenceFeeder.java:325)
    at org.eclipse.xtext.serializer.acceptor.SequenceFeeder.accept(SequenceFeeder.java:239)
    at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.accept(BacktrackingSemanticSequencer.java:400)
    at org.eclipse.xtext.serializer.sequencer.BacktrackingSemanticSequencer.createSequence(BacktrackingSemanticSequencer.java:449)
    at test.serializer.MyDslSemanticSequencer.sequence_Model(MyDslSemanticSequencer.java:75)
    at test.serializer.MyDslSemanticSequencer.createSequence(MyDslSemanticSequencer.java:39)
    at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:85)
    at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:108)
    at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:122)
    at org.eclipse.xtext.serializer.impl.Serializer.serialize(Serializer.java:51)
    at test.generator.MyDslGenerator.doGenerate(MyDslGenerator.java:42)
    at org.eclipse.xtext.builder.BuilderParticipant.handleChangedContents(BuilderParticipant.java:515)
    at org.eclipse.xtext.builder.BuilderParticipant.handleChangedContents(BuilderParticipant.java:505)
    at org.eclipse.xtext.builder.BuilderParticipant.doGenerate(BuilderParticipant.java:490)
    at org.eclipse.xtext.builder.BuilderParticipant.doBuild(BuilderParticipant.java:259)
    at org.eclipse.xtext.builder.BuilderParticipant.build(BuilderParticipant.java:217)
    at org.eclipse.xtext.builder.impl.RegistryBuilderParticipant$DeferredBuilderParticipant.build(RegistryBuilderParticipant.java:158)
    at org.eclipse.xtext.builder.impl.RegistryBuilderParticipant.build(RegistryBuilderParticipant.java:68)
    at org.eclipse.xtext.builder.impl.XtextBuilder.doBuild(XtextBuilder.java:189)
    at org.eclipse.xtext.builder.impl.XtextBuilder.incrementalBuild(XtextBuilder.java:167)
    at org.eclipse.xtext.builder.impl.XtextBuilder.build(XtextBuilder.java:95)
    at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:734)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:206)
    at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:246)
    at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:299)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:302)
    at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:358)
    at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:381)
    at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:143)
    at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:241)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)

Meaning, (i think), that it can't resolve a scope, and the only place, where this could happen is the Greeting rule's person reference.

Now if I'm writing a scope provider manually, the reference gets resolved without a problem, and it serializes fine.

class MyDslScopeProvider extends AbstractDeclarativeScopeProvider {
    //A dummy scope provider
    def scope_Greeting_person(Greeting g, EReference ref) {
        val model = g.eContainer as Model
        return Scopes.scopeFor(model.elements.filter(Person))
    }
}

So my question is:

In an obviously much more complex grammar, do I need to write all the individual scope-providers, to make the serialization work? Or is there some configuration option, that I'm missing?

2

There are 2 answers

0
Christian Dietrich On

what about adding the model to a dummy resource

va rs = injector.getInstance(ResourceSet)
val resource = rs.createResource(URI.createURI("dummy/test.mydsl"))
resource.contents += model
0
Martin Jü On

I cannot reply directly to @Balazs Edes, but the solution track that @Christian Dietrich has given is right; here's an example on how to implement it:

Inject resourceset:

@Inject Provider<XtextResourceSet> rsProvider

Then create a resource:

val rs = rsProvider.get

val resource = rs.createResource(URI.createURI("dummy/test.dmodel"))

In a later step, before running serialize(), add the model to the resource:

resource.getContents.add(model)