Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Exploiting types in a DSL: creating new types and referring to existing ones
icon9.gif  Exploiting types in a DSL: creating new types and referring to existing ones [message #649544] Wed, 19 January 2011 11:16 Go to next message
Victor Noël is currently offline Victor Noël
Messages: 112
Registered: June 2010
Senior Member
Hello,

I am trying to integrate my DSL with JavaVMTypes and I am stuck with some problems.

The idea is the following:
I have some elements named Component, inside a Namespace with imports, and I want these elements to have a name and a list of type parameters.
These components contains stuffs named Port that have the particularity to have a member referring to a real Java type.
And these real Java types can have type parameter, and for these, I would like to be either able to use other real Java types, or the type parameter of the enclosing component as type arguments.
Furthermore, component can contains also stuffs named val, that are instance of other components, i.e. referred to by their name along with type arguments for their type parameters.
Of course, every time I am referring to a type, be it a Component or a real Java type, I would like to verify that the number of arguments is correct (and maybe later add constraints for the type parameters...).
Finally, I want, for one instance of a component, inside of another component, to be able to bind ports together, and that this binding is respecting the semantics of the Java assignment with respect to types!

Here is an example of instance of my dsl that should work:
component C1[T] {
	required p1: java.lang.String
	required p2: java.util.List[T]
}

component C2[T] {
	provided p1: java.lang.String
	provided p2: java.util.List[T]
}

component C3 {
	val ci1: C1[java.lang.String] {
		bind p1 to ci2.p1
		bind p2 to ci2.p2
	}
	val ci2: C2[java.lang.String]
}


I have a first shot at answering that:

import "http://www.eclipse.org/xtext/common/JavaVMTypes" as types

File returns Namespace:
	(	imports+=Import
	|	elements+=Element
	)*; 

Namespace:
	'namespace' name=FQN '{'
		(	imports+=Import
		|	elements+=Element
		)*
	'}';

FQN:
	ID ('.' ID)*;

ImportedFQN:
	FQN ('.' '*')?;

Import:
	'import' importedNamespace=ImportedFQN;

Element:
	Namespace | Component;


Component:
	"component" type=ComponentTypeWithParam "{"
		(	"required" requireds+=Port
		|	"provided" provideds+=Port
		|	"val" vals+=Instance
		)*
	"}";

ComponentTypeWithParam returns types::JvmGenericType:
	fullyQualifiedName=ID ("[" typeParameters+=TypeParam ("," typeParameters+=TypeParam)* "]")?;

TypeParam returns types::JvmTypeParameter:
	name=ID;


Port:
	name=ID ":" interface=Interface;

Interface:
	javaType=TypeWithParamRef; // here, only keep interfaces

TypeWithParamRef returns types::JvmParameterizedTypeReference:
	type=[types::JvmType|FQN] ("[" arguments+=TypeParamRef ("," arguments+=TypeParamRef)* "]")?;

TypeParamRef returns types::JvmReferenceTypeArgument:
	typeReference=TypeWithParamRef;

Instance:
	name=ID ":" type=TypeWithParamRef // only keep the 
	("{"
		(bindings+=Binding)*
	"}")?;

Binding:
	"bind" from=[Port]
	"to" instance=[Instance]
	"." port=[Port];


But I encountered a set of problems:
1) ComponentTypeWithParam doesn't seems to be understood as referrable type by TypeWithParamRef in Instance... I guess it is linked to the way I declare NEW types with my DSL (see ComponentTypeWithParam)
2) It seems that since Composite does not declare any name member, I lost the nice differentiation between stuff with the same name enclosed in it (i.e. the DSL editor tells me that the different T in my example have the same name and can't. Also the same happens with the name of the port).
3) I don't know how to exploit the types to check the bindings, I guess when the rest will be ok, this will be straightforward !
4) It seems that the default scope provider for is not very good behaving using

At least, it seems that I can use one of the TypeParam as an argument to the type parameters of the TypeWithParamRef!

Thank you for any help,

