yukigo 0.1.0 → 0.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/.mocharc.json +3 -3
- package/CHANGELOG.md +26 -0
- package/README.md +193 -199
- package/dist/analyzer/GraphBuilder.d.ts +29 -0
- package/dist/analyzer/GraphBuilder.js +99 -0
- package/dist/analyzer/index.d.ts +11 -23
- package/dist/analyzer/index.js +100 -58
- package/dist/analyzer/inspections/functional/functional.d.ts +44 -0
- package/dist/analyzer/inspections/functional/functional.js +149 -0
- package/dist/analyzer/inspections/functional/smells.d.ts +16 -0
- package/dist/analyzer/inspections/functional/smells.js +98 -0
- package/dist/analyzer/inspections/{generic.d.ts → generic/generic.d.ts} +70 -43
- package/dist/analyzer/inspections/generic/generic.js +604 -0
- package/dist/analyzer/inspections/generic/smells.d.ts +61 -0
- package/dist/analyzer/inspections/generic/smells.js +349 -0
- package/dist/analyzer/inspections/imperative/imperative.d.ts +35 -0
- package/dist/analyzer/inspections/imperative/imperative.js +109 -0
- package/dist/analyzer/inspections/imperative/smells.d.ts +16 -0
- package/dist/analyzer/inspections/imperative/smells.js +58 -0
- package/dist/analyzer/inspections/logic/logic.d.ts +32 -0
- package/dist/analyzer/inspections/logic/logic.js +96 -0
- package/dist/analyzer/inspections/logic/smells.d.ts +15 -0
- package/dist/analyzer/inspections/logic/smells.js +60 -0
- package/dist/analyzer/inspections/object/object.d.ts +88 -0
- package/dist/analyzer/inspections/object/object.js +319 -0
- package/dist/analyzer/inspections/object/smells.d.ts +30 -0
- package/dist/analyzer/inspections/object/smells.js +135 -0
- package/dist/analyzer/utils.d.ts +26 -4
- package/dist/analyzer/utils.js +71 -13
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interpreter/components/EnvBuilder.d.ts +9 -5
- package/dist/interpreter/components/EnvBuilder.js +100 -30
- package/dist/interpreter/components/Operations.d.ts +4 -4
- package/dist/interpreter/components/Operations.js +17 -2
- package/dist/interpreter/components/PatternMatcher.d.ts +47 -17
- package/dist/interpreter/components/PatternMatcher.js +264 -119
- package/dist/interpreter/components/RuntimeContext.d.ts +35 -0
- package/dist/interpreter/components/RuntimeContext.js +93 -0
- package/dist/interpreter/components/TestRunner.d.ts +18 -0
- package/dist/interpreter/components/TestRunner.js +103 -0
- package/dist/interpreter/components/Visitor.d.ts +63 -57
- package/dist/interpreter/components/Visitor.js +508 -173
- package/dist/interpreter/components/logic/LogicEngine.d.ts +29 -0
- package/dist/interpreter/components/logic/LogicEngine.js +259 -0
- package/dist/interpreter/components/logic/LogicResolver.d.ts +53 -0
- package/dist/interpreter/components/logic/LogicResolver.js +471 -0
- package/dist/interpreter/components/logic/LogicTranslator.d.ts +14 -0
- package/dist/interpreter/components/logic/LogicTranslator.js +99 -0
- package/dist/interpreter/components/runtimes/FunctionRuntime.d.ts +12 -0
- package/dist/interpreter/components/runtimes/FunctionRuntime.js +147 -0
- package/dist/interpreter/components/runtimes/LazyRuntime.d.ts +19 -0
- package/dist/interpreter/components/runtimes/LazyRuntime.js +269 -0
- package/dist/interpreter/components/runtimes/ObjectRuntime.d.ts +35 -0
- package/dist/interpreter/components/runtimes/ObjectRuntime.js +126 -0
- package/dist/interpreter/entities.d.ts +105 -0
- package/dist/interpreter/entities.js +96 -0
- package/dist/interpreter/errors.d.ts +1 -1
- package/dist/interpreter/index.d.ts +4 -12
- package/dist/interpreter/index.js +10 -13
- package/dist/interpreter/trampoline.d.ts +17 -0
- package/dist/interpreter/trampoline.js +38 -0
- package/dist/interpreter/utils.d.ts +4 -7
- package/dist/interpreter/utils.js +25 -17
- package/dist/tester/index.d.ts +25 -0
- package/dist/tester/index.js +108 -0
- package/dist/utils/helpers.d.ts +0 -4
- package/dist/utils/helpers.js +20 -24
- package/package.json +2 -2
- package/src/analyzer/GraphBuilder.ts +142 -0
- package/src/analyzer/index.ts +185 -132
- package/src/analyzer/inspections/functional/functional.ts +121 -0
- package/src/analyzer/inspections/functional/smells.ts +102 -0
- package/src/analyzer/inspections/{generic.ts → generic/generic.ts} +581 -499
- package/src/analyzer/inspections/generic/smells.ts +365 -0
- package/src/analyzer/inspections/imperative/imperative.ts +101 -0
- package/src/analyzer/inspections/imperative/smells.ts +54 -0
- package/src/analyzer/inspections/logic/logic.ts +90 -0
- package/src/analyzer/inspections/logic/smells.ts +54 -0
- package/src/analyzer/inspections/{object.ts → object/object.ts} +264 -282
- package/src/analyzer/inspections/object/smells.ts +144 -0
- package/src/analyzer/utils.ts +109 -26
- package/src/index.ts +3 -2
- package/src/interpreter/components/EnvBuilder.ts +202 -97
- package/src/interpreter/components/Operations.ts +99 -81
- package/src/interpreter/components/PatternMatcher.ts +475 -254
- package/src/interpreter/components/RuntimeContext.ts +119 -0
- package/src/interpreter/components/TestRunner.ts +151 -0
- package/src/interpreter/components/Visitor.ts +1065 -493
- package/src/interpreter/components/logic/LogicEngine.ts +519 -0
- package/src/interpreter/components/logic/LogicResolver.ts +858 -0
- package/src/interpreter/components/logic/LogicTranslator.ts +149 -0
- package/src/interpreter/components/runtimes/FunctionRuntime.ts +227 -0
- package/src/interpreter/components/runtimes/LazyRuntime.ts +334 -0
- package/src/interpreter/components/runtimes/ObjectRuntime.ts +224 -0
- package/src/interpreter/errors.ts +47 -47
- package/src/interpreter/index.ts +52 -59
- package/src/interpreter/trampoline.ts +71 -0
- package/src/interpreter/utils.ts +84 -79
- package/src/tester/index.ts +128 -0
- package/src/utils/helpers.ts +67 -73
- package/tests/analyzer/functional.spec.ts +207 -221
- package/tests/analyzer/generic.spec.ts +178 -100
- package/tests/analyzer/helpers.spec.ts +83 -83
- package/tests/analyzer/logic.spec.ts +237 -292
- package/tests/analyzer/oop.spec.ts +323 -338
- package/tests/analyzer/transitive.spec.ts +166 -0
- package/tests/interpreter/EnvBuilder.spec.ts +183 -178
- package/tests/interpreter/FunctionRuntime.spec.ts +223 -234
- package/tests/interpreter/LazyRuntime.spec.ts +225 -190
- package/tests/interpreter/LogicEngine.spec.ts +327 -194
- package/tests/interpreter/LogicSubstitution.spec.ts +80 -0
- package/tests/interpreter/ObjectRuntime.spec.ts +606 -0
- package/tests/interpreter/Operations.spec.ts +220 -220
- package/tests/interpreter/PatternSystem.spec.ts +213 -189
- package/tests/interpreter/Tests.spec.ts +122 -0
- package/tests/interpreter/interpreter.spec.ts +991 -937
- package/tests/tester/Tester.spec.ts +153 -0
- package/tsconfig.build.json +15 -7
- package/tsconfig.json +25 -17
- package/dist/analyzer/inspections/functional.d.ts +0 -46
- package/dist/analyzer/inspections/functional.js +0 -123
- package/dist/analyzer/inspections/generic.js +0 -427
- package/dist/analyzer/inspections/imperative.d.ts +0 -37
- package/dist/analyzer/inspections/imperative.js +0 -105
- package/dist/analyzer/inspections/logic.d.ts +0 -49
- package/dist/analyzer/inspections/logic.js +0 -140
- package/dist/analyzer/inspections/object.d.ts +0 -83
- package/dist/analyzer/inspections/object.js +0 -235
- package/dist/interpreter/components/FunctionRuntime.d.ts +0 -8
- package/dist/interpreter/components/FunctionRuntime.js +0 -52
- package/dist/interpreter/components/LazyRuntime.d.ts +0 -7
- package/dist/interpreter/components/LazyRuntime.js +0 -75
- package/dist/interpreter/components/LogicEngine.d.ts +0 -21
- package/dist/interpreter/components/LogicEngine.js +0 -152
- package/dist/interpreter/components/LogicResolver.d.ts +0 -11
- package/dist/interpreter/components/LogicResolver.js +0 -87
- package/src/analyzer/inspections/functional.ts +0 -159
- package/src/analyzer/inspections/imperative.ts +0 -129
- package/src/analyzer/inspections/logic.ts +0 -166
- package/src/interpreter/components/FunctionRuntime.ts +0 -79
- package/src/interpreter/components/LazyRuntime.ts +0 -97
- package/src/interpreter/components/LogicEngine.ts +0 -227
- package/src/interpreter/components/LogicResolver.ts +0 -130
|
@@ -1,6 +1,64 @@
|
|
|
1
|
-
import { ConstructorPattern, isLazyList, ListPrimitive, } from "
|
|
1
|
+
import { ConstructorPattern, isLazyList, ListPrimitive, SimpleType, ListType, } from "yukigo-ast";
|
|
2
2
|
import { InterpreterVisitor } from "./Visitor.js";
|
|
3
|
-
import {
|
|
3
|
+
import { getYukigoType } from "../utils.js";
|
|
4
|
+
class SharedSequence {
|
|
5
|
+
cache = [];
|
|
6
|
+
source;
|
|
7
|
+
isDone = false;
|
|
8
|
+
constructor(generatorFactory) {
|
|
9
|
+
this.source = generatorFactory();
|
|
10
|
+
}
|
|
11
|
+
get(index) {
|
|
12
|
+
if (index < this.cache.length)
|
|
13
|
+
return { value: this.cache[index], done: false };
|
|
14
|
+
if (this.isDone)
|
|
15
|
+
return { value: null, done: true };
|
|
16
|
+
while (this.cache.length <= index) {
|
|
17
|
+
const next = this.source.next();
|
|
18
|
+
if (next.done) {
|
|
19
|
+
this.isDone = true;
|
|
20
|
+
return { value: null, done: true };
|
|
21
|
+
}
|
|
22
|
+
this.cache.push(next.value);
|
|
23
|
+
}
|
|
24
|
+
return { value: this.cache[index], done: false };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function isMemoizedList(list) {
|
|
28
|
+
return (list &&
|
|
29
|
+
typeof list === "object" &&
|
|
30
|
+
"type" in list &&
|
|
31
|
+
"_offset" in list &&
|
|
32
|
+
"_sequence" in list);
|
|
33
|
+
}
|
|
34
|
+
export function createMemoizedStream(genFactory, sequence, offset = 0) {
|
|
35
|
+
const seq = sequence ?? new SharedSequence(genFactory);
|
|
36
|
+
return {
|
|
37
|
+
type: "LazyList",
|
|
38
|
+
_sequence: seq,
|
|
39
|
+
_offset: offset,
|
|
40
|
+
generator: function* () {
|
|
41
|
+
let currentIdx = offset;
|
|
42
|
+
while (true) {
|
|
43
|
+
const res = seq.get(currentIdx);
|
|
44
|
+
if (res.done)
|
|
45
|
+
return;
|
|
46
|
+
yield res.value;
|
|
47
|
+
currentIdx++;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
toJSON() {
|
|
51
|
+
const iterator = this.generator();
|
|
52
|
+
const buffer = [];
|
|
53
|
+
let next = iterator.next();
|
|
54
|
+
while (!next.done) {
|
|
55
|
+
buffer.push(next.value);
|
|
56
|
+
next = iterator.next();
|
|
57
|
+
}
|
|
58
|
+
return buffer;
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
4
62
|
export class PatternResolver {
|
|
5
63
|
visitVariablePattern(node) {
|
|
6
64
|
return node.name.value;
|
|
@@ -11,7 +69,7 @@ export class PatternResolver {
|
|
|
11
69
|
visitLiteralPattern(node) {
|
|
12
70
|
const { name } = node;
|
|
13
71
|
if (name instanceof ListPrimitive)
|
|
14
|
-
return String(name.
|
|
72
|
+
return String(name.value.map((elem) => elem.accept(this)));
|
|
15
73
|
return String(name.value);
|
|
16
74
|
}
|
|
17
75
|
visitTuplePattern(node) {
|
|
@@ -24,28 +82,34 @@ export class PatternResolver {
|
|
|
24
82
|
: String(elements.map((elem) => elem.accept(this)));
|
|
25
83
|
}
|
|
26
84
|
visitConsPattern(node) {
|
|
27
|
-
const head = node.
|
|
28
|
-
const tail = node.
|
|
85
|
+
const head = node.left.accept(this);
|
|
86
|
+
const tail = node.right.accept(this);
|
|
29
87
|
return `(${head}:${tail})`;
|
|
30
88
|
}
|
|
31
89
|
visitConstructorPattern(node) {
|
|
32
|
-
const constr = node.
|
|
33
|
-
const args = node.
|
|
90
|
+
const constr = node.identifier.value;
|
|
91
|
+
const args = node.args.map((pat) => pat.accept(this)).join(" ");
|
|
34
92
|
return `${constr} ${args}`;
|
|
35
93
|
}
|
|
36
94
|
visitFunctorPattern(node) {
|
|
37
95
|
// Same as ConstructorPattern (alias)
|
|
38
|
-
return this.visitConstructorPattern(new ConstructorPattern(node.identifier
|
|
96
|
+
return this.visitConstructorPattern(new ConstructorPattern(node.identifier, node.args));
|
|
39
97
|
}
|
|
40
98
|
visitApplicationPattern(node) {
|
|
41
99
|
// Same as FunctorPattern
|
|
42
|
-
return this.visitConstructorPattern(new ConstructorPattern(node.
|
|
100
|
+
return this.visitConstructorPattern(new ConstructorPattern(node.identifier, node.args));
|
|
43
101
|
}
|
|
44
102
|
visitAsPattern(node) {
|
|
45
|
-
const
|
|
46
|
-
const
|
|
103
|
+
const alias = node.left.accept(this);
|
|
104
|
+
const pattern = node.right.accept(this);
|
|
47
105
|
return `${alias}@${pattern}`;
|
|
48
106
|
}
|
|
107
|
+
visitTypePattern(node) {
|
|
108
|
+
const typeStr = node.targetType.toString();
|
|
109
|
+
return node.innerPattern
|
|
110
|
+
? `(${typeStr} ${node.innerPattern.accept(this)})`
|
|
111
|
+
: typeStr;
|
|
112
|
+
}
|
|
49
113
|
visit(node) {
|
|
50
114
|
return node.accept(this);
|
|
51
115
|
}
|
|
@@ -58,149 +122,230 @@ export class PatternResolver {
|
|
|
58
122
|
export class PatternMatcher {
|
|
59
123
|
value;
|
|
60
124
|
bindings;
|
|
61
|
-
|
|
125
|
+
ctx;
|
|
126
|
+
constructor(value, bindings, ctx) {
|
|
62
127
|
this.value = value;
|
|
63
128
|
this.bindings = bindings;
|
|
129
|
+
this.ctx = ctx;
|
|
64
130
|
}
|
|
65
131
|
visitVariablePattern(node) {
|
|
66
|
-
|
|
67
|
-
|
|
132
|
+
return (k) => {
|
|
133
|
+
this.bindings.push([node.name.value, this.value]);
|
|
134
|
+
return k(true);
|
|
135
|
+
};
|
|
68
136
|
}
|
|
69
137
|
visitWildcardPattern(node) {
|
|
70
|
-
return true;
|
|
138
|
+
return (k) => k(true);
|
|
71
139
|
}
|
|
72
140
|
visitLiteralPattern(node) {
|
|
73
|
-
|
|
74
|
-
|
|
141
|
+
return (k) => {
|
|
142
|
+
const literalValue = InterpreterVisitor.evaluateLiteral(node.name);
|
|
143
|
+
return this.ctx.lazyRuntime.deepEqual(this.value, literalValue, k);
|
|
144
|
+
};
|
|
75
145
|
}
|
|
76
146
|
visitTuplePattern(node) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
147
|
+
return (k) => {
|
|
148
|
+
const processValue = (val) => {
|
|
149
|
+
if (!Array.isArray(val))
|
|
150
|
+
return k(false);
|
|
151
|
+
if (val.length !== node.elements.length)
|
|
152
|
+
return k(false);
|
|
153
|
+
const matchNext = (index) => {
|
|
154
|
+
if (index >= node.elements.length)
|
|
155
|
+
return k(true);
|
|
156
|
+
const matcher = new PatternMatcher(val[index], this.bindings, this.ctx);
|
|
157
|
+
return node.elements[index].accept(matcher)((isMatch) => {
|
|
158
|
+
if (!isMatch)
|
|
159
|
+
return k(false);
|
|
160
|
+
return () => matchNext(index + 1);
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
return matchNext(0);
|
|
164
|
+
};
|
|
165
|
+
if (isLazyList(this.value)) {
|
|
166
|
+
return this.ctx.lazyRuntime.realizeList(this.value, (val) => {
|
|
167
|
+
return () => processValue(val);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return processValue(this.value);
|
|
171
|
+
};
|
|
87
172
|
}
|
|
88
173
|
visitListPattern(node) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return
|
|
174
|
+
return (k) => {
|
|
175
|
+
const value = this.value;
|
|
176
|
+
const neededLength = node.elements.length;
|
|
177
|
+
const finishMatching = (valArr) => {
|
|
178
|
+
if (valArr.length !== neededLength)
|
|
179
|
+
return k(false);
|
|
180
|
+
return this.matchList(node.elements, valArr, k);
|
|
181
|
+
};
|
|
182
|
+
// empty list case
|
|
183
|
+
if (neededLength === 0) {
|
|
184
|
+
if (Array.isArray(value) || typeof value === "string")
|
|
185
|
+
return k(value.length === 0);
|
|
186
|
+
if (isLazyList(value)) {
|
|
187
|
+
const iter = value.generator();
|
|
188
|
+
return k(iter.next().done);
|
|
189
|
+
}
|
|
190
|
+
return k(false);
|
|
96
191
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
192
|
+
if (Array.isArray(value))
|
|
193
|
+
return finishMatching(value);
|
|
194
|
+
if (typeof value === "string")
|
|
195
|
+
return finishMatching(value.split(""));
|
|
196
|
+
if (isLazyList(value)) {
|
|
197
|
+
return this.ctx.lazyRuntime.realizeList(value, (valArr) => {
|
|
198
|
+
return () => finishMatching(valArr);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return k(false);
|
|
202
|
+
};
|
|
108
203
|
}
|
|
109
|
-
matchList(elements, value) {
|
|
204
|
+
matchList(elements, value, k) {
|
|
110
205
|
if (value.length !== elements.length)
|
|
111
|
-
return false;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
206
|
+
return k(false);
|
|
207
|
+
const matchNext = (index) => {
|
|
208
|
+
if (index >= elements.length)
|
|
209
|
+
return k(true);
|
|
210
|
+
const matcher = new PatternMatcher(value[index], this.bindings, this.ctx);
|
|
211
|
+
return elements[index].accept(matcher)((isMatch) => {
|
|
212
|
+
if (!isMatch)
|
|
213
|
+
return k(false);
|
|
214
|
+
return () => matchNext(index + 1);
|
|
215
|
+
});
|
|
216
|
+
};
|
|
217
|
+
return matchNext(0);
|
|
119
218
|
}
|
|
120
219
|
visitConsPattern(node) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
220
|
+
return (k) => {
|
|
221
|
+
const [head, tail] = this.resolveCons(this.value);
|
|
222
|
+
if (head === null || tail === null)
|
|
223
|
+
return k(false);
|
|
224
|
+
const headMatcher = new PatternMatcher(head, this.bindings, this.ctx);
|
|
225
|
+
return node.left.accept(headMatcher)((headMatches) => {
|
|
226
|
+
if (!headMatches)
|
|
227
|
+
return k(false);
|
|
228
|
+
const tailMatcher = new PatternMatcher(tail, this.bindings, this.ctx);
|
|
229
|
+
return node.right.accept(tailMatcher)(k);
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
visitTypePattern(node) {
|
|
234
|
+
return (k) => {
|
|
235
|
+
const actualType = getYukigoType(this.value);
|
|
236
|
+
let matches = false;
|
|
237
|
+
const targetType = node.targetType;
|
|
238
|
+
if (targetType instanceof SimpleType) {
|
|
239
|
+
matches = targetType.value === actualType;
|
|
240
|
+
}
|
|
241
|
+
else if (targetType instanceof ListType) {
|
|
242
|
+
matches = actualType === "YuList";
|
|
243
|
+
}
|
|
244
|
+
if (!matches)
|
|
245
|
+
return k(false);
|
|
246
|
+
if (node.innerPattern) {
|
|
247
|
+
const innerMatcher = new PatternMatcher(this.value, this.bindings, this.ctx);
|
|
248
|
+
return node.innerPattern.accept(innerMatcher)(k);
|
|
249
|
+
}
|
|
250
|
+
return k(true);
|
|
251
|
+
};
|
|
130
252
|
}
|
|
131
253
|
resolveCons(list) {
|
|
132
|
-
if (Array.isArray(list))
|
|
133
|
-
|
|
134
|
-
if (isLazyList(list)) {
|
|
135
|
-
const headIter = list.generator();
|
|
136
|
-
const next = headIter.next();
|
|
137
|
-
if (next.done)
|
|
254
|
+
if (Array.isArray(list)) {
|
|
255
|
+
if (list.length === 0)
|
|
138
256
|
return [null, null];
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
257
|
+
const isLazy = this.ctx.config.lazyLoading;
|
|
258
|
+
if (!isLazy)
|
|
259
|
+
return [list[0], list.slice(1)];
|
|
260
|
+
const tail = {
|
|
261
|
+
type: "LazyList",
|
|
262
|
+
generator: function* () {
|
|
263
|
+
for (let i = 1; i < list.length; i++)
|
|
264
|
+
yield list[i];
|
|
265
|
+
},
|
|
146
266
|
};
|
|
147
|
-
return [
|
|
267
|
+
return [list[0], tail];
|
|
268
|
+
}
|
|
269
|
+
if (typeof list === "string") {
|
|
270
|
+
if (list.length === 0)
|
|
271
|
+
return [null, null];
|
|
272
|
+
const isLazy = this.ctx.config.lazyLoading;
|
|
273
|
+
if (!isLazy)
|
|
274
|
+
return [list[0], list.slice(1)];
|
|
275
|
+
const tail = {
|
|
276
|
+
type: "LazyList",
|
|
277
|
+
generator: function* () {
|
|
278
|
+
for (let i = 1; i < list.length; i++)
|
|
279
|
+
yield list[i];
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
return [list[0], tail];
|
|
283
|
+
}
|
|
284
|
+
// lazy list case
|
|
285
|
+
if (isLazyList(list)) {
|
|
286
|
+
let memoList;
|
|
287
|
+
// optimize, convert to memoized
|
|
288
|
+
if (isMemoizedList(list)) {
|
|
289
|
+
memoList = list;
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
memoList = createMemoizedStream(list.generator);
|
|
293
|
+
}
|
|
294
|
+
const currentRes = memoList._sequence.get(memoList._offset);
|
|
295
|
+
if (currentRes.done)
|
|
296
|
+
return [null, null];
|
|
297
|
+
const tail = createMemoizedStream(list.generator, memoList._sequence, memoList._offset + 1);
|
|
298
|
+
return [currentRes.value, tail];
|
|
148
299
|
}
|
|
149
300
|
return [null, null];
|
|
150
301
|
}
|
|
151
302
|
visitConstructorPattern(node) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
303
|
+
return (k) => {
|
|
304
|
+
if (!Array.isArray(this.value) || this.value.length === 0)
|
|
305
|
+
return k(false);
|
|
306
|
+
if (this.value[0] !== node.identifier.value)
|
|
307
|
+
return k(false);
|
|
308
|
+
const args = this.value.slice(1);
|
|
309
|
+
return this.matchList(node.args, args, k);
|
|
310
|
+
};
|
|
158
311
|
}
|
|
159
312
|
visitFunctorPattern(node) {
|
|
160
|
-
return this.visitConstructorPattern(new ConstructorPattern(node.identifier
|
|
313
|
+
return this.visitConstructorPattern(new ConstructorPattern(node.identifier, node.args));
|
|
161
314
|
}
|
|
162
315
|
visitApplicationPattern(node) {
|
|
163
|
-
return this.visitConstructorPattern(new ConstructorPattern(node.
|
|
316
|
+
return this.visitConstructorPattern(new ConstructorPattern(node.identifier, node.args));
|
|
164
317
|
}
|
|
165
318
|
visitAsPattern(node) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
319
|
+
return (k) => {
|
|
320
|
+
const innerMatcher = new PatternMatcher(this.value, this.bindings, this.ctx);
|
|
321
|
+
return node.right.accept(innerMatcher)((innerMatches) => {
|
|
322
|
+
if (!innerMatches)
|
|
323
|
+
return k(false);
|
|
324
|
+
const aliasMatcher = new PatternMatcher(this.value, this.bindings, this.ctx);
|
|
325
|
+
return node.left.accept(aliasMatcher)(k);
|
|
326
|
+
});
|
|
327
|
+
};
|
|
172
328
|
}
|
|
173
329
|
visitUnionPattern(node) {
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
330
|
+
return (k) => {
|
|
331
|
+
const tryNext = (index) => {
|
|
332
|
+
if (index >= node.elements.length)
|
|
333
|
+
return k(false);
|
|
334
|
+
const pattern = node.elements[index];
|
|
335
|
+
const trialBindings = [];
|
|
336
|
+
const matcher = new PatternMatcher(this.value, trialBindings, this.ctx);
|
|
337
|
+
return pattern.accept(matcher)((isMatch) => {
|
|
338
|
+
if (isMatch) {
|
|
339
|
+
this.bindings.push(...trialBindings);
|
|
340
|
+
return k(true);
|
|
341
|
+
}
|
|
342
|
+
return () => tryNext(index + 1);
|
|
343
|
+
});
|
|
344
|
+
};
|
|
345
|
+
return tryNext(0);
|
|
346
|
+
};
|
|
183
347
|
}
|
|
184
348
|
visit(node) {
|
|
185
349
|
return node.accept(this);
|
|
186
350
|
}
|
|
187
|
-
deepEqual(a, b) {
|
|
188
|
-
if (a === b)
|
|
189
|
-
return true;
|
|
190
|
-
if (typeof a !== typeof b)
|
|
191
|
-
return false;
|
|
192
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
193
|
-
if (a.length !== b.length)
|
|
194
|
-
return false;
|
|
195
|
-
for (let i = 0; i < a.length; i++) {
|
|
196
|
-
if (!this.deepEqual(a[i], b[i]))
|
|
197
|
-
return false;
|
|
198
|
-
}
|
|
199
|
-
return true;
|
|
200
|
-
}
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
realize(value) {
|
|
204
|
-
return new InterpreterVisitor([new Map()], {}).realizeList(value);
|
|
205
|
-
}
|
|
206
351
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Environment, EnvStack, PrimitiveValue } from "yukigo-ast";
|
|
2
|
+
import { FunctionRuntime } from "./runtimes/FunctionRuntime.js";
|
|
3
|
+
import { LazyRuntime } from "./runtimes/LazyRuntime.js";
|
|
4
|
+
import { ObjectRuntime } from "./runtimes/ObjectRuntime.js";
|
|
5
|
+
export declare const DefaultConfiguration: Required<InterpreterConfig>;
|
|
6
|
+
export type LogicSearchMode = "first" | "all" | "stream";
|
|
7
|
+
export interface InterpreterConfig {
|
|
8
|
+
lazyLoading?: boolean;
|
|
9
|
+
debug?: boolean;
|
|
10
|
+
outputMode?: LogicSearchMode;
|
|
11
|
+
mutability?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare class UninitializedConfig extends Error {
|
|
14
|
+
constructor();
|
|
15
|
+
}
|
|
16
|
+
export declare class ReinitializedConfig extends Error {
|
|
17
|
+
constructor();
|
|
18
|
+
}
|
|
19
|
+
export declare class RuntimeContext {
|
|
20
|
+
readonly config: InterpreterConfig | null;
|
|
21
|
+
env: EnvStack;
|
|
22
|
+
lazyRuntime: LazyRuntime;
|
|
23
|
+
funcRuntime: FunctionRuntime;
|
|
24
|
+
objRuntime: ObjectRuntime;
|
|
25
|
+
constructor(config?: InterpreterConfig);
|
|
26
|
+
setEnv(env: EnvStack): void;
|
|
27
|
+
isDefined(name: string): boolean;
|
|
28
|
+
pushEnv(frame?: Environment): void;
|
|
29
|
+
replace(name: string, value: PrimitiveValue, onReplace?: (env: Environment) => void): boolean;
|
|
30
|
+
popEnv(): void;
|
|
31
|
+
lookup(name: string): PrimitiveValue;
|
|
32
|
+
remove(name: string): void;
|
|
33
|
+
define(name: string, value: PrimitiveValue): void;
|
|
34
|
+
clone(env?: EnvStack): EnvStack;
|
|
35
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { FunctionRuntime } from "./runtimes/FunctionRuntime.js";
|
|
2
|
+
import { LazyRuntime } from "./runtimes/LazyRuntime.js";
|
|
3
|
+
import { ObjectRuntime } from "./runtimes/ObjectRuntime.js";
|
|
4
|
+
import { createGlobalEnv } from "../utils.js";
|
|
5
|
+
import { UnboundVariable } from "../errors.js";
|
|
6
|
+
export const DefaultConfiguration = {
|
|
7
|
+
lazyLoading: false,
|
|
8
|
+
debug: false,
|
|
9
|
+
outputMode: "first",
|
|
10
|
+
mutability: true,
|
|
11
|
+
};
|
|
12
|
+
export class UninitializedConfig extends Error {
|
|
13
|
+
constructor() {
|
|
14
|
+
super("GlobalConfig was not initialized. You must call initialize() first.");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class ReinitializedConfig extends Error {
|
|
18
|
+
constructor() {
|
|
19
|
+
super("GlobalConfig is already initialized. You cannot change it at execution.");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class RuntimeContext {
|
|
23
|
+
config = null;
|
|
24
|
+
env;
|
|
25
|
+
lazyRuntime;
|
|
26
|
+
funcRuntime;
|
|
27
|
+
objRuntime;
|
|
28
|
+
constructor(config) {
|
|
29
|
+
this.config = Object.freeze({ ...DefaultConfiguration, ...config });
|
|
30
|
+
this.lazyRuntime = new LazyRuntime(this);
|
|
31
|
+
this.funcRuntime = new FunctionRuntime(this);
|
|
32
|
+
this.objRuntime = new ObjectRuntime(this);
|
|
33
|
+
this.env = createGlobalEnv();
|
|
34
|
+
}
|
|
35
|
+
setEnv(env) {
|
|
36
|
+
this.env = env;
|
|
37
|
+
}
|
|
38
|
+
isDefined(name) {
|
|
39
|
+
let current = this.env;
|
|
40
|
+
while (current !== null) {
|
|
41
|
+
if (current.head.has(name))
|
|
42
|
+
return true;
|
|
43
|
+
current = current.tail;
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
pushEnv(frame = new Map()) {
|
|
48
|
+
this.env = {
|
|
49
|
+
head: frame,
|
|
50
|
+
tail: this.env,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
replace(name, value, onReplace) {
|
|
54
|
+
let current = this.env;
|
|
55
|
+
while (current !== null) {
|
|
56
|
+
if (current.head.has(name)) {
|
|
57
|
+
current.head.set(name, value);
|
|
58
|
+
if (onReplace)
|
|
59
|
+
onReplace(current.head);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
current = current.tail;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
popEnv() {
|
|
67
|
+
if (!this.env.tail)
|
|
68
|
+
throw new Error("Runtime Error: Cannot pop the global environment scope.");
|
|
69
|
+
this.env = this.env.tail;
|
|
70
|
+
}
|
|
71
|
+
lookup(name) {
|
|
72
|
+
let current = this.env;
|
|
73
|
+
while (current !== null) {
|
|
74
|
+
if (current.head.has(name))
|
|
75
|
+
return current.head.get(name);
|
|
76
|
+
current = current.tail;
|
|
77
|
+
}
|
|
78
|
+
throw new UnboundVariable(name);
|
|
79
|
+
}
|
|
80
|
+
remove(name) {
|
|
81
|
+
this.env.head.delete(name);
|
|
82
|
+
}
|
|
83
|
+
define(name, value) {
|
|
84
|
+
this.env.head.set(name, value);
|
|
85
|
+
}
|
|
86
|
+
clone(env) {
|
|
87
|
+
const target = env ?? this.env;
|
|
88
|
+
return {
|
|
89
|
+
head: new Map(target.head),
|
|
90
|
+
tail: this.env.tail,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Assert, PrimitiveValue, Test, TestGroup, TraverseVisitor } from "yukigo-ast";
|
|
2
|
+
import { InterpreterVisitor } from "./Visitor.js";
|
|
3
|
+
import { CPSThunk } from "../trampoline.js";
|
|
4
|
+
import { LazyRuntime } from "./runtimes/LazyRuntime.js";
|
|
5
|
+
export declare class FailedAssert extends Error {
|
|
6
|
+
actual?: PrimitiveValue;
|
|
7
|
+
expected?: PrimitiveValue;
|
|
8
|
+
constructor(actual?: PrimitiveValue, expected?: PrimitiveValue, message?: string);
|
|
9
|
+
}
|
|
10
|
+
export declare class TestRunner extends TraverseVisitor {
|
|
11
|
+
interpreter: InterpreterVisitor;
|
|
12
|
+
private lazyRuntime;
|
|
13
|
+
constructor(interpreter: InterpreterVisitor, lazyRuntime: LazyRuntime);
|
|
14
|
+
run(node: TestGroup | Test | Assert): CPSThunk<void>;
|
|
15
|
+
visitTestGroup(node: TestGroup): CPSThunk<void>;
|
|
16
|
+
visitTest(node: Test): CPSThunk<void>;
|
|
17
|
+
visitAssert(node: Assert): CPSThunk<void>;
|
|
18
|
+
}
|