Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Get the effective type of JvmField in parametrized context(using JvmModelInferrer)
Get the effective type of JvmField in parametrized context [message #1067582] Tue, 09 July 2013 12:49 Go to next message
Kevin SERIN is currently offline Kevin SERINFriend
Messages: 19
Registered: May 2013
Junior Member
Hi,

I'm creating a DSL where we can specify components (which are classes). These components can be parametrized (like a class can be). Inside components, we can use instances of other declared components. This is a short example of what we can do:
component Comp1[A] {
	port p : A
}

component Comp2 {
	instance p1 : Comp1[String]
}

As you can see, components can also have typed ports.

What I'm trying to do is to know the EFFECTIVE type of the port 'p' inside the instance 'p1'. In this case, it's 'String' because the instance 'p1' is parametrized by the type 'String', and the port 'p' has the parametrized type as type.

This the grammar I use:
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.xbase.Xbase

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"

Model:
	components+=Component*;

Component:
	'component' name=ValidID 
	(("<"|"[") typeParameters+=JvmTypeParameter ("," typeParameters+=JvmTypeParameter)* (">"|"]"))?
	'{'
	(
		ports+=Port
		|parts+=Part
	)*
	'}';
		
Part:
	'instance' name=ValidID ':' reference=ParameterizedComponentReference;
	
ParameterizedComponentReference:
	component=[Component] (=>("<"|"[") arguments+=JvmArgumentTypeReference ("," arguments+=JvmArgumentTypeReference)* ("<"|"]"))?;
	
Port:
	"port" name=ValidID ":" typeReference=JvmParameterizedTypeReference;


And this is my JvmModelInferrer:
def dispatch void infer(Component component, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
   		acceptor.accept(component.toClass("mypackage."+component.name)[
   			typeParameters += component.typeParameters.map[cloneWithProxies]
   		]).initializeLater[
   			
   			//ports
   			for(port : component.ports) {
   				members += port.toField(port.name, port.typeReference)
   			}
   			//parts
   			for(part : component.parts) {
   				members += part.toMethod(part.name, part.reference.toType)[
   					visibility = JvmVisibility::PROTECTED
   				];
   			}
   		]
   	}
   	
   	def dispatch private JvmTypeReference toType(Component component) {
   		val ref = component.jvmElements.head
   		if(ref != null && ref instanceof JvmType) {
			return (ref as JvmType).newTypeRef()
		}
		return null
   	}
   	
   	def dispatch private JvmTypeReference toType(ParameterizedComponentReference ref) {
   		val type = ref.component.jvmElements.head as JvmType
   		if(type != null) {
   			val res = type.newTypeRef(ref.arguments)
   		 	ref.associate(res)
   		 	res
   		}
   	}


So I would like to get the effective type of my ports "inside" my instances in my validator. But of course, if I do this:
@Check
	def checkInstancePortType(Part instance) {
		for(port : instance.reference.component.ports) {
			println(getActualType(port.jvmElements.head as JvmField))
		}
		
	}

the returned type is 'A'. But I would like to have the type in the parametrized context (I want 'String') and i don't know how to do it (I hope I'm clear :/). Is there a way to do it ?
Re: Get the effective type of JvmField in parametrized context [message #1067589 is a reply to message #1067582] Tue, 09 July 2013 13:31 Go to previous messageGo to next message
Hallvard Traetteberg is currently offline Hallvard TraettebergFriend
Messages: 673
Registered: July 2009
Location: Trondheim, Norway
Senior Member
Hi,

I have a similar DSL. To compute the actual type, I have a custom copier
that resolves type parameters. I've inserted the code below, hopefully
it is helpful. Note that my model uses the existing JvmType objects,
rather than implementing my own.

Hallvard

package org.ptolemy.xtext.generator;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
import org.eclipse.xtext.common.types.JvmTypeParameter;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.xbase.jvmmodel.IJvmModelAssociations;
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder;
import org.ptolemy.ecore.actor.ActorRef;
import org.ptolemy.ecore.actor.TypeParameter;
import org.ptolemy.ecore.actor.TypeParameterized;
import org.ptolemy.ecore.kernel.Entity;
import org.ptolemy.ecore.kernel.EntityRef;

import com.google.inject.Inject;

class TypeParameterResolvingCopier extends Copier {

private boolean generic = false;

public boolean isGeneric() {
return generic;
}

public static class Result {

public final JvmTypeReference typeRef;
public boolean generic;

public Result(JvmTypeReference typeRef, boolean generic) {
super();
this.typeRef = typeRef;
this.generic = generic;
}
}

static Result getCachedResult(JvmTypeReference typeRef) {
return WrappingAdapter.getWrapped(typeRef, Result.class);
}

Result copyTypeReference(JvmTypeReference typeRef) {
JvmTypeReference copy = (JvmTypeReference) copy(typeRef);
copyReferences();
Result result = new Result(copy, generic);
new WrappingAdapter<Result>(result).attach(typeRef);
if (! generic) {
new WrappingAdapter<Result>(result).attach(copy);
}
return result;
}

@Override
public EObject copy(EObject eObject) {
if (eObject instanceof JvmTypeReference) {
JvmTypeReference typeRef = (JvmTypeReference) eObject;
if (typeRef.getType() instanceof JvmTypeParameter) {
JvmTypeReference resolveTypeRef = resolveTypeParameter(typeRef, true);
if (resolveTypeRef.getType() instanceof JvmTypeParameter) {
generic = true;
}
return resolveTypeRef;
}
}
return super.copy(eObject);
}

@Inject
private IJvmModelAssociations jvmModelAssociations;

@Inject
private JvmTypesBuilder jvmTypesBuilder;

JvmTypeReference resolveTypeParameter(JvmTypeReference typeRef, boolean
clone) {
while (typeRef != null && typeRef.getType() instanceof JvmTypeParameter) {
JvmTypeReference resolvedTypeRef = resolveTypeParameter1(typeRef);
if (resolvedTypeRef == null) {
break;
// return typeRef;
}
typeRef = resolvedTypeRef;
}
return (clone ? jvmTypesBuilder.cloneWithProxies(typeRef) : typeRef);
}

JvmTypeReference resolveTypeParameter1(JvmTypeReference typeRef) {
EObject container = typeRef.eContainer();
while (container != null) {
if (container instanceof Entity<?>) {
EntityRef<?> entityRef = ((Entity<?>) container).getSuperEntity();
if (entityRef != null && entityRef.getRef() != null) {
Entity<?> superEntity = entityRef.getRef();
if (entityRef instanceof ActorRef<?> && superEntity instanceof
TypeParameterized) {
EList<JvmTypeReference> typeArguments = ((ActorRef<?>)
entityRef).getTypeArguments();
int pos = 0;
for (TypeParameter typeParameter : ((TypeParameterized)
superEntity).getTypeParameters()) {
for (EObject jvmElement :
jvmModelAssociations.getJvmElements(typeParameter)) {
if (typeRef.getType() == jvmElement && pos < typeArguments.size()) {
return typeArguments.get(pos);
}
}
pos = pos + 1;
}
}
}
}
container = container.eContainer();
}
return null;
}
}



On 09.07.13 14.49, Kevin SERIN wrote:
> Hi,
>
> I'm creating a DSL where we can specify components (which are classes).
> These components can be parametrized (like a class can be). Inside
> components, we can use instances of other declared components. This is a
> short example of what we can do:
>
> component Comp1[A] {
> port p : A
> }
>
> component Comp2 {
> instance p1 : Comp1[String]
> }
>
> As you can see, components can also have typed ports.
> What I'm trying to do is to know the EFFECTIVE type of the port 'p'
> inside the instance 'p1'. In this case, it's 'String' because the
> instance 'p1' is parametrized by the type 'String', and the port 'p' has
> the parametrized type as type.
>
> This the grammar I use:
> grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.xbase.Xbase
>
> generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"
>
> Model:
> components+=Component*;
>
> Component:
> 'component' name=ValidID (("<"|"[")
> typeParameters+=JvmTypeParameter ("," typeParameters+=JvmTypeParameter)*
> (">"|"]"))?
> '{'
> (
> ports+=Port
> |parts+=Part
> )*
> '}';
>
> Part:
> 'instance' name=ValidID ':' reference=ParameterizedComponentReference;
>
> ParameterizedComponentReference:
> component=[Component] (=>("<"|"[")
> arguments+=JvmArgumentTypeReference (","
> arguments+=JvmArgumentTypeReference)* ("<"|"]"))?;
>
> Port:
> "port" name=ValidID ":" typeReference=JvmParameterizedTypeReference;
>
>
> And this is my JvmModelInferrer:
> def dispatch void infer(Component component, IJvmDeclaredTypeAcceptor
> acceptor, boolean isPreIndexingPhase) {
> acceptor.accept(component.toClass("mypackage."+component.name)[
> typeParameters +=
> component.typeParameters.map[cloneWithProxies]
> ]).initializeLater[
>
> //ports
> for(port : component.ports) {
> members += port.toField(port.name, port.typeReference)
> }
> //parts
> for(part : component.parts) {
> members += part.toMethod(part.name,
> part.reference.toType)[
> visibility = JvmVisibility::PROTECTED
> ];
> }
> ]
> }
>
> def dispatch private JvmTypeReference toType(Component component) {
> val ref = component.jvmElements.head
> if(ref != null && ref instanceof JvmType) {
> return (ref as JvmType).newTypeRef()
> }
> return null
> }
>
> def dispatch private JvmTypeReference
> toType(ParameterizedComponentReference ref) {
> val type = ref.component.jvmElements.head as JvmType
> if(type != null) {
> val res = type.newTypeRef(ref.arguments)
> ref.associate(res)
> res
> }
> }
>
> So I would like to get the effective type of my ports "inside" my
> instances in my validator. But of course, if I do this:
>
> @Check
> def checkInstancePortType(Part instance) {
> for(port : instance.reference.component.ports) {
> println(getActualType(port.jvmElements.head as JvmField))
> }
>
> }
>
> the returned type is 'A'. But I would like to have the type in the
> parametrized context (I want 'String') and i don't know how to do it (I
> hope I'm clear :/). Is there a way to do it ?
Re: Get the effective type of JvmField in parametrized context [message #1067597 is a reply to message #1067582] Tue, 09 July 2013 14:02 Go to previous messageGo to next message
Ian McDevitt is currently offline Ian McDevittFriend
Messages: 70
Registered: December 2012
Location: Belfast
Member
It may help to know about 'type erasure' where JVM type loses its parameter type, so if you define a List<String> in Java source code you only get List in the compiled output. This is a known behaviour probably for performance reasons. The parameterization of generics is only for the compiler to validate your code and isn't preserved for runtime.

You may be able to work back to your DSL model element from the JvmField using the model associations class and work it out from there?
Re: Get the effective type of JvmField in parametrized context [message #1067603 is a reply to message #1067597] Tue, 09 July 2013 14:32 Go to previous messageGo to next message
Kevin SERIN is currently offline Kevin SERINFriend
Messages: 19
Registered: May 2013
Junior Member
my Jvm reflet exactly my dsl model. I was wondering if the infrastructure provided by xtext could take care of doing the type parameter replacement, as it only does it for xbase languages' expressions
Re: Get the effective type of JvmField in parametrized context [message #1067762 is a reply to message #1067603] Wed, 10 July 2013 13:31 Go to previous messageGo to next message
Ian McDevitt is currently offline Ian McDevittFriend
Messages: 70
Registered: December 2012
Location: Belfast
Member
Your Jvm reflects your dsl model - except it won't contain type parameters. But you should be able to get the original declared type information by navigating your own model.

So the type of the instance.reference.component.ports should be the type of the instance.reference.arguments. That is the only place it is known, as far as I can see.

Re: Get the effective type of JvmField in parametrized context [message #1067790 is a reply to message #1067762] Wed, 10 July 2013 15:11 Go to previous messageGo to next message
Victor Noël is currently offline Victor NoëlFriend
Messages: 112
Registered: June 2010
Senior Member
Hi, yes it does contain them, it is not a problem about type erasure as we are not in the JVM itself but manipulating object representing Jvm elements.

Where we were wrong and you pointed us in the right direction is that we are actually interested in instance.jvmElements.head, which contains the reference with the type parameters.

So I am in the good direction to solve that but I'm still missing some pieces:

	@Check
	def checkInstancePortType(Part instance) {
		for(port : instance.reference.component.ports) {
			
			val partR = (instance.jvmElements.head as JvmField).type
			val portO = (port.jvmElements.head as JvmField)
			
			println(getRealType(partR, portO))
		}
		
	}
	
	def getRealType(JvmTypeReference type, JvmField f) {
		val part = type.toLightweightTypeReference;
		val mapping = new ConstraintAwareTypeArgumentCollector(part.owner).getTypeParameterMapping(part);
		new StandardTypeParameterSubstitutor(mapping, part.owner).substitute(f.type);
	}


What we are looking for is something like ConstraintAwareTypeArgumentCollector and StandardTypeParameterSubstitutor, but the current code is wrong, because we are not considering the type arguments collected from partR as different than those of the thing that contain instance, so if we have a recursive thing, the substitutor just goes crazy in the recursion.

Maybe we are in the good direction, it is difficult to dig into xtext code Wink
Re: Get the effective type of JvmField in parametrized context [message #1067802 is a reply to message #1067790] Wed, 10 July 2013 15:59 Go to previous message
Victor Noël is currently offline Victor NoëlFriend
Messages: 112
Registered: June 2010
Senior Member
It seems to work using UnboundTypeParameterPreservingSubstitutor, but frankly, this is really not clean work Smile

It would be nice to have some feedback from people at xtext: I don't know if the first one does not work because this is a bug (the substitution is applied to the substituted element) or if I am just missing something Smile
Previous Topic:Cross references across multiple DSL files. How ?
Next Topic:Problem exporting Eclipse product
Goto Forum:
  


Current Time: Wed Apr 24 23:45:28 GMT 2024

Powered by FUDForum. Page generated in 0.03245 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top