eyeling 1.34.5 → 1.34.6

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 (307) hide show
  1. package/README.md +3 -90
  2. package/bin/eyeling.cjs +4 -56
  3. package/dist/browser/eyeling.browser.js +0 -1
  4. package/examples/context-schema-audit.n3 +1 -1
  5. package/eyeling.js +0 -1
  6. package/index.d.ts +3 -37
  7. package/index.js +1 -90
  8. package/lib/cli.js +0 -1
  9. package/package.json +3 -12
  10. package/test/packlist.test.js +0 -2
  11. package/test/run.js +0 -2
  12. package/docs/eyelang-guide.md +0 -535
  13. package/docs/eyelang-language-reference.md +0 -697
  14. package/examples/eyelang/access-control-policy.pl +0 -52
  15. package/examples/eyelang/ackermann.pl +0 -46
  16. package/examples/eyelang/age.pl +0 -28
  17. package/examples/eyelang/aliases-and-namespaces.pl +0 -22
  18. package/examples/eyelang/alignment-demo.pl +0 -44
  19. package/examples/eyelang/allen-interval-calculus.pl +0 -64
  20. package/examples/eyelang/ancestor.pl +0 -21
  21. package/examples/eyelang/animal.pl +0 -21
  22. package/examples/eyelang/annotation.pl +0 -34
  23. package/examples/eyelang/auroracare.pl +0 -309
  24. package/examples/eyelang/backward.pl +0 -12
  25. package/examples/eyelang/basic-monadic.pl +0 -10032
  26. package/examples/eyelang/bayes-diagnosis.pl +0 -108
  27. package/examples/eyelang/bayes-therapy.pl +0 -182
  28. package/examples/eyelang/beam-deflection.pl +0 -50
  29. package/examples/eyelang/blocks-world-planning.pl +0 -75
  30. package/examples/eyelang/bmi.pl +0 -232
  31. package/examples/eyelang/braking-safety-worlds.pl +0 -69
  32. package/examples/eyelang/buck-converter-design.pl +0 -78
  33. package/examples/eyelang/cache-performance.pl +0 -54
  34. package/examples/eyelang/canary-release.pl +0 -49
  35. package/examples/eyelang/cat-koko.pl +0 -24
  36. package/examples/eyelang/clinical-trial-screening.pl +0 -92
  37. package/examples/eyelang/combinatorics-findall-sort.pl +0 -37
  38. package/examples/eyelang/competitive-enzyme-kinetics.pl +0 -78
  39. package/examples/eyelang/complex.pl +0 -121
  40. package/examples/eyelang/composition-of-injective-functions-is-injective.pl +0 -50
  41. package/examples/eyelang/context-association.pl +0 -53
  42. package/examples/eyelang/context-schema-audit.pl +0 -46
  43. package/examples/eyelang/control-system.pl +0 -72
  44. package/examples/eyelang/cyclic-path.pl +0 -16
  45. package/examples/eyelang/d3-group.pl +0 -100
  46. package/examples/eyelang/dairy-energy-balance.pl +0 -65
  47. package/examples/eyelang/data-negotiation.pl +0 -39
  48. package/examples/eyelang/deep-taxonomy-10.pl +0 -115
  49. package/examples/eyelang/deep-taxonomy-100.pl +0 -385
  50. package/examples/eyelang/deep-taxonomy-1000.pl +0 -3085
  51. package/examples/eyelang/deep-taxonomy-10000.pl +0 -30094
  52. package/examples/eyelang/deep-taxonomy-100000.pl +0 -300184
  53. package/examples/eyelang/delfour.pl +0 -281
  54. package/examples/eyelang/deontic-logic.pl +0 -52
  55. package/examples/eyelang/derived-backward-rule.pl +0 -30
  56. package/examples/eyelang/derived-rule.pl +0 -27
  57. package/examples/eyelang/diamond-property.pl +0 -38
  58. package/examples/eyelang/dijkstra-findall-sort.pl +0 -44
  59. package/examples/eyelang/dijkstra-risk-path.pl +0 -86
  60. package/examples/eyelang/dijkstra.pl +0 -46
  61. package/examples/eyelang/dining-philosophers.pl +0 -140
  62. package/examples/eyelang/dog.pl +0 -25
  63. package/examples/eyelang/dpv-odrl-purpose-mapping.pl +0 -46
  64. package/examples/eyelang/drone-corridor-planner.pl +0 -51
  65. package/examples/eyelang/easter-computus.pl +0 -89
  66. package/examples/eyelang/electrical-rc-filter.pl +0 -36
  67. package/examples/eyelang/epidemic-policy.pl +0 -67
  68. package/examples/eyelang/equivalence-classes-overlap-implies-same-class.pl +0 -27
  69. package/examples/eyelang/eulerian-path.pl +0 -85
  70. package/examples/eyelang/ev-range-worlds.pl +0 -82
  71. package/examples/eyelang/existential-rule.pl +0 -18
  72. package/examples/eyelang/exoplanet-validation-worlds.pl +0 -88
  73. package/examples/eyelang/expression-eval.pl +0 -43
  74. package/examples/eyelang/family-cousins.pl +0 -65
  75. package/examples/eyelang/fastpow.pl +0 -53
  76. package/examples/eyelang/fft8-numeric.pl +0 -83
  77. package/examples/eyelang/fibonacci.pl +0 -53
  78. package/examples/eyelang/field-nitrogen-balance.pl +0 -70
  79. package/examples/eyelang/flandor.pl +0 -296
  80. package/examples/eyelang/floating-point.pl +0 -23
  81. package/examples/eyelang/four-color-map.pl +0 -127
  82. package/examples/eyelang/fundamental-theorem-arithmetic.pl +0 -113
  83. package/examples/eyelang/gd-step-certified.pl +0 -158
  84. package/examples/eyelang/gdpr-compliance.pl +0 -69
  85. package/examples/eyelang/good-cobbler.pl +0 -14
  86. package/examples/eyelang/gps.pl +0 -152
  87. package/examples/eyelang/graph-reachability.pl +0 -36
  88. package/examples/eyelang/gray-code-counter.pl +0 -48
  89. package/examples/eyelang/greatest-lower-bound-uniqueness.pl +0 -28
  90. package/examples/eyelang/group-inverse-uniqueness.pl +0 -34
  91. package/examples/eyelang/hamiltonian-path.pl +0 -49
  92. package/examples/eyelang/hamming-code.pl +0 -105
  93. package/examples/eyelang/hanoi.pl +0 -20
  94. package/examples/eyelang/heat-loss.pl +0 -51
  95. package/examples/eyelang/heron-theorem.pl +0 -36
  96. package/examples/eyelang/ideal-gas-law.pl +0 -37
  97. package/examples/eyelang/illegitimate-reasoning.pl +0 -88
  98. package/examples/eyelang/knowledge-engineering-alignment-flow.pl +0 -40
  99. package/examples/eyelang/law-of-cosines.pl +0 -31
  100. package/examples/eyelang/least-squares-regression.pl +0 -81
  101. package/examples/eyelang/list-collection.pl +0 -33
  102. package/examples/eyelang/lldm.pl +0 -78
  103. package/examples/eyelang/manufacturing-quality-control.pl +0 -73
  104. package/examples/eyelang/microgrid-dispatch.pl +0 -85
  105. package/examples/eyelang/monkey-bananas.pl +0 -45
  106. package/examples/eyelang/network-sla.pl +0 -48
  107. package/examples/eyelang/newton-raphson.pl +0 -49
  108. package/examples/eyelang/nixon-diamond.pl +0 -37
  109. package/examples/eyelang/observability-log-correlation.pl +0 -34
  110. package/examples/eyelang/odrl-dpv-fpv-trust-flow.pl +0 -43
  111. package/examples/eyelang/odrl-dpv-healthcare-risk-ranked.pl +0 -266
  112. package/examples/eyelang/odrl-dpv-risk-ranked.pl +0 -320
  113. package/examples/eyelang/orbital-transfer-design.pl +0 -113
  114. package/examples/eyelang/output/access-control-policy.pl +0 -2
  115. package/examples/eyelang/output/ackermann.pl +0 -12
  116. package/examples/eyelang/output/age.pl +0 -2
  117. package/examples/eyelang/output/aliases-and-namespaces.pl +0 -5
  118. package/examples/eyelang/output/alignment-demo.pl +0 -32
  119. package/examples/eyelang/output/allen-interval-calculus.pl +0 -154
  120. package/examples/eyelang/output/ancestor.pl +0 -6
  121. package/examples/eyelang/output/animal.pl +0 -4
  122. package/examples/eyelang/output/annotation.pl +0 -4
  123. package/examples/eyelang/output/auroracare.pl +0 -117
  124. package/examples/eyelang/output/backward.pl +0 -1
  125. package/examples/eyelang/output/basic-monadic.pl +0 -1518
  126. package/examples/eyelang/output/bayes-diagnosis.pl +0 -13
  127. package/examples/eyelang/output/bayes-therapy.pl +0 -23
  128. package/examples/eyelang/output/beam-deflection.pl +0 -5
  129. package/examples/eyelang/output/blocks-world-planning.pl +0 -4
  130. package/examples/eyelang/output/bmi.pl +0 -32
  131. package/examples/eyelang/output/braking-safety-worlds.pl +0 -18
  132. package/examples/eyelang/output/buck-converter-design.pl +0 -6
  133. package/examples/eyelang/output/cache-performance.pl +0 -4
  134. package/examples/eyelang/output/canary-release.pl +0 -5
  135. package/examples/eyelang/output/cat-koko.pl +0 -3
  136. package/examples/eyelang/output/clinical-trial-screening.pl +0 -9
  137. package/examples/eyelang/output/combinatorics-findall-sort.pl +0 -2
  138. package/examples/eyelang/output/competitive-enzyme-kinetics.pl +0 -6
  139. package/examples/eyelang/output/complex.pl +0 -1
  140. package/examples/eyelang/output/composition-of-injective-functions-is-injective.pl +0 -2
  141. package/examples/eyelang/output/context-association.pl +0 -3
  142. package/examples/eyelang/output/context-schema-audit.pl +0 -12
  143. package/examples/eyelang/output/control-system.pl +0 -6
  144. package/examples/eyelang/output/cyclic-path.pl +0 -16
  145. package/examples/eyelang/output/d3-group.pl +0 -2
  146. package/examples/eyelang/output/dairy-energy-balance.pl +0 -13
  147. package/examples/eyelang/output/data-negotiation.pl +0 -1
  148. package/examples/eyelang/output/deep-taxonomy-10.pl +0 -16
  149. package/examples/eyelang/output/deep-taxonomy-100.pl +0 -16
  150. package/examples/eyelang/output/deep-taxonomy-1000.pl +0 -16
  151. package/examples/eyelang/output/deep-taxonomy-10000.pl +0 -16
  152. package/examples/eyelang/output/deep-taxonomy-100000.pl +0 -16
  153. package/examples/eyelang/output/delfour.pl +0 -31
  154. package/examples/eyelang/output/deontic-logic.pl +0 -4
  155. package/examples/eyelang/output/derived-backward-rule.pl +0 -3
  156. package/examples/eyelang/output/derived-rule.pl +0 -2
  157. package/examples/eyelang/output/diamond-property.pl +0 -4
  158. package/examples/eyelang/output/dijkstra-findall-sort.pl +0 -2
  159. package/examples/eyelang/output/dijkstra-risk-path.pl +0 -29
  160. package/examples/eyelang/output/dijkstra.pl +0 -16
  161. package/examples/eyelang/output/dining-philosophers.pl +0 -350
  162. package/examples/eyelang/output/dog.pl +0 -1
  163. package/examples/eyelang/output/dpv-odrl-purpose-mapping.pl +0 -18
  164. package/examples/eyelang/output/drone-corridor-planner.pl +0 -17
  165. package/examples/eyelang/output/easter-computus.pl +0 -30
  166. package/examples/eyelang/output/electrical-rc-filter.pl +0 -3
  167. package/examples/eyelang/output/epidemic-policy.pl +0 -14
  168. package/examples/eyelang/output/equivalence-classes-overlap-implies-same-class.pl +0 -18
  169. package/examples/eyelang/output/eulerian-path.pl +0 -3
  170. package/examples/eyelang/output/ev-range-worlds.pl +0 -19
  171. package/examples/eyelang/output/existential-rule.pl +0 -2
  172. package/examples/eyelang/output/exoplanet-validation-worlds.pl +0 -22
  173. package/examples/eyelang/output/expression-eval.pl +0 -1
  174. package/examples/eyelang/output/family-cousins.pl +0 -28
  175. package/examples/eyelang/output/fastpow.pl +0 -6
  176. package/examples/eyelang/output/fft8-numeric.pl +0 -4
  177. package/examples/eyelang/output/fibonacci.pl +0 -6
  178. package/examples/eyelang/output/field-nitrogen-balance.pl +0 -21
  179. package/examples/eyelang/output/flandor.pl +0 -43
  180. package/examples/eyelang/output/floating-point.pl +0 -9
  181. package/examples/eyelang/output/four-color-map.pl +0 -3
  182. package/examples/eyelang/output/fundamental-theorem-arithmetic.pl +0 -9
  183. package/examples/eyelang/output/gd-step-certified.pl +0 -79
  184. package/examples/eyelang/output/gdpr-compliance.pl +0 -6
  185. package/examples/eyelang/output/good-cobbler.pl +0 -1
  186. package/examples/eyelang/output/gps.pl +0 -21
  187. package/examples/eyelang/output/graph-reachability.pl +0 -3
  188. package/examples/eyelang/output/gray-code-counter.pl +0 -1
  189. package/examples/eyelang/output/greatest-lower-bound-uniqueness.pl +0 -2
  190. package/examples/eyelang/output/group-inverse-uniqueness.pl +0 -2
  191. package/examples/eyelang/output/hamiltonian-path.pl +0 -121
  192. package/examples/eyelang/output/hamming-code.pl +0 -6
  193. package/examples/eyelang/output/hanoi.pl +0 -1
  194. package/examples/eyelang/output/heat-loss.pl +0 -5
  195. package/examples/eyelang/output/heron-theorem.pl +0 -4
  196. package/examples/eyelang/output/ideal-gas-law.pl +0 -3
  197. package/examples/eyelang/output/illegitimate-reasoning.pl +0 -15
  198. package/examples/eyelang/output/knowledge-engineering-alignment-flow.pl +0 -17
  199. package/examples/eyelang/output/law-of-cosines.pl +0 -3
  200. package/examples/eyelang/output/least-squares-regression.pl +0 -5
  201. package/examples/eyelang/output/list-collection.pl +0 -3
  202. package/examples/eyelang/output/lldm.pl +0 -6
  203. package/examples/eyelang/output/manufacturing-quality-control.pl +0 -6
  204. package/examples/eyelang/output/microgrid-dispatch.pl +0 -6
  205. package/examples/eyelang/output/monkey-bananas.pl +0 -5
  206. package/examples/eyelang/output/network-sla.pl +0 -4
  207. package/examples/eyelang/output/newton-raphson.pl +0 -3
  208. package/examples/eyelang/output/nixon-diamond.pl +0 -5
  209. package/examples/eyelang/output/observability-log-correlation.pl +0 -28
  210. package/examples/eyelang/output/odrl-dpv-fpv-trust-flow.pl +0 -9
  211. package/examples/eyelang/output/odrl-dpv-healthcare-risk-ranked.pl +0 -42
  212. package/examples/eyelang/output/odrl-dpv-risk-ranked.pl +0 -120
  213. package/examples/eyelang/output/orbital-transfer-design.pl +0 -7
  214. package/examples/eyelang/output/path-discovery.pl +0 -3
  215. package/examples/eyelang/output/peano-arithmetic.pl +0 -3
  216. package/examples/eyelang/output/peasant.pl +0 -10
  217. package/examples/eyelang/output/pendulum-period.pl +0 -4
  218. package/examples/eyelang/output/polynomial.pl +0 -14
  219. package/examples/eyelang/output/proof-contrapositive.pl +0 -3
  220. package/examples/eyelang/output/quadratic-formula.pl +0 -6
  221. package/examples/eyelang/output/radioactive-decay.pl +0 -5
  222. package/examples/eyelang/output/reusable-builtins.pl +0 -5
  223. package/examples/eyelang/output/riemann-hypothesis.pl +0 -12
  224. package/examples/eyelang/output/security-incident-correlation.pl +0 -3
  225. package/examples/eyelang/output/service-impact.pl +0 -11
  226. package/examples/eyelang/output/sieve.pl +0 -1
  227. package/examples/eyelang/output/skolem-functions.pl +0 -16
  228. package/examples/eyelang/output/socket-age.pl +0 -1
  229. package/examples/eyelang/output/socket-family.pl +0 -3
  230. package/examples/eyelang/output/socrates.pl +0 -2
  231. package/examples/eyelang/output/statistics-summary.pl +0 -4
  232. package/examples/eyelang/output/superdense-coding.pl +0 -6
  233. package/examples/eyelang/output/term-tools.pl +0 -6
  234. package/examples/eyelang/output/trust-flow-provenance-threshold.pl +0 -6
  235. package/examples/eyelang/output/turing.pl +0 -12
  236. package/examples/eyelang/output/vector-similarity.pl +0 -4
  237. package/examples/eyelang/output/vulnerability-impact.pl +0 -20
  238. package/examples/eyelang/output/witch.pl +0 -7
  239. package/examples/eyelang/output/wolf-goat-cabbage.pl +0 -3
  240. package/examples/eyelang/output/zebra.pl +0 -3
  241. package/examples/eyelang/path-discovery.pl +0 -45013
  242. package/examples/eyelang/peano-arithmetic.pl +0 -31
  243. package/examples/eyelang/peasant.pl +0 -30
  244. package/examples/eyelang/pendulum-period.pl +0 -50
  245. package/examples/eyelang/polynomial.pl +0 -124
  246. package/examples/eyelang/proof/age.pl +0 -71
  247. package/examples/eyelang/proof/aliases-and-namespaces.pl +0 -78
  248. package/examples/eyelang/proof/ancestor.pl +0 -140
  249. package/examples/eyelang/proof/animal.pl +0 -68
  250. package/examples/eyelang/proof/annotation.pl +0 -80
  251. package/examples/eyelang/proof/backward.pl +0 -22
  252. package/examples/eyelang/proof/cat-koko.pl +0 -86
  253. package/examples/eyelang/proof/data-negotiation.pl +0 -76
  254. package/examples/eyelang/proof/derived-rule.pl +0 -43
  255. package/examples/eyelang/proof/dog.pl +0 -31
  256. package/examples/eyelang/proof/electrical-rc-filter.pl +0 -105
  257. package/examples/eyelang/proof/existential-rule.pl +0 -40
  258. package/examples/eyelang/proof/floating-point.pl +0 -160
  259. package/examples/eyelang/proof/good-cobbler.pl +0 -16
  260. package/examples/eyelang/proof/group-inverse-uniqueness.pl +0 -84
  261. package/examples/eyelang/proof/list-collection.pl +0 -52
  262. package/examples/eyelang/proof/proof-contrapositive.pl +0 -78
  263. package/examples/eyelang/proof/socket-age.pl +0 -32
  264. package/examples/eyelang/proof/socket-family.pl +0 -59
  265. package/examples/eyelang/proof/socrates.pl +0 -38
  266. package/examples/eyelang/proof-contrapositive.pl +0 -27
  267. package/examples/eyelang/quadratic-formula.pl +0 -54
  268. package/examples/eyelang/radioactive-decay.pl +0 -56
  269. package/examples/eyelang/reusable-builtins.pl +0 -32
  270. package/examples/eyelang/riemann-hypothesis.pl +0 -110
  271. package/examples/eyelang/security-incident-correlation.pl +0 -69
  272. package/examples/eyelang/service-impact.pl +0 -41
  273. package/examples/eyelang/sieve.pl +0 -20
  274. package/examples/eyelang/skolem-functions.pl +0 -52
  275. package/examples/eyelang/socket-age.pl +0 -39
  276. package/examples/eyelang/socket-family.pl +0 -28
  277. package/examples/eyelang/socrates.pl +0 -19
  278. package/examples/eyelang/statistics-summary.pl +0 -54
  279. package/examples/eyelang/superdense-coding.pl +0 -84
  280. package/examples/eyelang/term-tools.pl +0 -23
  281. package/examples/eyelang/trust-flow-provenance-threshold.pl +0 -40
  282. package/examples/eyelang/turing.pl +0 -67
  283. package/examples/eyelang/vector-similarity.pl +0 -56
  284. package/examples/eyelang/vulnerability-impact.pl +0 -70
  285. package/examples/eyelang/witch.pl +0 -38
  286. package/examples/eyelang/wolf-goat-cabbage.pl +0 -56
  287. package/examples/eyelang/zebra.pl +0 -44
  288. package/eyelang.d.ts +0 -80
  289. package/lib/eyelang/bin.js +0 -7
  290. package/lib/eyelang/builtins/aggregation.js +0 -81
  291. package/lib/eyelang/builtins/arithmetic.js +0 -208
  292. package/lib/eyelang/builtins/context.js +0 -42
  293. package/lib/eyelang/builtins/control.js +0 -34
  294. package/lib/eyelang/builtins/core.js +0 -78
  295. package/lib/eyelang/builtins/lists.js +0 -283
  296. package/lib/eyelang/builtins/registry.js +0 -48
  297. package/lib/eyelang/builtins/strings.js +0 -234
  298. package/lib/eyelang/builtins/terms.js +0 -66
  299. package/lib/eyelang/cli.js +0 -180
  300. package/lib/eyelang/explain.js +0 -324
  301. package/lib/eyelang/hash.js +0 -294
  302. package/lib/eyelang/index.js +0 -47
  303. package/lib/eyelang/package.json +0 -3
  304. package/lib/eyelang/parser.js +0 -428
  305. package/lib/eyelang/program.js +0 -237
  306. package/lib/eyelang/solver.js +0 -237
  307. package/lib/eyelang/term.js +0 -328
