deep6 1.1.4 → 1.2.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/LICENSE +1 -1
- package/README.md +40 -39
- package/llms-full.txt +371 -0
- package/llms.txt +154 -0
- package/package.json +31 -109
- package/src/env.d.ts +174 -0
- package/src/env.js +4 -4
- package/src/index.d.ts +86 -0
- package/src/index.js +10 -7
- package/src/traverse/assemble.d.ts +59 -0
- package/src/traverse/assemble.js +4 -3
- package/src/traverse/clone.d.ts +57 -0
- package/src/traverse/clone.js +4 -2
- package/src/traverse/deref.d.ts +59 -0
- package/src/traverse/deref.js +3 -2
- package/src/traverse/preprocess.d.ts +65 -0
- package/src/traverse/preprocess.js +2 -1
- package/src/traverse/walk.d.ts +219 -0
- package/src/traverse/walk.js +9 -4
- package/src/unifiers/matchCondition.d.ts +45 -0
- package/src/unifiers/matchCondition.js +1 -0
- package/src/unifiers/matchInstanceOf.d.ts +37 -0
- package/src/unifiers/matchInstanceOf.js +1 -0
- package/src/unifiers/matchString.d.ts +56 -0
- package/src/unifiers/matchString.js +1 -0
- package/src/unifiers/matchTypeOf.d.ts +37 -0
- package/src/unifiers/matchTypeOf.js +1 -0
- package/src/unifiers/ref.d.ts +52 -0
- package/src/unifiers/ref.js +1 -0
- package/src/unify.d.ts +95 -0
- package/src/unify.js +130 -66
- package/src/utils/replaceVars.d.ts +25 -0
- package/src/utils/replaceVars.js +23 -19
- package/cjs/env.js +0 -183
- package/cjs/index.js +0 -44
- package/cjs/package.json +0 -1
- package/cjs/traverse/assemble.js +0 -129
- package/cjs/traverse/clone.js +0 -82
- package/cjs/traverse/deref.js +0 -87
- package/cjs/traverse/preprocess.js +0 -84
- package/cjs/traverse/walk.js +0 -263
- package/cjs/unifiers/matchCondition.js +0 -18
- package/cjs/unifiers/matchInstanceOf.js +0 -18
- package/cjs/unifiers/matchString.js +0 -38
- package/cjs/unifiers/matchTypeOf.js +0 -18
- package/cjs/unifiers/ref.js +0 -23
- package/cjs/unify.js +0 -473
- package/cjs/utils/replaceVars.js +0 -28
package/src/unify.d.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// Type definitions for deep6 unification
|
|
2
|
+
// Generated from src/unify.js
|
|
3
|
+
|
|
4
|
+
import {Env, Unifier, Variable} from './env.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Options for unification
|
|
8
|
+
*/
|
|
9
|
+
export interface UnifyOptions {
|
|
10
|
+
/** Handle circular references (default: false) */
|
|
11
|
+
circular?: boolean;
|
|
12
|
+
/** Include symbol properties (default: false) */
|
|
13
|
+
symbols?: boolean;
|
|
14
|
+
/** Use loose equality for primitives (default: false) */
|
|
15
|
+
loose?: boolean;
|
|
16
|
+
/** Ignore function properties (default: false) */
|
|
17
|
+
ignoreFunctions?: boolean;
|
|
18
|
+
/** Distinguish +0 from -0 (default: false) */
|
|
19
|
+
signedZero?: boolean;
|
|
20
|
+
/** Allow extra keys on target objects (default: false) */
|
|
21
|
+
openObjects?: boolean;
|
|
22
|
+
/** Allow extra elements in target arrays (default: false) */
|
|
23
|
+
openArrays?: boolean;
|
|
24
|
+
/** Allow extra entries in target Maps (default: false) */
|
|
25
|
+
openMaps?: boolean;
|
|
26
|
+
/** Allow extra entries in target Sets (default: false) */
|
|
27
|
+
openSets?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Core unification algorithm
|
|
32
|
+
*
|
|
33
|
+
* Attempts to unify two values, optionally binding variables.
|
|
34
|
+
* Returns an Env with bindings on success, or null on failure.
|
|
35
|
+
*
|
|
36
|
+
* @param l - Left value
|
|
37
|
+
* @param r - Right value
|
|
38
|
+
* @param env - Existing environment, options object, or null
|
|
39
|
+
* @param options - Unification options (when env is provided separately)
|
|
40
|
+
* @returns Environment with bindings, or null on failure
|
|
41
|
+
*/
|
|
42
|
+
export declare const unify: (l: unknown, r: unknown, env?: Env | UnifyOptions | null, options?: UnifyOptions) => Env | null;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Flat array of type-specific unifier pairs: [Constructor, handler, Constructor, handler, ...]
|
|
46
|
+
*
|
|
47
|
+
* Use `registry.push(Type, handler)` to register a custom type handler.
|
|
48
|
+
* Handler signature: `(l, r, ls, rs, env) => boolean`
|
|
49
|
+
*/
|
|
50
|
+
export declare const registry: unknown[];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Flat array of filter pairs: [predicate, handler, predicate, handler, ...]
|
|
54
|
+
*
|
|
55
|
+
* Use `filters.push(predicate, handler)` to register a custom filter.
|
|
56
|
+
*/
|
|
57
|
+
export declare const filters: unknown[];
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Wraps a value for open matching (target may have extra properties)
|
|
61
|
+
* @param o - Value to wrap
|
|
62
|
+
* @returns Open-wrapped value
|
|
63
|
+
*/
|
|
64
|
+
export declare const open: <T>(o: T) => T;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Wraps a value for soft matching (bidirectional open, updates both sides)
|
|
68
|
+
* @param o - Value to wrap
|
|
69
|
+
* @returns Soft-wrapped value
|
|
70
|
+
*/
|
|
71
|
+
export declare const soft: <T>(o: T) => T;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Checks if a value is open-wrapped
|
|
75
|
+
* @param o - Value to check
|
|
76
|
+
*/
|
|
77
|
+
export declare const isOpen: (o: unknown) => boolean;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Checks if a value is soft-wrapped
|
|
81
|
+
* @param o - Value to check
|
|
82
|
+
*/
|
|
83
|
+
export declare const isSoft: (o: unknown) => boolean;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Checks if a value is wrapped (open or soft)
|
|
87
|
+
* @param o - Value to check
|
|
88
|
+
*/
|
|
89
|
+
export declare const isWrapped: (o: unknown) => boolean;
|
|
90
|
+
|
|
91
|
+
// Re-exports from env.js (value exports, usable as constructors)
|
|
92
|
+
export {Env, Unifier, Variable} from './env.js';
|
|
93
|
+
export {_, any, isUnifier, isVariable, variable} from './env.js';
|
|
94
|
+
|
|
95
|
+
export default unify;
|
package/src/unify.js
CHANGED
|
@@ -24,18 +24,17 @@ class Wrap extends Unifier {
|
|
|
24
24
|
value = isWrapped ? val.object : val;
|
|
25
25
|
if (!value || typeof value != 'object' || Array.isArray(this.object) !== Array.isArray(value)) return false;
|
|
26
26
|
if (Array.isArray(this.object)) {
|
|
27
|
-
if (!Array.isArray(value)) return false;
|
|
28
27
|
return isWrapped
|
|
29
28
|
? unifyObjects(this.object, this.type, this, val.object, val.type, val, ls, rs, env)
|
|
30
29
|
: unifyObjects(this.object, this.type, this, val, env.openArrays ? 'open' : 'exact', null, ls, rs, env);
|
|
31
30
|
}
|
|
32
|
-
if (
|
|
31
|
+
if (this.object instanceof Map) {
|
|
33
32
|
if (!(value instanceof Map)) return false;
|
|
34
33
|
return isWrapped
|
|
35
34
|
? unifyMaps(this.object, this.type, this, val.object, val.type, val, ls, rs, env)
|
|
36
35
|
: unifyMaps(this.object, this.type, this, val, env.openMaps ? 'open' : 'exact', null, ls, rs, env);
|
|
37
36
|
}
|
|
38
|
-
if (
|
|
37
|
+
if (this.object instanceof Set) {
|
|
39
38
|
if (!(value instanceof Set)) return false;
|
|
40
39
|
return isWrapped
|
|
41
40
|
? unifySets(this.object, this.type, this, val.object, val.type, val, ls, rs, env)
|
|
@@ -61,11 +60,12 @@ const registry = [
|
|
|
61
60
|
Date,
|
|
62
61
|
(l, r) => l instanceof Date && r instanceof Date && l.getTime() == r.getTime(),
|
|
63
62
|
RegExp,
|
|
64
|
-
(l, r) =>
|
|
65
|
-
l instanceof RegExp && r instanceof RegExp && l.source == r.source && l.global == r.global && l.multiline == r.multiline && l.ignoreCase == r.ignoreCase
|
|
63
|
+
(l, r) => l instanceof RegExp && r instanceof RegExp && l.source == r.source && l.flags == r.flags
|
|
66
64
|
],
|
|
67
65
|
filters = [];
|
|
68
66
|
|
|
67
|
+
typeof URL == 'function' && registry.push(URL, (l, r) => l instanceof URL && r instanceof URL && l.href == r.href);
|
|
68
|
+
|
|
69
69
|
// possible well-known constructors
|
|
70
70
|
|
|
71
71
|
const unifyTypedArrays = Type => (l, r, ls, rs, env) => {
|
|
@@ -99,9 +99,10 @@ const unifyDataView = (l, r, ls, rs, env) => {
|
|
|
99
99
|
};
|
|
100
100
|
typeof DataView == 'function' && registry.push(DataView, unifyDataView);
|
|
101
101
|
|
|
102
|
+
const unifyUint8Array = unifyTypedArrays(Uint8Array);
|
|
102
103
|
const unifyArrayBuffer = (l, r, ls, rs, env) => {
|
|
103
104
|
if (!(l instanceof ArrayBuffer) || !(r instanceof ArrayBuffer) || l.byteLength != r.byteLength) return false;
|
|
104
|
-
return
|
|
105
|
+
return unifyUint8Array(new Uint8Array(l), new Uint8Array(r), ls, rs, env);
|
|
105
106
|
};
|
|
106
107
|
typeof ArrayBuffer == 'function' && typeof Uint8Array == 'function' && registry.push(ArrayBuffer, unifyArrayBuffer);
|
|
107
108
|
|
|
@@ -161,22 +162,28 @@ const mapOps = {
|
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
164
|
};
|
|
164
|
-
mapOps.exact.exact.compare =
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
165
|
+
mapOps.exact.exact.compare =
|
|
166
|
+
mapOps.exact.open.compare =
|
|
167
|
+
mapOps.exact.soft.compare =
|
|
168
|
+
(l, r, ls, rs) => {
|
|
169
|
+
for (const [key, value] of r) {
|
|
170
|
+
if (!l.has(key)) return false;
|
|
171
|
+
ls.push(l.get(key));
|
|
172
|
+
rs.push(value);
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
};
|
|
176
|
+
mapOps.open.open.compare =
|
|
177
|
+
mapOps.open.soft.compare =
|
|
178
|
+
mapOps.soft.soft.compare =
|
|
179
|
+
(l, r, ls, rs) => {
|
|
180
|
+
for (const [key, value] of r) {
|
|
181
|
+
if (!l.has(key)) continue;
|
|
182
|
+
ls.push(l.get(key));
|
|
183
|
+
rs.push(value);
|
|
184
|
+
}
|
|
185
|
+
return true;
|
|
186
|
+
};
|
|
180
187
|
mapOps.exact.soft.update = mapOps.open.soft.update = function () {
|
|
181
188
|
for (const [key, value] of this.l) {
|
|
182
189
|
!this.r.has(key) && this.r.set(key, value);
|
|
@@ -186,7 +193,19 @@ mapOps.exact.soft.update = mapOps.open.soft.update = function () {
|
|
|
186
193
|
const unifyMaps = (l, lt, lm, r, rt, rm, ls, rs, env) => {
|
|
187
194
|
const ols = ls;
|
|
188
195
|
if (lt > rt) {
|
|
189
|
-
|
|
196
|
+
let tmp;
|
|
197
|
+
tmp = l;
|
|
198
|
+
l = r;
|
|
199
|
+
r = tmp;
|
|
200
|
+
tmp = lt;
|
|
201
|
+
lt = rt;
|
|
202
|
+
rt = tmp;
|
|
203
|
+
tmp = lm;
|
|
204
|
+
lm = rm;
|
|
205
|
+
rm = tmp;
|
|
206
|
+
tmp = ls;
|
|
207
|
+
ls = rs;
|
|
208
|
+
rs = tmp;
|
|
190
209
|
}
|
|
191
210
|
const ops = mapOps[lt][rt];
|
|
192
211
|
if (ops.precheck && !ops.precheck(l, r)) return false;
|
|
@@ -231,8 +250,13 @@ const setOps = {
|
|
|
231
250
|
}
|
|
232
251
|
}
|
|
233
252
|
};
|
|
234
|
-
setOps.exact.exact.compare =
|
|
235
|
-
|
|
253
|
+
setOps.exact.exact.compare =
|
|
254
|
+
setOps.exact.open.compare =
|
|
255
|
+
setOps.exact.soft.compare =
|
|
256
|
+
setOps.open.open.compare =
|
|
257
|
+
setOps.open.soft.compare =
|
|
258
|
+
setOps.soft.soft.compare =
|
|
259
|
+
() => true;
|
|
236
260
|
setOps.exact.soft.update = setOps.open.soft.update = function () {
|
|
237
261
|
for (const key of this.l) {
|
|
238
262
|
this.r.add(key);
|
|
@@ -242,7 +266,19 @@ setOps.exact.soft.update = setOps.open.soft.update = function () {
|
|
|
242
266
|
const unifySets = (l, lt, lm, r, rt, rm, ls, rs, env) => {
|
|
243
267
|
const ols = ls;
|
|
244
268
|
if (lt > rt) {
|
|
245
|
-
|
|
269
|
+
let tmp;
|
|
270
|
+
tmp = l;
|
|
271
|
+
l = r;
|
|
272
|
+
r = tmp;
|
|
273
|
+
tmp = lt;
|
|
274
|
+
lt = rt;
|
|
275
|
+
rt = tmp;
|
|
276
|
+
tmp = lm;
|
|
277
|
+
lm = rm;
|
|
278
|
+
rm = tmp;
|
|
279
|
+
tmp = ls;
|
|
280
|
+
ls = rs;
|
|
281
|
+
rs = tmp;
|
|
246
282
|
}
|
|
247
283
|
const ops = setOps[lt][rt];
|
|
248
284
|
if (ops.precheck && !ops.precheck(l, r)) return false;
|
|
@@ -267,7 +303,10 @@ const objectOps = {
|
|
|
267
303
|
rKeys = rKeys.concat(Object.getOwnPropertySymbols(r));
|
|
268
304
|
}
|
|
269
305
|
if (lKeys.length != rKeys.length) return false;
|
|
270
|
-
|
|
306
|
+
for (let i = 0; i < lKeys.length; ++i) {
|
|
307
|
+
if (!hasOwnProperty.call(r, lKeys[i])) return false;
|
|
308
|
+
}
|
|
309
|
+
return true;
|
|
271
310
|
}
|
|
272
311
|
},
|
|
273
312
|
open: {},
|
|
@@ -298,29 +337,34 @@ const objectOps = {
|
|
|
298
337
|
}
|
|
299
338
|
}
|
|
300
339
|
};
|
|
301
|
-
objectOps.exact.exact.compare =
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
340
|
+
objectOps.exact.exact.compare =
|
|
341
|
+
objectOps.exact.open.compare =
|
|
342
|
+
objectOps.exact.soft.compare =
|
|
343
|
+
(l, r, ls, rs, env) => {
|
|
344
|
+
let keys = Object.keys(r);
|
|
345
|
+
if (env.symbols) keys = keys.concat(Object.getOwnPropertySymbols(r));
|
|
346
|
+
for (let i = 0; i < keys.length; ++i) {
|
|
347
|
+
const k = keys[i];
|
|
348
|
+
if (!hasOwnProperty.call(l, k)) return false;
|
|
349
|
+
ls.push(l[k]);
|
|
350
|
+
rs.push(r[k]);
|
|
351
|
+
}
|
|
308
352
|
return true;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
};
|
|
353
|
+
};
|
|
354
|
+
objectOps.open.open.compare =
|
|
355
|
+
objectOps.open.soft.compare =
|
|
356
|
+
objectOps.soft.soft.compare =
|
|
357
|
+
(l, r, ls, rs, env) => {
|
|
358
|
+
let keys = Object.keys(r);
|
|
359
|
+
if (env.symbols) keys = keys.concat(Object.getOwnPropertySymbols(r));
|
|
360
|
+
for (const k of keys) {
|
|
361
|
+
if (hasOwnProperty.call(l, k)) {
|
|
362
|
+
ls.push(l[k]);
|
|
363
|
+
rs.push(r[k]);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return true;
|
|
367
|
+
};
|
|
324
368
|
objectOps.exact.soft.update = objectOps.open.soft.update = function () {
|
|
325
369
|
let keys = Object.keys(this.l);
|
|
326
370
|
if (this.e.symbols) keys = keys.concat(Object.getOwnPropertySymbols(this.l));
|
|
@@ -332,7 +376,19 @@ objectOps.exact.soft.update = objectOps.open.soft.update = function () {
|
|
|
332
376
|
const unifyObjects = (l, lt, lm, r, rt, rm, ls, rs, env) => {
|
|
333
377
|
const ols = ls;
|
|
334
378
|
if (lt > rt) {
|
|
335
|
-
|
|
379
|
+
let tmp;
|
|
380
|
+
tmp = l;
|
|
381
|
+
l = r;
|
|
382
|
+
r = tmp;
|
|
383
|
+
tmp = lt;
|
|
384
|
+
lt = rt;
|
|
385
|
+
rt = tmp;
|
|
386
|
+
tmp = lm;
|
|
387
|
+
lm = rm;
|
|
388
|
+
rm = tmp;
|
|
389
|
+
tmp = ls;
|
|
390
|
+
ls = rs;
|
|
391
|
+
rs = tmp;
|
|
336
392
|
}
|
|
337
393
|
const ops = objectOps[lt][rt];
|
|
338
394
|
if (ops.precheck && !ops.precheck(l, r, env)) return false;
|
|
@@ -354,36 +410,39 @@ const unify = (l, r, env, options) => {
|
|
|
354
410
|
env = Object.assign(env, options);
|
|
355
411
|
// options: openObjects, openArrays, openMaps, openSets, circular, loose, ignoreFunctions, signedZero, symbols.
|
|
356
412
|
const ls = [l],
|
|
357
|
-
rs = [r]
|
|
358
|
-
|
|
413
|
+
rs = [r];
|
|
414
|
+
let lSeen, rSeen;
|
|
415
|
+
if (env.circular) {
|
|
416
|
+
lSeen = new Map();
|
|
359
417
|
rSeen = new Map();
|
|
418
|
+
}
|
|
360
419
|
main: while (ls.length) {
|
|
361
420
|
// perform a command, or extract a pair
|
|
362
421
|
l = ls.pop();
|
|
363
|
-
if (l instanceof Command) {
|
|
422
|
+
if (typeof l == 'object' && l instanceof Command) {
|
|
364
423
|
l.f();
|
|
365
424
|
continue;
|
|
366
425
|
}
|
|
367
426
|
r = rs.pop();
|
|
368
427
|
// direct equality
|
|
369
428
|
if (l === r) {
|
|
370
|
-
if (
|
|
429
|
+
if (lSeen && l && typeof l == 'object' && lSeen.has(l) ^ rSeen.has(r)) return null;
|
|
371
430
|
if (env.signedZero && l === 0 && 1 / l !== 1 / r) return null;
|
|
372
431
|
continue;
|
|
373
432
|
}
|
|
374
433
|
// anyvar
|
|
375
434
|
if (l === _ || r === _) continue;
|
|
376
435
|
// process variables (variables have priority)
|
|
377
|
-
if (l instanceof Variable) {
|
|
436
|
+
if (typeof l == 'object' && l instanceof Variable) {
|
|
378
437
|
if (l.unify(r, ls, rs, env)) continue;
|
|
379
438
|
return null;
|
|
380
439
|
}
|
|
381
|
-
if (r instanceof Variable) {
|
|
440
|
+
if (typeof r == 'object' && r instanceof Variable) {
|
|
382
441
|
if (r.unify(l, ls, rs, env)) continue;
|
|
383
442
|
return null;
|
|
384
443
|
}
|
|
385
444
|
// process circular dependencies
|
|
386
|
-
if (
|
|
445
|
+
if (lSeen) {
|
|
387
446
|
const lIndex = lSeen.get(l);
|
|
388
447
|
if (typeof lIndex == 'number') {
|
|
389
448
|
if (lIndex === rSeen.get(r)) continue main;
|
|
@@ -396,11 +455,11 @@ const unify = (l, r, env, options) => {
|
|
|
396
455
|
r && typeof r == 'object' && rSeen.set(r, rSeen.size);
|
|
397
456
|
}
|
|
398
457
|
// invoke custom unifiers
|
|
399
|
-
if (l instanceof Unifier) {
|
|
458
|
+
if (typeof l == 'object' && l instanceof Unifier) {
|
|
400
459
|
if (l.unify(r, ls, rs, env)) continue;
|
|
401
460
|
return null;
|
|
402
461
|
}
|
|
403
|
-
if (r instanceof Unifier) {
|
|
462
|
+
if (typeof r == 'object' && r instanceof Unifier) {
|
|
404
463
|
if (r.unify(l, ls, rs, env)) continue;
|
|
405
464
|
return null;
|
|
406
465
|
}
|
|
@@ -414,12 +473,17 @@ const unify = (l, r, env, options) => {
|
|
|
414
473
|
if (typeof l == 'number' && isNaN(l) && isNaN(r)) continue;
|
|
415
474
|
// cut off impossible combinations
|
|
416
475
|
if (typeof l != 'object' || !l || !r) return null;
|
|
417
|
-
//
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
476
|
+
// fast path: plain objects and arrays skip registry
|
|
477
|
+
const lp = Object.getPrototypeOf(l),
|
|
478
|
+
rp = Object.getPrototypeOf(r);
|
|
479
|
+
if (!((lp === Object.prototype || lp === null || lp === Array.prototype) && (rp === Object.prototype || rp === null || rp === Array.prototype))) {
|
|
480
|
+
// process registered constructors
|
|
481
|
+
const registry = unify.registry;
|
|
482
|
+
for (let i = 0; i < registry.length; i += 2) {
|
|
483
|
+
if (l instanceof registry[i] || r instanceof registry[i]) {
|
|
484
|
+
if (registry[i + 1](l, r, ls, rs, env)) continue main;
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
423
487
|
}
|
|
424
488
|
}
|
|
425
489
|
// process registered filters
|
|
@@ -442,5 +506,5 @@ const unify = (l, r, env, options) => {
|
|
|
442
506
|
unify.registry = registry;
|
|
443
507
|
unify.filters = filters;
|
|
444
508
|
|
|
445
|
-
export {_, Env, Unifier, isUnifier, Variable, variable, isVariable, _ as any, open, soft, isOpen, isSoft, isWrapped};
|
|
509
|
+
export {_, Env, Unifier, isUnifier, Variable, variable, isVariable, _ as any, open, soft, isOpen, isSoft, isWrapped, unify};
|
|
446
510
|
export default unify;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Type definitions for deep6 replaceVars utility
|
|
2
|
+
// Generated from src/utils/replaceVars.js
|
|
3
|
+
|
|
4
|
+
import type {Env, Variable} from '../env.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates a tagged template function that substitutes variables from an environment
|
|
8
|
+
*
|
|
9
|
+
* Template interpolations can be Variable instances (resolved via `.get(env)`),
|
|
10
|
+
* strings/numbers/symbols (looked up in `env.values`), or other values (coerced to string).
|
|
11
|
+
*
|
|
12
|
+
* @param env - Unification environment with variable bindings
|
|
13
|
+
* @returns A tagged template literal function
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const x = variable('x');
|
|
18
|
+
* const env = unify({a: x}, {a: 42});
|
|
19
|
+
* const t = replaceVars(env);
|
|
20
|
+
* t`The answer is ${x}!`; // "The answer is 42!"
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare const replaceVars: (env: Env) => (strings: TemplateStringsArray, ...vars: unknown[]) => string;
|
|
24
|
+
|
|
25
|
+
export default replaceVars;
|
package/src/utils/replaceVars.js
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
import {isVariable} from '../env.js';
|
|
2
2
|
|
|
3
|
-
const replaceVars =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
const replaceVars =
|
|
4
|
+
env =>
|
|
5
|
+
(strings, ...vars) => {
|
|
6
|
+
let buffer = strings[0];
|
|
7
|
+
for (let i = 0; i < vars.length; ) {
|
|
8
|
+
const v = vars[i];
|
|
9
|
+
if (isVariable(v)) {
|
|
10
|
+
buffer += v.get(env);
|
|
11
|
+
} else
|
|
12
|
+
switch (typeof v) {
|
|
13
|
+
case 'string':
|
|
14
|
+
case 'number':
|
|
15
|
+
case 'symbol':
|
|
16
|
+
buffer += env.values[v];
|
|
17
|
+
break;
|
|
18
|
+
default:
|
|
19
|
+
buffer += v;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
buffer += strings[++i];
|
|
18
23
|
}
|
|
19
|
-
buffer
|
|
20
|
-
}
|
|
21
|
-
return buffer;
|
|
22
|
-
};
|
|
24
|
+
return buffer;
|
|
25
|
+
};
|
|
23
26
|
|
|
27
|
+
export {replaceVars};
|
|
24
28
|
export default replaceVars;
|
package/cjs/env.js
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.variable = exports.isVariable = exports.isUnifier = exports.any = exports._ = exports.Variable = exports.Unifier = exports.Env = void 0;
|
|
7
|
-
// Env
|
|
8
|
-
|
|
9
|
-
const keyDepth = Symbol.for('deep6.env.depth');
|
|
10
|
-
const collectSymbols = object => {
|
|
11
|
-
const symbols = new Set();
|
|
12
|
-
while (object && typeof object == 'object') {
|
|
13
|
-
Object.getOwnPropertySymbols(object).forEach(symbol => symbols.add(symbol));
|
|
14
|
-
object = Object.getPrototypeOf(object);
|
|
15
|
-
}
|
|
16
|
-
symbols.delete(keyDepth);
|
|
17
|
-
return Array.from(symbols);
|
|
18
|
-
};
|
|
19
|
-
const ensure = (object, depth) => {
|
|
20
|
-
while (object[keyDepth] > depth) object = object.getPrototypeOf(object);
|
|
21
|
-
if (object[keyDepth] < depth) {
|
|
22
|
-
object = Object.create(object);
|
|
23
|
-
object[keyDepth] = depth;
|
|
24
|
-
}
|
|
25
|
-
return object;
|
|
26
|
-
};
|
|
27
|
-
class Env {
|
|
28
|
-
constructor() {
|
|
29
|
-
this.variables = Object.create(null);
|
|
30
|
-
this.values = Object.create(null);
|
|
31
|
-
this.depth = this.variables[keyDepth] = this.values[keyDepth] = 0;
|
|
32
|
-
}
|
|
33
|
-
push() {
|
|
34
|
-
++this.depth;
|
|
35
|
-
}
|
|
36
|
-
pop() {
|
|
37
|
-
if (this.depth < 1) throw new Error('attempt to pop a frame with an empty stack');
|
|
38
|
-
--this.depth;
|
|
39
|
-
while (this.variables[keyDepth] > this.depth) this.variables = Object.getPrototypeOf(this.variables);
|
|
40
|
-
while (this.values[keyDepth] > this.depth) this.values = Object.getPrototypeOf(this.values);
|
|
41
|
-
}
|
|
42
|
-
revert(depth) {
|
|
43
|
-
if (this.depth < depth) throw new Error('attempt to revert a stack to a higher depth');
|
|
44
|
-
while (this.variables[keyDepth] > depth) this.variables = Object.getPrototypeOf(this.variables);
|
|
45
|
-
while (this.values[keyDepth] > depth) this.values = Object.getPrototypeOf(this.values);
|
|
46
|
-
this.depth = depth;
|
|
47
|
-
}
|
|
48
|
-
bindVar(name1, name2) {
|
|
49
|
-
const depth = this.depth,
|
|
50
|
-
vars = this.variables = ensure(this.variables, depth);
|
|
51
|
-
let u1 = vars[name1],
|
|
52
|
-
u2 = vars[name2];
|
|
53
|
-
u1 && (u1 = vars[name1] = ensure(u1, depth));
|
|
54
|
-
u2 && (u2 = vars[name2] = ensure(u2, depth));
|
|
55
|
-
if (u1) {
|
|
56
|
-
if (u2) {
|
|
57
|
-
for (const k in u2) {
|
|
58
|
-
vars[k] = u1;
|
|
59
|
-
u1[k] = 1;
|
|
60
|
-
}
|
|
61
|
-
collectSymbols(u2).forEach(k => (vars[k] = u1, u1[k] = 1));
|
|
62
|
-
} else {
|
|
63
|
-
vars[name2] = u1;
|
|
64
|
-
u1[name2] = 1;
|
|
65
|
-
}
|
|
66
|
-
} else {
|
|
67
|
-
if (u2) {
|
|
68
|
-
vars[name1] = u2;
|
|
69
|
-
u2[name1] = 1;
|
|
70
|
-
} else {
|
|
71
|
-
u2 = Object.create(null);
|
|
72
|
-
u2[keyDepth] = depth;
|
|
73
|
-
vars[name1] = vars[name2] = u2;
|
|
74
|
-
u2[name1] = u2[name2] = 1;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
bindVal(name, val) {
|
|
79
|
-
const depth = this.depth,
|
|
80
|
-
values = this.values = ensure(this.values, depth),
|
|
81
|
-
vars = this.variables = ensure(this.variables, depth);
|
|
82
|
-
let u = vars[name];
|
|
83
|
-
u && (u = vars[name] = ensure(u, depth));
|
|
84
|
-
if (u) {
|
|
85
|
-
for (const k in u) {
|
|
86
|
-
values[k] = val;
|
|
87
|
-
vars[k] = null;
|
|
88
|
-
}
|
|
89
|
-
collectSymbols(u).forEach(k => (values[k] = val, vars[k] = null));
|
|
90
|
-
} else {
|
|
91
|
-
values[name] = val;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
// helpers
|
|
95
|
-
isBound(name) {
|
|
96
|
-
return name in env.values;
|
|
97
|
-
}
|
|
98
|
-
isAlias(name1, name2) {
|
|
99
|
-
const u = env.variables[name2];
|
|
100
|
-
return u && u[name1] === 1;
|
|
101
|
-
}
|
|
102
|
-
get(name) {
|
|
103
|
-
return env.values[name];
|
|
104
|
-
}
|
|
105
|
-
// debugging
|
|
106
|
-
getAllValues() {
|
|
107
|
-
const values = this.values,
|
|
108
|
-
result = collectSymbols(values).map(k => ({
|
|
109
|
-
name: k,
|
|
110
|
-
value: values[k]
|
|
111
|
-
}));
|
|
112
|
-
for (const k in values) {
|
|
113
|
-
result.push({
|
|
114
|
-
name: k,
|
|
115
|
-
value: values[k]
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
return result;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Custom unifier
|
|
123
|
-
exports.Env = Env;
|
|
124
|
-
class Unifier {}
|
|
125
|
-
exports.Unifier = Unifier;
|
|
126
|
-
const isUnifier = x => x instanceof Unifier;
|
|
127
|
-
|
|
128
|
-
// Unifier should define a method:
|
|
129
|
-
// unify(val, ls, rs, env):
|
|
130
|
-
// val is a value we are unifying with
|
|
131
|
-
// ls is a stack of left arguments
|
|
132
|
-
// rs is a stack of right arguments corresponding to ls
|
|
133
|
-
// env is an environment
|
|
134
|
-
// the result should be true/false for success/failure
|
|
135
|
-
|
|
136
|
-
// AnyVar
|
|
137
|
-
exports.isUnifier = isUnifier;
|
|
138
|
-
const _ = exports._ = Symbol.for('deep6.any'),
|
|
139
|
-
any = exports.any = _;
|
|
140
|
-
|
|
141
|
-
// Variable
|
|
142
|
-
|
|
143
|
-
class Variable extends Unifier {
|
|
144
|
-
constructor(name) {
|
|
145
|
-
super();
|
|
146
|
-
this.name = name || Symbol();
|
|
147
|
-
}
|
|
148
|
-
isBound(env) {
|
|
149
|
-
return this.name in env.values;
|
|
150
|
-
}
|
|
151
|
-
isAlias(name, env) {
|
|
152
|
-
const u = env.variables[this.name];
|
|
153
|
-
return u && u[name instanceof Variable ? name.name : name] === 1;
|
|
154
|
-
}
|
|
155
|
-
get(env) {
|
|
156
|
-
return env.values[this.name];
|
|
157
|
-
}
|
|
158
|
-
unify(val, ls, rs, env) {
|
|
159
|
-
if (this.name in env.values) {
|
|
160
|
-
// isBound
|
|
161
|
-
ls.push(env.values[this.name]);
|
|
162
|
-
rs.push(val);
|
|
163
|
-
return true;
|
|
164
|
-
}
|
|
165
|
-
if (val === _ || val === this) return true;
|
|
166
|
-
if (val instanceof Variable) {
|
|
167
|
-
if (val.name in env.values) {
|
|
168
|
-
// isBound
|
|
169
|
-
env.bindVal(this.name, env.values[val.name]);
|
|
170
|
-
return true;
|
|
171
|
-
}
|
|
172
|
-
env.bindVar(this.name, val.name);
|
|
173
|
-
return true;
|
|
174
|
-
}
|
|
175
|
-
env.bindVal(this.name, val);
|
|
176
|
-
return true;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
exports.Variable = Variable;
|
|
180
|
-
const isVariable = x => x instanceof Variable,
|
|
181
|
-
variable = name => new Variable(name);
|
|
182
|
-
exports.variable = variable;
|
|
183
|
-
exports.isVariable = isVariable;
|