BaseVariableDeclaration: type is not a reference, why?

Hi,

I'm extending BaseVariableDeclaration from baseLanguag ein my DSL. I'd like to have some scoping logic that allows me to limit the possible types the user of my DSL can select as a type.

I was surprised to see that "type" is defined as a child of BaseVariableDeclaration, and not a reference. What is the reasoning behind it?

What way do you suggest to implement some domain-specific scoping in my concept for the type child. As I see it, I cannot really use the MPS scoping mechanisms since this works for references only.

I was thinking using a "node substitution action" to achieve it, but I'm reluctant since I read that 3.4 marks this kind of action as deprecated and replaces it with the new Transformation Menu Language, which at least sounds to me has different goals than what I'm trying to do...?

thanks,

Robert

8 comments

Can you provide an exact use case? For instance, DSL sample, and a required constraint you want to implement.

Are you aware of "implements SopeProvider" & override ScopeProvider.getScope behavior kind of thing?

0

References need a target node to refer to. If the "type" in VariableDeclaration were a reference, what would be the targets that it could point to? Mind you, a concept declaration of a type is not a node. You still need to create nodes for types in your models somewhere, if you want to refer to them.

Thus types are instantiated as child nodes of the variable declarations. You can specify "scoping" rules for these through the Constraints aspect's "can be child/parent" rules.

Vaclav

 

 

0

@Vladimir: a use case would be a basic Entity language: https://eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping
Let's imagine the language features different kinds of entities, A,B,C.
My concept "Feature" extends the concept BaseVariableDeclaration so that I can reuse baseLanguage types. At the same time, I want to use JDK types via the ClassifierType->ClassConcept interface.
Now I want to make sure that under certain circumstances, the user only sees let's say the types "java.lang.Date", "int" from baseLanguage and user-defined types of Entity-type B.

I'd consider that a scoping task.

@Vaclav: can you elaborate on or point me to a source that explains your sentence "a concept declaration of a type is not a node"?
I understand that the Type concept does not feature a property "name" or something so that one could refer to it, but that's not exactly what you mean, right?
Why do I need to create nodes for types in my model, if I want to use let's say "IntegerType" from baseLanguage?
The problem with "can be child/parent " is that it is unnecessarily restrictive. Or is there a way to customize the error message shown to the user if one of the functions returns false?

Also, I don't think using "can be child/parent" would have influence on the code completion, which is what I'd like to have.

0

"Why do I need to create nodes for types in my model, if I want to use let's say "IntegerType" from baseLanguage?"

Well, IntegerType is a concept, so you cannot refer to it from BaseVariableDeclaration through a reference. You first need an instance (node) of the IntegerType concept somewhere, if you want to refer to it.

 

"The problem with "can be child/parent " is that it is unnecessarily restrictive. Or is there a way to customize the error message shown to the user if one of the functions returns false?

Also, I don't think using "can be child/parent" would have influence on the code completion, which is what I'd like to have."

In fact these rules directly influence the content of the completion menu and so you should never be able to enter invalid type (one that does not fulfill the "can be child/parent" restriction) into your model, thus no customized error message is needed. Only if you change the rules after creating your model so that a type is no longer legal in a place, where it had been inserted before changing the rules, you will get a red underline with a default error message, e.g. "Node X not allowed here", which, admittedly, could benefit from customization.

 

 

0

Hi Vaclav,

now I understand better what you meant. I'm just used to having a type modelled as a reference, and I still think it would be a viable option (even if that means that there need to be instances for base types "pre-defined" in order to use them).

The reason I thought "can be child/parent" would not influence the menu content was because of an implementation of mine that didn't actually work as expected. I underestimated the fact that the arguments passed to the constraint function, in particular childNode, can only be set once the user made a selection (thus actually creating the node).

So, as a consequence, my constraint did not fire as I expected while the code completion menu was open (thus, not filtering the items as I expected), while it did show an error message once an invalid type was selected, created, and added to the model.

Best,

Robert

0

Hi Vaclav,

third attempt to write another response here, the forum kicked me out or just froze respectivly, thus I was losing my comment...

Anyways, I've hit another road block trying to write my constraint. I want to very selectivly filter the substitution menu for a Feature concept, which extends the BaseVariableDeclaration concept.

Basically, I only want to allow "char", "int", and "long" from baseLanguage, as well as "java.lang.String" and "java.util.Date" from the JDK.

My constraint uses the "childConcept" to whilte-list the three baseLanguage types (with "isExactly(BooleanType)", and so on).
I don't understand, however, how I am supposed to check the "classifier" for the substitution menu entries that are instances of "ClassifierTypes". None of the provided arguments seem to provide the information I need.

Btw.: the confluence page for Constraint seems to be pretty old, since my argument list is pretty different from what can be seen in the screenshots (someone also noticed that in the comments section of the page some time ago).

I think what I need is a parameterized substitution action, since this has a "parameterObject". Is this the only way? In other words, I cannot use a constraint to create the constraint I want?

 

0

My constraint uses the "childConcept" to whilte-list the three baseLanguage types (with "isExactly(BooleanType)", and so on).
I don't understand, however, how I am supposed to check the "classifier" for the substitution menu entries that are "ClassifierTypes". None of the provided arguments seem to provide the information I need.

If I understand correctly, I would suggest creating your own "ClassifierType" subconcept that could only be a child of your variable declaration and which would restrict the "classifier" reference to String and Date types:

concepts constraints MyClassifierType {

(childConcept, node, link, parentNode, operationContext)->boolean {
    return parentNode.isInstanceOf(YourVariableDeclaration);
}

can be parent <none>

can be ancestor <none>

<<property constraints>>

link {classifier}
  referent set handler:<none>
  scope:
    (exists, referenceNode, contextNode, containingLink, linkTarget, operationContext, enclosingNode, model, position, contextRole)-    >Scope {
      new ListScope(new arraylist<node<>>{node/String/, node/Date/}) {
        public string getName(node<> child) {
          child : INamedConcept.name;
        }
      };
}

}

You'll also need to disallow the original ClassifierType in the "type" role of your variable declaration in its "can be parent" constraint.

Vaclav

 

0

Also, thank you for pointing out that the Constraints documentation is outdated. I'll try to fix that.

0

Please sign in to leave a comment.