@@ -1,237 +0,0 @@
1
- // Depth-first eyelang solver with builtin dispatch, memoization, and guarded recursion handling.
2
- // Most semantic decisions still flow through unification; optimizations only select candidates earlier.
3
- import { COMPOUND, Env, flattenConjunction, freshTerm, termToString, unify, variantTerms } from './term.js';
4
- import { createDefaultRegistry } from './builtins/registry.js';
5
- import { selectClauseCandidates } from './program.js';
6
-
7
- let freshCounter = 0;
8
-
9
- export function nextFreshId() {
10
- return ++freshCounter;
11
- }
12
-
13
- export class Solver {
14
- constructor(program, options = {}) {
15
- this.program = program;
16
- this.registry = options.registry ?? createDefaultRegistry();
17
- this.maxDepth = options.maxDepth ?? 100000;
18
- this.solutionLimit = options.solutionLimit ?? 10000000;
19
- this.solutionsSeen = 0;
20
- this.active = [];
21
- this.memo = new Map();
22
- this.stats = {
23
- completed_goal_lists: 0,
24
- solve_goals_calls: 0,
25
- solve_one_goal_calls: 0,
26
- unify_calls: 0,
27
- max_depth: 0,
28
- max_goal_count: 0,
29
- deterministic_builtin_successes: 0,
30
- deterministic_builtin_failures: 0,
31
- };
32
- }
33
-
34
- cloneForInnerGoal(solutionLimit = this.solutionLimit) {
35
- const solver = new Solver(this.program, { registry: this.registry, maxDepth: this.maxDepth, solutionLimit });
36
- solver.memo = this.memo;
37
- return solver;
38
- }
39
-
40
- *solve(goals, env = new Env(), depth = 0) {
41
- this.stats.solve_goals_calls++;
42
- this.stats.max_depth = Math.max(this.stats.max_depth, depth);
43
- this.stats.max_goal_count = Math.max(this.stats.max_goal_count, goals.length);
44
- if (depth > this.maxDepth || this.solutionsSeen >= this.solutionLimit) return;
45
- if (!Array.isArray(goals)) goals = [goals];
46
-
47
- if (goals.length === 0) {
48
- this.solutionsSeen++;
49
- this.stats.completed_goal_lists++;
50
- yield env;
51
- return;
52
- }
53
-
54
- // eyelang normally solves left-to-right, but ready deterministic builtins can
55
- // be run early as pure filters. This gives large pruning wins without
56
- // reordering user predicates or nondeterministic generators.
57
- const selectedIndex = selectReadyDeterministicBuiltin(goals, env, this.registry);
58
- const goal = goals[selectedIndex];
59
- const rest = selectedIndex === 0 ? goals.slice(1) : [...goals.slice(0, selectedIndex), ...goals.slice(selectedIndex + 1)];
60
- if (goal.type === COMPOUND && goal.name === ',' && goal.arity === 2) {
61
- yield* this.solve([...flattenConjunction(goal), ...rest], env, depth + 1);
62
- return;
63
- }
64
-
65
- const def = goal.type === COMPOUND ? this.registry.get(goal.name, goal.arity) : null;
66
- if (def && builtinIsReadyOrAuthoritative(def, this, goal, env)) {
67
- let produced = false;
68
- for (const next of def.handler({ solver: this, goal, env })) {
69
- produced = true;
70
- yield* this.solve(rest, next, depth + 1);
71
- if (this.solutionsSeen >= this.solutionLimit) return;
72
- }
73
- if (def.deterministic) {
74
- if (produced) this.stats.deterministic_builtin_successes++;
75
- else this.stats.deterministic_builtin_failures++;
76
- }
77
- return;
78
- }
79
-
80
- yield* this.solveUserGoal(goal, rest, env, depth);
81
- }
82
-
83
- activeVariant(goal, env) {
84
- return this.active.some((entry) => variantTerms(goal, env, entry.goal, entry.env));
85
- }
86
-
87
- *solveUserGoal(goal, rest, env, depth) {
88
- this.stats.solve_one_goal_calls++;
89
- if (depth > this.maxDepth || this.solutionsSeen >= this.solutionLimit) return;
90
- if (goal.type !== COMPOUND) return;
91
- const group = this.program.findGroup(goal.name, goal.arity);
92
- if (!group) return;
93
- if (group.memoized) {
94
- yield* this.solveMemoizedGoal(group, goal, rest, env, depth);
95
- return;
96
- }
97
- yield* this.solveUserGoalUncached(group, goal, rest, env, depth);
98
- }
99
-
100
- *solveMemoizedGoal(group, goal, rest, env, depth) {
101
- // Memoization only pays off when at least one argument is bound. A fully
102
- // open call would require storing the entire relation and can mask useful
103
- // goal-ordering behavior, so it falls back to the normal path.
104
- const key = memoKey(goal, env);
105
- if (!key.hasBound) {
106
- yield* this.solveUserGoalUncached(group, goal, rest, env, depth);
107
- return;
108
- }
109
- const mapKey = `${goal.name}/${goal.arity}:${key.text}`;
110
- let entry = this.memo.get(mapKey);
111
- if (!entry) {
112
- entry = { computing: false, complete: false, answers: [] };
113
- this.memo.set(mapKey, entry);
114
- }
115
- if (!entry.complete && !entry.computing) {
116
- entry.computing = true;
117
- const collector = this.cloneForInnerGoal();
118
- for (const answerEnv of collector.solveUserGoalUncached(group, goal, [], env.clone(), depth)) {
119
- entry.answers.push(goal.args.map((arg) => importResolved(arg, answerEnv)));
120
- }
121
- entry.computing = false;
122
- entry.complete = true;
123
- }
124
- if (!entry.complete && entry.computing) {
125
- yield* this.solveUserGoalUncached(group, goal, rest, env, depth);
126
- return;
127
- }
128
- for (const answerArgs of entry.answers) {
129
- const next = env.clone();
130
- let ok = true;
131
- for (let i = 0; i < goal.arity; i++) {
132
- this.stats.unify_calls++;
133
- if (!unify(goal.args[i], answerArgs[i], next)) { ok = false; break; }
134
- }
135
- if (ok) yield* this.solve(rest, next, depth + 1);
136
- if (this.solutionsSeen >= this.solutionLimit) return;
137
- }
138
- }
139
-
140
- *solveUserGoalUncached(group, goal, rest, env, depth) {
141
- if (this.activeVariant(goal, env)) return;
142
- // Program indexes provide candidate clauses, but every candidate is still
143
- // freshened and unified below. The index is a performance hint, not a
144
- // semantic shortcut.
145
- const candidates = selectClauseCandidates(group, goal, env);
146
- for (const pass of [candidates.primary, candidates.fallback]) {
147
- for (const clause of pass) {
148
- if (headCannotMatch(goal, clause.head, env)) continue;
149
- const id = nextFreshId();
150
- const freshHead = freshTerm(clause.head, id);
151
- const freshBody = clause.body.map((term) => freshTerm(term, id));
152
- const next = env.clone();
153
- this.stats.unify_calls++;
154
- if (!unify(goal, freshHead, next)) continue;
155
- if (freshBody.length === 0) {
156
- yield* this.solve(rest, next, depth + 1);
157
- } else {
158
- yield* this.solveRuleBodyThenRest(goal, env, freshBody, rest, next, depth);
159
- }
160
- if (this.solutionsSeen >= this.solutionLimit) return;
161
- }
162
- }
163
- }
164
- *solveRuleBodyThenRest(goal, goalEnv, body, rest, env, depth) {
165
- // Match the C engine's active-call lifetime: the active guard protects
166
- // expansion of the current rule body, but it must be released before
167
- // the caller's remaining goals are solved. Keeping the goal active
168
- // through rest goals over-prunes valid transitive/recursive derivations.
169
- this.active.push({ goal, env: goalEnv });
170
- for (const bodyEnv of this.solve(body, env, depth + 1)) {
171
- if (this.solutionsSeen > 0) this.solutionsSeen--;
172
- this.active.pop();
173
- yield* this.solve(rest, bodyEnv, depth + 1);
174
- this.active.push({ goal, env: goalEnv });
175
- if (this.solutionsSeen >= this.solutionLimit) break;
176
- }
177
- this.active.pop();
178
- }
179
-
180
- }
181
-
182
-
183
- function builtinIsReadyOrAuthoritative(def, solver, goal, env) {
184
- if (typeof def.shouldUse === 'function' && !def.shouldUse({ solver, goal, env })) return false;
185
- if (typeof def.ready !== 'function') return true;
186
- if (def.ready(goal, env)) return true;
187
- return !def.fallbackWhenNotReady;
188
- }
189
-
190
- function selectReadyDeterministicBuiltin(goals, env, registry) {
191
- for (let i = 0; i < goals.length; i++) {
192
- const goal = goals[i];
193
- if (goal.type !== COMPOUND) continue;
194
- const def = registry.get(goal.name, goal.arity);
195
- if (!def?.deterministic || typeof def.ready !== 'function') continue;
196
- if (typeof def.shouldUse === 'function') continue;
197
- if (def.ready(goal, env)) return i;
198
- }
199
- return 0;
200
- }
201
-
202
- function headCannotMatch(goal, head, env) {
203
- if (goal.type !== COMPOUND || head.type !== COMPOUND) return false;
204
- if (goal.name !== head.name || goal.arity !== head.arity) return true;
205
- for (let i = 0; i < goal.arity; i++) {
206
- const a = goal.args[i];
207
- const b = head.args[i];
208
- // Keep this only as a cheap scalar rejection. unify() remains authoritative.
209
- const da = derefForLocal(a, env);
210
- if (da.args?.length === 0 && ['atom', 'string', 'number'].includes(da.type) && ['atom', 'string', 'number'].includes(b.type) && da.name !== b.name) return true;
211
- }
212
- return false;
213
- }
214
-
215
- function derefForLocal(term, env) {
216
- let current = term;
217
- while (current.type === 'var' && env.has(current.name)) current = env.get(current.name);
218
- return current;
219
- }
220
-
221
- function memoKey(goal, env) {
222
- let hasBound = false;
223
- const parts = goal.args.map((arg) => {
224
- const value = derefForLocal(arg, env);
225
- if (value.type !== 'var') hasBound = true;
226
- return value.type === 'var' ? '_' : termToString(value, env, true);
227
- });
228
- return { hasBound, text: parts.join('|') };
229
- }
230
-
231
- function importResolved(term, env) {
232
- const { copyResolved } = termModuleCache;
233
- return copyResolved(term, env);
234
- }
235
-
236
- // Avoid circular import surprises in older Node loaders.
237
- import * as termModuleCache from './term.js';
@@ -1,328 +0,0 @@
1
- // Term model, environments, unification, readback, and ordering helpers.
2
- // This file is intentionally dependency-free because nearly every other module imports it.
3
- export const VAR = 'var';
4
- export const ATOM = 'atom';
5
- export const STRING = 'string';
6
- export const NUMBER = 'number';
7
- export const COMPOUND = 'compound';
8
-
9
- export class Term {
10
- constructor(type, name, args = []) {
11
- this.type = type;
12
- this.name = String(name ?? '');
13
- this.args = args;
14
- }
15
- get arity() {
16
- return this.args.length;
17
- }
18
- }
19
-
20
- export const variable = (name) => new Term(VAR, name);
21
- export const atom = (name) => new Term(ATOM, name);
22
- export const stringTerm = (value) => new Term(STRING, value);
23
- export const numberTerm = (value) => new Term(NUMBER, value);
24
- export const compound = (name, args = []) => new Term(COMPOUND, name, args);
25
- export const emptyList = () => atom('[]');
26
- export const cons = (head, tail) => compound('.', [head, tail]);
27
-
28
- export class Env {
29
- constructor(bindings) {
30
- this.bindings = bindings ? new Map(bindings) : new Map();
31
- }
32
- clone() {
33
- return new Env(this.bindings);
34
- }
35
- has(name) {
36
- return this.bindings.has(name);
37
- }
38
- get(name) {
39
- return this.bindings.get(name);
40
- }
41
- bind(name, term) {
42
- this.bindings.set(name, term);
43
- }
44
- }
45
-
46
- export function deref(term, env) {
47
- // Follow variable bindings until a non-variable term is reached. The seen set
48
- // protects readback from accidental cycles in partially constructed terms.
49
- let current = term;
50
- const seen = new Set();
51
- while (current?.type === VAR && env?.has(current.name)) {
52
- if (seen.has(current.name)) break;
53
- seen.add(current.name);
54
- current = env.get(current.name);
55
- }
56
- return current;
57
- }
58
-
59
- export function isScalar(term) {
60
- return term && (term.type === ATOM || term.type === STRING || term.type === NUMBER);
61
- }
62
-
63
- export function isEmptyList(term) {
64
- return term?.type === ATOM && term.name === '[]';
65
- }
66
-
67
- export function isCons(term) {
68
- return term?.type === COMPOUND && term.name === '.' && term.arity === 2;
69
- }
70
-
71
- export function isConjunction(term) {
72
- return term?.type === COMPOUND && term.name === ',' && term.arity === 2;
73
- }
74
-
75
- export function unify(left, right, env) {
76
- // Iterative unification avoids deep JavaScript recursion on long lists or
77
- // deeply nested compounds. Bindings are written into the supplied Env.
78
- const stack = [[left, right]];
79
- while (stack.length) {
80
- let [a, b] = stack.pop();
81
- a = deref(a, env);
82
- b = deref(b, env);
83
-
84
- if (a.type === VAR && b.type === VAR && a.name === b.name) continue;
85
- if (a.type === VAR) {
86
- env.bind(a.name, b);
87
- continue;
88
- }
89
- if (b.type === VAR) {
90
- env.bind(b.name, a);
91
- continue;
92
- }
93
-
94
- if (a.type !== b.type) {
95
- if (isScalar(a) && isScalar(b) && a.name === b.name) continue;
96
- return false;
97
- }
98
-
99
- if (isScalar(a)) {
100
- if (a.name !== b.name) return false;
101
- continue;
102
- }
103
-
104
- if (a.type === COMPOUND) {
105
- if (a.name !== b.name || a.arity !== b.arity) return false;
106
- for (let i = a.arity - 1; i >= 0; i--) stack.push([a.args[i], b.args[i]]);
107
- continue;
108
- }
109
-
110
- return false;
111
- }
112
- return true;
113
- }
114
-
115
- export function cloneTerm(term) {
116
- return new Term(term.type, term.name, term.args.map(cloneTerm));
117
- }
118
-
119
- export function freshTerm(term, suffix) {
120
- if (term.type === VAR) return variable(`${term.name}#${suffix}`);
121
- return new Term(term.type, term.name, term.args.map((arg) => freshTerm(arg, suffix)));
122
- }
123
-
124
- export function copyResolved(term, env) {
125
- const resolved = deref(term, env);
126
- if (resolved.type === VAR) return variable(resolved.name);
127
- return new Term(resolved.type, resolved.name, resolved.args.map((arg) => copyResolved(arg, env)));
128
- }
129
-
130
- export function termIsGround(term, env = new Env()) {
131
- const resolved = deref(term, env);
132
- if (resolved.type === VAR) return false;
133
- return resolved.args.every((arg) => termIsGround(arg, env));
134
- }
135
-
136
- const graphicAtomChars = new Set('#$&*+-/<=>?@^~\\'.split(''));
137
-
138
- function atomNeedsQuotes(name) {
139
- if (!name) return true;
140
- if (name === '[]') return false;
141
- if (/^[a-z][A-Za-z0-9_]*$/.test(name)) return false;
142
- for (const ch of name) if (!graphicAtomChars.has(ch)) return true;
143
- return false;
144
- }
145
-
146
- function quoteAtom(name) {
147
- let out = "'";
148
- for (const ch of name) {
149
- if (ch === "'") out += "''";
150
- else if (ch === '\\') out += '\\\\';
151
- else if (ch === '\n') out += '\\n';
152
- else if (ch === '\t') out += '\\t';
153
- else out += ch;
154
- }
155
- return out + "'";
156
- }
157
-
158
- function writeAtom(name) {
159
- return atomNeedsQuotes(name) ? quoteAtom(name) : name;
160
- }
161
-
162
- function writeString(value, quoteStrings) {
163
- if (!quoteStrings) return value;
164
- let out = '"';
165
- for (const ch of value) {
166
- if (ch === '"' || ch === '\\') out += `\\${ch}`;
167
- else if (ch === '\n') out += '\\n';
168
- else out += ch;
169
- }
170
- return out + '"';
171
- }
172
-
173
- function writeList(term, env) {
174
- const parts = [];
175
- let cursor = term;
176
- while (true) {
177
- cursor = deref(cursor, env);
178
- if (isEmptyList(cursor)) return `[${parts.join(', ')}]`;
179
- if (!isCons(cursor)) {
180
- if (parts.length) return `[${parts.join(', ')} | ${termToString(cursor, env, true)}]`;
181
- return `[${termToString(cursor, env, true)}]`;
182
- }
183
- parts.push(termToString(cursor.args[0], env, true));
184
- cursor = cursor.args[1];
185
- }
186
- }
187
-
188
- export function termToString(term, env = new Env(), quoteStrings = true) {
189
- const resolved = deref(term, env);
190
- if (resolved.type === VAR) return resolved.name;
191
- if (isCons(resolved)) return writeList(resolved, env);
192
- if (resolved.type === STRING) return writeString(resolved.name, quoteStrings);
193
- if (resolved.type === ATOM) return writeAtom(resolved.name);
194
- if (resolved.type === NUMBER) return resolved.name;
195
- if (isConjunction(resolved)) {
196
- const parts = [];
197
- let cursor = resolved;
198
- while (true) {
199
- cursor = deref(cursor, env);
200
- if (isConjunction(cursor)) {
201
- parts.push(termToString(cursor.args[0], env, true));
202
- cursor = cursor.args[1];
203
- } else {
204
- parts.push(termToString(cursor, env, true));
205
- break;
206
- }
207
- }
208
- return `(${parts.join(', ')})`;
209
- }
210
- return `${writeAtom(resolved.name)}(${resolved.args.map((arg) => termToString(arg, env, true)).join(', ')})`;
211
- }
212
-
213
- export function lexicalValue(term, env) {
214
- const resolved = deref(term, env);
215
- if (resolved.type === VAR) return null;
216
- if (resolved.type === ATOM || resolved.type === STRING || resolved.type === NUMBER) return resolved.name;
217
- return termToString(resolved, env, true);
218
- }
219
-
220
- export function properListItems(list, env) {
221
- const items = [];
222
- let cursor = deref(list, env);
223
- while (isCons(cursor)) {
224
- items.push(cursor.args[0]);
225
- cursor = deref(cursor.args[1], env);
226
- }
227
- if (!isEmptyList(cursor)) return null;
228
- return items;
229
- }
230
-
231
- export function listFromItems(items, start = 0, end = items.length, tail = emptyList()) {
232
- let result = tail;
233
- for (let i = end - 1; i >= start; i--) result = cons(items[i], result);
234
- return result;
235
- }
236
-
237
- export function flattenConjunction(goal) {
238
- const out = [];
239
- const stack = [goal];
240
- while (stack.length) {
241
- const current = stack.pop();
242
- if (isConjunction(current)) {
243
- stack.push(current.args[1], current.args[0]);
244
- } else {
245
- out.push(current);
246
- }
247
- }
248
- return out;
249
- }
250
-
251
- export function termSignature(term) {
252
- return term?.type === COMPOUND ? `${term.name}/${term.arity}` : null;
253
- }
254
-
255
- export function variantTerms(left, leftEnv, right, rightEnv, pairs = new Map(), reverse = new Map()) {
256
- left = deref(left, leftEnv);
257
- right = deref(right, rightEnv);
258
- if (left.type === VAR || right.type === VAR) {
259
- if (left.type !== VAR || right.type !== VAR) return false;
260
- if (pairs.has(left.name) || reverse.has(right.name)) {
261
- return pairs.get(left.name) === right.name && reverse.get(right.name) === left.name;
262
- }
263
- pairs.set(left.name, right.name);
264
- reverse.set(right.name, left.name);
265
- return true;
266
- }
267
- if (left.type !== right.type || left.name !== right.name || left.arity !== right.arity) return false;
268
- for (let i = 0; i < left.arity; i++) {
269
- if (!variantTerms(left.args[i], leftEnv, right.args[i], rightEnv, pairs, reverse)) return false;
270
- }
271
- return true;
272
- }
273
-
274
- export function compareTerms(left, right) {
275
- const rank = (term) => ({ [VAR]: 0, [NUMBER]: 1, [ATOM]: 2, [STRING]: 3, [COMPOUND]: 4 })[term.type];
276
- left = deref(left, new Env());
277
- right = deref(right, new Env());
278
- const lr = rank(left);
279
- const rr = rank(right);
280
- if (lr !== rr) return lr < rr ? -1 : 1;
281
- if (left.type === NUMBER) return compareNumberText(left.name, right.name);
282
- if (left.type === VAR || left.type === ATOM || left.type === STRING) return left.name < right.name ? -1 : left.name > right.name ? 1 : 0;
283
- if (left.name !== right.name) return left.name < right.name ? -1 : 1;
284
- if (left.arity !== right.arity) return left.arity < right.arity ? -1 : 1;
285
- for (let i = 0; i < left.arity; i++) {
286
- const cmp = compareTerms(left.args[i], right.args[i]);
287
- if (cmp) return cmp;
288
- }
289
- return 0;
290
- }
291
-
292
- export function isDecimalInteger(text) {
293
- return /^-?\d+$/.test(text ?? '');
294
- }
295
-
296
- export function compareIntegerText(left, right) {
297
- const a = BigInt(left);
298
- const b = BigInt(right);
299
- return a < b ? -1 : a > b ? 1 : 0;
300
- }
301
-
302
- export function parseFiniteNumber(text) {
303
- if (text == null || text === '') return null;
304
- if (!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(text)) return null;
305
- const n = Number(text);
306
- return Number.isFinite(n) ? n : null;
307
- }
308
-
309
- export function numberTextFromDouble(value) {
310
- if (!Number.isFinite(value)) return null;
311
- if (Object.is(value, -0)) value = 0;
312
- let text = Number(value).toPrecision(17);
313
- if (text.includes('e') || text.includes('E')) {
314
- text = text.replace(/(\.\d*?[1-9])0+(e[+-]?\d+)$/i, '$1$2').replace(/\.0+(e[+-]?\d+)$/i, '$1');
315
- } else if (text.includes('.')) {
316
- text = text.replace(/0+$/, '').replace(/\.$/, '');
317
- }
318
- if (!/[.eE]/.test(text)) text += '.0';
319
- return text;
320
- }
321
-
322
- export function compareNumberText(left, right) {
323
- if (isDecimalInteger(left) && isDecimalInteger(right)) return compareIntegerText(left, right);
324
- const a = parseFiniteNumber(left);
325
- const b = parseFiniteNumber(right);
326
- if (a != null && b != null) return a < b ? -1 : a > b ? 1 : 0;
327
- return left < right ? -1 : left > right ? 1 : 0;
328
- }