|
|
|
|
|
Re: Nested Struct with Qualified Name [message #1707661 is a reply to message #1707560] |
Tue, 08 September 2015 12:11 |
Moussa Amrani Messages: 2 Registered: August 2015 |
Junior Member |
|
|
Hi,
Making your example work required a bit of extra work to make things fit with Xtext workflow.
First, I simplified your grammar in order to keep only the minimal things necessary. I also refactored some elements so that it will simplify further explanations. Here is the grammar. One of the main things was to separate the "component" declarations inside a structure from variable declaration (as an AbstractElement). You can still merge them if necessary, since they parse the same.
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals
generate myDsl "..."
Model:
(elements+=AbstractElement)*
;
AbstractElement:
types += TypeBlock | routines += RoutineBlock | variables += VariableBlock
;
TypeBlock: {TypeBlock}
'TYPE'
(types+=Structure)*
'END_TYPE'
;
Structure:
name=ID ':' 'STRUCT' (components+=StructureComponent)+ 'END_STRUCT'
;
StructureComponent:
name=ID ':' type=[Structure] |
name=ID ':' simple=PrimitiveType
;
VariableBlock: {VariableBlock}
'VAR' (isGlobal?='GLOBAL' | isPrivate?='PRIVATE')
(variables+=Variable)*
'END_VAR'
;
Variable: name=ID ':' type=[Structure] ';';
RoutineBlock:
'ROUTINE' name=ID
(statements+=Statement)*
'END_ROUTINE'
;
Statement: DotExpression;
DotExpression returns Expression:
VariableRef ({DotExpression.receiver=current} "." tail=[StructureComponent])* ':=' INT ';'
;
VariableRef returns Expression:
{VariableRef} ref=[Variable]
;
PrimitiveType:
{IntType} "INT" |
{BoolType} "BOOL" //|
// {RealType} "REAL"
;
The main point is to have a name for each relevant element (component of a structure, variable, etc.) so that we can rely on Xtext scoping/naming conventions.
Next, in order to enable your dot-based notation, we need to provide the proper scope for an expression like "var.x". The principle is based on retrieving the potential elements that can appear after the "." based on the type of the receiver var: if a "." is possible, then it means that var is a structure with a component named x.
So first, we need to type expressions. To make things simple, I just consider structures as types (you can extend that with SimpleType or more complicated things, once you get it, it's easier). So I created a MyDSLTypeProvider in the proper package (see package declaration in the code) that computes the type of an expression:
- The type of a VariableRef is the reference's declared type;
- The type of a DotExpression is the type of the tail, i.e. the type of the structure's component.
package org.xtext.example.mydsl.typing
import org.xtext.example.mydsl.myDsl.BoolType
import org.xtext.example.mydsl.myDsl.DotExpression
import org.xtext.example.mydsl.myDsl.Expression
import org.xtext.example.mydsl.myDsl.IntType
import org.xtext.example.mydsl.myDsl.MyDslFactory
import org.xtext.example.mydsl.myDsl.PrimitiveType
import org.xtext.example.mydsl.myDsl.Structure
import org.xtext.example.mydsl.myDsl.StructureComponent
import org.xtext.example.mydsl.myDsl.VariableRef
class MyDSLTypeProvider {
public static val integerType = MyDslFactory::eINSTANCE.createStructure => [name = "Integer"]
public static val booleanType = MyDslFactory::eINSTANCE.createStructure => [name = "Boolean"]
public static val nullType = MyDslFactory::eINSTANCE.createStructure => [name = "Null"]
def Structure typeFor(Expression e) {
switch (e) {
VariableRef: e.ref.type
DotExpression: e.tail.typeOf
}
}
def static typeOf(StructureComponent c){
if(c.type != null)
return c.type
else
return c.simple.typeOf
}
def static typeOf(PrimitiveType ptype){
switch(ptype){
IntType: integerType
BoolType: booleanType
}
}
// returns true if fakely created
// as a static value
def isPrimitive(Structure c) {
c.eResource == null
}
}
Note that we need "fake" structure types because your langage allows so-called PrimitiveType-s: I created one such "fake" structure for each necessary type (feel free to extend it in the future).
Now that we can type expressions, we can compute the scopes: we need to indicate to Xtext how to resolve the reference [StructureComponent] in a DotExpression like var.x. The component x has to be found between the components available for the type of var. In your example, since myWorld is declared as a koords, we indicate that the tail x should be among the structure components of koords. We create an Xtend class MyDslScopeProvider with a dedicated scope function to scope this particular component. We need to respect the Xtext convention for the name of the function: scope_DotExpression_tail.
Here is the corresponding code with all you need to make it work (please respect the correct package, the correct class extends clause, and so on):
package org.xtext.example.mydsl.scoping
import com.google.inject.Inject
import org.eclipse.emf.ecore.EReference
import org.eclipse.xtext.scoping.IScope
import org.eclipse.xtext.scoping.Scopes
import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider
import org.xtext.example.mydsl.myDsl.DotExpression
import org.xtext.example.mydsl.myDsl.Structure
import org.xtext.example.mydsl.typing.MyDSLTypeProvider
class MyDslScopeProvider extends AbstractDeclarativeScopeProvider{
@Inject extension MyDSLTypeProvider
def scope_DotExpression_tail(DotExpression e, EReference ref){
val nullScope = IScope::NULLSCOPE
val type = e.receiver.typeFor
if(type == null || type.isPrimitive)
return nullScope
if(type instanceof Structure)
return Scopes::scopeFor((type as Structure).components, nullScope)
}
}
With that, everything should work correctly: it parses, and it becomes clickable thanks to the proper scopes.
However, you should add some checks to ensure e.g. that components in the same structure (as well as structure/variable declarations) have different names, otherwise the clickable reference would become ambiguous.
|
|
|
|
|
|
|
Re: Nested Struct with Qualified Name [message #1707779 is a reply to message #1707772] |
Wed, 09 September 2015 10:40 |
|
your scoping method is wrongly named.
def IScope scope_SelectionExpression_member(SelectionExpression exp, EReference ref) {
and the type provider is not completely implemented
VariableRef: {
if(e.variable instanceof RecordTypeDescription) {
e.variable
}
else if(e.variable instanceof VariableDeclaration) {
(e.variable as VariableDeclaration).type
} else {
null
}
}
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Re: Nested Struct with Qualified Name [message #1707822 is a reply to message #1707820] |
Wed, 09 September 2015 14:17 |
|
asume the project the user models in is a java project (may be the case if the target runtime is java)
then create a libary jar that contains the libary models and put these to the classpath of that java project
asume the project the uses model in i a pure project then simpy copy and paste the libary models to that project
or ... or ...
or adapt global scope provider and put the libary onto scope there
or ... or ....
(beginning with the first or this requires deeper xtext knowlege and more than trivial customizatiions)
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
|
|
|
|
|
Re: Nested Struct with Qualified Name [message #1707837 is a reply to message #1707833] |
Wed, 09 September 2015 15:34 |
tam ay Messages: 44 Registered: May 2015 |
Member |
|
|
Ahhhh OK thank you. You are right... through global scoping it works out of the box if I allow a Type to be ref=[RecordTypeDescription].
PROGRAM LIBRARY;
TYPE
RECORD
real : X;
real : Y;
real : Z;
ENDRECORD = position;
ENDPROGRAM
PROGRAM testPrg;
VAR
position : p;
BEGIN
p.X := 4.0;
ENDPROGRAM
However the member X couldn't be resolved. There is no content assist. How do I have to change the ScopeProvider that it works?
[Updated on: Wed, 09 September 2015 15:38] Report message to a moderator
|
|
|
Re: Nested Struct with Qualified Name [message #1707840 is a reply to message #1707837] |
Wed, 09 September 2015 15:56 |
|
global scoping works by default but names are built like
parentname.childname.grandchildname
=>
(1) you can allow this in your syntax ref=[RecordTypeDescription|FQN]. with FQN: ID ("." ID)*; then you would write libary.position instead of position
(2) adapt the i qualified name provider to give the RecordTypeDescription its simple name
(3) adapt ImportedNamespaceAwareLocalScopeProvider and add an import for LIBRARY.* (org.eclipse.xtext.scoping.impl.ImportedNamespaceAwareLocalScopeProvider.getImplicitImports(boolean))
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.10894 seconds