@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 +554 -184
- package/dist/cli/cli.js +68 -53
- package/dist/cli/src/parser/Parser.d.ts +7 -2
- package/dist/index.esm.js +61 -48
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +61 -48
- package/dist/index.js.map +1 -1
- package/dist/lits.iife.js +61 -48
- package/dist/lits.iife.js.map +1 -1
- package/dist/src/parser/Parser.d.ts +7 -2
- package/dist/testFramework.esm.js +61 -48
- package/dist/testFramework.esm.js.map +1 -1
- package/dist/testFramework.js +61 -48
- package/dist/testFramework.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
-
###
|
|
77
|
+
### Data Types
|
|
45
78
|
|
|
46
|
-
```
|
|
79
|
+
```lits
|
|
47
80
|
// Numbers
|
|
48
|
-
42
|
|
49
|
-
3.14
|
|
50
|
-
0xFFFF
|
|
51
|
-
0b1100
|
|
52
|
-
0o77
|
|
53
|
-
-2.3e-2
|
|
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
|
-
###
|
|
108
|
+
### Mathematical Constants
|
|
73
109
|
|
|
74
|
-
Lits provides
|
|
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
|
-
//
|
|
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
|
-
|
|
135
|
+
## Special Expressions
|
|
112
136
|
|
|
113
137
|
### Variable Binding
|
|
114
138
|
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
//
|
|
124
|
-
let y =
|
|
149
|
+
// Shadowing in inner scopes
|
|
150
|
+
let y = {
|
|
125
151
|
let x = 20;
|
|
126
152
|
x
|
|
127
|
-
|
|
153
|
+
};
|
|
128
154
|
// => 20, outer x is still 10
|
|
129
155
|
```
|
|
130
156
|
|
|
131
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
|
141
|
-
let
|
|
142
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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),
|
|
259
|
+
end
|
|
260
|
+
// => "zero" (if x = 0), "one" (if x = 1), etc., or null if no match
|
|
261
|
+
```
|
|
169
262
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
190
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
202
|
-
let [nbr1, nbr2] = [1, 2, 3, 4];
|
|
203
|
-
// nbr1 => 1
|
|
204
|
-
// nbr2 => 2
|
|
391
|
+
### Arrays and Objects
|
|
205
392
|
|
|
206
|
-
|
|
207
|
-
let displayPerson = ({name, age}) ->
|
|
208
|
-
name ++ " is " ++ str(age) ++ " years old";
|
|
393
|
+
#### Array Construction
|
|
209
394
|
|
|
210
|
-
|
|
211
|
-
//
|
|
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
|
-
###
|
|
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
|
-
|
|
466
|
+
// Partial application with underscore placeholder
|
|
467
|
+
let add5 = +(5, _);
|
|
468
|
+
add5(3) // => 8
|
|
243
469
|
|
|
244
|
-
|
|
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
|
-
|
|
248
|
-
|
|
249
|
-
// => [1, 3]
|
|
474
|
+
// Single placeholder in different positions
|
|
475
|
+
let subtract = -(_, 2);
|
|
476
|
+
subtract(10) // => 8
|
|
250
477
|
|
|
251
|
-
|
|
252
|
-
|
|
478
|
+
let divide = /(10, _);
|
|
479
|
+
divide(2) // => 5
|
|
253
480
|
```
|
|
254
481
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
```
|
|
258
|
-
[1, 2, 3, 4] filter odd?;
|
|
259
|
-
// => [1, 3]
|
|
260
|
-
```
|
|
482
|
+
### Parameter Order
|
|
261
483
|
|
|
262
|
-
|
|
484
|
+
Lits favors subject-first parameter order for better operator chaining:
|
|
263
485
|
|
|
264
|
-
|
|
486
|
+
```lits
|
|
487
|
+
// Function style
|
|
488
|
+
filter([1, 2, 3, 4], odd?) // => [1, 3]
|
|
265
489
|
|
|
266
|
-
|
|
267
|
-
|
|
490
|
+
// Operator style (more readable)
|
|
491
|
+
[1, 2, 3, 4] filter odd? // => [1, 3]
|
|
268
492
|
|
|
269
|
-
|
|
270
|
-
|
|
493
|
+
// Chaining
|
|
494
|
+
[1, 2, 3, 4, 5, 6]
|
|
495
|
+
filter odd?
|
|
496
|
+
map square
|
|
497
|
+
reduce +
|
|
498
|
+
// => 35
|
|
499
|
+
```
|
|
271
500
|
|
|
272
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
279
|
-
|
|
505
|
+
```lits
|
|
506
|
+
// Without pipe operator
|
|
507
|
+
reduce(map(filter([1, 2, 3, 4, 5, 6], odd?), square), +)
|
|
280
508
|
|
|
281
|
-
|
|
282
|
-
|
|
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
|
-
|
|
285
|
-
|
|
516
|
+
// Simple transformations
|
|
517
|
+
"hello world"
|
|
518
|
+
|> upper-case
|
|
519
|
+
|> split(_, " ")
|
|
520
|
+
|> reverse
|
|
521
|
+
|> join(_, "-")
|
|
522
|
+
// => "WORLD-HELLO"
|
|
286
523
|
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
291
|
-
|
|
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
|
-
|
|
294
|
-
`<<`, `>>`, `>>>`, `~`, `&`, `bit-and-not`, `|`, `^`, `bit-flip`, `bit-clear`, `bit-set`, `bit-test`
|
|
540
|
+
## Built-in Functions
|
|
295
541
|
|
|
296
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
568
|
+
### Factorial
|
|
334
569
|
|
|
335
|
-
```
|
|
336
|
-
let factorial =
|
|
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
|
-
###
|
|
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
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
|
|
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
|
-
|
|
371
|
-
people map (p -> p.name);
|
|
372
|
-
// => ["Alice", "Bob", "Charlie", "Diana"]
|
|
668
|
+
## JavaScript Interoperability
|
|
373
669
|
|
|
374
|
-
|
|
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
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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
|
-
|
|
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
|
-
|
|
753
|
+
## Learn More
|
|
386
754
|
|
|
387
|
-
|
|
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
|
-
|
|
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.
|