@robinpath/robinpath 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +856 -0
  2. package/bin/robinpath.js +374 -0
  3. package/dist/classes/ASTSerializer.d.ts +45 -0
  4. package/dist/classes/ExecutionStateTracker.d.ts +30 -0
  5. package/dist/classes/Executor.d.ts +193 -0
  6. package/dist/classes/ExpressionEvaluator.d.ts +20 -0
  7. package/dist/classes/Lexer.d.ts +86 -0
  8. package/dist/classes/Parser.d.ts +71 -0
  9. package/dist/classes/RobinPathThread.d.ts +146 -0
  10. package/dist/classes/TokenStream.d.ts +217 -0
  11. package/dist/classes/code-converter/ASTToCodeConverter.d.ts +178 -0
  12. package/dist/classes/code-converter/LineIndex.d.ts +54 -0
  13. package/dist/classes/code-converter/Printer.d.ts +117 -0
  14. package/dist/classes/code-converter/Writer.d.ts +42 -0
  15. package/dist/classes/code-converter/index.d.ts +8 -0
  16. package/dist/classes/code-converter/types.d.ts +29 -0
  17. package/dist/classes/exceptions.d.ts +26 -0
  18. package/dist/classes/index.d.ts +16 -0
  19. package/dist/index.d.ts +485 -0
  20. package/dist/index.js +13808 -0
  21. package/dist/modules/Array.d.ts +10 -0
  22. package/dist/modules/Core.d.ts +10 -0
  23. package/dist/modules/Dom.d.ts +10 -0
  24. package/dist/modules/Fetch.d.ts +6 -0
  25. package/dist/modules/Json.d.ts +10 -0
  26. package/dist/modules/Math.d.ts +10 -0
  27. package/dist/modules/Object.d.ts +10 -0
  28. package/dist/modules/Random.d.ts +6 -0
  29. package/dist/modules/String.d.ts +10 -0
  30. package/dist/modules/Test.d.ts +10 -0
  31. package/dist/modules/Time.d.ts +10 -0
  32. package/dist/parsers/ArrayLiteralParser.d.ts +17 -0
  33. package/dist/parsers/AssignmentParser.d.ts +37 -0
  34. package/dist/parsers/BracketParser.d.ts +31 -0
  35. package/dist/parsers/BreakParser.d.ts +15 -0
  36. package/dist/parsers/CellBlockParser.d.ts +11 -0
  37. package/dist/parsers/ChunkMarkerParser.d.ts +12 -0
  38. package/dist/parsers/CommandParser.d.ts +56 -0
  39. package/dist/parsers/CommentParser.d.ts +37 -0
  40. package/dist/parsers/ContinueParser.d.ts +15 -0
  41. package/dist/parsers/DecoratorParser.d.ts +29 -0
  42. package/dist/parsers/DefineParser.d.ts +18 -0
  43. package/dist/parsers/EventParser.d.ts +17 -0
  44. package/dist/parsers/ExpressionParser.d.ts +3 -0
  45. package/dist/parsers/FenceClassifier.d.ts +29 -0
  46. package/dist/parsers/ForLoopParser.d.ts +17 -0
  47. package/dist/parsers/IfBlockParser.d.ts +17 -0
  48. package/dist/parsers/ObjectLiteralParser.d.ts +17 -0
  49. package/dist/parsers/ParserUtils.d.ts +15 -0
  50. package/dist/parsers/PromptBlockParser.d.ts +10 -0
  51. package/dist/parsers/ReturnParser.d.ts +16 -0
  52. package/dist/parsers/ScopeParser.d.ts +24 -0
  53. package/dist/parsers/StringTemplateParser.d.ts +31 -0
  54. package/dist/parsers/SubexpressionParser.d.ts +33 -0
  55. package/dist/parsers/TogetherBlockParser.d.ts +18 -0
  56. package/dist/parsers/WithScopeParser.d.ts +24 -0
  57. package/dist/types/Ast.type.d.ts +455 -0
  58. package/dist/types/Environment.type.d.ts +53 -0
  59. package/dist/utils/args.d.ts +24 -0
  60. package/dist/utils/errorFormatter.d.ts +22 -0
  61. package/dist/utils/index.d.ts +8 -0
  62. package/dist/utils/stringParsing.d.ts +41 -0
  63. package/dist/utils/types.d.ts +15 -0
  64. package/dist/utils/valueConversion.d.ts +25 -0
  65. package/package.json +50 -0
