@dallaylaen/ski-interpreter 1.0.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 +21 -0
- package/README.md +138 -0
- package/bin/ski.js +122 -0
- package/index.js +8 -0
- package/lib/expr.js +1009 -0
- package/lib/parser.js +326 -0
- package/lib/quest.js +311 -0
- package/lib/util.js +74 -0
- package/package.json +46 -0
- package/types/index.d.ts +7 -0
- package/types/lib/expr.d.ts +344 -0
- package/types/lib/parser.d.ts +138 -0
- package/types/lib/quest.d.ts +139 -0
- package/types/lib/util.d.ts +13 -0
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dallaylaen/ski-interpreter",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Simple Kombinator Interpreter - a combinatory logic & lambda calculus parser and interpreter. Supports SKI, BCKW, Church numerals, and setting up assertions ('quests') involving all of the above.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"combinatory logic",
|
|
7
|
+
"lambda calculus",
|
|
8
|
+
"functional programming",
|
|
9
|
+
"education",
|
|
10
|
+
"interpreter"
|
|
11
|
+
],
|
|
12
|
+
"main": "index.js",
|
|
13
|
+
"types": "types/index.d.ts",
|
|
14
|
+
"bin": {
|
|
15
|
+
"ski": "bin/ski.js"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "nyc mocha"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"package.json",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"lib",
|
|
25
|
+
"types"
|
|
26
|
+
],
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/dallaylaen/ski-interpreter.git"
|
|
30
|
+
},
|
|
31
|
+
"author": "Konstantin Uvarin",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/dallaylaen/ski-interpreter/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://dallaylaen.github.io/ski-interpreter/index.html",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"eslint": "^8.57.0",
|
|
39
|
+
"eslint-config-standard": "^17.1.0",
|
|
40
|
+
"eslint-plugin-align-assignments": "^1.1.2",
|
|
41
|
+
"eslint-plugin-import": "^2.29.1",
|
|
42
|
+
"typescript": "^5.8.2",
|
|
43
|
+
"mocha": "^10.2.0",
|
|
44
|
+
"nyc": "^15.1.0"
|
|
45
|
+
}
|
|
46
|
+
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
export type AnyArity = (arg0: Expr) => Expr | AnyArity;
|
|
2
|
+
export class Expr {
|
|
3
|
+
arity: number;
|
|
4
|
+
/**
|
|
5
|
+
* postprocess term after parsing. typically return self but may return other term or die
|
|
6
|
+
* @return {Expr}
|
|
7
|
+
*/
|
|
8
|
+
postParse(): Expr;
|
|
9
|
+
/**
|
|
10
|
+
* @desc apply self to zero or more terms and return the resulting term,
|
|
11
|
+
* without performing any calculations whatsoever
|
|
12
|
+
* @param {Expr} args
|
|
13
|
+
* @return {Expr}
|
|
14
|
+
*/
|
|
15
|
+
apply(...args: Expr): Expr;
|
|
16
|
+
/**
|
|
17
|
+
* expand all terms but don't perform any calculations
|
|
18
|
+
* @return {Expr}
|
|
19
|
+
*/
|
|
20
|
+
expand(): Expr;
|
|
21
|
+
/**
|
|
22
|
+
* @desc return all free variables within the term
|
|
23
|
+
* @return {Set<FreeVar>}
|
|
24
|
+
*/
|
|
25
|
+
freeVars(): Set<FreeVar>;
|
|
26
|
+
hasLambda(): any;
|
|
27
|
+
freeOnly(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* @desc return all terminal values within the term, that is, values not
|
|
30
|
+
* composed of other terms. For example, in S(KI)K, the terminals are S, K, I.
|
|
31
|
+
* @return {Map<Expr, number>}
|
|
32
|
+
*/
|
|
33
|
+
getSymbols(): Map<Expr, number>;
|
|
34
|
+
/**
|
|
35
|
+
* @desc rought estimate of the complexity of the term
|
|
36
|
+
* @return {number}
|
|
37
|
+
*/
|
|
38
|
+
weight(): number;
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* @param {{max: number?, maxArgs: number?, bestGuess?: Expr}} options
|
|
42
|
+
* @return {{
|
|
43
|
+
* found: boolean,
|
|
44
|
+
* proper: boolean,
|
|
45
|
+
* arity: number?,
|
|
46
|
+
* linear: boolean?,
|
|
47
|
+
* canonical?: Expr,
|
|
48
|
+
* steps: number?,
|
|
49
|
+
* skip: Set<number>?
|
|
50
|
+
* }}
|
|
51
|
+
*/
|
|
52
|
+
canonize(options?: {
|
|
53
|
+
max: number | null;
|
|
54
|
+
maxArgs: number | null;
|
|
55
|
+
bestGuess?: Expr;
|
|
56
|
+
}): {
|
|
57
|
+
found: boolean;
|
|
58
|
+
proper: boolean;
|
|
59
|
+
arity: number | null;
|
|
60
|
+
linear: boolean | null;
|
|
61
|
+
canonical?: Expr;
|
|
62
|
+
steps: number | null;
|
|
63
|
+
skip: Set<number> | null;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* @desc Returns a series of lambda terms equivalent to the given expression,
|
|
67
|
+
* up to the provided computation steps limit,
|
|
68
|
+
* in decreasing weight order.
|
|
69
|
+
* @param {{
|
|
70
|
+
* max: number?,
|
|
71
|
+
* maxArgs: number?,
|
|
72
|
+
* varGen: function(void): FreeVar?,
|
|
73
|
+
* steps: number?,
|
|
74
|
+
* html: boolean?,
|
|
75
|
+
* latin: number?,
|
|
76
|
+
* }} options
|
|
77
|
+
* @param {number} [maxWeight] - maximum allowed weight of terms in the sequence
|
|
78
|
+
* @return {IterableIterator<{expr: Expr, steps: number?, comment: string?}>}
|
|
79
|
+
*/
|
|
80
|
+
lambdify(options?: {
|
|
81
|
+
max: number | null;
|
|
82
|
+
maxArgs: number | null;
|
|
83
|
+
varGen: (arg0: void) => FreeVar | null;
|
|
84
|
+
steps: number | null;
|
|
85
|
+
html: boolean | null;
|
|
86
|
+
latin: number | null;
|
|
87
|
+
}): IterableIterator<{
|
|
88
|
+
expr: Expr;
|
|
89
|
+
steps: number | null;
|
|
90
|
+
comment: string | null;
|
|
91
|
+
}>;
|
|
92
|
+
/**
|
|
93
|
+
* @desc same semantics as walk() but rewrite step by step instead of computing
|
|
94
|
+
* @param {{max: number?}} options
|
|
95
|
+
* @return {IterableIterator<{final: boolean, expr: Expr, steps: number}>}
|
|
96
|
+
*/
|
|
97
|
+
rewriteSKI(options?: {
|
|
98
|
+
max: number | null;
|
|
99
|
+
}): IterableIterator<{
|
|
100
|
+
final: boolean;
|
|
101
|
+
expr: Expr;
|
|
102
|
+
steps: number;
|
|
103
|
+
}>;
|
|
104
|
+
/**
|
|
105
|
+
* @desc Rename free variables in the expression using the given sequence
|
|
106
|
+
* This is for eye-candy only, as the interpreter knows darn well hot to distinguish vars,
|
|
107
|
+
* regardless of names.
|
|
108
|
+
* @param {IterableIterator<string>} seq
|
|
109
|
+
* @return {Expr}
|
|
110
|
+
*/
|
|
111
|
+
renameVars(seq: IterableIterator<string>): Expr;
|
|
112
|
+
_rski(options: any): this;
|
|
113
|
+
/**
|
|
114
|
+
* @desc Whether the term will reduce further if given more arguments.
|
|
115
|
+
* In practice, equivalent to "starts with a FreeVar"
|
|
116
|
+
* Used by canonize (duh...)
|
|
117
|
+
* @return {boolean}
|
|
118
|
+
*/
|
|
119
|
+
wantsArgs(): boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Apply self to list of given args.
|
|
122
|
+
* Normally, only native combinators know how to do it.
|
|
123
|
+
* @param {Expr[]} args
|
|
124
|
+
* @return {Expr|null}
|
|
125
|
+
*/
|
|
126
|
+
reduce(args: Expr[]): Expr | null;
|
|
127
|
+
/**
|
|
128
|
+
* Replace all instances of free vars with corresponding values and return the resulting expression.
|
|
129
|
+
* return null if no changes could be made.
|
|
130
|
+
* @param {FreeVar} plug
|
|
131
|
+
* @param {Expr} value
|
|
132
|
+
* @return {Expr|null}
|
|
133
|
+
*/
|
|
134
|
+
subst(plug: FreeVar, value: Expr): Expr | null;
|
|
135
|
+
/**
|
|
136
|
+
* @desc iterate one step of calculation in accordance with known rules.
|
|
137
|
+
* @return {{expr: Expr, steps: number, changed: boolean}}
|
|
138
|
+
*/
|
|
139
|
+
step(): {
|
|
140
|
+
expr: Expr;
|
|
141
|
+
steps: number;
|
|
142
|
+
changed: boolean;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* @desc Run uninterrupted sequence of step() applications
|
|
146
|
+
* until the expression is irreducible, or max number of steps is reached.
|
|
147
|
+
* Default number of steps = 1000.
|
|
148
|
+
* @param {{max: number?, steps: number?, throw: boolean?}|Expr} [opt]
|
|
149
|
+
* @param {Expr} args
|
|
150
|
+
* @return {{expr: Expr, steps: number, final: boolean}}
|
|
151
|
+
*/
|
|
152
|
+
run(opt?: {
|
|
153
|
+
max: number | null;
|
|
154
|
+
steps: number | null;
|
|
155
|
+
throw: boolean | null;
|
|
156
|
+
} | Expr, ...args: Expr): {
|
|
157
|
+
expr: Expr;
|
|
158
|
+
steps: number;
|
|
159
|
+
final: boolean;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Execute step() while possible, yielding a brief description of events after each step.
|
|
163
|
+
* Mnemonics: like run() but slower.
|
|
164
|
+
* @param {{max: number?}} options
|
|
165
|
+
* @return {IterableIterator<{final: boolean, expr: Expr, steps: number}>}
|
|
166
|
+
*/
|
|
167
|
+
walk(options?: {
|
|
168
|
+
max: number | null;
|
|
169
|
+
}): IterableIterator<{
|
|
170
|
+
final: boolean;
|
|
171
|
+
expr: Expr;
|
|
172
|
+
steps: number;
|
|
173
|
+
}>;
|
|
174
|
+
/**
|
|
175
|
+
*
|
|
176
|
+
* @param {Expr} other
|
|
177
|
+
* @return {boolean}
|
|
178
|
+
*/
|
|
179
|
+
equals(other: Expr): boolean;
|
|
180
|
+
contains(other: any): boolean;
|
|
181
|
+
expect(other: any): void;
|
|
182
|
+
/**
|
|
183
|
+
* @param {{terse: boolean?, html: boolean?}} [options]
|
|
184
|
+
* @return {string} string representation of the expression
|
|
185
|
+
*/
|
|
186
|
+
toString(options?: {
|
|
187
|
+
terse: boolean | null;
|
|
188
|
+
html: boolean | null;
|
|
189
|
+
}): string;
|
|
190
|
+
/**
|
|
191
|
+
*
|
|
192
|
+
* @return {boolean}
|
|
193
|
+
*/
|
|
194
|
+
needsParens(): boolean;
|
|
195
|
+
/**
|
|
196
|
+
*
|
|
197
|
+
* @return {string}
|
|
198
|
+
*/
|
|
199
|
+
toJSON(): string;
|
|
200
|
+
}
|
|
201
|
+
export namespace Expr {
|
|
202
|
+
let lambdaPlaceholder: Native;
|
|
203
|
+
}
|
|
204
|
+
export class App extends Expr {
|
|
205
|
+
/**
|
|
206
|
+
* @desc Application of fun() to args.
|
|
207
|
+
* Never ever use new App(fun, ...args) directly, use fun.apply(...args) instead.
|
|
208
|
+
* @param {Expr} fun
|
|
209
|
+
* @param {Expr} args
|
|
210
|
+
*/
|
|
211
|
+
constructor(fun: Expr, ...args: Expr);
|
|
212
|
+
fun: Expr;
|
|
213
|
+
args: Expr;
|
|
214
|
+
final: boolean;
|
|
215
|
+
weight(): Expr;
|
|
216
|
+
apply(...args: any[]): any;
|
|
217
|
+
canonize(options?: {}): {
|
|
218
|
+
found: boolean;
|
|
219
|
+
proper: boolean;
|
|
220
|
+
arity: number | null;
|
|
221
|
+
linear: boolean | null;
|
|
222
|
+
canonical?: Expr;
|
|
223
|
+
steps: number | null;
|
|
224
|
+
skip: Set<number> | null;
|
|
225
|
+
};
|
|
226
|
+
renameVars(seq: any): Expr;
|
|
227
|
+
subst(plug: any, value: any): Expr;
|
|
228
|
+
/**
|
|
229
|
+
* @return {{expr: Expr, steps: number}}
|
|
230
|
+
*/
|
|
231
|
+
step(): {
|
|
232
|
+
expr: Expr;
|
|
233
|
+
steps: number;
|
|
234
|
+
};
|
|
235
|
+
split(): any[];
|
|
236
|
+
equals(other: any): boolean;
|
|
237
|
+
toString(opt?: {}): string;
|
|
238
|
+
}
|
|
239
|
+
export class FreeVar extends Named {
|
|
240
|
+
constructor(name: any);
|
|
241
|
+
id: number;
|
|
242
|
+
subst(plug: any, value: any): any;
|
|
243
|
+
toString(opt?: {}): string;
|
|
244
|
+
}
|
|
245
|
+
export class Lambda extends Expr {
|
|
246
|
+
/**
|
|
247
|
+
* @param {FreeVar|FreeVar[]} arg
|
|
248
|
+
* @param {Expr} impl
|
|
249
|
+
*/
|
|
250
|
+
constructor(arg: FreeVar | FreeVar[], impl: Expr);
|
|
251
|
+
arg: FreeVar;
|
|
252
|
+
impl: Expr;
|
|
253
|
+
reduce(input: any): Expr;
|
|
254
|
+
subst(plug: any, value: any): Lambda;
|
|
255
|
+
expand(): Lambda;
|
|
256
|
+
renameVars(seq: any): Lambda;
|
|
257
|
+
_rski(options: any): any;
|
|
258
|
+
equals(other: any): boolean;
|
|
259
|
+
toString(opt?: {}): string;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* @typedef {function(Expr): Expr | AnyArity} AnyArity
|
|
263
|
+
*/
|
|
264
|
+
export class Native extends Named {
|
|
265
|
+
/**
|
|
266
|
+
* @desc A term named 'name' that converts next 'arity' arguments into
|
|
267
|
+
* an expression returned by 'impl' function
|
|
268
|
+
* If an apply: Expr=>Expr|null function is given, it will be attempted upon application
|
|
269
|
+
* before building an App object. This allows to plug in argument coercions,
|
|
270
|
+
* e.g. instantly perform a numeric operation natively if the next term is a number.
|
|
271
|
+
* @param {String} name
|
|
272
|
+
* @param {AnyArity} impl
|
|
273
|
+
* @param {{note: string?, arity: number?, canonize: boolean?, apply: function(Expr):(Expr|null) }} [opt]
|
|
274
|
+
*/
|
|
275
|
+
constructor(name: string, impl: AnyArity, opt?: {
|
|
276
|
+
note: string | null;
|
|
277
|
+
arity: number | null;
|
|
278
|
+
canonize: boolean | null;
|
|
279
|
+
apply: (arg0: Expr) => (Expr | null);
|
|
280
|
+
});
|
|
281
|
+
impl: AnyArity;
|
|
282
|
+
onApply: (arg0: Expr) => (Expr | null);
|
|
283
|
+
arity: any;
|
|
284
|
+
note: any;
|
|
285
|
+
apply(...args: any[]): Expr;
|
|
286
|
+
_rski(options: any): Expr | this;
|
|
287
|
+
reduce(args: any): any;
|
|
288
|
+
}
|
|
289
|
+
export class Alias extends Named {
|
|
290
|
+
/**
|
|
291
|
+
* @desc An existing expression under a different name.
|
|
292
|
+
* @param {String} name
|
|
293
|
+
* @param {Expr} impl
|
|
294
|
+
* @param {{canonize: boolean?, max: number?, maxArgs: number?, note: string?, terminal: boolean?}} [options]
|
|
295
|
+
*/
|
|
296
|
+
constructor(name: string, impl: Expr, options?: {
|
|
297
|
+
canonize: boolean | null;
|
|
298
|
+
max: number | null;
|
|
299
|
+
maxArgs: number | null;
|
|
300
|
+
note: string | null;
|
|
301
|
+
terminal: boolean | null;
|
|
302
|
+
});
|
|
303
|
+
impl: Expr;
|
|
304
|
+
note: string;
|
|
305
|
+
arity: any;
|
|
306
|
+
proper: any;
|
|
307
|
+
terminal: any;
|
|
308
|
+
canonical: any;
|
|
309
|
+
subst(plug: any, value: any): Expr;
|
|
310
|
+
/**
|
|
311
|
+
*
|
|
312
|
+
* @return {{expr: Expr, steps: number}}
|
|
313
|
+
*/
|
|
314
|
+
step(): {
|
|
315
|
+
expr: Expr;
|
|
316
|
+
steps: number;
|
|
317
|
+
};
|
|
318
|
+
reduce(args: any): Expr;
|
|
319
|
+
equals(other: any): any;
|
|
320
|
+
_rski(options: any): Expr;
|
|
321
|
+
toString(opt: any): string;
|
|
322
|
+
}
|
|
323
|
+
export class Church extends Native {
|
|
324
|
+
constructor(n: any);
|
|
325
|
+
n: any;
|
|
326
|
+
arity: number;
|
|
327
|
+
equals(other: any): boolean;
|
|
328
|
+
}
|
|
329
|
+
export namespace globalOptions {
|
|
330
|
+
let terse: boolean;
|
|
331
|
+
let max: number;
|
|
332
|
+
let maxArgs: number;
|
|
333
|
+
}
|
|
334
|
+
export const native: {};
|
|
335
|
+
declare class Named extends Expr {
|
|
336
|
+
/**
|
|
337
|
+
* @desc a constant named 'name'
|
|
338
|
+
* @param {String} name
|
|
339
|
+
*/
|
|
340
|
+
constructor(name: string);
|
|
341
|
+
name: string;
|
|
342
|
+
toString(): string;
|
|
343
|
+
}
|
|
344
|
+
export {};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
export class SKI {
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* @param {{
|
|
5
|
+
* allow: string?,
|
|
6
|
+
* numbers: boolean?,
|
|
7
|
+
* lambdas: boolean?,
|
|
8
|
+
* terms: { [key: string]: Expr|string}?,
|
|
9
|
+
* annotate: boolean?,
|
|
10
|
+
* }} [options]
|
|
11
|
+
*/
|
|
12
|
+
constructor(options?: {
|
|
13
|
+
allow: string | null;
|
|
14
|
+
numbers: boolean | null;
|
|
15
|
+
lambdas: boolean | null;
|
|
16
|
+
terms: {
|
|
17
|
+
[key: string]: Expr | string;
|
|
18
|
+
} | null;
|
|
19
|
+
annotate: boolean | null;
|
|
20
|
+
});
|
|
21
|
+
annotate: boolean;
|
|
22
|
+
known: {};
|
|
23
|
+
hasNumbers: boolean;
|
|
24
|
+
hasLambdas: boolean;
|
|
25
|
+
allow: any;
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
* @param {Alias|String} term
|
|
29
|
+
* @param {Expr|String|[number, function(...Expr): Expr, {note: string?, fast: boolean?}]} [impl]
|
|
30
|
+
* @param {String} [note]
|
|
31
|
+
* @return {SKI} chainable
|
|
32
|
+
*/
|
|
33
|
+
add(term: Alias | string, impl?: Expr | string | [number, (...args: Expr[]) => Expr, {
|
|
34
|
+
note: string | null;
|
|
35
|
+
fast: boolean | null;
|
|
36
|
+
}], note?: string): SKI;
|
|
37
|
+
maybeAdd(name: any, impl: any): this;
|
|
38
|
+
/**
|
|
39
|
+
* Restrict the interpreter to given terms. Terms prepended with '+' will be added
|
|
40
|
+
* and terms preceeded with '-' will be removed.
|
|
41
|
+
* @example ski.restrict('SK') // use the basis
|
|
42
|
+
* @example ski.restrict('+I') // allow I now
|
|
43
|
+
* @example ski.restrict('-SKI +BCKW' ); // switch basis
|
|
44
|
+
* @example ski.restrict('-foo -bar'); // forbid some user functions
|
|
45
|
+
* @param {string} spec
|
|
46
|
+
* @return {SKI} chainable
|
|
47
|
+
*/
|
|
48
|
+
restrict(spec: string): SKI;
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
* @param {string} spec
|
|
52
|
+
* @return {string}
|
|
53
|
+
*/
|
|
54
|
+
showRestrict(spec?: string): string;
|
|
55
|
+
/**
|
|
56
|
+
*
|
|
57
|
+
* @param {String} name
|
|
58
|
+
* @return {SKI}
|
|
59
|
+
*/
|
|
60
|
+
remove(name: string): SKI;
|
|
61
|
+
/**
|
|
62
|
+
*
|
|
63
|
+
* @return {{[key:string]: Native|Alias}}
|
|
64
|
+
*/
|
|
65
|
+
getTerms(): {
|
|
66
|
+
[key: string]: Native | Alias;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
*
|
|
70
|
+
* @param {string} source
|
|
71
|
+
* @param {{[keys: string]: Expr}} vars
|
|
72
|
+
* @param {{numbers: boolean?, lambdas: boolean?, allow: string?}} options
|
|
73
|
+
* @return {Expr}
|
|
74
|
+
*/
|
|
75
|
+
parse(source: string, vars?: {
|
|
76
|
+
[keys: string]: Expr;
|
|
77
|
+
}, options?: {
|
|
78
|
+
numbers: boolean | null;
|
|
79
|
+
lambdas: boolean | null;
|
|
80
|
+
allow: string | null;
|
|
81
|
+
}): Expr;
|
|
82
|
+
/**
|
|
83
|
+
*
|
|
84
|
+
* @param {String} source S(KI)I
|
|
85
|
+
* @param {{[keys: string]: Expr}} vars
|
|
86
|
+
* @param {{numbers: boolean?, lambdas: boolean?, allow: string?}} options
|
|
87
|
+
* @return {Expr} parsed expression
|
|
88
|
+
*/
|
|
89
|
+
parseLine(source: string, vars?: {
|
|
90
|
+
[keys: string]: Expr;
|
|
91
|
+
}, options?: {
|
|
92
|
+
numbers: boolean | null;
|
|
93
|
+
lambdas: boolean | null;
|
|
94
|
+
allow: string | null;
|
|
95
|
+
}): Expr;
|
|
96
|
+
toJSON(): {
|
|
97
|
+
allow: string;
|
|
98
|
+
numbers: boolean;
|
|
99
|
+
lambdas: boolean;
|
|
100
|
+
terms: {
|
|
101
|
+
[key: string]: Native | Alias;
|
|
102
|
+
};
|
|
103
|
+
annotate: boolean;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export namespace SKI {
|
|
107
|
+
/**
|
|
108
|
+
* Create free var(s) for subsequent use
|
|
109
|
+
* @param {String} names
|
|
110
|
+
* @return {FreeVar[]}
|
|
111
|
+
*/
|
|
112
|
+
export function free(...names: string): FreeVar[];
|
|
113
|
+
/**
|
|
114
|
+
* Convert a number to Church encoding
|
|
115
|
+
* @param {number} n
|
|
116
|
+
* @return {Church}
|
|
117
|
+
*/
|
|
118
|
+
export function church(n: number): Church;
|
|
119
|
+
export namespace classes {
|
|
120
|
+
export { Expr };
|
|
121
|
+
export { Native };
|
|
122
|
+
export { Alias };
|
|
123
|
+
export { FreeVar };
|
|
124
|
+
export { Lambda };
|
|
125
|
+
export { Church };
|
|
126
|
+
}
|
|
127
|
+
export { native };
|
|
128
|
+
export { globalOptions as options };
|
|
129
|
+
export let lambdaPlaceholder: Native;
|
|
130
|
+
}
|
|
131
|
+
import { Alias } from "./expr";
|
|
132
|
+
import { Expr } from "./expr";
|
|
133
|
+
import { Native } from "./expr";
|
|
134
|
+
import { FreeVar } from "./expr";
|
|
135
|
+
import { Church } from "./expr";
|
|
136
|
+
import { Lambda } from "./expr";
|
|
137
|
+
import { native } from "./expr";
|
|
138
|
+
import { globalOptions } from "./expr";
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
export type CaseResult = {
|
|
2
|
+
pass: boolean;
|
|
3
|
+
reason: string | null;
|
|
4
|
+
steps: number;
|
|
5
|
+
start: typeof import("./expr").Expr;
|
|
6
|
+
found: typeof import("./expr").Expr;
|
|
7
|
+
expected: typeof import("./expr").Expr;
|
|
8
|
+
note: string | null;
|
|
9
|
+
args: typeof import("./expr").Expr[];
|
|
10
|
+
case: Case;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {{
|
|
14
|
+
* pass: boolean,
|
|
15
|
+
* reason: string?,
|
|
16
|
+
* steps: number,
|
|
17
|
+
* start: Expr,
|
|
18
|
+
* found: Expr,
|
|
19
|
+
* expected: Expr,
|
|
20
|
+
* note: string?,
|
|
21
|
+
* args: Expr[],
|
|
22
|
+
* case: Case
|
|
23
|
+
* }} CaseResult
|
|
24
|
+
*/
|
|
25
|
+
export class Quest {
|
|
26
|
+
/**
|
|
27
|
+
* @description A combinator problem with a set of test cases for the proposed solution.
|
|
28
|
+
* @param {{
|
|
29
|
+
* title: string?,
|
|
30
|
+
* descr: string?,
|
|
31
|
+
* subst: string?,
|
|
32
|
+
* allow: string?,
|
|
33
|
+
* numbers: boolean?,
|
|
34
|
+
* vars: string[]?,
|
|
35
|
+
* engine: SKI?,
|
|
36
|
+
* engineFull: SKI?,
|
|
37
|
+
* cases: [{max: number?, note: string?, feedInput: boolean, lambdas: boolean?}|string[], ...string[][]]?
|
|
38
|
+
* }} options
|
|
39
|
+
*/
|
|
40
|
+
constructor(options?: {
|
|
41
|
+
title: string | null;
|
|
42
|
+
descr: string | null;
|
|
43
|
+
subst: string | null;
|
|
44
|
+
allow: string | null;
|
|
45
|
+
numbers: boolean | null;
|
|
46
|
+
vars: string[] | null;
|
|
47
|
+
engine: SKI | null;
|
|
48
|
+
engineFull: SKI | null;
|
|
49
|
+
cases: [{
|
|
50
|
+
max: number | null;
|
|
51
|
+
note: string | null;
|
|
52
|
+
feedInput: boolean;
|
|
53
|
+
lambdas: boolean | null;
|
|
54
|
+
} | string[], ...string[][]] | null;
|
|
55
|
+
});
|
|
56
|
+
engine: SKI;
|
|
57
|
+
engineFull: SKI;
|
|
58
|
+
restrict: {
|
|
59
|
+
allow: string;
|
|
60
|
+
numbers: boolean;
|
|
61
|
+
lambdas: any;
|
|
62
|
+
};
|
|
63
|
+
vars: {};
|
|
64
|
+
subst: string[] | (string & any[]);
|
|
65
|
+
input: any[];
|
|
66
|
+
varsFull: {};
|
|
67
|
+
cases: any[];
|
|
68
|
+
title: string;
|
|
69
|
+
descr: string;
|
|
70
|
+
meta: {
|
|
71
|
+
title: string | null;
|
|
72
|
+
descr: string | null;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Display allowed terms based on what engine thinks of this.vars + this.restrict.allow
|
|
76
|
+
* @return {string}
|
|
77
|
+
*/
|
|
78
|
+
allowed(): string;
|
|
79
|
+
addInput(term: any): void;
|
|
80
|
+
/**
|
|
81
|
+
*
|
|
82
|
+
* @param {{} | string} opt
|
|
83
|
+
* @param {string} terms
|
|
84
|
+
* @return {Quest}
|
|
85
|
+
*/
|
|
86
|
+
add(opt: {} | string, ...terms: string): Quest;
|
|
87
|
+
/**
|
|
88
|
+
* @description Statefully parse a list of strings into expressions or fancy aliases thereof.
|
|
89
|
+
* @param {string[]} input
|
|
90
|
+
* @return {{terms: Expr[], weight: number}}
|
|
91
|
+
*/
|
|
92
|
+
prepare(...input: string[]): {
|
|
93
|
+
terms: typeof import("./expr").Expr[];
|
|
94
|
+
weight: number;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
*
|
|
98
|
+
* @param {string} input
|
|
99
|
+
* @return {{
|
|
100
|
+
* expr: Expr?,
|
|
101
|
+
* pass: boolean,
|
|
102
|
+
* details: CaseResult[],
|
|
103
|
+
* exception: Error?,
|
|
104
|
+
* steps: number,
|
|
105
|
+
* input: Expr[]|string[],
|
|
106
|
+
* weight: number?
|
|
107
|
+
* }}
|
|
108
|
+
*/
|
|
109
|
+
check(...input: string): {
|
|
110
|
+
expr: typeof import("./expr").Expr | null;
|
|
111
|
+
pass: boolean;
|
|
112
|
+
details: CaseResult[];
|
|
113
|
+
exception: Error | null;
|
|
114
|
+
steps: number;
|
|
115
|
+
input: typeof import("./expr").Expr[] | string[];
|
|
116
|
+
weight: number | null;
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
*
|
|
120
|
+
* @return {TestCase[]}
|
|
121
|
+
*/
|
|
122
|
+
show(): TestCase[];
|
|
123
|
+
}
|
|
124
|
+
declare class Case {
|
|
125
|
+
constructor(input: any, options: any);
|
|
126
|
+
max: any;
|
|
127
|
+
note: any;
|
|
128
|
+
vars: any;
|
|
129
|
+
input: any;
|
|
130
|
+
engine: any;
|
|
131
|
+
parse(src: any): import("./expr").Lambda;
|
|
132
|
+
/**
|
|
133
|
+
* @param {Expr} expr
|
|
134
|
+
* @return {CaseResult}
|
|
135
|
+
*/
|
|
136
|
+
check(...expr: typeof import("./expr").Expr): CaseResult;
|
|
137
|
+
}
|
|
138
|
+
import { SKI } from "./parser";
|
|
139
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class Tokenizer {
|
|
2
|
+
constructor(...terms: any[]);
|
|
3
|
+
rex: RegExp;
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {string} str
|
|
7
|
+
* @return {string[]}
|
|
8
|
+
*/
|
|
9
|
+
split(str: string): string[];
|
|
10
|
+
}
|
|
11
|
+
export function restrict(set: any, spec: any): any;
|
|
12
|
+
export function missingIndices(arr: any, set: any): any;
|
|
13
|
+
export function isSubset(a: any, b: any): boolean;
|