Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » [XBase] Model inferer: Problem with manually building AST
[XBase] Model inferer: Problem with manually building AST [message #1064025] Mon, 17 June 2013 06:27 Go to next message
Alan DW is currently offline Alan DW
Messages: 104
Registered: March 2012
Senior Member
Hello everyone,

I'm building a ModelInferrer for my grammar using Xtext 2.4. It transforms my DSL into Java code using XBase.

Now I have the following problem. I need my generator to output a certain string into the generated *.java file (which is always the same). In an ordinary Xtend generator, you would simply output the desired string, but in XBase, things are different.

So, here's what I want to do: I want the generated file to contain the string (attention: the target is NOT supposed to be a string *literal*!):

MyRuntime.myUtilityMethod(arg);


Okay, so since I'm using Xbase, it seems that I cannot write this expression directly in the target file. But building the XExpression AST tree for that by hand (by calling the XBaseFactory and using setters and getters) is an extremely tedious task due to the very deep nesting level of elements required in XBase to map even this (rather simple) expression.

Therefore my question is: what is the best way to approach this problem? Is there some kind of "AST Utility" class that helps in building more complex XBase expressions? Or an expression parser that takes the code above as string and transforms it into an XBase expression?

Thanks,


Alan

[Updated on: Mon, 17 June 2013 07:07]

Report message to a moderator

Re: [XBase] Model inferer: Problem building AST [message #1064174 is a reply to message #1064025] Tue, 18 June 2013 02:01 Go to previous messageGo to next message
Sebastian Zarnekow is currently offline Sebastian Zarnekow
Messages: 2809
Registered: July 2009
Senior Member
Hi Alan,

you could bind a custom JvmModelGenerator and override the method that
produces the text for your class. There, you could insert the statement
as plain text.

Regards,
Sebastian
--
Looking for professional support for Xtext, Xtend or Eclipse Modeling?
Go visit: http://xtext.itemis.com

Am 17.06.13 12:27, schrieb Alan DW:
> Hello everyone,
>
> I'm building a ModelInferrer for my grammar using Xtext 2.4. It
> transforms my DSL into Java code using XBase.
>
> Now I have the following problem. I need my generator to output a
> certain string into the generated *.java file (which is always the
> same). In an ordinary Xtend generator, you would simply output the
> desired string, but in XBase, things are different.
>
> So, here's what I want to do: I want the generated file to contain the
> string (attention: the target is NOT supposed to be a string *literal*!):
>
> MyRuntime.myUtilityMethod(arg);
>
> Okay, so since I'm using Xbase, it seems that I cannot write this
> expression directly in the target file. But building the XExpression AST
> tree for that by hand (by calling the XBaseFactory and using setters and
> getters) is an extremely tedious task due to the very deep nesting level
> of elements required in XBase to map even this (rather simple) expression.
>
> Therefore my question is: what is the best way to approach this problem?
> Is there some kind of "AST Utility" class that helps in building more
> complex XBase expressions? Or an expression parser that takes the code
> above as string and transforms it into an XBase expression?
>
> Thanks,
>
>
> Alan
Re: [XBase] Model inferer: Problem building AST [message #1064208 is a reply to message #1064174] Tue, 18 June 2013 05:10 Go to previous messageGo to next message
Alan DW is currently offline Alan DW
Messages: 104
Registered: March 2012
Senior Member
Hi Sebastian,

thanks for your response, it's much appreciated. Is there any kind of documentation or tutorial on how to implement and integrate a custom JvmModelGenerator?

Thanks,


Alan
Re: [XBase] Model inferer: Problem building AST [message #1064739 is a reply to message #1064025] Thu, 20 June 2013 14:09 Go to previous messageGo to next message
Hallvard Traetteberg is currently offline Hallvard Traetteberg
Messages: 594
Registered: July 2009
Location: Trondheim, Norway
Senior Member
Hi,

I'm not sure I understood your problem, e.g. where in the file that
specific string should be generated/output. When using Xbase there are
typically two cases:
1) An XExpression is the complete body a method. This is handled by
assigning that expression to the body using method.body = expression
2) The XExpression is part of the body of the method, so the method
provides the scope. To handle this case, you instead assign the method
as the XExpression's logical container using
IJvmModelAssociator.associateLogicalContainer to get the scoping right,
and then assign a lambda as the method's body: method.body = [
it.append("whatever"); ... ]
'it' is bound to an ITreeAppendable and you use the standard way of
outputting strings to it. You can use an injected XBaseCompiler to
output an XExpression as part of the body (either as an expression or a
statement) and a TypeReferenceSerializer to output types.

Hallvard

On 17.06.13 03.27, Alan DW wrote:
> Hello everyone,
>
> I'm building a ModelInferrer for my grammar using Xtext 2.4. It
> transforms my DSL into Java code using XBase.
>
> Now I have the following problem. I need my generator to output a
> certain string into the generated *.java file (which is always the
> same). In an ordinary Xtend generator, you would simply output the
> desired string, but in XBase, things are different.
>
> So, here's what I want to do: I want the generated file to contain the
> string (attention: the target is NOT supposed to be a string *literal*!):
>
> MyRuntime.myUtilityMethod(arg);
>
> Okay, so since I'm using Xbase, it seems that I cannot write this
> expression directly in the target file. But building the XExpression AST
> tree for that by hand (by calling the XBaseFactory and using setters and
> getters) is an extremely tedious task due to the very deep nesting level
> of elements required in XBase to map even this (rather simple) expression.
>
> Therefore my question is: what is the best way to approach this problem?
> Is there some kind of "AST Utility" class that helps in building more
> complex XBase expressions? Or an expression parser that takes the code
> above as string and transforms it into an XBase expression?
>
> Thanks,
>
>
> Alan
Re: [XBase] Model inferer: Problem with manually building AST [message #1065386 is a reply to message #1064025] Tue, 25 June 2013 10:09 Go to previous messageGo to next message
Alan DW is currently offline Alan DW
Messages: 104
Registered: March 2012
Senior Member
Hi,

sorry for the late response, somehow I didn't get notified per Mail that there was a new post here...

So, to clarify what's going on, here's my full scenario.


The problem definition

My team and I were assigned to the task of creating a "method level access control framework" with Java, using Xtext. What this boils down to is that we have standard Java, with the addition of a "require" keyword followed by an expression, that determines if a method can be called. Here's an example of a DSL instance:

package myPackage;

public class Test extends Object {

   private String property;
   private int a; 

   require this.property.contentEquals("test");
   public int getA(){
      return this.a;
   }

}



So, we have this additional "require" block in front of every method. Afterwards, an arbitrary Java expression (that evaluates to boolean) may follow, then a semicolon, and then the actual body of the method.


Our solution attempt

We use a Xtext project in combination with XBase. We re-modelled all components above the "XExpression" level (so our grammar contains the constructs for package declaration, import declaration, class declaration etc., often referring to the structures offered by XBase, e.g. JVMTypeReference), modelled the DSL-specific part with the "require" keyword (the part between "require" and ";" is an XExpression), defined the method header and using another XExpression as method body.

Then, when generating Java code, we want to inject the "require" expression into an if-statement on the first line of the method body, which throws an exception when the condition is not fulfilled, and continues with the normal method body if the condition is fulfilled. This looks like this (pseudo-code):

... method header ... {
   if(!<require expression>){
      throw new AccessDeniedException();
   }
   ... continue with normal method body...
}



We managed to come this far, even though the "throw new AccessDeniedException()" was challenging to map onto the XBase AST.


The Showstopper

But we also have another DSL that allows to specify user roles (e.g. guest, admin...) and we have to support references inside the "require" block. So, we introduced a very basic runtime class, that statically holds the current user. Its interface looks like this:

public class UserManager{

   public static User getCurrentUser();
   public static boolean isUserLoggedIn();
   public static boolean doesUserHaveAccessLevel(AccessLevel minimumLevel);

}



Now, a "require" block could look like this:

require role Admin;


... where "Admin" is a user role defined in our User DSL. We managed to do that as well and link together the two Xtext DSLs (even though modifying the MWE file was quite a pain due to string equivalences and typos), so on the surface, this works. However, we face a problem in code generation, because what we need to inject as first statement into our method in this case is:

... method header ... {
   if(!UserManager.doesUserHaveAccessLevel(Admin.getLevel()){
      throw new AccessDeniedException();
   }
   ... continue with normal method body...
}



... so we need to form a call to a static method in the XBase AST, and we have to do it manually from code (i.e. we cannot rely on the XBase parser here since that call does not exist in the DSL source code).


And this is as far as we got. The UI is working perfectly, but we could not manage to get the XBase AST structure right to do this method call in the code generation.


Sorry for the long post, but this required some explanation Smile


Greets,


Alan
Re: [XBase] Model inferer: Problem with manually building AST [message #1066362 is a reply to message #1065386] Tue, 02 July 2013 06:48 Go to previous message
Hallvard Traetteberg is currently offline Hallvard Traetteberg
Messages: 594
Registered: July 2009
Location: Trondheim, Norway
Senior Member
Hi,

Although for simple cases, you may be able to construct an AST for a
"derived" XExpression that contains XExpressions in the DSL, this is in
general difficult, as you have experienced. Instead, you need to emit
the code as text, using an ITreeAppendable, corresponding to option 2)
in my previous message:

"The XExpression is part of the body of the method, so the method
provides the scope. To handle this case, you instead assign the method
as the XExpression's logical container using
IJvmModelAssociator.associateLogicalContainer to get the scoping right,
and then assign a lambda as the method's body: method.body = [
it.append("whatever"); ... ]
'it' is bound to an ITreeAppendable and you use the standard way of
outputting strings to it. You can use an injected XBaseCompiler to
output an XExpression as part of the body (either as an expression or a
statement) and a TypeReferenceSerializer to output types."

Here's the pseudo-code:

val reqMethod = req.toMethod(methodDecl.name + "Pre", booleanType)
reqMethod.body = req.expression
jvmModelAssociator.associateLogicalContainer(methodDecl.body)
val bodyMethod = methodDecl.toMethod(methodDecl.name, methodDecl.returnType)
bodyMethod.body = [
it.append('''if (! <<methodDecl.name + "Pre">>()) { throw ...} ''')
xbaseCompiler.toJavaExpression(methodDecl.body, it)
]

Hallvard

On 25.06.13 16.09, Alan DW wrote:
> Hi,
>
> sorry for the late response, somehow I didn't get notified per Mail that
> there was a new post here...
>
> So, to clarify what's going on, here's my full scenario.
>
> The problem definition
>
> My team and I were assigned to the task of creating a "method level
> access control framework" with Java, using Xtext. What this boils down
> to is that we have standard Java, with the addition of a "require"
> keyword followed by an expression, that determines if a method can be
> called. Here's an example of a DSL instance:
>
> package myPackage;
>
> public class Test extends Object {
>
> private String property;
> private int a;
> require this.property.contentEquals("test");
> public int getA(){
> return this.a;
> }
>
> }
>
>
>
> So, we have this additional "require" block in front of every method.
> Afterwards, an arbitrary Java expression (that evaluates to boolean) may
> follow, then a semicolon, and then the actual body of the method.
>
>
> Our solution attempt
>
> We use a Xtext project in combination with XBase. We re-modelled all
> components above the "XExpression" level (so our grammar contains the
> constructs for package declaration, import declaration, class
> declaration etc., often referring to the structures offered by XBase,
> e.g. JVMTypeReference), modelled the DSL-specific part with the
> "require" keyword (the part between "require" and ";" is an
> XExpression), defined the method header and using another XExpression as
> method body.
>
> Then, when generating Java code, we want to inject the "require"
> expression into an if-statement on the first line of the method body,
> which throws an exception when the condition is not fulfilled, and
> continues with the normal method body if the condition is fulfilled.
> This looks like this (pseudo-code):
>
> .. method header ... {
> if(!<require expression>){
> throw new AccessDeniedException();
> }
> ... continue with normal method body...
> }
>
>
> We managed to come this far, even though the "throw new
> AccessDeniedException()" was challenging to map onto the XBase AST.
>
>
> The Showstopper
>
> But we also have another DSL that allows to specify user roles (e.g.
> guest, admin...) and we have to support references inside the "require"
> block. So, we introduced a very basic runtime class, that statically
> holds the current user. Its interface looks like this:
>
> public class UserManager{
>
> public static User getCurrentUser();
> public static boolean isUserLoggedIn();
> public static boolean doesUserHaveAccessLevel(AccessLevel minimumLevel);
>
> }
>
>
> Now, a "require" block could look like this:
>
> require role Admin;
>
> .. where "Admin" is a user role defined in our User DSL. We managed to
> do that as well and link together the two Xtext DSLs (even though
> modifying the MWE file was quite a pain due to string equivalences and
> typos), so on the surface, this works. However, we face a problem in
> code generation, because what we need to inject as first statement into
> our method in this case is:
>
> .. method header ... {
> if(!UserManager.doesUserHaveAccessLevel(Admin.getLevel()){
> throw new AccessDeniedException();
> }
> ... continue with normal method body...
> }
>
>
> .. so we need to form a call to a static method in the XBase AST, and we
> have to do it manually from code (i.e. we cannot rely on the XBase
> parser here since that call does not exist in the DSL source code).
>
>
> And this is as far as we got. The UI is working perfectly, but we could
> not manage to get the XBase AST structure right to do this method call
> in the code generation.
>
>
> Sorry for the long post, but this required some explanation :)
>
>
> Greets,
>
>
> Alan
Previous Topic:suppress generation of .gitignore by Xtend
Next Topic:How to install my xtext dsl as a plug in to Eclipse?
Goto Forum:
  


Current Time: Sun Aug 31 04:31:17 EDT 2014

Powered by FUDForum. Page generated in 0.02092 seconds