Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Integration with Xbase - reference to model elements and java-like methodscalls
Integration with Xbase - reference to model elements and java-like methodscalls [message #1784965] Fri, 06 April 2018 10:55 Go to next message
Fabian G. is currently offline Fabian G.Friend
Messages: 60
Registered: May 2010
Location: Christchurch (NZ)
Member
HI,

I tried to create a simple language (for pedagogical purposes) integrated with Xbase. I took some inspiration from the domain model and wrote this grammar


grammar nz.ac.canterbury.seng441.Component with org.eclipse.xtext.xbase.Xbase

generate component "http://www.ac.nz/canterbury/seng441/Component"

ComponentModel:
  importSection=XImportSection?
	elements += AbstractElement+;
	
AbstractElement:
    PackageDeclaration | Component;
 
PackageDeclaration:
  'package' name=QualifiedName '{'
      elements+=AbstractElement+
  '}';
 
Component:
	'component' name=ValidID ('extends' superType=JvmTypeReference)? '{'
    content += Content*
	'}';

Content:
  Declaration | Provide | Require ;

Declaration:
  'var' type=JvmTypeReference name=ValidID ';';

Provide:
  'provides' name=ValidID ('('(parameters+=FullJvmFormalParameter("," parameters+=FullJvmFormalParameter)*)?')')? 
  (':' type=JvmTypeReference)? 
  (isEmpty?=';' | body=XBlockExpression);

Require:
  'requires' type=JvmTypeReference '::' method=JAVALIKECALL;


The (partial) inferrer:

@Inject extension JvmTypesBuilder
  @Inject extension IQualifiedNameProvider
  
  // working on the component level as we want to create one class per component
	def dispatch void infer(Component component, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {  
  
    acceptor.accept(component.toClass(component.fullyQualifiedName)) [
          
      documentation = component.documentation
      if (component.superType !== null) {
        superTypes += component.superType.cloneWithProxies
      }
      // add a default constructor
      members += component.toConstructor []
      
      for (content : component.content) {
        switch (content) {
          Declaration : {
            members += content.toField(content.name, content.type)    
          }
          
          Provide : {
            var type = typeRef(Void::TYPE);
            if (content.type !== null) {
              type = content.type
            }
            members += content.toMethod(content.name, type) [
              content.parameters.forEach[parameter | parameters += parameter.toParameter(parameter.name, parameter.parameterType)]
              if (content.isIsEmpty) {
                body = '''/* TODO implement me */'''
              } else {
                body = content.body
              }
            ]            
          }
        }
      }
    ]
  }


I have two questions:

1. I'm not able to reference components that I just declared until they are generated at save time. Do I have to add some configuration somewhere to be able to reference them on the fly without saving the model (and trigger the java code generation)? I tried to replicate the domainmodel example, but it seems I missed something. Strangely, I can call the methods declared as provides inside XblockExpression before saving (but only using their simple names, but it should just be a matter of qualifiedname, I beleve).

2. As you can see, I'd like to simply create provides clauses where a method is declared (possibly with its implementation, this is working) and requires clauses that must refer to them. In the XBlockExpression part, I can call the method by its name, but I can't figure out what I have to put in place of the JAVALIKECALL. I've seen/tried things with XFeatures, or alike, but with no success.

Any help will be appreciated,
Thanks,
Cheers,
Fabian
Re: Integration with Xbase - reference to model elements and java-like methodscalls [message #1785647 is a reply to message #1784965] Tue, 17 April 2018 22:43 Go to previous messageGo to next message
Fabian G. is currently offline Fabian G.Friend
Messages: 60
Registered: May 2010
Location: Christchurch (NZ)
Member
Hi,

I found some time to progress on this, but I still have one strange behaviour. I combined some answers from previous posts to have something like this for the Require rule (to be scoped correctly, thanks to https://www.eclipse.org/forums/index.php/m/1723598/#msg_1723598

Require:
  'requires' declaration=[Declaration] '::' method=XRestrictedFeatureCall; 

XRestrictedFeatureCall returns xbase::XExpression:
  {xbase::XFeatureCall}
  ('<' typeArguments+=JvmArgumentTypeReference (',' typeArguments+=JvmArgumentTypeReference)* '>')? 
  feature=[jvmTypes::JvmIdentifiableElement|IdOrSuper] 
  (=>explicitOperationCall?='(' 
    (
        featureCallArguments+=XShortClosure
      | featureCallArguments+=XExpression (',' featureCallArguments+=XExpression)*
    )? 
  ')');


The relevant inferrer part:
Require : {
            members += content.toMethod("require" + content.declaration.type.simpleName, inferredType) [
              visibility = JvmVisibility.PUBLIC
              parameters += content.toParameter("it", content.declaration.type.cloneWithProxies) => []
              body = content.method
            ]
          }


The strange thing is that whatever I use instead of "it" as the parameter name, makes the generated plugin issue an error saying the method is undefined. But with that "magic it", it works. An idea? The strange stuff is that my scoping works and it proposes only the methods defined inside the component.

A sample model
component First { 
  provides first(int param1);
}
component Second { 
  First myFirst
  requires myFirst::first(10) // got "the method first(int) is undefined if the inferrer uses any other parameter name than "it"
}

[Updated on: Wed, 18 April 2018 03:55]

Report message to a moderator

Re: Integration with Xbase - reference to model elements and java-like methodscalls [message #1785650 is a reply to message #1785647] Wed, 18 April 2018 04:43 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
From your inferrer I don't see how First myFirst in Second gets translated.

You automatically get all methods on parameters callled it offered so that you can call them without explicit Naming the parameter

It.xxxx or xxxxx would be both possible (not in your case since you just want to have restricted feature calls) so at your place there is only xxxxx

You can customize this behaviour in the feature scopes class (or by inferrring an additional @Extension annotation to the parameter ( that needs to be tested because I am not 1000 percent sure)


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Integration with Xbase - reference to model elements and java-like methodscalls [message #1785652 is a reply to message #1785650] Wed, 18 April 2018 05:34 Go to previous messageGo to next message
Fabian G. is currently offline Fabian G.Friend
Messages: 60
Registered: May 2010
Location: Christchurch (NZ)
Member
I finally got rid of the "declaration" part in the grammar (which was actually annoying and redundant) and I don't quite understand your answer, maybe I wasn't clear enough. I put all the simplified code:

ComponentModel:
  // magic import resolution mechanism (works out of the box)
  importSection=XImportSection? 
	elements += AbstractElement+;
	
AbstractElement:
    PackageDeclaration | Component;
 
PackageDeclaration:
  'package' name=QualifiedName '{'
      elements+=AbstractElement+
  '}';
 
Component:
  'component' name=ValidID ('extends' superType=JvmTypeReference)? '{' 
    content += Content*
  '}';

Content:
  Provide | Require ;

Provide:
  'provides' name=ValidID ('('(parameters+=FullJvmFormalParameter("," parameters+=FullJvmFormalParameter)*)?')')?
  (':' type=JvmTypeReference)? 
  (isEmpty?=';' | body=XBlockExpression);

Require:
  'requires' declaration=JvmTypeReference '::' method=XRestrictedFeatureCall ";";

XRestrictedFeatureCall returns xbase::XExpression:
  {xbase::XFeatureCall}
  ('<' typeArguments+=JvmArgumentTypeReference (',' typeArguments+=JvmArgumentTypeReference)* '>')?
  feature=[jvmTypes::JvmIdentifiableElement|IdOrSuper]
  (=>explicitOperationCall?='('
    (
        featureCallArguments+=XShortClosure
      | featureCallArguments+=XExpression (',' featureCallArguments+=XExpression)*
    )? 
  ')');

and the complete inferrer (where the "it" parameter in plain string is confusing me in the Require translation code),
def dispatch void infer(Component component, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {  
    acceptor.accept(component.toClass(component.fullyQualifiedName)) [
      documentation = component.documentation
      if (component.superType !== null) {
        superTypes += component.superType.cloneWithProxies
      }
      members += component.toConstructor []
      for (content : component.content) {
        switch (content) {
          Provide : {
            var type = typeRef(Void::TYPE);
            if (content.type !== null) {              
              type = content.type
            }
            members += content.toMethod(content.name, type) [
              content.parameters.forEach[parameter | parameters += parameter.toParameter(parameter.name, parameter.parameterType)]
              if (content.isIsEmpty) {
                body = '''/* TODO implement me */'''
              } else {
                body = content.body
              }
            ]            
          }
          Require : {
            members += content.toMethod("require" + content.declaration.simpleName, inferredType) [
              visibility = JvmVisibility.PUBLIC
              // if I use "content.declaration.simpleName.toLowerCase" instead of "it", I got the method is undefined error in the DSL model
              // using "it" as parameter here makes the trick => what am I missing to have the freedom on the name of that parameter ?
              parameters += content.toParameter("it", content.declaration.cloneWithProxies)
              body = content.method
            ]
          }
        }
      }
    ]
 }


The simplified models looks like
component First { 
  provides first(int param1);
}
component Second {
  requires First::first(10);
}

[Updated on: Wed, 18 April 2018 05:36]

Report message to a moderator

Re: Integration with Xbase - reference to model elements and java-like methodscalls [message #1785661 is a reply to message #1785652] Wed, 18 April 2018 07:05 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
it is it cause xtext treats it (as java this) differently so that you do not explicitely have to specify the parameter name in the expression:

in java

class X {
public void doSth2() {
doSth();// -> no this required, in xbase same hold true for params named it (contant in IFeatureNames)
}
public void doSth() {
}
}


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Integration with Xbase - reference to model elements and java-like methodscalls [message #1785662 is a reply to message #1785661] Wed, 18 April 2018 07:42 Go to previous messageGo to next message
Fabian G. is currently offline Fabian G.Friend
Messages: 60
Registered: May 2010
Location: Christchurch (NZ)
Member
Thanks for your answer, Christian. So, if I understand correctly, this is somewhat compulsory to use that special keyword here, right?
Re: Integration with Xbase - reference to model elements and java-like methodscalls [message #1785664 is a reply to message #1785662] Wed, 18 April 2018 07:49 Go to previous message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
it is inspired by "other" functional languages like groovy

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Previous Topic:Regarding cross-references between different files.
Next Topic:Hover on Keyword and Token
Goto Forum:
  


Current Time: Tue Apr 16 10:37:45 GMT 2024

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

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

Back to the top