====== 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");