3
votes

I have a problem with cross-referencing terminals that are only locally unique (in their block/scope), but not globally. I found tutorials that describe, how I can use fully qualified names or package declarations, but my case is syntactically a little bit different from the example and I cannot change the DSL to support something like explicit fully qualified names or package declarations.

In my DSL I have two types of structured JSON resources:

  • The instance that contains my data.
  • A meta model, containing type information etc. for my data.

I can easily parse those two, and get an EMF model with the following Java snippet:

new MyDSLStandaloneSetup().createInjectorAndDoEMFRegistration();
ResourceSet rs = new ResourceSetImpl();
rs.getResource(URI.createPlatformResourceURI("/Foo/meta.json", true), true);
Resource instanceResource= rs.getResource(URI.createPlatformResourceURI("/Bar/instance.json", true), true);
EObject eobject = instanceResource.getContents().get(0);

Simplyfied example:

meta.json

{
    "toplevel_1": {
        "sublevels": {
            "sublevel_1": {
                "type": "int"
            },
            "sublevel_2": {
                "type": "long"
            }
        }
    },
    "toplevel_2": {
        "sublevels": {
            "sublevel_1": {
                "type": "float"
            },
            "sublevel_2": {
                "type": "double"
            }
        }
    }
}

instance.json

{
    "toplevel_1": {
        "sublevel_1": "1",
        "sublevel_2": "2"
    },
    "toplevel_2": {
        "sublevel_1": "3",
        "sublevel_2": "4"
    }
}

From this I want to infer that:

  • toplevel_1:sublevel_1 has type int and value 1
  • toplevel_1:sublevel_2 has type long and value 2
  • toplevel_2:sublevel_1 has type float and value 3
  • toplevel_2:sublevel_2 has type double and value 4

I was able to cross-reference the unique toplevel-elements and iterate over all sublevels until I found the ones that I was looking for, but for my use case that is quite inefficient and complicated. Also, I don't get the generated editor to link between the sublevels this way.

I played around with linking and scoping, but I'm unsure as to what I really need, and if I have to extend the providers-classes AbstractDeclarativeScopeProvider and/or DefaultDeclarativeQualifiedNameProvider.

What's the best way to go?

See also:

1

1 Answers

2
votes

After some trial and error I solved my problem with a ScopeProvider. The main issue was that I didn't really understand what a scope is in Xtext-terms, and what I have to provide it to.

Looking at the signature from the documentation:

IScope scope_<RefDeclaringEClass>_<Reference>(<ContextType> ctx, EReference ref)

In my example language:

  • RefDeclaringEClass would refer to the Sublevel from instance.json,
  • Reference to the cross-reference to the Sublevel from meta.json, and
  • ContextType would match the RefDeclaringEClass.

Using the eContainer of ctx I can get the Toplevel from instance.json. This Toplevel already has a cross-reference to the matching Toplevel from meta.json, which I can use to get the Sublevels from meta.json. This collection of Sublevels is basically the scope within which the current Sublevel should be unique.

To get the IScope I used Scopes#scopeFor(Iterable).

I didn't post any code here because the actual grammar is bigger/different, and therefore doesn't really help the explanation.