package/README.md ADDED
@@ -0,0 +1,856 @@
1
+ # RobinPath
2
+
3
+ A scripting language interpreter with a REPL interface and built-in modules for math, strings, JSON, time, arrays, and more.
4
+
5
+ ## Installation
6
+
7
+ Install RobinPath as a dependency in your project:
8
+
9
+ ```bash
10
+ npm i @wiredwp/robinpath
11
+ ```
12
+
13
+ ## Integration
14
+
15
+ ### Basic Usage
16
+
17
+ Import and create a `RobinPath` instance to execute scripts in your application:
18
+
19
+ ```typescript
20
+ import { RobinPath } from '@wiredwp/robinpath';
21
+
22
+ // Create an interpreter instance
23
+ const rp = new RobinPath();
24
+
25
+ // Execute a script
26
+ const result = await rp.executeScript(`
27
+ add 10 20
28
+ multiply $ 2
29
+ `);
30
+
31
+ console.log('Result:', result); // 60
32
+ ```
33
+
34
+ ### REPL Mode (Persistent State)
35
+
36
+ Use `executeLine()` for REPL-like behavior where state persists between calls:
37
+
38
+ ```typescript
39
+ const rp = new RobinPath();
40
+
41
+ // First line - sets $result
42
+ await rp.executeLine('$result = add 10 20');
43
+ console.log(rp.getLastValue()); // 30
44
+
45
+ // Second line - uses previous result
46
+ await rp.executeLine('multiply $result 2');
47
+ console.log(rp.getLastValue()); // 60
48
+ ```
49
+
50
+ ### Working with Variables
51
+
52
+ Get and set variables programmatically:
53
+
54
+ ```typescript
55
+ const rp = new RobinPath();
56
+
57
+ // Set a variable from JavaScript
58
+ rp.setVariable('name', 'Alice');
59
+ rp.setVariable('age', 25);
60
+
61
+ // Execute script that uses the variable
62
+ await rp.executeScript(`
63
+ log "Hello" $name
64
+ log "Age:" $age
65
+ `);
66
+
67
+ // Get a variable value
68
+ const name = rp.getVariable('name');
69
+ console.log(name); // "Alice"
70
+ ```
71
+
72
+ ### Threads (Isolated Execution Contexts)
73
+
74
+ Create isolated execution contexts with threads:
75
+
76
+ ```typescript
77
+ const rp = new RobinPath({ threadControl: true });
78
+
79
+ // Create a new thread
80
+ const thread1 = rp.createThread('user-123');
81
+ await thread1.executeScript('$count = 10');
82
+
83
+ // Create another thread with separate variables
84
+ const thread2 = rp.createThread('user-456');
85
+ await thread2.executeScript('$count = 20');
86
+
87
+ // Each thread maintains its own state
88
+ console.log(thread1.getVariable('count')); // 10
89
+ console.log(thread2.getVariable('count')); // 20
90
+
91
+ // Switch between threads
92
+ rp.useThread('user-123');
93
+ console.log(rp.currentThread?.getVariable('count')); // 10
94
+ ```
95
+
96
+ ### Registering Custom Functions
97
+
98
+ Extend RobinPath with your own builtin functions:
99
+
100
+ ```typescript
101
+ const rp = new RobinPath();
102
+
103
+ // Register a simple builtin
104
+ rp.registerBuiltin('greet', (args) => {
105
+ const name = String(args[0] ?? 'World');
106
+ return `Hello, ${name}!`;
107
+ });
108
+
109
+ // Use it in scripts
110
+ await rp.executeScript('greet "Alice"');
111
+ console.log(rp.getLastValue()); // "Hello, Alice!"
112
+ ```
113
+
114
+ ### Registering Custom Modules
115
+
116
+ Create and register custom modules:
117
+
118
+ ```typescript
119
+ const rp = new RobinPath();
120
+
121
+ // Register module functions
122
+ rp.registerModule('myapp', {
123
+ process: (args) => {
124
+ const data = args[0];
125
+ // Process data...
126
+ return processedData;
127
+ },
128
+ validate: (args) => {
129
+ const input = args[0];
130
+ return isValid(input);
131
+ }
132
+ });
133
+
134
+ // Register function metadata for documentation
135
+ rp.registerModuleFunctionMeta('myapp', 'process', {
136
+ description: 'Processes input data',
137
+ parameters: [
138
+ {
139
+ name: 'data',
140
+ dataType: 'object',
141
+ description: 'Data to process',
142
+ formInputType: 'json',
143
+ required: true
144
+ }
145
+ ],
146
+ returnType: 'object',
147
+ returnDescription: 'Processed data'
148
+ });
149
+
150
+ // Register module-level metadata
151
+ rp.registerModuleInfo('myapp', {
152
+ description: 'Custom application module',
153
+ methods: ['process', 'validate']
154
+ });
155
+
156
+ // Use in scripts
157
+ await rp.executeScript(`
158
+ use myapp
159
+ myapp.process $data
160
+ `);
161
+ ```
162
+
163
+ ### Getting Available Commands
164
+
165
+ Query available commands for autocomplete or help:
166
+
167
+ ```typescript
168
+ const rp = new RobinPath();
169
+
170
+ const commands = rp.getAvailableCommands();
171
+ console.log(commands.native); // Native commands (if, def, etc.)
172
+ console.log(commands.builtin); // Root-level builtins
173
+ console.log(commands.modules); // Available modules
174
+ console.log(commands.moduleFunctions); // Module.function names
175
+ console.log(commands.userFunctions); // User-defined functions
176
+ ```
177
+
178
+ ### AST with Execution State
179
+
180
+ Get the AST with execution state for debugging or visualization:
181
+
182
+ ```typescript
183
+ const rp = new RobinPath({ threadControl: true });
184
+ const thread = rp.createThread('debug');
185
+
186
+ const script = `
187
+ add 5 5
188
+ $result = $
189
+ if $result > 5
190
+ multiply $result 2
191
+ endif
192
+ `;
193
+
194
+ const astResult = await thread.getASTWithState(script);
195
+ console.log(astResult.ast); // AST with lastValue at each node
196
+ console.log(astResult.variables); // Thread and global variables
197
+ console.log(astResult.lastValue); // Final result
198
+ console.log(astResult.callStack); // Call stack frames
199
+ ```
200
+
201
+ ### Checking for Incomplete Blocks
202
+
203
+ Check if a script needs more input (useful for multi-line input):
204
+
205
+ ```typescript
206
+ const rp = new RobinPath();
207
+
208
+ const check1 = rp.needsMoreInput('if $x > 5');
209
+ console.log(check1); // { needsMore: true, waitingFor: 'endif' }
210
+
211
+ const check2 = rp.needsMoreInput('if $x > 5\n log "yes"\nendif');
212
+ console.log(check2); // { needsMore: false }
213
+ ```
214
+
215
+ ### Error Handling
216
+
217
+ Handle errors from script execution:
218
+
219
+ ```typescript
220
+ const rp = new RobinPath();
221
+
222
+ try {
223
+ await rp.executeScript('unknown_function 123');
224
+ } catch (error) {
225
+ console.error('Script error:', error.message);
226
+ // "Unknown function: unknown_function"
227
+ }
228
+ ```
229
+
230
+ ## CLI Usage
231
+
232
+ ### Installation
233
+
234
+ Install globally to use the `robinpath` command:
235
+
236
+ ```bash
237
+ npm i -g @wiredwp/robinpath
238
+ ```
239
+
240
+ Or use it directly with `npx`:
241
+
242
+ ```bash
243
+ npx @wiredwp/robinpath
244
+ ```
245
+
246
+ ### Starting the REPL
247
+
248
+ Start the interactive REPL:
249
+
250
+ ```bash
251
+ robinpath
252
+ ```
253
+
254
+ Or if installed locally:
255
+
256
+ ```bash
257
+ npm run cli
258
+ ```
259
+
260
+ This will start an interactive session where you can type commands and see results immediately.
261
+
262
+ ### REPL Commands
263
+
264
+ - `help` or `.help` - Show help message
265
+ - `exit`, `quit`, `.exit`, `.quit` - Exit the REPL
266
+ - `clear` or `.clear` - Clear the screen
267
+ - `..` - Show all available commands as JSON
268
+
269
+ ### REPL Features
270
+
271
+ **Multi-line Blocks:**
272
+ The REPL automatically detects incomplete blocks and waits for completion:
273
+
274
+ ```robinpath
275
+ > if $x > 5
276
+ ... log "yes"
277
+ ... endif
278
+ ```
279
+
280
+ **Backslash Line Continuation:**
281
+ Use `\` at the end of a line to continue the command on the next line:
282
+
283
+ ```robinpath
284
+ > log "this is a very long message " \
285
+ ... "that continues on the next line"
286
+ ```
287
+
288
+ The backslash continuation works with any statement type and can be chained across multiple lines.
289
+
290
+ **Thread Management:**
291
+ When thread control is enabled, the prompt shows the current thread and module:
292
+
293
+ ```robinpath
294
+ default@math> add 5 5
295
+ 10
296
+ default@math> use clear
297
+ Cleared module context
298
+ default> thread list
299
+ Threads:
300
+ - default (current)
301
+ - user-123
302
+ default> thread use user-123
303
+ Switched to thread: user-123
304
+ user-123>
305
+ ```
306
+
307
+ **Module Context:**
308
+ The prompt shows the current module when using `use`:
309
+
310
+ ```robinpath
311
+ > use math
312
+ Using module: math
313
+ default@math> add 5 5
314
+ 10
315
+ default@math> use clear
316
+ Cleared module context
317
+ default>
318
+ ```
319
+
320
+ ## Basic Syntax
321
+
322
+ ### Commands
323
+
324
+ Commands are executed by typing the command name followed by arguments:
325
+
326
+ ```robinpath
327
+ add 10 20
328
+ log "Hello, World!"
329
+ multiply 5 3
330
+ ```
331
+
332
+ ### Variables
333
+
334
+ Variables are prefixed with `$`:
335
+
336
+ ```robinpath
337
+ $name = "Alice"
338
+ $age = 25
339
+ log $name $age
340
+ ```
341
+
342
+ You can declare variables with `var` (mutable) or `const` (immutable):
343
+
344
+ ```robinpath
345
+ var $count 0
346
+ const $MAX_RETRIES 5
347
+ ```
348
+
349
+ ### Last Value Reference
350
+
351
+ Use `$` to reference the last computed value:
352
+
353
+ ```robinpath
354
+ add 10 20
355
+ multiply $ 2 # Uses 30 (result of add)
356
+ log $ # Prints 60
357
+ ```
358
+
359
+ ### Shorthand Assignment
360
+
361
+ Assign the last value to a variable by simply referencing it:
362
+
363
+ ```robinpath
364
+ add 5 3
365
+ $sum # Assigns 8 to $sum
366
+ log $sum # Prints 8
367
+ ```
368
+
369
+ ### Variable-to-Variable Assignment
370
+
371
+ Assign the value of one variable to another, including chained assignments:
372
+
373
+ ```robinpath
374
+ $city = "New York"
375
+ $city2 = $city # Copies "New York" to $city2
376
+ log $city2 # Prints "New York"
377
+
378
+ $number1 = 42
379
+ $number2 = $number1 # Copies 42 to $number2
380
+ $number3 = $number2 # Can chain assignments
381
+ ```
382
+
383
+ ### Into Syntax
384
+
385
+ Use `into $variable` to assign the result of a command, block, or function call directly to a variable:
386
+
387
+ ```robinpath
388
+ math.add 10 20 into $sum
389
+ log $sum # Prints 30
390
+
391
+ # Works with functions
392
+ myFunction(1 2) into $result
393
+
394
+ # Works with do blocks
395
+ do into $blockResult
396
+ math.add 5 5
397
+ math.multiply $ 2
398
+ enddo
399
+
400
+ # Works with repeat loops
401
+ repeat 3 with into $total
402
+ add $2 10
403
+ endwith
404
+
405
+ # Works with object property assignment
406
+ math.add 1 2 into $obj.sum
407
+ ```
408
+
409
+ ### Attribute Access and Array Indexing
410
+
411
+ RobinPath supports accessing object properties and array elements directly using dot notation and bracket notation:
412
+
413
+ **Property Access:**
414
+ ```robinpath
415
+ json.parse '{"name": "John", "age": 30, "address": {"city": "NYC"}}'
416
+ $user = $
417
+
418
+ # Access properties using dot notation
419
+ log $user.name # Prints "John"
420
+ log $user.age # Prints 30
421
+ log $user.address.city # Prints "NYC" (nested property access)
422
+
423
+ # Use in expressions
424
+ if $user.age >= 18
425
+ log "Adult"
426
+ endif
427
+
428
+ # Use as function arguments
429
+ math.add $user.age 5 # Adds 30 + 5 = 35
430
+ ```
431
+
432
+ **Array Indexing:**
433
+ ```robinpath
434
+ $arr = range 10 15
435
+ log $arr[0] # Prints 10 (first element)
436
+ log $arr[2] # Prints 12 (third element)
437
+ log $arr[5] # Prints 15 (last element)
438
+
439
+ # Out of bounds access returns null
440
+ log $arr[10] # Prints null
441
+
442
+ # Use in expressions
443
+ if $arr[0] == 10
444
+ log "First is 10"
445
+ endif
446
+ ```
447
+
448
+ **Combined Access:**
449
+ You can combine property access and array indexing:
450
+ ```robinpath
451
+ json.parse '{"items": [{"name": "item1", "price": 10}, {"name": "item2", "price": 20}]}'
452
+ $data = $
453
+
454
+ log $data.items[0].name # Prints "item1"
455
+ log $data.items[0].price # Prints 10
456
+ log $data.items[1].name # Prints "item2"
457
+
458
+ # Assign to variables
459
+ $firstItem = $data.items[0].name
460
+ log $firstItem # Prints "item1"
461
+ ```
462
+
463
+ **Error Handling:**
464
+ - Accessing a property of `null` or `undefined` throws an error.
465
+ - Accessing a property of a non-object throws an error.
466
+ - Array indexing on a non-array throws an error.
467
+ - Out-of-bounds array access returns `null`.
468
+
469
+ **Note:** Assignment targets must be simple variable names or object/array paths:
470
+ ```robinpath
471
+ $user.name = "Jane" # Supported
472
+ $arr[0] = 42 # Supported
473
+ $data.items[0].price = 99 # Deep assignment supported
474
+ ```
475
+
476
+ ### Native Reserved Methods
477
+
478
+ RobinPath includes several built-in reserved methods:
479
+
480
+ **`log` - Output values:**
481
+ ```robinpath
482
+ log "Hello, World!"
483
+ log $name $age
484
+ log "Result:" $(add 5 5)
485
+ ```
486
+
487
+ **`obj` - Create objects using JSON5 syntax or builder pattern:**
488
+ ```robinpath
489
+ # Create empty object
490
+ obj
491
+ $empty = $
492
+
493
+ # Create object with JSON5 syntax
494
+ obj '{name: "John", age: 30}'
495
+ $user = $
496
+
497
+ # Create object with key-value pairs (builder style)
498
+ obj name "John" age 30
499
+ ```
500
+
501
+ **`array` - Create arrays from arguments:**
502
+ ```robinpath
503
+ # Create empty array
504
+ array
505
+ $empty = $
506
+
507
+ # Create array with elements
508
+ array 1 2 3
509
+ $numbers = $
510
+ ```
511
+
512
+ **`set` - Assign a value:**
513
+ ```robinpath
514
+ set $var "value"
515
+ set $var as "value" # 'as' is optional
516
+ set $obj.prop "value" # path assignment
517
+
518
+ # Set with fallback (used if value is null/empty)
519
+ set $var $maybeNull "default value"
520
+ ```
521
+
522
+ **`get` - Get a value by path:**
523
+ ```robinpath
524
+ get $user "address.city"
525
+ ```
526
+
527
+ **`assign` - Assign a value to a variable (with optional fallback):**
528
+ ```robinpath
529
+ # Basic assignment
530
+ assign $myVar "hello"
531
+
532
+ # Assignment with fallback (3rd parameter used if 2nd is empty/null)
533
+ assign $result $maybeEmpty "default value"
534
+ ```
535
+
536
+ **`empty` - Clear/empty a variable:**
537
+ ```robinpath
538
+ $myVar = "some value"
539
+ empty $myVar
540
+ log $myVar # Prints null
541
+ ```
542
+
543
+ **`fallback` - Return variable value or fallback if empty/null:**
544
+ ```robinpath
545
+ $maybeEmpty = null
546
+ fallback $maybeEmpty "default value" # Returns "default value"
547
+ ```
548
+
549
+ **`meta` / `getMeta` - Manage metadata:**
550
+ ```robinpath
551
+ # Set metadata for variables, functions, or constants
552
+ meta $var description "Description"
553
+ meta myFunction author "Author"
554
+ meta $const version "1.0"
555
+
556
+ # Get metadata
557
+ getMeta $var description
558
+ getMeta myFunction author
559
+ ```
560
+
561
+ **`clear` - Clear the last return value ($):**
562
+ ```robinpath
563
+ math.add 10 20
564
+ clear
565
+ log $ # Prints null
566
+ ```
567
+
568
+ **`forget` - Hide a variable or function in the current scope:**
569
+ ```robinpath
570
+ $val = 10
571
+ do
572
+ forget $val
573
+ log $val # Prints null
574
+ enddo
575
+ ```
576
+
577
+ **`getType` - Get the type of a variable:**
578
+ ```robinpath
579
+ getType "hello" # "string"
580
+ getType 42 # "number"
581
+ getType true # "boolean"
582
+ getType null # "null"
583
+ getType [] # "array"
584
+ getType {} # "object"
585
+ ```
586
+
587
+ **`has` - Check if a variable or function exists:**
588
+ ```robinpath
589
+ has $var
590
+ has myFunction
591
+ has math.add
592
+ ```
593
+
594
+ **`end` - Stop script execution:**
595
+ ```robinpath
596
+ log "Start"
597
+ end
598
+ log "This is never reached"
599
+ ```
600
+
601
+ ### Do Blocks (Scopes)
602
+
603
+ `do` blocks create a new scope. Variables defined inside are local to the scope.
604
+
605
+ ```robinpath
606
+ do
607
+ $local = 10
608
+ enddo
609
+ log $local # Prints null (if not defined globally)
610
+ ```
611
+
612
+ **Isolated Scopes with Parameters:**
613
+ Scopes can be declared with parameters to create **isolated** execution contexts. Unlike regular `do` blocks, isolated scopes **do not inherit** variables from parent scopes unless they are explicitly passed as arguments.
614
+
615
+ ```robinpath
616
+ $outer = 100
617
+ do $a $b
618
+ # $outer is NOT accessible here (returns null)
619
+ # $a and $b are initialized from arguments passed to the block
620
+ $inner = 20
621
+ enddo
622
+ ```
623
+
624
+ ### Comments
625
+
626
+ Lines starting with `#` are comments:
627
+
628
+ ```robinpath
629
+ # This is a comment
630
+ add 1 2 # Inline comment
631
+ ```
632
+
633
+ ### Conditionals
634
+
635
+ **Inline if:**
636
+ ```robinpath
637
+ if $age >= 18 then log "Adult"
638
+ ```
639
+
640
+ **Block if:**
641
+ ```robinpath
642
+ if $score >= 90
643
+ log "Grade: A"
644
+ elseif $score >= 80
645
+ log "Grade: B"
646
+ else
647
+ log "Grade: F"
648
+ endif
649
+ ```
650
+
651
+ ### Loops
652
+
653
+ **For loops:**
654
+ ```robinpath
655
+ # Iterate over a range
656
+ for $i from 1 to 5
657
+ log "Iteration:" $i
658
+ endfor
659
+
660
+ # Iterate with custom step and key (index)
661
+ for $a from 0 to 10 step 2 key $index
662
+ log "value: " + $a + ", index: " + $index
663
+ endfor
664
+
665
+ # Range parameters can be in any order
666
+ for $x by 5 to 100 from 0
667
+ log $x
668
+ endfor
669
+
670
+ # Iterate over an array
671
+ $numbers = [10, 11, 12]
672
+ for $num in $numbers key $i
673
+ log "Number " + $i + ": " + $num
674
+ endfor
675
+ ```
676
+
677
+ **Repeat loop:**
678
+ The `repeat` loop runs a block `N` times. Inside the block:
679
+ - `$1` is the current iteration index (0-based).
680
+ - `$2` is the result of the previous iteration (or `null` for the first).
681
+
682
+ ```robinpath
683
+ repeat 5 with
684
+ log "Iteration:" $1 # 0, 1, 2, 3, 4
685
+ endwith
686
+
687
+ # Accumulate values
688
+ repeat 5 with
689
+ if $2 == null
690
+ return 0
691
+ endif
692
+ math.add $2 $1 # Adds current index to sum
693
+ endwith
694
+ # Result: 10 (0+1+2+3+4)
695
+ ```
696
+
697
+ **Break and Continue:**
698
+ Use `break` to exit a loop early, and `continue` to skip to the next iteration.
699
+
700
+ ```robinpath
701
+ for $i in range 1 10
702
+ if $i == 5
703
+ break
704
+ endif
705
+ endfor
706
+ ```
707
+
708
+ ### Functions
709
+
710
+ Define custom functions with `def` (or `define`):
711
+
712
+ ```robinpath
713
+ def greet $name
714
+ log "Hello" $name
715
+ enddef
716
+
717
+ # 'define' alias works too
718
+ define sum $a $b
719
+ math.add $a $b
720
+ enddef
721
+ ```
722
+
723
+ **Named Parameters:**
724
+ You can optionally use `as` after parameters.
725
+
726
+ ```robinpath
727
+ def greet $name $age as
728
+ # $name is alias for $1
729
+ # $age is alias for $2
730
+ log "Hello" $name "Age" $age
731
+ enddef
732
+ ```
733
+
734
+ **Call Syntax:**
735
+ ```robinpath
736
+ # CLI-style
737
+ greet "Alice" 25
738
+
739
+ # Parenthesized style (commas optional)
740
+ greet("Alice" 25)
741
+ greet(
742
+ "Alice"
743
+ 25
744
+ )
745
+ ```
746
+
747
+ **Named Arguments:**
748
+ ```robinpath
749
+ def config $env
750
+ log "Env:" $env "Key:" $args.key
751
+ enddef
752
+
753
+ config("prod" key="123")
754
+ config(
755
+ "prod"
756
+ key="123"
757
+ )
758
+ ```
759
+
760
+ **Decorators:**
761
+ Use decorators to add metadata to functions and variables:
762
+ ```robinpath
763
+ @desc "Calculates sum"
764
+ @param number $a "First number"
765
+ @param number $b "Second number"
766
+ @return number "The sum"
767
+ def add $a $b
768
+ math.add $a $b
769
+ enddef
770
+ ```
771
+
772
+ Common decorators: `@desc`, `@title`, `@param`, `@arg`, `@required`, `@return`, `@deprecated`.
773
+
774
+ ### Events
775
+
776
+ Define event handlers with `on`. Multiple handlers can be defined for the same event.
777
+
778
+ ```robinpath
779
+ on "user_login"
780
+ log "User logged in:" $1
781
+ endon
782
+
783
+ # Trigger an event
784
+ trigger "user_login" "Alice"
785
+ ```
786
+
787
+ ### Parallel Execution
788
+
789
+ Use `together` to run blocks in parallel:
790
+
791
+ ```robinpath
792
+ together
793
+ do
794
+ # Task 1
795
+ wait 1000
796
+ log "Task 1 done"
797
+ enddo
798
+ do
799
+ # Task 2
800
+ log "Task 2 done"
801
+ enddo
802
+ endtogether
803
+ ```
804
+
805
+ ### Modules
806
+
807
+ Use modules to access specialized functions:
808
+
809
+ ```robinpath
810
+ use math
811
+ math.add 5 10
812
+ ```
813
+
814
+ **Available Modules:**
815
+ - **`math`**: `add`, `subtract`, `multiply`, `divide`, `modulo`, `power`, `sqrt`, `abs`, `round`, `floor`, `ceil`, `min`, `max`.
816
+ - **`string`**: `length`, `substring`, `toUpperCase`, `toLowerCase`, `trim`, `replace`, `replaceAll`, `split`, `startsWith`, `endsWith`, `contains`, `indexOf`, `lastIndexOf`, `charAt`, `padStart`, `padEnd`, `repeat`, `concat`.
817
+ - **`json`**: `parse`, `stringify`, `isValid`.
818
+ - **`object`**: `keys`, `values`, `entries`, `merge`, `clone`. (Global commands like `keys` also available).
819
+ - **`time`**: `now`, `timestamp`, `format`, `addDays`, `diffDays`.
820
+ - **`random`**: `int`, `float`, `uuid`, `choice`.
821
+ - **`array`**: `create`, `length`, `get`, `slice`, `push`, `concat`, `join`.
822
+ - **`dom`**: `click` (with callback support), etc.
823
+
824
+ ### Inline Subexpressions
825
+
826
+ Use `$( ... )` for inline subexpressions. Subexpressions can be multi-line and contain multiple statements (returns result of the last one).
827
+
828
+ ```robinpath
829
+ log "Result:" $(math.add 10 20)
830
+
831
+ $val = $(
832
+ math.add 5 5
833
+ math.multiply $ 2
834
+ )
835
+ # $val is 20
836
+ ```
837
+
838
+ ### Comparison Functions
839
+
840
+ RobinPath provides built-in comparison functions useful for testing and assertions:
841
+ - `test.assertEqual`
842
+ - `test.isEqual`
843
+ - `test.isBigger`
844
+ - `test.isSmaller`
845
+ - `test.isEqualOrBigger`
846
+ - `test.isEqualOrSmaller`
847
+ - `test.assertTrue`
848
+ - `test.assertFalse`
849
+ - `test.assertNull`
850
+ - `test.assertNotNull`
851
+ - `test.assertType`
852
+ - `test.assertContains`
853
+
854
+ ## Creating Custom Modules
855
+
856
+ (Refer to "Creating Custom Modules" in the previous section of documentation for details on extending RobinPath with TypeScript).