====== LARA Fundamentals ======
==== Aspects ====
Aspectdef definition
aspectdef MyFirstAspect // The main aspect is the first declared in the file
// aspect code
end
aspectdef ASecondAspect // An aspect that can be called in the main aspect
// aspect code
end
==== Select ====
Select with full join point chain:
select program.file.function.body.loop end
Select with only last join point. The chain is induced, produces the same result as above:
select loop end
Assign the selected join points to a variable for later use:
LOOPS: select loop end
Assign an alias for specific join points:
select ($p=loop).($c=loop) end
==== Apply ====
Apply after a select:
select loop end
apply
println($loop.rank);
end
Apply on a previously selected set of join points:
apply to LOOPS
println($loop.rank);
end
It is possible to perform a natural join on two sets of join points:
LOOP_START: select function.body.loop.($loop_start = first) end
FUNCTION_FIRST: select function.body.first end
apply to LOOP_START::FUNCTION_FIRST
// Init counters at the beginning of the function
$first.insert before%{counter_[[$loop.uid]] = 0;}%;
// Increment counters when entering the loop
$loop_start.insert before%{counter_[[$loop.uid]] = counter_[[$loop.uid]] +1;}%;
// ...
end
Use of join points with aliases inside the apply statement:
select ($p=loop).($c=loop) end
apply
$p.exec Interchange($c);
end
==== Conditions ====
Using a condition block:
select function end
apply
// ...
end
condition
$function.name == 'kernel'
end
Combining conditions using && (and) and || (or) operators:
select loop end
apply
$loop.exec Unroll(2);
end
condition
$loop.is_innermost &&
$loop.type=="for"
end
Using "filter" conditions on the join point chain:
select function{name=='kernel'} end
apply
// ...
end
// OR
select function{'kernel'} end // uses the default attribute of the join point
apply
// ...
end
==== Aspect Inputs and Outputs ====
Input parameter definition:
input
funcs,
opt
end
Input parameter definition with default values:
input
funcs = ['kernel'],
opt = ['unroll', 'interchange', 'tile']
end
Output definition. Output cannot be initialized inside the **output** block:
output
optFuncs,
code
end
optFuncs = [];
code = '';
==== Calling Aspects ====
Simple aspect call:
call OptimizeProgram();
Calling an aspect with arguments:
call OptimizeFunctions(functions, optimizations);
Calling an aspect with named arguments:
call OptimizeFunctions(opt: optimizations, funcs: ['gridIterate']);
Calling an aspect and retrieving the outputs:
// Current syntax
var optimizer = call OptimizeFunctions(functions, optimizations);
// Previous syntax
call optimizer : OptimizeFunctions(functions, optimizations);
var changedFuncs = optimizer.optFuncs;
var finalCode = optimizer.code;
Assigning an aspect call to a variable for later use. Can still use input arguments and outputs as shown before:
var optimizer = new OptimizeFunctions(functions, optimizations);
call optimizer(); // or optimizer.call()
var changedFuncs = optimizer.optFuncs;
var finalCode = optimizer.code;
Aspects can also be called inside Javascript files (.js). You need to build the aspect object and reference the complete path, separated by dollar signs ($):
// Calling aspect MeasureEnergy from inside a .js file
(new lara$profiling$Energy$EnergyTest()).call();
==== Using LARA Actions ====
Actions are used inside apply statements. There are two default actions, **insert** and **def**. Then, it is possible to use weaver-specific actions, which are called with the **exec** keyword:
select function{'kernel'} end
apply
insert before '/* Creating a clone. */'; // add a comment before the function
def name = 'original_kernel'; // redefine the name of the kernel function
exec clone('cloned_kernel'); // use a MANET-specific action to create a 'kernel' clone named 'cloned_kernel'
end
When calling an action we can specify any join point in the chain to be the action target:
select function.loop end
apply
$loop.exec tile(8);
$function.insert before '/* This function was transformed. */';
end
It is possible to omit the target, the last join point in the chain is used:
select function.loop end
apply
exec unroll(2); // performed on the same loop as below
$loop.exec tile(8); // performed on the same loop as above
end
If the action returns a result, we can use the following syntax:
var result = $jp.exec ;
If 'result' is a variable that already exists, 'var' can be omitted:
result = $jp.exec ;
The keyword '.exec' can be omitted if you prefix the name of the action with the target join point, and add parenthesis:
result = $jp.();
==== Calling shell commands ====
You can invoke shell commands from LARA using the function cmd. The first argument is the command, and the second an array with the arguments for the command:
cmd("ls", ["-l", "-v"]);
==== Using LARA from the Command Line ====
=== Include Folder ===
To add include folders, use the flag -i. To add more than one folder, use double quotes and separate the folders with the file separator character of your current system
larai -i "libs1;libs2"
=== Passing Arguments to the Aspect ===
To pass arguments to the top-level aspect use the flag -av. The input is a JSON representation of the input:
larai -av "{inputFile:'data.json',execute:true,iterations:10}"
==== Codedef Sections ====
To insert sections of code that span several lines, you can define codedef sections, which act as templates. Example:
codedef CodeTemplate(param1, param2) %{
// This code is inserted as-is, without escaping
// To apply the values of parameters, use [[]]
var [[param1]] = [[param2]];
}% end
Declared codedefs can then be used in the code as functions:
code = CodeTemplate("varName", 2);
====== Miscellaneous ======
==== Regular Expressions ====
Lara supports JavaScript regular expressions, for instance:
var regex = /(return\s+)(10)(\s*;)/;
regex.test("return 10;"); // Returns 'true'
Since **exec** is a LARA keyword, calling **regex.exec** is not permitted. However, you can access object properties using strings to circumvent this limitation:
(regex['exec']("return 10;"))[2]; // Returns '10'
Alternatively, you can also use the **match** function in strings:
String('aaaa').match(new RegExp('a*')) // Returns 'aaaa'
Or you can also use the **match** boolean operator ( **~=** ):
'aaaa' ~= /a*/ // Returns true
==== Importing LARA Files ====
LARA supports importing LARA files that are present in the include path using the keyword **import**. To import a file, you have to use the path to the file from the include folder, using *.* as separator and omitting the extension of the file. For instance, if you add as include the folder *~/foo* and you want to import the file *~/foo/bar/Aspect.lara*, you can write the following code:
import bar.Aspect;
Import statements must be the first statements in a LARA file. LARA weavers come bundled with support for a set of imports, which are part of their API (e.g., [[http://specs.fe.up.pt/tools/clava/doc/|Clava API]]).
==== Reading/Writing JSON Files ====
LARA supports reading from and writing to JSON objects with the object **Io**:
import lara.Io;
...
Io.writeJson("file.json", anObject);
var loadedObject = Io.readJson("file.json");