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.
Files changed (144) hide show
  1. package/.mocharc.json +3 -3
  2. package/CHANGELOG.md +26 -0
  3. package/README.md +193 -199
  4. package/dist/analyzer/GraphBuilder.d.ts +29 -0
  5. package/dist/analyzer/GraphBuilder.js +99 -0
  6. package/dist/analyzer/index.d.ts +11 -23
  7. package/dist/analyzer/index.js +100 -58
  8. package/dist/analyzer/inspections/functional/functional.d.ts +44 -0
  9. package/dist/analyzer/inspections/functional/functional.js +149 -0
  10. package/dist/analyzer/inspections/functional/smells.d.ts +16 -0
  11. package/dist/analyzer/inspections/functional/smells.js +98 -0
  12. package/dist/analyzer/inspections/{generic.d.ts → generic/generic.d.ts} +70 -43
  13. package/dist/analyzer/inspections/generic/generic.js +604 -0
  14. package/dist/analyzer/inspections/generic/smells.d.ts +61 -0
  15. package/dist/analyzer/inspections/generic/smells.js +349 -0
  16. package/dist/analyzer/inspections/imperative/imperative.d.ts +35 -0
  17. package/dist/analyzer/inspections/imperative/imperative.js +109 -0
  18. package/dist/analyzer/inspections/imperative/smells.d.ts +16 -0
  19. package/dist/analyzer/inspections/imperative/smells.js +58 -0
  20. package/dist/analyzer/inspections/logic/logic.d.ts +32 -0
  21. package/dist/analyzer/inspections/logic/logic.js +96 -0
  22. package/dist/analyzer/inspections/logic/smells.d.ts +15 -0
  23. package/dist/analyzer/inspections/logic/smells.js +60 -0
  24. package/dist/analyzer/inspections/object/object.d.ts +88 -0
  25. package/dist/analyzer/inspections/object/object.js +319 -0
  26. package/dist/analyzer/inspections/object/smells.d.ts +30 -0
  27. package/dist/analyzer/inspections/object/smells.js +135 -0
  28. package/dist/analyzer/utils.d.ts +26 -4
  29. package/dist/analyzer/utils.js +71 -13
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.js +1 -0
  32. package/dist/interpreter/components/EnvBuilder.d.ts +9 -5
  33. package/dist/interpreter/components/EnvBuilder.js +100 -30
  34. package/dist/interpreter/components/Operations.d.ts +4 -4
  35. package/dist/interpreter/components/Operations.js +17 -2
  36. package/dist/interpreter/components/PatternMatcher.d.ts +47 -17
  37. package/dist/interpreter/components/PatternMatcher.js +264 -119
  38. package/dist/interpreter/components/RuntimeContext.d.ts +35 -0
  39. package/dist/interpreter/components/RuntimeContext.js +93 -0
  40. package/dist/interpreter/components/TestRunner.d.ts +18 -0
  41. package/dist/interpreter/components/TestRunner.js +103 -0
  42. package/dist/interpreter/components/Visitor.d.ts +63 -57
  43. package/dist/interpreter/components/Visitor.js +508 -173
  44. package/dist/interpreter/components/logic/LogicEngine.d.ts +29 -0
  45. package/dist/interpreter/components/logic/LogicEngine.js +259 -0
  46. package/dist/interpreter/components/logic/LogicResolver.d.ts +53 -0
  47. package/dist/interpreter/components/logic/LogicResolver.js +471 -0
  48. package/dist/interpreter/components/logic/LogicTranslator.d.ts +14 -0
  49. package/dist/interpreter/components/logic/LogicTranslator.js +99 -0
  50. package/dist/interpreter/components/runtimes/FunctionRuntime.d.ts +12 -0
  51. package/dist/interpreter/components/runtimes/FunctionRuntime.js +147 -0
  52. package/dist/interpreter/components/runtimes/LazyRuntime.d.ts +19 -0
  53. package/dist/interpreter/components/runtimes/LazyRuntime.js +269 -0
  54. package/dist/interpreter/components/runtimes/ObjectRuntime.d.ts +35 -0
  55. package/dist/interpreter/components/runtimes/ObjectRuntime.js +126 -0
  56. package/dist/interpreter/entities.d.ts +105 -0
  57. package/dist/interpreter/entities.js +96 -0
  58. package/dist/interpreter/errors.d.ts +1 -1
  59. package/dist/interpreter/index.d.ts +4 -12
  60. package/dist/interpreter/index.js +10 -13
  61. package/dist/interpreter/trampoline.d.ts +17 -0
  62. package/dist/interpreter/trampoline.js +38 -0
  63. package/dist/interpreter/utils.d.ts +4 -7
  64. package/dist/interpreter/utils.js +25 -17
  65. package/dist/tester/index.d.ts +25 -0
  66. package/dist/tester/index.js +108 -0
  67. package/dist/utils/helpers.d.ts +0 -4
  68. package/dist/utils/helpers.js +20 -24
  69. package/package.json +2 -2
  70. package/src/analyzer/GraphBuilder.ts +142 -0
  71. package/src/analyzer/index.ts +185 -132
  72. package/src/analyzer/inspections/functional/functional.ts +121 -0
  73. package/src/analyzer/inspections/functional/smells.ts +102 -0
  74. package/src/analyzer/inspections/{generic.ts → generic/generic.ts} +581 -499
  75. package/src/analyzer/inspections/generic/smells.ts +365 -0
  76. package/src/analyzer/inspections/imperative/imperative.ts +101 -0
  77. package/src/analyzer/inspections/imperative/smells.ts +54 -0
  78. package/src/analyzer/inspections/logic/logic.ts +90 -0
  79. package/src/analyzer/inspections/logic/smells.ts +54 -0
  80. package/src/analyzer/inspections/{object.ts → object/object.ts} +264 -282
  81. package/src/analyzer/inspections/object/smells.ts +144 -0
  82. package/src/analyzer/utils.ts +109 -26
  83. package/src/index.ts +3 -2
  84. package/src/interpreter/components/EnvBuilder.ts +202 -97
  85. package/src/interpreter/components/Operations.ts +99 -81
  86. package/src/interpreter/components/PatternMatcher.ts +475 -254
  87. package/src/interpreter/components/RuntimeContext.ts +119 -0
  88. package/src/interpreter/components/TestRunner.ts +151 -0
  89. package/src/interpreter/components/Visitor.ts +1065 -493
  90. package/src/interpreter/components/logic/LogicEngine.ts +519 -0
  91. package/src/interpreter/components/logic/LogicResolver.ts +858 -0
  92. package/src/interpreter/components/logic/LogicTranslator.ts +149 -0
  93. package/src/interpreter/components/runtimes/FunctionRuntime.ts +227 -0
  94. package/src/interpreter/components/runtimes/LazyRuntime.ts +334 -0
  95. package/src/interpreter/components/runtimes/ObjectRuntime.ts +224 -0
  96. package/src/interpreter/errors.ts +47 -47
  97. package/src/interpreter/index.ts +52 -59
  98. package/src/interpreter/trampoline.ts +71 -0
  99. package/src/interpreter/utils.ts +84 -79
  100. package/src/tester/index.ts +128 -0
  101. package/src/utils/helpers.ts +67 -73
  102. package/tests/analyzer/functional.spec.ts +207 -221
  103. package/tests/analyzer/generic.spec.ts +178 -100
  104. package/tests/analyzer/helpers.spec.ts +83 -83
  105. package/tests/analyzer/logic.spec.ts +237 -292
  106. package/tests/analyzer/oop.spec.ts +323 -338
  107. package/tests/analyzer/transitive.spec.ts +166 -0
  108. package/tests/interpreter/EnvBuilder.spec.ts +183 -178
  109. package/tests/interpreter/FunctionRuntime.spec.ts +223 -234
  110. package/tests/interpreter/LazyRuntime.spec.ts +225 -190
  111. package/tests/interpreter/LogicEngine.spec.ts +327 -194
  112. package/tests/interpreter/LogicSubstitution.spec.ts +80 -0
  113. package/tests/interpreter/ObjectRuntime.spec.ts +606 -0
  114. package/tests/interpreter/Operations.spec.ts +220 -220
  115. package/tests/interpreter/PatternSystem.spec.ts +213 -189
  116. package/tests/interpreter/Tests.spec.ts +122 -0
  117. package/tests/interpreter/interpreter.spec.ts +991 -937
  118. package/tests/tester/Tester.spec.ts +153 -0
  119. package/tsconfig.build.json +15 -7
  120. package/tsconfig.json +25 -17
  121. package/dist/analyzer/inspections/functional.d.ts +0 -46
  122. package/dist/analyzer/inspections/functional.js +0 -123
  123. package/dist/analyzer/inspections/generic.js +0 -427
  124. package/dist/analyzer/inspections/imperative.d.ts +0 -37
  125. package/dist/analyzer/inspections/imperative.js +0 -105
  126. package/dist/analyzer/inspections/logic.d.ts +0 -49
  127. package/dist/analyzer/inspections/logic.js +0 -140
  128. package/dist/analyzer/inspections/object.d.ts +0 -83
  129. package/dist/analyzer/inspections/object.js +0 -235
  130. package/dist/interpreter/components/FunctionRuntime.d.ts +0 -8
  131. package/dist/interpreter/components/FunctionRuntime.js +0 -52
  132. package/dist/interpreter/components/LazyRuntime.d.ts +0 -7
  133. package/dist/interpreter/components/LazyRuntime.js +0 -75
  134. package/dist/interpreter/components/LogicEngine.d.ts +0 -21
  135. package/dist/interpreter/components/LogicEngine.js +0 -152
  136. package/dist/interpreter/components/LogicResolver.d.ts +0 -11
  137. package/dist/interpreter/components/LogicResolver.js +0 -87
  138. package/src/analyzer/inspections/functional.ts +0 -159
  139. package/src/analyzer/inspections/imperative.ts +0 -129
  140. package/src/analyzer/inspections/logic.ts +0 -166
  141. package/src/interpreter/components/FunctionRuntime.ts +0 -79
  142. package/src/interpreter/components/LazyRuntime.ts +0 -97
  143. package/src/interpreter/components/LogicEngine.ts +0 -227
  144. package/src/interpreter/components/LogicResolver.ts +0 -130
