|
|
Re: Implicitly add method call to generated interface. [message #1754656 is a reply to message #1754651] |
Tue, 21 February 2017 11:21 |
Markus Wutzler Messages: 11 Registered: October 2015 |
Junior Member |
|
|
Thanks for your reply!
Christian Dietrich wrote on Tue, 21 February 2017 10:20can you please post the expected java code as well.
For each Role a class and an interface is generated.
The class gets the following method:
public String bar() {
player.performBRoleDoSomething() // something like getPlayer().doSomething() would be preferred actually.
return null;
}
and the interface gets the performBRoleDoSomething() method.
Christian Dietrich wrote on Tue, 21 February 2017 10:20is the interface inferred or is it a existing class?
both, here an excerpt of my Inferer:
def dispatch void infer(NonCoordinatorRole role, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase, CollSpec collSpec){
acceptor.accept(role.toClass('''«collSpec.module.fullyQualifiedName».«role.name»Role''')) [
documentation = role.documentation
if(!isPreIndexingPhase) {
superTypes += AbstractRole.typeRef
var playerRef = typesFactory.createJvmField()
playerRef.type = typeRef('''«collSpec.module.fullyQualifiedName».I«role.name»RolePlayer''')
playerRef.simpleName = 'player'
playerRef.visibility = JvmVisibility.PRIVATE
playerRef.type
members += playerRef
}
for(feature : role.features) {
switch feature {
Property : {
members += feature.toField(feature.name, feature.type)
members += feature.toGetter(feature.name, feature.type)
members += feature.toSetter(feature.name, feature.type)
}
Operation : {
members += feature.toMethod(feature.name, feature.type) [
documentation = feature.documentation
for(p : feature.params) {
parameters += p.toParameter(p.name, p.parameterType)
}
body = feature.body
]
}
}
}
]
}
def void inferPlayerInterface(Role role, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase, CollSpec collSpec) {
acceptor.accept(role.toClass('''«collSpec.module.fullyQualifiedName».I«role.name»RolePlayer''')) [
setInterface = true
for (feature : role.features) {
if (feature instanceof Operation) {
if (feature.isPlayerQualifierSet) {
members += feature.toMethod('''perform«role.name»Role«feature.name.toFirstUpper»''', feature.type) [
documentation = feature.documentation
for(p : feature.params) {
parameters += p.toParameter(p.name, p.parameterType)
}
// body = feature.body
]
}
}
}
]
}
Christian Dietrich wrote on Tue, 21 February 2017 10:20you want to be ablte to call a method that does not exist? so let it drop from the sky?
Actually yes, it shall be dispatched at run time. So it does not drop from the sky but the complementing implementation is provided somewhere else. In the end there should be no fixed player attribute but for the moment this would be ok.
[Updated on: Tue, 21 February 2017 11:24] Report message to a moderator
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Re: Implicitly add method call to generated interface. [message #1754937 is a reply to message #1754935] |
Fri, 24 February 2017 09:34 |
Markus Wutzler Messages: 11 Registered: October 2015 |
Junior Member |
|
|
Sure.
In the JvmInferrer I start with inferring the root element.
def dispatch void infer(CollSpec collSpec, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
infer(collSpec.module.collaboration,acceptor,isPreIndexingPhase,collSpec)
collSpec.module.collaboration.roles.forEach [
infer(it,acceptor,isPreIndexingPhase,collSpec)
]
collSpec.module.collaboration.roles.forEach [
inferPlayerInterface(it,acceptor,isPreIndexingPhase,collSpec)
]
}
The interface is generated like this:
def void inferPlayerInterface(Role role, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase, CollSpec collSpec) {
acceptor.accept(role.toClass('''«collSpec.module.fullyQualifiedName».I«role.name»RolePlayer''')) [
setInterface = true
for(feature : role.features) {
if(feature instanceof Operation) {
if(feature.isPlayerQualifierSet) {
members += feature.toMethod('''perform«role.name»Role«feature.name.toFirstUpper»''', feature.type) [
setDefault = false
documentation = feature.documentation
for(p : feature.params) {
parameters += p.toParameter(p.name, p.parameterType)
}
]
}
var playerReferences = feature?.body?.findPlayerReferences
for(featureCall : playerReferences) {
println(featureCall)
var op = typesFactory.createJvmOperation
members += featureCall.toMethod('''perform«role.name»Role«feature.name.toFirstUpper»«featureCall.feature.simpleName.toFirstUpper»''',if(featureCall.explicitReturnType) featureCall.returnType else Void.typeRef) [
setDefault = false
setAbstract = true
]
}
}
}
]
}
The method findPlayerReferences returns the correct references - I added them as a specific modeling element to my grammar:
PlayerFeatureCall returns xBase::XExpression:
(=>'player' '.' {PlayerFeatureCall}
//('<' typeArguments+=JvmArgumentTypeReference (',' typeArguments+=JvmArgumentTypeReference)* '>')?
feature=[types::JvmIdentifiableElement|IdOrSuper] (
=>explicitOperationCall?='('
(
//memberCallArguments+=XShortClosure
//|
memberCallArguments+=XExpression (',' memberCallArguments+=XExpression)*
)?
')')?
(=>explicitReturnType?='returns' returnType=JvmTypeReference)?
//memberCallArguments+=XClosure?
);
XPrimaryExpression returns xBase::XExpression:
XConstructorCall |
XBlockExpression |
XSwitchExpression |
XSynchronizedExpression |
XFeatureCall |
XLiteral |
XIfExpression |
XForLoopExpression |
XBasicForLoopExpression |
XWhileExpression |
XDoWhileExpression |
XThrowExpression |
XReturnExpression |
XTryCatchFinallyExpression |
XParenthesizedExpression |
PlayerFeatureCall
;
|
|
|
|
|
Re: Implicitly add method call to generated interface. [message #1754941 is a reply to message #1754938] |
Fri, 24 February 2017 10:32 |
|
AST !== NodeModel
Model:
elements+=Element*
;
Element:
"element" name=ID "{"
operation=Operation
"}"
;
Operation:
"op" name=ID "("")" body=XBlockExpression
;
/*
* generated by Xtext 2.11.0.RC2
*/
package org.xtext.example.mydsl.jvmmodel
import com.google.inject.Inject
import org.eclipse.xtext.Action
import org.eclipse.xtext.nodemodel.ICompositeNode
import org.eclipse.xtext.nodemodel.util.NodeModelUtils
import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.xtext.example.mydsl.myDsl.Element
import org.xtext.example.mydsl.services.MyDslGrammarAccess
import org.eclipse.xtext.RuleCall
/**
* <p>Infers a JVM model from the source model.</p>
*
* <p>The JVM model should contain all elements that would appear in the Java code
* which is generated from the source model. Other models link against the JVM model rather than the source model.</p>
*/
class MyDslJvmModelInferrer extends AbstractModelInferrer {
@Inject extension JvmTypesBuilder
@Inject extension MyDslGrammarAccess
def dispatch void infer(Element element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(element.toInterface("demo.I" + element.name + "Player", [])) [
if (element.operation !== null) {
val node = NodeModelUtils.findActualNodeFor(element.operation.body)
// search the nodemodel. this is just an example. make sure you catch all cases
if (node !== null) {
for (e : node.asTreeIterable) {
val ge = e.grammarElement
if (ge instanceof Action) {
if (ge === XMemberFeatureCallAccess.XMemberFeatureCallMemberCallTargetAction_1_1_0_0_0) {
if (e instanceof ICompositeNode) {
for (ex : e.children) {
val gex = ex.grammarElement
if (gex instanceof RuleCall) {
if (gex.rule === XMemberFeatureCallRule) {
val text = ex.text.trim
if ("player".equals(text)) {
var next = ex.nextSibling
while (next !== null) {
if (next.grammarElement ==
XMemberFeatureCallAccess.
featureJvmIdentifiableElementCrossReference_1_1_2_0) {
val ftext = next.text.trim
members +=
element.toMethod(ftext, Void.TYPE.typeRef)[]
next = null
} else {
next = next.nextSibling
}
}
}
}
}
}
}
}
}
}
}
}
]
acceptor.accept(element.toClass("demo." + element.name)) [
members += element.toField("player", ("demo.I" + element.name + "Player").typeRef)[]
if (element.operation !== null) {
members += element.operation.toMethod(element.operation.name, Void.TYPE.typeRef) [
body = element.operation.body
]
}
]
}
}
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Day Job: https://www.everest-systems.com
|
|
|
Re: Implicitly add method call to generated interface. [message #1754942 is a reply to message #1754941] |
Fri, 24 February 2017 10:39 |
|
p.s.
you might start traversing the ast as you do,
but you may never follow cross references but use NodeModelUtils to get the node and text e.g
class MyDslJvmModelInferrer extends AbstractModelInferrer {
@Inject extension JvmTypesBuilder
@Inject extension MyDslGrammarAccess
def dispatch void infer(Element element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(element.toInterface("demo.I" + element.name + "Player", [])) [
if (element.operation !== null) {
for (XMemberFeatureCall c : EcoreUtil2.getAllContentsOfType(element.operation.body,
XMemberFeatureCall)) {
val node = NodeModelUtils.findNodesForFeature(c,
XbasePackage.Literals.XMEMBER_FEATURE_CALL__MEMBER_CALL_TARGET).head
if (node !== null) {
val text = node.text.trim
if ("player" == text) {
val node2 = NodeModelUtils.findNodesForFeature(c,
XbasePackage.Literals.XABSTRACT_FEATURE_CALL__FEATURE).head
if (node2 !== null) {
val text2 = node2.text.trim
members+= element.toMethod(text2, Void.TYPE.typeRef)[]
}
}
}
}
}
]
acceptor.accept(element.toClass("demo." + element.name)) [
members += element.toField("player", ("demo.I" + element.name + "Player").typeRef)[]
if (element.operation !== null) {
members += element.operation.toMethod(element.operation.name, Void.TYPE.typeRef) [
body = element.operation.body
]
}
]
}
}
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Day Job: https://www.everest-systems.com
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.05539 seconds