Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Simple Xtext Interpreter Example (for the real world)  () 1 Vote
Simple Xtext Interpreter Example (for the real world) [message #847490] Tue, 17 April 2012 11:05 Go to next message
Karl Puperze is currently offline Karl PuperzeFriend
Messages: 36
Registered: August 2011
Member
I have read a couple of tutorials and the Xtext doc but i still need some help. I would like to write a DSL based on XBase to make some tax calculations. One part of the DSL will be referencing account balances and do some calculations. The XBase package should provide expressions and variable declarations.

The DSL part should look like this:
var x = account(123) + account(321)
var y = account(1a22) + account(b1145)

Expected result when evaluating the program: account(xxx) should read the account balance from a database, the calculation should be performed and the variables x and y should be written to the database.

Can someone explain to me, how the DSL definition should look like for this simple example and how to implement an interpreter (I don´t know how to utilize the XbaseInterpreter)?

Re: Simple Xtext Interpreter Example (for the real world) [message #847846 is a reply to message #847490] Tue, 17 April 2012 18:09 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Hi,

it is very hard to answer such a general question. what is your problem? what do you have so far?
do you really need everything xbase offers? maybe writing a xbase independent dsl is better.

never the less: here is a five min example

Model:
	expressions+=XVariableDeclaration*;
	
XPrimaryExpression returns xbase::XExpression:
	XConstructorCall |
	XBlockExpression |
	XSwitchExpression |
	XAccountStuff |
	XFeatureCall |
	XLiteral |
	XIfExpression |
	XForLoopExpression |
	XWhileExpression |
	XDoWhileExpression |
	XThrowExpression |
	XReturnExpression |
	XTryCatchFinallyExpression |
	XParenthesizedExpression;	
	
XAccountStuff:
	"account" "(" id=ID ")"
;	


@SuppressWarnings("restriction")
public class MyInterpreter extends XbaseInterpreter {
	
	protected Object _evaluateXAccountStuff(XAccountStuff stuff,
			IEvaluationContext context, CancelIndicator indicator) {
		return stuff.getId().length();
	}
	
	protected Object _evaluateVariableDeclaration(XVariableDeclaration variableDecl, IEvaluationContext context, CancelIndicator indicator) {
		super._evaluateVariableDeclaration(variableDecl, context, indicator);
		return context.getValue(QualifiedName.create(variableDecl.getName()));
	}

}


@RunWith(XtextRunner.class)
@InjectWith(MyDslInjectorProvider.class)
public class InterpreterTest {
	
	@Inject MyInterpreter myInterpreter;
	
	@Inject ParseHelper<Model> parseHelper;
	
	@SuppressWarnings("restriction")
	@Test
	public void test() throws Exception {
		String model = "var x = account(xxx)\nvar y = account(xxxxxx)";
		Model m = parseHelper.parse(model);
		for  (XExpression decl : m.getExpressions()) {
			System.out.println(myInterpreter.evaluate(decl).getResult());
			
		}
	}

}


~Christian


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Simple Xtext Interpreter Example (for the real world) [message #848520 is a reply to message #847846] Wed, 18 April 2012 09:54 Go to previous messageGo to next message
John Blue is currently offline John BlueFriend
Messages: 7
Registered: April 2012
Location: San Francisco
Junior Member

Thanks Christian for your response. I want to expand on the example with our xbase derived language which we are also trying to interprete.

Our Grammar has two parts: first part is define variables and bean declarations, similar to Spring Beans, or even MWE2 (on Xbase). For example

1   module test
2      val foo = 'FOO'
3      val port = '123'
4      val bar = foo + port
5      bean book com.company.OrderProcessor(s1){ 
6         title = foo.[ foo | foo.toFirstLower ]              
7      }


Notice in line 4 how 'bar' is defined in terms of another variable with xbase expression, whereas on line 5, a bean is declared with a constructor call, and a series of assignment blocks.

Second part is a typical workflow definition using those variables and bean declarations as follows:

8      step one uri 'incomingOrders${port}'        
9      flow {
10         one => OrderProcessor => step two uri 'outgoingOrders'
11     }

Notice how on line 8, the step definition uses a variable ${port} in its uri definition, as well as in line 10, how declaredBean is used as a flow step.

Our initial grammar which was somewhat like this:

Module:
  {Module}
  'module' canonicalName=QualifiedName 
  elements += ModuleElement*;

ModuleElement:
	Import | 
	Variable | 
	Bean | 
	Step |
	Flow;  

Variable : 	variable = XVariableDeclaration;

Bean:    // copied from xbase.XConstructorCall   
  {Bean} 'bean'  name=ValidID type=[types::JvmType|QualifiedName] 
	'(' 
		(
		    arguments+=XShortClosure
		  |	arguments+=XExpression (',' arguments+=XExpression)*
		)? 
	')'
	assignments = AssignmentBlock?

AssignmentBlock: {AssignmentBlock}
	'{' => assignments+=Assignment*  '}' ;
	
Assignment: assignment = XAssignment;


Although with proper scoping, the editors are working as expected, we are experiencing the difficulty of interpreting the expressions if we dont extend from XPrimaryExpression as Christian suggests.

Now, based on Christian's feedback we will experiment with the following approach where we use XVariableDeclaration directly and Bean, Step, Flow are subtypes of XPrimaryExpression as Christian suggested in his example

Module:
  {Module}
  'module' canonicalName=QualifiedName
  imports += Import*
  elements += XExpressionInsideBlock*;
  
  XPrimaryExpression returns xbase::XExpression:
	XConstructorCall |   // needed for initializing variables?
	XBlockExpression |
	XSwitchExpression |
	XFeatureCall |
	XLiteral |
	XIfExpression |      
	XForLoopExpression | 
	XWhileExpression |   
	XDoWhileExpression | 
	XThrowExpression |
	XReturnExpression |  
	XTryCatchFinallyExpression |
	XParenthesizedExpression |
	Bean | 
	Step |
	Flow ;

From the Bean declarations: we will initialize a set of beans using the Xbase Interpreter at startup. Beans will be put to a Bean registry similiar to Spring. From the workflow definitions however, we will create instances of a workflow engine API and execute the workflow.

Questions:
1- Does it make sense to extend Bean/Step and Flow from XPrimaryExpression in this case?
2- What is the impact of redefining XPrimaryExpression elements from xbase to interpreter etc. eg. Notice the similarity of Bean declaration with assignments to XConstructorCall, perhaps Bean can be defined as a redefinition of XConstructorCall?
3- One idea is to separate the Bean + Variable declarations which gets interpreted to a separate language on its own, in order to simplify the workflow part of the language which does not really need Xbase as much.. Would you recommend this?
Re: Simple Xtext Interpreter Example (for the real world) [message #848785 is a reply to message #848520] Wed, 18 April 2012 15:16 Go to previous messageGo to next message
Karl Puperze is currently offline Karl PuperzeFriend
Messages: 36
Registered: August 2011
Member
Thanks a lot. I think I got the idea.
Re: Simple Xtext Interpreter Example (for the real world) [message #848882 is a reply to message #848520] Wed, 18 April 2012 17:07 Go to previous messageGo to next message
Sebastian Zarnekow is currently offline Sebastian ZarnekowFriend
Messages: 3118
Registered: July 2009
Senior Member
Hi John,

1 - yes, that does make sense. Please note how the abstract syntax only
suggests that bean, flow and step inherit from XExpression. That's what
I would recognize as 'extend'. The fact that you redefine the production
rule XPrimaryExpression has only an impact on the concrete syntax of
your language and in your case it only affects the precedencies. I think
it's reasonable to assume that bean, flow and step are on the same
hierarchical level as if, for and e.g. constructor calls.

2 - see (1) + you have to add cases for your own types, e.g. add the method

protected Object _evaluateBean(Bean bean, IEvaluationContext context,
CancelIndicator cancelIndicator) { .. process bean .. }

Regarding the question about XConstructorCall: That would probably make
your model cleaner thus validation and the like would be more straight
forward since you already use a cross reference to a specific
JvmConstructor instead of a type. However, that is independent from the
concrete syntax, e.g. your EClass 'Bean' could inherit from
XConstructorCall while you still override XPrimaryExpression in the grammar.

3 - sorry I did not get the idea of separating both into an own
language. Generally speaking another language introduces additional
complexity and should be done with care.

Regards,
Sebastian
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com

Am 18.04.12 11:54, schrieb John Blue:
> Thanks Christian for your response. I want to expand on the example with
> our xbase derived language which we are also trying to interprete.
>
> Our Grammar has two parts: first part is define variables and bean
> declarations, similar to Spring Beans, or even MWE2 (on Xbase). For example
>
> 1 module test
> 2 val foo = 'FOO'
> 3 val port = '123'
> 4 val bar = foo + port
> 5 bean book com.company.OrderProcessor(s1){ 6 title = foo.[ foo |
> foo.toFirstLower ] 7 }
>
>
> Notice in line 4 how 'bar' is defined in terms of another variable with
> xbase expression, whereas on line 5, a bean is declared with a
> constructor call, and a series of assignment blocks.
>
> Second part is a typical workflow definition using those variables and
> bean declarations as follows:
>
> 8 step one uri 'incomingOrders${port}' 9 flow {
> 10 one => OrderProcessor => step two uri 'outgoingOrders'
> 11 }
>
> Notice how on line 8, the step definition uses a variable ${port} in its
> uri definition, as well as in line 10, how declaredBean is used as a
> flow step.
>
> Our initial grammar which was somewhat like this:
>
> Module:
> {Module}
> 'module' canonicalName=QualifiedName elements += ModuleElement*;
>
> ModuleElement:
> Import | Variable | Bean | Step |
> Flow;
> Variable : variable = XVariableDeclaration;
>
> Bean: // copied from xbase.XConstructorCall {Bean} 'bean' name=ValidID
> type=[types::JvmType|QualifiedName] '(' (
> arguments+=XShortClosure
> | arguments+=XExpression (',' arguments+=XExpression)*
> )? ')'
> assignments = AssignmentBlock?
>
> AssignmentBlock: {AssignmentBlock}
> '{' => assignments+=Assignment* '}' ;
>
> Assignment: assignment = XAssignment;
>
>
> Although with proper scoping, the editors are working as expected, we
> are experiencing the difficulty of interpreting the expressions if we
> dont extend from XPrimaryExpression as Christian suggests.
>
> Now, based on Christian's feedback we will experiment with the following
> approach where we use XVariableDeclaration directly and Bean, Step, Flow
> are subtypes of XPrimaryExpression as Christian suggested in his example
>
> Module:
> {Module}
> 'module' canonicalName=QualifiedName
> imports += Import*
> elements += XExpressionInsideBlock*;
>
> XPrimaryExpression returns xbase::XExpression:
> XConstructorCall | // needed for initializing variables?
> XBlockExpression |
> XSwitchExpression |
> XFeatureCall |
> XLiteral |
> XIfExpression | XForLoopExpression | XWhileExpression |
> XDoWhileExpression | XThrowExpression |
> XReturnExpression | XTryCatchFinallyExpression |
> XParenthesizedExpression |
> Bean | Step |
> Flow ;
>
> From the Bean declarations: we will initialize a set of beans using the
> Xbase Interpreter at startup. Beans will be put to a Bean registry
> similiar to Spring. From the workflow definitions however, we will
> create instances of a workflow engine API and execute the workflow.
> Questions: 1- Does it make sense to extend Bean/Step and Flow from
> XPrimaryExpression in this case?
> 2- What is the impact of redefining XPrimaryExpression elements from
> xbase to interpreter etc. eg. Notice the similarity of Bean declaration
> with assignments to XConstructorCall, perhaps Bean can be defined as a
> redefinition of XConstructorCall? 3- One idea is to separate the Bean +
> Variable declarations which gets interpreted to a separate language on
> its own, in order to simplify the workflow part of the language which
> does not really need Xbase as much.. Would you recommend this?
Re: Simple Xtext Interpreter Example (for the real world) [message #849642 is a reply to message #848882] Thu, 19 April 2012 10:27 Go to previous message
John Blue is currently offline John BlueFriend
Messages: 7
Registered: April 2012
Location: San Francisco
Junior Member

Thanks Sebastian. We've got some grammar conflicts with XFeatureCall at both Step and Component which extend from XPrimaryExpression.

As an example, we want to be able to say:
1 componentType myType
2 myType myComponent
3 myComponent step myStep

where 'componentType' and 'step' are keywords, but it can't differentiate whether myType is an XFeatureCall or ComponentType reference on line 2, or whether 'myComponent' is a XFeatureCall or Component reference on line 3.

Here is my grammar:

XPrimaryExpression returns xbase::XExpression:
    ...
	XFeatureCall |   
	...
	Bean | 
	Component |
	Step ;

Step returns xbase::XExpression:
	{Step}	
	(component = [Component|QualifiedName])? 
	'step' name=ValidID ;

Component returns xbase::XExpression:
	{Component}
	type=[extension::ComponentType|QualifiedName] 
	name=ValidID
	assignments = AssignmentBlock;
	
XFeatureCall returns XExpression:   (original from XBase)
	{XFeatureCall}
	(declaringType=[types::JvmDeclaredType|StaticQualifier])?
	...
	feature=[types::JvmIdentifiableElement|IdOrSuper] 
	...
	
AssignmentBlock returns xbase::XBlockExpression:
	{AssignmentBlock}
	'{'
    	(expressions+=XAssignment ';'?)*
  	'}' 
;		

We are trying to determine the best way of resolving these conflicts. More questions:
1 - Would using JVMModelInferer to map Component, ComponentType to JVMTypes help, so we can have Step and Component extend from XFeatureCall?
2 - To do proper left-factoring, we probably should not redefine XExpression higher up from XPrimaryExpression, perhaps redefining XExpression itself..?
3- Does AssignmentBlock which extends from XBlockExpression look ok? Or would you recommend to use XBlockExpression directly from Component, and use validation to ensure that only assignments are inside the block when used within the context of Component element?
Previous Topic:Xtext and Xtend
Next Topic:validating for unique names in different resources
Goto Forum:
  


Current Time: Thu Apr 25 09:39:44 GMT 2024

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

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

Back to the top