@mojir/lits 2.1.35 → 2.1.36
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.
- package/README.md +333 -237
- package/dist/cli/cli.js +74 -14
- package/dist/index.esm.js +73 -13
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +73 -13
- package/dist/index.js.map +1 -1
- package/dist/lits.iife.js +73 -13
- package/dist/lits.iife.js.map +1 -1
- package/dist/testFramework.esm.js +73 -13
- package/dist/testFramework.esm.js.map +1 -1
- package/dist/testFramework.js +73 -13
- package/dist/testFramework.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ let squares = [1, 2, 3, 4, 5] map square;
|
|
|
68
68
|
// => [1, 4, 9, 16, 25]
|
|
69
69
|
|
|
70
70
|
// Using operator as a function
|
|
71
|
-
let sum = +(
|
|
71
|
+
let sum = +(1, 2, 3, 4, 5);
|
|
72
72
|
// => 15
|
|
73
73
|
```
|
|
74
74
|
|
|
@@ -153,18 +153,14 @@ let y = {
|
|
|
153
153
|
|
|
154
154
|
#### Destructuring
|
|
155
155
|
|
|
156
|
+
##### Basic Object Destructuring
|
|
157
|
+
|
|
156
158
|
```lits
|
|
157
159
|
// Object destructuring
|
|
158
160
|
let { name, age } = { name: "John", age: 30 };
|
|
159
161
|
// name => "John", age => 30
|
|
160
162
|
```
|
|
161
163
|
|
|
162
|
-
```lits
|
|
163
|
-
// Array destructuring
|
|
164
|
-
let [a, b] = [1, 2, 3, 4];
|
|
165
|
-
// a => 1, b => 2
|
|
166
|
-
```
|
|
167
|
-
|
|
168
164
|
```lits
|
|
169
165
|
// With default values
|
|
170
166
|
let { name = "Unknown", age = 0 } = { name: "John" };
|
|
@@ -172,18 +168,101 @@ let { name = "Unknown", age = 0 } = { name: "John" };
|
|
|
172
168
|
```
|
|
173
169
|
|
|
174
170
|
```lits
|
|
175
|
-
//
|
|
171
|
+
// Renaming with 'as'
|
|
172
|
+
let { name as userName } = { name: "Dave" };
|
|
173
|
+
// userName => "Dave"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
```lits
|
|
177
|
+
// Multiple renames
|
|
178
|
+
let { firstName as name, age as years } = { firstName: "Eve", age: 28 };
|
|
179
|
+
// name => "Eve", years => 28
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
##### Advanced Destructuring Patterns
|
|
183
|
+
|
|
184
|
+
```lits
|
|
185
|
+
// Complex nested destructuring with defaults and renaming
|
|
186
|
+
let {
|
|
187
|
+
name as userName = "Guest",
|
|
188
|
+
profile: {
|
|
189
|
+
age = 0,
|
|
190
|
+
contact: { email as userEmail = "none" }
|
|
191
|
+
},
|
|
192
|
+
settings = { theme: "light" },
|
|
193
|
+
scores as userScores = [],
|
|
194
|
+
...others
|
|
195
|
+
} = { name: "Sam", profile: { contact: {} }};
|
|
196
|
+
// userName => "Sam", age => 0, userEmail => "none", etc.
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
```lits
|
|
200
|
+
// Combining array and object destructuring
|
|
201
|
+
let [{ name }, { age }] = [{ name: "Tina" }, { age: 33 }];
|
|
202
|
+
// name => "Tina", age => 33
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```lits
|
|
206
|
+
// Object with array property destructuring
|
|
207
|
+
let { name, scores: [one, two] } = { name: "Uma", scores: [85, 92] };
|
|
208
|
+
// name => "Uma", one => 85, two => 92
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
##### Array Destructuring
|
|
212
|
+
|
|
213
|
+
```lits
|
|
214
|
+
// Array destructuring
|
|
215
|
+
let [, , a, b] = [1, 2, 3, 4];
|
|
216
|
+
// a => 3, b => 4
|
|
217
|
+
|
|
218
|
+
// Array destructuring with defaults
|
|
219
|
+
let [one, two = 2] = [1];
|
|
220
|
+
// one => 1, two => 2
|
|
221
|
+
|
|
222
|
+
// Skipping elements
|
|
223
|
+
let [x, , z] = [1, 2, 3];
|
|
224
|
+
// x => 1, z => 3
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
##### Rest Patterns
|
|
228
|
+
|
|
229
|
+
```lits
|
|
230
|
+
// Array rest pattern
|
|
176
231
|
let [head, ...tail] = [1, 2, 3, 4];
|
|
177
232
|
// head => 1, tail => [2, 3, 4]
|
|
233
|
+
|
|
234
|
+
// Object rest pattern
|
|
235
|
+
let { name, ...otherProps } = { name: "John", age: 30, city: "NYC" };
|
|
236
|
+
// name => "John", otherProps => { age: 30, city: "NYC" }
|
|
237
|
+
|
|
238
|
+
// Empty rest patterns
|
|
239
|
+
let [only, ...empty] = [1];
|
|
240
|
+
// only => 1, empty => []
|
|
178
241
|
```
|
|
179
242
|
|
|
243
|
+
##### Function Parameter Destructuring
|
|
244
|
+
|
|
180
245
|
```lits
|
|
181
|
-
//
|
|
182
|
-
let
|
|
183
|
-
|
|
246
|
+
// Basic parameter destructuring
|
|
247
|
+
let greet = ({ name }) -> "Hello, " ++ name;
|
|
248
|
+
greet({ name: "Pat" });
|
|
249
|
+
// => "Hello, Pat"
|
|
250
|
+
|
|
251
|
+
// With defaults in parameters
|
|
252
|
+
let greet2 = ({ name = "friend" }) -> "Hello, " ++ name;
|
|
253
|
+
greet2({});
|
|
254
|
+
// => "Hello, friend"
|
|
255
|
+
|
|
256
|
+
// Nested parameter destructuring
|
|
257
|
+
let processUser = ({ profile: { name, age }}) ->
|
|
258
|
+
name ++ " is " ++ str(age);
|
|
259
|
+
processUser({ profile: { name: "Quinn", age: 29 }});
|
|
260
|
+
// => "Quinn is 29"
|
|
184
261
|
|
|
185
|
-
|
|
186
|
-
|
|
262
|
+
// Array parameter destructuring
|
|
263
|
+
let processCoords = ([x, y]) -> x + y;
|
|
264
|
+
processCoords([3, 4]);
|
|
265
|
+
// => 7
|
|
187
266
|
```
|
|
188
267
|
|
|
189
268
|
### Functions
|
|
@@ -220,7 +299,6 @@ let factorial = n ->
|
|
|
220
299
|
#### If/Unless
|
|
221
300
|
|
|
222
301
|
```lits
|
|
223
|
-
// If expression
|
|
224
302
|
let x = !:random-int(0, 20); // Random number between 0 and 19
|
|
225
303
|
|
|
226
304
|
if x > 10 then
|
|
@@ -235,12 +313,13 @@ if false then "never" end;
|
|
|
235
313
|
// => null
|
|
236
314
|
|
|
237
315
|
// Unless (inverted if)
|
|
238
|
-
|
|
316
|
+
let y = !:random-int(0, 20);
|
|
317
|
+
unless y > 10 then
|
|
239
318
|
"small"
|
|
240
319
|
else
|
|
241
320
|
"large"
|
|
242
321
|
end;
|
|
243
|
-
// => "small" (if
|
|
322
|
+
// => "small" (if y <= 10) or "large" (if y > 10)
|
|
244
323
|
```
|
|
245
324
|
|
|
246
325
|
#### Cond
|
|
@@ -253,8 +332,17 @@ cond
|
|
|
253
332
|
case x < 5 then "small"
|
|
254
333
|
case x < 10 then "medium"
|
|
255
334
|
case x < 15 then "large"
|
|
256
|
-
end ?? "extra large"
|
|
335
|
+
end ?? "extra large";
|
|
257
336
|
// Tests conditions sequentially, returns first truthy match
|
|
337
|
+
|
|
338
|
+
// Cond with complex conditions
|
|
339
|
+
let urgent = !:random-int(0, 2) == 1;
|
|
340
|
+
let important = !:random-int(0, 2) == 1;
|
|
341
|
+
let priority = cond
|
|
342
|
+
case urgent && important then "critical"
|
|
343
|
+
case urgent then "high"
|
|
344
|
+
case important then "medium"
|
|
345
|
+
end ?? "low";
|
|
258
346
|
```
|
|
259
347
|
|
|
260
348
|
#### Switch
|
|
@@ -267,8 +355,20 @@ switch x
|
|
|
267
355
|
case 0 then "zero"
|
|
268
356
|
case 1 then "one"
|
|
269
357
|
case 2 then "two"
|
|
270
|
-
end
|
|
358
|
+
end;
|
|
271
359
|
// => "zero" (if x = 0), "one" (if x = 1), etc., or null if no match
|
|
360
|
+
|
|
361
|
+
// Switch with multiple cases
|
|
362
|
+
let userInput = "help";
|
|
363
|
+
let exit = -> "exiting";
|
|
364
|
+
let showHelp = -> "showing help";
|
|
365
|
+
let saveData = -> "saving data";
|
|
366
|
+
|
|
367
|
+
switch userInput
|
|
368
|
+
case "quit" then exit()
|
|
369
|
+
case "help" then showHelp()
|
|
370
|
+
case "save" then saveData()
|
|
371
|
+
end;
|
|
272
372
|
```
|
|
273
373
|
|
|
274
374
|
### Loops and Iteration
|
|
@@ -280,15 +380,15 @@ end
|
|
|
280
380
|
for (x in [1, 2, 3, 4]) -> x * 2;
|
|
281
381
|
// => [2, 4, 6, 8]
|
|
282
382
|
|
|
283
|
-
// With filtering
|
|
383
|
+
// With filtering (when clause)
|
|
284
384
|
for (x in [1, 2, 3, 4] when odd?(x)) -> x * 2;
|
|
285
385
|
// => [2, 6]
|
|
286
386
|
|
|
287
|
-
// With while
|
|
387
|
+
// With early termination (while clause)
|
|
288
388
|
for (x in [1, 2, 3, 4] while x < 3) -> x * 2;
|
|
289
389
|
// => [2, 4]
|
|
290
390
|
|
|
291
|
-
// With let bindings
|
|
391
|
+
// With let bindings for intermediate calculations
|
|
292
392
|
for (x in [1, 2, 3] let doubled = x * 2) -> doubled + 1;
|
|
293
393
|
// => [3, 5, 7]
|
|
294
394
|
|
|
@@ -296,6 +396,20 @@ for (x in [1, 2, 3] let doubled = x * 2) -> doubled + 1;
|
|
|
296
396
|
for (x in [1, 2], y in [10, 20]) -> x + y;
|
|
297
397
|
// => [11, 21, 12, 22]
|
|
298
398
|
|
|
399
|
+
// Complex for comprehensions with multiple conditions
|
|
400
|
+
for (
|
|
401
|
+
i in range(10)
|
|
402
|
+
let ii = i ^ 2
|
|
403
|
+
while ii < 40
|
|
404
|
+
when ii % 3 == 0,
|
|
405
|
+
j in range(10)
|
|
406
|
+
when j % 2 == 1
|
|
407
|
+
) -> ii + j;
|
|
408
|
+
|
|
409
|
+
// Using previous bindings in subsequent iterations
|
|
410
|
+
for (x in [1, 2], y in [x, 2 * x]) -> x * y;
|
|
411
|
+
// => [1, 2, 4, 8]
|
|
412
|
+
|
|
299
413
|
// Object iteration
|
|
300
414
|
for (entry in { a: 1, b: 2 } let [key, value] = entry) -> key ++ ":" ++ str(value);
|
|
301
415
|
// => ["a:1", "b:2"]
|
|
@@ -319,8 +433,41 @@ loop (n = 5, acc = 1) -> {
|
|
|
319
433
|
else
|
|
320
434
|
recur(n - 1, acc * n)
|
|
321
435
|
end
|
|
322
|
-
}
|
|
436
|
+
};
|
|
323
437
|
// => 120 (factorial of 5)
|
|
438
|
+
|
|
439
|
+
// Complex loop with multiple variables
|
|
440
|
+
loop (items = [1, 2, 3, 4, 5], sum = 0, cnt = 0) -> {
|
|
441
|
+
if empty?(items) then
|
|
442
|
+
{ sum: sum, average: sum / cnt }
|
|
443
|
+
else
|
|
444
|
+
recur(rest(items), sum + first(items), cnt + 1)
|
|
445
|
+
end
|
|
446
|
+
};
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Recursion with Recur
|
|
450
|
+
|
|
451
|
+
#### Function Recursion
|
|
452
|
+
|
|
453
|
+
```lits
|
|
454
|
+
// Simple recursive function with recur
|
|
455
|
+
let factorial = (n) -> {
|
|
456
|
+
if n <= 1 then
|
|
457
|
+
1
|
|
458
|
+
else
|
|
459
|
+
n * recur(n - 1)
|
|
460
|
+
end
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
// Tail-recursive function
|
|
464
|
+
let sumToN = (n, acc = 0) -> {
|
|
465
|
+
if zero?(n) then
|
|
466
|
+
acc
|
|
467
|
+
else
|
|
468
|
+
recur(n - 1, acc + n)
|
|
469
|
+
end
|
|
470
|
+
};
|
|
324
471
|
```
|
|
325
472
|
|
|
326
473
|
### Error Handling
|
|
@@ -329,6 +476,7 @@ loop (n = 5, acc = 1) -> {
|
|
|
329
476
|
|
|
330
477
|
```lits
|
|
331
478
|
// Basic try/catch
|
|
479
|
+
let riskyOperation = () -> throw("Something went wrong");
|
|
332
480
|
try
|
|
333
481
|
riskyOperation()
|
|
334
482
|
catch
|
|
@@ -341,6 +489,16 @@ try
|
|
|
341
489
|
catch (error)
|
|
342
490
|
"Error: " ++ error.message
|
|
343
491
|
end;
|
|
492
|
+
|
|
493
|
+
// Try-catch for graceful degradation
|
|
494
|
+
let parseData = () -> { value: 42 };
|
|
495
|
+
let process = (val) -> val * 2;
|
|
496
|
+
try
|
|
497
|
+
let { value } = parseData();
|
|
498
|
+
process(value);
|
|
499
|
+
catch
|
|
500
|
+
"Using default value"
|
|
501
|
+
end;
|
|
344
502
|
```
|
|
345
503
|
|
|
346
504
|
#### Throw
|
|
@@ -348,202 +506,177 @@ end;
|
|
|
348
506
|
```lits
|
|
349
507
|
// Throwing errors
|
|
350
508
|
try
|
|
351
|
-
throw("Custom error message")
|
|
509
|
+
throw("Custom error message")
|
|
352
510
|
catch
|
|
353
511
|
"Caught an error"
|
|
354
512
|
end;
|
|
355
513
|
|
|
356
|
-
//
|
|
514
|
+
// Custom error messages in functions
|
|
357
515
|
let divide = (a, b) ->
|
|
358
516
|
if zero?(b) then
|
|
359
|
-
throw("
|
|
517
|
+
throw("Cannot divide by zero")
|
|
360
518
|
else
|
|
361
519
|
a / b
|
|
362
520
|
end;
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
### Logical Operators
|
|
366
|
-
|
|
367
|
-
#### And/Or
|
|
368
|
-
|
|
369
|
-
```lits
|
|
370
|
-
// Logical AND (short-circuit)
|
|
371
|
-
true && "second value"; // => "second value"
|
|
372
|
-
false && "never reached"; // => false
|
|
373
|
-
|
|
374
|
-
// Logical OR (short-circuit)
|
|
375
|
-
false || "default value"; // => "default value"
|
|
376
|
-
true || "never reached"; // => true
|
|
377
521
|
|
|
378
|
-
//
|
|
379
|
-
|
|
380
|
-
|
|
522
|
+
// Conditional error throwing
|
|
523
|
+
let validateAge = (age) ->
|
|
524
|
+
cond
|
|
525
|
+
case age < 0 then throw("Age cannot be negative")
|
|
526
|
+
case age > 150 then throw("Age seems unrealistic")
|
|
527
|
+
case true then age
|
|
528
|
+
end;
|
|
381
529
|
```
|
|
382
530
|
|
|
383
|
-
|
|
531
|
+
### Block Expressions
|
|
384
532
|
|
|
385
533
|
```lits
|
|
386
|
-
//
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
false ?? "default"; // => false
|
|
391
|
-
"" ?? "default"; // => ""
|
|
392
|
-
```
|
|
534
|
+
// Block for grouping expressions
|
|
535
|
+
let computeX = () -> 5;
|
|
536
|
+
let computeY = () -> 10;
|
|
537
|
+
let processResult = (z) -> z * 2;
|
|
393
538
|
|
|
394
|
-
|
|
539
|
+
let result = {
|
|
540
|
+
let x = computeX();
|
|
541
|
+
let y = computeY();
|
|
542
|
+
let z = x * y;
|
|
543
|
+
processResult(z)
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
// Block with side effects
|
|
547
|
+
let loadData = () -> [1, 2, 3];
|
|
548
|
+
let processData = (data) -> data map -> $ * 2;
|
|
395
549
|
|
|
396
|
-
```lits
|
|
397
|
-
// Block expressions
|
|
398
550
|
{
|
|
399
|
-
|
|
400
|
-
let
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
551
|
+
write!("Starting process...");
|
|
552
|
+
let data = loadData();
|
|
553
|
+
let processed = processData(data);
|
|
554
|
+
write!("Process completed");
|
|
555
|
+
processed
|
|
556
|
+
};
|
|
404
557
|
```
|
|
405
558
|
|
|
406
|
-
###
|
|
559
|
+
### Array and Object Spread
|
|
407
560
|
|
|
408
|
-
#### Array
|
|
561
|
+
#### Array Spread
|
|
409
562
|
|
|
410
563
|
```lits
|
|
411
|
-
//
|
|
412
|
-
[1, 2, 3, 4];
|
|
564
|
+
// Spread in array literals
|
|
565
|
+
let combined = [1, 2, ...[3, 4, 5], 6];
|
|
566
|
+
// => [1, 2, 3, 4, 5, 6]
|
|
413
567
|
|
|
414
|
-
//
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
let
|
|
419
|
-
[1, 2, ...small-set, 6];
|
|
420
|
-
// => [1, 2, 3, 4, 5, 6];
|
|
568
|
+
// Multiple spreads
|
|
569
|
+
let start = [1, 2];
|
|
570
|
+
let middle = [3, 4];
|
|
571
|
+
let stop = [5, 6];
|
|
572
|
+
let result = [...start, ...middle, ...stop];
|
|
421
573
|
```
|
|
422
574
|
|
|
423
|
-
#### Object
|
|
575
|
+
#### Object Spread
|
|
424
576
|
|
|
425
577
|
```lits
|
|
426
|
-
// Object
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
// Object function
|
|
430
|
-
object("name", "John", "age", 30);
|
|
431
|
-
|
|
432
|
-
// With spread
|
|
433
|
-
let defaults = { type: "Person", active: true };
|
|
434
|
-
{
|
|
435
|
-
...defaults,
|
|
578
|
+
// Object spread for merging
|
|
579
|
+
let person = {
|
|
436
580
|
name: "John",
|
|
437
581
|
age: 30
|
|
438
582
|
};
|
|
439
|
-
// => { type: "Person", active: true, name: "John", age: 30 }
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
### Recursion
|
|
443
583
|
|
|
444
|
-
|
|
584
|
+
let employee = {
|
|
585
|
+
...person,
|
|
586
|
+
id: "E123",
|
|
587
|
+
department: "Engineering"
|
|
588
|
+
};
|
|
589
|
+
// => { name: "John", age: 30, id: "E123", department: "Engineering" }
|
|
445
590
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
recur(n - 1)
|
|
452
|
-
end
|
|
591
|
+
// Spread with override
|
|
592
|
+
let defaults = {
|
|
593
|
+
name: "Default Name",
|
|
594
|
+
theme: "light",
|
|
595
|
+
active: true
|
|
453
596
|
};
|
|
454
597
|
|
|
455
|
-
|
|
456
|
-
|
|
598
|
+
let updated = {
|
|
599
|
+
...defaults,
|
|
600
|
+
name: "Custom Name" // Override defaults.name
|
|
601
|
+
};
|
|
457
602
|
```
|
|
458
603
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
### Algebraic Notation
|
|
604
|
+
### Logical Operators
|
|
462
605
|
|
|
463
|
-
|
|
606
|
+
#### And/Or
|
|
464
607
|
|
|
465
608
|
```lits
|
|
466
|
-
//
|
|
467
|
-
|
|
609
|
+
// Logical AND (short-circuit)
|
|
610
|
+
true && "second value"; // => "second value"
|
|
611
|
+
false && "never reached"; // => false
|
|
468
612
|
|
|
469
|
-
//
|
|
470
|
-
|
|
613
|
+
// Logical OR (short-circuit)
|
|
614
|
+
false || "default value"; // => "default value"
|
|
615
|
+
true || "never reached"; // => true
|
|
616
|
+
|
|
617
|
+
// Multiple arguments
|
|
618
|
+
&&(true, true, "all true"); // => "all true"
|
|
619
|
+
||(false, false, "found"); // => "found"
|
|
471
620
|
```
|
|
472
621
|
|
|
473
|
-
|
|
622
|
+
#### Null Coalescing
|
|
474
623
|
|
|
475
624
|
```lits
|
|
476
|
-
//
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
//
|
|
480
|
-
|
|
625
|
+
// Null coalescing operator
|
|
626
|
+
null ?? "default"; // => "default"
|
|
627
|
+
undefined-var ?? "default"; // => "default"
|
|
628
|
+
0 ?? "default"; // => 0 (only null/undefined are coalesced)
|
|
629
|
+
false ?? "default"; // => false
|
|
630
|
+
"" ?? "default"; // => ""
|
|
631
|
+
```
|
|
481
632
|
|
|
482
|
-
|
|
483
|
-
let add5 = +(5, _);
|
|
484
|
-
add5(3); // => 8
|
|
633
|
+
### Ternary Operator
|
|
485
634
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
635
|
+
```lits
|
|
636
|
+
// Conditional expression
|
|
637
|
+
let age = !:random-int(10, 60);
|
|
638
|
+
let result = age >= 18 ? "adult" : "minor";
|
|
489
639
|
|
|
490
|
-
//
|
|
491
|
-
let
|
|
492
|
-
|
|
640
|
+
// Nested ternary
|
|
641
|
+
let score = !:random-int(0, 100);
|
|
642
|
+
let category = score >= 90 ? "A" : score >= 80 ? "B" : "C";
|
|
493
643
|
|
|
494
|
-
|
|
495
|
-
|
|
644
|
+
// With complex expressions
|
|
645
|
+
let isLoggedIn = () -> true;
|
|
646
|
+
let hasPermission = () -> true;
|
|
647
|
+
let status = isLoggedIn() && hasPermission() ? "authorized" : "unauthorized";
|
|
496
648
|
```
|
|
497
649
|
|
|
498
|
-
|
|
650
|
+
## Operators and Precedence
|
|
499
651
|
|
|
500
|
-
Lits
|
|
652
|
+
Lits follows a clear operator precedence hierarchy. Understanding precedence helps you write expressions that behave as expected:
|
|
501
653
|
|
|
502
|
-
|
|
503
|
-
// Function style
|
|
504
|
-
filter([1, 2, 3, 4], odd?); // => [1, 3]
|
|
505
|
-
|
|
506
|
-
// Operator style (more readable)
|
|
507
|
-
[1, 2, 3, 4] filter odd?; // => [1, 3]
|
|
508
|
-
```
|
|
654
|
+
### Precedence Table (Highest to Lowest)
|
|
509
655
|
|
|
510
|
-
|
|
656
|
+
1. **Function calls** - `fn(args)`
|
|
657
|
+
2. **Array/Object access** - `arr[index]`, `obj.property`
|
|
658
|
+
3. **Unary operators** - `not`, `!`, `-` (negation)
|
|
659
|
+
4. **Exponentiation** - `^` (right-associative)
|
|
660
|
+
5. **Multiplication, Division, Modulo** - `*`, `/`, `%`
|
|
661
|
+
6. **Addition, Subtraction** - `+`, `-`
|
|
662
|
+
7. **String concatenation** - `++`
|
|
663
|
+
8. **Comparison operators** - `<`, `>`, `<=`, `>=`
|
|
664
|
+
9. **Equality operators** - `==`, `!=`, `identical?`
|
|
665
|
+
10. **Logical AND** - `&&`
|
|
666
|
+
11. **Logical OR** - `||`
|
|
667
|
+
12. **Null coalescing** - `??`
|
|
668
|
+
13. **Ternary conditional** - `condition ? true-value : false-value`
|
|
511
669
|
|
|
512
|
-
|
|
670
|
+
### Examples
|
|
513
671
|
|
|
514
672
|
```lits
|
|
515
|
-
//
|
|
516
|
-
|
|
673
|
+
// Comparison and logical operators
|
|
674
|
+
5 > 3 && 2 < 4; // => true
|
|
675
|
+
5 > 3 || 2 > 4; // => true
|
|
517
676
|
|
|
518
|
-
//
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|> map(_, -> $ * $)
|
|
522
|
-
|> reduce(_, +, 0);
|
|
523
|
-
// => 35
|
|
524
|
-
|
|
525
|
-
// Simple transformations
|
|
526
|
-
"hello world"
|
|
527
|
-
|> upper-case
|
|
528
|
-
|> split(_, " ")
|
|
529
|
-
|> reverse
|
|
530
|
-
|> join(_, "-");
|
|
531
|
-
// => "WORLD-HELLO"
|
|
532
|
-
|
|
533
|
-
// Mathematical operations
|
|
534
|
-
10
|
|
535
|
-
|> +(_, 5)
|
|
536
|
-
|> *(_, 2)
|
|
537
|
-
|> /(_, 3);
|
|
538
|
-
// => 10 (10 + 5 = 15, 15 * 2 = 30, 30 / 3 = 10)
|
|
539
|
-
|
|
540
|
-
// Data processing pipeline
|
|
541
|
-
{ numbers: [1, 2, 3, 4, 5], multiplier: 3 }
|
|
542
|
-
|> get(_, "numbers")
|
|
543
|
-
|> filter(_, even?)
|
|
544
|
-
|> map(_, *(_, 3))
|
|
545
|
-
|> reduce(_, +, 0);
|
|
546
|
-
// => 18 (even numbers [2, 4] -> [6, 12] -> sum = 18)
|
|
677
|
+
// Ternary has low precedence
|
|
678
|
+
let x = !:random-int(0, 10);
|
|
679
|
+
x + 3 > 4 ? 1 : 0; // => (x + 3) > 4 ? 1 : 0
|
|
547
680
|
```
|
|
548
681
|
|
|
549
682
|
## Built-in Functions
|
|
@@ -577,12 +710,7 @@ export let square = x -> x * x;
|
|
|
577
710
|
### Factorial
|
|
578
711
|
|
|
579
712
|
```lits
|
|
580
|
-
let factorial = n ->
|
|
581
|
-
if n <= 1 then
|
|
582
|
-
1
|
|
583
|
-
else
|
|
584
|
-
n * self(n - 1)
|
|
585
|
-
end;
|
|
713
|
+
let factorial = n -> n <= 1 ? 1 : n * self(n - 1);
|
|
586
714
|
|
|
587
715
|
factorial(5) // => 120
|
|
588
716
|
```
|
|
@@ -605,99 +733,67 @@ let oddSum = numbers
|
|
|
605
733
|
// => 25
|
|
606
734
|
```
|
|
607
735
|
|
|
608
|
-
###
|
|
736
|
+
### String Processing
|
|
609
737
|
|
|
610
738
|
```lits
|
|
611
|
-
let
|
|
612
|
-
|
|
613
|
-
// Update age
|
|
614
|
-
let older = assoc(person, "age", 31);
|
|
739
|
+
let text = "Hello, World! How are you today?";
|
|
615
740
|
|
|
616
|
-
//
|
|
617
|
-
let
|
|
741
|
+
// Word count
|
|
742
|
+
let wordCount = text
|
|
743
|
+
|> split(_, #"\s+")
|
|
744
|
+
|> count(_);
|
|
745
|
+
// => 6
|
|
618
746
|
|
|
619
|
-
//
|
|
620
|
-
let
|
|
621
|
-
|>
|
|
622
|
-
|>
|
|
747
|
+
// Uppercase words longer than 4 characters
|
|
748
|
+
let longWords = text
|
|
749
|
+
|> split(_, #"\s+")
|
|
750
|
+
|> filter(_, -> count($) > 4)
|
|
751
|
+
|> map(_, upper-case);
|
|
752
|
+
// => ["HELLO,", "WORLD!", "TODAY?"]
|
|
623
753
|
```
|
|
624
754
|
|
|
625
|
-
###
|
|
626
|
-
|
|
627
|
-
#### Switch (for matching against a single value)
|
|
755
|
+
### Data Transformation
|
|
628
756
|
|
|
629
757
|
```lits
|
|
630
|
-
let
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
case 60 then "D"
|
|
636
|
-
end ?? "F";
|
|
758
|
+
let users = [
|
|
759
|
+
{ name: "Alice", age: 30, department: "Engineering" },
|
|
760
|
+
{ name: "Bob", age: 25, department: "Marketing" },
|
|
761
|
+
{ name: "Charlie", age: 35, department: "Engineering" }
|
|
762
|
+
];
|
|
637
763
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
#### Cond (for testing different conditions)
|
|
651
|
-
|
|
652
|
-
```lits
|
|
653
|
-
let describe = x ->
|
|
654
|
-
cond
|
|
655
|
-
case null?(x) then "nothing"
|
|
656
|
-
case number?(x) then "a number: " ++ str(x)
|
|
657
|
-
case string?(x) then "text: " ++ x
|
|
658
|
-
case array?(x) then "list of " ++ str(count(x)) ++ " items"
|
|
659
|
-
end ?? "unknown type";
|
|
660
|
-
|
|
661
|
-
describe(42); // => "a number: 42"
|
|
662
|
-
describe([1,2,3]); // => "list of 3 items"
|
|
663
|
-
|
|
664
|
-
// Grade ranges
|
|
665
|
-
let gradeToLetter = score ->
|
|
666
|
-
cond
|
|
667
|
-
case score >= 90 then "A"
|
|
668
|
-
case score >= 80 then "B"
|
|
669
|
-
case score >= 70 then "C"
|
|
670
|
-
case score >= 60 then "D"
|
|
671
|
-
end ?? "F";
|
|
672
|
-
|
|
673
|
-
gradeToLetter(85); // => "B"
|
|
674
|
-
gradeToLetter(55); // => "F"
|
|
764
|
+
// Group by department and get average age
|
|
765
|
+
let grouped = users |> group-by(_, "department");
|
|
766
|
+
let departmentAges = grouped
|
|
767
|
+
|> entries(_)
|
|
768
|
+
|> map(_, ([dept, people]) -> {
|
|
769
|
+
let ages = people |> map(_, "age");
|
|
770
|
+
let total = ages |> reduce(_, +, 0);
|
|
771
|
+
[dept, total / count(ages)]
|
|
772
|
+
})
|
|
773
|
+
|> (pairs -> zipmap(map(pairs, 0), map(pairs, 1)));
|
|
774
|
+
// => { "Engineering": 32.5, "Marketing": 25 }
|
|
675
775
|
```
|
|
676
776
|
|
|
677
777
|
## JavaScript Interoperability
|
|
678
778
|
|
|
679
|
-
|
|
779
|
+
### Using Lits in JavaScript
|
|
680
780
|
|
|
681
781
|
```javascript
|
|
682
|
-
import { Lits } from 'lits';
|
|
782
|
+
import { Lits } from '@mojir/lits';
|
|
683
783
|
|
|
684
|
-
// Create a Lits instance
|
|
685
784
|
const lits = new Lits();
|
|
686
785
|
|
|
687
|
-
//
|
|
688
|
-
const
|
|
689
|
-
console.log(
|
|
786
|
+
// Basic usage
|
|
787
|
+
const result1 = lits.run('+(1, 2, 3)');
|
|
788
|
+
console.log(result1); // 6
|
|
690
789
|
|
|
691
|
-
//
|
|
790
|
+
// Provide JavaScript values
|
|
692
791
|
const result2 = lits.run('name ++ " is " ++ str(age)', {
|
|
693
|
-
values: {
|
|
694
|
-
name: "John",
|
|
695
|
-
age: 30
|
|
696
|
-
}
|
|
792
|
+
values: { name: 'John', age: 30 }
|
|
697
793
|
});
|
|
698
794
|
console.log(result2); // "John is 30"
|
|
699
795
|
|
|
700
|
-
// Expose JavaScript functions
|
|
796
|
+
// Expose JavaScript functions
|
|
701
797
|
const result3 = lits.run('myAlert("Hello from Lits!")', {
|
|
702
798
|
jsFunctions: {
|
|
703
799
|
myAlert: {
|