tape-six 0.9.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.
@@ -0,0 +1,262 @@
1
+ import {_} from '../unify.js';
2
+
3
+ const empty = {};
4
+
5
+ const nop = () => {};
6
+
7
+ // public utilities to build walkers
8
+
9
+ class Circular {
10
+ constructor(value) {
11
+ this.value = value;
12
+ }
13
+ }
14
+
15
+ const setObject = (seen, source, value) => {
16
+ const record = seen.get(source);
17
+ if (record) {
18
+ record.actions.forEach(([object, key]) => {
19
+ if (object instanceof Map) {
20
+ object.set(key, value);
21
+ } else {
22
+ const d = Object.getOwnPropertyDescriptor(object, key);
23
+ d.value = value;
24
+ Object.defineProperty(object, key, d);
25
+ }
26
+ });
27
+ }
28
+ seen.set(source, {value});
29
+ };
30
+
31
+ const processOther = (value, context) => context.stackOut.push(value);
32
+
33
+ const processCircular = (value, context) => context.stackOut.push(new Circular(value));
34
+
35
+ const processMap = (postProcess, postProcessSeen) => (object, context) => {
36
+ const stack = context.stack;
37
+ postProcess && stack.push(new Command(postProcessSeen ? (context.seen ? postProcessSeen : postProcess) : postProcess, object));
38
+ for (const value of object.values()) {
39
+ stack.push(value);
40
+ }
41
+ };
42
+
43
+ const postMapCircular = (source, context) => {
44
+ const {stackOut, seen, wrapMap} = context,
45
+ t = new Map();
46
+ for (const k of source.keys()) {
47
+ const value = stackOut.pop();
48
+ if (!(value instanceof Circular)) {
49
+ t.set(k, value);
50
+ continue;
51
+ }
52
+ const record = seen.get(value.value);
53
+ if (record) {
54
+ if (record.actions) {
55
+ record.actions.push([t, k]);
56
+ } else {
57
+ t.set(k, record.value);
58
+ }
59
+ } else {
60
+ seen.set(value.value, {actions: [[t, k]]});
61
+ }
62
+ }
63
+ const o = wrapMap ? wrapMap(t) : t;
64
+ setObject(seen, source, o);
65
+ stackOut.push(o);
66
+ };
67
+
68
+ const buildNewMap = (keys, stackOut, wrap) => {
69
+ const t = new Map();
70
+ for (const k of keys) {
71
+ t.set(k, stackOut.pop());
72
+ }
73
+ stackOut.push(wrap ? wrap(t) : t);
74
+ };
75
+
76
+ const replaceObject = (upTo, object, stackOut) => {
77
+ const l = stackOut.length - 1 - upTo;
78
+ if (l) {
79
+ stackOut.splice(-l, l, object);
80
+ } else {
81
+ stackOut.push(object);
82
+ }
83
+ };
84
+
85
+ const processObject = (postProcess, postProcessSeen) => (object, context) => {
86
+ const stack = context.stack;
87
+ postProcess && stack.push(new Command(postProcessSeen ? (context.seen ? postProcessSeen : postProcess) : postProcess, object));
88
+ const {descriptors, keys} = getObjectData(object, context);
89
+ for (const k of keys) {
90
+ const d = descriptors[k];
91
+ !(d.get || d.set) && stack.push(d.value);
92
+ }
93
+ };
94
+
95
+ const postObjectCircular = (source, descriptors, keys, context) => {
96
+ const {stackOut, seen} = context,
97
+ isArray = Array.isArray(source),
98
+ wrap = context[isArray ? 'wrapArray' : 'wrapObject'],
99
+ t = isArray ? [] : Object.create(Object.getPrototypeOf(source));
100
+ for (const k of keys) {
101
+ const d = descriptors[k];
102
+ if (d.get || d.set) {
103
+ Object.defineProperty(t, k, d);
104
+ continue;
105
+ }
106
+ const value = stackOut.pop();
107
+ if (!(value instanceof Circular)) {
108
+ d.value = value;
109
+ Object.defineProperty(t, k, d);
110
+ continue;
111
+ }
112
+ const record = seen.get(value.value);
113
+ if (record) {
114
+ if (record.actions) {
115
+ record.actions.push([t, k]);
116
+ d.value = null;
117
+ } else {
118
+ d.value = record.value;
119
+ }
120
+ Object.defineProperty(t, k, d);
121
+ continue;
122
+ }
123
+ seen.set(value.value, {actions: [[t, k]]});
124
+ d.value = null;
125
+ Object.defineProperty(t, k, d);
126
+ }
127
+ const o = wrap ? wrap(t) : t;
128
+ setObject(seen, source, o);
129
+ stackOut.push(o);
130
+ };
131
+
132
+ const getObjectData = (object, context) => {
133
+ const descriptors = Object.getOwnPropertyDescriptors(object);
134
+ if (Array.isArray(object)) delete descriptors.length;
135
+ let keys = Object.keys(descriptors);
136
+ if (context.symbols) keys = keys.concat(Object.getOwnPropertySymbols(descriptors));
137
+ if (!context.allProps) keys = keys.filter(key => descriptors[key].enumerable);
138
+ return {descriptors, keys};
139
+ };
140
+
141
+ const buildNewObject = (source, descriptors, keys, stackOut, wrap) => {
142
+ const t = Array.isArray(source) ? [] : Object.create(Object.getPrototypeOf(source));
143
+ for (const k of keys) {
144
+ const d = descriptors[k];
145
+ if (!(d.get || d.set)) {
146
+ d.value = stackOut.pop();
147
+ }
148
+ Object.defineProperty(t, k, d);
149
+ }
150
+ stackOut.push(wrap ? wrap(t) : t);
151
+ };
152
+
153
+ const processVariable = (val, context) => {
154
+ const env = context.env;
155
+ if (val.isBound(env)) {
156
+ context.stack.push(val.get(env));
157
+ } else {
158
+ context.stackOut.push(val);
159
+ }
160
+ };
161
+
162
+ // implementation
163
+
164
+ class Command {
165
+ constructor(f, s) {
166
+ this.f = f;
167
+ this.s = s;
168
+ }
169
+ }
170
+
171
+ const processCommand = (val, context) => val.f(context);
172
+
173
+ const defaultRegistry = [Command, processCommand, Array, processObject(), Date, nop, RegExp, nop, Map, processMap(), Set, nop, Promise, nop],
174
+ defaultFilters = [];
175
+
176
+ // add more types
177
+
178
+ const addType = (Type, process) => defaultRegistry.push(Type, process || nop);
179
+
180
+ typeof Int8Array == 'function' && addType(Int8Array);
181
+ typeof Uint8Array == 'function' && addType(Uint8Array);
182
+ typeof Uint8ClampedArray == 'function' && addType(Uint8ClampedArray);
183
+ typeof Int16Array == 'function' && addType(Int16Array);
184
+ typeof Uint16Array == 'function' && addType(Uint16Array);
185
+ typeof Int32Array == 'function' && addType(Int32Array);
186
+ typeof Uint32Array == 'function' && addType(Uint32Array);
187
+ typeof Float32Array == 'function' && addType(Float32Array);
188
+ typeof Float64Array == 'function' && addType(Float64Array);
189
+ typeof BigInt64Array == 'function' && addType(BigInt64Array);
190
+ typeof BigUint64Array == 'function' && addType(BigUint64Array);
191
+ typeof DataView == 'function' && addType(DataView);
192
+ typeof ArrayBuffer == 'function' && addType(ArrayBuffer);
193
+
194
+ // main
195
+
196
+ const walk = (o, options) => {
197
+ // non-recursive stack-based walk about an object tree
198
+ options = options || empty;
199
+ const doObject = options.processObject || processObject(),
200
+ doOther = options.processOther || nop,
201
+ doCircular = options.processCircular || nop,
202
+ registry = options.registry || defaultRegistry,
203
+ filters = options.filters || defaultFilters,
204
+ context = options.context || {},
205
+ stack = [o],
206
+ seen = options.circular ? new Map() : null;
207
+ context.stack = stack;
208
+ context.seen = seen;
209
+ context.symbols = options.symbols;
210
+ context.allProps = options.allProps;
211
+ main: while (stack.length) {
212
+ o = stack.pop();
213
+ if (!o || typeof o != 'object' || o === _) {
214
+ doOther(o, context);
215
+ continue;
216
+ }
217
+ // process circular dependencies
218
+ if (seen) {
219
+ if (seen.has(o)) {
220
+ doCircular(o, context);
221
+ continue;
222
+ }
223
+ seen.set(o, null);
224
+ }
225
+ // process registered constructors
226
+ for (let i = 0; i < registry.length; i += 2) {
227
+ if (o instanceof registry[i]) {
228
+ registry[i + 1](o, context);
229
+ continue main;
230
+ }
231
+ }
232
+ // process registered filters
233
+ for (let i = 0; i < filters.length; ++i) {
234
+ if (filters[i](o, context)) continue main;
235
+ }
236
+ // process naked objects
237
+ doObject(o, context);
238
+ }
239
+ };
240
+
241
+ walk.Command = Command;
242
+
243
+ export {
244
+ Command,
245
+ defaultRegistry as registry,
246
+ defaultFilters as filters,
247
+ Circular,
248
+ setObject,
249
+ processMap,
250
+ postMapCircular,
251
+ processOther,
252
+ processCircular,
253
+ buildNewMap,
254
+ replaceObject,
255
+ processObject,
256
+ postObjectCircular,
257
+ getObjectData,
258
+ buildNewObject,
259
+ processVariable,
260
+ processCommand
261
+ };
262
+ export default walk;
@@ -0,0 +1,16 @@
1
+ import {Unifier} from '../env.js';
2
+
3
+ class MatchCondition extends Unifier {
4
+ constructor(f) {
5
+ super();
6
+ this.f = f;
7
+ }
8
+
9
+ unify(val, ls, rs, env) {
10
+ return this.f(val, ls, rs, env);
11
+ }
12
+ }
13
+
14
+ const matchCondition = f => new MatchCondition(f);
15
+
16
+ export default matchCondition;
@@ -0,0 +1,16 @@
1
+ import {Unifier, isVariable} from '../env.js';
2
+
3
+ class MatchInstanceOf extends Unifier {
4
+ constructor(types) {
5
+ super();
6
+ this.types = types instanceof Array ? types : [types];
7
+ }
8
+
9
+ unify(val, ls, rs) {
10
+ return val && !isVariable(val) && this.types.some(type => val instanceof type);
11
+ }
12
+ }
13
+
14
+ const matchInstanceOf = types => new MatchInstanceOf(types);
15
+
16
+ export default matchInstanceOf;
@@ -0,0 +1,33 @@
1
+ import {Unifier, isVariable} from '../env.js';
2
+
3
+ class MatchString extends Unifier {
4
+ constructor(regexp, matches, props) {
5
+ super();
6
+ this.regexp = regexp;
7
+ this.matches = matches;
8
+ this.props = props;
9
+ }
10
+
11
+ unify(val, ls, rs) {
12
+ if (isVariable(val)) {
13
+ // cannot match with an unbound variable
14
+ return false;
15
+ }
16
+ const result = this.regexp.exec('' + val);
17
+ if (result) {
18
+ if (this.matches) {
19
+ ls.push(this.matches);
20
+ rs.push(Array.prototype.slice.call(result, 0));
21
+ }
22
+ if (this.props) {
23
+ ls.push(this.props);
24
+ rs.push({index: result.index, input: result.input});
25
+ }
26
+ }
27
+ return result;
28
+ }
29
+ }
30
+
31
+ const matchString = (regexp, matches, props) => new MatchString(regexp, matches, props);
32
+
33
+ export default matchString;
@@ -0,0 +1,16 @@
1
+ import {Unifier, isVariable} from '../env.js';
2
+
3
+ class MatchTypeOf extends Unifier {
4
+ constructor(types) {
5
+ super();
6
+ this.types = types instanceof Array ? types : [types];
7
+ }
8
+
9
+ unify(val, ls, rs) {
10
+ return !isVariable(val) && this.types.indexOf(typeof val) >= 0;
11
+ }
12
+ }
13
+
14
+ const matchTypeOf = types => new MatchTypeOf(types);
15
+
16
+ export default matchTypeOf;
@@ -0,0 +1,21 @@
1
+ import {Variable} from '../env.js';
2
+
3
+ class Ref extends Variable {
4
+ constructor(variable, value) {
5
+ const v = typeof variable == 'string' ? new Variable(variable) : variable;
6
+ super(v.name);
7
+ this.variable = v;
8
+ this.value = value;
9
+ }
10
+
11
+ unify(val, ls, rs, env) {
12
+ ls.push(this.value, this.variable);
13
+ rs.push(val, val);
14
+ return true;
15
+ }
16
+ }
17
+
18
+ const ref = (variable, value) => new Ref(variable, value);
19
+ ref.Ref = Ref;
20
+
21
+ export default ref;