This shows you the differences between two versions of the page.
lara:docs:sheet [2018/10/23 12:48] tdrc [Regular Expressions] |
lara:docs:sheet [2019/09/22 15:47] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== LARA Fundamentals ====== | ||
- | |||
- | ==== Aspects ==== | ||
- | Aspectdef definition | ||
- | |||
- | <code lara> | ||
- | 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 | ||
- | </code> | ||
- | |||
- | |||
- | ==== Select ==== | ||
- | |||
- | Select with full join point chain: | ||
- | |||
- | <code lara> | ||
- | select program.file.function.body.loop end | ||
- | </code> | ||
- | |||
- | Select with only last join point. The chain is induced, produces the same result as above: | ||
- | |||
- | <code lara> | ||
- | select loop end | ||
- | </code> | ||
- | |||
- | Assign the selected join points to a variable for later use: | ||
- | |||
- | <code lara> | ||
- | LOOPS: select loop end | ||
- | </code> | ||
- | |||
- | Assign an alias for specific join points: | ||
- | |||
- | <code lara> | ||
- | select ($p=loop).($c=loop) end | ||
- | </code> | ||
- | ==== Apply ==== | ||
- | |||
- | Apply after a select: | ||
- | |||
- | <code lara> | ||
- | select loop end | ||
- | apply | ||
- | println($loop.rank); | ||
- | end | ||
- | </code> | ||
- | |||
- | Apply on a previously selected set of join points: | ||
- | |||
- | <code lara> | ||
- | apply to LOOPS | ||
- | println($loop.rank); | ||
- | end | ||
- | </code> | ||
- | |||
- | It is possible to perform a natural join on two sets of join points: | ||
- | |||
- | <code lara> | ||
- | 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 | ||
- | </code> | ||
- | |||
- | Use of join points with aliases inside the apply statement: | ||
- | |||
- | <code lara> | ||
- | select ($p=loop).($c=loop) end | ||
- | apply | ||
- | $p.exec Interchange($c); | ||
- | end | ||
- | </code> | ||
- | |||
- | ==== Conditions ==== | ||
- | |||
- | Using a condition block: | ||
- | |||
- | <code lara> | ||
- | select function end | ||
- | apply | ||
- | // ... | ||
- | end | ||
- | condition | ||
- | $function.name == 'kernel' | ||
- | end | ||
- | </code> | ||
- | |||
- | Combining conditions using && (and) and || (or) operators: | ||
- | |||
- | <code lara> | ||
- | select loop end | ||
- | apply | ||
- | $loop.exec Unroll(2); | ||
- | end | ||
- | condition | ||
- | $loop.is_innermost && | ||
- | $loop.type=="for" | ||
- | end | ||
- | </code> | ||
- | |||
- | Using "filter" conditions on the join point chain: | ||
- | |||
- | <code lara> | ||
- | select function{name=='kernel'} end | ||
- | apply | ||
- | // ... | ||
- | end | ||
- | |||
- | // OR | ||
- | select function{'kernel'} end // uses the default attribute of the join point | ||
- | apply | ||
- | // ... | ||
- | end | ||
- | </code> | ||
- | |||
- | ==== Aspect Inputs and Outputs ==== | ||
- | |||
- | Input parameter definition: | ||
- | |||
- | <code lara> | ||
- | input | ||
- | funcs, | ||
- | opt | ||
- | end | ||
- | </code> | ||
- | |||
- | Input parameter definition with default values: | ||
- | |||
- | <code lara> | ||
- | input | ||
- | funcs = ['kernel'], | ||
- | opt = ['unroll', 'interchange', 'tile'] | ||
- | end | ||
- | </code> | ||
- | |||
- | Output definition. Output cannot be initialized inside the **output** block: | ||
- | |||
- | <code lara> | ||
- | output | ||
- | optFuncs, | ||
- | code | ||
- | end | ||
- | |||
- | optFuncs = []; | ||
- | code = ''; | ||
- | </code> | ||
- | |||
- | ==== Calling Aspects ==== | ||
- | |||
- | Simple aspect call: | ||
- | |||
- | <code lara> | ||
- | call OptimizeProgram(); | ||
- | </code> | ||
- | |||
- | Calling an aspect with arguments: | ||
- | |||
- | <code lara> | ||
- | call OptimizeFunctions(functions, optimizations); | ||
- | </code> | ||
- | |||
- | Calling an aspect with named arguments: | ||
- | |||
- | <code lara> | ||
- | call OptimizeFunctions(opt: optimizations, funcs: ['gridIterate']); | ||
- | </code> | ||
- | |||
- | |||
- | Calling an aspect and retrieving the outputs: | ||
- | |||
- | <code lara> | ||
- | // Current syntax | ||
- | var optimizer = call OptimizeFunctions(functions, optimizations); | ||
- | |||
- | // Previous syntax | ||
- | call optimizer : OptimizeFunctions(functions, optimizations); | ||
- | |||
- | var changedFuncs = optimizer.optFuncs; | ||
- | var finalCode = optimizer.code; | ||
- | </code> | ||
- | |||
- | Assigning an aspect call to a variable for later use. Can still use input arguments and outputs as shown before: | ||
- | |||
- | <code lara> | ||
- | var optimizer = new OptimizeFunctions(functions, optimizations); | ||
- | |||
- | call optimizer(); // or optimizer.call() | ||
- | |||
- | var changedFuncs = optimizer.optFuncs; | ||
- | var finalCode = optimizer.code; | ||
- | </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 ($): | ||
- | |||
- | <code lara> | ||
- | // Calling aspect MeasureEnergy from inside a .js file | ||
- | |||
- | (new lara$profiling$Energy$EnergyTest()).call(); | ||
- | </code> | ||
- | ==== 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: | ||
- | |||
- | <code lara> | ||
- | 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 | ||
- | </code> | ||
- | |||
- | When calling an action we can specify any join point in the chain to be the action target: | ||
- | |||
- | <code lara> | ||
- | select function.loop end | ||
- | apply | ||
- | $loop.exec tile(8); | ||
- | $function.insert before '/* This function was transformed. */'; | ||
- | end | ||
- | </code> | ||
- | |||
- | It is possible to omit the target, the last join point in the chain is used: | ||
- | |||
- | <code lara> | ||
- | 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 | ||
- | </code> | ||
- | |||
- | |||
- | If the action returns a result, we can use the following syntax: | ||
- | |||
- | <code lara> | ||
- | var result = $jp.exec <action_name>; | ||
- | </code> | ||
- | |||
- | If 'result' is a variable that already exists, 'var' can be omitted: | ||
- | |||
- | <code lara> | ||
- | result = $jp.exec <action_name>; | ||
- | </code> | ||
- | |||
- | The keyword '.exec' can be omitted if you prefix the name of the action with the target join point, and add parenthesis: | ||
- | |||
- | <code lara> | ||
- | result = $jp.<action_name>(); | ||
- | </code> | ||
- | |||
- | ==== 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: | ||
- | |||
- | <code lara> | ||
- | |||
- | cmd("ls", ["-l", "-v"]); | ||
- | |||
- | </code> | ||
- | |||
- | |||
- | ==== 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 | ||
- | |||
- | <code> | ||
- | |||
- | larai -i "libs1;libs2" | ||
- | |||
- | </code> | ||
- | |||
- | === 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: | ||
- | |||
- | <code> | ||
- | |||
- | larai -av "{inputFile:'data.json',execute:true,iterations:10}" | ||
- | |||
- | </code> | ||
- | |||
- | |||
- | ==== Codedef Sections ==== | ||
- | |||
- | To insert sections of code that span several lines, you can define codedef sections, which act as templates. Example: | ||
- | |||
- | <code lara> | ||
- | |||
- | codedef CodeTemplate(param1, param2) %{ | ||
- | // This code is inserted as-is, without escaping | ||
- | |||
- | // To apply the values of parameters, use [[]] | ||
- | var [[param1]] = [[param2]]; | ||
- | |||
- | }% end | ||
- | |||
- | </code> | ||
- | |||
- | Declared codedefs can then be used in the code as functions: | ||
- | |||
- | <code lara> | ||
- | |||
- | code = CodeTemplate("varName", 2); | ||
- | |||
- | </code> | ||
- | |||
- | ====== Miscellaneous ====== | ||
- | |||
- | ==== Regular Expressions ==== | ||
- | |||
- | Lara supports JavaScript regular expressions, for instance: | ||
- | |||
- | <code lara> | ||
- | |||
- | var regex = /(return\s+)(10)(\s*;)/; | ||
- | regex.test("return 10;"); // Returns 'true' | ||
- | |||
- | </code> | ||
- | |||
- | Since **exec** is a LARA keyword, calling **regex.exec** is not permitted. However, you can access object properties using strings to circumvent this limitation: | ||
- | |||
- | <code lara> | ||
- | |||
- | (regex['exec']("return 10;"))[2]; // Returns '10' | ||
- | |||
- | </code> | ||
- | |||
- | Alternatively, you can also use the **match** function in strings: | ||
- | |||
- | <code lara> | ||
- | |||
- | String('aaaa').match(new RegExp('a*')) // Returns 'aaaa' | ||
- | |||
- | </code> | ||
- | |||
- | Or you can also use the **match** boolean operator ( **~=** ): | ||
- | |||
- | <code lara> | ||
- | |||
- | 'aaaa' ~= 'a*' // Returns true | ||
- | |||
- | </code> | ||
- | |||
- | ==== 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: | ||
- | |||
- | <code lara> | ||
- | |||
- | import bar.Aspect; | ||
- | |||
- | </code> | ||
- | |||
- | 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**: | ||
- | |||
- | <code lara> | ||
- | |||
- | import lara.Io; | ||
- | |||
- | ... | ||
- | |||
- | Io.writeJson("file.json", anObject); | ||
- | var loadedObject = Io.readJson("file.json"); | ||
- | |||
- | </code> | ||
- | |||
- | |||