@mojir/lits 2.1.33 → 2.1.35
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 +585 -206
- package/dist/cli/cli.js +136 -121
- package/dist/cli/src/parser/Parser.d.ts +7 -2
- package/dist/index.esm.js +129 -116
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +129 -116
- package/dist/index.js.map +1 -1
- package/dist/lits.iife.js +129 -116
- package/dist/lits.iife.js.map +1 -1
- package/dist/src/parser/Parser.d.ts +7 -2
- package/dist/testFramework.esm.js +129 -116
- package/dist/testFramework.esm.js.map +1 -1
- package/dist/testFramework.js +129 -116
- 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,351 +72,697 @@ 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
|
-
"Hello, world!"
|
|
89
|
+
"Hello, world!";
|
|
57
90
|
|
|
58
91
|
// Booleans
|
|
59
|
-
true
|
|
60
|
-
false
|
|
92
|
+
true;
|
|
93
|
+
false;
|
|
61
94
|
|
|
62
95
|
// Null
|
|
63
|
-
null
|
|
96
|
+
null;
|
|
64
97
|
|
|
65
98
|
// Arrays
|
|
66
|
-
[1, 2, 3, 4]
|
|
99
|
+
[1, 2, 3, 4];
|
|
67
100
|
|
|
68
101
|
// Objects
|
|
69
|
-
{ name: "John", age: 30 }
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Builtin Number Symbols
|
|
73
|
-
|
|
74
|
-
Lits provides a set of predefined mathematical constants that can be used directly in your code:
|
|
102
|
+
{ name: "John", age: 30 };
|
|
75
103
|
|
|
104
|
+
// Regular expressions
|
|
105
|
+
#"pattern";
|
|
76
106
|
```
|
|
77
|
-
// Mathematical constants
|
|
78
|
-
PI // => 3.141592653589793
|
|
79
|
-
π // => 3.141592653589793 (Unicode alternative)
|
|
80
|
-
-PI // => -3.141592653589793
|
|
81
|
-
-π // => -3.141592653589793
|
|
82
|
-
|
|
83
|
-
E // => 2.718281828459045 (Euler's number)
|
|
84
|
-
ε // => 2.718281828459045 (Unicode alternative)
|
|
85
|
-
-E // => -2.718281828459045
|
|
86
|
-
-ε // => -2.718281828459045
|
|
87
107
|
|
|
88
|
-
|
|
89
|
-
φ // => 1.618033988749895 (Unicode alternative)
|
|
90
|
-
-PHI // => -1.618033988749895
|
|
91
|
-
-φ // => -1.618033988749895
|
|
108
|
+
### Mathematical Constants
|
|
92
109
|
|
|
93
|
-
|
|
94
|
-
POSITIVE_INFINITY // => Infinity
|
|
95
|
-
∞ // => Infinity (Unicode alternative)
|
|
96
|
-
NEGATIVE_INFINITY // => -Infinity
|
|
97
|
-
-∞ // => -Infinity (Unicode alternative)
|
|
110
|
+
Lits provides predefined mathematical constants:
|
|
98
111
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
112
|
+
```lits
|
|
113
|
+
PI; // => 3.141592653589793
|
|
114
|
+
π; // => 3.141592653589793 (Unicode alternative)
|
|
115
|
+
E; // => 2.718281828459045 (Euler's number)
|
|
116
|
+
ε; // => 2.718281828459045 (Unicode alternative)
|
|
117
|
+
PHI; // => 1.618033988749895 (Golden ratio)
|
|
118
|
+
φ; // => 1.618033988749895 (Unicode alternative)
|
|
102
119
|
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
120
|
+
// Infinity values
|
|
121
|
+
POSITIVE_INFINITY; // => Infinity
|
|
122
|
+
∞; // => Infinity (Unicode alternative)
|
|
123
|
+
NEGATIVE_INFINITY; // => -Infinity
|
|
106
124
|
|
|
107
|
-
//
|
|
108
|
-
|
|
125
|
+
// Integer and float limits
|
|
126
|
+
MAX_SAFE_INTEGER; // => 9007199254740991
|
|
127
|
+
MIN_SAFE_INTEGER; // => -9007199254740991
|
|
128
|
+
MAX_VALUE; // => 1.7976931348623157e+308
|
|
129
|
+
MIN_VALUE; // => 5e-324
|
|
109
130
|
```
|
|
110
131
|
|
|
111
|
-
|
|
132
|
+
## Special Expressions
|
|
112
133
|
|
|
113
134
|
### Variable Binding
|
|
114
135
|
|
|
115
|
-
|
|
116
|
-
|
|
136
|
+
#### Let
|
|
137
|
+
|
|
138
|
+
```lits
|
|
139
|
+
// Simple binding
|
|
117
140
|
let x = 10;
|
|
118
141
|
// => 10
|
|
119
142
|
|
|
120
143
|
// Variables are immutable
|
|
121
|
-
let x = 20; // Error: x is already defined
|
|
144
|
+
// let x = 20; // Error: x is already defined
|
|
122
145
|
|
|
123
|
-
//
|
|
124
|
-
let y =
|
|
146
|
+
// Shadowing in inner scopes
|
|
147
|
+
let y = {
|
|
125
148
|
let x = 20;
|
|
126
149
|
x
|
|
127
|
-
|
|
150
|
+
};
|
|
128
151
|
// => 20, outer x is still 10
|
|
129
152
|
```
|
|
130
153
|
|
|
131
|
-
|
|
154
|
+
#### Destructuring
|
|
155
|
+
|
|
156
|
+
```lits
|
|
157
|
+
// Object destructuring
|
|
158
|
+
let { name, age } = { name: "John", age: 30 };
|
|
159
|
+
// name => "John", age => 30
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
```lits
|
|
163
|
+
// Array destructuring
|
|
164
|
+
let [a, b] = [1, 2, 3, 4];
|
|
165
|
+
// a => 1, b => 2
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```lits
|
|
169
|
+
// With default values
|
|
170
|
+
let { name = "Unknown", age = 0 } = { name: "John" };
|
|
171
|
+
// name => "John", age => 0
|
|
172
|
+
```
|
|
132
173
|
|
|
174
|
+
```lits
|
|
175
|
+
// Rest patterns
|
|
176
|
+
let [head, ...tail] = [1, 2, 3, 4];
|
|
177
|
+
// head => 1, tail => [2, 3, 4]
|
|
133
178
|
```
|
|
134
|
-
|
|
179
|
+
|
|
180
|
+
```lits
|
|
181
|
+
// Destructuring in function parameters
|
|
182
|
+
let displayPerson = ({name, age}) ->
|
|
183
|
+
name ++ " is " ++ str(age) ++ " years old";
|
|
184
|
+
|
|
185
|
+
displayPerson({ name: "John", age: 30 });
|
|
186
|
+
// => "John is 30 years old"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Functions
|
|
190
|
+
|
|
191
|
+
#### Lambda Functions
|
|
192
|
+
|
|
193
|
+
```lits
|
|
194
|
+
// Multi-parameter lambda
|
|
135
195
|
let add = (a, b) -> a + b;
|
|
136
196
|
|
|
137
|
-
//
|
|
138
|
-
let
|
|
197
|
+
// Single parameter (parentheses optional)
|
|
198
|
+
let square = x -> x * x;
|
|
199
|
+
|
|
200
|
+
// No parameters
|
|
201
|
+
let constant = () -> 42;
|
|
139
202
|
|
|
140
|
-
//
|
|
141
|
-
let
|
|
142
|
-
|
|
203
|
+
// Positional arguments
|
|
204
|
+
let add-v2 = -> $1 + $2;
|
|
205
|
+
|
|
206
|
+
// Single positional argument
|
|
207
|
+
let square-v2 = -> $ * $;
|
|
208
|
+
|
|
209
|
+
// Self-reference for recursion
|
|
210
|
+
let factorial = n ->
|
|
211
|
+
if n <= 1 then
|
|
212
|
+
1
|
|
213
|
+
else
|
|
214
|
+
n * self(n - 1)
|
|
215
|
+
end;
|
|
143
216
|
```
|
|
144
217
|
|
|
145
218
|
### Control Flow
|
|
146
219
|
|
|
147
|
-
|
|
220
|
+
#### If/Unless
|
|
221
|
+
|
|
222
|
+
```lits
|
|
148
223
|
// If expression
|
|
224
|
+
let x = !:random-int(0, 20); // Random number between 0 and 19
|
|
225
|
+
|
|
149
226
|
if x > 10 then
|
|
150
227
|
"large"
|
|
151
228
|
else
|
|
152
229
|
"small"
|
|
230
|
+
end;
|
|
153
231
|
// => "large" (if x > 10) or "small" (if x <= 10)
|
|
154
232
|
|
|
155
|
-
//
|
|
233
|
+
// If without else returns null
|
|
234
|
+
if false then "never" end;
|
|
235
|
+
// => null
|
|
236
|
+
|
|
237
|
+
// Unless (inverted if)
|
|
156
238
|
unless x > 10 then
|
|
157
239
|
"small"
|
|
158
240
|
else
|
|
159
241
|
"large"
|
|
242
|
+
end;
|
|
160
243
|
// => "small" (if x <= 10) or "large" (if x > 10)
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
#### Cond
|
|
247
|
+
|
|
248
|
+
```lits
|
|
249
|
+
let x = !:random-int(0, 20); // Random number between 0 and 19
|
|
250
|
+
|
|
251
|
+
// Multi-branch conditional
|
|
252
|
+
cond
|
|
253
|
+
case x < 5 then "small"
|
|
254
|
+
case x < 10 then "medium"
|
|
255
|
+
case x < 15 then "large"
|
|
256
|
+
end ?? "extra large"
|
|
257
|
+
// Tests conditions sequentially, returns first truthy match
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
#### Switch
|
|
261
|
+
|
|
262
|
+
```lits
|
|
263
|
+
let x = !:random-int(0, 3); // Random number between 0 and 2
|
|
161
264
|
|
|
162
|
-
// Switch
|
|
265
|
+
// Switch on value
|
|
163
266
|
switch x
|
|
164
267
|
case 0 then "zero"
|
|
165
268
|
case 1 then "one"
|
|
166
269
|
case 2 then "two"
|
|
167
|
-
end
|
|
168
|
-
// => "zero" (if x = 0), "one" (if x = 1),
|
|
270
|
+
end
|
|
271
|
+
// => "zero" (if x = 0), "one" (if x = 1), etc., or null if no match
|
|
272
|
+
```
|
|
169
273
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
274
|
+
### Loops and Iteration
|
|
275
|
+
|
|
276
|
+
#### For Comprehensions
|
|
277
|
+
|
|
278
|
+
```lits
|
|
279
|
+
// Simple iteration
|
|
280
|
+
for (x in [1, 2, 3, 4]) -> x * 2;
|
|
281
|
+
// => [2, 4, 6, 8]
|
|
282
|
+
|
|
283
|
+
// With filtering
|
|
284
|
+
for (x in [1, 2, 3, 4] when odd?(x)) -> x * 2;
|
|
285
|
+
// => [2, 6]
|
|
286
|
+
|
|
287
|
+
// With while condition
|
|
288
|
+
for (x in [1, 2, 3, 4] while x < 3) -> x * 2;
|
|
289
|
+
// => [2, 4]
|
|
290
|
+
|
|
291
|
+
// With let bindings
|
|
292
|
+
for (x in [1, 2, 3] let doubled = x * 2) -> doubled + 1;
|
|
293
|
+
// => [3, 5, 7]
|
|
294
|
+
|
|
295
|
+
// Multiple iterators
|
|
296
|
+
for (x in [1, 2], y in [10, 20]) -> x + y;
|
|
297
|
+
// => [11, 21, 12, 22]
|
|
298
|
+
|
|
299
|
+
// Object iteration
|
|
300
|
+
for (entry in { a: 1, b: 2 } let [key, value] = entry) -> key ++ ":" ++ str(value);
|
|
301
|
+
// => ["a:1", "b:2"]
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### Doseq (Side Effects)
|
|
305
|
+
|
|
306
|
+
```lits
|
|
307
|
+
// For side effects only (returns null)
|
|
308
|
+
doseq (x in [1, 2, 3]) -> write!(x)
|
|
309
|
+
// Prints: 1 2 3, returns null
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
#### Loop (Tail Recursion)
|
|
313
|
+
|
|
314
|
+
```lits
|
|
315
|
+
// Loop with recur for tail recursion
|
|
316
|
+
loop (n = 5, acc = 1) -> {
|
|
317
|
+
if zero?(n) then
|
|
318
|
+
acc
|
|
319
|
+
else
|
|
320
|
+
recur(n - 1, acc * n)
|
|
321
|
+
end
|
|
322
|
+
}
|
|
323
|
+
// => 120 (factorial of 5)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Error Handling
|
|
327
|
+
|
|
328
|
+
#### Try/Catch
|
|
177
329
|
|
|
178
|
-
|
|
330
|
+
```lits
|
|
331
|
+
// Basic try/catch
|
|
332
|
+
try
|
|
333
|
+
riskyOperation()
|
|
334
|
+
catch
|
|
335
|
+
"Something went wrong"
|
|
336
|
+
end;
|
|
337
|
+
|
|
338
|
+
// With error binding
|
|
179
339
|
try
|
|
180
340
|
riskyOperation()
|
|
181
341
|
catch (error)
|
|
182
342
|
"Error: " ++ error.message
|
|
183
|
-
|
|
343
|
+
end;
|
|
184
344
|
```
|
|
185
345
|
|
|
186
|
-
|
|
346
|
+
#### Throw
|
|
187
347
|
|
|
348
|
+
```lits
|
|
349
|
+
// Throwing errors
|
|
350
|
+
try
|
|
351
|
+
throw("Custom error message");
|
|
352
|
+
catch
|
|
353
|
+
"Caught an error"
|
|
354
|
+
end;
|
|
355
|
+
|
|
356
|
+
// In context
|
|
357
|
+
let divide = (a, b) ->
|
|
358
|
+
if zero?(b) then
|
|
359
|
+
throw("Division by zero")
|
|
360
|
+
else
|
|
361
|
+
a / b
|
|
362
|
+
end;
|
|
188
363
|
```
|
|
189
|
-
|
|
190
|
-
|
|
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
|
+
|
|
378
|
+
// Multiple arguments
|
|
379
|
+
&&(true, true, "all true"); // => "all true"
|
|
380
|
+
||(false, false, "found"); // => "found"
|
|
191
381
|
```
|
|
192
382
|
|
|
193
|
-
|
|
383
|
+
#### Null Coalescing
|
|
194
384
|
|
|
385
|
+
```lits
|
|
386
|
+
// Null coalescing operator
|
|
387
|
+
null ?? "default"; // => "default"
|
|
388
|
+
undefined ?? "default"; // => "default"
|
|
389
|
+
0 ?? "default"; // => 0 (only null/undefined are coalesced)
|
|
390
|
+
false ?? "default"; // => false
|
|
391
|
+
"" ?? "default"; // => ""
|
|
195
392
|
```
|
|
196
|
-
// Object destructuring
|
|
197
|
-
let { name, age } = { name: "John", age: 30 };
|
|
198
|
-
// name => "John"
|
|
199
|
-
// age => 30
|
|
200
393
|
|
|
201
|
-
|
|
202
|
-
let [nbr1, nbr2] = [1, 2, 3, 4];
|
|
203
|
-
// nbr1 => 1
|
|
204
|
-
// nbr2 => 2
|
|
394
|
+
### Blocks
|
|
205
395
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
396
|
+
```lits
|
|
397
|
+
// Block expressions
|
|
398
|
+
{
|
|
399
|
+
let a = 1 + 2 + 3;
|
|
400
|
+
let b = x -> x * x;
|
|
401
|
+
b(a)
|
|
402
|
+
}
|
|
403
|
+
// => 36 (returns value of last expression)
|
|
404
|
+
```
|
|
209
405
|
|
|
210
|
-
|
|
211
|
-
|
|
406
|
+
### Arrays and Objects
|
|
407
|
+
|
|
408
|
+
#### Array Construction
|
|
409
|
+
|
|
410
|
+
```lits
|
|
411
|
+
// Array literal
|
|
412
|
+
[1, 2, 3, 4];
|
|
413
|
+
|
|
414
|
+
// Array function
|
|
415
|
+
array(1, 2, 3, 4);
|
|
416
|
+
|
|
417
|
+
// With spread
|
|
418
|
+
let small-set = [3, 4, 5];
|
|
419
|
+
[1, 2, ...small-set, 6];
|
|
420
|
+
// => [1, 2, 3, 4, 5, 6];
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
#### Object Construction
|
|
424
|
+
|
|
425
|
+
```lits
|
|
426
|
+
// Object literal
|
|
427
|
+
{ name: "John", age: 30 };
|
|
428
|
+
|
|
429
|
+
// Object function
|
|
430
|
+
object("name", "John", "age", 30);
|
|
431
|
+
|
|
432
|
+
// With spread
|
|
433
|
+
let defaults = { type: "Person", active: true };
|
|
434
|
+
{
|
|
435
|
+
...defaults,
|
|
436
|
+
name: "John",
|
|
437
|
+
age: 30
|
|
438
|
+
};
|
|
439
|
+
// => { type: "Person", active: true, name: "John", age: 30 }
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Recursion
|
|
443
|
+
|
|
444
|
+
#### Recur
|
|
445
|
+
|
|
446
|
+
```lits
|
|
447
|
+
// Tail recursion with recur
|
|
448
|
+
let countdown = n -> {
|
|
449
|
+
write!(n);
|
|
450
|
+
if pos?(n) then
|
|
451
|
+
recur(n - 1)
|
|
452
|
+
end
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
countdown(3)
|
|
456
|
+
// Prints: 3 2 1 0
|
|
212
457
|
```
|
|
213
458
|
|
|
214
459
|
## Operators and Functions
|
|
215
460
|
|
|
216
|
-
###
|
|
461
|
+
### Algebraic Notation
|
|
217
462
|
|
|
218
463
|
All functions that take two parameters can be used as operators:
|
|
219
464
|
|
|
220
|
-
```
|
|
465
|
+
```lits
|
|
221
466
|
// As a function
|
|
222
|
-
max(5, 10);
|
|
223
|
-
// => 10
|
|
467
|
+
max(5, 10); // => 10
|
|
224
468
|
|
|
225
469
|
// As an operator
|
|
226
|
-
5 max 10;
|
|
227
|
-
// => 10
|
|
470
|
+
5 max 10; // => 10
|
|
228
471
|
```
|
|
229
472
|
|
|
230
473
|
All operators can be used as functions:
|
|
231
474
|
|
|
232
|
-
```
|
|
475
|
+
```lits
|
|
233
476
|
// As an operator
|
|
234
|
-
5 + 3;
|
|
235
|
-
// => 8
|
|
477
|
+
5 + 3; // => 8
|
|
236
478
|
|
|
237
479
|
// As a function
|
|
238
|
-
+(5, 3);
|
|
239
|
-
// => 8
|
|
240
|
-
```
|
|
480
|
+
+(5, 3); // => 8
|
|
241
481
|
|
|
242
|
-
|
|
482
|
+
// Partial application with underscore placeholder
|
|
483
|
+
let add5 = +(5, _);
|
|
484
|
+
add5(3); // => 8
|
|
243
485
|
|
|
244
|
-
|
|
486
|
+
// Multiple placeholders
|
|
487
|
+
let subtractTwoValues = -(100, _, _);
|
|
488
|
+
subtractTwoValues(4, 3); // => 93
|
|
245
489
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
// => [1, 3]
|
|
490
|
+
// Single placeholder in different positions
|
|
491
|
+
let subtract = -(_, 2);
|
|
492
|
+
subtract(10); // => 8
|
|
250
493
|
|
|
251
|
-
|
|
252
|
-
|
|
494
|
+
let divide = /(10, _);
|
|
495
|
+
divide(2); // => 5
|
|
253
496
|
```
|
|
254
497
|
|
|
255
|
-
|
|
498
|
+
### Parameter Order
|
|
256
499
|
|
|
257
|
-
|
|
258
|
-
[1, 2, 3, 4] filter odd?;
|
|
259
|
-
// => [1, 3]
|
|
260
|
-
```
|
|
500
|
+
Lits favors subject-first parameter order for better operator chaining:
|
|
261
501
|
|
|
262
|
-
|
|
502
|
+
```lits
|
|
503
|
+
// Function style
|
|
504
|
+
filter([1, 2, 3, 4], odd?); // => [1, 3]
|
|
263
505
|
|
|
264
|
-
|
|
506
|
+
// Operator style (more readable)
|
|
507
|
+
[1, 2, 3, 4] filter odd?; // => [1, 3]
|
|
508
|
+
```
|
|
265
509
|
|
|
266
|
-
###
|
|
267
|
-
`count`, `get`, `get-in`, `contains?`, `assoc`, `assoc-in`, `++`, `not-empty`, `every?`, `not-every?`, `any?`, `not-any?`, `update`, `update-in`
|
|
510
|
+
### Pipe Operator
|
|
268
511
|
|
|
269
|
-
|
|
270
|
-
`array`, `range`, `repeat`, `flatten`, `mapcat`
|
|
512
|
+
The pipe operator `|>` passes the result of the left expression as the first argument to the right function:
|
|
271
513
|
|
|
272
|
-
|
|
273
|
-
|
|
514
|
+
```lits
|
|
515
|
+
// Without pipe operator
|
|
516
|
+
reduce(map(filter([1, 2, 3, 4, 5, 6], odd?), -> $ + $), +, 0);
|
|
274
517
|
|
|
275
|
-
|
|
276
|
-
|
|
518
|
+
// With pipe operator (much more readable)
|
|
519
|
+
[1, 2, 3, 4, 5, 6]
|
|
520
|
+
|> filter(_, odd?)
|
|
521
|
+
|> map(_, -> $ * $)
|
|
522
|
+
|> reduce(_, +, 0);
|
|
523
|
+
// => 35
|
|
277
524
|
|
|
278
|
-
|
|
279
|
-
|
|
525
|
+
// Simple transformations
|
|
526
|
+
"hello world"
|
|
527
|
+
|> upper-case
|
|
528
|
+
|> split(_, " ")
|
|
529
|
+
|> reverse
|
|
530
|
+
|> join(_, "-");
|
|
531
|
+
// => "WORLD-HELLO"
|
|
280
532
|
|
|
281
|
-
|
|
282
|
-
|
|
533
|
+
// Mathematical operations
|
|
534
|
+
10
|
|
535
|
+
|> +(_, 5)
|
|
536
|
+
|> *(_, 2)
|
|
537
|
+
|> /(_, 3);
|
|
538
|
+
// => 10 (10 + 5 = 15, 15 * 2 = 30, 30 / 3 = 10)
|
|
283
539
|
|
|
284
|
-
|
|
285
|
-
|
|
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)
|
|
547
|
+
```
|
|
286
548
|
|
|
287
|
-
|
|
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?`
|
|
549
|
+
## Built-in Functions
|
|
289
550
|
|
|
290
|
-
|
|
291
|
-
`regexp`, `match`, `replace`, `replace-all`
|
|
551
|
+
Lits comes with a comprehensive standard library of functions for:
|
|
292
552
|
|
|
293
|
-
|
|
294
|
-
|
|
553
|
+
- **Arithmetic and Math**: Basic operations, trigonometry, logarithms, rounding
|
|
554
|
+
- **Collections**: Working with arrays and objects (get, assoc, merge, etc.)
|
|
555
|
+
- **Sequences**: Filtering, mapping, reducing, sorting, and transforming data
|
|
556
|
+
- **Strings**: Manipulation, formatting, encoding, and pattern matching
|
|
557
|
+
- **Predicates**: Type checking and condition testing functions
|
|
558
|
+
- **Functional Programming**: Function composition, partial application, and utilities
|
|
559
|
+
- **Regular Expressions**: Pattern matching and text processing
|
|
560
|
+
- **Bitwise Operations**: Low-level bit manipulation
|
|
561
|
+
- **Assertions**: Testing and validation utilities
|
|
295
562
|
|
|
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`
|
|
563
|
+
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.
|
|
298
564
|
|
|
299
565
|
## Modules and Exports
|
|
300
566
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
// Exporting variables
|
|
305
|
-
export let magic-number = 42;
|
|
306
|
-
// => 42
|
|
307
|
-
|
|
308
|
-
// Exporting functions
|
|
567
|
+
```lits
|
|
568
|
+
// Export variables and functions
|
|
569
|
+
export let pi = 3.14159;
|
|
309
570
|
export let square = x -> x * x;
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
## API
|
|
313
|
-
|
|
314
|
-
Lits provides a JavaScript API for embedding:
|
|
315
571
|
|
|
316
|
-
|
|
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
|
-
}
|
|
572
|
+
// Exported values become available to other modules
|
|
329
573
|
```
|
|
330
574
|
|
|
331
575
|
## Examples
|
|
332
576
|
|
|
333
|
-
### Factorial
|
|
577
|
+
### Factorial
|
|
334
578
|
|
|
335
|
-
```
|
|
336
|
-
let factorial =
|
|
579
|
+
```lits
|
|
580
|
+
let factorial = n ->
|
|
337
581
|
if n <= 1 then
|
|
338
582
|
1
|
|
339
583
|
else
|
|
340
|
-
n * self(n - 1)
|
|
584
|
+
n * self(n - 1)
|
|
585
|
+
end;
|
|
341
586
|
|
|
342
|
-
factorial(5)
|
|
343
|
-
// => 120
|
|
587
|
+
factorial(5) // => 120
|
|
344
588
|
```
|
|
345
589
|
|
|
346
|
-
###
|
|
590
|
+
### Array Processing
|
|
591
|
+
|
|
592
|
+
```lits
|
|
593
|
+
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
594
|
+
|
|
595
|
+
// Get even numbers squared
|
|
596
|
+
let evenSquares = numbers
|
|
597
|
+
|> filter(_, even?)
|
|
598
|
+
|> map(_, -> $ * $);
|
|
599
|
+
// => [4, 16, 36, 64, 100]
|
|
347
600
|
|
|
601
|
+
// Sum of odd numbers
|
|
602
|
+
let oddSum = numbers
|
|
603
|
+
|> filter(_, odd?)
|
|
604
|
+
|> reduce(_, +, 0);
|
|
605
|
+
// => 25
|
|
348
606
|
```
|
|
349
|
-
let fib = n ->
|
|
350
|
-
if n < 2 then
|
|
351
|
-
n
|
|
352
|
-
else
|
|
353
|
-
self(n - 1) + fib(n - 2)
|
|
354
607
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
608
|
+
### Object Manipulation
|
|
609
|
+
|
|
610
|
+
```lits
|
|
611
|
+
let person = { name: "John", age: 30, city: "New York" };
|
|
612
|
+
|
|
613
|
+
// Update age
|
|
614
|
+
let older = assoc(person, "age", 31);
|
|
615
|
+
|
|
616
|
+
// Add new field
|
|
617
|
+
let withJob = assoc(older, "job", "Developer");
|
|
618
|
+
|
|
619
|
+
// Using pipe operator for chaining
|
|
620
|
+
let updated = person
|
|
621
|
+
|> assoc(_, "age", 31)
|
|
622
|
+
|> assoc(_, "job", "Developer");
|
|
358
623
|
```
|
|
359
624
|
|
|
360
|
-
###
|
|
625
|
+
### Pattern Matching Examples
|
|
626
|
+
|
|
627
|
+
#### Switch (for matching against a single value)
|
|
628
|
+
|
|
629
|
+
```lits
|
|
630
|
+
let gradeToLetter = grade ->
|
|
631
|
+
switch grade
|
|
632
|
+
case 90 then "A"
|
|
633
|
+
case 80 then "B"
|
|
634
|
+
case 70 then "C"
|
|
635
|
+
case 60 then "D"
|
|
636
|
+
end ?? "F";
|
|
361
637
|
|
|
638
|
+
gradeToLetter(80); // => "B"
|
|
639
|
+
gradeToLetter(55); // => "F"
|
|
640
|
+
|
|
641
|
+
// HTTP status code handling
|
|
642
|
+
let statusMessage = code ->
|
|
643
|
+
switch code
|
|
644
|
+
case 200 then "OK"
|
|
645
|
+
case 404 then "Not Found"
|
|
646
|
+
case 500 then "Internal Server Error"
|
|
647
|
+
end ?? "Unknown Status";
|
|
362
648
|
```
|
|
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
649
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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"
|
|
373
663
|
|
|
374
|
-
//
|
|
375
|
-
|
|
376
|
-
|
|
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";
|
|
377
672
|
|
|
378
|
-
//
|
|
379
|
-
(
|
|
380
|
-
// => 32.5
|
|
673
|
+
gradeToLetter(85); // => "B"
|
|
674
|
+
gradeToLetter(55); // => "F"
|
|
381
675
|
```
|
|
382
676
|
|
|
383
|
-
##
|
|
677
|
+
## JavaScript Interoperability
|
|
678
|
+
|
|
679
|
+
Lits provides a comprehensive JavaScript API for embedding and integration:
|
|
680
|
+
|
|
681
|
+
```javascript
|
|
682
|
+
import { Lits } from 'lits';
|
|
683
|
+
|
|
684
|
+
// Create a Lits instance
|
|
685
|
+
const lits = new Lits();
|
|
686
|
+
|
|
687
|
+
// Run Lits code
|
|
688
|
+
const result = lits.run('+(5, 3)');
|
|
689
|
+
console.log(result); // 8
|
|
690
|
+
|
|
691
|
+
// Pass JavaScript values to Lits
|
|
692
|
+
const result2 = lits.run('name ++ " is " ++ str(age)', {
|
|
693
|
+
values: {
|
|
694
|
+
name: "John",
|
|
695
|
+
age: 30
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
console.log(result2); // "John is 30"
|
|
699
|
+
|
|
700
|
+
// Expose JavaScript functions to Lits
|
|
701
|
+
const result3 = lits.run('myAlert("Hello from Lits!")', {
|
|
702
|
+
jsFunctions: {
|
|
703
|
+
myAlert: {
|
|
704
|
+
fn: (message) => console.log(`Alert: ${message}`),
|
|
705
|
+
arity: { min: 1, max: 1 }
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
// Parse and evaluate separately for better performance
|
|
711
|
+
const tokens = lits.tokenize('+(5, 3)');
|
|
712
|
+
const ast = lits.parse(tokens);
|
|
713
|
+
const result4 = lits.evaluate(ast, {});
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
### Lits Class Methods
|
|
717
|
+
|
|
718
|
+
```typescript
|
|
719
|
+
interface Lits {
|
|
720
|
+
// Execute Lits code directly
|
|
721
|
+
run(program: string, params?: ContextParams & FilePathParams): unknown
|
|
722
|
+
|
|
723
|
+
// Get execution context after running code
|
|
724
|
+
context(programOrAst: string | Ast, params?: ContextParams & FilePathParams): Context
|
|
725
|
+
|
|
726
|
+
// Find undefined symbols in code
|
|
727
|
+
getUndefinedSymbols(programOrAst: string | Ast, params?: ContextParams): Set<string>
|
|
728
|
+
|
|
729
|
+
// Parse pipeline
|
|
730
|
+
tokenize(program: string, params?: FilePathParams & MinifyParams): TokenStream
|
|
731
|
+
parse(tokenStream: TokenStream): Ast
|
|
732
|
+
evaluate(ast: Ast, params: ContextParams): unknown
|
|
733
|
+
|
|
734
|
+
// Apply Lits function with JavaScript arguments
|
|
735
|
+
apply(fn: LitsFunction, fnParams: unknown[], params?: ContextParams): unknown
|
|
736
|
+
|
|
737
|
+
// Utility methods
|
|
738
|
+
transformSymbols(tokenStream: TokenStream, transformer: (symbol: string) => string): TokenStream
|
|
739
|
+
untokenize(tokenStream: TokenStream): string
|
|
740
|
+
getRuntimeInfo(): LitsRuntimeInfo
|
|
741
|
+
}
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
### Context Parameters
|
|
745
|
+
|
|
746
|
+
```typescript
|
|
747
|
+
interface ContextParams {
|
|
748
|
+
globalContext?: Context // Global variable context
|
|
749
|
+
contexts?: Context[] // Additional context layers
|
|
750
|
+
values?: Record<string, unknown> // JavaScript values to expose
|
|
751
|
+
jsFunctions?: Record<string, JsFunction> // JavaScript functions to expose
|
|
752
|
+
globalModuleScope?: boolean // Module scoping behavior
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
interface JsFunction {
|
|
756
|
+
fn: (...args: any[]) => unknown // The JavaScript function
|
|
757
|
+
arity?: Arity // Function arity constraints
|
|
758
|
+
docString?: string // Documentation
|
|
759
|
+
}
|
|
760
|
+
```
|
|
384
761
|
|
|
385
|
-
|
|
762
|
+
## Learn More
|
|
386
763
|
|
|
387
|
-
|
|
764
|
+
- Try Lits in the [online playground](https://mojir.github.io/lits/)
|
|
765
|
+
- Explore the comprehensive function reference
|
|
766
|
+
- Check out more complex examples in the documentation
|
|
388
767
|
|
|
389
|
-
|
|
768
|
+
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.
|