Functions are used as a programming facility. Like in an object oriented language, functions are assigned to model elements and have access to all properties of that model element. They provide the means to easily request derived information from a model element, like the following example shows.

Functions are used as a programming facility. Like in an object oriented language, functions are assigned to model elements and have access to all properties of that model element. They provide the means to easily request derived information from a model element, like the following example shows.

+

Functions are declaritive constructs and behave like functions in a functional language.

'''Definition:'''

'''Definition:'''

Line 83:

Line 84:

:''This function without parameter is defined on <tt>OclModelElement</tt> to build a string.''

:''This function without parameter is defined on <tt>OclModelElement</tt> to build a string.''

+

+

==== Attributes ====

+

Attributes can be used to decorate model elements with extra information.

+

+

'''Definition:'''

+

<pre>

+

attribute <Context>::<Attribute Name> =

+

<Attribute Definition>;

+

</pre>

+

+

'''Example:'''

+

<pre>

+

attribute Object::location =

+

self.__xmiID__;

+

</pre>

+

+

:'' From the comment in ATL.acg: "ACG uses the location to distinguish variable declarations but the QVT metamodel does not have this feature. Therefore, we emulate it using the xmi ID."''

=== Code production helpers ===

=== Code production helpers ===

Line 228:

Line 246:

unmatched(subRule):

unmatched(subRule):

}

}

−

}

</pre>

</pre>

:''Here we would find jumps inside the production code of the foreach loop that act as forward/continue statements. Without the extra parameter the offset will be calculated only once and later iterations will jump backward, possibly creating infinite loops''

:''Here we would find jumps inside the production code of the foreach loop that act as forward/continue statements. Without the extra parameter the offset will be calculated only once and later iterations will jump backward, possibly creating infinite loops''

Line 268:

Line 285:

Consider there exist multiple conditional templates for this type, then the conditions are evaluated within the context of the element that is being analyzed. As conditions must define a partition of candidate model elements, at most one conditional template can be called. In case that no conditional template is defined or no condition is matched, the default template (the one with no condition call on it) is called.

Consider there exist multiple conditional templates for this type, then the conditions are evaluated within the context of the element that is being analyzed. As conditions must define a partition of candidate model elements, at most one conditional template can be called. In case that no conditional template is defined or no condition is matched, the default template (the one with no condition call on it) is called.

−

==== Functions ====

+

==== Calling Functions ====

Functions can be called on model elements if they are of the type (or a subtype of) of the function context.

Functions can be called on model elements if they are of the type (or a subtype of) of the function context.

A function defined on type foo, named bar and with no parameter would be called this way:

A function defined on type foo, named bar and with no parameter would be called this way:

Line 285:

Line 302:

}

}

</pre>

</pre>

+

+

Parameters can be put in a comma-separated fashion between the parenthesis. They are passed by reference so can be used as return values.

+

+

'''Example:'''

+

<pre>

+

MyObject {

+

<Production rules with a declaration of variable x>

+

push self.foo.bar2(x)

+

}

+

</pre>

+

+

==== Calling Attribute Values ====

+

Much the same as for function calling, but without parenthesis.

=== Operation based instructions ===

=== Operation based instructions ===

Line 332:

Line 362:

}

}

</pre>

</pre>

−

:''This is the definition of an operation called <tt>resolveTemp</tt> on the ATL context module with two parameters (an Object <tt>value</tt> and a String <tt>name</tt>).''

+

:''This is the definition of an operation called <tt>resolveTemp</tt> on the ATL context module with two parameters (an Object <tt>value</tt> and a String <tt>name</tt>). This will generate an assembly operation as demonstrated below.''

+

+

<pre>

+

&lt;operation name="resolveTemp"&gt;

+

&lt;context type="A"/&gt;

+

&lt;parameters&gt;

+

&lt;parameter name="value" type="J"/&gt;

+

&lt;parameter name="name" type="S"/&gt;

+

&lt;/parameters&gt;

+

&lt;code&gt;

+

</pre>

==== variable ====

==== variable ====

Line 343:

Line 383:

}

}

</pre>

