@mojir/lits 2.4.1 → 2.5.1
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 +2 -2
- package/dist/cli/cli.js +127 -54
- 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
|
@@ -48,10 +48,10 @@ $ lits eval "[1, 2, 3, 4] filter odd? map inc"
|
|
|
48
48
|
$ lits run script.lits
|
|
49
49
|
|
|
50
50
|
# Bundle a multi-file project into a single .json file
|
|
51
|
-
$ lits bundle main.lits -o bundle.json
|
|
51
|
+
$ lits bundle main.lits -o bundle.lits.json
|
|
52
52
|
|
|
53
53
|
# Run a bundle
|
|
54
|
-
$ lits run-bundle bundle.json
|
|
54
|
+
$ lits run-bundle bundle.lits.json
|
|
55
55
|
|
|
56
56
|
# Run tests
|
|
57
57
|
$ lits test tests.test.lits
|
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.1";
|
|
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
|
};
|
|
@@ -34626,6 +34668,7 @@ const HIST_SIZE = 1000;
|
|
|
34626
34668
|
const PROMPT = fmt.bright.gray('> ');
|
|
34627
34669
|
const historyResults = [];
|
|
34628
34670
|
const formatValue = getInlineCodeFormatter(fmt);
|
|
34671
|
+
const booleanFlags = new Set(['-s', '--silent', '--pure']);
|
|
34629
34672
|
const commands = ['`help', '`quit', '`builtins', '`context'];
|
|
34630
34673
|
const expressionRegExp = new RegExp(`^(.*\\(\\s*)(${polishSymbolFirstCharacterClass}${polishSymbolCharacterClass}*)$`);
|
|
34631
34674
|
const nameRegExp = new RegExp(`^(.*?)(${polishSymbolFirstCharacterClass}${polishSymbolCharacterClass}*)$`);
|
|
@@ -34633,18 +34676,19 @@ const helpRegExp = new RegExp(`^\`help\\s+(${polishSymbolFirstCharacterClass}${p
|
|
|
34633
34676
|
const expressions = [...normalExpressionKeys, ...specialExpressionKeys];
|
|
34634
34677
|
const config = processArguments(process.argv.slice(2));
|
|
34635
34678
|
const cliModules = getCliModules();
|
|
34636
|
-
function createLits(context) {
|
|
34679
|
+
function createLits(context, pure) {
|
|
34637
34680
|
const _lits = new Lits({ debug: true, modules: [...allBuiltinModules, ...cliModules] });
|
|
34638
34681
|
return {
|
|
34639
34682
|
run: (program) => _lits.run(program, {
|
|
34640
34683
|
globalContext: context,
|
|
34641
34684
|
globalModuleScope: true,
|
|
34685
|
+
pure,
|
|
34642
34686
|
}),
|
|
34643
34687
|
};
|
|
34644
34688
|
}
|
|
34645
34689
|
switch (config.subcommand) {
|
|
34646
34690
|
case 'run': {
|
|
34647
|
-
const lits = createLits(config.context);
|
|
34691
|
+
const lits = createLits(config.context, config.pure);
|
|
34648
34692
|
try {
|
|
34649
34693
|
const content = fs.readFileSync(config.filename, { encoding: 'utf-8' });
|
|
34650
34694
|
const result = lits.run(content);
|
|
@@ -34660,7 +34704,7 @@ switch (config.subcommand) {
|
|
|
34660
34704
|
break;
|
|
34661
34705
|
}
|
|
34662
34706
|
case 'run-bundle': {
|
|
34663
|
-
const lits = createLits(config.context);
|
|
34707
|
+
const lits = createLits(config.context, config.pure);
|
|
34664
34708
|
try {
|
|
34665
34709
|
const content = fs.readFileSync(config.filename, { encoding: 'utf-8' });
|
|
34666
34710
|
let parsed;
|
|
@@ -34688,7 +34732,7 @@ switch (config.subcommand) {
|
|
|
34688
34732
|
break;
|
|
34689
34733
|
}
|
|
34690
34734
|
case 'eval': {
|
|
34691
|
-
const lits = createLits(config.context);
|
|
34735
|
+
const lits = createLits(config.context, config.pure);
|
|
34692
34736
|
try {
|
|
34693
34737
|
const result = lits.run(config.expression);
|
|
34694
34738
|
if (config.printResult) {
|
|
@@ -34728,7 +34772,7 @@ switch (config.subcommand) {
|
|
|
34728
34772
|
}
|
|
34729
34773
|
case 'repl': {
|
|
34730
34774
|
if (config.loadFilename) {
|
|
34731
|
-
const lits = createLits(config.context);
|
|
34775
|
+
const lits = createLits(config.context, false);
|
|
34732
34776
|
const content = fs.readFileSync(config.loadFilename, { encoding: 'utf-8' });
|
|
34733
34777
|
const result = lits.run(content);
|
|
34734
34778
|
if (result !== null && typeof result === 'object' && !Array.isArray(result)) {
|
|
@@ -34765,7 +34809,7 @@ function runLitsTest(testPath, testNamePattern) {
|
|
|
34765
34809
|
process.exit(1);
|
|
34766
34810
|
}
|
|
34767
34811
|
function execute(expression, context) {
|
|
34768
|
-
const lits = createLits(context);
|
|
34812
|
+
const lits = createLits(context, false);
|
|
34769
34813
|
try {
|
|
34770
34814
|
const result = lits.run(expression);
|
|
34771
34815
|
historyResults.unshift(result);
|
|
@@ -34803,14 +34847,26 @@ function setReplHistoryVariables(context) {
|
|
|
34803
34847
|
}
|
|
34804
34848
|
function parseOption(args, i) {
|
|
34805
34849
|
const option = args[i];
|
|
34806
|
-
|
|
34807
|
-
|
|
34808
|
-
|
|
34809
|
-
|
|
34850
|
+
// Short option: -x
|
|
34851
|
+
if (/^-[a-z]$/i.test(option)) {
|
|
34852
|
+
if (booleanFlags.has(option)) {
|
|
34853
|
+
return { option, argument: null, count: 1 };
|
|
34854
|
+
}
|
|
34810
34855
|
return { option, argument: args[i + 1] ?? null, count: 2 };
|
|
34856
|
+
}
|
|
34857
|
+
// Long option: --foo or --foo=value
|
|
34811
34858
|
const match = /^(--[a-z-]+)(?:=(.*))?$/i.exec(option);
|
|
34812
|
-
if (match)
|
|
34813
|
-
|
|
34859
|
+
if (match) {
|
|
34860
|
+
const name = match[1];
|
|
34861
|
+
const inlineArg = match[2];
|
|
34862
|
+
if (inlineArg !== undefined) {
|
|
34863
|
+
return { option: name, argument: inlineArg, count: 1 };
|
|
34864
|
+
}
|
|
34865
|
+
if (booleanFlags.has(name)) {
|
|
34866
|
+
return { option: name, argument: null, count: 1 };
|
|
34867
|
+
}
|
|
34868
|
+
return { option: name, argument: args[i + 1] ?? null, count: 2 };
|
|
34869
|
+
}
|
|
34814
34870
|
return null;
|
|
34815
34871
|
}
|
|
34816
34872
|
function parseContextOptions(args, startIndex) {
|
|
@@ -34884,11 +34940,20 @@ function parsePrintOptions(args, startIndex) {
|
|
|
34884
34940
|
function parseRunEvalOptions(args, startIndex) {
|
|
34885
34941
|
let context = {};
|
|
34886
34942
|
let printResult = true;
|
|
34943
|
+
let pure = false;
|
|
34944
|
+
let positional = null;
|
|
34887
34945
|
let i = startIndex;
|
|
34888
34946
|
while (i < args.length) {
|
|
34889
34947
|
const parsed = parseOption(args, i);
|
|
34890
|
-
if (!parsed)
|
|
34891
|
-
|
|
34948
|
+
if (!parsed) {
|
|
34949
|
+
if (positional !== null) {
|
|
34950
|
+
printErrorMessage(`Unexpected argument "${args[i]}"`);
|
|
34951
|
+
process.exit(1);
|
|
34952
|
+
}
|
|
34953
|
+
positional = args[i];
|
|
34954
|
+
i += 1;
|
|
34955
|
+
continue;
|
|
34956
|
+
}
|
|
34892
34957
|
switch (parsed.option) {
|
|
34893
34958
|
case '-c':
|
|
34894
34959
|
case '--context':
|
|
@@ -34906,16 +34971,16 @@ function parseRunEvalOptions(args, startIndex) {
|
|
|
34906
34971
|
i = result.nextIndex;
|
|
34907
34972
|
break;
|
|
34908
34973
|
}
|
|
34974
|
+
case '--pure':
|
|
34975
|
+
pure = true;
|
|
34976
|
+
i += parsed.count;
|
|
34977
|
+
break;
|
|
34909
34978
|
default:
|
|
34910
34979
|
printErrorMessage(`Unknown option "${parsed.option}"`);
|
|
34911
34980
|
process.exit(1);
|
|
34912
34981
|
}
|
|
34913
34982
|
}
|
|
34914
|
-
|
|
34915
|
-
printErrorMessage(`Unknown argument "${args[i]}"`);
|
|
34916
|
-
process.exit(1);
|
|
34917
|
-
}
|
|
34918
|
-
return { context, printResult, nextIndex: i };
|
|
34983
|
+
return { context, printResult, pure, positional, nextIndex: i };
|
|
34919
34984
|
}
|
|
34920
34985
|
function processArguments(args) {
|
|
34921
34986
|
// Global flags (no subcommand)
|
|
@@ -34931,45 +34996,43 @@ function processArguments(args) {
|
|
|
34931
34996
|
}
|
|
34932
34997
|
switch (first) {
|
|
34933
34998
|
case 'run': {
|
|
34934
|
-
const filename = args
|
|
34935
|
-
if (!filename
|
|
34999
|
+
const { positional: filename, context, printResult, pure } = parseRunEvalOptions(args, 1);
|
|
35000
|
+
if (!filename) {
|
|
34936
35001
|
printErrorMessage('Missing filename after "run"');
|
|
34937
35002
|
process.exit(1);
|
|
34938
35003
|
}
|
|
34939
|
-
|
|
34940
|
-
return { subcommand: 'run', filename, context, printResult };
|
|
35004
|
+
return { subcommand: 'run', filename, context, printResult, pure };
|
|
34941
35005
|
}
|
|
34942
35006
|
case 'run-bundle': {
|
|
34943
|
-
const filename = args
|
|
34944
|
-
if (!filename
|
|
35007
|
+
const { positional: filename, context, printResult, pure } = parseRunEvalOptions(args, 1);
|
|
35008
|
+
if (!filename) {
|
|
34945
35009
|
printErrorMessage('Missing filename after "run-bundle"');
|
|
34946
35010
|
process.exit(1);
|
|
34947
35011
|
}
|
|
34948
|
-
|
|
34949
|
-
return { subcommand: 'run-bundle', filename, context, printResult };
|
|
35012
|
+
return { subcommand: 'run-bundle', filename, context, printResult, pure };
|
|
34950
35013
|
}
|
|
34951
35014
|
case 'eval': {
|
|
34952
|
-
const expression = args
|
|
34953
|
-
if (!expression
|
|
35015
|
+
const { positional: expression, context, printResult, pure } = parseRunEvalOptions(args, 1);
|
|
35016
|
+
if (!expression) {
|
|
34954
35017
|
printErrorMessage('Missing expression after "eval"');
|
|
34955
35018
|
process.exit(1);
|
|
34956
35019
|
}
|
|
34957
|
-
|
|
34958
|
-
return { subcommand: 'eval', expression, context, printResult };
|
|
35020
|
+
return { subcommand: 'eval', expression, context, printResult, pure };
|
|
34959
35021
|
}
|
|
34960
35022
|
case 'bundle': {
|
|
34961
|
-
|
|
34962
|
-
if (!filename || filename.startsWith('-')) {
|
|
34963
|
-
printErrorMessage('Missing filename after "bundle"');
|
|
34964
|
-
process.exit(1);
|
|
34965
|
-
}
|
|
35023
|
+
let filename = null;
|
|
34966
35024
|
let output = null;
|
|
34967
|
-
let i =
|
|
35025
|
+
let i = 1;
|
|
34968
35026
|
while (i < args.length) {
|
|
34969
35027
|
const parsed = parseOption(args, i);
|
|
34970
35028
|
if (!parsed) {
|
|
34971
|
-
|
|
34972
|
-
|
|
35029
|
+
if (filename !== null) {
|
|
35030
|
+
printErrorMessage(`Unexpected argument "${args[i]}"`);
|
|
35031
|
+
process.exit(1);
|
|
35032
|
+
}
|
|
35033
|
+
filename = args[i];
|
|
35034
|
+
i += 1;
|
|
35035
|
+
continue;
|
|
34973
35036
|
}
|
|
34974
35037
|
switch (parsed.option) {
|
|
34975
35038
|
case '-o':
|
|
@@ -34986,21 +35049,26 @@ function processArguments(args) {
|
|
|
34986
35049
|
process.exit(1);
|
|
34987
35050
|
}
|
|
34988
35051
|
}
|
|
35052
|
+
if (!filename) {
|
|
35053
|
+
printErrorMessage('Missing filename after "bundle"');
|
|
35054
|
+
process.exit(1);
|
|
35055
|
+
}
|
|
34989
35056
|
return { subcommand: 'bundle', filename, output };
|
|
34990
35057
|
}
|
|
34991
35058
|
case 'test': {
|
|
34992
|
-
|
|
34993
|
-
if (!filename || filename.startsWith('-')) {
|
|
34994
|
-
printErrorMessage('Missing filename after "test"');
|
|
34995
|
-
process.exit(1);
|
|
34996
|
-
}
|
|
35059
|
+
let filename = null;
|
|
34997
35060
|
let testPattern = null;
|
|
34998
|
-
let i =
|
|
35061
|
+
let i = 1;
|
|
34999
35062
|
while (i < args.length) {
|
|
35000
35063
|
const parsed = parseOption(args, i);
|
|
35001
35064
|
if (!parsed) {
|
|
35002
|
-
|
|
35003
|
-
|
|
35065
|
+
if (filename !== null) {
|
|
35066
|
+
printErrorMessage(`Unexpected argument "${args[i]}"`);
|
|
35067
|
+
process.exit(1);
|
|
35068
|
+
}
|
|
35069
|
+
filename = args[i];
|
|
35070
|
+
i += 1;
|
|
35071
|
+
continue;
|
|
35004
35072
|
}
|
|
35005
35073
|
switch (parsed.option) {
|
|
35006
35074
|
case '--pattern':
|
|
@@ -35016,6 +35084,10 @@ function processArguments(args) {
|
|
|
35016
35084
|
process.exit(1);
|
|
35017
35085
|
}
|
|
35018
35086
|
}
|
|
35087
|
+
if (!filename) {
|
|
35088
|
+
printErrorMessage('Missing filename after "test"');
|
|
35089
|
+
process.exit(1);
|
|
35090
|
+
}
|
|
35019
35091
|
return { subcommand: 'test', filename, testPattern };
|
|
35020
35092
|
}
|
|
35021
35093
|
case 'repl': {
|
|
@@ -35147,6 +35219,7 @@ Run/Run-bundle/Eval options:
|
|
|
35147
35219
|
-c, --context=<json> Context as a JSON string
|
|
35148
35220
|
-C, --context-file=<file> Context from a .json file
|
|
35149
35221
|
-s, --silent Suppress printing the result
|
|
35222
|
+
--pure Enforce pure mode (no side effects or non-determinism)
|
|
35150
35223
|
|
|
35151
35224
|
Bundle options:
|
|
35152
35225
|
-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';
|