@mojir/lits 2.1.33 → 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
 
@@ -13,18 +13,51 @@ Try it in the [Lits Playground](https://mojir.github.io/lits/).
13
13
  - **Comprehensive standard library** - Rich set of functions for collections, math, strings, and more
14
14
  - **Structural equality** - Objects are compared by value, not by reference
15
15
  - **Destructuring** - Extract values from complex data structures with ease
16
+ - **Lexical scoping** - Variables are scoped to their defining context
16
17
 
17
18
  ## Installation
18
19
 
19
- *[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.
20
53
 
21
54
  ## Quick Start
22
55
 
23
56
  Here's a simple example to get you started:
24
57
 
25
- ```
58
+ ```lits
26
59
  // Defining a function
27
- square = x -> x * x;
60
+ let square = x -> x * x;
28
61
 
29
62
  // Using the function
30
63
  let result = square(5);
@@ -39,18 +72,18 @@ let sum = +([1, 2, 3, 4, 5]);
39
72
  // => 15
40
73
  ```
41
74
 
42
- ## Syntax
75
+ ## Basic Syntax
43
76
 
44
- ### Basic Data Types
77
+ ### Data Types
45
78
 
46
- ```
79
+ ```lits
47
80
  // Numbers
48
- 42 // integer
49
- 3.14 // float
50
- 0xFFFF // hexadecimal
51
- 0b1100 // binary
52
- 0o77 // octal
53
- -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
54
87
 
55
88
  // Strings
56
89
  "Hello, world!"
@@ -67,323 +100,660 @@ null
67
100
 
68
101
  // Objects
69
102
  { name: "John", age: 30 }
103
+
104
+ // Regular expressions
105
+ #"pattern"
70
106
  ```
71
107
 
72
- ### Builtin Number Symbols
108
+ ### Mathematical Constants
73
109
 
74
- Lits provides a set of predefined mathematical constants that can be used directly in your code:
110
+ Lits provides predefined mathematical constants:
75
111
 
76
- ```
77
- // Mathematical constants
112
+ ```lits
78
113
  PI // => 3.141592653589793
79
114
  π // => 3.141592653589793 (Unicode alternative)
80
- -PI // => -3.141592653589793
81
- -π // => -3.141592653589793
82
-
83
115
  E // => 2.718281828459045 (Euler's number)
84
116
  ε // => 2.718281828459045 (Unicode alternative)
85
- -E // => -2.718281828459045
86
- -ε // => -2.718281828459045
87
-
88
117
  PHI // => 1.618033988749895 (Golden ratio)
89
118
  φ // => 1.618033988749895 (Unicode alternative)
90
- -PHI // => -1.618033988749895
91
- -φ // => -1.618033988749895
92
119
 
93
120
  // Infinity values
94
121
  POSITIVE_INFINITY // => Infinity
95
122
  ∞ // => Infinity (Unicode alternative)
96
123
  NEGATIVE_INFINITY // => -Infinity
97
- -∞ // => -Infinity (Unicode alternative)
98
124
 
99
- // Integer limits
125
+ // Integer and float limits
100
126
  MAX_SAFE_INTEGER // => 9007199254740991
101
127
  MIN_SAFE_INTEGER // => -9007199254740991
102
-
103
- // Floating point limits
104
- MAX_VALUE // => 1.7976931348623157e+308
105
- MIN_VALUE // => 5e-324
128
+ MAX_VALUE // => 1.7976931348623157e+308
129
+ MIN_VALUE // => 5e-324
106
130
 
107
131
  // Not a Number
108
132
  NaN // => NaN
109
133
  ```
110
134
 
111
- These constants can be used anywhere a number value is expected and help make mathematical code more readable and elegant.
135
+ ## Special Expressions
112
136
 
113
137
  ### Variable Binding
114
138
 
115
- ```
116
- // Let expression
139
+ #### Let
140
+
141
+ ```lits
142
+ // Simple binding
117
143
  let x = 10;
118
144
  // => 10
119
145
 
120
146
  // Variables are immutable
121
147
  let x = 20; // Error: x is already defined
122
148
 
123
- // But can be shadowed in inner scopes
124
- let y = do
149
+ // Shadowing in inner scopes
150
+ let y = {
125
151
  let x = 20;
126
152
  x
127
- end;
153
+ };
128
154
  // => 20, outer x is still 10
129
155
  ```
130
156
 
131
- ### Functions
157
+ #### Destructuring
158
+
159
+ ```lits
160
+ // Object destructuring
161
+ let { name, age } = { name: "John", age: 30 };
162
+ // name => "John", age => 30
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";
132
179
 
180
+ displayPerson({ name: "John", age: 30 });
181
+ // => "John is 30 years old"
133
182
  ```
134
- // Lambda functions
183
+
184
+ ### Functions
185
+
186
+ #### Lambda Functions
187
+
188
+ ```lits
189
+ // Multi-parameter lambda
135
190
  let add = (a, b) -> a + b;
136
191
 
137
- // Short form with positional arguments
192
+ // Single parameter (parentheses optional)
193
+ let square = x -> x * x;
194
+
195
+ // No parameters
196
+ let constant = () -> 42;
197
+
198
+ // Positional arguments
138
199
  let add = -> $1 + $2;
139
200
 
140
- // Single argument short form
141
- let cube = x -> x ** 3;
142
- let fourth = -> $ ** 4;
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;
143
211
  ```
144
212
 
145
213
  ### Control Flow
146
214
 
147
- ```
215
+ #### If/Unless
216
+
217
+ ```lits
148
218
  // If expression
149
219
  if x > 10 then
150
220
  "large"
151
221
  else
152
222
  "small"
223
+ end
153
224
  // => "large" (if x > 10) or "small" (if x <= 10)
154
225
 
155
- // Unless expression (reversed if)
226
+ // If without else returns null
227
+ if false then "never" end
228
+ // => null
229
+
230
+ // Unless (inverted if)
156
231
  unless x > 10 then
157
232
  "small"
158
233
  else
159
234
  "large"
235
+ end
160
236
  // => "small" (if x <= 10) or "large" (if x > 10)
237
+ ```
238
+
239
+ #### Cond
161
240
 
162
- // Switch expression
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
+ ```
250
+
251
+ #### Switch
252
+
253
+ ```lits
254
+ // Switch on value
163
255
  switch x
164
256
  case 0 then "zero"
165
257
  case 1 then "one"
166
258
  case 2 then "two"
167
- end;
168
- // => "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
+ ```
169
262
 
170
- // Cond expression
171
- cond
172
- case val < 5 then "S"
173
- case val < 10 then "M"
174
- case val < 15 then "L"
175
- end ?? "No match";
176
- // => "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]
177
279
 
178
- // Try/catch
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]
287
+
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
179
328
  try
180
329
  riskyOperation()
181
330
  catch (error)
182
331
  "Error: " ++ error.message
183
- // => result of riskyOperation() or error message if an exception occurs
332
+ end
333
+ ```
334
+
335
+ #### Throw
336
+
337
+ ```lits
338
+ // Throwing errors
339
+ throw("Custom error message")
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;
184
348
  ```
185
349
 
186
- ### List Comprehension
350
+ ### Logical Operators
351
+
352
+ #### And/Or
187
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"
188
366
  ```
189
- // Simple for comprehension
190
- TODO
367
+
368
+ #### Null Coalescing
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" // => ""
191
377
  ```
192
378
 
193
- ### Destructuring
379
+ ### Blocks
194
380
 
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)
195
389
  ```
196
- // Object destructuring
197
- let { name, age } = { name: "John", age: 30 };
198
- // name => "John"
199
- // age => 30
200
390
 
201
- // Array destructuring
202
- let [nbr1, nbr2] = [1, 2, 3, 4];
203
- // nbr1 => 1
204
- // nbr2 => 2
391
+ ### Arrays and Objects
205
392
 
206
- // Destructuring in function parameters
207
- let displayPerson = ({name, age}) ->
208
- name ++ " is " ++ str(age) ++ " years old";
393
+ #### Array Construction
209
394
 
210
- displayPerson({ name: "John", age: 30 });
211
- // => "John is 30 years old"
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
212
441
  ```
213
442
 
214
443
  ## Operators and Functions
215
444
 
216
- ### Function Usage vs Operator Usage
445
+ ### Algebraic Notation
217
446
 
218
447
  All functions that take two parameters can be used as operators:
219
448
 
220
- ```
449
+ ```lits
221
450
  // As a function
222
- max(5, 10);
223
- // => 10
451
+ max(5, 10) // => 10
224
452
 
225
453
  // As an operator
226
- 5 max 10;
227
- // => 10
454
+ 5 max 10 // => 10
228
455
  ```
229
456
 
230
457
  All operators can be used as functions:
231
458
 
232
- ```
459
+ ```lits
233
460
  // As an operator
234
- 5 + 3;
235
- // => 8
461
+ 5 + 3 // => 8
236
462
 
237
463
  // As a function
238
- +(5, 3);
239
- // => 8
240
- ```
464
+ +(5, 3) // => 8
241
465
 
242
- ### Parameter Order
466
+ // Partial application with underscore placeholder
467
+ let add5 = +(5, _);
468
+ add5(3) // => 8
243
469
 
244
- 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)
245
473
 
246
- ```
247
- // Lits
248
- filter([1, 2, 3, 4], odd?);
249
- // => [1, 3]
474
+ // Single placeholder in different positions
475
+ let subtract = -(_, 2);
476
+ subtract(10) // => 8
250
477
 
251
- // Unlike for example Clojure
252
- // (filter odd? [1 2 3 4])
478
+ let divide = /(10, _);
479
+ divide(2) // => 5
253
480
  ```
254
481
 
255
- This makes operator usage more readable:
256
-
257
- ```
258
- [1, 2, 3, 4] filter odd?;
259
- // => [1, 3]
260
- ```
482
+ ### Parameter Order
261
483
 
262
- ## Built-in Functions
484
+ Lits favors subject-first parameter order for better operator chaining:
263
485
 
264
- Lits comes with a comprehensive standard library of functions organized into categories:
486
+ ```lits
487
+ // Function style
488
+ filter([1, 2, 3, 4], odd?) // => [1, 3]
265
489
 
266
- ### Collection Functions
267
- `count`, `get`, `get-in`, `contains?`, `assoc`, `assoc-in`, `++`, `not-empty`, `every?`, `not-every?`, `any?`, `not-any?`, `update`, `update-in`
490
+ // Operator style (more readable)
491
+ [1, 2, 3, 4] filter odd? // => [1, 3]
268
492
 
269
- ### Array Functions
270
- `array`, `range`, `repeat`, `flatten`, `mapcat`
493
+ // Chaining
494
+ [1, 2, 3, 4, 5, 6]
495
+ filter odd?
496
+ map square
497
+ reduce +
498
+ // => 35
499
+ ```
271
500
 
272
- ### Sequence Functions
273
- `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`
501
+ ### Pipe Operator
274
502
 
275
- ### Math Functions
276
- `+`, `-`, `*`, `/`, `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`
503
+ The pipe operator `|>` passes the result of the left expression as the first argument to the right function:
277
504
 
278
- ### Functional Programming
279
- `apply`, `identity`, `partial`, `comp`, `constantly`, `juxt`, `complement`, `every-pred`, `some-pred`, `fnull`
505
+ ```lits
506
+ // Without pipe operator
507
+ reduce(map(filter([1, 2, 3, 4, 5, 6], odd?), square), +)
280
508
 
281
- ### Object Functions
282
- `dissoc`, `object`, `keys`, `vals`, `entries`, `find`, `merge`, `merge-with`, `zipmap`, `select-keys`
509
+ // With pipe operator (much more readable)
510
+ [1, 2, 3, 4, 5, 6]
511
+ |> filter(_, odd?)
512
+ |> map(_, square)
513
+ |> reduce(_, +)
514
+ // => 35
283
515
 
284
- ### String Functions
285
- `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?`
516
+ // Simple transformations
517
+ "hello world"
518
+ |> upper-case
519
+ |> split(_, " ")
520
+ |> reverse
521
+ |> join(_, "-")
522
+ // => "WORLD-HELLO"
286
523
 
287
- ### Predicates
288
- `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?`
524
+ // Mathematical operations
525
+ 10
526
+ |> +(_, 5)
527
+ |> *(_, 2)
528
+ |> /(_, 3)
529
+ // => 10 (10 + 5 = 15, 15 * 2 = 30, 30 / 3 = 10)
289
530
 
290
- ### Regular Expressions
291
- `regexp`, `match`, `replace`, `replace-all`
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
+ ```
292
539
 
293
- ### Bitwise Operations
294
- `<<`, `>>`, `>>>`, `~`, `&`, `bit-and-not`, `|`, `^`, `bit-flip`, `bit-clear`, `bit-set`, `bit-test`
540
+ ## Built-in Functions
295
541
 
296
- ### Assertions
297
- `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`
542
+ Lits comes with a comprehensive standard library of functions for:
298
543
 
299
- ## Modules and Exports
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
300
553
 
301
- You can export definitions to make them available to other modules:
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.
302
555
 
303
- ```
304
- // Exporting variables
305
- export let magic-number = 42;
306
- // => 42
556
+ ## Modules and Exports
307
557
 
308
- // Exporting functions
558
+ ```lits
559
+ // Export variables and functions
560
+ export let PI = 3.14159;
309
561
  export let square = x -> x * x;
310
- ```
311
-
312
- ## API
313
562
 
314
- Lits provides a JavaScript API for embedding:
315
-
316
- ```javascript
317
- interface Lits {
318
- getRuntimeInfo: () => LitsRuntimeInfo
319
- run: (program: string, params?: ContextParams & FilePathParams) => unknown
320
- context: (programOrAst: string | Ast, params?: ContextParams & FilePathParams) => Context
321
- getUndefinedSymbols: (programOrAst: string | Ast, params: ContextParams) => Set<string>
322
- tokenize: (program: string, tokenizeParams: FilePathParams & MinifyParams) => TokenStream
323
- parse: (tokenStream: TokenStream) => Ast
324
- evaluate: (ast: Ast, params: ContextParams) => unknown
325
- transformSymbols: (tokenStream: TokenStream, transformer: (symbol: string) => string) => TokenStream
326
- untokenize: (tokenStream: TokenStream) => string
327
- apply: (fn: LitsFunction, fnParams: unknown[], params: ContextParams) => unknown
328
- }
563
+ // Exported values become available to other modules
329
564
  ```
330
565
 
331
566
  ## Examples
332
567
 
333
- ### Factorial Function
568
+ ### Factorial
334
569
 
335
- ```
336
- let factorial = (n) ->
570
+ ```lits
571
+ let factorial = n ->
337
572
  if n <= 1 then
338
573
  1
339
574
  else
340
- n * self(n - 1);
575
+ n * self(n - 1)
576
+ end;
341
577
 
342
- factorial(5);
343
- // => 120
578
+ factorial(5) // => 120
344
579
  ```
345
580
 
346
- ### Fibonacci Sequence
581
+ ### Array Processing
347
582
 
583
+ ```lits
584
+ let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
585
+
586
+ // Get even numbers squared
587
+ let evenSquares = numbers
588
+ filter even?
589
+ map square;
590
+ // => [4, 16, 36, 64, 100]
591
+
592
+ // Sum of odd numbers
593
+ let oddSum = numbers
594
+ filter odd?
595
+ reduce +;
596
+ // => 25
348
597
  ```
349
- let fib = n ->
350
- if n < 2 then
351
- n
352
- else
353
- self(n - 1) + fib(n - 2)
354
598
 
355
- // Generate the first 10 Fibonacci numbers
356
- range(10) map fib;
357
- // => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
599
+ ### Object Manipulation
600
+
601
+ ```lits
602
+ let person = { name: "John", age: 30, city: "New York" };
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");
614
+ ```
615
+
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";
358
639
  ```
359
640
 
360
- ### 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";
361
651
 
652
+ describe(42) // => "a number: 42"
653
+ describe([1,2,3]) // => "list of 3 items"
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"
362
666
  ```
363
- let people = [
364
- { name: "Alice", age: 25 },
365
- { name: "Bob", age: 30 },
366
- { name: "Charlie", age: 35 },
367
- { name: "Diana", age: 40 }
368
- ];
369
667
 
370
- // Get all names
371
- people map (p -> p.name);
372
- // => ["Alice", "Bob", "Charlie", "Diana"]
668
+ ## JavaScript Interoperability
373
669
 
374
- // Get people older than 30
375
- people filter (p -> p.age > 30);
376
- // => [{ name: "Charlie", age: 35 }, { name: "Diana", age: 40 }]
670
+ Lits provides a comprehensive JavaScript API for embedding and integration:
377
671
 
378
- // Calculate average age
379
- (people map (p -> p.age) reduce +) / count(people);
380
- // => 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
+ }
381
733
  ```
382
734
 
383
- ## 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
+ ```
384
752
 
385
- *[Add contribution guidelines here]*
753
+ ## Learn More
386
754
 
387
- ## 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
388
758
 
389
- *[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.