</pre>

−

The variable instruction needs an identifier as the name is not restrictive enough. Indeed, several variable with the same name can coexists in the same code scope.

+

The variable instruction is defined on a model element but also needs a name. The combination of these two allows ACG to maintain variables across severall rules. Several variables with the same name can coexists in the same code scope.

'''Example:'''

'''Example:'''

Line 354:

Line 394:

}

}

</pre>

</pre>

−

:''The variable definition (line 1) allows the load call (line 3).''

+

:''The variable definition (line 1) allows the load call (line 3). Remember that a variable declaration also immediately stores a value, so we have to be sure a value is available on the stack before we can declare a variable. For a case where the value can't be known prior to declarationm one can use <tt>OclUndefined</tt>''

+

+

==== field ====

+

As normal variables are local to operations, we also need a way to specify global variables. This can be done with the field keyword. They can be specified in the ASM context or within rules, so they can be generated from the input model.

+

+

'''Definition:'''

+

<pre>

+

field <field name> : <field type>

+

</pre>

+

+

'''Example:'''

+

<pre>

+

field 'links' : 'NTransientLinkSet;'

+

</pre>

+

+

:''This generates a global variable of type <tt>NTransientLinkSet</tt>. Later more on this type.''

+

+

Since fields reside in the global asm context, they are referenced as a property of this context. The following example illustrates this.

+

+

'''Example:'''

+

<pre>

+

getasm

+

get 'links'

+

</pre>

+

+

:''This code will pop the content of <tt>links</tt> a <tt>NTransientLinkSet</tt> on the stack.''

=== VM Instructions ===

=== VM Instructions ===

There exists one statement per ATL VM instruction. Each of these statements have the same name than the instruction and, of course, leads to the production of this instruction in the target model.

There exists one statement per ATL VM instruction. Each of these statements have the same name than the instruction and, of course, leads to the production of this instruction in the target model.

−

An instruction is followed by its operand as defined in the VM specification. For some arguments defined is ACG, the compiler performs a rewriting (or more exactly an interpretation -read transformation) given that that ASM code is not convenient to write by hand and that ACG could help by making things more "human compliant".

+

An instruction is followed by its operand as defined in the VM specification. For some arguments defined in ACG, the compiler performs a rewriting (or more exactly an interpretation -read transformation) given that that ASM code is not convenient to write by hand and that ACG could help by making things more "human compliant".

It is the case for :

It is the case for :

*the <tt>load</tt> instruction: Its argument is a variable reference. In ACG, this reference is:

*the <tt>load</tt> instruction: Its argument is a variable reference. In ACG, this reference is:

−

**their identifier for common variables

+

**the identifier of a common variable

−

**their name for parameters.

+

**the name of a parameter.

: &rarr; It is rewritten in corresponding slot number.

: &rarr; It is rewritten in corresponding slot number.

−

*the <tt>if</tt> instruction: Its argument is a code offset.

+

*the <tt>if</tt> instruction: Its argument is a referrence to a label.

−

: &rarr; It is replaced by the absolute position of where the referred label should have been if it had not been removed.

+

: &rarr; It is replaced by the offset from the location of the label after code generation.

*the <tt>goto</tt> instruction

*the <tt>goto</tt> instruction

−

: &rarr; Same rewritting

+

: &rarr; See <tt>if</tt>

+

+

=== Things to Keep in Mind ===

+

When writing ACG code, we specify compile-time calculation to generate runtime code. We have to keep in mind that the only interface between compile-time and runtime is the generated assembly file. At runtime we can't access the language model, so any complex model structure we want to referrence, has to be specified in the generated assembly explicitly.

+

We can circumvent this problem to a certain extend by making use of some higher level model queries provided by EMF, shown in the following section.

+

+

=== Usefull Functionality ===

+

==== Transient Links ====

+

Writing model transformations, we often have to keep track of the tracibility links created between source and target models. Model transformation languages like ATL and QVT keep track of these links behind the screens, they can then either be explicitly referenced in the language (as is the case in QVT Operational Mappings) or they can be used by the language to automaticly transform links between model elements (as is done in ATL and QVT relational).