I am fighting with this for a long time :)
Re: Exploiting types in a DSL: creating new types and referring to existing ones [message #649575 is a reply to message #649544] Wed, 19 January 2011 13:50 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian Dietrich
Messages: 6143
Registered: July 2009
Senior Member
Hello Victor,

doing some adaptions to the grammar and introducing a QualifiedNameProvider and Scoping should help

grammar org.xtext.example.mydsl1.MyDsl1 with org.eclipse.xtext.common.Terminals

generate myDsl1 "http://www.xtext.org/example/mydsl1/MyDsl1"

import "http://www.eclipse.org/xtext/common/JavaVMTypes" as types

File returns Namespace:
	(	imports+=Import
	|	elements+=Element
	)*; 

Namespace:
	'namespace' name=FQN '{'
		(	imports+=Import
		|	elements+=Element
		)*
	'}';

FQN:
	ID ('.' ID)*;

ImportedFQN:
	FQN ('.' '*')?;

Import:
	'import' importedNamespace=ImportedFQN;

Element:
	Namespace | Component;


Component:
	"component" type=ComponentTypeWithParam "{"
		(	"required" requireds+=Port
		|	"provided" provideds+=Port
		|	"val" vals+=Instance
		)*
	"}";

ComponentTypeWithParam returns types::JvmGenericType:
	{ComponentTypeWithParam} fullyQualifiedName=ID ("[" typeParameters+=TypeParam ("," typeParameters+=TypeParam)* "]")?;

TypeParam returns types::JvmTypeParameter:
	{TypeParam} name=ID;


Port:
	name=ID ":" interface=Interface;

Interface:
	javaType=TypeWithParamRef; // here, only keep interfaces

TypeWithParamRef returns types::JvmParameterizedTypeReference:
	type=[types::JvmType|FQN] ("[" arguments+=TypeParamRef ("," arguments+=TypeParamRef)* "]")?;
	
ComponentRefWithParamRef:
	type=[Component|FQN] ("[" arguments+=TypeParamRef ("," arguments+=TypeParamRef)* "]")?;
	


TypeParamRef returns types::JvmReferenceTypeArgument:
	typeReference=TypeWithParamRef;

Instance:
	name=ID ":" type=ComponentRefWithParamRef // only keep the 
	("{"
		(bindings+=Binding)*
	"}")?;

Binding:
	"bind" from=[Port]
	"to" instance=[Instance]
	"." port=[Port];


package org.xtext.example.mydsl1;

import org.eclipse.xtext.naming.DefaultDeclarativeQualifiedNameProvider;
import org.xtext.example.mydsl1.myDsl1.Component;
import org.xtext.example.mydsl1.myDsl1.ComponentTypeWithParam;
import org.xtext.example.mydsl1.myDsl1.TypeParam;

public class MyQNP extends DefaultDeclarativeQualifiedNameProvider {
	
	public String qualifiedName(Component component) {
		return component.getType().getFullyQualifiedName();
	}
	
	public String qualifiedName(TypeParam typeParam) {
		return getQualifiedName((ComponentTypeWithParam)typeParam.eContainer())+"."+typeParam.getName();
	}
	
	public String qualifiedName(ComponentTypeWithParam componentTypeWithParam) {
		return componentTypeWithParam.getFullyQualifiedName();
	}

}



/*
 * generated by Xtext
 */
package org.xtext.example.mydsl1;

import org.eclipse.xtext.naming.IQualifiedNameProvider;

/**
 * Use this class to register components to be used at runtime / without the Equinox extension registry.
 */
public class MyDsl1RuntimeModule extends org.xtext.example.mydsl1.AbstractMyDsl1RuntimeModule {
	
	@Override
	public Class<? extends IQualifiedNameProvider> bindIQualifiedNameProvider() {
		return MyQNP.class;
	}

}



/*
 * generated by Xtext
 */
package org.xtext.example.mydsl1.scoping;

import java.util.ArrayList;
import java.util.List;

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.mydsl1.myDsl1.Binding;
import org.xtext.example.mydsl1.myDsl1.Instance;
import org.xtext.example.mydsl1.myDsl1.Port;


/**
 * This class contains custom scoping description.
 * 
 * see : http://www.eclipse.org/Xtext/documentation/latest/xtext.html#scoping
 * on how and when to use it 
 *
 */
public class MyDsl1ScopeProvider extends AbstractDeclarativeScopeProvider {
	
	public IScope scope_Binding_from(Binding binding, EReference ref) {
		List<Port> ports = new ArrayList<Port>();
		ports.addAll(((Instance)binding.eContainer()).getType().getType().getProvideds());
		ports.addAll(((Instance)binding.eContainer()).getType().getType().getRequireds());
		return Scopes.scopeFor(ports);
	}
	
	public IScope scope_Binding_port(Binding binding, EReference ref) {
		List<Port> ports = new ArrayList<Port>();
		ports.addAll(binding.getInstance().getType().getType().getProvideds());
		ports.addAll(binding.getInstance().getType().getType().getRequireds());
		return Scopes.scopeFor(ports);
	}

}



~Christian
Re: Exploiting types in a DSL: creating new types and referring to existing ones [message #649669 is a reply to message #649544] Thu, 20 January 2011 03:50 Go to previous messageGo to next message
Victor Noël is currently offline Victor Noël
Messages: 112
Registered: June 2010
Senior Member
Hello Christian,

Thank you for your quick reply, it is very helpful :)

Now to complete your solution, I changed and added some stuffs:

In particular, I reduced the scopes for the bindings only to a subset of the ports
public class MyDslScopeProvider extends AbstractDeclarativeScopeProvider {
	public IScope scope_Binding_from(Binding binding, EReference ref) {
		List<Port> ports = new ArrayList<Port>();
		ports.addAll(((Instance)binding.eContainer()).getType().getType().getRequireds());
		return Scopes.scopeFor(ports);
	}
	
	public IScope scope_Binding_port(Binding binding, EReference ref) {
		List<Port> ports = new ArrayList<Port>();
		ports.addAll(binding.getInstance().getType().getType().getProvideds());
		return Scopes.scopeFor(ports);
	}
}


And I added a constraint to check types.
public class MyDslJavaValidator extends AbstractMyDslJavaValidator {

	@Inject
	private IAssignabilityComputer assComp;

	@Check
	public void checkBinding(Binding b) {
		if (!assComp.isAssignableFrom(b.getFrom().getInterface().getJavaType(), b.getPort().getInterface().getJavaType())) {
			error("Incompatible interfaces", MyDslPackage.BINDING);
		}
	}
}



Then, with the current code:
component C1[T] {
	required p1: java.lang.String
	required p2: java.util.List[T]
}

namespace ns1 {
	component C2[T] {
		provided p1: java.lang.String
		provided p2: java.util.List[T]
	}
}

component C3 {
	val c: ns1.C2[java.lang.String] // pb namespace
}

component C3 {} // pb C3 duplicate

component C4a {
	val ci1: C1[java.lang.String] {
		bind p1 to ci2.p1
		bind p2 to ci2.p2 // pb types
		
	}
	val ci2: C2[java.lang.String]
}

component C4b[T] {
	val ci1: C1[T] {
		bind p1 to ci2.p1
		bind p2 to ci2.p2 // pb types
	}
	val ci2: C2[T]
}


My problems are the following:
1) As demonstrated with C3, the namespace is not taken into account, I am not sure of what I should do to have the same behaviour as with out-of-the-box namespace and names.
2) Maybe linked to 1, as demonstrated with C3, the out-of-the-box check for duplicates does not seem to work either.
3) As demonstrated with C4b and C4b, the types of the ports are not taking the type arguments into account in ci1 for p2.
4) It seems that the completion fails to work when typing a TypeWithParamRef: it doesn't complete the namespace part of the types.
5) How to override the completion in order to have also type parameter with default arguments when typing TypeWithParamRef or ComponentRefWithParamRef?

