|
| 1 | +--- |
| 2 | +sidebar_position: 3 |
| 3 | +--- |
| 4 | + |
| 5 | +# LASSO Scripting Language (LSL) — Beginner’s Guide & Specification |
| 6 | + |
| 7 | +(Note: Find the full specification of LSL [here](../datastructures/lsl.md).) |
| 8 | + |
| 9 | +The LASSO Scripting Language (LSL) lets you design code search, generation, testing, and evaluation pipelines in an easy and readable way. It is Groovy-based and made for workflows that involve functional abstractions (coding problems in terms of required interfaces), finding or generating implementations, and running tests. |
| 10 | + |
| 11 | +--- |
| 12 | + |
| 13 | +Table of Contents |
| 14 | + |
| 15 | +1. How Does an LSL Script Look? (Quick Example) |
| 16 | +2. Main Building Blocks |
| 17 | + - a. dataSource |
| 18 | + - b. study |
| 19 | + - c. profile |
| 20 | + - d. action |
| 21 | + - e. stimulusMatrix, implementation, test, row |
| 22 | + - f. dependsOn / include |
| 23 | + - g. features and other options |
| 24 | + - h. Groovy code & variables |
| 25 | +3. Putting It Together: Step-by-Step Example |
| 26 | +4. Key Patterns, FAQs, Tips |
| 27 | +5. Where to Find More |
| 28 | + |
| 29 | +--- |
| 30 | + |
| 31 | +## 1. How Does an LSL Script Look? (Quick Example) |
| 32 | + |
| 33 | +Let’s see a super-short LSL workflow: |
| 34 | + |
| 35 | +```groovy |
| 36 | +dataSource 'lasso_quickstart' // Where to get classes, tests etc. |
| 37 | +
|
| 38 | +study(name: 'HelloWorld') { |
| 39 | + // Where/code will run |
| 40 | + profile('java17') { |
| 41 | + environment('java17') { |
| 42 | + image = 'maven:3.9-eclipse-temurin-17' |
| 43 | + } |
| 44 | + } |
| 45 | + // Make a new task: Create a "Stack" abstractiion and test code candidates |
| 46 | + action(name: 'create') { |
| 47 | + execute { |
| 48 | + stimulusMatrix('Stack', """ |
| 49 | + Stack { |
| 50 | + push(java.lang.String)->java.lang.String |
| 51 | + size()->int |
| 52 | + } |
| 53 | + """, |
| 54 | + [ |
| 55 | + implementation("1", "java.util.Stack") // Use JDK built-in Java Stack |
| 56 | + ], [ |
| 57 | + test(name: 'testPush()') { |
| 58 | + row '', 'create', 'Stack' |
| 59 | + row '', 'push', 'A1', '"Hello World!"' |
| 60 | + row '', 'size', 'A1' |
| 61 | + } |
| 62 | + ]) |
| 63 | + } |
| 64 | +} |
| 65 | + // Run/test the Stack via Arena Test Driver |
| 66 | + action(name: 'filter', type: 'Arena') { |
| 67 | + dependsOn 'create' |
| 68 | + include 'Stack' |
| 69 | + profile('java17') |
| 70 | + } |
| 71 | +} |
| 72 | +``` |
| 73 | + |
| 74 | + |
| 75 | +--- |
| 76 | + |
| 77 | +## 2. Main Building Blocks |
| 78 | + |
| 79 | +a. `dataSource` |
| 80 | + |
| 81 | +What: Where the platform should look for code, classes, or data. |
| 82 | + |
| 83 | +Usage: |
| 84 | + |
| 85 | +```groovy |
| 86 | +dataSource 'lasso_quickstart' |
| 87 | +dataSource "mavenCentral2023" |
| 88 | +``` |
| 89 | + |
| 90 | +Tip: You can have different studies using different data sources. |
| 91 | + |
| 92 | +--- |
| 93 | + |
| 94 | +b. `study` |
| 95 | + |
| 96 | +What: Groups together a series of actions (your workflow). |
| 97 | + |
| 98 | +Usage: |
| 99 | + |
| 100 | +```groovy |
| 101 | +study(name: 'MyAwesomeExperiment') { |
| 102 | +// actions, profiles, variables... |
| 103 | +} |
| 104 | +``` |
| 105 | + |
| 106 | +--- |
| 107 | + |
| 108 | +c. `profile` |
| 109 | + |
| 110 | +What: Defines how and where actions are run (Java version, Docker image, toolchains etc). |
| 111 | + |
| 112 | +Usage: |
| 113 | + |
| 114 | +```groovy |
| 115 | +profile('java17') { |
| 116 | + environment('java17') { |
| 117 | + image = 'maven:3.9-eclipse-temurin-17' |
| 118 | + } |
| 119 | +} |
| 120 | +``` |
| 121 | + |
| 122 | +Tip: You can define several profiles (e.g., for Java 11 and Java 17) and switch between them. |
| 123 | + |
| 124 | +--- |
| 125 | + |
| 126 | +d. `action` |
| 127 | + |
| 128 | +What: A step in your pipeline; can create, search, filter, test, generate, etc. |
| 129 | + |
| 130 | +Usage: |
| 131 | + |
| 132 | +```groovy |
| 133 | +action(name: 'create') { |
| 134 | + execute { |
| 135 | + // define abstraction (Stimulus Matrix), etc. |
| 136 | + } |
| 137 | +} |
| 138 | +action(name: 'filter', type: 'Arena') { |
| 139 | + dependsOn 'create' |
| 140 | + include '*' |
| 141 | + // config here |
| 142 | +} |
| 143 | +``` |
| 144 | + |
| 145 | +`type` defines what kind of action it is: 'Arena', 'Search', 'EvoSuite', etc. |
| 146 | + |
| 147 | +--- |
| 148 | + |
| 149 | +e. `stimulusMatrix`, `implementation`, `test`, `row` |
| 150 | + |
| 151 | +These are the heart of LSL for defining what you want to study and test! |
| 152 | + |
| 153 | +`stimulusMatrix` |
| 154 | + |
| 155 | +- Lets you define: |
| 156 | + 1. The interface: (what methods/behavior you expect) |
| 157 | + 2. Some sample implementations: (what code/classes to run) |
| 158 | + 3. Tests: (how to check if it works) |
| 159 | + |
| 160 | +Example: |
| 161 | + |
| 162 | +```groovy |
| 163 | +stimulusMatrix('Base64', """ |
| 164 | + Base64 { |
| 165 | + encode(byte[])->byte[] |
| 166 | + decode(java.lang.String)->byte[] |
| 167 | + } |
| 168 | + """, |
| 169 | + [ |
| 170 | + implementation("1", "org.apache.commons.codec.binary.Base64", "commons-codec:commons-codec:1.15") |
| 171 | + ], [ |
| 172 | + test(name: 'testEncode()') { |
| 173 | + row '', 'create', 'Base64' |
| 174 | + row '"SGVsbG8gV29ybGQ=".getBytes()', 'encode', 'A1', '"Hello World".getBytes()' |
| 175 | + } |
| 176 | +]) |
| 177 | +``` |
| 178 | + |
| 179 | +- First value: The matrix name (unique in this study) |
| 180 | +- Second value: The interface (in [LQL format](../datastructures/lql.md)) |
| 181 | +- Third: List of implementations you want to try |
| 182 | +- Fourth: List of tests to verify them |
| 183 | + |
| 184 | +`implementation` |
| 185 | + |
| 186 | +- Specifies a class to try, optionally pointing to a Maven dependency (by coordinate). |
| 187 | + |
| 188 | +```groovy |
| 189 | +implementation("1", "org.apache.commons.codec.binary.Base64", "commons-codec:commons-codec:1.15") |
| 190 | +``` |
| 191 | + |
| 192 | +`test` and `row` |
| 193 | + |
| 194 | +- A test (Stimulus Sheet) defines a scenario. |
| 195 | +- Each row is an operation (method) invocation (e.g., expected output, operation, target object reference, input parameter args). |
| 196 | + |
| 197 | +```groovy |
| 198 | +test(name: 'testPush()') { |
| 199 | + // expected output, operation, target object reference, input parameters |
| 200 | + row '', 'create', 'Stack' // special virtual operation to create an instance |
| 201 | + row '', 'push', 'A1', '"Hello World!"' |
| 202 | + row '', 'size', 'A1' |
| 203 | +} |
| 204 | +``` |
| 205 | + |
| 206 | +- `'A1'` refers to the result of the first row (`create 'Stack'`). |
| 207 | +- Parameters can be used for data-driven or parameterized tests: |
| 208 | + ```groovy |
| 209 | + test(name: 'testEncode(p1=byte[], p2=byte[])', p1:'"Hello".getBytes()', p2:'"SGVsbG8=".getBytes()') |
| 210 | + ``` |
| 211 | +
|
| 212 | +`testFromJUnit` |
| 213 | +You can also provide a full JUnit test case as a string! |
| 214 | +
|
| 215 | +```groovy |
| 216 | +testFromJUnit(""" |
| 217 | +import org.junit.jupiter.api.Test; |
| 218 | +public class MyTest { @Test void test() { /* ... */ } } |
| 219 | +""") |
| 220 | +``` |
| 221 | + |
| 222 | +--- |
| 223 | + |
| 224 | +f. `dependsOn` / `include` |
| 225 | + |
| 226 | +- `dependsOn 'ActionName'` means this action runs after the named action and can use its outputs. |
| 227 | +- `include 'ThingName'` or `include '*'` means apply this action to a certain abstraction (or to all). |
| 228 | + |
| 229 | +Example: |
| 230 | + |
| 231 | +```groovy |
| 232 | +action(name: 'filter', type: 'Arena') { |
| 233 | + dependsOn 'create' |
| 234 | + include 'Stack' |
| 235 | +} |
| 236 | +``` |
| 237 | + |
| 238 | +--- |
| 239 | + |
| 240 | +g. `features` and Other Options |
| 241 | + |
| 242 | +Some actions accept extra options, like: |
| 243 | + |
| 244 | +```groovy |
| 245 | +features = ['cc', 'mutation'] // code coverage, mutation analysis |
| 246 | +maxAdaptations = 2 // try at most 2 adaptation strategies |
| 247 | +adapterStrategy = 'PassThroughAdaptationStrategy' |
| 248 | +``` |
| 249 | + |
| 250 | +Other blocks: |
| 251 | +- `prompt { ... }` and `query { ... }` are for more advanced cases (e.g., generating prompts or search queries for AI code/gen or search tools). |
| 252 | + |
| 253 | +--- |
| 254 | + |
| 255 | +h. Groovy Code & Variables |
| 256 | + |
| 257 | +- You can use Groovy variables and code anywhere: |
| 258 | + ```groovy |
| 259 | + def ollamaServers = ["http://localhost:11434"] |
| 260 | + ... |
| 261 | + action(name: 'myGenAI', type: 'GenerateCodeOllama') { |
| 262 | + servers = ollamaServers |
| 263 | + } |
| 264 | + ``` |
| 265 | + |
| 266 | +- Useful to define lists, constants, or reference values elsewhere. |
| 267 | + |
| 268 | +--- |
| 269 | + |
| 270 | +## 3. Putting It Together: Step-by-Step Example |
| 271 | + |
| 272 | +Let’s design a simple workflow: |
| 273 | +"I want to check that a class implementing Stack in Java can push and pop elements." |
| 274 | + |
| 275 | +```groovy |
| 276 | +dataSource 'lasso_quickstart' |
| 277 | +study(name: 'CheckStack') { |
| 278 | + profile('java17Profile') { |
| 279 | + environment('java17') { |
| 280 | + image = 'maven:3.9-eclipse-temurin-17' |
| 281 | + } |
| 282 | + } |
| 283 | +
|
| 284 | + action(name: 'createStackMatrix') { |
| 285 | + execute { |
| 286 | + stimulusMatrix('Stack', """ |
| 287 | + Stack { |
| 288 | + push(java.lang.Object)->java.lang.Object |
| 289 | + pop()->java.lang.Object |
| 290 | + size()->int |
| 291 | + } |
| 292 | + """, |
| 293 | + [ |
| 294 | + implementation("1", "java.util.Stack"), |
| 295 | + implementation("2", "java.util.ArrayDeque"), |
| 296 | + implementation("3", "java.util.LinkedList") |
| 297 | + ], [ |
| 298 | + test(name: 'testPushPop()') { |
| 299 | + row '', 'create', 'Stack' |
| 300 | + row '', 'push', 'A1', '"BwGPT"' |
| 301 | + row 'D2', 'pop', 'A1' |
| 302 | + row '', 'size', 'A1' |
| 303 | + } |
| 304 | + ]) |
| 305 | + } |
| 306 | + } |
| 307 | +
|
| 308 | + action(name: 'test', type: 'Arena') { |
| 309 | + dependsOn 'createStackMatrix' |
| 310 | + include 'Stack' |
| 311 | + features = ['cc'] // enable code coverage |
| 312 | + profile('java17Profile') |
| 313 | + } |
| 314 | +} |
| 315 | +``` |
| 316 | + |
| 317 | +What happens here? |
| 318 | +- We define a study using `lasso_quickstart` data. |
| 319 | +- We provide a profile matching Java 17 as our execution environment. |
| 320 | +- We create a Stack abstraction, list possible implementations, and give a simple test. |
| 321 | +- We test the abstraction and measure code coverage. |
| 322 | + |
| 323 | +--- |
| 324 | + |
| 325 | +## 4. Key Patterns, FAQs, Tips |
| 326 | + |
| 327 | +- How do I add more test cases? |
| 328 | + Add another `test(name: ...) { ... }` block inside the matrix’s test list. |
| 329 | +- How do I switch to another Java version? |
| 330 | + Add or change a `profile` and use a different image (e.g., for Java 11). |
| 331 | +- Can I process multiple abstractions at once? |
| 332 | + Use `include '*'` to apply actions to all abstractions in context. |
| 333 | +- Want to do AI code generation? |
| 334 | + Use actions with `type: 'GenerateCodeOllama'` (or `'GenerateCodeOpenAI'`), supply prompts in the block, and manage AI settings there. |
| 335 | +- Want fully custom JUnit tests? |
| 336 | + Use `testFromJUnit("...your full JUnit source...")` inside the matrix. |
| 337 | +- Need search or code generation prompt customization? |
| 338 | + Use a `prompt { ... }` or `query { ... }` closure inside the action for full control. |
| 339 | + |
| 340 | +--- |
| 341 | + |
| 342 | +## 5. Where to Find More |
| 343 | + |
| 344 | +- Explore more LSL pipelines and their results in [TDSEHub](../datastructures/lsl) |
| 345 | +- Generate LSL pipelines for [Code Search](/web/lasso/ssn?recommendation=search) |
| 346 | +- Generate LSL pipelines for [Code Generation](/web/lasso/ssn?recommendation=gen) |
| 347 | +- [LSLFlow](https://softwareobservatorium.github.io/lslflow/) for visual construction of pipelines |
| 348 | + |
| 349 | +--- |
| 350 | + |
| 351 | +## Full Specification: LSL is flexible and feature-rich |
| 352 | + |
| 353 | +Define WHAT you want to test/find, HOW to test it, and WHERE to run it — and LSL does the rest. Find the full specification of LSL [here](../datastructures/lsl.md). |
0 commit comments