@@ -1,6 +1,64 @@
1
- import { ConstructorPattern, isLazyList, ListPrimitive, } from "@yukigo/ast";
1
+ import { ConstructorPattern, isLazyList, ListPrimitive, SimpleType, ListType, } from "yukigo-ast";
2
2
  import { InterpreterVisitor } from "./Visitor.js";
3
- import { createStream } from "../utils.js";
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.elements.map((elem) => elem.accept(this)));
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.head.accept(this);
28
- const tail = node.tail.accept(this);
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.constr;
33
- const args = node.patterns.map((pat) => pat.accept(this)).join(" ");
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.value, node.args));
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.symbol.value, node.args));
100
+ return this.visitConstructorPattern(new ConstructorPattern(node.identifier, node.args));
43
101
  }
44
102
  visitAsPattern(node) {
45
- const pattern = node.pattern.accept(this);
46
- const alias = node.alias.accept(this);
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
- constructor(value, bindings) {
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
- this.bindings.push([node.name.value, this.value]);
67
- return true;
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
- const literalValue = InterpreterVisitor.evaluateLiteral(node.name);
74
- return this.deepEqual(this.value, literalValue);
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
- if (!Array.isArray(this.value))
78
- return false;
79
- if (this.value.length !== node.elements.length)
80
- return false;
81
- for (let i = 0; i < node.elements.length; i++) {
82
- const matcher = new PatternMatcher(this.value[i], this.bindings);
83
- if (!node.elements[i].accept(matcher))
84
- return false;
85
- }
86
- return true;
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
- // empty list case
90
- if (node.elements.length === 0) {
91
- if (Array.isArray(this.value))
92
- return this.value.length === 0;
93
- if (isLazyList(this.value)) {
94
- const iter = this.value.generator();
95
- return iter.next().done;
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
- return false;
98
- }
99
- // finite list case
100
- if (Array.isArray(this.value))
101
- return this.matchList(node.elements, this.value);
102
- // lazy list case
103
- if (isLazyList(this.value)) {
104
- const realized = this.realize(this.value);
105
- return this.matchList(node.elements, realized);
106
- }
107
- return false;
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
- for (let i = 0; i < elements.length; i++) {
113
- const matcher = new PatternMatcher(value[i], this.bindings);
114
- const isMatch = elements[i].accept(matcher);
115
- if (!isMatch)
116
- return false;
117
- }
118
- return true;
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
- const [head, tail] = this.resolveCons(this.value);
122
- if (!head || !tail)
123
- return false;
124
- const headMatcher = new PatternMatcher(head, this.bindings);
125
- const headMatches = node.head.accept(headMatcher);
126
- if (!headMatches)
127
- return false;
128
- const tailMatcher = new PatternMatcher(tail, this.bindings);
129
- return node.tail.accept(tailMatcher);
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
- return list.length === 0 ? [null, null] : [list[0], list.slice(1)];
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 parentGeneratorFactory = list.generator;
140
- const tailGenerator = function* () {
141
- const freshIter = parentGeneratorFactory();
142
- freshIter.next();
143
- let next;
144
- while (!(next = freshIter.next()).done)
145
- yield next.value;
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 [next.value, createStream(tailGenerator)];
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
- if (!Array.isArray(this.value) || this.value.length === 0)
153
- return false;
154
- if (this.value[0] !== node.constr)
155
- return false;
156
- const args = this.value.slice(1);
157
- return this.matchList(node.patterns, args);
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.value, node.args));
313
+ return this.visitConstructorPattern(new ConstructorPattern(node.identifier, node.args));
161
314
  }
162
315
  visitApplicationPattern(node) {
163
- return this.visitConstructorPattern(new ConstructorPattern(node.symbol.value, node.args));
316
+ return this.visitConstructorPattern(new ConstructorPattern(node.identifier, node.args));
164
317
  }
165
318
  visitAsPattern(node) {
166
- const innerMatcher = new PatternMatcher(this.value, this.bindings);
167
- const innerMatches = node.pattern.accept(innerMatcher);
168
- if (!innerMatches)
169
- return false;
170
- const aliasMatcher = new PatternMatcher(this.value, this.bindings);
171
- return node.alias.accept(aliasMatcher);
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
- for (const pattern of node.patterns) {
175
- const trialBindings = [];
176
- const matcher = new PatternMatcher(this.value, trialBindings);
177
- if (pattern.accept(matcher)) {
178
- this.bindings.push(...trialBindings);
179
- return true;
180
- }
181
- }
182
- return false;
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
+ }