yukigo 0.2.3 → 0.3.2

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 (266) hide show
  1. package/.mocharc.json +3 -3
  2. package/CHANGELOG.md +105 -40
  3. package/README.md +193 -193
  4. package/dist/analyzer/GraphBuilder.d.ts +1 -0
  5. package/dist/analyzer/GraphBuilder.js +2 -1
  6. package/dist/analyzer/index.d.ts +0 -7
  7. package/dist/analyzer/index.js +3 -3
  8. package/dist/analyzer/inspections/functional/functional.d.ts +1 -1
  9. package/dist/analyzer/inspections/functional/functional.js +1 -1
  10. package/dist/analyzer/inspections/functional/smells.d.ts +3 -3
  11. package/dist/analyzer/inspections/functional/smells.js +27 -35
  12. package/dist/analyzer/inspections/generic/generic.d.ts +22 -14
  13. package/dist/analyzer/inspections/generic/generic.js +82 -60
  14. package/dist/analyzer/inspections/generic/smells.d.ts +2 -0
  15. package/dist/analyzer/inspections/generic/smells.js +55 -64
  16. package/dist/analyzer/inspections/imperative/imperative.d.ts +3 -3
  17. package/dist/analyzer/inspections/imperative/imperative.js +3 -3
  18. package/dist/analyzer/inspections/imperative/smells.d.ts +1 -0
  19. package/dist/analyzer/inspections/imperative/smells.js +8 -5
  20. package/dist/analyzer/inspections/logic/logic.d.ts +8 -8
  21. package/dist/analyzer/inspections/logic/logic.js +5 -5
  22. package/dist/analyzer/inspections/logic/smells.js +2 -2
  23. package/dist/analyzer/inspections/object/object.d.ts +5 -5
  24. package/dist/analyzer/inspections/object/object.js +22 -21
  25. package/dist/analyzer/inspections/object/smells.js +11 -23
  26. package/dist/analyzer/utils.d.ts +6 -2
  27. package/dist/analyzer/utils.js +6 -2
  28. package/dist/interpreter/components/EnvBuilder.d.ts +20 -1
  29. package/dist/interpreter/components/EnvBuilder.js +211 -66
  30. package/dist/interpreter/components/EqualityComparer.d.ts +15 -0
  31. package/dist/interpreter/components/EqualityComparer.js +69 -0
  32. package/dist/interpreter/components/Operations.d.ts +17 -14
  33. package/dist/interpreter/components/Operations.js +61 -62
  34. package/dist/interpreter/components/PatternMatcher.d.ts +19 -58
  35. package/dist/interpreter/components/PatternMatcher.js +185 -286
  36. package/dist/interpreter/components/RuntimeContext.d.ts +24 -15
  37. package/dist/interpreter/components/RuntimeContext.js +43 -4
  38. package/dist/interpreter/components/TestRunner.d.ts +15 -13
  39. package/dist/interpreter/components/TestRunner.js +86 -53
  40. package/dist/interpreter/components/evaluators/BaseEvaluator.d.ts +19 -0
  41. package/dist/interpreter/components/evaluators/BaseEvaluator.js +20 -0
  42. package/dist/interpreter/components/evaluators/ExpressionEvaluator.d.ts +34 -0
  43. package/dist/interpreter/components/evaluators/ExpressionEvaluator.js +298 -0
  44. package/dist/interpreter/components/evaluators/OperationEvaluator.d.ts +25 -0
  45. package/dist/interpreter/components/evaluators/OperationEvaluator.js +226 -0
  46. package/dist/interpreter/components/evaluators/PrimitiveEvaluator.d.ts +19 -0
  47. package/dist/interpreter/components/evaluators/PrimitiveEvaluator.js +50 -0
  48. package/dist/interpreter/components/evaluators/StatementEvaluator.d.ts +28 -0
  49. package/dist/interpreter/components/evaluators/StatementEvaluator.js +240 -0
  50. package/dist/interpreter/components/evaluators/TestingEvaluator.d.ts +15 -0
  51. package/dist/interpreter/components/evaluators/TestingEvaluator.js +14 -0
  52. package/dist/interpreter/components/evaluators/index.d.ts +110 -0
  53. package/dist/interpreter/components/evaluators/index.js +21 -0
  54. package/dist/interpreter/components/evaluators/utils.d.ts +7 -0
  55. package/dist/interpreter/components/evaluators/utils.js +50 -0
  56. package/dist/interpreter/components/hooks/YukigoHook.d.ts +27 -0
  57. package/dist/interpreter/components/hooks/YukigoHook.js +1 -0
  58. package/dist/interpreter/components/kernel/commands.d.ts +122 -0
  59. package/dist/interpreter/components/kernel/commands.js +203 -0
  60. package/dist/interpreter/components/kernel/index.d.ts +51 -0
  61. package/dist/interpreter/components/kernel/index.js +176 -0
  62. package/dist/interpreter/components/logic/LogicEngine.d.ts +26 -23
  63. package/dist/interpreter/components/logic/LogicEngine.js +234 -221
  64. package/dist/interpreter/components/logic/LogicResolver.d.ts +22 -51
  65. package/dist/interpreter/components/logic/LogicResolver.js +73 -440
  66. package/dist/interpreter/components/logic/LogicTerm.d.ts +104 -0
  67. package/dist/interpreter/components/logic/LogicTerm.js +423 -0
  68. package/dist/interpreter/components/logic/LogicTranslator.d.ts +25 -9
  69. package/dist/interpreter/components/logic/LogicTranslator.js +211 -74
  70. package/dist/interpreter/components/runtimes/FunctionRuntime.d.ts +6 -4
  71. package/dist/interpreter/components/runtimes/FunctionRuntime.js +82 -84
  72. package/dist/interpreter/components/runtimes/LazyRuntime.d.ts +13 -14
  73. package/dist/interpreter/components/runtimes/LazyRuntime.js +112 -239
  74. package/dist/interpreter/components/runtimes/ObjectRuntime.d.ts +17 -14
  75. package/dist/interpreter/components/runtimes/ObjectRuntime.js +105 -74
  76. package/dist/interpreter/errors.d.ts +10 -0
  77. package/dist/interpreter/errors.js +17 -0
  78. package/dist/interpreter/index.d.ts +9 -5
  79. package/dist/interpreter/index.js +11 -13
  80. package/dist/interpreter/primitives/YuValue.d.ts +21 -0
  81. package/dist/interpreter/primitives/YuValue.js +40 -0
  82. package/dist/interpreter/primitives/capabilities.d.ts +90 -0
  83. package/dist/interpreter/primitives/capabilities.js +1 -0
  84. package/dist/interpreter/primitives/entities/LazyList.d.ts +48 -0
  85. package/dist/interpreter/primitives/entities/LazyList.js +164 -0
  86. package/dist/interpreter/primitives/entities/LogicResult.d.ts +51 -0
  87. package/dist/interpreter/primitives/entities/LogicResult.js +101 -0
  88. package/dist/interpreter/primitives/entities/RuntimeClass.d.ts +24 -0
  89. package/dist/interpreter/primitives/entities/RuntimeClass.js +57 -0
  90. package/dist/interpreter/primitives/entities/RuntimeFunction.d.ts +40 -0
  91. package/dist/interpreter/primitives/entities/RuntimeFunction.js +73 -0
  92. package/dist/interpreter/primitives/entities/RuntimeObject.d.ts +27 -0
  93. package/dist/interpreter/primitives/entities/RuntimeObject.js +82 -0
  94. package/dist/interpreter/primitives/entities/RuntimePredicate.d.ts +19 -0
  95. package/dist/interpreter/primitives/entities/RuntimePredicate.js +59 -0
  96. package/dist/interpreter/primitives/index.d.ts +14 -0
  97. package/dist/interpreter/primitives/index.js +14 -0
  98. package/dist/interpreter/primitives/scalars/YuBoolean.d.ts +24 -0
  99. package/dist/interpreter/primitives/scalars/YuBoolean.js +69 -0
  100. package/dist/interpreter/primitives/scalars/YuChar.d.ts +28 -0
  101. package/dist/interpreter/primitives/scalars/YuChar.js +78 -0
  102. package/dist/interpreter/primitives/scalars/YuNil.d.ts +25 -0
  103. package/dist/interpreter/primitives/scalars/YuNil.js +73 -0
  104. package/dist/interpreter/primitives/scalars/YuNumber.d.ts +49 -0
  105. package/dist/interpreter/primitives/scalars/YuNumber.js +165 -0
  106. package/dist/interpreter/primitives/sequences/YuArray.d.ts +33 -0
  107. package/dist/interpreter/primitives/sequences/YuArray.js +150 -0
  108. package/dist/interpreter/primitives/sequences/YuString.d.ts +40 -0
  109. package/dist/interpreter/primitives/sequences/YuString.js +130 -0
  110. package/dist/interpreter/utils.d.ts +23 -10
  111. package/dist/interpreter/utils.js +25 -30
  112. package/dist/tester/index.d.ts +3 -3
  113. package/dist/tester/index.js +39 -28
  114. package/dist/utils/helpers.d.ts +13 -5
  115. package/dist/utils/helpers.js +38 -85
  116. package/package.json +3 -16
  117. package/src/analyzer/GraphBuilder.ts +143 -142
  118. package/src/analyzer/index.ts +185 -194
  119. package/src/analyzer/inspections/functional/functional.ts +121 -121
  120. package/src/analyzer/inspections/functional/smells.ts +88 -102
  121. package/src/analyzer/inspections/generic/generic.ts +610 -577
  122. package/src/analyzer/inspections/generic/smells.ts +355 -365
  123. package/src/analyzer/inspections/imperative/imperative.ts +104 -101
  124. package/src/analyzer/inspections/imperative/smells.ts +58 -54
  125. package/src/analyzer/inspections/logic/logic.ts +84 -90
  126. package/src/analyzer/inspections/logic/smells.ts +54 -54
  127. package/src/analyzer/inspections/object/object.ts +295 -264
  128. package/src/analyzer/inspections/object/smells.ts +130 -144
  129. package/src/analyzer/utils.ts +115 -109
  130. package/src/index.ts +3 -3
  131. package/src/interpreter/components/EnvBuilder.ts +405 -202
  132. package/src/interpreter/components/EqualityComparer.ts +107 -0
  133. package/src/interpreter/components/Operations.ts +126 -99
  134. package/src/interpreter/components/PatternMatcher.ts +375 -475
  135. package/src/interpreter/components/RuntimeContext.ts +181 -119
  136. package/src/interpreter/components/TestRunner.ts +223 -151
  137. package/src/interpreter/components/evaluators/BaseEvaluator.ts +36 -0
  138. package/src/interpreter/components/evaluators/ExpressionEvaluator.ts +475 -0
  139. package/src/interpreter/components/evaluators/OperationEvaluator.ts +477 -0
  140. package/src/interpreter/components/evaluators/PrimitiveEvaluator.ts +80 -0
  141. package/src/interpreter/components/evaluators/StatementEvaluator.ts +372 -0
  142. package/src/interpreter/components/evaluators/TestingEvaluator.ts +26 -0
  143. package/src/interpreter/components/evaluators/index.ts +34 -0
  144. package/src/interpreter/components/evaluators/utils.ts +64 -0
  145. package/src/interpreter/components/hooks/YukigoHook.ts +45 -0
  146. package/src/interpreter/components/kernel/commands.ts +255 -0
  147. package/src/interpreter/components/kernel/index.ts +222 -0
  148. package/src/interpreter/components/logic/LogicEngine.ts +509 -519
  149. package/src/interpreter/components/logic/LogicResolver.ts +209 -858
  150. package/src/interpreter/components/logic/LogicTerm.ts +477 -0
  151. package/src/interpreter/components/logic/LogicTranslator.ts +362 -149
  152. package/src/interpreter/components/runtimes/FunctionRuntime.ts +249 -227
  153. package/src/interpreter/components/runtimes/LazyRuntime.ts +226 -334
  154. package/src/interpreter/components/runtimes/ObjectRuntime.ts +262 -224
  155. package/src/interpreter/errors.ts +68 -47
  156. package/src/interpreter/index.ts +50 -52
  157. package/src/interpreter/primitives/YuValue.ts +64 -0
  158. package/src/interpreter/primitives/capabilities.ts +111 -0
  159. package/src/interpreter/primitives/entities/LazyList.ts +225 -0
  160. package/src/interpreter/primitives/entities/LogicResult.ts +133 -0
  161. package/src/interpreter/primitives/entities/RuntimeClass.ts +70 -0
  162. package/src/interpreter/primitives/entities/RuntimeFunction.ts +108 -0
  163. package/src/interpreter/primitives/entities/RuntimeObject.ts +110 -0
  164. package/src/interpreter/primitives/entities/RuntimePredicate.ts +77 -0
  165. package/src/interpreter/primitives/index.ts +17 -0
  166. package/src/interpreter/primitives/scalars/YuBoolean.ts +79 -0
  167. package/src/interpreter/primitives/scalars/YuChar.ts +94 -0
  168. package/src/interpreter/primitives/scalars/YuNil.ts +84 -0
  169. package/src/interpreter/primitives/scalars/YuNumber.ts +187 -0
  170. package/src/interpreter/primitives/sequences/YuArray.ts +178 -0
  171. package/src/interpreter/primitives/sequences/YuString.ts +165 -0
  172. package/src/interpreter/utils.ts +105 -84
  173. package/src/tester/index.ts +157 -128
  174. package/src/utils/helpers.ts +113 -169
  175. package/tests/analyzer/functional.spec.ts +221 -207
  176. package/tests/analyzer/generic.spec.ts +178 -178
  177. package/tests/analyzer/helpers.spec.ts +83 -89
  178. package/tests/analyzer/logic.spec.ts +237 -237
  179. package/tests/analyzer/oop.spec.ts +320 -323
  180. package/tests/analyzer/transitive.spec.ts +166 -166
  181. package/tests/interpreter/EnvBuilder.spec.ts +181 -183
  182. package/tests/interpreter/FunctionRuntime.spec.ts +224 -223
  183. package/tests/interpreter/LazyRuntime.spec.ts +227 -225
  184. package/tests/interpreter/LogicEngine.spec.ts +371 -327
  185. package/tests/interpreter/LogicSubstitution.spec.ts +90 -80
  186. package/tests/interpreter/ObjectRuntime.spec.ts +431 -606
  187. package/tests/interpreter/Operations.spec.ts +312 -220
  188. package/tests/interpreter/PatternSystem.spec.ts +254 -213
  189. package/tests/interpreter/Tests.spec.ts +122 -122
  190. package/tests/interpreter/interpreter.spec.ts +1143 -991
  191. package/tests/kernel/YukigoKernel.spec.ts +112 -0
  192. package/tests/tester/Tester.spec.ts +156 -152
  193. package/tsconfig.build.json +16 -15
  194. package/tsconfig.json +27 -25
  195. package/dist/interpreter/components/Visitor.d.ts +0 -70
  196. package/dist/interpreter/components/Visitor.js +0 -634
  197. package/dist/interpreter/entities.d.ts +0 -105
  198. package/dist/interpreter/entities.js +0 -96
  199. package/dist/interpreter/trampoline.d.ts +0 -17
  200. package/dist/interpreter/trampoline.js +0 -38
  201. package/dist/src/analyzer/GraphBuilder.d.ts +0 -30
  202. package/dist/src/analyzer/GraphBuilder.js +0 -100
  203. package/dist/src/analyzer/index.d.ts +0 -59
  204. package/dist/src/analyzer/index.js +0 -152
  205. package/dist/src/analyzer/inspections/functional/functional.d.ts +0 -44
  206. package/dist/src/analyzer/inspections/functional/functional.js +0 -149
  207. package/dist/src/analyzer/inspections/functional/smells.d.ts +0 -16
  208. package/dist/src/analyzer/inspections/functional/smells.js +0 -98
  209. package/dist/src/analyzer/inspections/generic/generic.d.ts +0 -178
  210. package/dist/src/analyzer/inspections/generic/generic.js +0 -604
  211. package/dist/src/analyzer/inspections/generic/smells.d.ts +0 -61
  212. package/dist/src/analyzer/inspections/generic/smells.js +0 -349
  213. package/dist/src/analyzer/inspections/imperative/imperative.d.ts +0 -35
  214. package/dist/src/analyzer/inspections/imperative/imperative.js +0 -109
  215. package/dist/src/analyzer/inspections/imperative/smells.d.ts +0 -16
  216. package/dist/src/analyzer/inspections/imperative/smells.js +0 -58
  217. package/dist/src/analyzer/inspections/logic/logic.d.ts +0 -32
  218. package/dist/src/analyzer/inspections/logic/logic.js +0 -96
  219. package/dist/src/analyzer/inspections/logic/smells.d.ts +0 -15
  220. package/dist/src/analyzer/inspections/logic/smells.js +0 -60
  221. package/dist/src/analyzer/inspections/object/object.d.ts +0 -90
  222. package/dist/src/analyzer/inspections/object/object.js +0 -321
  223. package/dist/src/analyzer/inspections/object/smells.d.ts +0 -30
  224. package/dist/src/analyzer/inspections/object/smells.js +0 -135
  225. package/dist/src/analyzer/utils.d.ts +0 -30
  226. package/dist/src/analyzer/utils.js +0 -78
  227. package/dist/src/index.d.ts +0 -4
  228. package/dist/src/index.js +0 -4
  229. package/dist/src/interpreter/components/EnvBuilder.d.ts +0 -21
  230. package/dist/src/interpreter/components/EnvBuilder.js +0 -155
  231. package/dist/src/interpreter/components/Operations.d.ts +0 -14
  232. package/dist/src/interpreter/components/Operations.js +0 -84
  233. package/dist/src/interpreter/components/PatternMatcher.d.ts +0 -73
  234. package/dist/src/interpreter/components/PatternMatcher.js +0 -358
  235. package/dist/src/interpreter/components/RuntimeContext.d.ts +0 -35
  236. package/dist/src/interpreter/components/RuntimeContext.js +0 -93
  237. package/dist/src/interpreter/components/TestRunner.d.ts +0 -19
  238. package/dist/src/interpreter/components/TestRunner.js +0 -110
  239. package/dist/src/interpreter/components/Visitor.d.ts +0 -71
  240. package/dist/src/interpreter/components/Visitor.js +0 -638
  241. package/dist/src/interpreter/components/logic/LogicEngine.d.ts +0 -29
  242. package/dist/src/interpreter/components/logic/LogicEngine.js +0 -259
  243. package/dist/src/interpreter/components/logic/LogicResolver.d.ts +0 -53
  244. package/dist/src/interpreter/components/logic/LogicResolver.js +0 -484
  245. package/dist/src/interpreter/components/logic/LogicTranslator.d.ts +0 -14
  246. package/dist/src/interpreter/components/logic/LogicTranslator.js +0 -99
  247. package/dist/src/interpreter/components/runtimes/FunctionRuntime.d.ts +0 -12
  248. package/dist/src/interpreter/components/runtimes/FunctionRuntime.js +0 -149
  249. package/dist/src/interpreter/components/runtimes/LazyRuntime.d.ts +0 -19
  250. package/dist/src/interpreter/components/runtimes/LazyRuntime.js +0 -269
  251. package/dist/src/interpreter/components/runtimes/ObjectRuntime.d.ts +0 -35
  252. package/dist/src/interpreter/components/runtimes/ObjectRuntime.js +0 -126
  253. package/dist/src/interpreter/errors.d.ts +0 -19
  254. package/dist/src/interpreter/errors.js +0 -36
  255. package/dist/src/interpreter/index.d.ts +0 -24
  256. package/dist/src/interpreter/index.js +0 -41
  257. package/dist/src/interpreter/trampoline.d.ts +0 -17
  258. package/dist/src/interpreter/trampoline.js +0 -38
  259. package/dist/src/interpreter/utils.d.ts +0 -11
  260. package/dist/src/interpreter/utils.js +0 -65
  261. package/dist/src/tester/index.d.ts +0 -25
  262. package/dist/src/tester/index.js +0 -113
  263. package/dist/src/utils/helpers.d.ts +0 -13
  264. package/dist/src/utils/helpers.js +0 -52
  265. package/src/interpreter/components/Visitor.ts +0 -1065
  266. package/src/interpreter/trampoline.ts +0 -71
