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
@@ -0,0 +1,471 @@
1
+ import { Fact, FunctorPattern, ListPattern, LiteralPattern, Rule, VariablePattern, WildcardPattern, isRuntimePredicate, UnguardedBody, Findall, ConsPattern, Equation, SymbolPrimitive, Goal, Exist, LogicConstraint, Sequence, Not, ComparisonOperation, UnifyOperation, ApplicationPattern, TuplePattern, ConstructorPattern, UnionPattern, AsPattern, TypePattern, AssignOperation, ArithmeticBinaryOperation, ArithmeticUnaryOperation, ConsExpression, ListPrimitive, TupleExpression, If, Forall, Call, ListBinaryOperation, ListUnaryOperation, LogicalBinaryOperation, LogicalUnaryOperation, BitwiseBinaryOperation, BitwiseUnaryOperation, StringOperation, isUnguardedBody, } from "yukigo-ast";
2
+ /**
3
+ * Creates a successful logic result.
4
+ */
5
+ export function success(substs) {
6
+ return { success: true, substs };
7
+ }
8
+ /**
9
+ * Unifies two patterns given an existing set of substitutions.
10
+ * Returns the updated substitution map or null if unification fails.
11
+ */
12
+ export function unify(t1, t2, argEnv) {
13
+ const env = argEnv ? new Map(argEnv) : new Map();
14
+ return unifyInPlace(t1, t2, env) ? env : null;
15
+ }
16
+ /**
17
+ * Internal unification that modifies the environment in place for efficiency during recursion.
18
+ */
19
+ function unifyInPlace(t1, t2, env) {
20
+ const r1 = resolve(t1, env);
21
+ const r2 = resolve(t2, env);
22
+ if (r1 === r2)
23
+ return true;
24
+ if (r1 instanceof WildcardPattern || r2 instanceof WildcardPattern) {
25
+ return true;
26
+ }
27
+ if (r1 instanceof VariablePattern) {
28
+ env.set(r1.name.value, r2);
29
+ return true;
30
+ }
31
+ if (r2 instanceof VariablePattern) {
32
+ env.set(r2.name.value, r1);
33
+ return true;
34
+ }
35
+ if (r1 instanceof LiteralPattern && r2 instanceof LiteralPattern) {
36
+ return r1.name.equals(r2.name);
37
+ }
38
+ if (r1 instanceof FunctorPattern && r2 instanceof FunctorPattern) {
39
+ if (r1.identifier.value !== r2.identifier.value)
40
+ return false;
41
+ if (r1.args.length !== r2.args.length)
42
+ return false;
43
+ for (let i = 0; i < r1.args.length; i++) {
44
+ if (!unifyInPlace(r1.args[i], r2.args[i], env))
45
+ return false;
46
+ }
47
+ return true;
48
+ }
49
+ if (r1 instanceof ListPattern && r2 instanceof ListPattern) {
50
+ if (r1.elements.length !== r2.elements.length)
51
+ return false;
52
+ for (let i = 0; i < r1.elements.length; i++) {
53
+ if (!unifyInPlace(r1.elements[i], r2.elements[i], env))
54
+ return false;
55
+ }
56
+ return true;
57
+ }
58
+ if (r1 instanceof ConsPattern && r2 instanceof ConsPattern) {
59
+ let curr1 = r1;
60
+ let curr2 = r2;
61
+ while (curr1 instanceof ConsPattern && curr2 instanceof ConsPattern) {
62
+ if (!unifyInPlace(curr1.left, curr2.left, env))
63
+ return false;
64
+ curr1 = resolve(curr1.right, env);
65
+ curr2 = resolve(curr2.right, env);
66
+ }
67
+ return unifyInPlace(curr1, curr2, env);
68
+ }
69
+ if (r1 instanceof ConsPattern && r2 instanceof ListPattern) {
70
+ if (r2.elements.length === 0)
71
+ return false;
72
+ const [head, ...tail] = r2.elements;
73
+ return (unifyInPlace(r1.left, head, env) &&
74
+ unifyInPlace(r1.right, new ListPattern(tail), env));
75
+ }
76
+ if (r1 instanceof ListPattern && r2 instanceof ConsPattern) {
77
+ if (r1.elements.length === 0)
78
+ return false;
79
+ const [head, ...tail] = r1.elements;
80
+ return (unifyInPlace(head, r2.left, env) &&
81
+ unifyInPlace(new ListPattern(tail), r2.right, env));
82
+ }
83
+ return false;
84
+ }
85
+ /**
86
+ * Follows variable bindings in the substitution map until a non-variable or unbound variable is found.
87
+ */
88
+ export function resolve(node, env) {
89
+ let current = node;
90
+ const seen = new Set();
91
+ while (current instanceof VariablePattern) {
92
+ const name = current.name.value;
93
+ if (seen.has(name))
94
+ break;
95
+ seen.add(name);
96
+ const bound = env.get(name);
97
+ if (!bound)
98
+ break;
99
+ current = bound;
100
+ }
101
+ return current;
102
+ }
103
+ class Instantiator {
104
+ substs;
105
+ seen;
106
+ constructor(substs, seen = new Set()) {
107
+ this.substs = substs;
108
+ this.seen = seen;
109
+ }
110
+ visitVariablePattern(node) {
111
+ const name = node.name.value;
112
+ if (this.seen.has(name))
113
+ return node;
114
+ const val = this.substs.get(name);
115
+ if (val) {
116
+ const nextSeen = new Set(this.seen);
117
+ nextSeen.add(name);
118
+ return new Instantiator(this.substs, nextSeen).instantiate(val);
119
+ }
120
+ return node;
121
+ }
122
+ visitLiteralPattern(node) {
123
+ return node;
124
+ }
125
+ visitApplicationPattern(node) {
126
+ return new ApplicationPattern(node.identifier, node.args.map((arg) => this.instantiate(arg)), node.loc);
127
+ }
128
+ visitTuplePattern(node) {
129
+ return new TuplePattern(node.elements.map((el) => this.instantiate(el)), node.loc);
130
+ }
131
+ visitListPattern(node) {
132
+ return new ListPattern(node.elements.map((el) => this.instantiate(el)), node.loc);
133
+ }
134
+ visitFunctorPattern(node) {
135
+ return new FunctorPattern(node.identifier, node.args.map((arg) => this.instantiate(arg)), node.loc);
136
+ }
137
+ visitAsPattern(node) {
138
+ return new AsPattern(this.instantiate(node.left), this.instantiate(node.right), node.loc);
139
+ }
140
+ visitWildcardPattern(node) {
141
+ return node;
142
+ }
143
+ visitUnionPattern(node) {
144
+ return new UnionPattern(node.elements.map((el) => this.instantiate(el)), node.loc);
145
+ }
146
+ visitConstructorPattern(node) {
147
+ return new ConstructorPattern(node.identifier, node.args.map((arg) => this.instantiate(arg)), node.loc);
148
+ }
149
+ visitConsPattern(node) {
150
+ return new ConsPattern(this.instantiate(node.left), this.instantiate(node.right), node.loc);
151
+ }
152
+ visitTypePattern(node) {
153
+ return new TypePattern(node.targetType, node.innerPattern ? this.instantiate(node.innerPattern) : undefined, node.loc);
154
+ }
155
+ instantiate(pattern) {
156
+ return pattern.accept(this);
157
+ }
158
+ }
159
+ /**
160
+ * Fully instantiates a pattern by replacing all bound variables with their values.
161
+ */
162
+ export function instantiate(pattern, substs, seen = new Set()) {
163
+ return new Instantiator(substs, seen).instantiate(pattern);
164
+ }
165
+ let variableCounter = 0;
166
+ class LogicVariableRenamer {
167
+ renames;
168
+ freshId;
169
+ constructor(renames, freshId) {
170
+ this.renames = renames;
171
+ this.freshId = freshId;
172
+ }
173
+ rename(node) {
174
+ if (!node || typeof node !== "object")
175
+ return node;
176
+ if (typeof node.accept === "function") {
177
+ return node.accept(this);
178
+ }
179
+ return node;
180
+ }
181
+ visitFact(node) {
182
+ return new Fact(node.identifier, node.patterns.map((p) => this.rename(p)), node.loc);
183
+ }
184
+ visitRule(node) {
185
+ const renamedEquations = node.equations.map((eq) => {
186
+ const body = eq.body;
187
+ if (!isUnguardedBody(body))
188
+ throw new Error("GuardedBody renaming not implemented");
189
+ return new Equation(eq.patterns.map((p) => this.rename(p)), body.accept(this), eq.returnExpr, eq.loc);
190
+ });
191
+ return new Rule(node.identifier, renamedEquations, node.loc);
192
+ }
193
+ visitUnguardedBody(node) {
194
+ return new UnguardedBody(new Sequence(node.sequence.statements.map((stmt) => this.rename(stmt)), node.sequence.loc), node.loc);
195
+ }
196
+ // PatternVisitor
197
+ visitVariablePattern(node) {
198
+ const name = node.name.value;
199
+ let newName = this.renames.get(name);
200
+ if (!newName) {
201
+ newName = `${name}_${this.freshId}`;
202
+ this.renames.set(name, newName);
203
+ }
204
+ return new VariablePattern(new SymbolPrimitive(newName), node.loc);
205
+ }
206
+ visitLiteralPattern(node) {
207
+ return node;
208
+ }
209
+ visitApplicationPattern(node) {
210
+ return new ApplicationPattern(node.identifier, node.args.map((arg) => this.rename(arg)), node.loc);
211
+ }
212
+ visitTuplePattern(node) {
213
+ return new TuplePattern(node.elements.map((el) => this.rename(el)), node.loc);
214
+ }
215
+ visitListPattern(node) {
216
+ return new ListPattern(node.elements.map((el) => this.rename(el)), node.loc);
217
+ }
218
+ visitFunctorPattern(node) {
219
+ return new FunctorPattern(node.identifier, node.args.map((arg) => this.rename(arg)), node.loc);
220
+ }
221
+ visitAsPattern(node) {
222
+ return new AsPattern(this.rename(node.left), this.rename(node.right), node.loc);
223
+ }
224
+ visitWildcardPattern(node) {
225
+ return node;
226
+ }
227
+ visitUnionPattern(node) {
228
+ return new UnionPattern(node.elements.map((el) => this.rename(el)), node.loc);
229
+ }
230
+ visitConstructorPattern(node) {
231
+ return new ConstructorPattern(node.identifier, node.args.map((arg) => this.rename(arg)), node.loc);
232
+ }
233
+ visitConsPattern(node) {
234
+ return new ConsPattern(this.rename(node.left), this.rename(node.right), node.loc);
235
+ }
236
+ visitTypePattern(node) {
237
+ return new TypePattern(node.targetType, node.innerPattern ? this.rename(node.innerPattern) : undefined, node.loc);
238
+ }
239
+ // Expression/Statement Visitor
240
+ visitSymbolPrimitive(node) {
241
+ const name = node.value;
242
+ if (/^[A-Z_]/.test(name) && name !== "_") {
243
+ let newName = this.renames.get(name);
244
+ if (!newName) {
245
+ newName = `${name}_${this.freshId}`;
246
+ this.renames.set(name, newName);
247
+ }
248
+ return new SymbolPrimitive(newName, node.loc);
249
+ }
250
+ return node;
251
+ }
252
+ visitNumberPrimitive(node) {
253
+ return node;
254
+ }
255
+ visitStringPrimitive(node) {
256
+ return node;
257
+ }
258
+ visitBooleanPrimitive(node) {
259
+ return node;
260
+ }
261
+ visitNilPrimitive(node) {
262
+ return node;
263
+ }
264
+ visitCharPrimitive(node) {
265
+ return node;
266
+ }
267
+ visitGoal(node) {
268
+ return new Goal(node.identifier, node.args.map((arg) => this.rename(arg)), node.loc);
269
+ }
270
+ visitExist(node) {
271
+ return new Exist(node.identifier, node.patterns.map((pat) => this.rename(pat)), node.loc);
272
+ }
273
+ visitFindall(node) {
274
+ return new Findall(this.rename(node.template), this.rename(node.goal), this.rename(node.bag), node.loc);
275
+ }
276
+ visitForall(node) {
277
+ return new Forall(this.rename(node.condition), this.rename(node.action), node.loc);
278
+ }
279
+ visitCall(node) {
280
+ return new Call(this.rename(node.callee), node.args.map((arg) => this.rename(arg)), node.loc);
281
+ }
282
+ visitNot(node) {
283
+ return new Not(this.rename(node.expression), node.loc);
284
+ }
285
+ visitLogicConstraint(node) {
286
+ return new LogicConstraint(this.rename(node.expression), node.loc);
287
+ }
288
+ visitSequence(node) {
289
+ return new Sequence(node.statements.map((stmt) => this.rename(stmt)), node.loc);
290
+ }
291
+ visitIf(node) {
292
+ return new If(this.rename(node.condition), this.rename(node.then), this.rename(node.elseExpr), node.loc);
293
+ }
294
+ visitComparisonOperation(node) {
295
+ return new ComparisonOperation(node.operator, this.rename(node.left), this.rename(node.right), node.loc);
296
+ }
297
+ visitUnifyOperation(node) {
298
+ return new UnifyOperation(node.operator, this.rename(node.left), this.rename(node.right), node.loc);
299
+ }
300
+ visitAssignOperation(node) {
301
+ return new AssignOperation(node.operator, this.rename(node.left), this.rename(node.right), node.loc);
302
+ }
303
+ visitArithmeticBinaryOperation(node) {
304
+ return new ArithmeticBinaryOperation(node.operator, this.rename(node.left), this.rename(node.right), node.loc);
305
+ }
306
+ visitArithmeticUnaryOperation(node) {
307
+ return new ArithmeticUnaryOperation(node.operator, this.rename(node.operand), node.loc);
308
+ }
309
+ visitListBinaryOperation(node) {
310
+ return new ListBinaryOperation(node.operator, this.rename(node.left), this.rename(node.right), node.loc);
311
+ }
312
+ visitListUnaryOperation(node) {
313
+ return new ListUnaryOperation(node.operator, this.rename(node.operand), node.loc);
314
+ }
315
+ visitLogicalBinaryOperation(node) {
316
+ return new LogicalBinaryOperation(node.operator, this.rename(node.left), this.rename(node.right), node.loc);
317
+ }
318
+ visitLogicalUnaryOperation(node) {
319
+ return new LogicalUnaryOperation(node.operator, this.rename(node.operand), node.loc);
320
+ }
321
+ visitBitwiseBinaryOperation(node) {
322
+ return new BitwiseBinaryOperation(node.operator, this.rename(node.left), this.rename(node.right), node.loc);
323
+ }
324
+ visitBitwiseUnaryOperation(node) {
325
+ return new BitwiseUnaryOperation(node.operator, this.rename(node.operand), node.loc);
326
+ }
327
+ visitStringOperation(node) {
328
+ return new StringOperation(node.operator, this.rename(node.left), this.rename(node.right), node.loc);
329
+ }
330
+ visitConsExpression(node) {
331
+ return new ConsExpression(this.rename(node.head), this.rename(node.tail), node.loc);
332
+ }
333
+ visitListPrimitive(node) {
334
+ return new ListPrimitive(node.value.map((el) => this.rename(el)), node.loc);
335
+ }
336
+ visitTupleExpr(node) {
337
+ return new TupleExpression(node.elements.map((el) => this.rename(el)), node.loc);
338
+ }
339
+ }
340
+ /**
341
+ * Renames all variables in a Rule or Fact to fresh names to avoid name clashes during unification.
342
+ */
343
+ export function renameVariables(clause) {
344
+ const renames = new Map();
345
+ const freshId = ++variableCounter;
346
+ const renamer = new LogicVariableRenamer(renames, freshId);
347
+ const renamedClause = clause.accept(renamer);
348
+ return renamedClause;
349
+ }
350
+ class CPSBodyVisitor {
351
+ solveBody;
352
+ substs;
353
+ onSuccess;
354
+ onNextEq;
355
+ constructor(solveBody, substs, onSuccess, onNextEq) {
356
+ this.solveBody = solveBody;
357
+ this.substs = substs;
358
+ this.onSuccess = onSuccess;
359
+ this.onNextEq = onNextEq;
360
+ }
361
+ visitUnguardedBody(body) {
362
+ return this.solveBody(body.sequence.statements, this.substs, this.onSuccess, this.onNextEq);
363
+ }
364
+ visitGuardedBody(body) {
365
+ return this.solveBody([body.condition], this.substs, (guardSubsts, _nextGuardChoice) => {
366
+ return this.solveBody([body.body], guardSubsts, this.onSuccess, this.onNextEq);
367
+ }, this.onNextEq);
368
+ }
369
+ }
370
+ class GoalSolverVisitor {
371
+ args;
372
+ baseSubst;
373
+ solveBody;
374
+ onSuccess;
375
+ onNextClause;
376
+ constructor(args, baseSubst, solveBody, onSuccess, onNextClause) {
377
+ this.args = args;
378
+ this.baseSubst = baseSubst;
379
+ this.solveBody = solveBody;
380
+ this.onSuccess = onSuccess;
381
+ this.onNextClause = onNextClause;
382
+ }
383
+ visitFact(fact) {
384
+ if (fact.patterns.length !== this.args.length)
385
+ return this.onNextClause;
386
+ const renamedFact = renameVariables(fact);
387
+ const substs = unifyParameters(renamedFact.patterns, this.args, this.baseSubst);
388
+ if (substs)
389
+ return this.onSuccess(substs, this.onNextClause);
390
+ return this.onNextClause;
391
+ }
392
+ visitRule(rule) {
393
+ if (rule.equations.length === 0)
394
+ return this.onNextClause;
395
+ const arity = rule.equations[0].patterns.length;
396
+ if (arity !== this.args.length)
397
+ return this.onNextClause;
398
+ const renamedRule = renameVariables(rule);
399
+ const tryRuleEq = (eqIndex) => {
400
+ if (eqIndex >= renamedRule.equations.length)
401
+ return this.onNextClause;
402
+ const eq = renamedRule.equations[eqIndex];
403
+ const substs = unifyParameters(eq.patterns, this.args, this.baseSubst);
404
+ const onNextEq = () => tryRuleEq(eqIndex + 1);
405
+ if (!substs)
406
+ return onNextEq;
407
+ const bodyVisitor = new CPSBodyVisitor(this.solveBody, substs, this.onSuccess, onNextEq);
408
+ if (isUnguardedBody(eq.body))
409
+ return eq.body.accept(bodyVisitor);
410
+ return eq.body.forEach((branch) => branch.accept(bodyVisitor));
411
+ };
412
+ return () => tryRuleEq(0);
413
+ }
414
+ }
415
+ /**
416
+ * Solves a single logic goal (predicate call) using CPS.
417
+ */
418
+ export function solveGoalCPS(ctx, predicateName, args, solveBody, baseSubst, onSuccess, onFailure) {
419
+ const tryClause = (index) => {
420
+ let equations;
421
+ try {
422
+ const pred = ctx.lookup(predicateName);
423
+ if (!pred || !isRuntimePredicate(pred))
424
+ return () => onFailure();
425
+ equations = pred.equations;
426
+ }
427
+ catch (error) {
428
+ return () => onFailure();
429
+ }
430
+ if (index >= equations.length)
431
+ return () => onFailure();
432
+ const clause = equations[index];
433
+ const onNextClause = () => tryClause(index + 1);
434
+ const clauseVisitor = new GoalSolverVisitor(args, baseSubst, solveBody, onSuccess, onNextClause);
435
+ return clause.accept(clauseVisitor);
436
+ };
437
+ return () => tryClause(0);
438
+ }
439
+ /**
440
+ * Unifies two lists of parameters. Returns the resulting Substitution or null.
441
+ */
442
+ function unifyParameters(patterns, args, baseSubst) {
443
+ let subst = new Map(baseSubst);
444
+ for (let i = 0; i < patterns.length; i++) {
445
+ const nextSubst = unify(patterns[i], args[i], subst);
446
+ if (!nextSubst)
447
+ return null;
448
+ subst = nextSubst;
449
+ }
450
+ return subst;
451
+ }
452
+ /**
453
+ * Solves a findall/3 goal using CPS.
454
+ */
455
+ export function solveFindallCPS(node, currentSubsts, solveBody, onSuccess, onFailure) {
456
+ const gathered = [];
457
+ const collectResults = () => {
458
+ return solveBody([node.goal], currentSubsts, (resultSubsts, next) => {
459
+ gathered.push(instantiate(node.template, resultSubsts));
460
+ return () => next();
461
+ }, () => {
462
+ const resultList = new ListPattern(gathered);
463
+ const finalSubsts = unify(node.bag, resultList, currentSubsts);
464
+ if (finalSubsts) {
465
+ return onSuccess(finalSubsts, onFailure);
466
+ }
467
+ return () => onFailure();
468
+ });
469
+ };
470
+ return collectResults();
471
+ }
@@ -0,0 +1,14 @@
1
+ import { Expression, Pattern, PrimitiveValue } from "yukigo-ast";
2
+ import { Substitution } from "./LogicResolver.js";
3
+ import { ExpressionEvaluator } from "../../utils.js";
4
+ import { Continuation, Thunk } from "../../trampoline.js";
5
+ import { RuntimeContext } from "../RuntimeContext.js";
6
+ export declare class LogicTranslator {
7
+ private evaluator;
8
+ private ctx;
9
+ constructor(evaluator: ExpressionEvaluator, ctx: RuntimeContext);
10
+ patternToPrimitive(pat: Pattern): PrimitiveValue | undefined;
11
+ expressionToPattern<R = Pattern>(expr: Expression, k: Continuation<Pattern, R>): Thunk<R>;
12
+ primitiveToPattern(val: PrimitiveValue): Pattern;
13
+ instantiateExpressionAsPattern<R = Pattern>(expr: Expression, substs: Substitution, k: Continuation<Pattern, R>): Thunk<R>;
14
+ }
@@ -0,0 +1,99 @@
1
+ import { LiteralPattern, SymbolPrimitive, Variable, VariablePattern, isPattern, NumberPrimitive, StringPrimitive, BooleanPrimitive, ListPrimitive, ListPattern, ConsExpression, ConsPattern, FunctorPattern, } from "yukigo-ast";
2
+ import { instantiate } from "./LogicResolver.js";
3
+ import { InterpreterError } from "../../errors.js";
4
+ export class LogicTranslator {
5
+ evaluator;
6
+ ctx;
7
+ constructor(evaluator, ctx) {
8
+ this.evaluator = evaluator;
9
+ this.ctx = ctx;
10
+ }
11
+ patternToPrimitive(pat) {
12
+ if (pat instanceof LiteralPattern) {
13
+ const primitive = pat.name;
14
+ return primitive.value;
15
+ }
16
+ if (pat instanceof ListPattern) {
17
+ return pat.elements.map((el) => this.patternToPrimitive(el));
18
+ }
19
+ if (pat instanceof ConsPattern) {
20
+ const head = this.patternToPrimitive(pat.left);
21
+ const tail = this.patternToPrimitive(pat.right);
22
+ if (Array.isArray(tail)) {
23
+ return [head, ...tail];
24
+ }
25
+ return [head, tail];
26
+ }
27
+ // Return the pattern itself for non-primitive logic terms (VariablePattern, FunctorPattern, etc.)
28
+ return pat;
29
+ }
30
+ expressionToPattern(expr, k) {
31
+ if (isPattern(expr))
32
+ return k(expr);
33
+ if (expr instanceof ListPrimitive) {
34
+ const results = [];
35
+ const next = (index) => {
36
+ if (index >= expr.value.length)
37
+ return k(new ListPattern(results));
38
+ return this.expressionToPattern(expr.value[index], (p) => {
39
+ results.push(p);
40
+ return () => next(index + 1);
41
+ });
42
+ };
43
+ return next(0);
44
+ }
45
+ if (expr instanceof ConsExpression) {
46
+ return this.expressionToPattern(expr.head, (headPat) => {
47
+ return () => this.expressionToPattern(expr.tail, (tailPat) => {
48
+ return k(new ConsPattern(headPat, tailPat));
49
+ });
50
+ });
51
+ }
52
+ if (expr instanceof Variable || expr instanceof SymbolPrimitive) {
53
+ const name = expr instanceof Variable ? expr.identifier.value : expr.value;
54
+ if (this.ctx.isDefined(name)) {
55
+ return this.evaluator.evaluate(expr, (val) => {
56
+ return k(this.primitiveToPattern(val));
57
+ });
58
+ }
59
+ return k(new VariablePattern(expr instanceof Variable ? expr.identifier : expr));
60
+ }
61
+ return this.evaluator.evaluate(expr, (val) => {
62
+ return k(this.primitiveToPattern(val));
63
+ });
64
+ }
65
+ primitiveToPattern(val) {
66
+ if (isPattern(val)) {
67
+ return val;
68
+ }
69
+ if (typeof val === "number") {
70
+ return new LiteralPattern(new NumberPrimitive(val));
71
+ }
72
+ if (typeof val === "string") {
73
+ return new LiteralPattern(new StringPrimitive(val));
74
+ }
75
+ if (typeof val === "boolean") {
76
+ return new LiteralPattern(new BooleanPrimitive(val));
77
+ }
78
+ if (Array.isArray(val)) {
79
+ return new ListPattern(val.map((v) => this.primitiveToPattern(v)));
80
+ }
81
+ if (val &&
82
+ typeof val === "object" &&
83
+ "type" in val &&
84
+ val.type === "Object") {
85
+ // Convert RuntimeObject to FunctorPattern for logic matching
86
+ const args = [];
87
+ for (const [_, fieldVal] of val.fields) {
88
+ args.push(this.primitiveToPattern(fieldVal));
89
+ }
90
+ return new FunctorPattern(new SymbolPrimitive(val.className || val.identifier), args);
91
+ }
92
+ throw new InterpreterError("primitiveToPattern", `Cannot convert value ${val} to Logic Pattern`);
93
+ }
94
+ instantiateExpressionAsPattern(expr, substs, k) {
95
+ return this.expressionToPattern(expr, (patternBase) => {
96
+ return k(instantiate(patternBase, substs));
97
+ });
98
+ }
99
+ }
@@ -0,0 +1,12 @@
1
+ import { PrimitiveValue, RuntimeFunction } from "yukigo-ast";
2
+ import { Continuation, CPSThunk, Thunk } from "../../trampoline.js";
3
+ import { RuntimeContext } from "../RuntimeContext.js";
4
+ export declare class FunctionRuntime {
5
+ private context;
6
+ constructor(context: RuntimeContext);
7
+ apply(func: RuntimeFunction, args: PrimitiveValue[], k: Continuation<PrimitiveValue>): Thunk<PrimitiveValue>;
8
+ applyArguments(func: RuntimeFunction, args: (PrimitiveValue | (() => PrimitiveValue))[]): CPSThunk<PrimitiveValue>;
9
+ private preloadDefinitions;
10
+ private patternsMatch;
11
+ private evaluateSequence;
12
+ }