@mojir/lits 2.4.0 → 2.5.0
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 +34 -4
- package/dist/cli/cli.js +112 -36
- package/dist/cli/src/Lits/Lits.d.ts +8 -4
- package/dist/cli/src/builtin/interface.d.ts +1 -0
- package/dist/cli/src/evaluator/ContextStack.d.ts +4 -2
- package/dist/cli/src/index.d.ts +1 -1
- package/dist/full.esm.js +1 -1
- package/dist/full.esm.js.map +1 -1
- package/dist/full.js +1 -1
- package/dist/full.js.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lits.iife.js +1 -1
- package/dist/lits.iife.js.map +1 -1
- package/dist/modules/random.esm.js +1 -1
- package/dist/modules/random.esm.js.map +1 -1
- package/dist/modules/random.js +1 -1
- package/dist/modules/random.js.map +1 -1
- package/dist/modules/src/Lits/Lits.d.ts +8 -4
- package/dist/modules/src/builtin/interface.d.ts +1 -0
- package/dist/modules/src/evaluator/ContextStack.d.ts +4 -2
- package/dist/modules/src/index.d.ts +1 -1
- package/dist/src/Lits/Lits.d.ts +8 -4
- package/dist/src/builtin/interface.d.ts +1 -0
- package/dist/src/evaluator/ContextStack.d.ts +4 -2
- package/dist/src/index.d.ts +1 -1
- package/dist/testFramework.esm.js +1 -1
- package/dist/testFramework.esm.js.map +1 -1
- package/dist/testFramework.js +1 -1
- package/dist/testFramework.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,17 +41,47 @@ npm install --global @mojir/lits
|
|
|
41
41
|
$ lits
|
|
42
42
|
|
|
43
43
|
# Evaluate Lits code directly
|
|
44
|
-
$ lits
|
|
45
|
-
$ lits
|
|
44
|
+
$ lits eval "5 + 3"
|
|
45
|
+
$ lits eval "[1, 2, 3, 4] filter odd? map inc"
|
|
46
46
|
|
|
47
47
|
# Run a Lits file
|
|
48
|
-
$ lits
|
|
49
|
-
|
|
48
|
+
$ lits run script.lits
|
|
49
|
+
|
|
50
|
+
# Bundle a multi-file project into a single .json file
|
|
51
|
+
$ lits bundle main.lits -o bundle.lits.json
|
|
52
|
+
|
|
53
|
+
# Run a bundle
|
|
54
|
+
$ lits run-bundle bundle.lits.json
|
|
55
|
+
|
|
56
|
+
# Run tests
|
|
57
|
+
$ lits test tests.test.lits
|
|
50
58
|
|
|
51
59
|
# Get help
|
|
52
60
|
$ lits --help
|
|
53
61
|
```
|
|
54
62
|
|
|
63
|
+
**Subcommands:**
|
|
64
|
+
|
|
65
|
+
| Subcommand | Description |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `run <file>` | Run a `.lits` source file |
|
|
68
|
+
| `run-bundle <file>` | Run a `.json` bundle (with validation) |
|
|
69
|
+
| `eval <expression>` | Evaluate a Lits expression |
|
|
70
|
+
| `bundle <entry>` | Bundle a multi-file project into a single JSON file |
|
|
71
|
+
| `test <file>` | Run a `.test.lits` test file |
|
|
72
|
+
| `repl` | Start an interactive REPL (default when no subcommand) |
|
|
73
|
+
|
|
74
|
+
**Common options:**
|
|
75
|
+
|
|
76
|
+
| Option | Applies to | Description |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `-c, --context=<json>` | `run`, `run-bundle`, `eval`, `repl` | Provide context as a JSON string |
|
|
79
|
+
| `-C, --context-file=<file>` | `run`, `run-bundle`, `eval`, `repl` | Provide context from a `.json` file |
|
|
80
|
+
| `-s, --silent` | `run`, `run-bundle`, `eval` | Suppress printing the result |
|
|
81
|
+
| `-o, --output=<file>` | `bundle` | Write bundle to file (default: stdout) |
|
|
82
|
+
| `--pattern=<regex>` | `test` | Only run tests matching pattern |
|
|
83
|
+
| `-l, --load=<file>` | `repl` | Preload a `.lits` file into the REPL |
|
|
84
|
+
|
|
55
85
|
The REPL provides an interactive environment where you can experiment with Lits code, test functions, and explore the language features in real-time.
|
|
56
86
|
|
|
57
87
|
## Quick Start
|
package/dist/cli/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ var readline = require('node:readline');
|
|
|
7
7
|
var os = require('node:os');
|
|
8
8
|
var process$1 = require('node:process');
|
|
9
9
|
|
|
10
|
-
var version = "2.
|
|
10
|
+
var version = "2.5.0";
|
|
11
11
|
|
|
12
12
|
function getCodeMarker(sourceCodeInfo) {
|
|
13
13
|
if (!sourceCodeInfo.position || !sourceCodeInfo.code)
|
|
@@ -3677,6 +3677,7 @@ const miscNormalExpression = {
|
|
|
3677
3677
|
return asAny(params[params.length - 1], sourceCodeInfo);
|
|
3678
3678
|
return null;
|
|
3679
3679
|
},
|
|
3680
|
+
pure: false,
|
|
3680
3681
|
arity: {},
|
|
3681
3682
|
docs: {
|
|
3682
3683
|
category: 'misc',
|
|
@@ -6757,7 +6758,10 @@ function isNumberReservedSymbol(symbol) {
|
|
|
6757
6758
|
}
|
|
6758
6759
|
|
|
6759
6760
|
const functionExecutors = {
|
|
6760
|
-
NativeJsFunction: (fn, params, sourceCodeInfo) => {
|
|
6761
|
+
NativeJsFunction: (fn, params, sourceCodeInfo, contextStack) => {
|
|
6762
|
+
if (contextStack.pure && !fn.nativeFn.pure) {
|
|
6763
|
+
throw new LitsError(`Cannot call impure native function '${fn.name}' in pure mode`, sourceCodeInfo);
|
|
6764
|
+
}
|
|
6761
6765
|
try {
|
|
6762
6766
|
const result = fn.nativeFn.fn(...params);
|
|
6763
6767
|
// If the native function returns a Promise, await it transparently
|
|
@@ -6938,6 +6942,9 @@ const functionExecutors = {
|
|
|
6938
6942
|
},
|
|
6939
6943
|
Builtin: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
|
|
6940
6944
|
const normalExpression = asNonUndefined(allNormalExpressions[fn.normalBuiltinSymbolType], sourceCodeInfo);
|
|
6945
|
+
if (contextStack.pure && normalExpression.pure === false) {
|
|
6946
|
+
throw new LitsError(`Cannot call impure function '${fn.name}' in pure mode`, sourceCodeInfo);
|
|
6947
|
+
}
|
|
6941
6948
|
return normalExpression.evaluate(params, sourceCodeInfo, contextStack, { executeFunction });
|
|
6942
6949
|
},
|
|
6943
6950
|
SpecialBuiltin: (fn, params, sourceCodeInfo, contextStack, { executeFunction }) => {
|
|
@@ -6958,6 +6965,9 @@ const functionExecutors = {
|
|
|
6958
6965
|
if (!expression) {
|
|
6959
6966
|
throw new LitsError(`Function '${fn.functionName}' not found in module '${fn.moduleName}'.`, sourceCodeInfo);
|
|
6960
6967
|
}
|
|
6968
|
+
if (contextStack.pure && expression.pure === false) {
|
|
6969
|
+
throw new LitsError(`Cannot call impure function '${fn.functionName}' in pure mode`, sourceCodeInfo);
|
|
6970
|
+
}
|
|
6961
6971
|
assertNumberOfParams(expression.arity, params.length, sourceCodeInfo);
|
|
6962
6972
|
return expression.evaluate(params, sourceCodeInfo, contextStack, { executeFunction });
|
|
6963
6973
|
},
|
|
@@ -7056,6 +7066,9 @@ function evaluateNormalExpression(node, contextStack) {
|
|
|
7056
7066
|
if (isNormalBuiltinSymbolNode(nameSymbol)) {
|
|
7057
7067
|
const type = nameSymbol[1];
|
|
7058
7068
|
const normalExpression = builtin.allNormalExpressions[type];
|
|
7069
|
+
if (contextStack.pure && normalExpression.pure === false) {
|
|
7070
|
+
throw new LitsError(`Cannot call impure function '${normalExpression.name}' in pure mode`, node[2]);
|
|
7071
|
+
}
|
|
7059
7072
|
return normalExpression.evaluate(params, node[2], contextStack, { executeFunction });
|
|
7060
7073
|
}
|
|
7061
7074
|
else {
|
|
@@ -7152,13 +7165,15 @@ class ContextStackImpl {
|
|
|
7152
7165
|
nativeJsFunctions;
|
|
7153
7166
|
modules;
|
|
7154
7167
|
valueModules;
|
|
7155
|
-
|
|
7168
|
+
pure;
|
|
7169
|
+
constructor({ contexts, values: hostValues, nativeJsFunctions, modules, valueModules, pure, }) {
|
|
7156
7170
|
this.globalContext = asNonUndefined(contexts[0]);
|
|
7157
7171
|
this.contexts = contexts;
|
|
7158
7172
|
this.values = hostValues;
|
|
7159
7173
|
this.nativeJsFunctions = nativeJsFunctions;
|
|
7160
7174
|
this.modules = modules ?? new Map();
|
|
7161
7175
|
this.valueModules = valueModules ?? new Map();
|
|
7176
|
+
this.pure = pure ?? false;
|
|
7162
7177
|
}
|
|
7163
7178
|
getModule(name) {
|
|
7164
7179
|
return this.modules.get(name);
|
|
@@ -7180,13 +7195,14 @@ class ContextStackImpl {
|
|
|
7180
7195
|
nativeJsFunctions: this.nativeJsFunctions,
|
|
7181
7196
|
modules: this.modules,
|
|
7182
7197
|
valueModules: this.valueModules,
|
|
7198
|
+
pure: this.pure,
|
|
7183
7199
|
});
|
|
7184
7200
|
contextStack.globalContext = globalContext;
|
|
7185
7201
|
return contextStack;
|
|
7186
7202
|
}
|
|
7187
7203
|
new(context) {
|
|
7188
7204
|
const contexts = [{}, context];
|
|
7189
|
-
return new ContextStackImpl({ contexts, modules: this.modules, valueModules: this.valueModules });
|
|
7205
|
+
return new ContextStackImpl({ contexts, modules: this.modules, valueModules: this.valueModules, pure: this.pure });
|
|
7190
7206
|
}
|
|
7191
7207
|
addValues(values, sourceCodeInfo) {
|
|
7192
7208
|
const currentContext = this.contexts[0];
|
|
@@ -7292,7 +7308,7 @@ function assertNotShadowingBuiltin(name) {
|
|
|
7292
7308
|
throw new LitsError(`Cannot shadow ${shadowedName}`, undefined);
|
|
7293
7309
|
}
|
|
7294
7310
|
}
|
|
7295
|
-
function createContextStack(params = {}, modules) {
|
|
7311
|
+
function createContextStack(params = {}, modules, pure) {
|
|
7296
7312
|
const globalContext = params.globalContext ?? {};
|
|
7297
7313
|
// Contexts are checked from left to right
|
|
7298
7314
|
const contexts = params.contexts ? [globalContext, ...params.contexts] : [globalContext];
|
|
@@ -7336,6 +7352,7 @@ function createContextStack(params = {}, modules) {
|
|
|
7336
7352
|
values: hostValues,
|
|
7337
7353
|
modules,
|
|
7338
7354
|
nativeJsFunctions,
|
|
7355
|
+
pure,
|
|
7339
7356
|
});
|
|
7340
7357
|
return params.globalModuleScope ? contextStack : contextStack.create({});
|
|
7341
7358
|
}
|
|
@@ -9443,9 +9460,13 @@ class Lits {
|
|
|
9443
9460
|
return result;
|
|
9444
9461
|
}
|
|
9445
9462
|
runBundle(bundle, params = {}) {
|
|
9446
|
-
const contextStack = createContextStack(params, this.modules);
|
|
9463
|
+
const contextStack = createContextStack(params, this.modules, params.pure);
|
|
9447
9464
|
// Evaluate file modules in dependency order and register as value modules.
|
|
9448
9465
|
// Each file module is evaluated in its own scope so local bindings don't leak.
|
|
9466
|
+
// File modules are always evaluated in pure mode to ensure deterministic,
|
|
9467
|
+
// side-effect-free initialization regardless of the caller's pure setting.
|
|
9468
|
+
const savedPure = contextStack.pure;
|
|
9469
|
+
contextStack.pure = true;
|
|
9449
9470
|
for (const [name, source] of bundle.fileModules) {
|
|
9450
9471
|
const ast = this.generateAst(source, params);
|
|
9451
9472
|
const moduleContextStack = contextStack.create({});
|
|
@@ -9455,6 +9476,7 @@ class Lits {
|
|
|
9455
9476
|
}
|
|
9456
9477
|
contextStack.registerValueModule(name, result);
|
|
9457
9478
|
}
|
|
9479
|
+
contextStack.pure = savedPure;
|
|
9458
9480
|
// Parse and evaluate the main program
|
|
9459
9481
|
const ast = this.generateAst(bundle.program, params);
|
|
9460
9482
|
const result = evaluate(ast, contextStack);
|
|
@@ -9482,7 +9504,7 @@ class Lits {
|
|
|
9482
9504
|
return ast;
|
|
9483
9505
|
}
|
|
9484
9506
|
evaluate(ast, params) {
|
|
9485
|
-
const contextStack = createContextStack(params, this.modules);
|
|
9507
|
+
const contextStack = createContextStack(params, this.modules, params.pure);
|
|
9486
9508
|
return evaluate(ast, contextStack);
|
|
9487
9509
|
}
|
|
9488
9510
|
transformSymbols(tokenStream, transformer) {
|
|
@@ -13256,6 +13278,7 @@ const randomFunctions = {
|
|
|
13256
13278
|
evaluate: () => {
|
|
13257
13279
|
return Math.random();
|
|
13258
13280
|
},
|
|
13281
|
+
pure: false,
|
|
13259
13282
|
arity: toFixedArity(0),
|
|
13260
13283
|
},
|
|
13261
13284
|
'random-int!': {
|
|
@@ -13264,6 +13287,7 @@ const randomFunctions = {
|
|
|
13264
13287
|
assertNumber(max, sourceCodeInfo, { integer: true, gt: min });
|
|
13265
13288
|
return Math.floor(Math.random() * (max - min)) + min;
|
|
13266
13289
|
},
|
|
13290
|
+
pure: false,
|
|
13267
13291
|
arity: toFixedArity(2),
|
|
13268
13292
|
},
|
|
13269
13293
|
'random-int-inclusive!': {
|
|
@@ -13272,6 +13296,7 @@ const randomFunctions = {
|
|
|
13272
13296
|
assertNumber(max, sourceCodeInfo, { integer: true, gte: min });
|
|
13273
13297
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
13274
13298
|
},
|
|
13299
|
+
pure: false,
|
|
13275
13300
|
arity: toFixedArity(2),
|
|
13276
13301
|
},
|
|
13277
13302
|
'random-float!': {
|
|
@@ -13280,6 +13305,7 @@ const randomFunctions = {
|
|
|
13280
13305
|
assertNumber(max, sourceCodeInfo, { gt: min });
|
|
13281
13306
|
return Math.random() * (max - min) + min;
|
|
13282
13307
|
},
|
|
13308
|
+
pure: false,
|
|
13283
13309
|
arity: toFixedArity(2),
|
|
13284
13310
|
},
|
|
13285
13311
|
'random-boolean!': {
|
|
@@ -13288,6 +13314,7 @@ const randomFunctions = {
|
|
|
13288
13314
|
assertNumber(probability, sourceCodeInfo, { gte: 0, lte: 1 });
|
|
13289
13315
|
return Math.random() < probability;
|
|
13290
13316
|
},
|
|
13317
|
+
pure: false,
|
|
13291
13318
|
arity: { min: 0, max: 1 },
|
|
13292
13319
|
},
|
|
13293
13320
|
'random-item!': {
|
|
@@ -13296,6 +13323,7 @@ const randomFunctions = {
|
|
|
13296
13323
|
const index = Math.floor(Math.random() * array.length);
|
|
13297
13324
|
return asAny(array[index]);
|
|
13298
13325
|
},
|
|
13326
|
+
pure: false,
|
|
13299
13327
|
arity: toFixedArity(1),
|
|
13300
13328
|
},
|
|
13301
13329
|
'random-sample!': {
|
|
@@ -13314,6 +13342,7 @@ const randomFunctions = {
|
|
|
13314
13342
|
}
|
|
13315
13343
|
return result;
|
|
13316
13344
|
},
|
|
13345
|
+
pure: false,
|
|
13317
13346
|
arity: toFixedArity(2),
|
|
13318
13347
|
},
|
|
13319
13348
|
'random-sample-unique!': {
|
|
@@ -13335,6 +13364,7 @@ const randomFunctions = {
|
|
|
13335
13364
|
}
|
|
13336
13365
|
return result;
|
|
13337
13366
|
},
|
|
13367
|
+
pure: false,
|
|
13338
13368
|
arity: toFixedArity(2),
|
|
13339
13369
|
},
|
|
13340
13370
|
'shuffle!': {
|
|
@@ -13347,6 +13377,7 @@ const randomFunctions = {
|
|
|
13347
13377
|
}
|
|
13348
13378
|
return shuffledArray;
|
|
13349
13379
|
},
|
|
13380
|
+
pure: false,
|
|
13350
13381
|
arity: toFixedArity(1),
|
|
13351
13382
|
},
|
|
13352
13383
|
'random-normal!': {
|
|
@@ -13358,6 +13389,7 @@ const randomFunctions = {
|
|
|
13358
13389
|
const z0 = Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2);
|
|
13359
13390
|
return z0 * stdDev + mean;
|
|
13360
13391
|
},
|
|
13392
|
+
pure: false,
|
|
13361
13393
|
arity: toFixedArity(2),
|
|
13362
13394
|
},
|
|
13363
13395
|
'random-exponential!': {
|
|
@@ -13366,6 +13398,7 @@ const randomFunctions = {
|
|
|
13366
13398
|
const u = Math.random();
|
|
13367
13399
|
return -Math.log(u) / lambda;
|
|
13368
13400
|
},
|
|
13401
|
+
pure: false,
|
|
13369
13402
|
arity: toFixedArity(1),
|
|
13370
13403
|
},
|
|
13371
13404
|
'random-binomial!': {
|
|
@@ -13380,6 +13413,7 @@ const randomFunctions = {
|
|
|
13380
13413
|
}
|
|
13381
13414
|
return k;
|
|
13382
13415
|
},
|
|
13416
|
+
pure: false,
|
|
13383
13417
|
arity: toFixedArity(2),
|
|
13384
13418
|
},
|
|
13385
13419
|
'random-poisson!': {
|
|
@@ -13394,6 +13428,7 @@ const randomFunctions = {
|
|
|
13394
13428
|
} while (p > L);
|
|
13395
13429
|
return k - 1;
|
|
13396
13430
|
},
|
|
13431
|
+
pure: false,
|
|
13397
13432
|
arity: toFixedArity(1),
|
|
13398
13433
|
},
|
|
13399
13434
|
'random-gamma!': {
|
|
@@ -13402,6 +13437,7 @@ const randomFunctions = {
|
|
|
13402
13437
|
assertNumber(scale, sourceCodeInfo, { gt: 0 });
|
|
13403
13438
|
return randomGamma(shape, scale);
|
|
13404
13439
|
},
|
|
13440
|
+
pure: false,
|
|
13405
13441
|
arity: toFixedArity(2),
|
|
13406
13442
|
},
|
|
13407
13443
|
'random-pareto!': {
|
|
@@ -13410,6 +13446,7 @@ const randomFunctions = {
|
|
|
13410
13446
|
const u = Math.random();
|
|
13411
13447
|
return (1 / u) ** (1 / alpha);
|
|
13412
13448
|
},
|
|
13449
|
+
pure: false,
|
|
13413
13450
|
arity: toFixedArity(1),
|
|
13414
13451
|
},
|
|
13415
13452
|
'uuid!': {
|
|
@@ -13420,6 +13457,7 @@ const randomFunctions = {
|
|
|
13420
13457
|
return value.toString(16);
|
|
13421
13458
|
});
|
|
13422
13459
|
},
|
|
13460
|
+
pure: false,
|
|
13423
13461
|
arity: toFixedArity(0),
|
|
13424
13462
|
},
|
|
13425
13463
|
'random-char!': {
|
|
@@ -13431,6 +13469,7 @@ const randomFunctions = {
|
|
|
13431
13469
|
const randomIndex = Math.floor(Math.random() * charSet.length);
|
|
13432
13470
|
return charSet[randomIndex];
|
|
13433
13471
|
},
|
|
13472
|
+
pure: false,
|
|
13434
13473
|
arity: toFixedArity(1),
|
|
13435
13474
|
},
|
|
13436
13475
|
'random-string!': {
|
|
@@ -13447,6 +13486,7 @@ const randomFunctions = {
|
|
|
13447
13486
|
}
|
|
13448
13487
|
return result;
|
|
13449
13488
|
},
|
|
13489
|
+
pure: false,
|
|
13450
13490
|
arity: toFixedArity(2),
|
|
13451
13491
|
},
|
|
13452
13492
|
'random-id!': {
|
|
@@ -13460,6 +13500,7 @@ const randomFunctions = {
|
|
|
13460
13500
|
}
|
|
13461
13501
|
return result;
|
|
13462
13502
|
},
|
|
13503
|
+
pure: false,
|
|
13463
13504
|
arity: toFixedArity(1),
|
|
13464
13505
|
},
|
|
13465
13506
|
'random-color!': {
|
|
@@ -13467,6 +13508,7 @@ const randomFunctions = {
|
|
|
13467
13508
|
const randomColor = Math.floor(Math.random() * 0x1000000).toString(16);
|
|
13468
13509
|
return `#${randomColor.padStart(6, '0')}`;
|
|
13469
13510
|
},
|
|
13511
|
+
pure: false,
|
|
13470
13512
|
arity: toFixedArity(0),
|
|
13471
13513
|
},
|
|
13472
13514
|
};
|
|
@@ -34633,32 +34675,50 @@ const helpRegExp = new RegExp(`^\`help\\s+(${polishSymbolFirstCharacterClass}${p
|
|
|
34633
34675
|
const expressions = [...normalExpressionKeys, ...specialExpressionKeys];
|
|
34634
34676
|
const config = processArguments(process.argv.slice(2));
|
|
34635
34677
|
const cliModules = getCliModules();
|
|
34636
|
-
function createLits(context) {
|
|
34678
|
+
function createLits(context, pure) {
|
|
34637
34679
|
const _lits = new Lits({ debug: true, modules: [...allBuiltinModules, ...cliModules] });
|
|
34638
34680
|
return {
|
|
34639
34681
|
run: (program) => _lits.run(program, {
|
|
34640
34682
|
globalContext: context,
|
|
34641
34683
|
globalModuleScope: true,
|
|
34684
|
+
pure,
|
|
34642
34685
|
}),
|
|
34643
34686
|
};
|
|
34644
34687
|
}
|
|
34645
34688
|
switch (config.subcommand) {
|
|
34646
34689
|
case 'run': {
|
|
34647
|
-
const lits = createLits(config.context);
|
|
34690
|
+
const lits = createLits(config.context, config.pure);
|
|
34648
34691
|
try {
|
|
34649
34692
|
const content = fs.readFileSync(config.filename, { encoding: 'utf-8' });
|
|
34650
|
-
|
|
34651
|
-
|
|
34693
|
+
const result = lits.run(content);
|
|
34694
|
+
if (config.printResult) {
|
|
34695
|
+
console.log(result);
|
|
34696
|
+
}
|
|
34697
|
+
process.exit(0);
|
|
34698
|
+
}
|
|
34699
|
+
catch (error) {
|
|
34700
|
+
printErrorMessage(`${error}`);
|
|
34701
|
+
process.exit(1);
|
|
34702
|
+
}
|
|
34703
|
+
break;
|
|
34704
|
+
}
|
|
34705
|
+
case 'run-bundle': {
|
|
34706
|
+
const lits = createLits(config.context, config.pure);
|
|
34707
|
+
try {
|
|
34708
|
+
const content = fs.readFileSync(config.filename, { encoding: 'utf-8' });
|
|
34709
|
+
let parsed;
|
|
34652
34710
|
try {
|
|
34653
|
-
|
|
34654
|
-
if (isLitsBundle(parsed)) {
|
|
34655
|
-
programOrBundle = parsed;
|
|
34656
|
-
}
|
|
34711
|
+
parsed = JSON.parse(content);
|
|
34657
34712
|
}
|
|
34658
34713
|
catch {
|
|
34659
|
-
|
|
34714
|
+
printErrorMessage(`Invalid bundle: ${config.filename} is not valid JSON`);
|
|
34715
|
+
process.exit(1);
|
|
34716
|
+
}
|
|
34717
|
+
if (!isLitsBundle(parsed)) {
|
|
34718
|
+
printErrorMessage(`Invalid bundle: ${config.filename} is not a valid Lits bundle (expected "program" string and "fileModules" array)`);
|
|
34719
|
+
process.exit(1);
|
|
34660
34720
|
}
|
|
34661
|
-
const result = lits.run(
|
|
34721
|
+
const result = lits.run(parsed);
|
|
34662
34722
|
if (config.printResult) {
|
|
34663
34723
|
console.log(result);
|
|
34664
34724
|
}
|
|
@@ -34671,7 +34731,7 @@ switch (config.subcommand) {
|
|
|
34671
34731
|
break;
|
|
34672
34732
|
}
|
|
34673
34733
|
case 'eval': {
|
|
34674
|
-
const lits = createLits(config.context);
|
|
34734
|
+
const lits = createLits(config.context, config.pure);
|
|
34675
34735
|
try {
|
|
34676
34736
|
const result = lits.run(config.expression);
|
|
34677
34737
|
if (config.printResult) {
|
|
@@ -34711,7 +34771,7 @@ switch (config.subcommand) {
|
|
|
34711
34771
|
}
|
|
34712
34772
|
case 'repl': {
|
|
34713
34773
|
if (config.loadFilename) {
|
|
34714
|
-
const lits = createLits(config.context);
|
|
34774
|
+
const lits = createLits(config.context, false);
|
|
34715
34775
|
const content = fs.readFileSync(config.loadFilename, { encoding: 'utf-8' });
|
|
34716
34776
|
const result = lits.run(content);
|
|
34717
34777
|
if (result !== null && typeof result === 'object' && !Array.isArray(result)) {
|
|
@@ -34748,7 +34808,7 @@ function runLitsTest(testPath, testNamePattern) {
|
|
|
34748
34808
|
process.exit(1);
|
|
34749
34809
|
}
|
|
34750
34810
|
function execute(expression, context) {
|
|
34751
|
-
const lits = createLits(context);
|
|
34811
|
+
const lits = createLits(context, false);
|
|
34752
34812
|
try {
|
|
34753
34813
|
const result = lits.run(expression);
|
|
34754
34814
|
historyResults.unshift(result);
|
|
@@ -34786,7 +34846,7 @@ function setReplHistoryVariables(context) {
|
|
|
34786
34846
|
}
|
|
34787
34847
|
function parseOption(args, i) {
|
|
34788
34848
|
const option = args[i];
|
|
34789
|
-
if (option === '-
|
|
34849
|
+
if (option === '-s') {
|
|
34790
34850
|
return { option, argument: null, count: 1 };
|
|
34791
34851
|
}
|
|
34792
34852
|
if (/^-[a-z]$/i.test(option))
|
|
@@ -34846,16 +34906,16 @@ function parseContextOptions(args, startIndex) {
|
|
|
34846
34906
|
return { options, nextIndex: i };
|
|
34847
34907
|
}
|
|
34848
34908
|
function parsePrintOptions(args, startIndex) {
|
|
34849
|
-
const options = { printResult:
|
|
34909
|
+
const options = { printResult: true };
|
|
34850
34910
|
let i = startIndex;
|
|
34851
34911
|
while (i < args.length) {
|
|
34852
34912
|
const parsed = parseOption(args, i);
|
|
34853
34913
|
if (!parsed)
|
|
34854
34914
|
break;
|
|
34855
34915
|
switch (parsed.option) {
|
|
34856
|
-
case '-
|
|
34857
|
-
case '--
|
|
34858
|
-
options.printResult =
|
|
34916
|
+
case '-s':
|
|
34917
|
+
case '--silent':
|
|
34918
|
+
options.printResult = false;
|
|
34859
34919
|
i += parsed.count;
|
|
34860
34920
|
break;
|
|
34861
34921
|
default:
|
|
@@ -34866,7 +34926,8 @@ function parsePrintOptions(args, startIndex) {
|
|
|
34866
34926
|
}
|
|
34867
34927
|
function parseRunEvalOptions(args, startIndex) {
|
|
34868
34928
|
let context = {};
|
|
34869
|
-
let printResult =
|
|
34929
|
+
let printResult = true;
|
|
34930
|
+
let pure = false;
|
|
34870
34931
|
let i = startIndex;
|
|
34871
34932
|
while (i < args.length) {
|
|
34872
34933
|
const parsed = parseOption(args, i);
|
|
@@ -34882,13 +34943,17 @@ function parseRunEvalOptions(args, startIndex) {
|
|
|
34882
34943
|
i = result.nextIndex;
|
|
34883
34944
|
break;
|
|
34884
34945
|
}
|
|
34885
|
-
case '-
|
|
34886
|
-
case '--
|
|
34946
|
+
case '-s':
|
|
34947
|
+
case '--silent': {
|
|
34887
34948
|
const result = parsePrintOptions(args, i);
|
|
34888
34949
|
printResult = result.options.printResult;
|
|
34889
34950
|
i = result.nextIndex;
|
|
34890
34951
|
break;
|
|
34891
34952
|
}
|
|
34953
|
+
case '--pure':
|
|
34954
|
+
pure = true;
|
|
34955
|
+
i += parsed.count;
|
|
34956
|
+
break;
|
|
34892
34957
|
default:
|
|
34893
34958
|
printErrorMessage(`Unknown option "${parsed.option}"`);
|
|
34894
34959
|
process.exit(1);
|
|
@@ -34898,7 +34963,7 @@ function parseRunEvalOptions(args, startIndex) {
|
|
|
34898
34963
|
printErrorMessage(`Unknown argument "${args[i]}"`);
|
|
34899
34964
|
process.exit(1);
|
|
34900
34965
|
}
|
|
34901
|
-
return { context, printResult, nextIndex: i };
|
|
34966
|
+
return { context, printResult, pure, nextIndex: i };
|
|
34902
34967
|
}
|
|
34903
34968
|
function processArguments(args) {
|
|
34904
34969
|
// Global flags (no subcommand)
|
|
@@ -34919,8 +34984,17 @@ function processArguments(args) {
|
|
|
34919
34984
|
printErrorMessage('Missing filename after "run"');
|
|
34920
34985
|
process.exit(1);
|
|
34921
34986
|
}
|
|
34922
|
-
const { context, printResult } = parseRunEvalOptions(args, 2);
|
|
34923
|
-
return { subcommand: 'run', filename, context, printResult };
|
|
34987
|
+
const { context, printResult, pure } = parseRunEvalOptions(args, 2);
|
|
34988
|
+
return { subcommand: 'run', filename, context, printResult, pure };
|
|
34989
|
+
}
|
|
34990
|
+
case 'run-bundle': {
|
|
34991
|
+
const filename = args[1];
|
|
34992
|
+
if (!filename || filename.startsWith('-')) {
|
|
34993
|
+
printErrorMessage('Missing filename after "run-bundle"');
|
|
34994
|
+
process.exit(1);
|
|
34995
|
+
}
|
|
34996
|
+
const { context, printResult, pure } = parseRunEvalOptions(args, 2);
|
|
34997
|
+
return { subcommand: 'run-bundle', filename, context, printResult, pure };
|
|
34924
34998
|
}
|
|
34925
34999
|
case 'eval': {
|
|
34926
35000
|
const expression = args[1];
|
|
@@ -34928,8 +35002,8 @@ function processArguments(args) {
|
|
|
34928
35002
|
printErrorMessage('Missing expression after "eval"');
|
|
34929
35003
|
process.exit(1);
|
|
34930
35004
|
}
|
|
34931
|
-
const { context, printResult } = parseRunEvalOptions(args, 2);
|
|
34932
|
-
return { subcommand: 'eval', expression, context, printResult };
|
|
35005
|
+
const { context, printResult, pure } = parseRunEvalOptions(args, 2);
|
|
35006
|
+
return { subcommand: 'eval', expression, context, printResult, pure };
|
|
34933
35007
|
}
|
|
34934
35008
|
case 'bundle': {
|
|
34935
35009
|
const filename = args[1];
|
|
@@ -35109,17 +35183,19 @@ function printUsage() {
|
|
|
35109
35183
|
Usage: lits [subcommand] [options]
|
|
35110
35184
|
|
|
35111
35185
|
Subcommands:
|
|
35112
|
-
run <file> [options] Run a .lits file
|
|
35186
|
+
run <file> [options] Run a .lits file
|
|
35187
|
+
run-bundle <file> [options] Run a .json bundle
|
|
35113
35188
|
eval <expression> [options] Evaluate a Lits expression
|
|
35114
35189
|
bundle <entry> [options] Bundle a multi-file project
|
|
35115
35190
|
test <file> [options] Run a .test.lits test file
|
|
35116
35191
|
repl [options] Start an interactive REPL
|
|
35117
35192
|
help Show this help
|
|
35118
35193
|
|
|
35119
|
-
Run/Eval options:
|
|
35194
|
+
Run/Run-bundle/Eval options:
|
|
35120
35195
|
-c, --context=<json> Context as a JSON string
|
|
35121
35196
|
-C, --context-file=<file> Context from a .json file
|
|
35122
|
-
-
|
|
35197
|
+
-s, --silent Suppress printing the result
|
|
35198
|
+
--pure Enforce pure mode (no side effects or non-determinism)
|
|
35123
35199
|
|
|
35124
35200
|
Bundle options:
|
|
35125
35201
|
-o, --output=<file> Write bundle to file (default: stdout)
|
|
@@ -16,6 +16,7 @@ export interface LitsRuntimeInfo {
|
|
|
16
16
|
export interface JsFunction {
|
|
17
17
|
fn: (...args: any[]) => unknown;
|
|
18
18
|
arity?: Arity;
|
|
19
|
+
pure?: boolean;
|
|
19
20
|
docString?: string;
|
|
20
21
|
}
|
|
21
22
|
export interface ContextParams {
|
|
@@ -30,6 +31,9 @@ export interface MinifyParams {
|
|
|
30
31
|
export interface FilePathParams {
|
|
31
32
|
filePath?: string;
|
|
32
33
|
}
|
|
34
|
+
export interface PureParams {
|
|
35
|
+
pure?: boolean;
|
|
36
|
+
}
|
|
33
37
|
interface LitsConfig {
|
|
34
38
|
initialCache?: Record<string, Ast>;
|
|
35
39
|
astCacheSize?: number | null;
|
|
@@ -44,10 +48,10 @@ export declare class Lits {
|
|
|
44
48
|
constructor(config?: LitsConfig);
|
|
45
49
|
getRuntimeInfo(): LitsRuntimeInfo;
|
|
46
50
|
readonly async: {
|
|
47
|
-
run: (programOrBundle: string | LitsBundle, params?: ContextParams & FilePathParams) => Promise<unknown>;
|
|
48
|
-
apply: (fn: LitsFunction, fnParams: unknown[], params?: ContextParams) => Promise<unknown>;
|
|
51
|
+
run: (programOrBundle: string | LitsBundle, params?: ContextParams & FilePathParams & PureParams) => Promise<unknown>;
|
|
52
|
+
apply: (fn: LitsFunction, fnParams: unknown[], params?: ContextParams & PureParams) => Promise<unknown>;
|
|
49
53
|
};
|
|
50
|
-
run(programOrBundle: string | LitsBundle, params?: ContextParams & FilePathParams): unknown;
|
|
54
|
+
run(programOrBundle: string | LitsBundle, params?: ContextParams & FilePathParams & PureParams): unknown;
|
|
51
55
|
private runBundle;
|
|
52
56
|
getUndefinedSymbols(programOrAst: string | Ast, params?: ContextParams): Set<string>;
|
|
53
57
|
tokenize(program: string, tokenizeParams?: FilePathParams & MinifyParams): TokenStream;
|
|
@@ -55,7 +59,7 @@ export declare class Lits {
|
|
|
55
59
|
private evaluate;
|
|
56
60
|
transformSymbols(tokenStream: TokenStream, transformer: (symbol: string) => string): TokenStream;
|
|
57
61
|
untokenize(tokenStream: TokenStream): string;
|
|
58
|
-
apply(fn: LitsFunction, fnParams: unknown[], params?: ContextParams): MaybePromise<Any>;
|
|
62
|
+
apply(fn: LitsFunction, fnParams: unknown[], params?: ContextParams & PureParams): MaybePromise<Any>;
|
|
59
63
|
private generateApplyFunctionCall;
|
|
60
64
|
private generateAst;
|
|
61
65
|
getAutoCompleter(program: string, position: number, params?: ContextParams): AutoCompleter;
|
|
@@ -80,6 +80,7 @@ type NormalExpressionEvaluator<T> = (params: Arr, sourceCodeInfo: SourceCodeInfo
|
|
|
80
80
|
}) => MaybePromise<T>;
|
|
81
81
|
export interface BuiltinNormalExpression<T> {
|
|
82
82
|
evaluate: NormalExpressionEvaluator<T>;
|
|
83
|
+
pure?: boolean;
|
|
83
84
|
name?: string;
|
|
84
85
|
arity: Arity;
|
|
85
86
|
docs?: FunctionDocs;
|
|
@@ -12,12 +12,14 @@ export declare class ContextStackImpl {
|
|
|
12
12
|
private nativeJsFunctions?;
|
|
13
13
|
private modules;
|
|
14
14
|
private valueModules;
|
|
15
|
-
|
|
15
|
+
pure: boolean;
|
|
16
|
+
constructor({ contexts, values: hostValues, nativeJsFunctions, modules, valueModules, pure, }: {
|
|
16
17
|
contexts: Context[];
|
|
17
18
|
values?: Record<string, unknown>;
|
|
18
19
|
nativeJsFunctions?: Record<string, NativeJsFunction>;
|
|
19
20
|
modules?: Map<string, LitsModule>;
|
|
20
21
|
valueModules?: Map<string, unknown>;
|
|
22
|
+
pure?: boolean;
|
|
21
23
|
});
|
|
22
24
|
getModule(name: string): LitsModule | undefined;
|
|
23
25
|
getValueModule(name: string): {
|
|
@@ -32,4 +34,4 @@ export declare class ContextStackImpl {
|
|
|
32
34
|
lookUp(node: UserDefinedSymbolNode): LookUpResult;
|
|
33
35
|
evaluateSymbol(node: SymbolNode): Any;
|
|
34
36
|
}
|
|
35
|
-
export declare function createContextStack(params?: ContextParams, modules?: Map<string, LitsModule
|
|
37
|
+
export declare function createContextStack(params?: ContextParams, modules?: Map<string, LitsModule>, pure?: boolean): ContextStack;
|
package/dist/cli/src/index.d.ts
CHANGED
|
@@ -11,6 +11,6 @@ export type { LitsModule } from './builtin/modules/interface';
|
|
|
11
11
|
export type { LitsBundle } from './bundler/interface';
|
|
12
12
|
export { isLitsBundle } from './bundler/interface';
|
|
13
13
|
export { type LitsError, isLitsError } from './errors';
|
|
14
|
-
export type { ContextParams, FilePathParams, MinifyParams, LitsRuntimeInfo, JsFunction } from './Lits/Lits';
|
|
14
|
+
export type { ContextParams, FilePathParams, MinifyParams, PureParams, LitsRuntimeInfo, JsFunction } from './Lits/Lits';
|
|
15
15
|
export { isGrid, isMatrix, isVector } from './typeGuards/annotatedArrays';
|
|
16
16
|
export type { AutoCompleter } from './AutoCompleter/AutoCompleter';
|