@@ -1,327 +1,371 @@
1
- import { expect } from "chai";
2
- import {
3
- SymbolPrimitive,
4
- NumberPrimitive,
5
- LiteralPattern,
6
- VariablePattern,
7
- Fact,
8
- Findall,
9
- Goal,
10
- Pattern,
11
- Rule,
12
- LogicResult,
13
- EnvStack,
14
- Equation,
15
- Sequence,
16
- UnguardedBody,
17
- Statement,
18
- Variable,
19
- ConsPattern,
20
- ListPattern,
21
- NilPrimitive,
22
- LazyList,
23
- LogicConstraint,
24
- Expression,
25
- SuccessLogicResult,
26
- RuntimePredicate,
27
- } from "yukigo-ast";
28
- import {
29
- createGlobalEnv,
30
- ExpressionEvaluator,
31
- } from "../../src/interpreter/utils.js";
32
- import { LogicEngine } from "../../src/interpreter/components/logic/LogicEngine.js";
33
- import { unify } from "../../src/interpreter/components/logic/LogicResolver.js";
34
- import { PatternResolver } from "../../src/interpreter/components/PatternMatcher.js";
35
- import { InterpreterVisitor } from "../../src/interpreter/components/Visitor.js";
36
- import {
37
- idContinuation,
38
- trampoline,
39
- } from "../../src/interpreter/trampoline.js";
40
- import {
41
- InterpreterConfig,
42
- RuntimeContext,
43
- } from "../../src/interpreter/components/RuntimeContext.js";
44
-
45
- const s = (val: string) => new SymbolPrimitive(val);
46
- const n = (val: number) => new NumberPrimitive(val);
47
- const lit = (val: string | number) =>
48
- new LiteralPattern(typeof val === "string" ? s(val) : n(val));
49
- const varPat = (name: string) => new VariablePattern(s(name));
50
-
51
- const makeEq = (args: Pattern[], stmts: Statement[]) =>
52
- new Equation(args, new UnguardedBody(new Sequence(stmts)));
53
- const makeFact = (id: string, args: Pattern[]) => new Fact(s(id), args);
54
- const makeRule = (id: string, body: Equation[]) => new Rule(s(id), body);
55
- const makeGoal = (id: string, args: Pattern[]) => new Goal(s(id), args);
56
- const makeConstraint = (expr: Expression) => new LogicConstraint(expr);
57
-
58
- const factsParent: RuntimePredicate = {
59
- kind: "Fact",
60
- identifier: "parent",
61
- equations: [
62
- makeFact("parent", [lit("zeus"), lit("ares")]),
63
- makeFact("parent", [lit("zeus"), lit("athena")]),
64
- makeFact("parent", [lit("hera"), lit("ares")]),
65
- ],
66
- };
67
- const rulesSibling: RuntimePredicate = {
68
- kind: "Rule",
69
- identifier: "sibling",
70
- equations: [
71
- makeRule("sibling", [
72
- makeEq(
73
- [varPat("X"), varPat("Y")],
74
- [
75
- makeConstraint(makeGoal("parent", [varPat("Z"), varPat("X")])),
76
- makeConstraint(makeGoal("parent", [varPat("Z"), varPat("Y")])),
77
- ],
78
- ),
79
- ]),
80
- ],
81
- };
82
-
83
- const env = createGlobalEnv();
84
- const context = new RuntimeContext({
85
- debug: false,
86
- outputMode: "all",
87
- });
88
- context.setEnv(env);
89
- context.define("sibling", rulesSibling);
90
- context.define("parent", factsParent);
91
-
92
- describe("Logic Engine & Unification", () => {
93
- let engine: LogicEngine;
94
- let evaluator: ExpressionEvaluator;
95
-
96
- beforeEach(() => {
97
- evaluator = new InterpreterVisitor(context);
98
- engine = new LogicEngine(evaluator, context);
99
- });
100
-
101
- describe("Unification Algorithm", () => {
102
- it("should unify two identical literals", () => {
103
- const p1 = lit("cat");
104
- const p2 = lit("cat");
105
- const result = unify(p1, p2);
106
- expect(result).to.not.be.null;
107
- });
108
-
109
- it("should not unify different literals", () => {
110
- const p1 = lit("cat");
111
- const p2 = lit("dog");
112
- const result = unify(p1, p2);
113
- expect(result).to.be.null;
114
- });
115
-
116
- it("should unify a variable with a literal", () => {
117
- const v1 = varPat("X");
118
- const p2 = lit("cat");
119
- const result = unify(v1, p2);
120
-
121
- expect(result).to.not.be.null;
122
- const resolved = result!.get("X");
123
- expect(resolved).to.be.instanceOf(LiteralPattern);
124
- const resolver = new PatternResolver();
125
- expect(resolved?.accept(resolver)).to.equal("cat");
126
- });
127
-
128
- it("should unify two variables (aliasing)", () => {
129
- const v1 = varPat("X");
130
- const v2 = varPat("Y");
131
- const result = unify(v1, v2);
132
- expect(result).to.not.be.null;
133
- expect(result!.has("X")).to.be.true;
134
- });
135
-
136
- describe("ConsPattern Unification", () => {
137
- it("should unify two identical ConsPatterns", () => {
138
- const p1 = new ConsPattern(lit(1), new ListPattern([]));
139
- const p2 = new ConsPattern(lit(1), new ListPattern([]));
140
- const result = unify(p1, p2);
141
- expect(result).to.not.be.null;
142
- });
143
-
144
- it("should unify ConsPattern with equivalent ListPattern", () => {
145
- const cons = new ConsPattern(lit(1), new ListPattern([lit(2)]));
146
- const list = new ListPattern([lit(1), lit(2)]);
147
- const result = unify(cons, list);
148
- expect(result).to.not.be.null;
149
- });
150
-
151
- it("should unify ListPattern with equivalent ConsPattern", () => {
152
- const list = new ListPattern([lit(1), lit(2)]);
153
- const cons = new ConsPattern(lit(1), new ListPattern([lit(2)]));
154
- const result = unify(list, cons);
155
- expect(result).to.not.be.null;
156
- });
157
-
158
- it("should fail if heads do not match", () => {
159
- const cons = new ConsPattern(lit(1), new ListPattern([lit(2)]));
160
- const list = new ListPattern([lit(3), lit(2)]);
161
- const result = unify(cons, list);
162
- expect(result).to.be.null;
163
- });
164
-
165
- it("should fail if ListPattern is empty and ConsPattern expects head", () => {
166
- const list = new ListPattern([]);
167
- const cons = new ConsPattern(varPat("H"), varPat("T"));
168
- const result = unify(list, cons);
169
- expect(result).to.be.null;
170
- });
171
-
172
- it("should bind variables in ConsPattern", () => {
173
- const cons = new ConsPattern(varPat("H"), varPat("T"));
174
- const list = new ListPattern([lit(1), lit(2)]);
175
- const result = unify(cons, list);
176
- expect(result).to.not.be.null;
177
-
178
- const h = result!.get("H");
179
- expect(h).to.be.instanceOf(LiteralPattern);
180
-
181
- const t = result!.get("T");
182
- expect(t).to.be.instanceOf(ListPattern);
183
- expect((t as ListPattern).elements).to.have.lengthOf(1);
184
- });
185
-
186
- it("should unify infinite LazyList with Variable lazily", () => {
187
- // Create infinite generator
188
- const gen = function*() {
189
- let i = 1;
190
- while(true) yield i++;
191
- };
192
- const lazyList: LazyList = {
193
- type: "LazyList",
194
- generator: gen
195
- };
196
-
197
- // Mock evaluator to return this lazy list for variable "Infinite"
198
- evaluator.evaluate = (node: any) => {
199
- if (node instanceof Variable && node.identifier.value === "Infinite") {
200
- return lazyList;
201
- }
202
- if (node instanceof SymbolPrimitive) return node.value;
203
- return null;
204
- };
205
-
206
- // Unify X = Infinite
207
- const infiniteVar = new Variable(s("Infinite"), new NilPrimitive(null));
208
- const xVar = new Variable(s("X"), new NilPrimitive(null));
209
-
210
- const result = trampoline(engine.unifyExpr(xVar, infiniteVar, idContinuation)) as boolean;
211
- expect(result).to.be.true;
212
- });
213
- });
214
- });
215
-
216
- describe("LogicEngine Execution", () => {
217
- it("should solve a simple ground goal (Fact exists)", () => {
218
- const query = makeGoal("parent", [lit("zeus"), lit("ares")]);
219
- const results = trampoline(
220
- engine.solveGoal(query, idContinuation),
221
- ) as LogicResult[];
222
- expect(results).to.not.be.false;
223
- results.forEach((res) => expect(res.success).to.be.true);
224
- });
225
-
226
- it("should fail a ground goal that does not exist", () => {
227
- const query = makeGoal("parent", [lit("zeus"), lit("thor")]);
228
- const results = trampoline(
229
- engine.solveGoal(query, idContinuation),
230
- ) as LogicResult[];
231
- results.forEach((res) => expect(res.success).to.be.false);
232
- });
233
-
234
- it("should solve a goal with a variable", () => {
235
- const query = makeGoal("parent", [lit("zeus"), varPat("Child")]);
236
- const results = trampoline(
237
- engine.solveGoal(query, idContinuation),
238
- ) as LogicResult[];
239
-
240
- results.forEach((res) => {
241
- if (!res.success) expect.fail("Result should be successful");
242
- expect(res.solutions.has("Child")).to.be.true;
243
- });
244
-
245
- const names = results.map((r) => {
246
- if (!r.success) throw new Error("Unexpected failure");
247
- return r.solutions.get("Child");
248
- });
249
-
250
- expect(names).to.include("ares");
251
- expect(names).to.include("athena");
252
- });
253
-
254
- it("should solve a rule using backtracking", () => {
255
- const query = makeGoal("sibling", [lit("ares"), lit("athena")]);
256
- const results = trampoline(
257
- engine.solveGoal(query, idContinuation),
258
- ) as LogicResult[];
259
- expect(results.length).to.be.eq(1);
260
- const solution = results[0] as SuccessLogicResult;
261
- expect(solution.success).to.be.true;
262
- expect(solution.solutions.get("X")).to.eq("ares");
263
- expect(solution.solutions.get("Y")).to.eq("athena");
264
- expect(solution.solutions.get("Z")).to.eq("zeus");
265
- });
266
- });
267
- it("should solve a rule using backtracking with variable", () => {
268
- const query = makeGoal("sibling", [lit("ares"), varPat("Child")]);
269
- const results = trampoline(
270
- engine.solveGoal(query, idContinuation),
271
- ) as LogicResult[];
272
- results.forEach((res) => {
273
- if (!res.success) expect.fail("Result should be successful");
274
- expect(res.solutions.has("Child")).to.be.true;
275
- });
276
- const names = results.map((r) => {
277
- if (!r.success) throw new Error("Unexpected failure");
278
- return r.solutions.get("Child");
279
- });
280
- expect(names).to.include("ares");
281
- expect(names).to.include("athena");
282
- });
283
- describe("Output Modes", () => {
284
- it('should return all results when outputMode is "all"', () => {
285
- const query = makeGoal("parent", [lit("zeus"), varPat("X")]);
286
-
287
- const results = trampoline(
288
- engine.solveGoal(query, idContinuation),
289
- ) as LogicResult[];
290
- expect(results).to.be.an("array");
291
- expect(results).to.have.lengthOf(2);
292
- const names = results.map((r) => {
293
- if (!r.success) throw new Error("Unexpected failure");
294
- return r.solutions.get("X");
295
- });
296
- expect(names).to.include("ares");
297
- expect(names).to.include("athena");
298
- });
299
- });
300
-
301
- describe("Findall", () => {
302
- it("should collect all solutions into a list", () => {
303
- const findallNode = new Findall(
304
- varPat("X"), // Template
305
- makeGoal("parent", [lit("zeus"), varPat("X")]), // Goal
306
- varPat("List"), // Bag variable
307
- );
308
- const result = trampoline(
309
- engine.solveFindall(findallNode, idContinuation),
310
- ) as any;
311
- expect(Array.isArray(result)).to.be.true;
312
- expect(result).to.have.lengthOf(2);
313
- expect(result).to.include("ares");
314
- expect(result).to.include("athena");
315
- });
316
-
317
- describe("Expression Unification", () => {
318
- it("should successfully unify a variable with an array expression", () => {
319
- env.head.set("myList", "dummy");
320
- const X = new Variable(s("X"), new NilPrimitive(null));
321
- const myList = new Variable(s("myList"), new NilPrimitive(null));
322
- const result = trampoline(engine.unifyExpr(X, myList, idContinuation));
323
- expect(result).to.be.true;
324
- });
325
- });
326
- });
327
- });
1
+ import { expect } from "chai";
2
+ import {
3
+ SymbolPrimitive,
4
+ NumberPrimitive,
5
+ LiteralPattern,
6
+ VariablePattern,
7
+ Fact,
8
+ Findall,
9
+ Goal,
10
+ Pattern,
11
+ Rule,
12
+ Equation,
13
+ Sequence,
14
+ UnguardedBody,
15
+ Statement,
16
+ Variable,
17
+ NilPrimitive,
18
+ LogicConstraint,
19
+ Expression,
20
+ Query,
21
+ } from "yukigo-ast";
22
+ import { createGlobalEnv } from "../../src/interpreter/utils.js";
23
+ import { LogicEngine } from "../../src/interpreter/components/logic/LogicEngine.js";
24
+ import { RuntimeContext } from "../../src/interpreter/components/RuntimeContext.js";
25
+ import { YukigoKernel } from "../../src/interpreter/components/kernel/index.js";
26
+ import { StepCommand } from "../../src/interpreter/components/kernel/commands.js";
27
+ import {
28
+ VariableTerm,
29
+ ConstantTerm,
30
+ ListTerm,
31
+ ConsTerm,
32
+ CompoundTerm,
33
+ } from "../../src/interpreter/components/logic/LogicTerm.js";
34
+ import {
35
+ YuValue,
36
+ RuntimePredicate,
37
+ LogicTerm,
38
+ Substitution,
39
+ YuString,
40
+ YuNumber,
41
+ LazyList,
42
+ LazyStepResult,
43
+ YuNil,
44
+ LogicResult,
45
+ YuBoolean,
46
+ } from "../../src/interpreter/primitives/index.js";
47
+ import { InterpreterVisitor } from "../../src/interpreter/components/evaluators/index.js";
48
+
49
+ const s = (val: string) => new SymbolPrimitive(val);
50
+ const n = (val: number) => new NumberPrimitive(val);
51
+ const lit = (val: string | number) =>
52
+ new LiteralPattern(typeof val === "string" ? s(val) : n(val));
53
+ const varPat = (name: string) => new VariablePattern(s(name));
54
+
55
+ const makeEq = (args: Pattern[], stmts: Statement[]) =>
56
+ new Equation(args, new UnguardedBody(new Sequence(stmts)));
57
+ const makeFact = (id: string, args: Pattern[]) => new Fact(s(id), args);
58
+ const makeRule = (id: string, body: Equation[]) => new Rule(s(id), body);
59
+ const makeGoal = (id: string, args: Pattern[]) => new Goal(s(id), args);
60
+ const makeConstraint = (expr: Expression) => new LogicConstraint(expr);
61
+
62
+ const factsParent = new RuntimePredicate("parent", [
63
+ makeFact("parent", [lit("zeus"), lit("ares")]),
64
+ makeFact("parent", [lit("zeus"), lit("athena")]),
65
+ makeFact("parent", [lit("hera"), lit("ares")]),
66
+ ]);
67
+ const rulesSibling = new RuntimePredicate("sibling", [
68
+ makeRule("sibling", [
69
+ makeEq(
70
+ [varPat("X"), varPat("Y")],
71
+ [
72
+ makeConstraint(makeGoal("parent", [varPat("Z"), varPat("X")])),
73
+ makeConstraint(makeGoal("parent", [varPat("Z"), varPat("Y")])),
74
+ ],
75
+ ),
76
+ ]),
77
+ ]);
78
+
79
+ describe("Logic Engine & Unification", () => {
80
+ let engine: LogicEngine;
81
+ let evaluator: InterpreterVisitor;
82
+ let kernel: YukigoKernel;
83
+ let context: RuntimeContext;
84
+ let globalEnv: any;
85
+
86
+ beforeEach(() => {
87
+ globalEnv = createGlobalEnv();
88
+ context = new RuntimeContext({
89
+ debug: false,
90
+ outputMode: "all",
91
+ });
92
+ context.setEnv(globalEnv);
93
+ context.define("sibling", rulesSibling);
94
+ context.define("parent", factsParent);
95
+ evaluator = new InterpreterVisitor(context);
96
+ engine = new LogicEngine(evaluator, context);
97
+ kernel = new YukigoKernel(evaluator, "all");
98
+ });
99
+
100
+ const unify = (
101
+ t1: LogicTerm,
102
+ t2: LogicTerm,
103
+ substs: Substitution = new Map(),
104
+ ) => {
105
+ const cmd = t1.unify(t2, substs);
106
+ const k = new YukigoKernel(evaluator, "first");
107
+ const res = k.run(cmd);
108
+ if (res instanceof YuBoolean && res.value) {
109
+ return substs;
110
+ }
111
+ return null;
112
+ };
113
+
114
+ describe("Unification Algorithm", () => {
115
+ it("should unify two identical literals", () => {
116
+ const p1 = new ConstantTerm(new YuString("cat"));
117
+ const p2 = new ConstantTerm(new YuString("cat"));
118
+ const result = unify(p1, p2);
119
+ expect(result).to.not.be.null;
120
+ });
121
+
122
+ it("should not unify different literals", () => {
123
+ const p1 = new ConstantTerm(new YuString("cat"));
124
+ const p2 = new ConstantTerm(new YuString("dog"));
125
+ const result = unify(p1, p2);
126
+ expect(result).to.be.null;
127
+ });
128
+
129
+ it("should unify a variable with a literal", () => {
130
+ const v1 = new VariableTerm(1, "X");
131
+ const p2 = new ConstantTerm(new YuString("cat"));
132
+ const result = unify(v1, p2);
133
+
134
+ expect(result).to.not.be.null;
135
+ const resolved = v1.resolve(result!);
136
+ expect(resolved).to.be.instanceOf(ConstantTerm);
137
+ expect((resolved as ConstantTerm).value.toJSON()).to.equal("cat");
138
+ });
139
+
140
+ it("should unify two variables (aliasing)", () => {
141
+ const v1 = new VariableTerm(1, "X");
142
+ const v2 = new VariableTerm(2, "Y");
143
+ const result = unify(v1, v2);
144
+ expect(result).to.not.be.null;
145
+ expect(result!.has(1)).to.be.true;
146
+ });
147
+
148
+ describe("ConsPattern Unification", () => {
149
+ it("should unify two identical ConsPatterns", () => {
150
+ const p1 = new ConsTerm(
151
+ new ConstantTerm(new YuNumber(1)),
152
+ new ListTerm([]),
153
+ );
154
+ const p2 = new ConsTerm(
155
+ new ConstantTerm(new YuNumber(1)),
156
+ new ListTerm([]),
157
+ );
158
+ const result = unify(p1, p2);
159
+ expect(result).to.not.be.null;
160
+ });
161
+
162
+ it("should unify ConsPattern with equivalent ListPattern", () => {
163
+ const cons = new ConsTerm(
164
+ new ConstantTerm(new YuNumber(1)),
165
+ new ListTerm([new ConstantTerm(new YuNumber(2))]),
166
+ );
167
+ const list = new ListTerm([
168
+ new ConstantTerm(new YuNumber(1)),
169
+ new ConstantTerm(new YuNumber(2)),
170
+ ]);
171
+ const result = unify(cons, list);
172
+ expect(result).to.not.be.null;
173
+ });
174
+
175
+ it("should unify ListPattern with equivalent ConsPattern", () => {
176
+ const list = new ListTerm([
177
+ new ConstantTerm(new YuNumber(1)),
178
+ new ConstantTerm(new YuNumber(2)),
179
+ ]);
180
+ const cons = new ConsTerm(
181
+ new ConstantTerm(new YuNumber(1)),
182
+ new ListTerm([new ConstantTerm(new YuNumber(2))]),
183
+ );
184
+ const result = unify(list, cons);
185
+ expect(result).to.not.be.null;
186
+ });
187
+
188
+ it("should fail if heads do not match", () => {
189
+ const cons = new ConsTerm(
190
+ new ConstantTerm(new YuNumber(1)),
191
+ new ListTerm([new ConstantTerm(new YuNumber(2))]),
192
+ );
193
+ const list = new ListTerm([
194
+ new ConstantTerm(new YuNumber(3)),
195
+ new ConstantTerm(new YuNumber(2)),
196
+ ]);
197
+ const result = unify(cons, list);
198
+ expect(result).to.be.null;
199
+ });
200
+
201
+ it("should fail if ListPattern is empty and ConsPattern expects head", () => {
202
+ const list = new ListTerm([]);
203
+ const cons = new ConsTerm(
204
+ new VariableTerm(1, "H"),
205
+ new VariableTerm(2, "T"),
206
+ );
207
+ const result = unify(list, cons);
208
+ expect(result).to.be.null;
209
+ });
210
+
211
+ it("should bind variables in ConsPattern", () => {
212
+ const list = new ListTerm([
213
+ new ConstantTerm(new YuNumber(1)),
214
+ new ConstantTerm(new YuNumber(2)),
215
+ ]);
216
+
217
+ const vH = new VariableTerm(1, "H");
218
+ const vT = new VariableTerm(2, "T");
219
+ const cons = new ConsTerm(vH, vT);
220
+ const result = unify(cons, list) as Substitution;
221
+ expect(result).to.not.be.null;
222
+
223
+ const h = vH.resolve(result);
224
+ expect(h).to.be.instanceOf(ConstantTerm);
225
+
226
+ const t = vT.resolve(result);
227
+ expect(t).to.be.instanceOf(ListTerm);
228
+ expect((t as ListTerm).elements).to.have.lengthOf(1);
229
+ });
230
+
231
+ it("should fail unification with occurs check (circularity)", () => {
232
+ const vX = new VariableTerm(1, "X");
233
+ const compound = new CompoundTerm("f", [vX]);
234
+ const result = unify(vX, compound);
235
+ expect(result).to.be.null;
236
+ });
237
+
238
+ it("should unify infinite LazyList with Variable lazily", () => {
239
+ const createLazyRange = (val: number): LazyList => {
240
+ return new LazyList(() => {
241
+ return new StepCommand(
242
+ new LazyStepResult(new YuNumber(val), createLazyRange(val + 1)),
243
+ );
244
+ }, `Range(${val})`);
245
+ };
246
+
247
+ const lazyList = createLazyRange(1);
248
+
249
+ evaluator.evaluate = (node: any) => {
250
+ if (
251
+ node instanceof Variable &&
252
+ node.identifier.value === "Infinite"
253
+ ) {
254
+ return new StepCommand(lazyList);
255
+ }
256
+ if (node instanceof SymbolPrimitive)
257
+ return new StepCommand(new YuString(node.value));
258
+ return new StepCommand(YuNil.getInstance());
259
+ };
260
+
261
+ const infiniteVar = new Variable(s("Infinite"), new NilPrimitive(null));
262
+ const xVar = new Variable(s("X"), new NilPrimitive(null));
263
+
264
+ const result = kernel.run(
265
+ engine.unifyExpr(xVar, infiniteVar),
266
+ ) as YuValue[];
267
+ expect(result[0].toJSON()).to.be.true;
268
+ });
269
+ });
270
+ });
271
+
272
+ describe("LogicEngine Execution", () => {
273
+ it("should solve a simple ground goal (Fact exists)", () => {
274
+ const query = makeGoal("parent", [lit("zeus"), lit("ares")]);
275
+ const results = kernel.run(engine.solveGoalLike(query)) as LogicResult[];
276
+ expect(results[0].success).to.be.true;
277
+ });
278
+
279
+ it("should fail a ground goal that does not exist", () => {
280
+ const query = makeGoal("parent", [lit("zeus"), lit("thor")]);
281
+ const results = kernel.run(engine.solveGoalLike(query)) as LogicResult[];
282
+ expect(results).to.be.empty;
283
+ });
284
+
285
+ it("should solve a goal with a variable", () => {
286
+ const goal = makeGoal("parent", [lit("zeus"), varPat("Child")]);
287
+ const query = new Query([goal]);
288
+ const results = kernel.run(engine.solveQuery(query)) as LogicResult[];
289
+
290
+ expect(results.every((res) => res.allSuccessful())).to.be.true;
291
+
292
+ const names = results.map((res) =>
293
+ (res.solutions.get("Child") as ConstantTerm).value.toJSON(),
294
+ );
295
+
296
+ expect(names).to.include("ares");
297
+ expect(names).to.include("athena");
298
+ });
299
+
300
+ it("should solve a rule using backtracking", () => {
301
+ const query = makeGoal("sibling", [lit("ares"), lit("athena")]);
302
+ const results = kernel.run(engine.solveGoalLike(query)) as LogicResult[];
303
+ expect(results[0].success).to.be.true;
304
+ });
305
+ });
306
+
307
+ it("should solve a rule using backtracking with variable", () => {
308
+ const goal = makeGoal("sibling", [lit("ares"), varPat("Child")]);
309
+ const query = new Query([goal]);
310
+ const results = kernel.run(engine.solveQuery(query)) as LogicResult[];
311
+ expect(results.every((res) => res.allSuccessful())).to.be.true;
312
+ const names = results.map((res) =>
313
+ (res.solutions.get("Child") as ConstantTerm).value.toJSON(),
314
+ );
315
+ expect(names).to.include("ares");
316
+ expect(names).to.include("athena");
317
+ });
318
+
319
+ describe("Output Modes", () => {
320
+ it('should return all results when outputMode is "all"', () => {
321
+ const goal = makeGoal("parent", [lit("zeus"), varPat("X")]);
322
+ const query = new Query([goal]);
323
+ const results = kernel.run(engine.solveQuery(query)) as LogicResult[];
324
+ expect(results[0]).to.be.instanceOf(LogicResult);
325
+ expect(results[1]).to.be.instanceOf(LogicResult);
326
+ const names = results.map((res) =>
327
+ (res.solutions.get("X") as ConstantTerm).value.toJSON(),
328
+ );
329
+ expect(names).to.include("ares");
330
+ expect(names).to.include("athena");
331
+ });
332
+ });
333
+
334
+ describe("Findall", () => {
335
+ it("should collect all solutions into a list", () => {
336
+ const findallNode = new Findall(
337
+ varPat("X"),
338
+ makeGoal("parent", [lit("zeus"), varPat("X")]),
339
+ varPat("List"),
340
+ );
341
+
342
+ const queryNode = new Query([findallNode]);
343
+ const results = kernel.run(engine.solveQuery(queryNode)) as LogicResult[];
344
+ const firstResult = results[0];
345
+ expect(firstResult.allSuccessful()).to.be.true;
346
+
347
+ const answer = firstResult.allAnswers[0];
348
+ const solution = answer.getSolution();
349
+
350
+ const list = solution.get("List") as ListTerm;
351
+ expect(list).to.not.be.undefined;
352
+
353
+ const names = list.elements.map((el) =>
354
+ (el as ConstantTerm).value.toJSON(),
355
+ );
356
+ expect(names).to.have.lengthOf(2);
357
+ expect(names).to.include("ares");
358
+ expect(names).to.include("athena");
359
+ });
360
+
361
+ describe("Expression Unification", () => {
362
+ it("should successfully unify a variable with an array expression", () => {
363
+ globalEnv.head.set("myList", new YuString("dummy"));
364
+ const X = new Variable(s("X"), new NilPrimitive(null));
365
+ const myList = new Variable(s("myList"), new NilPrimitive(null));
366
+ const result = kernel.run(engine.unifyExpr(X, myList)) as YuValue[];
367
+ expect(result[0].toJSON()).to.be.true;
368
+ });
369
+ });
370
+ });
371
+ });