@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 +561 -226
- package/dist/cli/cli.js +258 -365
- package/dist/cli/src/builtin/index.d.ts +1 -1
- package/dist/cli/src/builtin/specialExpressionTypes.d.ts +13 -15
- package/dist/cli/src/builtin/specialExpressions/functions.d.ts +3 -7
- package/dist/cli/src/builtin/specialExpressions/loop.d.ts +1 -1
- package/dist/cli/src/parser/Parser.d.ts +10 -4
- package/dist/cli/src/tokenizer/reservedNames.d.ts +2 -0
- package/dist/index.esm.js +261 -370
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +261 -370
- package/dist/index.js.map +1 -1
- package/dist/lits.iife.js +261 -370
- package/dist/lits.iife.js.map +1 -1
- package/dist/src/builtin/index.d.ts +1 -1
- package/dist/src/builtin/specialExpressionTypes.d.ts +13 -15
- package/dist/src/builtin/specialExpressions/functions.d.ts +3 -7
- package/dist/src/builtin/specialExpressions/loop.d.ts +1 -1
- package/dist/src/parser/Parser.d.ts +10 -4
- package/dist/src/tokenizer/reservedNames.d.ts +2 -0
- package/dist/testFramework.esm.js +251 -360
- package/dist/testFramework.esm.js.map +1 -1
- package/dist/testFramework.js +251 -360
- 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
|
|
|
@@ -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
|
-
|
|
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
|
-
|
|
29
|
-
x * x
|
|
30
|
-
end;
|
|
60
|
+
let square = x -> x * x;
|
|
31
61
|
|
|
32
62
|
// Using the function
|
|
33
|
-
let result
|
|
63
|
+
let result = square(5);
|
|
34
64
|
// => 25
|
|
35
65
|
|
|
36
66
|
// Using function as an operator
|
|
37
|
-
let squares
|
|
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
|
|
71
|
+
let sum = +([1, 2, 3, 4, 5]);
|
|
42
72
|
// => 15
|
|
43
73
|
```
|
|
44
74
|
|
|
45
|
-
## Syntax
|
|
75
|
+
## Basic Syntax
|
|
46
76
|
|
|
47
|
-
###
|
|
77
|
+
### Data Types
|
|
48
78
|
|
|
49
|
-
```
|
|
79
|
+
```lits
|
|
50
80
|
// Numbers
|
|
51
|
-
42
|
|
52
|
-
3.14
|
|
53
|
-
0xFFFF
|
|
54
|
-
0b1100
|
|
55
|
-
0o77
|
|
56
|
-
-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
|
|
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
|
|
102
|
+
{ name: "John", age: 30 }
|
|
103
|
+
|
|
104
|
+
// Regular expressions
|
|
105
|
+
#"pattern"
|
|
73
106
|
```
|
|
74
107
|
|
|
75
|
-
###
|
|
108
|
+
### Mathematical Constants
|
|
76
109
|
|
|
77
|
-
Lits provides
|
|
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
|
-
//
|
|
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
|
-
|
|
135
|
+
## Special Expressions
|
|
115
136
|
|
|
116
137
|
### Variable Binding
|
|
117
138
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
|
147
|
+
let x = 20; // Error: x is already defined
|
|
125
148
|
|
|
126
|
-
//
|
|
127
|
-
let y
|
|
128
|
-
let x
|
|
149
|
+
// Shadowing in inner scopes
|
|
150
|
+
let y = {
|
|
151
|
+
let x = 20;
|
|
129
152
|
x
|
|
130
|
-
|
|
153
|
+
};
|
|
131
154
|
// => 20, outer x is still 10
|
|
132
155
|
```
|
|
133
156
|
|
|
134
|
-
|
|
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
|
-
|
|
143
|
-
|
|
184
|
+
### Functions
|
|
185
|
+
|
|
186
|
+
#### Lambda Functions
|
|
187
|
+
|
|
188
|
+
```lits
|
|
189
|
+
// Multi-parameter lambda
|
|
190
|
+
let add = (a, b) -> a + b;
|
|
144
191
|
|
|
145
|
-
//
|
|
146
|
-
let
|
|
192
|
+
// Single parameter (parentheses optional)
|
|
193
|
+
let square = x -> x * x;
|
|
147
194
|
|
|
148
|
-
//
|
|
149
|
-
let
|
|
150
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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),
|
|
259
|
+
end
|
|
260
|
+
// => "zero" (if x = 0), "one" (if x = 1), etc., or null if no match
|
|
261
|
+
```
|
|
179
262
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
//
|
|
218
|
-
|
|
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
|
-
|
|
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
|
-
|
|
230
|
-
let [nbr1, nbr2] := [1, 2, 3, 4];
|
|
231
|
-
// nbr1 => 1
|
|
232
|
-
// nbr2 => 2
|
|
379
|
+
### Blocks
|
|
233
380
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
-
|
|
240
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
466
|
+
// Partial application with underscore placeholder
|
|
467
|
+
let add5 = +(5, _);
|
|
468
|
+
add5(3) // => 8
|
|
272
469
|
|
|
273
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
// => [1, 3]
|
|
474
|
+
// Single placeholder in different positions
|
|
475
|
+
let subtract = -(_, 2);
|
|
476
|
+
subtract(10) // => 8
|
|
279
477
|
|
|
280
|
-
|
|
281
|
-
|
|
478
|
+
let divide = /(10, _);
|
|
479
|
+
divide(2) // => 5
|
|
282
480
|
```
|
|
283
481
|
|
|
284
|
-
|
|
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
|
-
|
|
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
|
-
|
|
493
|
+
// Chaining
|
|
494
|
+
[1, 2, 3, 4, 5, 6]
|
|
495
|
+
filter odd?
|
|
496
|
+
map square
|
|
497
|
+
reduce +
|
|
498
|
+
// => 35
|
|
499
|
+
```
|
|
294
500
|
|
|
295
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
302
|
-
|
|
505
|
+
```lits
|
|
506
|
+
// Without pipe operator
|
|
507
|
+
reduce(map(filter([1, 2, 3, 4, 5, 6], odd?), square), +)
|
|
303
508
|
|
|
304
|
-
|
|
305
|
-
|
|
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
|
-
|
|
308
|
-
|
|
516
|
+
// Simple transformations
|
|
517
|
+
"hello world"
|
|
518
|
+
|> upper-case
|
|
519
|
+
|> split(_, " ")
|
|
520
|
+
|> reverse
|
|
521
|
+
|> join(_, "-")
|
|
522
|
+
// => "WORLD-HELLO"
|
|
309
523
|
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
|
|
314
|
-
|
|
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
|
-
|
|
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
|
-
|
|
320
|
-
`regexp`, `match`, `replace`, `replace-all`
|
|
542
|
+
Lits comes with a comprehensive standard library of functions for:
|
|
321
543
|
|
|
322
|
-
|
|
323
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
338
|
-
export function square(x)
|
|
339
|
-
x * x
|
|
340
|
-
end;
|
|
341
|
-
```
|
|
566
|
+
## Examples
|
|
342
567
|
|
|
343
|
-
|
|
568
|
+
### Factorial
|
|
344
569
|
|
|
345
|
-
|
|
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
|
-
|
|
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
|
-
|
|
581
|
+
### Array Processing
|
|
363
582
|
|
|
364
|
-
|
|
583
|
+
```lits
|
|
584
|
+
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
365
585
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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
|
-
|
|
376
|
-
|
|
592
|
+
// Sum of odd numbers
|
|
593
|
+
let oddSum = numbers
|
|
594
|
+
filter odd?
|
|
595
|
+
reduce +;
|
|
596
|
+
// => 25
|
|
377
597
|
```
|
|
378
598
|
|
|
379
|
-
###
|
|
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
|
-
|
|
391
|
-
|
|
392
|
-
|
|
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
|
-
|
|
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
|
-
|
|
406
|
-
people map (p -> p.name);
|
|
407
|
-
// => ["Alice", "Bob", "Charlie", "Diana"]
|
|
668
|
+
## JavaScript Interoperability
|
|
408
669
|
|
|
409
|
-
|
|
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
|
-
|
|
414
|
-
|
|
415
|
-
|
|
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
|
-
|
|
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
|
-
|
|
753
|
+
## Learn More
|
|
421
754
|
|
|
422
|
-
|
|
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
|
-
|
|
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.
|