@mojir/lits 2.1.32 → 2.1.34

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Lits
2
2
 
3
- Lits is a lexically scoped pure functional language with algebraic notation. It combines the power of functional programming with an intuitive, readable syntax.
3
+ Lits is a lexically scoped pure functional language with algebraic notation. It combines the power of functional programming with an intuitive, readable syntax that makes complex operations simple and expressive.
4
4
 
5
5
  Try it in the [Lits Playground](https://mojir.github.io/lits/).
6
6
 
@@ -10,50 +10,80 @@ Try it in the [Lits Playground](https://mojir.github.io/lits/).
10
10
  - **JavaScript interoperability** - JavaScript values and functions can easily be exposed in Lits
11
11
  - **First-class functions** - Functions are treated as values that can be passed to other functions
12
12
  - **Algebraic notation** - All operators can be used as functions, and functions that take two parameters can be used as operators
13
- - **Clojure-inspired functions** - Most core functions are inspired by Clojure
14
13
  - **Comprehensive standard library** - Rich set of functions for collections, math, strings, and more
15
14
  - **Structural equality** - Objects are compared by value, not by reference
16
15
  - **Destructuring** - Extract values from complex data structures with ease
16
+ - **Lexical scoping** - Variables are scoped to their defining context
17
17
 
18
18
  ## Installation
19
19
 
20
- *[Add installation instructions here]*
20
+ ### As a Library
21
+
22
+ ```bash
23
+ npm install @mojir/lits
24
+ ```
25
+
26
+ ### CLI Tool
27
+
28
+ Install globally to use the Lits command-line interface:
29
+
30
+ ```bash
31
+ npm install --global @mojir/lits
32
+ ```
33
+
34
+ #### CLI Usage
35
+
36
+ ```bash
37
+ # Start an interactive REPL session
38
+ $ lits
39
+
40
+ # Evaluate Lits code directly
41
+ $ lits -e "5 + 3"
42
+ $ lits -e "[1, 2, 3, 4] filter odd? map inc"
43
+
44
+ # Run a Lits file
45
+ $ lits -f script.lits
46
+ $ lits -f examples/factorial.lits
47
+
48
+ # Get help
49
+ $ lits --help
50
+ ```
51
+
52
+ The REPL provides an interactive environment where you can experiment with Lits code, test functions, and explore the language features in real-time.
21
53
 
22
54
  ## Quick Start
23
55
 
24
56
  Here's a simple example to get you started:
25
57
 
26
- ```
58
+ ```lits
27
59
  // Defining a function
28
- function square(x)
29
- x * x
30
- end;
60
+ let square = x -> x * x;
31
61
 
32
62
  // Using the function
33
- let result := square(5);
63
+ let result = square(5);
34
64
  // => 25
35
65
 
36
66
  // Using function as an operator
37
- let squares := [1, 2, 3, 4, 5] map square;
67
+ let squares = [1, 2, 3, 4, 5] map square;
38
68
  // => [1, 4, 9, 16, 25]
39
69
 
40
70
  // Using operator as a function
41
- let sum := +([1, 2, 3, 4, 5]);
71
+ let sum = +([1, 2, 3, 4, 5]);
42
72
  // => 15
43
73
  ```
44
74
 
45
- ## Syntax
75
+ ## Basic Syntax
46
76
 
47
- ### Basic Data Types
77
+ ### Data Types
48
78
 
49
- ```
79
+ ```lits
50
80
  // Numbers
51
- 42 // integer
52
- 3.14 // float
53
- 0xFFFF // hexadecimal
54
- 0b1100 // binary
55
- 0o77 // octal
56
- -2.3e-2 // scientific notation
81
+ 42 // integer
82
+ 3.14 // float
83
+ 0xFFFF // hexadecimal
84
+ 0b1100 // binary
85
+ 0o77 // octal
86
+ -2.3e-2 // scientific notation
57
87
 
58
88
  // Strings
59
89
  "Hello, world!"
@@ -69,356 +99,661 @@ null
69
99
  [1, 2, 3, 4]
70
100
 
71
101
  // Objects
72
- { name := "John", age := 30 }
102
+ { name: "John", age: 30 }
103
+
104
+ // Regular expressions
105
+ #"pattern"
73
106
  ```
74
107
 
75
- ### Builtin Number Symbols
108
+ ### Mathematical Constants
76
109
 
77
- Lits provides a set of predefined mathematical constants that can be used directly in your code:
110
+ Lits provides predefined mathematical constants:
78
111
 
79
- ```
80
- // Mathematical constants
112
+ ```lits
81
113
  PI // => 3.141592653589793
82
114
  π // => 3.141592653589793 (Unicode alternative)
83
- -PI // => -3.141592653589793
84
- -π // => -3.141592653589793
85
-
86
115
  E // => 2.718281828459045 (Euler's number)
87
116
  ε // => 2.718281828459045 (Unicode alternative)
88
- -E // => -2.718281828459045
89
- -ε // => -2.718281828459045
90
-
91
117
  PHI // => 1.618033988749895 (Golden ratio)
92
118
  φ // => 1.618033988749895 (Unicode alternative)
93
- -PHI // => -1.618033988749895
94
- -φ // => -1.618033988749895
95
119
 
96
120
  // Infinity values
97
121
  POSITIVE_INFINITY // => Infinity
98
122
  ∞ // => Infinity (Unicode alternative)
99
123
  NEGATIVE_INFINITY // => -Infinity
100
- -∞ // => -Infinity (Unicode alternative)
101
124
 
102
- // Integer limits
125
+ // Integer and float limits
103
126
  MAX_SAFE_INTEGER // => 9007199254740991
104
127
  MIN_SAFE_INTEGER // => -9007199254740991
105
-
106
- // Floating point limits
107
- MAX_VALUE // => 1.7976931348623157e+308
108
- MIN_VALUE // => 5e-324
128
+ MAX_VALUE // => 1.7976931348623157e+308
129
+ MIN_VALUE // => 5e-324
109
130
 
110
131
  // Not a Number
111
132
  NaN // => NaN
112
133
  ```
113
134
 
114
- These constants can be used anywhere a number value is expected and help make mathematical code more readable and elegant.
135
+ ## Special Expressions
115
136
 
116
137
  ### Variable Binding
117
138
 
118
- ```
119
- // Let expression
120
- let x := 10;
139
+ #### Let
140
+
141
+ ```lits
142
+ // Simple binding
143
+ let x = 10;
121
144
  // => 10
122
145
 
123
146
  // Variables are immutable
124
- let x := 20; // Error: x is already defined
147
+ let x = 20; // Error: x is already defined
125
148
 
126
- // But can be shadowed in inner scopes
127
- let y := do
128
- let x := 20;
149
+ // Shadowing in inner scopes
150
+ let y = {
151
+ let x = 20;
129
152
  x
130
- end;
153
+ };
131
154
  // => 20, outer x is still 10
132
155
  ```
133
156
 
134
- ### Functions
157
+ #### Destructuring
158
+
159
+ ```lits
160
+ // Object destructuring
161
+ let { name, age } = { name: "John", age: 30 };
162
+ // name => "John", age => 30
135
163
 
164
+ // Array destructuring
165
+ let [first, second] = [1, 2, 3, 4];
166
+ // first => 1, second => 2
167
+
168
+ // With default values
169
+ let { name = "Unknown", age = 0 } = { name: "John" };
170
+ // name => "John", age => 0
171
+
172
+ // Rest patterns
173
+ let [head, ...tail] = [1, 2, 3, 4];
174
+ // head => 1, tail => [2, 3, 4]
175
+
176
+ // Destructuring in function parameters
177
+ let displayPerson = ({name, age}) ->
178
+ name ++ " is " ++ str(age) ++ " years old";
179
+
180
+ displayPerson({ name: "John", age: 30 });
181
+ // => "John is 30 years old"
136
182
  ```
137
- // Standard function definition
138
- function add(a, b)
139
- a + b
140
- end;
141
183
 
142
- // Lambda functions
143
- let add := (a, b) -> a + b;
184
+ ### Functions
185
+
186
+ #### Lambda Functions
187
+
188
+ ```lits
189
+ // Multi-parameter lambda
190
+ let add = (a, b) -> a + b;
144
191
 
145
- // Short form with positional arguments
146
- let add := -> $1 + $2;
192
+ // Single parameter (parentheses optional)
193
+ let square = x -> x * x;
147
194
 
148
- // Single argument short form
149
- let cube := x -> x ** 3;
150
- let fourth := -> $ ** 4;
195
+ // No parameters
196
+ let constant = () -> 42;
197
+
198
+ // Positional arguments
199
+ let add = -> $1 + $2;
200
+
201
+ // Single positional argument
202
+ let square = -> $ * $;
203
+
204
+ // Self-reference for recursion
205
+ let factorial = n ->
206
+ if n <= 1 then
207
+ 1
208
+ else
209
+ n * self(n - 1)
210
+ end;
151
211
  ```
152
212
 
153
213
  ### Control Flow
154
214
 
155
- ```
215
+ #### If/Unless
216
+
217
+ ```lits
156
218
  // If expression
157
219
  if x > 10 then
158
220
  "large"
159
221
  else
160
222
  "small"
161
- end;
223
+ end
162
224
  // => "large" (if x > 10) or "small" (if x <= 10)
163
225
 
164
- // Unless expression (reversed if)
226
+ // If without else returns null
227
+ if false then "never" end
228
+ // => null
229
+
230
+ // Unless (inverted if)
165
231
  unless x > 10 then
166
232
  "small"
167
233
  else
168
234
  "large"
169
- end;
235
+ end
170
236
  // => "small" (if x <= 10) or "large" (if x > 10)
237
+ ```
238
+
239
+ #### Cond
240
+
241
+ ```lits
242
+ // Multi-branch conditional
243
+ cond
244
+ case x < 5 then "small"
245
+ case x < 10 then "medium"
246
+ case x < 15 then "large"
247
+ end ?? "extra large"
248
+ // Tests conditions sequentially, returns first truthy match
249
+ ```
171
250
 
172
- // Switch expression
251
+ #### Switch
252
+
253
+ ```lits
254
+ // Switch on value
173
255
  switch x
174
256
  case 0 then "zero"
175
257
  case 1 then "one"
176
258
  case 2 then "two"
177
- end;
178
- // => "zero" (if x = 0), "one" (if x = 1), "two" (if x = 2), or null (otherwise)
259
+ end
260
+ // => "zero" (if x = 0), "one" (if x = 1), etc., or null if no match
261
+ ```
179
262
 
180
- // Cond expression
181
- cond
182
- case val < 5 then "S"
183
- case val < 10 then "M"
184
- case val < 15 then "L"
185
- end ?? "No match";
186
- // => "S" (if val < 5), "M" (if 5 <= val < 10), "L" (if 10 <= val < 15), or "No match" (otherwise)
263
+ ### Loops and Iteration
264
+
265
+ #### For Comprehensions
266
+
267
+ ```lits
268
+ // Simple iteration
269
+ for (x in [1, 2, 3, 4]) -> x * 2
270
+ // => [2, 4, 6, 8]
271
+
272
+ // With filtering
273
+ for (x in [1, 2, 3, 4] when odd?(x)) -> x * 2
274
+ // => [2, 6]
275
+
276
+ // With while condition
277
+ for (x in [1, 2, 3, 4] while x < 3) -> x * 2
278
+ // => [2, 4]
279
+
280
+ // With let bindings
281
+ for (x in [1, 2, 3] let doubled = x * 2) -> doubled + 1
282
+ // => [3, 5, 7]
283
+
284
+ // Multiple iterators
285
+ for (x in [1, 2], y in [10, 20]) -> x + y
286
+ // => [11, 21, 12, 22]
187
287
 
188
- // Try/catch
288
+ // Object iteration
289
+ for ([key, value] in { a: 1, b: 2 }) -> key ++ ":" ++ str(value)
290
+ // => ["a:1", "b:2"]
291
+ ```
292
+
293
+ #### Doseq (Side Effects)
294
+
295
+ ```lits
296
+ // For side effects only (returns null)
297
+ doseq (x in [1, 2, 3]) -> write!(x)
298
+ // Prints: 1 2 3, returns null
299
+ ```
300
+
301
+ #### Loop (Tail Recursion)
302
+
303
+ ```lits
304
+ // Loop with recur for tail recursion
305
+ loop (n = 5, acc = 1) -> {
306
+ if zero?(n) then
307
+ acc
308
+ else
309
+ recur(n - 1, acc * n)
310
+ end
311
+ }
312
+ // => 120 (factorial of 5)
313
+ ```
314
+
315
+ ### Error Handling
316
+
317
+ #### Try/Catch
318
+
319
+ ```lits
320
+ // Basic try/catch
321
+ try
322
+ riskyOperation()
323
+ catch
324
+ "Something went wrong"
325
+ end
326
+
327
+ // With error binding
189
328
  try
190
329
  riskyOperation()
191
330
  catch (error)
192
331
  "Error: " ++ error.message
193
- end;
194
- // => result of riskyOperation() or error message if an exception occurs
332
+ end
195
333
  ```
196
334
 
197
- ### List Comprehension
335
+ #### Throw
336
+
337
+ ```lits
338
+ // Throwing errors
339
+ throw("Custom error message")
198
340
 
341
+ // In context
342
+ let divide = (a, b) ->
343
+ if zero?(b) then
344
+ throw("Division by zero")
345
+ else
346
+ a / b
347
+ end;
199
348
  ```
200
- // Simple for comprehension
201
- for
202
- each x of [0, 1, 2, 3, 4, 5], let y := x * 3, while even?(y)
203
- do
204
- y
205
- end;
206
- // => [0, 6, 12]
207
349
 
208
- // Multiple generators
209
- for (
210
- each x of [1, 2, 3]
211
- each y of [1, 2, 3], when x <= y
212
- z of [1, 2, 3]
213
- )
214
- [x, y, z]
215
- end;
216
- // => [[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2, 1], [1, 2, 2], [1, 2, 3], [1, 3, 1], [1, 3, 2], [1, 3, 3],
217
- // [2, 2, 1], [2, 2, 2], [2, 2, 3], [2, 3, 1], [2, 3, 2], [2, 3, 3],
218
- // [3, 3, 1], [3, 3, 2], [3, 3, 3]]
350
+ ### Logical Operators
351
+
352
+ #### And/Or
353
+
354
+ ```lits
355
+ // Logical AND (short-circuit)
356
+ true && "second value" // => "second value"
357
+ false && "never reached" // => false
358
+
359
+ // Logical OR (short-circuit)
360
+ false || "default value" // => "default value"
361
+ true || "never reached" // => true
362
+
363
+ // Multiple arguments
364
+ &&(true, true, "all true") // => "all true"
365
+ ||(false, false, "found") // => "found"
219
366
  ```
220
367
 
221
- ### Destructuring
368
+ #### Null Coalescing
222
369
 
370
+ ```lits
371
+ // Null coalescing operator
372
+ null ?? "default" // => "default"
373
+ undefined ?? "default" // => "default"
374
+ 0 ?? "default" // => 0 (only null/undefined are coalesced)
375
+ false ?? "default" // => false
376
+ "" ?? "default" // => ""
223
377
  ```
224
- // Object destructuring
225
- let { name, age } := { name := "John", age := 30 };
226
- // name => "John"
227
- // age => 30
228
378
 
229
- // Array destructuring
230
- let [nbr1, nbr2] := [1, 2, 3, 4];
231
- // nbr1 => 1
232
- // nbr2 => 2
379
+ ### Blocks
233
380
 
234
- // Destructuring in function parameters
235
- function displayPerson({name, age})
236
- name ++ " is " ++ str(age) ++ " years old"
237
- end;
381
+ ```lits
382
+ // Block expressions
383
+ {
384
+ let a = 1 + 2 + 3;
385
+ let b = x -> x * x;
386
+ b(a)
387
+ }
388
+ // => 36 (returns value of last expression)
389
+ ```
238
390
 
239
- displayPerson({ name := "John", age := 30 });
240
- // => "John is 30 years old"
391
+ ### Arrays and Objects
392
+
393
+ #### Array Construction
394
+
395
+ ```lits
396
+ // Array literal
397
+ [1, 2, 3, 4]
398
+
399
+ // Array function
400
+ array(1, 2, 3, 4)
401
+
402
+ // With spread
403
+ [1, 2, ...[3, 4, 5], 6]
404
+ // => [1, 2, 3, 4, 5, 6]
405
+ ```
406
+
407
+ #### Object Construction
408
+
409
+ ```lits
410
+ // Object literal
411
+ { name: "John", age: 30 }
412
+
413
+ // Object function
414
+ object("name", "John", "age", 30)
415
+
416
+ // With spread
417
+ let defaults = { type: "Person", active: true };
418
+ {
419
+ ...defaults,
420
+ name: "John",
421
+ age: 30
422
+ }
423
+ // => { type: "Person", active: true, name: "John", age: 30 }
424
+ ```
425
+
426
+ ### Recursion
427
+
428
+ #### Recur
429
+
430
+ ```lits
431
+ // Tail recursion with recur
432
+ let countdown = n -> {
433
+ write!(n);
434
+ if pos?(n) then
435
+ recur(n - 1)
436
+ end
437
+ };
438
+
439
+ countdown(3)
440
+ // Prints: 3 2 1 0
241
441
  ```
242
442
 
243
443
  ## Operators and Functions
244
444
 
245
- ### Function Usage vs Operator Usage
445
+ ### Algebraic Notation
246
446
 
247
447
  All functions that take two parameters can be used as operators:
248
448
 
249
- ```
449
+ ```lits
250
450
  // As a function
251
- max(5, 10);
252
- // => 10
451
+ max(5, 10) // => 10
253
452
 
254
453
  // As an operator
255
- 5 max 10;
256
- // => 10
454
+ 5 max 10 // => 10
257
455
  ```
258
456
 
259
457
  All operators can be used as functions:
260
458
 
261
- ```
459
+ ```lits
262
460
  // As an operator
263
- 5 + 3;
264
- // => 8
461
+ 5 + 3 // => 8
265
462
 
266
463
  // As a function
267
- +(5, 3);
268
- // => 8
269
- ```
464
+ +(5, 3) // => 8
270
465
 
271
- ### Parameter Order
466
+ // Partial application with underscore placeholder
467
+ let add5 = +(5, _);
468
+ add5(3) // => 8
272
469
 
273
- Unlike Clojure, Lits favors subject-first parameter order:
470
+ // Multiple placeholders
471
+ let subtractAndDivide = /(-(_, _), 2);
472
+ subtractAndDivide(10, 3) // => 3.5 (10 - 3 = 7, then 7 / 2 = 3.5)
274
473
 
275
- ```
276
- // Lits
277
- filter([1, 2, 3, 4], odd?);
278
- // => [1, 3]
474
+ // Single placeholder in different positions
475
+ let subtract = -(_, 2);
476
+ subtract(10) // => 8
279
477
 
280
- // Equivalent Clojure
281
- // (filter odd? [1 2 3 4])
478
+ let divide = /(10, _);
479
+ divide(2) // => 5
282
480
  ```
283
481
 
284
- This makes operator usage more readable:
482
+ ### Parameter Order
285
483
 
286
- ```
287
- [1, 2, 3, 4] filter odd?;
288
- // => [1, 3]
289
- ```
484
+ Lits favors subject-first parameter order for better operator chaining:
290
485
 
291
- ## Built-in Functions
486
+ ```lits
487
+ // Function style
488
+ filter([1, 2, 3, 4], odd?) // => [1, 3]
489
+
490
+ // Operator style (more readable)
491
+ [1, 2, 3, 4] filter odd? // => [1, 3]
292
492
 
293
- Lits comes with a comprehensive standard library of functions organized into categories:
493
+ // Chaining
494
+ [1, 2, 3, 4, 5, 6]
495
+ filter odd?
496
+ map square
497
+ reduce +
498
+ // => 35
499
+ ```
294
500
 
295
- ### Collection Functions
296
- `count`, `get`, `get-in`, `contains?`, `assoc`, `assoc-in`, `++`, `not-empty`, `every?`, `not-every?`, `any?`, `not-any?`, `update`, `update-in`
501
+ ### Pipe Operator
297
502
 
298
- ### Array Functions
299
- `array`, `range`, `repeat`, `flatten`, `mapcat`
503
+ The pipe operator `|>` passes the result of the left expression as the first argument to the right function:
300
504
 
301
- ### Sequence Functions
302
- `nth`, `push`, `pop`, `unshift`, `shift`, `slice`, `splice`, `reductions`, `reduce`, `reduce-right`, `map`, `filter`, `position`, `index-of`, `last-index-of`, `some`, `reverse`, `first`, `second`, `last`, `rest`, `next`, `take`, `take-last`, `take-while`, `drop`, `drop-last`, `drop-while`, `sort`, `sort-by`, `distinct`, `remove`, `remove-at`, `split-at`, `split-with`, `frequencies`, `group-by`, `partition`, `partition-all`, `partition-by`, `starts-with?`, `ends-with?`, `interleave`, `interpose`
505
+ ```lits
506
+ // Without pipe operator
507
+ reduce(map(filter([1, 2, 3, 4, 5, 6], odd?), square), +)
303
508
 
304
- ### Math Functions
305
- `+`, `-`, `*`, `/`, `mod`, `%`, `quot`, `inc`, `dec`, `√`, `∛`, `**`, `round`, `trunc`, `floor`, `ceil`, `min`, `max`, `abs`, `sign`, `log`, `log2`, `log10`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh`
509
+ // With pipe operator (much more readable)
510
+ [1, 2, 3, 4, 5, 6]
511
+ |> filter(_, odd?)
512
+ |> map(_, square)
513
+ |> reduce(_, +)
514
+ // => 35
306
515
 
307
- ### Functional Programming
308
- `apply`, `identity`, `partial`, `comp`, `constantly`, `juxt`, `complement`, `every-pred`, `some-pred`, `fnull`
516
+ // Simple transformations
517
+ "hello world"
518
+ |> upper-case
519
+ |> split(_, " ")
520
+ |> reverse
521
+ |> join(_, "-")
522
+ // => "WORLD-HELLO"
309
523
 
310
- ### Object Functions
311
- `dissoc`, `object`, `keys`, `vals`, `entries`, `find`, `merge`, `merge-with`, `zipmap`, `select-keys`
524
+ // Mathematical operations
525
+ 10
526
+ |> +(_, 5)
527
+ |> *(_, 2)
528
+ |> /(_, 3)
529
+ // => 10 (10 + 5 = 15, 15 * 2 = 30, 30 / 3 = 10)
312
530
 
313
- ### String Functions
314
- `string-repeat`, `str`, `number`, `lower-case`, `upper-case`, `trim`, `trim-left`, `trim-right`, `pad-left`, `pad-right`, `split`, `split-lines`, `template`, `to-char-code`, `from-char-code`, `encode-base64`, `decode-base64`, `encode-uri-component`, `decode-uri-component`, `join`, `capitalize`, `blank?`
531
+ // Data processing pipeline
532
+ { numbers: [1, 2, 3, 4, 5], multiplier: 3 }
533
+ |> get(_, "numbers")
534
+ |> filter(_, even?)
535
+ |> map(_, *(_, 3))
536
+ |> reduce(_, +)
537
+ // => 18 (even numbers [2, 4] -> [6, 12] -> sum = 18)
538
+ ```
315
539
 
316
- ### Predicates
317
- `boolean?`, `null?`, `number?`, `string?`, `function?`, `integer?`, `array?`, `object?`, `coll?`, `seq?`, `regexp?`, `zero?`, `pos?`, `neg?`, `even?`, `odd?`, `finite?`, `nan?`, `negative-infinity?`, `positive-infinity?`, `false?`, `true?`, `empty?`, `not-empty?`
540
+ ## Built-in Functions
318
541
 
319
- ### Regular Expressions
320
- `regexp`, `match`, `replace`, `replace-all`
542
+ Lits comes with a comprehensive standard library of functions for:
321
543
 
322
- ### Bitwise Operations
323
- `<<`, `>>`, `>>>`, `~`, `&`, `bit-and-not`, `|`, `^`, `bit-flip`, `bit-clear`, `bit-set`, `bit-test`
544
+ - **Arithmetic and Math**: Basic operations, trigonometry, logarithms, rounding
545
+ - **Collections**: Working with arrays and objects (get, assoc, merge, etc.)
546
+ - **Sequences**: Filtering, mapping, reducing, sorting, and transforming data
547
+ - **Strings**: Manipulation, formatting, encoding, and pattern matching
548
+ - **Predicates**: Type checking and condition testing functions
549
+ - **Functional Programming**: Function composition, partial application, and utilities
550
+ - **Regular Expressions**: Pattern matching and text processing
551
+ - **Bitwise Operations**: Low-level bit manipulation
552
+ - **Assertions**: Testing and validation utilities
324
553
 
325
- ### Assertions
326
- `assert`, `assert=`, `assert!=`, `assert-gt`, `assert-lt`, `assert-gte`, `assert-lte`, `assert-true`, `assert-false`, `assert-truthy`, `assert-falsy`, `assert-null`, `assert-throws`, `assert-throws-error`, `assert-not-throws`
554
+ For a complete reference of all available functions with examples, visit the [Lits Playground](https://mojir.github.io/lits/) where you can explore the interactive documentation and try functions in real-time.
327
555
 
328
556
  ## Modules and Exports
329
557
 
330
- You can export definitions to make them available to other modules:
558
+ ```lits
559
+ // Export variables and functions
560
+ export let PI = 3.14159;
561
+ export let square = x -> x * x;
331
562
 
563
+ // Exported values become available to other modules
332
564
  ```
333
- // Exporting variables
334
- export let magic-number := 42;
335
- // => 42
336
565
 
337
- // Exporting functions
338
- export function square(x)
339
- x * x
340
- end;
341
- ```
566
+ ## Examples
342
567
 
343
- ## API
568
+ ### Factorial
344
569
 
345
- Lits provides a JavaScript API for embedding:
570
+ ```lits
571
+ let factorial = n ->
572
+ if n <= 1 then
573
+ 1
574
+ else
575
+ n * self(n - 1)
576
+ end;
346
577
 
347
- ```javascript
348
- interface Lits {
349
- getRuntimeInfo: () => LitsRuntimeInfo
350
- run: (program: string, params?: ContextParams & FilePathParams) => unknown
351
- context: (programOrAst: string | Ast, params?: ContextParams & FilePathParams) => Context
352
- getUndefinedSymbols: (programOrAst: string | Ast, params: ContextParams) => Set<string>
353
- tokenize: (program: string, tokenizeParams: FilePathParams & MinifyParams) => TokenStream
354
- parse: (tokenStream: TokenStream) => Ast
355
- evaluate: (ast: Ast, params: ContextParams) => unknown
356
- transformSymbols: (tokenStream: TokenStream, transformer: (symbol: string) => string) => TokenStream
357
- untokenize: (tokenStream: TokenStream) => string
358
- apply: (fn: LitsFunction, fnParams: unknown[], params: ContextParams) => unknown
359
- }
578
+ factorial(5) // => 120
360
579
  ```
361
580
 
362
- ## Examples
581
+ ### Array Processing
363
582
 
364
- ### Factorial Function
583
+ ```lits
584
+ let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
365
585
 
366
- ```
367
- function factorial(n)
368
- if n <= 1 then
369
- 1
370
- else
371
- n * factorial(n - 1)
372
- end
373
- end;
586
+ // Get even numbers squared
587
+ let evenSquares = numbers
588
+ filter even?
589
+ map square;
590
+ // => [4, 16, 36, 64, 100]
374
591
 
375
- factorial(5);
376
- // => 120
592
+ // Sum of odd numbers
593
+ let oddSum = numbers
594
+ filter odd?
595
+ reduce +;
596
+ // => 25
377
597
  ```
378
598
 
379
- ### Fibonacci Sequence
599
+ ### Object Manipulation
600
+
601
+ ```lits
602
+ let person = { name: "John", age: 30, city: "New York" };
380
603
 
604
+ // Update age
605
+ let older = assoc(person, "age", 31);
606
+
607
+ // Add new field
608
+ let withJob = assoc(older, "job", "Developer");
609
+
610
+ // Using pipe operator for chaining
611
+ let updated = person
612
+ |> assoc(_, "age", 31)
613
+ |> assoc(_, "job", "Developer");
381
614
  ```
382
- function fib(n)
383
- if n < 2 then
384
- n
385
- else
386
- fib(n - 1) + fib(n - 2)
387
- end
388
- end;
389
615
 
390
- // Generate the first 10 Fibonacci numbers
391
- range(10) map fib;
392
- // => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
616
+ ### Pattern Matching Examples
617
+
618
+ #### Switch (for matching against a single value)
619
+
620
+ ```lits
621
+ let gradeToLetter = grade ->
622
+ switch grade
623
+ case 90 then "A"
624
+ case 80 then "B"
625
+ case 70 then "C"
626
+ case 60 then "D"
627
+ end ?? "F";
628
+
629
+ gradeToLetter(80) // => "B"
630
+ gradeToLetter(55) // => "F"
631
+
632
+ // HTTP status code handling
633
+ let statusMessage = code ->
634
+ switch code
635
+ case 200 then "OK"
636
+ case 404 then "Not Found"
637
+ case 500 then "Internal Server Error"
638
+ end ?? "Unknown Status";
393
639
  ```
394
640
 
395
- ### Working with Collections
641
+ #### Cond (for testing different conditions)
642
+
643
+ ```lits
644
+ let describe = x ->
645
+ cond
646
+ case null?(x) then "nothing"
647
+ case number?(x) then "a number: " ++ str(x)
648
+ case string?(x) then "text: " ++ x
649
+ case array?(x) then "list of " ++ str(count(x)) ++ " items"
650
+ end ?? "unknown type";
651
+
652
+ describe(42) // => "a number: 42"
653
+ describe([1,2,3]) // => "list of 3 items"
396
654
 
655
+ // Grade ranges
656
+ let gradeToLetter = score ->
657
+ cond
658
+ case score >= 90 then "A"
659
+ case score >= 80 then "B"
660
+ case score >= 70 then "C"
661
+ case score >= 60 then "D"
662
+ end ?? "F";
663
+
664
+ gradeToLetter(85) // => "B"
665
+ gradeToLetter(55) // => "F"
397
666
  ```
398
- let people := [
399
- { name := "Alice", age := 25 },
400
- { name := "Bob", age := 30 },
401
- { name := "Charlie", age := 35 },
402
- { name := "Diana", age := 40 }
403
- ];
404
667
 
405
- // Get all names
406
- people map (p -> p.name);
407
- // => ["Alice", "Bob", "Charlie", "Diana"]
668
+ ## JavaScript Interoperability
408
669
 
409
- // Get people older than 30
410
- people filter (p -> p.age > 30);
411
- // => [{ name := "Charlie", age := 35 }, { name := "Diana", age := 40 }]
670
+ Lits provides a comprehensive JavaScript API for embedding and integration:
412
671
 
413
- // Calculate average age
414
- (people map (p -> p.age) reduce +) / count(people);
415
- // => 32.5
672
+ ```javascript
673
+ import { Lits } from 'lits';
674
+
675
+ // Create a Lits instance
676
+ const lits = new Lits();
677
+
678
+ // Run Lits code
679
+ const result = lits.run('+(5, 3)');
680
+ console.log(result); // 8
681
+
682
+ // Pass JavaScript values to Lits
683
+ const result2 = lits.run('name ++ " is " ++ str(age)', {
684
+ values: {
685
+ name: "John",
686
+ age: 30
687
+ }
688
+ });
689
+ console.log(result2); // "John is 30"
690
+
691
+ // Expose JavaScript functions to Lits
692
+ const result3 = lits.run('myAlert("Hello from Lits!")', {
693
+ jsFunctions: {
694
+ myAlert: {
695
+ fn: (message) => console.log(`Alert: ${message}`),
696
+ arity: { min: 1, max: 1 }
697
+ }
698
+ }
699
+ });
700
+
701
+ // Parse and evaluate separately for better performance
702
+ const tokens = lits.tokenize('+(5, 3)');
703
+ const ast = lits.parse(tokens);
704
+ const result4 = lits.evaluate(ast, {});
705
+ ```
706
+
707
+ ### Lits Class Methods
708
+
709
+ ```typescript
710
+ interface Lits {
711
+ // Execute Lits code directly
712
+ run(program: string, params?: ContextParams & FilePathParams): unknown
713
+
714
+ // Get execution context after running code
715
+ context(programOrAst: string | Ast, params?: ContextParams & FilePathParams): Context
716
+
717
+ // Find undefined symbols in code
718
+ getUndefinedSymbols(programOrAst: string | Ast, params?: ContextParams): Set<string>
719
+
720
+ // Parse pipeline
721
+ tokenize(program: string, params?: FilePathParams & MinifyParams): TokenStream
722
+ parse(tokenStream: TokenStream): Ast
723
+ evaluate(ast: Ast, params: ContextParams): unknown
724
+
725
+ // Apply Lits function with JavaScript arguments
726
+ apply(fn: LitsFunction, fnParams: unknown[], params?: ContextParams): unknown
727
+
728
+ // Utility methods
729
+ transformSymbols(tokenStream: TokenStream, transformer: (symbol: string) => string): TokenStream
730
+ untokenize(tokenStream: TokenStream): string
731
+ getRuntimeInfo(): LitsRuntimeInfo
732
+ }
416
733
  ```
417
734
 
418
- ## Contributing
735
+ ### Context Parameters
736
+
737
+ ```typescript
738
+ interface ContextParams {
739
+ globalContext?: Context // Global variable context
740
+ contexts?: Context[] // Additional context layers
741
+ values?: Record<string, unknown> // JavaScript values to expose
742
+ jsFunctions?: Record<string, JsFunction> // JavaScript functions to expose
743
+ globalModuleScope?: boolean // Module scoping behavior
744
+ }
745
+
746
+ interface JsFunction {
747
+ fn: (...args: any[]) => unknown // The JavaScript function
748
+ arity?: Arity // Function arity constraints
749
+ docString?: string // Documentation
750
+ }
751
+ ```
419
752
 
420
- *[Add contribution guidelines here]*
753
+ ## Learn More
421
754
 
422
- ## License
755
+ - Try Lits in the [online playground](https://mojir.github.io/lits/)
756
+ - Explore the comprehensive function reference
757
+ - Check out more complex examples in the documentation
423
758
 
424
- *[Add license information here]*
759
+ Lits combines the elegance of functional programming with practical syntax, making it perfect for data transformation, mathematical computation, and any scenario where immutability and expressiveness are valued.