====== Writing a Target Language Specification ====== ;#; [[lara:tutorial:advanced| ← Advanced LARA ]] | [[lara:tutorial:languagespecification| Language Specification ]] | [[lara:tutorial:larai|Basic larai → ]] ;#; The most critical element of an aspect-oriented language mechanism is the join point model, the model that represents the programming language’s points of interest, like method execution, field gets, etc. The join point model can be different from programming language to programming language, and also depends on the capability of the weaver to support all the join points inside the chain. Having so, the join point model cannot be the same for all the concerning programming languages and each one should have its join point model that illustrates those supported points of interest. One of the aspects of the LARA language is that it is partially agnostic to the target language. How LARA knows the join point model, the available attributes, and action that can be applied, is by using an external representation of the target language. This is accomplished by defining three files that represents the join point model and the attributes of a certain programming language, and the actions available in the weaver that will execute the LARA aspects. This approach proves an important feature of LARA that represents its flexibility and expandability. The three files are defined in an XML format, each with specific tags and attributes. ===== Join Point Model ===== The join point model represents a hierarchical structure of the points of interest one can select on the target application. ... For this tutorial we are using the join point model structure depicted in the graph below. This graph defines app as the **root** of the join point model hierarchy, and the arrows depict a selectable join point from the source join point. For instance, **app** → **file** means that we can select **files** inside the **app** join point. Some important remarks of this example: - The gray arrow between **assignExpr** → **expr** means that **assignExpr** inherits everything that **expr** contains, including selectable join points, attributes and actions; - The arrows between **body** ↔ **loop** defines that **body** is able to select the loops inside itself and, in turn, **loop** is able to select its own body; - The two arrows connecting **body** → **stmt** means that in the first connection (without label) we are able to select all statements inside the body and in the second connection (with label **first_stmt**) we are going to select one type of statement (the first statement of the body). This is an example of having different selects for the same type of join point. digraph finite_state_machine { graph [ dpi = 300 ]; node [shape = square, style=rounded, penwidth=2, bgcolor=white]; app; node [shape = square, style=rounded, penwidth=1, color=black]; app -> file; file -> function; function -> body; body -> var; body -> loop; loop -> body; body -> assignExpr; body -> stmt; body -> stmt [label="first_stmt"]; assignExpr -> expr [label="extends" style=dashed, penwidth=0.5, color="#888888", fontcolor="#888888",fontsize=10px]; } ==== The Join Point List Declaration ==== The join point model is specified in an xml format that starts with a **** element that gather all the available join points. Inside this element we specify all the join points available in the target language. Each join point is specified inside a **** element, where the attributes **class** (mandatory) and **extends** (optional) are available. The **class** attribute defines the class of the join point we are dealing with. For instance, when the join point specifies the class as **function**, it means that we are defining function as a selectable point in the program. The **extends** attribute defines that the join point extends all the information and functionality that another join point can have. In the following example we are defining the join points specified in the previous graph: **file**, **function**, **body**,etc. Note that the **assignExpr** is extending the **expr** join point, this means that all selectable join points, attributes and actions available in the extended join point will be available in the extending join point. Now that we have the join points listed, we have to define which one is the **root**, i.e., the top on the hierarchy structure. In the graph above we consider **app** as root. For this, we use the **root_class** and **root_alias** attributes, in the **joinpoints** element, to specify which join point is the root and the alias that we will use inside the LARA language. Since we have named our join point as **application** and the graph uses **app**, we are going to use the last as the alias for the root and the first as the join point class to use, as defined below. ==== Defining the Hierarchy ==== The previous example shows the complete list of join points available in and which one is identified as the joint point root. Since we don't have any associations between the join points, the hierarchy is still missing. The join point hierarchy, i.e. which //descendent// join points can a specific join point select. This may be accomplished by using a list of ** ===== Attributes Model ===== Once the join point model is defined, we have to describe the information one can retrieve from a join point, in other words, the attributes associated to the join point class. The attributes are defined in a xml formatted file separated from the join point model. For this part of the tutorial we assume the following (example) information can be retrieved from the join point model defined in . Note that the global attributes are information that can be retrieved from ANY declared join point. ^ Join Point ^ Attribute ^ Type ^ Description ^ | Global Attributes | uid | int | the unique identifier of the join point | | ::: | src_code | string | source code representation for the join point | | application | name | string | the name of the application | | ::: | folder | string | the directory of the target source code | | ::: | num_src_files | int | the number of source files | | file | name | string | the name of the file | | ::: | path | string | the path to the file | | function | name | string | the name of the function | | ::: | return_type | TypeDef | the return type | | body | num_lines | int | number of lines of the body | | ::: | num_reads | int | number of reads to a specific variable in this body | | ::: | num_writes | int | number of writes to a specific variable in this body | | var | name | string | the name of the variable | | ::: | type | TypeDef | the type of the variable | | ::: | reference | 'read', 'write' or 'decl' | the type of reference to the variable | | loop | type | 'for', 'while' or 'do-while' | the type of the loop | | ::: | rank | string | the rank of the loop inside its function | | ::: | nested_level | int | the nesting level of the loop | | expr | type | 'assign', 'binary', 'unary', 'access', 'call', 'id' or 'literal' | the type of this expression | | ::: | num_oper | int | number of operations in the expression | | ::: | num_calls | int | number of function calls in the expression | | ::: | num_array_refs | int | number of array references in the expression | | assingExpr | operator | string | the operator used in the assignment | | stmt | line | int | the line number of the statement | The list of attributes that a join point contains is defined as **artifact**. To start defining the list of **artifacts** we use the **** element, as defined below. This element does not contain any particular attribute to be defined. Now each list of attributes, for each join point class, is defined in an **** element, in which the attribute **class** defines the join point associated to the attributes. This element also considers an optional attribute named **default**, which defines the default attribute used as filter in a //select// statement (please see [[lara:tutorial:basics#select| LARA Basic 101]] tutorial for further details). ... ... ... ... ... Having the artifacts defined for each joint point class type, now we can list each attribute with the element **** that has two mandatory parameters: the name of the attribute and its type. The type of an attribute may be defined in different forms: - **primitive** - use one of the primitive types (similar to Java™): short, int, float, double, boolean, string, Object; - **join point** - a join point class defined in the Join Point Model; - **enumeration** - a list of the possible values the attribute may have (defined between'{' and '}', and each value separated by a ',' (comma)); - **defined object** - use an //"object type"// that is defined in the **** element. Depending on the interpreter used, if the type used does not fit in one of these possibilities, the interpreter will warn the user, or possibly suspend the execution. The following code contains some of the attributes associated to each join point class. Note the use of an enumeration in the **reference** attribute of the join point **var**. ... ... As you can see we are using a **TypeDef** as type for the **return_type** attribute in join point **function**. Since this type is not a primitive, or a join point definition, we have to declare this new type as an object definition with the **** element. The **object** contains a parameter defining its name and a list of attributes that this object may contain. ... ... Now if we look at the description of the attributes **num_reads** and **num_writes** in the join point **body**, it says that returns the number of reads/writes of a specific variable, which then should be given as an input to allow the calculation. For this end, an attribute may have a list of **** defining which inputs are necessary to get that attribute. In these examples, we are going to need one parameter: the string with the name of the variable. ... ... Now the only part missing is the attributes that are common for all classes of join points. This is accomplished by defining an artifact without the class specified, or by defining the class as "*", i.e. ANY class. ... This last version of the attributes model contains all the attributes defined in the table above. Note that since we defined in the join point model that **assignExpr** extends the **expr** class, all the attributes from **expr** is also available in **assignExpr**. ===== Action Model ===== The Actions Model defines the actions that can be applied over the application. By default, LARA has already the **insert** and **def** actions predefined. All other actions the weaver is able to perform is defined in this action model. The following table considers some actions that current existing weavers can perform. ^ Action ^ Parameters ^^^ Target Join Point ^ Description ^ | ::: ^ Name ^Type ^ Default | ::: | ::: | | report | - | - | - | any | create a report of a join point by using its attributes | | dna | - | - | - | function, loop | extract a program DNA representation from the join point | | map | to | string | - | function | map computations to the given (embedded) target system | | ::: | id | string | "0" | ::: | ::: | | ::: | mode | string | "default" | ::: | ::: | | unroll | factor | int | 0 | loop | unroll a loop with a given factor | | interchange | loop2 | loop | - | loop | interchange the current loop with another, nested, loop | The action model is defined in its own xml formatted file. The list of actions is defined inside an **** element, with no attributes specified for this element. ... Each action is then defined in an **** element with two attributes: the **name** of the action (mandatory) and the target **class** (optional). The target class specifies the join point classes that can perform that action. Many classes may be used in the **class** attribute, separated with a ',' (comma). When the **class** attribute is not defined (or defined as "*"), then it is considered that the action can be performed in any join point class. The **report** and **dna** actions are ready to be used, since they do not require parameters. For the rest of the actions, a list of parameters is required. The parameters are defined each in a **** element, inside the **** element, with three attributes: the name and type (both mandatory), and the default value (optional) to be used if the parameter is not assigned in an action call, in a LARA aspect. The following code shows the complete action model for the actions defined in the table above. ;#; [[lara:tutorial:advanced| ← Advanced LARA ]] | [[lara:tutorial:languagespecification| Language Specification ]] | [[lara:tutorial:larai|Basic larai → ]] ;#;