Would you have any idea regarding these things, I know it start to get complex, but I am sure that with the correct knowledge, it should be doable :)

Thank you very much.

Victor
Re: Exploiting types in a DSL: creating new types and referring to existing ones [message #650562 is a reply to message #649544] Tue, 25 January 2011 09:24 Go to previous messageGo to next message
Victor Noël is currently offline Victor Noël
Messages: 112
Registered: June 2010
Senior Member
No idea about it?

Sorry for the up, I am afraid my answer was drown by the high activity of the forum :)
Re: Exploiting types in a DSL: creating new types and referring to existing ones [message #651007 is a reply to message #649544] Thu, 27 January 2011 07:41 Go to previous message
Victor Noël is currently offline Victor Noël
Messages: 112
Registered: June 2010
Senior Member
For the record, I managed to fix my namespace and reference problems with the following QNP:
public class MyQNP extends DefaultDeclarativeQualifiedNameProvider {
	
	public String qualifiedName(Component component) {
		return getQualifiedName((Namespace) component.eContainer()) + getDelimiter() + component.getType().getFullyQualifiedName();
	}
	
	public String qualifiedName(TypeParam typeParam) {
		return getQualifiedName((Component) typeParam.eContainer().eContainer()) + getDelimiter() + typeParam.getName();
	}
	
	public String qualifiedName(ComponentTypeWithParam componentTypeWithParam) {
		return null;
	}
}


The problem of duplicates is taken care of in:
http://www.eclipse.org/forums/index.php?t=msg&th=203545

I still need to work on having nice completion and proposal for the Jvm types.
Previous Topic:dependency cycle in plugins
Next Topic:Left recursion
Goto Forum:
  


Current Time: Thu Jul 31 01:36:01 EDT 2014

Powered by FUDForum. Page generated in 0.01741 seconds