+

Either means that, implementing these languages, we need to keep track of the links. The ATLVM therefore provides the <tt>TransientLink</tt> object. It can be referenced in ACG.

+

+

'''Example:'''

+

<pre>

+

push 'TransientLink'

+

push '#native'

+

new

+

+

dup

+

push self.name

+

call 'NTransientLink;.setRule(MATL!Rule;):V'

+

+

foreach(ipe in self.inPattern.elements) {

+

dup

+

push ipe.varName

+

load ipe.actualDeclaration()

+

call 'NTransientLink;.addSourceElement(SJ):V'

+

}

+

...

+

</pre>

+

+

:''In this example a <tt>TransientLink</tt> is created, given a reference to the executing rule and some source model elements are added. We can also add target elements and variables and later store the link in a <tt>TransientLinkSet</tt>. More on this can be found in [http://www.eclipse.org/m2m/atl/doc/ATL_VM_Presentation_%5B1.0%5D.pdf ATL VM specification]''

+

+

NOTE: Maintaining trace information can also be done by specifying another input model to store these informations.

+

+

==== EMF Model Query Functions ====

+

As noted before we cannot access the language model at runtime, making it dificult to implement lookaheads and things like that. EMF however provides facilities to reference the model via queries on the metametamodel. Here some examples that might be useful for your compiler design. These functionscan be called runtime and compile-time on any model element.

+

+

'''Example:'''

+

<pre>

+

self.refImmediateComposite()

+

</pre>

+

:''Will get all the parent of the model element.''

+

+

'''Example:'''

+

<pre>

+

self.eContents()

+

</pre>

+

:''Will get a <tt>Set</tt> of all the children (referrences) of the model element.''

+

+

'''Example:'''

+

<pre>

+

self.eClass()

+

</pre>

+

:''Will get implicit type of the model element as resolved by the metamodel.''

ACG also does not allow us to define (static) global compile-time variables. We can emulate these by adding an attribute to the Object model elements, the super type of all model elements. The following example uses this to be able to switch from a debug to normal compiler.

+

+

'''Example:'''

+

<pre>

+

attribute Object::__debug = true; --either true or false

+

</pre>

+

+

:''The debug variable can now easily be accessed in any context.''

== Use ==

== Use ==

−

Once the ACG file is defined for the transformation language model, it has to be compiled so that every transformations written is this language could be compiled into ASM.

+

Once the ACG file is defined for the transformation language model, it has to be compiled so that every transformation written is this language could be compiled into ASM.

This is done thanks to an AMMA tool set including several Ant scripts. Those scripts are intended to provide all the facilities to build a Domain Specific Language (editor, megamodel, concrete and abstract syntax and a compiler if the semantics relies on the ATL VM).

This is done thanks to an AMMA tool set including several Ant scripts. Those scripts are intended to provide all the facilities to build a Domain Specific Language (editor, megamodel, concrete and abstract syntax and a compiler if the semantics relies on the ATL VM).

+

+

==Source==

+

+

The source of ACG is provided as the [http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.m2m/org.eclipse.m2m.atl/dsls/ACG/?root=Modeling_Project ACG] [[TCS/Language Project|language project]], which contains:

Background

Use Case

The ATL language semantics defines operations on models (such as testing condition on an element, creating an element or setting an element feature to a value). These operations are implemented by the ATL VM which executes ASM program on source model(s) to produce the output model(s).

Getting the compiled ASM version of an ATL transformation is done in three stages:

injecting ATL source code to get it into a model based representation (XMI whose structure conforms to the ATL model)

transform this ATL model into an ASM model

extracting the ASM model to get it into a textual representation conforming to its syntax (ASM code).

The second stage is actually done by a transformation in ACG defined in ATL.acg.

This process has been bootstrapped. This means that ACG semantic is defined in ACG. Thus an ACG script is now compiled using ACG to get the corresponding ASM version. This means that the compilation from a transformation model to ATL VM code is done by the ATL VM itself using ACG.acg.

Every transformation defines an entry point (with the keyword startsWith). It is a production rule called at the beginning of the transformation. It defines thereby the top level element of the transformation.

Templates

The elements used to express the transformation are the templates. They are the code production rules defined in the context of an element of the transformation language model. They define what code should be generated for this kind of item.
Rule execution may be limited to only several elements of the kind satisfying a given condition. The condition can be entered after the pipe symbol.

This is a production rule defined from the object Helper which carries out only one operation (analyze). Accordingly, the production rule will be called corresponding to the property feature of the property definition of the current Helper model element

Functions

Functions are used as a programming facility. Like in an object oriented language, functions are assigned to model elements and have access to all properties of that model element. They provide the means to easily request derived information from a model element, like the following example shows.
Functions are declaritive constructs and behave like functions in a functional language.

This statement is defined in the context of an object having a multi-valued feature named parameters, of which only the only which property kind is equal to 'in' are filtered using the OCL select function. For each one of these parameters a param instruction is called with arguments:

the varName feature of the parameters component in question

the string “J”

In one of the following sections it is explained how the param keyword is used in conjunction with an operation and what effects its parameters actually have.

Only Once Evaluation Statement

The corresponding rules will be evaluated only once. If it is defined inside a Foreach statement, the evaluation will be done after the last loop executed and is then inserted into the resulting assembly from the loop. This is useful for blocks interweaving.

Analyze statement

Call the matching template for the model element(s) resulting from the OCL evaluation in the current context. Between braces we can put the production code that should be executed after each temple calling (not used in example).

From within the current object, this will fetch the object pointed by the inPattern reference, and then will follow its filter reference to get the object which will lead in the launch of the production rule corresponding to the objects type.

Offsets management

The procedural style of ACG (defining templates as units of processing) leaves the replacing of a template call by corresponding code to the compiler. This results in a lack of a priori knowledge of the amount of code generated by an analyze statement and thereby in the difficulty to handle code offsets (needed by some instructions of the ATL VM). To fix this difficulty, ACG provides a mechanism of labels.

Definition:

<label name>:

This way, the ACG compilation replaces any argument of jump instructions referencing a label by the correct offset. Of course, no trace of label is left in the ASM code.

This code starts with an analyze statement followed by a if statement. We can assume that the result of the evaluation of self.condition will lead to instructions pushing their result (a boolean) on the stack. The if statement will ask an evaluation of this variable and will make the execution continue at a point depending on the result. If there is true on the top of the stack, the execution pointer will jump over the instructions produced by the production rules before thn:. Otherwise it will continue on the next line. The goto statement will always make the execution pointer jump to the location of the eoi: label.

Inside foreachstatements a parameter can begiven to the label, so the compiler knows it should recalculate the offset for each iteration.
Example:

Here we would find jumps inside the production code of the foreach loop that act as forward/continue statements. Without the extra parameter the offset will be calculated only once and later iterations will jump backward, possibly creating infinite loops

Simple code factoring

The let statement allows a programmer to write an OCL expression only and use it several times. The resulting value is bound to a literal. This way, anywhere inside the let statement scope, the compiler will replace this literal by the corresponding OCL expression.

The outer brackets define the let statement's scope (the code in which ep will be recognized). The code inside uses this binding resulting in a clearer and smarter code.

Usage of ACG structures

Calling Templates

Templates can be assigned call condition which allows to define several behaviours for a single type depending on a condition.

When an analyze statement is found, a template defined for the element's true type is called.
Consider there exist multiple conditional templates for this type, then the conditions are evaluated within the context of the element that is being analyzed. As conditions must define a partition of candidate model elements, at most one conditional template can be called. In case that no conditional template is defined or no condition is matched, the default template (the one with no condition call on it) is called.

Calling Functions

Functions can be called on model elements if they are of the type (or a subtype of) of the function context.
A function defined on type foo, named bar and with no parameter would be called this way:

param

This is the definition of an operation called resolveTemp on the ATL context module with two parameters (an Object value and a String name). This will generate an assembly operation as demonstrated below.

variable

Allocates a slot in the operation. The scope of the the variable is defined by the brackets. It also calls a store instruction at its place (the result is an immediate initialization of the variable with the value on the top of the stack (popped).

Definition:

variable <identifier> name <variable name> {
<Produced code definition for which the variable is defined>
}

The variable instruction is defined on a model element but also needs a name. The combination of these two allows ACG to maintain variables across severall rules. Several variables with the same name can coexists in the same code scope.

The variable definition (line 1) allows the load call (line 3). Remember that a variable declaration also immediately stores a value, so we have to be sure a value is available on the stack before we can declare a variable. For a case where the value can't be known prior to declarationm one can use OclUndefined

field

As normal variables are local to operations, we also need a way to specify global variables. This can be done with the field keyword. They can be specified in the ASM context or within rules, so they can be generated from the input model.

Definition:

field <field name> : <field type>

Example:

field 'links' : 'NTransientLinkSet;'

This generates a global variable of type NTransientLinkSet. Later more on this type.

Since fields reside in the global asm context, they are referenced as a property of this context. The following example illustrates this.

Example:

getasm
get 'links'

This code will pop the content of links a NTransientLinkSet on the stack.

VM Instructions

There exists one statement per ATL VM instruction. Each of these statements have the same name than the instruction and, of course, leads to the production of this instruction in the target model.

An instruction is followed by its operand as defined in the VM specification. For some arguments defined in ACG, the compiler performs a rewriting (or more exactly an interpretation -read transformation) given that that ASM code is not convenient to write by hand and that ACG could help by making things more "human compliant".
It is the case for :

the load instruction: Its argument is a variable reference. In ACG, this reference is:

the identifier of a common variable

the name of a parameter.

→ It is rewritten in corresponding slot number.

the if instruction: Its argument is a referrence to a label.

→ It is replaced by the offset from the location of the label after code generation.

the goto instruction

→ See if

Things to Keep in Mind

When writing ACG code, we specify compile-time calculation to generate runtime code. We have to keep in mind that the only interface between compile-time and runtime is the generated assembly file. At runtime we can't access the language model, so any complex model structure we want to referrence, has to be specified in the generated assembly explicitly.
We can circumvent this problem to a certain extend by making use of some higher level model queries provided by EMF, shown in the following section.

Usefull Functionality

Transient Links

Writing model transformations, we often have to keep track of the tracibility links created between source and target models. Model transformation languages like ATL and QVT keep track of these links behind the screens, they can then either be explicitly referenced in the language (as is the case in QVT Operational Mappings) or they can be used by the language to automaticly transform links between model elements (as is done in ATL and QVT relational).
Either means that, implementing these languages, we need to keep track of the links. The ATLVM therefore provides the TransientLink object. It can be referenced in ACG.

In this example a TransientLink is created, given a reference to the executing rule and some source model elements are added. We can also add target elements and variables and later store the link in a TransientLinkSet. More on this can be found in ATL VM specification

NOTE: Maintaining trace information can also be done by specifying another input model to store these informations.

EMF Model Query Functions

As noted before we cannot access the language model at runtime, making it dificult to implement lookaheads and things like that. EMF however provides facilities to reference the model via queries on the metametamodel. Here some examples that might be useful for your compiler design. These functionscan be called runtime and compile-time on any model element.

Example:

self.refImmediateComposite()

Will get all the parent of the model element.

Example:

self.eContents()

Will get a Set of all the children (referrences) of the model element.

Example:

self.eClass()

Will get implicit type of the model element as resolved by the metamodel.

Others

ACG also does not allow us to define (static) global compile-time variables. We can emulate these by adding an attribute to the Object model elements, the super type of all model elements. The following example uses this to be able to switch from a debug to normal compiler.

Example:

attribute Object::__debug = true; --either true or false

The debug variable can now easily be accessed in any context.

Use

Once the ACG file is defined for the transformation language model, it has to be compiled so that every transformation written is this language could be compiled into ASM.

This is done thanks to an AMMA tool set including several Ant scripts. Those scripts are intended to provide all the facilities to build a Domain Specific Language (editor, megamodel, concrete and abstract syntax and a compiler if the semantics relies on the ATL VM).