eyelang 1.6.0 → 1.7.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 (1072) hide show
  1. package/README.md +39 -602
  2. package/bin/eyelang.js +7 -0
  3. package/docs/guide.md +591 -0
  4. package/docs/language-reference.md +763 -0
  5. package/examples/access-control-policy.eye +52 -0
  6. package/examples/ackermann.eye +47 -0
  7. package/examples/age.eye +26 -0
  8. package/examples/aliases-and-namespaces.eye +20 -0
  9. package/examples/alignment-demo.eye +44 -0
  10. package/examples/allen-interval-calculus.eye +64 -0
  11. package/examples/ancestor.eye +22 -0
  12. package/examples/animal.eye +21 -0
  13. package/examples/annotation.eye +34 -0
  14. package/examples/auroracare.eye +309 -0
  15. package/examples/backward.eye +11 -0
  16. package/examples/basic-monadic.eye +10032 -0
  17. package/examples/bayes-diagnosis.eye +108 -0
  18. package/examples/bayes-therapy.eye +189 -0
  19. package/examples/beam-deflection.eye +48 -0
  20. package/examples/binomial-vandermonde.eye +49 -0
  21. package/examples/blocks-world-planning.eye +77 -0
  22. package/examples/bmi.eye +232 -0
  23. package/examples/braking-safety-worlds.eye +69 -0
  24. package/examples/buck-converter-design.eye +83 -0
  25. package/examples/cache-performance.eye +56 -0
  26. package/examples/canary-release.eye +51 -0
  27. package/examples/cat-koko.eye +24 -0
  28. package/examples/catalan-convolution.eye +37 -0
  29. package/examples/chart-parser.eye +65 -0
  30. package/examples/clinical-trial-screening.eye +97 -0
  31. package/examples/collatz-1000.eye +45 -0
  32. package/examples/combinatorics-findall-sort.eye +38 -0
  33. package/examples/competitive-enzyme-kinetics.eye +78 -0
  34. package/examples/complex.eye +133 -0
  35. package/examples/composition-of-injective-functions-is-injective.eye +50 -0
  36. package/examples/context-association.eye +53 -0
  37. package/examples/context-schema-audit.eye +46 -0
  38. package/examples/continued-fraction-sqrt2.eye +36 -0
  39. package/examples/control-system.eye +76 -0
  40. package/examples/critical-path-schedule.eye +82 -0
  41. package/examples/cyclic-path.eye +18 -0
  42. package/examples/d3-group.eye +99 -0
  43. package/examples/dairy-energy-balance.eye +66 -0
  44. package/examples/data-negotiation.eye +38 -0
  45. package/examples/deep-taxonomy-10.eye +115 -0
  46. package/examples/deep-taxonomy-100.eye +385 -0
  47. package/examples/deep-taxonomy-1000.eye +3085 -0
  48. package/examples/deep-taxonomy-10000.eye +30094 -0
  49. package/examples/deep-taxonomy-100000.eye +300184 -0
  50. package/examples/delfour.eye +281 -0
  51. package/examples/deontic-logic.eye +52 -0
  52. package/examples/derived-backward-rule.eye +30 -0
  53. package/examples/derived-rule.eye +27 -0
  54. package/examples/diamond-property.eye +38 -0
  55. package/examples/dijkstra-findall-sort.eye +43 -0
  56. package/examples/dijkstra-risk-path.eye +87 -0
  57. package/examples/dijkstra.eye +50 -0
  58. package/examples/dining-philosophers.eye +147 -0
  59. package/examples/dog.eye +25 -0
  60. package/examples/dpv-odrl-purpose-mapping.eye +48 -0
  61. package/examples/drone-corridor-planner.eye +48 -0
  62. package/examples/easter-computus.eye +88 -0
  63. package/examples/electrical-rc-filter.eye +37 -0
  64. package/examples/epidemic-policy.eye +66 -0
  65. package/examples/equivalence-classes-overlap-implies-same-class.eye +27 -0
  66. package/examples/eulerian-path.eye +87 -0
  67. package/examples/ev-range-worlds.eye +87 -0
  68. package/examples/existential-rule.eye +21 -0
  69. package/examples/exoplanet-validation-worlds.eye +94 -0
  70. package/examples/expression-eval.eye +45 -0
  71. package/examples/family-cousins.eye +67 -0
  72. package/examples/fastpow.eye +61 -0
  73. package/examples/fft8-numeric.eye +85 -0
  74. package/examples/fibonacci.eye +60 -0
  75. package/examples/field-nitrogen-balance.eye +73 -0
  76. package/examples/flandor.eye +296 -0
  77. package/examples/floating-point.eye +28 -0
  78. package/examples/four-color-map.eye +133 -0
  79. package/examples/fundamental-theorem-arithmetic.eye +119 -0
  80. package/examples/gd-step-certified.eye +162 -0
  81. package/examples/gdpr-compliance.eye +69 -0
  82. package/examples/good-cobbler.eye +16 -0
  83. package/examples/gps.eye +146 -0
  84. package/examples/graph-reachability.eye +33 -0
  85. package/examples/graph.eye +35 -0
  86. package/examples/gray-code-counter.eye +47 -0
  87. package/examples/greatest-lower-bound-uniqueness.eye +30 -0
  88. package/examples/group-inverse-uniqueness.eye +36 -0
  89. package/examples/hamiltonian-path.eye +51 -0
  90. package/examples/hamming-code.eye +109 -0
  91. package/examples/hanoi.eye +19 -0
  92. package/examples/heat-loss.eye +56 -0
  93. package/examples/heron-theorem.eye +42 -0
  94. package/examples/ideal-gas-law.eye +39 -0
  95. package/examples/illegitimate-reasoning.eye +88 -0
  96. package/examples/integer-partitions.eye +35 -0
  97. package/examples/intuitionistic-logic-kripke.eye +69 -0
  98. package/examples/job-shop-scheduling.eye +48 -0
  99. package/examples/knapsack-optimization.eye +46 -0
  100. package/examples/knowledge-engineering-alignment-flow.eye +46 -0
  101. package/examples/language.eye +25 -0
  102. package/examples/law-of-cosines.eye +37 -0
  103. package/examples/least-squares-regression.eye +85 -0
  104. package/examples/linear-logic-resources.eye +51 -0
  105. package/examples/list-collection.eye +35 -0
  106. package/examples/lldm.eye +80 -0
  107. package/examples/manufacturing-quality-control.eye +73 -0
  108. package/examples/matrix-chain-order.eye +79 -0
  109. package/examples/microgrid-dispatch.eye +89 -0
  110. package/examples/missionaries-cannibals.eye +53 -0
  111. package/examples/modal-logic-kripke.eye +45 -0
  112. package/examples/modular-exponentiation.eye +35 -0
  113. package/examples/monkey-bananas.eye +45 -0
  114. package/examples/n-queens-8.eye +35 -0
  115. package/examples/network-sla.eye +48 -0
  116. package/examples/newton-raphson.eye +48 -0
  117. package/examples/nixon-diamond.eye +37 -0
  118. package/examples/observability-log-correlation.eye +40 -0
  119. package/examples/odrl-dpv-fpv-trust-flow.eye +51 -0
  120. package/examples/odrl-dpv-healthcare-risk-ranked.eye +270 -0
  121. package/examples/odrl-dpv-risk-ranked.eye +320 -0
  122. package/examples/orbital-transfer-design.eye +116 -0
  123. package/examples/output/basic-monadic.eye +1518 -0
  124. package/examples/output/binomial-vandermonde.eye +4 -0
  125. package/examples/output/catalan-convolution.eye +4 -0
  126. package/examples/output/chart-parser.eye +6 -0
  127. package/examples/output/collatz-1000.eye +1000 -0
  128. package/examples/output/complex.eye +6 -0
  129. package/examples/output/context-schema-audit.eye +12 -0
  130. package/examples/output/continued-fraction-sqrt2.eye +4 -0
  131. package/examples/output/critical-path-schedule.eye +19 -0
  132. package/examples/output/dpv-odrl-purpose-mapping.eye +18 -0
  133. package/examples/output/graph.eye +21 -0
  134. package/examples/output/integer-partitions.eye +4 -0
  135. package/examples/output/intuitionistic-logic-kripke.eye +5 -0
  136. package/examples/output/job-shop-scheduling.eye +3 -0
  137. package/examples/output/knapsack-optimization.eye +4 -0
  138. package/examples/output/knowledge-engineering-alignment-flow.eye +17 -0
  139. package/examples/output/language.eye +6 -0
  140. package/examples/output/linear-logic-resources.eye +2 -0
  141. package/examples/output/matrix-chain-order.eye +4 -0
  142. package/examples/output/missionaries-cannibals.eye +3 -0
  143. package/examples/output/modal-logic-kripke.eye +4 -0
  144. package/examples/output/modular-exponentiation.eye +4 -0
  145. package/examples/output/n-queens-8.eye +1 -0
  146. package/examples/output/observability-log-correlation.eye +28 -0
  147. package/examples/output/odrl-dpv-fpv-trust-flow.eye +9 -0
  148. package/examples/output/path-discovery.eye +3 -0
  149. package/examples/output/pell-equation.eye +4 -0
  150. package/examples/output/reusable-builtins.eye +5 -0
  151. package/examples/output/send-more-money.eye +3 -0
  152. package/examples/output/stable-marriage.eye +2 -0
  153. package/examples/output/stirling-bell-numbers.eye +4 -0
  154. package/examples/output/sudoku-4x4.eye +2 -0
  155. package/examples/output/term-tools.eye +6 -0
  156. package/examples/output/totient-summatory.eye +4 -0
  157. package/examples/output/trust-flow-provenance-threshold.eye +6 -0
  158. package/examples/output/vulnerability-impact.eye +20 -0
  159. package/examples/output/web-names.eye +10 -0
  160. package/examples/output/weighted-interval-scheduling.eye +5 -0
  161. package/examples/path-discovery.eye +45013 -0
  162. package/examples/peano-arithmetic.eye +33 -0
  163. package/examples/peasant.eye +29 -0
  164. package/examples/pell-equation.eye +34 -0
  165. package/examples/pendulum-period.eye +50 -0
  166. package/examples/polynomial.eye +124 -0
  167. package/examples/proof/access-control-policy.eye +158 -0
  168. package/examples/proof/age.eye +71 -0
  169. package/examples/proof/aliases-and-namespaces.eye +78 -0
  170. package/examples/proof/ancestor.eye +140 -0
  171. package/examples/proof/animal.eye +68 -0
  172. package/examples/proof/annotation.eye +80 -0
  173. package/examples/proof/backward.eye +22 -0
  174. package/examples/proof/bayes-diagnosis.eye +208 -0
  175. package/examples/proof/beam-deflection.eye +227 -0
  176. package/examples/proof/cache-performance.eye +310 -0
  177. package/examples/proof/canary-release.eye +172 -0
  178. package/examples/proof/cat-koko.eye +86 -0
  179. package/examples/proof/chart-parser.eye +474 -0
  180. package/examples/proof/clinical-trial-screening.eye +389 -0
  181. package/examples/proof/composition-of-injective-functions-is-injective.eye +258 -0
  182. package/examples/proof/context-association.eye +78 -0
  183. package/examples/proof/data-negotiation.eye +76 -0
  184. package/examples/proof/deontic-logic.eye +109 -0
  185. package/examples/proof/derived-backward-rule.eye +74 -0
  186. package/examples/proof/derived-rule.eye +43 -0
  187. package/examples/proof/diamond-property.eye +307 -0
  188. package/examples/proof/dog.eye +31 -0
  189. package/examples/proof/dpv-odrl-purpose-mapping.eye +348 -0
  190. package/examples/proof/electrical-rc-filter.eye +105 -0
  191. package/examples/proof/epidemic-policy.eye +774 -0
  192. package/examples/proof/equivalence-classes-overlap-implies-same-class.eye +1098 -0
  193. package/examples/proof/existential-rule.eye +40 -0
  194. package/examples/proof/expression-eval.eye +105 -0
  195. package/examples/proof/floating-point.eye +160 -0
  196. package/examples/proof/gdpr-compliance.eye +199 -0
  197. package/examples/proof/good-cobbler.eye +16 -0
  198. package/examples/proof/graph-reachability.eye +151 -0
  199. package/examples/proof/greatest-lower-bound-uniqueness.eye +150 -0
  200. package/examples/proof/group-inverse-uniqueness.eye +84 -0
  201. package/examples/proof/hanoi.eye +185 -0
  202. package/examples/proof/heat-loss.eye +228 -0
  203. package/examples/proof/ideal-gas-law.eye +151 -0
  204. package/examples/proof/intuitionistic-logic-kripke.eye +133 -0
  205. package/examples/proof/linear-logic-resources.eye +205 -0
  206. package/examples/proof/list-collection.eye +52 -0
  207. package/examples/proof/modal-logic-kripke.eye +125 -0
  208. package/examples/proof/nixon-diamond.eye +181 -0
  209. package/examples/proof/proof-contrapositive.eye +78 -0
  210. package/examples/proof/reusable-builtins.eye +124 -0
  211. package/examples/proof/security-incident-correlation.eye +270 -0
  212. package/examples/proof/socket-age.eye +32 -0
  213. package/examples/proof/socket-family.eye +59 -0
  214. package/examples/proof/socrates.eye +38 -0
  215. package/examples/proof/term-tools.eye +95 -0
  216. package/examples/proof/witch.eye +216 -0
  217. package/examples/proof-contrapositive.eye +27 -0
  218. package/examples/quadratic-formula.eye +56 -0
  219. package/examples/radioactive-decay.eye +58 -0
  220. package/examples/reusable-builtins.eye +36 -0
  221. package/examples/riemann-hypothesis.eye +110 -0
  222. package/examples/security-incident-correlation.eye +69 -0
  223. package/examples/send-more-money.eye +71 -0
  224. package/examples/service-impact.eye +41 -0
  225. package/examples/sieve.eye +20 -0
  226. package/examples/skolem-functions.eye +52 -0
  227. package/examples/socket-age.eye +39 -0
  228. package/examples/socket-family.eye +28 -0
  229. package/examples/socrates.eye +19 -0
  230. package/examples/stable-marriage.eye +92 -0
  231. package/examples/statistics-summary.eye +56 -0
  232. package/examples/stirling-bell-numbers.eye +32 -0
  233. package/examples/sudoku-4x4.eye +54 -0
  234. package/examples/superdense-coding.eye +84 -0
  235. package/examples/term-tools.eye +32 -0
  236. package/examples/totient-summatory.eye +33 -0
  237. package/examples/trust-flow-provenance-threshold.eye +47 -0
  238. package/examples/turing.eye +69 -0
  239. package/examples/vector-similarity.eye +60 -0
  240. package/examples/vulnerability-impact.eye +69 -0
  241. package/examples/web-names.eye +83 -0
  242. package/examples/weighted-interval-scheduling.eye +81 -0
  243. package/examples/witch.eye +38 -0
  244. package/examples/wolf-goat-cabbage.eye +56 -0
  245. package/examples/zebra.eye +45 -0
  246. package/index.d.ts +230 -0
  247. package/index.js +4 -0
  248. package/package.json +23 -17
  249. package/playground.html +1065 -1201
  250. package/src/bin.js +7 -0
  251. package/src/builtins/arithmetic.js +19 -8
  252. package/src/builtins/context.js +42 -0
  253. package/src/builtins/control.js +12 -0
  254. package/src/builtins/lists.js +144 -10
  255. package/src/builtins/registry.js +3 -9
  256. package/src/builtins/strings.js +207 -14
  257. package/src/builtins/terms.js +68 -0
  258. package/src/cli.js +20 -16
  259. package/src/explain.js +1 -1
  260. package/src/hash.js +294 -0
  261. package/src/index.js +0 -1
  262. package/src/parser.js +101 -33
  263. package/src/program.js +222 -19
  264. package/src/solver.js +163 -35
  265. package/src/term.js +14 -1
  266. package/test/conformance/README.md +43 -0
  267. package/test/conformance/cases/001_fact_output.eye +4 -0
  268. package/test/conformance/cases/002_rule_recursion.eye +7 -0
  269. package/test/conformance/cases/002_rule_recursion.query +1 -0
  270. package/test/conformance/cases/003_terms_and_readback.eye +16 -0
  271. package/test/conformance/cases/003_terms_and_readback.query +1 -0
  272. package/test/conformance/cases/004_conjunction_and_parentheses.eye +5 -0
  273. package/test/conformance/cases/004_conjunction_and_parentheses.query +1 -0
  274. package/test/conformance/cases/005_list_deconstruction.eye +6 -0
  275. package/test/conformance/cases/005_list_deconstruction.query +1 -0
  276. package/test/conformance/cases/006_comma_formula_data.eye +4 -0
  277. package/test/conformance/cases/006_comma_formula_data.query +1 -0
  278. package/test/conformance/cases/007_anonymous_variables.eye +5 -0
  279. package/test/conformance/cases/007_anonymous_variables.query +1 -0
  280. package/test/conformance/cases/008_graphic_atoms.eye +6 -0
  281. package/test/conformance/cases/008_graphic_atoms.query +1 -0
  282. package/test/conformance/cases/009_comments_and_whitespace.eye +5 -0
  283. package/test/conformance/cases/009_comments_and_whitespace.query +1 -0
  284. package/test/conformance/cases/010_variable_scope_and_reuse.eye +8 -0
  285. package/test/conformance/cases/010_variable_scope_and_reuse.query +1 -0
  286. package/test/conformance/cases/011_predicate_arity.eye +6 -0
  287. package/test/conformance/cases/011_predicate_arity.query +1 -0
  288. package/test/conformance/cases/012_nested_compound_unification.eye +5 -0
  289. package/test/conformance/cases/012_nested_compound_unification.query +1 -0
  290. package/test/conformance/cases/013_multiple_clauses_order.eye +6 -0
  291. package/test/conformance/cases/013_multiple_clauses_order.query +1 -0
  292. package/test/conformance/cases/014_failure_filters_answers.eye +7 -0
  293. package/test/conformance/cases/014_failure_filters_answers.query +1 -0
  294. package/test/conformance/cases/015_improper_list_unification.eye +6 -0
  295. package/test/conformance/cases/015_improper_list_unification.query +1 -0
  296. package/test/conformance/cases/016_arity_zero_atom.eye +4 -0
  297. package/test/conformance/cases/017_three_step_recursion.eye +8 -0
  298. package/test/conformance/cases/017_three_step_recursion.query +1 -0
  299. package/test/conformance/cases/018_quoted_atom_readback.eye +6 -0
  300. package/test/conformance/cases/018_quoted_atom_readback.query +1 -0
  301. package/test/conformance/cases/019_parenthesized_three_conjuncts.eye +7 -0
  302. package/test/conformance/cases/019_parenthesized_three_conjuncts.query +1 -0
  303. package/test/conformance/cases/020_nested_list_terms.eye +5 -0
  304. package/test/conformance/cases/020_nested_list_terms.query +1 -0
  305. package/test/conformance/cases/021_repeated_variable_head.eye +7 -0
  306. package/test/conformance/cases/022_rule_head_structure.eye +5 -0
  307. package/test/conformance/cases/023_quoted_escapes_readback.eye +5 -0
  308. package/test/conformance/cases/024_numeric_literal_readback.eye +6 -0
  309. package/test/conformance/cases/025_body_parentheses_with_formula_data.eye +5 -0
  310. package/test/conformance/cases/026_question_underscore_named_variable_reuse.eye +5 -0
  311. package/test/conformance/cases/027_default_derived_output.eye +5 -0
  312. package/test/conformance/cases/028_materialize_focus.eye +5 -0
  313. package/test/conformance/cases/029_arithmetic_and_comparison.eye +11 -0
  314. package/test/conformance/cases/029_arithmetic_and_comparison.query +1 -0
  315. package/test/conformance/cases/030_strings_and_atoms.eye +4 -0
  316. package/test/conformance/cases/030_strings_and_atoms.query +1 -0
  317. package/test/conformance/cases/031_lists_aggregation_ordering.eye +10 -0
  318. package/test/conformance/cases/031_lists_aggregation_ordering.query +1 -0
  319. package/test/conformance/cases/032_holds_parts.eye +4 -0
  320. package/test/conformance/cases/033_negation_once_generators.eye +7 -0
  321. package/test/conformance/cases/033_negation_once_generators.query +1 -0
  322. package/test/conformance/cases/034_equality_and_inequality.eye +6 -0
  323. package/test/conformance/cases/034_equality_and_inequality.query +1 -0
  324. package/test/conformance/cases/035_list_relations.eye +5 -0
  325. package/test/conformance/cases/035_list_relations.query +1 -0
  326. package/test/conformance/cases/036_append_splits.eye +3 -0
  327. package/test/conformance/cases/036_append_splits.query +1 -0
  328. package/test/conformance/cases/037_matching_and_comparison.eye +7 -0
  329. package/test/conformance/cases/037_matching_and_comparison.query +1 -0
  330. package/test/conformance/cases/038_table_declaration.eye +8 -0
  331. package/test/conformance/cases/038_table_declaration.query +1 -0
  332. package/test/conformance/cases/039_numeric_functions.eye +9 -0
  333. package/test/conformance/cases/039_numeric_functions.query +1 -0
  334. package/test/conformance/cases/040_between_enumeration.eye +3 -0
  335. package/test/conformance/cases/040_between_enumeration.query +1 -0
  336. package/test/conformance/cases/041_smallest_divisor.eye +3 -0
  337. package/test/conformance/cases/041_smallest_divisor.query +1 -0
  338. package/test/conformance/cases/042_negation_filter.eye +7 -0
  339. package/test/conformance/cases/042_negation_filter.query +1 -0
  340. package/test/conformance/cases/043_once_user_predicate.eye +5 -0
  341. package/test/conformance/cases/043_once_user_predicate.query +1 -0
  342. package/test/conformance/cases/044_findall_user_goal.eye +6 -0
  343. package/test/conformance/cases/044_findall_user_goal.query +1 -0
  344. package/test/conformance/cases/045_sort_deduplicates_atoms.eye +3 -0
  345. package/test/conformance/cases/045_sort_deduplicates_atoms.query +1 -0
  346. package/test/conformance/cases/046_append_bound_prefix_suffix.eye +4 -0
  347. package/test/conformance/cases/046_append_bound_prefix_suffix.query +1 -0
  348. package/test/conformance/cases/047_nth0_index_generation.eye +3 -0
  349. package/test/conformance/cases/047_nth0_index_generation.query +1 -0
  350. package/test/conformance/cases/048_set_nth0_edges.eye +4 -0
  351. package/test/conformance/cases/048_set_nth0_edges.query +1 -0
  352. package/test/conformance/cases/049_select_duplicate_occurrences.eye +3 -0
  353. package/test/conformance/cases/049_select_duplicate_occurrences.query +1 -0
  354. package/test/conformance/cases/050_not_member_filter.eye +6 -0
  355. package/test/conformance/cases/050_not_member_filter.query +1 -0
  356. package/test/conformance/cases/051_nested_holds_parts.eye +4 -0
  357. package/test/conformance/cases/052_holds_member.eye +3 -0
  358. package/test/conformance/cases/053_materialize_excludes_source_fact.eye +6 -0
  359. package/test/conformance/cases/054_numeric_and_lexical_comparison.eye +5 -0
  360. package/test/conformance/cases/054_numeric_and_lexical_comparison.query +1 -0
  361. package/test/conformance/cases/055_string_matching_filters.eye +6 -0
  362. package/test/conformance/cases/055_string_matching_filters.query +1 -0
  363. package/test/conformance/cases/056_string_and_atom_concat.eye +3 -0
  364. package/test/conformance/cases/056_string_and_atom_concat.query +1 -0
  365. package/test/conformance/cases/057_countall_empty_and_nonempty.eye +4 -0
  366. package/test/conformance/cases/057_countall_empty_and_nonempty.query +1 -0
  367. package/test/conformance/cases/058_sumall_numeric_template.eye +5 -0
  368. package/test/conformance/cases/058_sumall_numeric_template.query +1 -0
  369. package/test/conformance/cases/059_aggregate_min_template.eye +5 -0
  370. package/test/conformance/cases/059_aggregate_min_template.query +1 -0
  371. package/test/conformance/cases/060_aggregate_max_compound_key.eye +5 -0
  372. package/test/conformance/cases/060_aggregate_max_compound_key.query +1 -0
  373. package/test/conformance/cases/061_date_difference.eye +4 -0
  374. package/test/conformance/cases/062_reusable_numeric_builtins.eye +10 -0
  375. package/test/conformance/cases/063_reusable_list_builtins.eye +11 -0
  376. package/test/conformance/cases/064_reusable_string_builtins.eye +12 -0
  377. package/test/conformance/cases/065_reusable_term_control_builtins.eye +11 -0
  378. package/test/conformance/cases/066_numeric_edges.eye +14 -0
  379. package/test/conformance/cases/067_list_edges.eye +10 -0
  380. package/test/conformance/cases/068_list_generation_order.eye +7 -0
  381. package/test/conformance/cases/069_list_summaries_and_sets.eye +9 -0
  382. package/test/conformance/cases/070_matches_named_captures.eye +13 -0
  383. package/test/conformance/cases/071_string_edges.eye +10 -0
  384. package/test/conformance/cases/072_string_conversions.eye +10 -0
  385. package/test/conformance/cases/073_term_introspection_edges.eye +11 -0
  386. package/test/conformance/cases/074_forall_edges.eye +10 -0
  387. package/test/conformance/cases/075_aggregation_edges.eye +12 -0
  388. package/test/conformance/cases/076_composed_reusable_builtins.eye +8 -0
  389. package/test/conformance/cases/077_recursive_path_with_lists.eye +10 -0
  390. package/test/conformance/cases/078_mutual_recursion_with_arithmetic.eye +7 -0
  391. package/test/conformance/cases/079_big_integer_arithmetic.eye +8 -0
  392. package/test/conformance/cases/080_rounding_modes.eye +10 -0
  393. package/test/conformance/cases/081_zero_safe_numeric_functions.eye +9 -0
  394. package/test/conformance/cases/082_comparison_semantics.eye +10 -0
  395. package/test/conformance/cases/083_between_modes_and_empty_ranges.eye +8 -0
  396. package/test/conformance/cases/084_append_and_select_composition.eye +7 -0
  397. package/test/conformance/cases/085_nth_and_update_edges.eye +8 -0
  398. package/test/conformance/cases/086_slicing_pipeline.eye +10 -0
  399. package/test/conformance/cases/087_sort_reverse_length.eye +8 -0
  400. package/test/conformance/cases/088_list_summaries_failures.eye +8 -0
  401. package/test/conformance/cases/089_string_split_join_pipeline.eye +7 -0
  402. package/test/conformance/cases/090_string_substring_replace_edges.eye +9 -0
  403. package/test/conformance/cases/091_string_case_and_trim.eye +7 -0
  404. package/test/conformance/cases/092_scalar_string_conversions.eye +9 -0
  405. package/test/conformance/cases/093_regex_named_captures_context.eye +8 -0
  406. package/test/conformance/cases/094_context_holds_enumeration.eye +7 -0
  407. package/test/conformance/cases/095_term_introspection_roundtrip.eye +8 -0
  408. package/test/conformance/cases/096_functor_scalar_edges.eye +8 -0
  409. package/test/conformance/cases/097_control_negation_once_forall.eye +13 -0
  410. package/test/conformance/cases/098_aggregation_nested_templates.eye +11 -0
  411. package/test/conformance/cases/099_materialize_multiple_arities.eye +8 -0
  412. package/test/conformance/cases/100_reusable_builtin_workflow.eye +10 -0
  413. package/test/conformance/cases/101_question_mark_variables.eye +7 -0
  414. package/test/conformance/cases/102_table_declaration.eye +11 -0
  415. package/test/conformance/cases/103_angle_iri_atoms.eye +7 -0
  416. package/test/conformance/cases/104_mode_determinism_declarations.eye +11 -0
  417. package/test/conformance/expected/003_terms_and_readback.eye +13 -0
  418. package/test/conformance/expected/016_arity_zero_atom.eye +1 -0
  419. package/test/conformance/expected/029_arithmetic_and_comparison.eye +9 -0
  420. package/test/conformance/expected/030_strings_and_atoms.eye +2 -0
  421. package/test/conformance/expected/032_holds_parts.eye +3 -0
  422. package/test/conformance/expected/035_list_relations.eye +4 -0
  423. package/test/conformance/expected/051_nested_holds_parts.eye +3 -0
  424. package/test/conformance/expected/052_holds_member.eye +2 -0
  425. package/test/conformance/expected/056_string_and_atom_concat.eye +1 -0
  426. package/test/conformance/expected/062_reusable_numeric_builtins.eye +8 -0
  427. package/test/conformance/expected/063_reusable_list_builtins.eye +9 -0
  428. package/test/conformance/expected/064_reusable_string_builtins.eye +10 -0
  429. package/test/conformance/expected/065_reusable_term_control_builtins.eye +6 -0
  430. package/test/conformance/expected/066_numeric_edges.eye +12 -0
  431. package/test/conformance/expected/067_list_edges.eye +8 -0
  432. package/test/conformance/expected/068_list_generation_order.eye +10 -0
  433. package/test/conformance/expected/069_list_summaries_and_sets.eye +7 -0
  434. package/test/conformance/expected/070_matches_named_captures.eye +1 -0
  435. package/test/conformance/expected/071_string_edges.eye +8 -0
  436. package/test/conformance/expected/072_string_conversions.eye +8 -0
  437. package/test/conformance/expected/073_term_introspection_edges.eye +9 -0
  438. package/test/conformance/expected/074_forall_edges.eye +5 -0
  439. package/test/conformance/expected/075_aggregation_edges.eye +7 -0
  440. package/test/conformance/expected/076_composed_reusable_builtins.eye +5 -0
  441. package/test/conformance/expected/077_recursive_path_with_lists.eye +3 -0
  442. package/test/conformance/expected/078_mutual_recursion_with_arithmetic.eye +7 -0
  443. package/test/conformance/expected/079_big_integer_arithmetic.eye +6 -0
  444. package/test/conformance/expected/080_rounding_modes.eye +8 -0
  445. package/test/conformance/expected/081_zero_safe_numeric_functions.eye +7 -0
  446. package/test/conformance/expected/082_comparison_semantics.eye +8 -0
  447. package/test/conformance/expected/083_between_modes_and_empty_ranges.eye +8 -0
  448. package/test/conformance/expected/084_append_and_select_composition.eye +10 -0
  449. package/test/conformance/expected/085_nth_and_update_edges.eye +8 -0
  450. package/test/conformance/expected/086_slicing_pipeline.eye +7 -0
  451. package/test/conformance/expected/087_sort_reverse_length.eye +6 -0
  452. package/test/conformance/expected/088_list_summaries_failures.eye +6 -0
  453. package/test/conformance/expected/089_string_split_join_pipeline.eye +4 -0
  454. package/test/conformance/expected/090_string_substring_replace_edges.eye +7 -0
  455. package/test/conformance/expected/091_string_case_and_trim.eye +5 -0
  456. package/test/conformance/expected/092_scalar_string_conversions.eye +7 -0
  457. package/test/conformance/expected/093_regex_named_captures_context.eye +5 -0
  458. package/test/conformance/expected/094_context_holds_enumeration.eye +8 -0
  459. package/test/conformance/expected/095_term_introspection_roundtrip.eye +6 -0
  460. package/test/conformance/expected/096_functor_scalar_edges.eye +6 -0
  461. package/test/conformance/expected/097_control_negation_once_forall.eye +5 -0
  462. package/test/conformance/expected/098_aggregation_nested_templates.eye +5 -0
  463. package/test/conformance/expected/099_materialize_multiple_arities.eye +4 -0
  464. package/test/conformance/expected/100_reusable_builtin_workflow.eye +6 -0
  465. package/test/conformance/expected/101_question_mark_variables.eye +3 -0
  466. package/test/conformance/expected/102_table_declaration.eye +6 -0
  467. package/test/conformance/expected/103_angle_iri_atoms.eye +3 -0
  468. package/test/conformance/expected/104_mode_determinism_declarations.eye +4 -0
  469. package/test/run-all.mjs +20 -0
  470. package/test/run-conformance.mjs +78 -0
  471. package/test/run-examples.mjs +155 -0
  472. package/test/run-regression.mjs +1215 -0
  473. package/test/test-style.mjs +94 -0
  474. package/SPEC.md +0 -684
  475. package/bin/eyelang +0 -7
  476. package/conformance/README.md +0 -45
  477. package/conformance/cases/core/001_fact_output.pl +0 -4
  478. package/conformance/cases/core/001_fact_query.query +0 -1
  479. package/conformance/cases/core/002_rule_recursion.pl +0 -7
  480. package/conformance/cases/core/002_rule_recursion.query +0 -1
  481. package/conformance/cases/core/003_terms_and_readback.pl +0 -16
  482. package/conformance/cases/core/003_terms_and_readback.query +0 -1
  483. package/conformance/cases/core/004_conjunction_and_parentheses.pl +0 -5
  484. package/conformance/cases/core/004_conjunction_and_parentheses.query +0 -1
  485. package/conformance/cases/core/005_list_deconstruction.pl +0 -6
  486. package/conformance/cases/core/005_list_deconstruction.query +0 -1
  487. package/conformance/cases/core/006_comma_formula_data.pl +0 -4
  488. package/conformance/cases/core/006_comma_formula_data.query +0 -1
  489. package/conformance/cases/core/007_anonymous_variables.pl +0 -5
  490. package/conformance/cases/core/007_anonymous_variables.query +0 -1
  491. package/conformance/cases/core/008_graphic_atoms.pl +0 -6
  492. package/conformance/cases/core/008_graphic_atoms.query +0 -1
  493. package/conformance/cases/core/009_comments_and_whitespace.pl +0 -5
  494. package/conformance/cases/core/009_comments_and_whitespace.query +0 -1
  495. package/conformance/cases/core/010_variable_scope_and_reuse.pl +0 -8
  496. package/conformance/cases/core/010_variable_scope_and_reuse.query +0 -1
  497. package/conformance/cases/core/011_predicate_arity.pl +0 -6
  498. package/conformance/cases/core/011_predicate_arity.query +0 -1
  499. package/conformance/cases/core/012_nested_compound_unification.pl +0 -5
  500. package/conformance/cases/core/012_nested_compound_unification.query +0 -1
  501. package/conformance/cases/core/013_multiple_clauses_order.pl +0 -6
  502. package/conformance/cases/core/013_multiple_clauses_order.query +0 -1
  503. package/conformance/cases/core/014_failure_filters_answers.pl +0 -7
  504. package/conformance/cases/core/014_failure_filters_answers.query +0 -1
  505. package/conformance/cases/core/015_improper_list_unification.pl +0 -6
  506. package/conformance/cases/core/015_improper_list_unification.query +0 -1
  507. package/conformance/cases/core/016_zero_arity_compound.pl +0 -4
  508. package/conformance/cases/core/016_zero_arity_compound.query +0 -1
  509. package/conformance/cases/core/017_three_step_recursion.pl +0 -8
  510. package/conformance/cases/core/017_three_step_recursion.query +0 -1
  511. package/conformance/cases/core/018_quoted_atom_readback.pl +0 -6
  512. package/conformance/cases/core/018_quoted_atom_readback.query +0 -1
  513. package/conformance/cases/core/019_parenthesized_three_conjuncts.pl +0 -7
  514. package/conformance/cases/core/019_parenthesized_three_conjuncts.query +0 -1
  515. package/conformance/cases/core/020_nested_list_terms.pl +0 -5
  516. package/conformance/cases/core/020_nested_list_terms.query +0 -1
  517. package/conformance/cases/core/021_repeated_variable_head.pl +0 -7
  518. package/conformance/cases/core/022_rule_head_structure.pl +0 -5
  519. package/conformance/cases/core/023_quoted_escapes_readback.pl +0 -5
  520. package/conformance/cases/core/024_numeric_literal_readback.pl +0 -6
  521. package/conformance/cases/core/025_body_parentheses_with_formula_data.pl +0 -5
  522. package/conformance/cases/core/026_underscore_named_variable_reuse.pl +0 -5
  523. package/conformance/cases/extension/001_default_derived_output.pl +0 -5
  524. package/conformance/cases/extension/002_materialize_focus.pl +0 -5
  525. package/conformance/cases/extension/003_arithmetic_and_comparison.pl +0 -12
  526. package/conformance/cases/extension/003_arithmetic_and_comparison.query +0 -1
  527. package/conformance/cases/extension/004_strings_and_atoms.pl +0 -6
  528. package/conformance/cases/extension/004_strings_and_atoms.query +0 -1
  529. package/conformance/cases/extension/005_lists_aggregation_ordering.pl +0 -10
  530. package/conformance/cases/extension/005_lists_aggregation_ordering.query +0 -1
  531. package/conformance/cases/extension/006_formula_terms.pl +0 -5
  532. package/conformance/cases/extension/006_formula_terms.query +0 -1
  533. package/conformance/cases/extension/007_negation_once_generators.pl +0 -7
  534. package/conformance/cases/extension/007_negation_once_generators.query +0 -1
  535. package/conformance/cases/extension/008_equality_and_inequality.pl +0 -6
  536. package/conformance/cases/extension/008_equality_and_inequality.query +0 -1
  537. package/conformance/cases/extension/009_list_relations.pl +0 -6
  538. package/conformance/cases/extension/009_list_relations.query +0 -1
  539. package/conformance/cases/extension/010_append_splits.pl +0 -3
  540. package/conformance/cases/extension/010_append_splits.query +0 -1
  541. package/conformance/cases/extension/011_matching_and_comparison.pl +0 -7
  542. package/conformance/cases/extension/011_matching_and_comparison.query +0 -1
  543. package/conformance/cases/extension/012_memoize_declaration.pl +0 -8
  544. package/conformance/cases/extension/012_memoize_declaration.query +0 -1
  545. package/conformance/cases/extension/013_numeric_functions.pl +0 -9
  546. package/conformance/cases/extension/013_numeric_functions.query +0 -1
  547. package/conformance/cases/extension/014_between_enumeration.pl +0 -3
  548. package/conformance/cases/extension/014_between_enumeration.query +0 -1
  549. package/conformance/cases/extension/015_smallest_divisor.pl +0 -3
  550. package/conformance/cases/extension/015_smallest_divisor.query +0 -1
  551. package/conformance/cases/extension/016_negation_filter.pl +0 -7
  552. package/conformance/cases/extension/016_negation_filter.query +0 -1
  553. package/conformance/cases/extension/017_once_user_predicate.pl +0 -5
  554. package/conformance/cases/extension/017_once_user_predicate.query +0 -1
  555. package/conformance/cases/extension/018_findall_user_goal.pl +0 -6
  556. package/conformance/cases/extension/018_findall_user_goal.query +0 -1
  557. package/conformance/cases/extension/019_sort_deduplicates_atoms.pl +0 -3
  558. package/conformance/cases/extension/019_sort_deduplicates_atoms.query +0 -1
  559. package/conformance/cases/extension/020_append_bound_prefix_suffix.pl +0 -4
  560. package/conformance/cases/extension/020_append_bound_prefix_suffix.query +0 -1
  561. package/conformance/cases/extension/021_nth0_index_generation.pl +0 -3
  562. package/conformance/cases/extension/021_nth0_index_generation.query +0 -1
  563. package/conformance/cases/extension/022_set_nth0_edges.pl +0 -4
  564. package/conformance/cases/extension/022_set_nth0_edges.query +0 -1
  565. package/conformance/cases/extension/023_select_duplicate_occurrences.pl +0 -3
  566. package/conformance/cases/extension/023_select_duplicate_occurrences.query +0 -1
  567. package/conformance/cases/extension/024_not_member_filter.pl +0 -6
  568. package/conformance/cases/extension/024_not_member_filter.query +0 -1
  569. package/conformance/cases/extension/025_is_list_filter.pl +0 -5
  570. package/conformance/cases/extension/025_is_list_filter.query +0 -1
  571. package/conformance/cases/extension/026_nested_formula_terms.pl +0 -5
  572. package/conformance/cases/extension/026_nested_formula_terms.query +0 -1
  573. package/conformance/cases/extension/027_materialize_excludes_source_fact.pl +0 -6
  574. package/conformance/cases/extension/028_numeric_and_lexical_comparison.pl +0 -5
  575. package/conformance/cases/extension/028_numeric_and_lexical_comparison.query +0 -1
  576. package/conformance/cases/extension/029_string_matching_filters.pl +0 -6
  577. package/conformance/cases/extension/029_string_matching_filters.query +0 -1
  578. package/conformance/cases/extension/030_string_and_atom_concat.pl +0 -4
  579. package/conformance/cases/extension/030_string_and_atom_concat.query +0 -1
  580. package/conformance/cases/extension/031_countall_empty_and_nonempty.pl +0 -4
  581. package/conformance/cases/extension/031_countall_empty_and_nonempty.query +0 -1
  582. package/conformance/cases/extension/032_sumall_numeric_template.pl +0 -5
  583. package/conformance/cases/extension/032_sumall_numeric_template.query +0 -1
  584. package/conformance/cases/extension/033_aggregate_min_template.pl +0 -5
  585. package/conformance/cases/extension/033_aggregate_min_template.query +0 -1
  586. package/conformance/cases/extension/034_aggregate_max_compound_key.pl +0 -5
  587. package/conformance/cases/extension/034_aggregate_max_compound_key.query +0 -1
  588. package/conformance/cases/extension/035_date_difference.pl +0 -4
  589. package/conformance/cases/extension/036_extended_gcd.pl +0 -3
  590. package/conformance/cases/extension/037_collatz_trajectory.pl +0 -3
  591. package/conformance/cases/extension/038_kaprekar_steps.pl +0 -3
  592. package/conformance/cases/extension/039_goldbach_pair.pl +0 -3
  593. package/conformance/cases/extension/040_matrix_operations.pl +0 -5
  594. package/conformance/cases/extension/041_atom_range_generators.pl +0 -5
  595. package/conformance/cases/extension/042_n_queens_small.pl +0 -3
  596. package/conformance/cases/extension/043_cnf_model.pl +0 -3
  597. package/conformance/cases/extension/044_cover9_filter.pl +0 -6
  598. package/conformance/cases/extension/045_alphametic_sum_small.pl +0 -3
  599. package/conformance/cases/extension/046_bounded_subset.pl +0 -4
  600. package/conformance/expected/core/003_terms_and_readback.out +0 -13
  601. package/conformance/expected/core/016_zero_arity_compound.out +0 -1
  602. package/conformance/expected/extension/003_arithmetic_and_comparison.out +0 -10
  603. package/conformance/expected/extension/004_strings_and_atoms.out +0 -4
  604. package/conformance/expected/extension/006_formula_terms.out +0 -4
  605. package/conformance/expected/extension/009_list_relations.out +0 -5
  606. package/conformance/expected/extension/025_is_list_filter.out +0 -1
  607. package/conformance/expected/extension/026_nested_formula_terms.out +0 -6
  608. package/conformance/expected/extension/030_string_and_atom_concat.out +0 -2
  609. package/conformance/expected/extension/036_extended_gcd.out +0 -1
  610. package/conformance/expected/extension/037_collatz_trajectory.out +0 -1
  611. package/conformance/expected/extension/038_kaprekar_steps.out +0 -1
  612. package/conformance/expected/extension/039_goldbach_pair.out +0 -2
  613. package/conformance/expected/extension/040_matrix_operations.out +0 -3
  614. package/conformance/expected/extension/041_atom_range_generators.out +0 -8
  615. package/conformance/expected/extension/042_n_queens_small.out +0 -2
  616. package/conformance/expected/extension/043_cnf_model.out +0 -1
  617. package/conformance/expected/extension/044_cover9_filter.out +0 -2
  618. package/conformance/expected/extension/045_alphametic_sum_small.out +0 -4
  619. package/conformance/expected/extension/046_bounded_subset.out +0 -5
  620. package/examples/access-control-policy.pl +0 -52
  621. package/examples/ackermann.pl +0 -46
  622. package/examples/age.pl +0 -28
  623. package/examples/aliases-and-namespaces.pl +0 -22
  624. package/examples/alignment-demo.pl +0 -44
  625. package/examples/allen-interval-calculus.pl +0 -64
  626. package/examples/ancestor.pl +0 -21
  627. package/examples/animal.pl +0 -21
  628. package/examples/annotation-rdf12.ttl +0 -12
  629. package/examples/annotation.pl +0 -34
  630. package/examples/auroracare.pl +0 -309
  631. package/examples/backward.pl +0 -12
  632. package/examples/basic-monadic.pl +0 -10018
  633. package/examples/bayes-diagnosis.pl +0 -108
  634. package/examples/bayes-therapy.pl +0 -182
  635. package/examples/beam-deflection.pl +0 -50
  636. package/examples/blocks-world-planning.pl +0 -75
  637. package/examples/bmi.pl +0 -232
  638. package/examples/braking-safety-worlds.pl +0 -69
  639. package/examples/buck-converter-design.pl +0 -78
  640. package/examples/cache-performance.pl +0 -54
  641. package/examples/canary-release.pl +0 -49
  642. package/examples/cat-koko.pl +0 -24
  643. package/examples/clinical-trial-screening.pl +0 -92
  644. package/examples/collatz-1000.pl +0 -14
  645. package/examples/combinatorics-findall-sort.pl +0 -37
  646. package/examples/competitive-enzyme-kinetics.pl +0 -78
  647. package/examples/complex-matrix-stability.pl +0 -45
  648. package/examples/complex.pl +0 -121
  649. package/examples/composition-of-injective-functions-is-injective.pl +0 -50
  650. package/examples/context-association.pl +0 -53
  651. package/examples/control-system.pl +0 -72
  652. package/examples/cryptarithmetic-send-more-money.pl +0 -49
  653. package/examples/cyclic-path.pl +0 -16
  654. package/examples/d3-group.pl +0 -100
  655. package/examples/dairy-energy-balance.pl +0 -65
  656. package/examples/data-negotiation.pl +0 -39
  657. package/examples/deep-taxonomy-10.pl +0 -115
  658. package/examples/deep-taxonomy-100.pl +0 -385
  659. package/examples/deep-taxonomy-1000.pl +0 -3085
  660. package/examples/deep-taxonomy-10000.pl +0 -30094
  661. package/examples/deep-taxonomy-100000.pl +0 -300184
  662. package/examples/delfour.pl +0 -281
  663. package/examples/dense-hamiltonian-cycle.pl +0 -92
  664. package/examples/deontic-logic.pl +0 -52
  665. package/examples/derived-backward-rule.pl +0 -30
  666. package/examples/derived-rule.pl +0 -27
  667. package/examples/diamond-property.pl +0 -38
  668. package/examples/dijkstra-findall-sort.pl +0 -44
  669. package/examples/dijkstra-risk-path.pl +0 -86
  670. package/examples/dijkstra.pl +0 -46
  671. package/examples/dining-philosophers.pl +0 -140
  672. package/examples/directional-language.ttl +0 -9
  673. package/examples/dog.pl +0 -25
  674. package/examples/drone-corridor-planner.pl +0 -51
  675. package/examples/easter-computus.pl +0 -89
  676. package/examples/electrical-rc-filter.pl +0 -36
  677. package/examples/epidemic-policy.pl +0 -67
  678. package/examples/equivalence-classes-overlap-implies-same-class.pl +0 -27
  679. package/examples/eulerian-path.pl +0 -85
  680. package/examples/ev-range-worlds.pl +0 -82
  681. package/examples/exact-cover-sudoku.pl +0 -113
  682. package/examples/existential-rule.pl +0 -18
  683. package/examples/exoplanet-validation-worlds.pl +0 -88
  684. package/examples/expression-eval.pl +0 -43
  685. package/examples/eyeling-ackermann.n3 +0 -41
  686. package/examples/eyeling-age-threshold.n3 +0 -12
  687. package/examples/eyeling-alignment-demo.n3 +0 -11
  688. package/examples/eyeling-allen-interval-calculus-small.n3 +0 -13
  689. package/examples/eyeling-backward-recursion.n3 +0 -11
  690. package/examples/eyeling-backward.n3 +0 -10
  691. package/examples/eyeling-basic-monadic-small.n3 +0 -11
  692. package/examples/eyeling-bmi.n3 +0 -10
  693. package/examples/eyeling-cat-koko.n3 +0 -15
  694. package/examples/eyeling-collatz-small.n3 +0 -11
  695. package/examples/eyeling-collection.n3 +0 -11
  696. package/examples/eyeling-complex-arithmetic.n3 +0 -10
  697. package/examples/eyeling-context-association.n3 +0 -11
  698. package/examples/eyeling-control-system-small.n3 +0 -11
  699. package/examples/eyeling-crypto-builtins-extra.n3 +0 -10
  700. package/examples/eyeling-crypto-builtins.n3 +0 -8
  701. package/examples/eyeling-deep-taxonomy-10.n3 +0 -18
  702. package/examples/eyeling-derived-backward-rule-flat.n3 +0 -10
  703. package/examples/eyeling-derived-rule-flat.n3 +0 -9
  704. package/examples/eyeling-digital-product-passport-small.n3 +0 -11
  705. package/examples/eyeling-dijkstra-tiny.n3 +0 -14
  706. package/examples/eyeling-dog-license.n3 +0 -13
  707. package/examples/eyeling-drone-corridor-planner-small.n3 +0 -13
  708. package/examples/eyeling-equals.n3 +0 -8
  709. package/examples/eyeling-equivalence-classes.n3 +0 -11
  710. package/examples/eyeling-euler-identity.n3 +0 -9
  711. package/examples/eyeling-existential-rule.n3 +0 -9
  712. package/examples/eyeling-expression-eval.n3 +0 -11
  713. package/examples/eyeling-family-cousins-extended.n3 +0 -12
  714. package/examples/eyeling-fastpow.n3 +0 -10
  715. package/examples/eyeling-fibonacci.n3 +0 -44
  716. package/examples/eyeling-french-cities-reachability.n3 +0 -22
  717. package/examples/eyeling-goldbach-small.n3 +0 -22
  718. package/examples/eyeling-good-cobbler.n3 +0 -9
  719. package/examples/eyeling-list-builtins.n3 +0 -10
  720. package/examples/eyeling-list-collection-extra.n3 +0 -9
  721. package/examples/eyeling-math-builtins.n3 +0 -9
  722. package/examples/eyeling-string-builtins-extra.n3 +0 -9
  723. package/examples/eyeling-string-builtins.n3 +0 -10
  724. package/examples/eyeling-time-builtins.n3 +0 -11
  725. package/examples/eyeling-time-components-extra.n3 +0 -10
  726. package/examples/eyeling-witch.n3 +0 -10
  727. package/examples/family-cousins.n3 +0 -17
  728. package/examples/family-cousins.pl +0 -65
  729. package/examples/fastpow.pl +0 -53
  730. package/examples/fft8-numeric.pl +0 -83
  731. package/examples/fibonacci.pl +0 -53
  732. package/examples/field-nitrogen-balance.pl +0 -70
  733. package/examples/flandor.pl +0 -296
  734. package/examples/floating-point.pl +0 -23
  735. package/examples/four-color-map.pl +0 -127
  736. package/examples/fundamental-theorem-arithmetic.pl +0 -113
  737. package/examples/gcd-bezout-identity.pl +0 -48
  738. package/examples/gd-step-certified.pl +0 -158
  739. package/examples/gdpr-compliance.pl +0 -69
  740. package/examples/goldbach-1000.pl +0 -185
  741. package/examples/good-cobbler.pl +0 -14
  742. package/examples/gps.pl +0 -152
  743. package/examples/graph-reachability.pl +0 -36
  744. package/examples/gray-code-counter.pl +0 -48
  745. package/examples/greatest-lower-bound-uniqueness.pl +0 -28
  746. package/examples/group-inverse-uniqueness.pl +0 -34
  747. package/examples/hamiltonian-cycle.pl +0 -55
  748. package/examples/hamiltonian-path.pl +0 -49
  749. package/examples/hamming-code.pl +0 -105
  750. package/examples/hanoi.pl +0 -20
  751. package/examples/heat-loss.pl +0 -51
  752. package/examples/heron-theorem.pl +0 -36
  753. package/examples/ideal-gas-law.pl +0 -37
  754. package/examples/illegitimate-reasoning.pl +0 -88
  755. package/examples/kaprekar.pl +0 -32
  756. package/examples/law-of-cosines.pl +0 -31
  757. package/examples/least-squares-regression.pl +0 -81
  758. package/examples/list-collection.pl +0 -33
  759. package/examples/lldm.pl +0 -78
  760. package/examples/manufacturing-quality-control.pl +0 -73
  761. package/examples/matrix.pl +0 -296
  762. package/examples/microgrid-dispatch.pl +0 -85
  763. package/examples/monkey-bananas.pl +0 -45
  764. package/examples/n-queens.pl +0 -23
  765. package/examples/n3-builtins.n3 +0 -28
  766. package/examples/network-sla.pl +0 -48
  767. package/examples/newton-raphson.pl +0 -49
  768. package/examples/nixon-diamond.pl +0 -37
  769. package/examples/odrl-dpv-healthcare-risk-ranked.pl +0 -266
  770. package/examples/odrl-dpv-risk-ranked.pl +0 -320
  771. package/examples/orbital-transfer-design.pl +0 -113
  772. package/examples/output/annotation-rdf12.ttl +0 -1
  773. package/examples/output/basic-monadic.pl +0 -1518
  774. package/examples/output/collatz-1000.pl +0 -1000
  775. package/examples/output/complex-matrix-stability.pl +0 -5
  776. package/examples/output/complex.pl +0 -1
  777. package/examples/output/cryptarithmetic-send-more-money.pl +0 -6
  778. package/examples/output/dense-hamiltonian-cycle.pl +0 -4
  779. package/examples/output/directional-language.ttl +0 -1
  780. package/examples/output/exact-cover-sudoku.pl +0 -3
  781. package/examples/output/eyeling-ackermann.n3 +0 -12
  782. package/examples/output/eyeling-age-threshold.n3 +0 -4
  783. package/examples/output/eyeling-alignment-demo.n3 +0 -1
  784. package/examples/output/eyeling-allen-interval-calculus-small.n3 +0 -3
  785. package/examples/output/eyeling-backward-recursion.n3 +0 -9
  786. package/examples/output/eyeling-backward.n3 +0 -1
  787. package/examples/output/eyeling-basic-monadic-small.n3 +0 -8
  788. package/examples/output/eyeling-bmi.n3 +0 -2
  789. package/examples/output/eyeling-cat-koko.n3 +0 -3
  790. package/examples/output/eyeling-collatz-small.n3 +0 -3
  791. package/examples/output/eyeling-collection.n3 +0 -1
  792. package/examples/output/eyeling-complex-arithmetic.n3 +0 -5
  793. package/examples/output/eyeling-context-association.n3 +0 -4
  794. package/examples/output/eyeling-control-system-small.n3 +0 -4
  795. package/examples/output/eyeling-crypto-builtins-extra.n3 +0 -3
  796. package/examples/output/eyeling-crypto-builtins.n3 +0 -2
  797. package/examples/output/eyeling-deep-taxonomy-10.n3 +0 -32
  798. package/examples/output/eyeling-derived-backward-rule-flat.n3 +0 -4
  799. package/examples/output/eyeling-derived-rule-flat.n3 +0 -2
  800. package/examples/output/eyeling-digital-product-passport-small.n3 +0 -3
  801. package/examples/output/eyeling-dijkstra-tiny.n3 +0 -9
  802. package/examples/output/eyeling-dog-license.n3 +0 -1
  803. package/examples/output/eyeling-drone-corridor-planner-small.n3 +0 -5
  804. package/examples/output/eyeling-equals.n3 +0 -1
  805. package/examples/output/eyeling-equivalence-classes.n3 +0 -2
  806. package/examples/output/eyeling-euler-identity.n3 +0 -3
  807. package/examples/output/eyeling-existential-rule.n3 +0 -4
  808. package/examples/output/eyeling-expression-eval.n3 +0 -3
  809. package/examples/output/eyeling-family-cousins-extended.n3 +0 -6
  810. package/examples/output/eyeling-fastpow.n3 +0 -4
  811. package/examples/output/eyeling-fibonacci.n3 +0 -6
  812. package/examples/output/eyeling-french-cities-reachability.n3 +0 -25
  813. package/examples/output/eyeling-goldbach-small.n3 +0 -2
  814. package/examples/output/eyeling-good-cobbler.n3 +0 -2
  815. package/examples/output/eyeling-list-builtins.n3 +0 -6
  816. package/examples/output/eyeling-list-collection-extra.n3 +0 -5
  817. package/examples/output/eyeling-math-builtins.n3 +0 -5
  818. package/examples/output/eyeling-string-builtins-extra.n3 +0 -3
  819. package/examples/output/eyeling-string-builtins.n3 +0 -4
  820. package/examples/output/eyeling-time-builtins.n3 +0 -4
  821. package/examples/output/eyeling-time-components-extra.n3 +0 -5
  822. package/examples/output/eyeling-witch.n3 +0 -2
  823. package/examples/output/family-cousins.n3 +0 -8
  824. package/examples/output/gcd-bezout-identity.pl +0 -36
  825. package/examples/output/goldbach-1000.pl +0 -667
  826. package/examples/output/hamiltonian-cycle.pl +0 -4
  827. package/examples/output/kaprekar.pl +0 -8
  828. package/examples/output/matrix.pl +0 -10
  829. package/examples/output/n-queens.pl +0 -93
  830. package/examples/output/n3-builtins.n3 +0 -6
  831. package/examples/output/path-discovery.pl +0 -3
  832. package/examples/output/project-portfolio-optimization.pl +0 -6
  833. package/examples/output/quine-mccluskey.pl +0 -3
  834. package/examples/output/resilient-city-orchestration.pl +0 -67
  835. package/examples/output/sat-dpll.pl +0 -5
  836. package/examples/output/socrates.n3 +0 -1
  837. package/examples/output/sudoku.pl +0 -2
  838. package/examples/output/traveling-salesman.pl +0 -1
  839. package/examples/output/triple-term.n3 +0 -2
  840. package/examples/path-discovery.pl +0 -44998
  841. package/examples/peano-arithmetic.pl +0 -31
  842. package/examples/peasant.pl +0 -30
  843. package/examples/pendulum-period.pl +0 -50
  844. package/examples/polynomial.pl +0 -124
  845. package/examples/project-portfolio-optimization.pl +0 -101
  846. package/examples/proof/age.pl +0 -71
  847. package/examples/proof/aliases-and-namespaces.pl +0 -78
  848. package/examples/proof/ancestor.pl +0 -140
  849. package/examples/proof/animal.pl +0 -68
  850. package/examples/proof/annotation.pl +0 -80
  851. package/examples/proof/backward.pl +0 -22
  852. package/examples/proof/cat-koko.pl +0 -86
  853. package/examples/proof/data-negotiation.pl +0 -76
  854. package/examples/proof/derived-rule.pl +0 -43
  855. package/examples/proof/dog.pl +0 -31
  856. package/examples/proof/electrical-rc-filter.pl +0 -105
  857. package/examples/proof/existential-rule.pl +0 -40
  858. package/examples/proof/floating-point.pl +0 -160
  859. package/examples/proof/good-cobbler.pl +0 -16
  860. package/examples/proof/group-inverse-uniqueness.pl +0 -84
  861. package/examples/proof/list-collection.pl +0 -52
  862. package/examples/proof/proof-contrapositive.pl +0 -78
  863. package/examples/proof/socket-age.pl +0 -32
  864. package/examples/proof/socket-family.pl +0 -59
  865. package/examples/proof/socrates.pl +0 -38
  866. package/examples/proof-contrapositive.pl +0 -27
  867. package/examples/quadratic-formula.pl +0 -54
  868. package/examples/quine-mccluskey.pl +0 -143
  869. package/examples/radioactive-decay.pl +0 -56
  870. package/examples/resilient-city-orchestration.pl +0 -303
  871. package/examples/riemann-hypothesis.pl +0 -110
  872. package/examples/sat-dpll.pl +0 -80
  873. package/examples/security-incident-correlation.pl +0 -69
  874. package/examples/service-impact.pl +0 -41
  875. package/examples/sieve.pl +0 -20
  876. package/examples/skolem-functions.pl +0 -52
  877. package/examples/socket-age.pl +0 -39
  878. package/examples/socket-family.pl +0 -28
  879. package/examples/socrates.n3 +0 -11
  880. package/examples/socrates.pl +0 -19
  881. package/examples/statistics-summary.pl +0 -54
  882. package/examples/sudoku.pl +0 -20
  883. package/examples/superdense-coding.pl +0 -84
  884. package/examples/traveling-salesman.pl +0 -64
  885. package/examples/triple-term.n3 +0 -9
  886. package/examples/turing.pl +0 -67
  887. package/examples/vector-similarity.pl +0 -56
  888. package/examples/witch.pl +0 -38
  889. package/examples/wolf-goat-cabbage.pl +0 -56
  890. package/examples/zebra.pl +0 -44
  891. package/playground-worker.mjs +0 -141
  892. package/src/builtins/alphametic.js +0 -144
  893. package/src/builtins/formula.js +0 -42
  894. package/src/builtins/matrix.js +0 -226
  895. package/src/builtins/n3.js +0 -483
  896. package/src/builtins/number-theory.js +0 -114
  897. package/src/builtins/portfolio.js +0 -73
  898. package/src/builtins/search.js +0 -579
  899. package/src/builtins/sudoku.js +0 -141
  900. package/src/rdf.js +0 -747
  901. package/test/run-all.js +0 -20
  902. package/test/run-conformance.js +0 -80
  903. package/test/run-examples.js +0 -125
  904. package/test/run-regression.js +0 -603
  905. package/test/test-style.js +0 -91
  906. /package/examples/output/{access-control-policy.pl → access-control-policy.eye} +0 -0
  907. /package/examples/output/{ackermann.pl → ackermann.eye} +0 -0
  908. /package/examples/output/{age.pl → age.eye} +0 -0
  909. /package/examples/output/{aliases-and-namespaces.pl → aliases-and-namespaces.eye} +0 -0
  910. /package/examples/output/{alignment-demo.pl → alignment-demo.eye} +0 -0
  911. /package/examples/output/{allen-interval-calculus.pl → allen-interval-calculus.eye} +0 -0
  912. /package/examples/output/{ancestor.pl → ancestor.eye} +0 -0
  913. /package/examples/output/{animal.pl → animal.eye} +0 -0
  914. /package/examples/output/{annotation.pl → annotation.eye} +0 -0
  915. /package/examples/output/{auroracare.pl → auroracare.eye} +0 -0
  916. /package/examples/output/{backward.pl → backward.eye} +0 -0
  917. /package/examples/output/{bayes-diagnosis.pl → bayes-diagnosis.eye} +0 -0
  918. /package/examples/output/{bayes-therapy.pl → bayes-therapy.eye} +0 -0
  919. /package/examples/output/{beam-deflection.pl → beam-deflection.eye} +0 -0
  920. /package/examples/output/{blocks-world-planning.pl → blocks-world-planning.eye} +0 -0
  921. /package/examples/output/{bmi.pl → bmi.eye} +0 -0
  922. /package/examples/output/{braking-safety-worlds.pl → braking-safety-worlds.eye} +0 -0
  923. /package/examples/output/{buck-converter-design.pl → buck-converter-design.eye} +0 -0
  924. /package/examples/output/{cache-performance.pl → cache-performance.eye} +0 -0
  925. /package/examples/output/{canary-release.pl → canary-release.eye} +0 -0
  926. /package/examples/output/{cat-koko.pl → cat-koko.eye} +0 -0
  927. /package/examples/output/{clinical-trial-screening.pl → clinical-trial-screening.eye} +0 -0
  928. /package/examples/output/{combinatorics-findall-sort.pl → combinatorics-findall-sort.eye} +0 -0
  929. /package/examples/output/{competitive-enzyme-kinetics.pl → competitive-enzyme-kinetics.eye} +0 -0
  930. /package/examples/output/{composition-of-injective-functions-is-injective.pl → composition-of-injective-functions-is-injective.eye} +0 -0
  931. /package/examples/output/{context-association.pl → context-association.eye} +0 -0
  932. /package/examples/output/{control-system.pl → control-system.eye} +0 -0
  933. /package/examples/output/{cyclic-path.pl → cyclic-path.eye} +0 -0
  934. /package/examples/output/{d3-group.pl → d3-group.eye} +0 -0
  935. /package/examples/output/{dairy-energy-balance.pl → dairy-energy-balance.eye} +0 -0
  936. /package/examples/output/{data-negotiation.pl → data-negotiation.eye} +0 -0
  937. /package/examples/output/{deep-taxonomy-10.pl → deep-taxonomy-10.eye} +0 -0
  938. /package/examples/output/{deep-taxonomy-100.pl → deep-taxonomy-100.eye} +0 -0
  939. /package/examples/output/{deep-taxonomy-1000.pl → deep-taxonomy-1000.eye} +0 -0
  940. /package/examples/output/{deep-taxonomy-10000.pl → deep-taxonomy-10000.eye} +0 -0
  941. /package/examples/output/{deep-taxonomy-100000.pl → deep-taxonomy-100000.eye} +0 -0
  942. /package/examples/output/{delfour.pl → delfour.eye} +0 -0
  943. /package/examples/output/{deontic-logic.pl → deontic-logic.eye} +0 -0
  944. /package/examples/output/{derived-backward-rule.pl → derived-backward-rule.eye} +0 -0
  945. /package/examples/output/{derived-rule.pl → derived-rule.eye} +0 -0
  946. /package/examples/output/{diamond-property.pl → diamond-property.eye} +0 -0
  947. /package/examples/output/{dijkstra-findall-sort.pl → dijkstra-findall-sort.eye} +0 -0
  948. /package/examples/output/{dijkstra-risk-path.pl → dijkstra-risk-path.eye} +0 -0
  949. /package/examples/output/{dijkstra.pl → dijkstra.eye} +0 -0
  950. /package/examples/output/{dining-philosophers.pl → dining-philosophers.eye} +0 -0
  951. /package/examples/output/{dog.pl → dog.eye} +0 -0
  952. /package/examples/output/{drone-corridor-planner.pl → drone-corridor-planner.eye} +0 -0
  953. /package/examples/output/{easter-computus.pl → easter-computus.eye} +0 -0
  954. /package/examples/output/{electrical-rc-filter.pl → electrical-rc-filter.eye} +0 -0
  955. /package/examples/output/{epidemic-policy.pl → epidemic-policy.eye} +0 -0
  956. /package/examples/output/{equivalence-classes-overlap-implies-same-class.pl → equivalence-classes-overlap-implies-same-class.eye} +0 -0
  957. /package/examples/output/{eulerian-path.pl → eulerian-path.eye} +0 -0
  958. /package/examples/output/{ev-range-worlds.pl → ev-range-worlds.eye} +0 -0
  959. /package/examples/output/{existential-rule.pl → existential-rule.eye} +0 -0
  960. /package/examples/output/{exoplanet-validation-worlds.pl → exoplanet-validation-worlds.eye} +0 -0
  961. /package/examples/output/{expression-eval.pl → expression-eval.eye} +0 -0
  962. /package/examples/output/{family-cousins.pl → family-cousins.eye} +0 -0
  963. /package/examples/output/{fastpow.pl → fastpow.eye} +0 -0
  964. /package/examples/output/{fft8-numeric.pl → fft8-numeric.eye} +0 -0
  965. /package/examples/output/{fibonacci.pl → fibonacci.eye} +0 -0
  966. /package/examples/output/{field-nitrogen-balance.pl → field-nitrogen-balance.eye} +0 -0
  967. /package/examples/output/{flandor.pl → flandor.eye} +0 -0
  968. /package/examples/output/{floating-point.pl → floating-point.eye} +0 -0
  969. /package/examples/output/{four-color-map.pl → four-color-map.eye} +0 -0
  970. /package/examples/output/{fundamental-theorem-arithmetic.pl → fundamental-theorem-arithmetic.eye} +0 -0
  971. /package/examples/output/{gd-step-certified.pl → gd-step-certified.eye} +0 -0
  972. /package/examples/output/{gdpr-compliance.pl → gdpr-compliance.eye} +0 -0
  973. /package/examples/output/{good-cobbler.pl → good-cobbler.eye} +0 -0
  974. /package/examples/output/{gps.pl → gps.eye} +0 -0
  975. /package/examples/output/{graph-reachability.pl → graph-reachability.eye} +0 -0
  976. /package/examples/output/{gray-code-counter.pl → gray-code-counter.eye} +0 -0
  977. /package/examples/output/{greatest-lower-bound-uniqueness.pl → greatest-lower-bound-uniqueness.eye} +0 -0
  978. /package/examples/output/{group-inverse-uniqueness.pl → group-inverse-uniqueness.eye} +0 -0
  979. /package/examples/output/{hamiltonian-path.pl → hamiltonian-path.eye} +0 -0
  980. /package/examples/output/{hamming-code.pl → hamming-code.eye} +0 -0
  981. /package/examples/output/{hanoi.pl → hanoi.eye} +0 -0
  982. /package/examples/output/{heat-loss.pl → heat-loss.eye} +0 -0
  983. /package/examples/output/{heron-theorem.pl → heron-theorem.eye} +0 -0
  984. /package/examples/output/{ideal-gas-law.pl → ideal-gas-law.eye} +0 -0
  985. /package/examples/output/{illegitimate-reasoning.pl → illegitimate-reasoning.eye} +0 -0
  986. /package/examples/output/{law-of-cosines.pl → law-of-cosines.eye} +0 -0
  987. /package/examples/output/{least-squares-regression.pl → least-squares-regression.eye} +0 -0
  988. /package/examples/output/{list-collection.pl → list-collection.eye} +0 -0
  989. /package/examples/output/{lldm.pl → lldm.eye} +0 -0
  990. /package/examples/output/{manufacturing-quality-control.pl → manufacturing-quality-control.eye} +0 -0
  991. /package/examples/output/{microgrid-dispatch.pl → microgrid-dispatch.eye} +0 -0
  992. /package/examples/output/{monkey-bananas.pl → monkey-bananas.eye} +0 -0
  993. /package/examples/output/{network-sla.pl → network-sla.eye} +0 -0
  994. /package/examples/output/{newton-raphson.pl → newton-raphson.eye} +0 -0
  995. /package/examples/output/{nixon-diamond.pl → nixon-diamond.eye} +0 -0
  996. /package/examples/output/{odrl-dpv-healthcare-risk-ranked.pl → odrl-dpv-healthcare-risk-ranked.eye} +0 -0
  997. /package/examples/output/{odrl-dpv-risk-ranked.pl → odrl-dpv-risk-ranked.eye} +0 -0
  998. /package/examples/output/{orbital-transfer-design.pl → orbital-transfer-design.eye} +0 -0
  999. /package/examples/output/{peano-arithmetic.pl → peano-arithmetic.eye} +0 -0
  1000. /package/examples/output/{peasant.pl → peasant.eye} +0 -0
  1001. /package/examples/output/{pendulum-period.pl → pendulum-period.eye} +0 -0
  1002. /package/examples/output/{polynomial.pl → polynomial.eye} +0 -0
  1003. /package/examples/output/{proof-contrapositive.pl → proof-contrapositive.eye} +0 -0
  1004. /package/examples/output/{quadratic-formula.pl → quadratic-formula.eye} +0 -0
  1005. /package/examples/output/{radioactive-decay.pl → radioactive-decay.eye} +0 -0
  1006. /package/examples/output/{riemann-hypothesis.pl → riemann-hypothesis.eye} +0 -0
  1007. /package/examples/output/{security-incident-correlation.pl → security-incident-correlation.eye} +0 -0
  1008. /package/examples/output/{service-impact.pl → service-impact.eye} +0 -0
  1009. /package/examples/output/{sieve.pl → sieve.eye} +0 -0
  1010. /package/examples/output/{skolem-functions.pl → skolem-functions.eye} +0 -0
  1011. /package/examples/output/{socket-age.pl → socket-age.eye} +0 -0
  1012. /package/{conformance/expected/extension/001_default_derived_output.out → examples/output/socket-family.eye} +0 -0
  1013. /package/examples/output/{socrates.pl → socrates.eye} +0 -0
  1014. /package/examples/output/{statistics-summary.pl → statistics-summary.eye} +0 -0
  1015. /package/examples/output/{superdense-coding.pl → superdense-coding.eye} +0 -0
  1016. /package/examples/output/{turing.pl → turing.eye} +0 -0
  1017. /package/examples/output/{vector-similarity.pl → vector-similarity.eye} +0 -0
  1018. /package/examples/output/{witch.pl → witch.eye} +0 -0
  1019. /package/examples/output/{wolf-goat-cabbage.pl → wolf-goat-cabbage.eye} +0 -0
  1020. /package/examples/output/{zebra.pl → zebra.eye} +0 -0
  1021. /package/{conformance/expected/core/001_fact_output.out → test/conformance/expected/001_fact_output.eye} +0 -0
  1022. /package/{conformance/expected/core/002_rule_recursion.out → test/conformance/expected/002_rule_recursion.eye} +0 -0
  1023. /package/{conformance/expected/core/004_conjunction_and_parentheses.out → test/conformance/expected/004_conjunction_and_parentheses.eye} +0 -0
  1024. /package/{conformance/expected/core/005_list_deconstruction.out → test/conformance/expected/005_list_deconstruction.eye} +0 -0
  1025. /package/{conformance/expected/core/006_comma_formula_data.out → test/conformance/expected/006_comma_formula_data.eye} +0 -0
  1026. /package/{conformance/expected/core/007_anonymous_variables.out → test/conformance/expected/007_anonymous_variables.eye} +0 -0
  1027. /package/{conformance/expected/core/008_graphic_atoms.out → test/conformance/expected/008_graphic_atoms.eye} +0 -0
  1028. /package/{conformance/expected/core/009_comments_and_whitespace.out → test/conformance/expected/009_comments_and_whitespace.eye} +0 -0
  1029. /package/{conformance/expected/core/010_variable_scope_and_reuse.out → test/conformance/expected/010_variable_scope_and_reuse.eye} +0 -0
  1030. /package/{conformance/expected/core/011_predicate_arity.out → test/conformance/expected/011_predicate_arity.eye} +0 -0
  1031. /package/{conformance/expected/core/012_nested_compound_unification.out → test/conformance/expected/012_nested_compound_unification.eye} +0 -0
  1032. /package/{conformance/expected/core/013_multiple_clauses_order.out → test/conformance/expected/013_multiple_clauses_order.eye} +0 -0
  1033. /package/{conformance/expected/core/014_failure_filters_answers.out → test/conformance/expected/014_failure_filters_answers.eye} +0 -0
  1034. /package/{conformance/expected/core/015_improper_list_unification.out → test/conformance/expected/015_improper_list_unification.eye} +0 -0
  1035. /package/{conformance/expected/core/017_three_step_recursion.out → test/conformance/expected/017_three_step_recursion.eye} +0 -0
  1036. /package/{conformance/expected/core/018_quoted_atom_readback.out → test/conformance/expected/018_quoted_atom_readback.eye} +0 -0
  1037. /package/{conformance/expected/core/019_parenthesized_three_conjuncts.out → test/conformance/expected/019_parenthesized_three_conjuncts.eye} +0 -0
  1038. /package/{conformance/expected/core/020_nested_list_terms.out → test/conformance/expected/020_nested_list_terms.eye} +0 -0
  1039. /package/{conformance/expected/core/021_repeated_variable_head.out → test/conformance/expected/021_repeated_variable_head.eye} +0 -0
  1040. /package/{conformance/expected/core/022_rule_head_structure.out → test/conformance/expected/022_rule_head_structure.eye} +0 -0
  1041. /package/{conformance/expected/core/023_quoted_escapes_readback.out → test/conformance/expected/023_quoted_escapes_readback.eye} +0 -0
  1042. /package/{conformance/expected/core/024_numeric_literal_readback.out → test/conformance/expected/024_numeric_literal_readback.eye} +0 -0
  1043. /package/{conformance/expected/core/025_body_parentheses_with_formula_data.out → test/conformance/expected/025_body_parentheses_with_formula_data.eye} +0 -0
  1044. /package/{conformance/expected/core/026_underscore_named_variable_reuse.out → test/conformance/expected/026_question_underscore_named_variable_reuse.eye} +0 -0
  1045. /package/{examples/output/socket-family.pl → test/conformance/expected/027_default_derived_output.eye} +0 -0
  1046. /package/{conformance/expected/extension/002_materialize_focus.out → test/conformance/expected/028_materialize_focus.eye} +0 -0
  1047. /package/{conformance/expected/extension/005_lists_aggregation_ordering.out → test/conformance/expected/031_lists_aggregation_ordering.eye} +0 -0
  1048. /package/{conformance/expected/extension/007_negation_once_generators.out → test/conformance/expected/033_negation_once_generators.eye} +0 -0
  1049. /package/{conformance/expected/extension/008_equality_and_inequality.out → test/conformance/expected/034_equality_and_inequality.eye} +0 -0
  1050. /package/{conformance/expected/extension/010_append_splits.out → test/conformance/expected/036_append_splits.eye} +0 -0
  1051. /package/{conformance/expected/extension/011_matching_and_comparison.out → test/conformance/expected/037_matching_and_comparison.eye} +0 -0
  1052. /package/{conformance/expected/extension/012_memoize_declaration.out → test/conformance/expected/038_table_declaration.eye} +0 -0
  1053. /package/{conformance/expected/extension/013_numeric_functions.out → test/conformance/expected/039_numeric_functions.eye} +0 -0
  1054. /package/{conformance/expected/extension/014_between_enumeration.out → test/conformance/expected/040_between_enumeration.eye} +0 -0
  1055. /package/{conformance/expected/extension/015_smallest_divisor.out → test/conformance/expected/041_smallest_divisor.eye} +0 -0
  1056. /package/{conformance/expected/extension/016_negation_filter.out → test/conformance/expected/042_negation_filter.eye} +0 -0
  1057. /package/{conformance/expected/extension/017_once_user_predicate.out → test/conformance/expected/043_once_user_predicate.eye} +0 -0
  1058. /package/{conformance/expected/extension/018_findall_user_goal.out → test/conformance/expected/044_findall_user_goal.eye} +0 -0
  1059. /package/{conformance/expected/extension/019_sort_deduplicates_atoms.out → test/conformance/expected/045_sort_deduplicates_atoms.eye} +0 -0
  1060. /package/{conformance/expected/extension/020_append_bound_prefix_suffix.out → test/conformance/expected/046_append_bound_prefix_suffix.eye} +0 -0
  1061. /package/{conformance/expected/extension/021_nth0_index_generation.out → test/conformance/expected/047_nth0_index_generation.eye} +0 -0
  1062. /package/{conformance/expected/extension/022_set_nth0_edges.out → test/conformance/expected/048_set_nth0_edges.eye} +0 -0
  1063. /package/{conformance/expected/extension/023_select_duplicate_occurrences.out → test/conformance/expected/049_select_duplicate_occurrences.eye} +0 -0
  1064. /package/{conformance/expected/extension/024_not_member_filter.out → test/conformance/expected/050_not_member_filter.eye} +0 -0
  1065. /package/{conformance/expected/extension/027_materialize_excludes_source_fact.out → test/conformance/expected/053_materialize_excludes_source_fact.eye} +0 -0
  1066. /package/{conformance/expected/extension/028_numeric_and_lexical_comparison.out → test/conformance/expected/054_numeric_and_lexical_comparison.eye} +0 -0
  1067. /package/{conformance/expected/extension/029_string_matching_filters.out → test/conformance/expected/055_string_matching_filters.eye} +0 -0
  1068. /package/{conformance/expected/extension/031_countall_empty_and_nonempty.out → test/conformance/expected/057_countall_empty_and_nonempty.eye} +0 -0
  1069. /package/{conformance/expected/extension/032_sumall_numeric_template.out → test/conformance/expected/058_sumall_numeric_template.eye} +0 -0
  1070. /package/{conformance/expected/extension/033_aggregate_min_template.out → test/conformance/expected/059_aggregate_min_template.eye} +0 -0
  1071. /package/{conformance/expected/extension/034_aggregate_max_compound_key.out → test/conformance/expected/060_aggregate_max_compound_key.eye} +0 -0
  1072. /package/{conformance/expected/extension/035_date_difference.out → test/conformance/expected/061_date_difference.eye} +0 -0
package/playground.html CHANGED
@@ -3,1373 +3,1237 @@
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>eyelang Playground</title>
6
+ <title>Eyelang Playground</title>
7
7
  <style>
8
8
  :root {
9
- color-scheme: light;
10
- --bg: #f8fafc;
9
+ color-scheme: light dark;
10
+ --bg: #f7f8fb;
11
11
  --panel: #ffffff;
12
- --panel-soft: #f1f5f9;
12
+ --panel-soft: #eef2f7;
13
13
  --text: #172033;
14
- --muted: #667085;
15
- --border: #d0d5dd;
16
- --accent: #315efb;
17
- --accent-strong: #2448c7;
14
+ --muted: #64748b;
15
+ --border: #d7dce5;
16
+ --accent: #0969da;
17
+ --accent-strong: #0757b8;
18
18
  --danger: #b42318;
19
- --ok: #067647;
20
- --warn-bg: #fff7e6;
21
- --warn-border: #fdb022;
22
- --code-bg: #ffffff;
23
- --code-text: #111827;
24
- --syn-comment: #667085;
25
- --syn-string: #067647;
26
- --syn-quoted: #9a3412;
27
- --syn-number: #6d28d9;
28
- --syn-variable: #175cd3;
29
- --syn-predicate: #b42318;
30
- --syn-builtin: #0e7490;
31
- --syn-punctuation: #475467;
19
+ --editor-bg: #ffffff;
20
+ --editor-text: #172033;
21
+ --editor-caret: #111827;
22
+ --editor-selection: rgba(9, 105, 218, 0.18);
23
+ --editor-error-line: #fee2e2;
24
+ --editor-error-border: #dc2626;
25
+ --line-number-bg: #f8fafc;
26
+ --line-number-text: #64748b;
27
+ --line-number-border: #e2e8f0;
28
+ --code-bg: #0f172a;
29
+ --code-text: #dbeafe;
30
+ --comment: #64748b;
31
+ --string: #047857;
32
+ --number: #b45309;
33
+ --variable: #1d4ed8;
34
+ --keyword: #7c3aed;
35
+ --predicate: #be123c;
36
+ --punctuation: #475569;
37
+ }
38
+
39
+ @media (prefers-color-scheme: dark) {
40
+ :root {
41
+ --bg: #0b1020;
42
+ --panel: #111827;
43
+ --panel-soft: #1f2937;
44
+ --text: #e5e7eb;
45
+ --muted: #9ca3af;
46
+ --border: #374151;
47
+ --accent: #60a5fa;
48
+ --accent-strong: #93c5fd;
49
+ }
32
50
  }
51
+
33
52
  * { box-sizing: border-box; }
53
+
34
54
  body {
35
55
  margin: 0;
36
- min-height: 100vh;
37
56
  background: var(--bg);
38
57
  color: var(--text);
39
- font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
58
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
59
+ line-height: 1.45;
40
60
  }
41
- header, main {
42
- width: min(920px, calc(100vw - 24px));
61
+
62
+ header,
63
+ main,
64
+ footer {
65
+ width: min(100% - 2rem, 72rem);
43
66
  margin: 0 auto;
44
67
  }
45
- header { padding: 24px 0 16px; }
46
- h1 { margin: 0; font-size: clamp(2rem, 11vw, 3.4rem); letter-spacing: -0.055em; }
47
- h2 { margin: 0 0 12px; font-size: 1.05rem; }
48
- p { line-height: 1.55; }
49
- a { color: var(--accent); }
50
- code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; }
51
- .lead { max-width: 760px; color: var(--muted); margin: 10px 0 0; }
52
- .meta { margin: 10px 0 0; color: var(--muted); font-size: 0.92rem; }
53
- .version-badge {
54
- display: inline-flex;
55
- align-items: center;
56
- min-height: 28px;
57
- padding: 3px 10px;
58
- border: 1px solid var(--border);
59
- border-radius: 999px;
60
- background: var(--panel-soft);
61
- color: var(--text);
62
- font-variant-numeric: tabular-nums;
68
+
69
+ header { padding: 1.25rem 0 0.9rem; }
70
+
71
+ h1 {
72
+ margin: 0;
73
+ font-size: clamp(1.35rem, 4vw, 2rem);
63
74
  }
64
- .stack {
65
- display: flex;
66
- flex-direction: column;
67
- gap: 16px;
68
- padding-bottom: 32px;
75
+
76
+ header p { margin: 0.35rem 0 0; color: var(--muted); }
77
+
78
+ main {
79
+ display: block;
80
+ padding: 0 0 2rem;
69
81
  }
70
- .card {
82
+
83
+ section {
71
84
  background: var(--panel);
72
85
  border: 1px solid var(--border);
73
- border-radius: 20px;
74
- box-shadow: 0 10px 28px rgba(16, 24, 40, 0.08);
86
+ border-radius: 0.9rem;
87
+ box-shadow: 0 8px 28px rgba(15, 23, 42, 0.06);
75
88
  overflow: hidden;
89
+ margin: 1rem 0;
76
90
  }
77
- .card-header { padding: 16px 16px 0; }
78
- .card-body { padding: 16px; }
79
- .toolbar, .row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
80
- .toolbar { margin: 12px 0; }
81
- .toolbar.grow > input[type="text"] { flex: 1 1 280px; }
82
- label { font-size: 0.9rem; color: var(--muted); }
83
- select, input[type="text"], textarea, button { font: inherit; }
84
- select, input[type="text"] {
85
- min-height: 42px;
86
- border: 1px solid var(--border);
87
- border-radius: 12px;
88
- padding: 8px 10px;
89
- background: var(--panel);
90
- color: var(--text);
91
- }
92
- select { max-width: 100%; }
93
- textarea {
94
- width: 100%;
95
- min-height: 44vh;
96
- resize: vertical;
97
- border: 1px solid var(--border);
98
- border-radius: 16px;
99
- padding: 14px;
100
- background: var(--code-bg);
101
- color: var(--code-text);
102
- line-height: 1.45;
103
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
104
- font-size: 0.95rem;
105
- tab-size: 2;
106
- }
107
- .editor-shell {
108
- position: relative;
109
- min-height: 44vh;
110
- border: 1px solid var(--border);
111
- border-radius: 16px;
112
- background: var(--code-bg);
113
- overflow: hidden;
91
+
92
+ .panel-body { padding: 1rem; }
93
+
94
+ .toolbar,
95
+ .example-row,
96
+ .button-row,
97
+ .option-row,
98
+ .background-row {
99
+ display: flex;
100
+ flex-wrap: wrap;
101
+ gap: 0.6rem;
102
+ align-items: center;
114
103
  }
115
- .editor-shell textarea,
116
- .syntax-layer {
117
- width: 100%;
118
- min-height: 44vh;
119
- margin: 0;
120
- padding: 14px;
121
- line-height: 1.45;
122
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
123
- font-size: 0.95rem;
124
- tab-size: 2;
125
- white-space: pre-wrap;
126
- word-break: break-word;
127
- overflow-wrap: break-word;
104
+
105
+ .toolbar {
106
+ padding: 0.85rem 1rem;
107
+ border-bottom: 1px solid var(--border);
108
+ background: var(--panel-soft);
128
109
  }
129
- .editor-shell textarea {
130
- position: relative;
131
- z-index: 2;
132
- display: block;
133
- resize: vertical;
134
- border: 0;
135
- border-radius: 0;
136
- background: transparent;
137
- color: transparent;
138
- caret-color: var(--code-text);
139
- outline: none;
140
- overflow: auto;
141
- -webkit-text-fill-color: transparent;
110
+
111
+ .toolbar:last-child { border-bottom: 0; }
112
+
113
+ details summary {
114
+ cursor: pointer;
115
+ font-weight: 700;
116
+ padding: 0.85rem 1rem;
117
+ background: var(--panel-soft);
118
+ border-bottom: 1px solid var(--border);
142
119
  }
143
- .editor-shell textarea::selection {
144
- background: #dbeafe;
120
+
121
+ details:not([open]) summary { border-bottom: 0; }
122
+
123
+ label { font-weight: 650; }
124
+
125
+ select,
126
+ input,
127
+ textarea,
128
+ button {
129
+ font: inherit;
130
+ font-size: 1rem;
145
131
  }
146
- .syntax-layer {
147
- position: absolute;
148
- inset: 0;
149
- z-index: 1;
150
- pointer-events: none;
151
- color: var(--code-text);
152
- border: 0;
153
- background: transparent;
154
- overflow: auto;
132
+
133
+ select,
134
+ input[type="url"],
135
+ input[type="search"] {
136
+ min-height: 2.65rem;
137
+ padding: 0.55rem 0.7rem;
138
+ border: 1px solid var(--border);
139
+ border-radius: 0.55rem;
140
+ background: var(--panel);
141
+ color: var(--text);
155
142
  }
156
- .syn-comment { color: var(--syn-comment); font-style: italic; }
157
- .syn-string { color: var(--syn-string); }
158
- .syn-quoted { color: var(--syn-quoted); }
159
- .syn-number { color: var(--syn-number); }
160
- .syn-variable { color: var(--syn-variable); }
161
- .syn-predicate { color: var(--syn-predicate); font-weight: 600; }
162
- .syn-builtin { color: var(--syn-builtin); font-weight: 600; }
163
- .syn-punctuation { color: var(--syn-punctuation); }
143
+
144
+ select { min-width: min(100%, 18rem); flex: 1; }
145
+ input[type="url"] { flex: 1 1 20rem; min-width: 12rem; }
146
+ input[type="search"] { flex: 1 1 12rem; min-width: 10rem; }
147
+
164
148
  button {
165
149
  border: 1px solid var(--border);
166
- border-radius: 999px;
167
- padding: 9px 14px;
150
+ border-radius: 0.55rem;
151
+ padding: 0.58rem 0.78rem;
152
+ min-height: 2.65rem;
168
153
  background: var(--panel);
169
154
  color: var(--text);
170
155
  cursor: pointer;
171
156
  }
172
- button.primary { border-color: var(--accent); background: var(--accent); color: white; }
173
- button.primary:hover { background: var(--accent-strong); }
174
- button:disabled { opacity: 0.55; cursor: not-allowed; }
175
- .run-options {
176
- margin-top: 10px;
177
- align-items: flex-start;
178
- }
179
- .command-preview {
180
- display: block;
181
- margin-top: 8px;
182
- padding: 8px 10px;
183
- border: 1px solid var(--border);
184
- border-radius: 12px;
185
- background: var(--panel-soft);
186
- color: var(--muted);
187
- flex: 1 1 100%;
188
- overflow-x: auto;
189
- white-space: nowrap;
190
- }
191
- .status { min-height: 1.4em; color: var(--muted); font-size: 0.92rem; }
192
- .status.ok { color: var(--ok); }
193
- .status.error { color: var(--danger); }
194
- .output-header { justify-content: space-between; }
195
- .output-tabs { display: inline-flex; padding: 3px; border: 1px solid var(--border); border-radius: 999px; gap: 3px; }
196
- .output-tabs button { border: 0; padding: 6px 12px; }
197
- .output-tabs button.active { background: var(--accent); color: white; }
198
- pre {
199
- margin: 0;
200
- min-height: 280px;
201
- white-space: pre-wrap;
202
- word-break: break-word;
203
- border: 1px solid var(--border);
204
- border-radius: 16px;
205
- padding: 14px;
206
- background: var(--code-bg);
207
- color: var(--code-text);
208
- overflow: auto;
209
- line-height: 1.45;
210
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
211
- font-size: 0.95rem;
157
+
158
+ button.primary {
159
+ border-color: var(--accent);
160
+ background: var(--accent);
161
+ color: white;
162
+ font-weight: 700;
212
163
  }
213
- .notice, .background-note {
214
- margin-top: 10px;
215
- border-radius: 14px;
216
- padding: 10px 12px;
164
+
165
+ button.primary:hover { background: var(--accent-strong); }
166
+ button:disabled { cursor: not-allowed; opacity: 0.6; }
167
+
168
+ .option-row label,
169
+ .background-row label {
170
+ display: inline-flex;
171
+ gap: 0.35rem;
172
+ align-items: center;
173
+ font-weight: 500;
217
174
  color: var(--muted);
218
- font-size: 0.92rem;
219
- }
220
- .notice {
221
- border: 1px solid var(--warn-border);
222
- background: var(--warn-bg);
223
- color: var(--text);
224
175
  }
225
- .background-note { border: 1px dashed var(--border); }
226
- .hidden { display: none !important; }
227
- .small { font-size: 0.86rem; color: var(--muted); }
228
176
 
177
+ .editor-shell { padding: 0; }
229
178
 
230
- .editor-shell {
231
- display: grid;
232
- grid-template-columns: 4.2rem minmax(0, 1fr);
233
- height: 56vh;
234
- min-height: 360px;
235
- border: 1px solid var(--border);
236
- border-radius: 16px;
237
- background: var(--code-bg);
179
+ .editor-label {
180
+ display: flex;
181
+ justify-content: space-between;
182
+ gap: 1rem;
183
+ padding: 0.7rem 1rem;
184
+ border-bottom: 1px solid var(--border);
185
+ background: var(--panel);
186
+ }
187
+
188
+ .editor {
189
+ position: relative;
190
+ min-height: 56vh;
191
+ background: var(--editor-bg);
238
192
  overflow: hidden;
239
193
  }
240
- .line-gutter {
241
- padding: 14px 10px 14px 6px;
242
- border-right: 1px solid var(--border);
243
- background: var(--panel-soft);
244
- color: #475467;
245
- text-align: right;
246
- line-height: 1.45;
194
+
195
+ .line-numbers,
196
+ .editor pre,
197
+ .editor textarea {
247
198
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
248
199
  font-size: 0.95rem;
249
- white-space: pre;
200
+ line-height: 1.55;
201
+ }
202
+
203
+ .line-numbers {
204
+ position: absolute;
205
+ inset: 0 auto 0 0;
206
+ width: 3.6rem;
207
+ padding: 1rem 0.65rem 1rem 0.35rem;
250
208
  overflow: hidden;
209
+ text-align: right;
210
+ color: var(--line-number-text);
211
+ background: var(--line-number-bg);
212
+ border-right: 1px solid var(--line-number-border);
251
213
  user-select: none;
252
- font-variant-numeric: tabular-nums;
214
+ pointer-events: none;
215
+ z-index: 3;
216
+ }
217
+
218
+ .line-numbers-inner { will-change: transform; }
219
+
220
+ .line-number {
221
+ display: block;
222
+ min-height: 1.55em;
223
+ padding-right: 0.1rem;
253
224
  }
254
- .line-gutter .error-line { color: var(--danger); font-weight: 700; }
255
- .editor-code { position: relative; min-width: 0; height: 100%; background: var(--code-bg); overflow: hidden; }
256
- .program-syntax,
257
- .editor-shell textarea.program-textarea {
225
+
226
+ .line-number.error {
227
+ color: var(--danger);
228
+ background: var(--editor-error-line);
229
+ font-weight: 700;
230
+ margin: 0 -0.65rem 0 -0.35rem;
231
+ padding: 0 0.65rem 0 0.35rem;
232
+ }
233
+
234
+ .editor pre,
235
+ .editor textarea {
258
236
  position: absolute;
259
237
  inset: 0;
260
- width: 100%;
261
- height: 100%;
262
- min-height: 0;
263
238
  margin: 0;
264
- padding: 14px;
239
+ padding: 1rem 1rem 1rem 4.35rem;
265
240
  border: 0;
266
- border-radius: 0;
267
- line-height: 1.45;
268
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
269
- font-size: 0.95rem;
270
- tab-size: 2;
271
- white-space: pre-wrap;
272
- overflow-wrap: anywhere;
273
- word-break: normal;
274
- }
275
- .program-syntax {
276
- z-index: 1;
277
- pointer-events: none;
278
- color: var(--code-text);
279
- background: transparent;
280
- /* Keep the highlighted text as a full-height document layer.
281
- The parent clips the viewport; this layer itself must not clip,
282
- otherwise longer programs disappear after the first editor screen. */
283
- bottom: auto;
284
- min-height: 100%;
285
- height: auto;
286
- overflow: visible;
287
- box-sizing: border-box;
288
- }
289
- .editor-shell textarea.program-textarea {
290
- z-index: 3;
291
- display: block;
241
+ width: 100%;
242
+ height: 100%;
292
243
  resize: none;
293
- background: transparent;
294
- color: transparent;
295
- -webkit-text-fill-color: transparent;
296
- caret-color: var(--code-text);
297
- outline: none;
298
244
  overflow: auto;
299
- overflow-x: hidden;
300
- }
301
- .editor-shell textarea.program-textarea::selection {
302
- background: rgba(37, 99, 235, 0.22);
245
+ white-space: pre;
246
+ tab-size: 2;
303
247
  }
304
- .error-band {
248
+
249
+ .error-line-marker {
305
250
  position: absolute;
306
- z-index: 2;
307
251
  left: 0;
308
252
  right: 0;
309
- height: calc(1em * 1.45);
310
- background: rgba(244, 63, 94, 0.16);
311
- border-left: 4px solid var(--danger);
253
+ top: 0;
254
+ display: none;
312
255
  pointer-events: none;
256
+ background: var(--editor-error-line);
257
+ border-left: 0.28rem solid var(--editor-error-border);
258
+ z-index: 0;
313
259
  }
314
- .output-shell {
315
- display: grid;
316
- grid-template-columns: 4.2rem minmax(0, 1fr);
317
- min-height: 280px;
318
- max-height: 60vh;
319
- border: 1px solid var(--border);
320
- border-radius: 16px;
321
- background: var(--code-bg);
322
- overflow: hidden;
260
+
261
+ .editor pre {
262
+ pointer-events: none;
263
+ color: var(--editor-text);
264
+ z-index: 1;
323
265
  }
324
- .output-shell pre {
325
- min-height: 280px;
326
- max-height: 60vh;
327
- border: 0;
328
- border-radius: 0;
329
- padding: 14px;
266
+
267
+ .editor textarea {
268
+ background: transparent;
269
+ color: rgba(17, 24, 39, 0.025);
270
+ caret-color: var(--editor-caret);
271
+ outline: none;
272
+ z-index: 2;
273
+ -webkit-text-fill-color: rgba(17, 24, 39, 0.025);
274
+ }
275
+
276
+ .editor textarea::selection { background: var(--editor-selection); }
277
+
278
+ .tok-comment { color: var(--comment); font-style: italic; }
279
+ .tok-string { color: var(--string); }
280
+ .tok-number { color: var(--number); }
281
+ .tok-variable { color: var(--variable); }
282
+ .tok-keyword { color: var(--keyword); font-weight: 700; }
283
+ .tok-predicate { color: var(--predicate); }
284
+ .tok-punctuation { color: var(--punctuation); }
285
+
286
+ .output {
287
+ min-height: 18rem;
288
+ max-height: 58vh;
289
+ overflow: auto;
290
+ padding: 1rem;
291
+ margin: 0;
292
+ background: var(--code-bg);
293
+ color: var(--code-text);
294
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
295
+ font-size: 0.9rem;
296
+ line-height: 1.55;
330
297
  white-space: pre-wrap;
331
298
  overflow-wrap: anywhere;
332
- overflow: auto;
333
- user-select: text;
334
- }
335
- .output-shell .line-gutter { max-height: 60vh; }
336
- .stderr-label { color: var(--danger); font-weight: 700; }
337
- .stderr-text { color: var(--danger); }
338
-
339
- @media (max-width: 620px) {
340
- header, main { width: min(100vw - 14px, 920px); }
341
- header { padding-top: 18px; }
342
- .card { border-radius: 16px; }
343
- .card-header, .card-body { padding-left: 12px; padding-right: 12px; }
344
- .toolbar { align-items: stretch; }
345
- .toolbar > label:first-child { flex-basis: 100%; }
346
- .toolbar button,
347
- .toolbar select,
348
- .toolbar input[type="text"] { width: 100%; }
349
- .toolbar label.row { width: 100%; }
350
- .output-header { align-items: flex-start; }
351
- .output-tabs { width: 100%; }
352
- .output-tabs button { flex: 1; }
353
- textarea, .editor-shell, .editor-shell textarea, .syntax-layer { min-height: 360px; font-size: 0.9rem; }
354
- pre { min-height: 240px; font-size: 0.9rem; }
299
+ }
300
+
301
+ .status {
302
+ display: flex;
303
+ align-items: center;
304
+ justify-content: space-between;
305
+ gap: 0.75rem;
306
+ padding: 0.65rem 1rem;
307
+ border-top: 1px solid var(--border);
308
+ color: var(--muted);
309
+ font-size: 0.95rem;
310
+ }
311
+
312
+ .hint {
313
+ color: var(--muted);
314
+ font-size: 0.95rem;
315
+ margin: 0.4rem 0 0;
316
+ }
317
+
318
+ .error { color: var(--danger); }
319
+
320
+ footer {
321
+ color: var(--muted);
322
+ padding: 0 0 1.5rem;
323
+ text-align: center;
324
+ font-size: 0.95rem;
325
+ }
326
+
327
+ footer a { color: var(--accent); }
328
+
329
+ @media (max-width: 560px) {
330
+ header,
331
+ main,
332
+ footer { width: min(100% - 1rem, 72rem); }
333
+ .toolbar,
334
+ .panel-body,
335
+ .editor-label,
336
+ details summary { padding: 0.8rem; }
337
+ button,
338
+ select,
339
+ input[type="url"],
340
+ input[type="search"] { width: 100%; }
341
+ .button-row > button { flex: 1 1 8rem; }
342
+ .editor { min-height: 58vh; }
343
+ .line-numbers,
344
+ .editor pre,
345
+ .editor textarea { font-size: 0.9rem; }
346
+ .line-numbers { width: 3.2rem; padding: 0.8rem 0.55rem 0.8rem 0.25rem; }
347
+ .line-number.error { margin: 0 -0.55rem 0 -0.25rem; padding: 0 0.55rem 0 0.25rem; }
348
+ .editor pre,
349
+ .editor textarea { padding: 0.8rem 0.8rem 0.8rem 3.85rem; }
355
350
  }
356
351
  </style>
357
352
  </head>
358
353
  <body>
359
354
  <header>
360
- <h1>eyelang Playground</h1>
361
- <p class="lead">Edit an eyelang program, run it with the JavaScript engine entirely in your browser, load examples or URLs, autosave locally, and share a compact link.</p>
362
- <p class="meta"><span id="versionBadge" class="version-badge">eyelang 1.1.0</span></p>
355
+ <h1>The Eyelang Playground</h1>
356
+ <p>Run Eyelang programs in your browser with syntax coloring, examples, proofs, and shareable editor links.</p>
363
357
  </header>
364
358
 
365
- <main class="stack">
366
- <section id="fileProtocolNotice" class="notice hidden">
367
- This page is open as a local <code>file://</code> URL. Browser security rules usually block module workers and example loading in that mode. Serve this directory with <code>python3 -m http.server 8000</code> and open <code>http://localhost:8000/playground.html</code>.
359
+ <main>
360
+ <section aria-labelledby="examples-heading">
361
+ <div class="toolbar" aria-label="Example loader">
362
+ <label id="examples-heading" for="example-search">Load an example</label>
363
+ <input id="example-search" type="search" placeholder="Filter examples" autocomplete="off">
364
+ <select id="examples" aria-label="Examples"></select>
365
+ <button id="load-example" type="button">Load example</button>
366
+ </div>
368
367
  </section>
369
368
 
370
- <section class="card">
371
- <div class="card-header">
372
- <h2>Input program</h2>
373
- <div class="toolbar">
374
- <label for="exampleSelect">Example</label>
375
- <select id="exampleSelect"></select>
376
- <button id="loadExampleButton" type="button">Load example</button>
377
- <button id="resetButton" type="button">Reset</button>
369
+ <section aria-labelledby="advanced-heading">
370
+ <details>
371
+ <summary id="advanced-heading">⚙ Advanced configuration</summary>
372
+ <div class="toolbar" aria-label="URL loader">
373
+ <label for="source-url">Load Eyelang from URL</label>
374
+ <input id="source-url" type="url" placeholder="https://example.org/program.eye">
375
+ <button id="load-url" type="button">Load from URL</button>
378
376
  </div>
379
- <div class="toolbar grow">
380
- <input id="urlInput" type="text" placeholder="Load .pl from URL, for example examples/ancestor.pl" spellcheck="false">
381
- <button id="loadUrlButton" type="button">Load from URL</button>
382
- <label class="row"><input id="backgroundToggle" type="checkbox"> add as background</label>
377
+ <div class="toolbar background-row">
378
+ <label><input id="load-background" type="checkbox"> Load into background knowledge instead of overwriting the editor</label>
379
+ <span id="background-status" class="hint">No background knowledge loaded.</span>
380
+ <button id="clear-background" type="button">Clear background</button>
383
381
  </div>
384
- <div id="backgroundNote" class="background-note hidden"></div>
385
- </div>
386
- <div class="card-body">
387
- <div class="editor-shell" id="programEditor">
388
- <div id="programGutter" class="line-gutter" aria-hidden="true">1</div>
389
- <div class="editor-code">
390
- <div id="programSyntax" class="program-syntax" aria-hidden="true"></div>
391
- <div id="programErrorBand" class="error-band hidden" aria-hidden="true"></div>
392
- <textarea id="programInput" class="program-textarea" spellcheck="false" autocapitalize="off" autocomplete="off" wrap="soft" aria-label="Editable eyelang program"></textarea>
393
- </div>
382
+ <div class="toolbar option-row" aria-label="Run options">
383
+ <label><input id="proof" type="checkbox"> Show proof explanations</label>
384
+ <label><input id="stats" type="checkbox"> Show stats</label>
385
+ </div>
386
+ <div class="panel-body">
387
+ <p class="hint">Enter any Eyelang file URL and click “Load from URL”. Background knowledge is prepended when the program runs.</p>
394
388
  </div>
395
- <div class="toolbar run-options">
396
- <label class="row"><input id="statsToggle" type="checkbox"> include <code>--stats</code> counters</label>
397
- <label class="row"><input id="proofToggle" type="checkbox"> include <code>--proof</code> explanations</label>
398
- <code id="commandPreview" class="command-preview" aria-label="Equivalent CLI command">eyelang input.pl</code>
389
+ </details>
390
+ </section>
391
+
392
+ <section aria-labelledby="editor-heading">
393
+ <div class="editor-shell">
394
+ <div class="editor-label">
395
+ <strong id="editor-heading">Editable Eyelang program</strong>
396
+ <span id="source-name" class="hint">custom program</span>
399
397
  </div>
400
- <div class="toolbar">
401
- <button id="runButton" class="primary" type="button">Run eyelang</button>
402
- <button id="stopButton" type="button" disabled>Stop</button>
403
- <button id="copyLinkButton" type="button">Copy share link</button>
404
- <button id="clearSavedButton" type="button">Clear autosave</button>
405
- <span id="status" class="status" role="status">Idle.</span>
398
+ <div class="editor">
399
+ <div id="line-numbers" class="line-numbers" aria-hidden="true"><div class="line-numbers-inner"></div></div>
400
+ <div id="error-line-marker" class="error-line-marker" aria-hidden="true"></div>
401
+ <pre id="highlight" aria-hidden="true"><code></code></pre>
402
+ <textarea id="source" spellcheck="false" autocapitalize="off" autocomplete="off" aria-label="Editable Eyelang source"></textarea>
406
403
  </div>
407
- <p class="small">The playground concatenates loaded background programs before the editor contents. Use <code>materialize/2</code> declarations to focus output and the <code>--stats</code> toggle for counters. Output is ordinary eyelang syntax: answer facts by default, with <code>why/2</code> explanations added when <code>--proof</code> is selected.</p>
404
+ </div>
405
+ <div class="toolbar button-row">
406
+ <button id="run" type="button" class="primary">Run reasoning</button>
407
+ <button id="stop" type="button" disabled>Stop</button>
408
+ <button id="copy-source" type="button">Copy source</button>
409
+ <button id="copy-output" type="button">Copy output</button>
410
+ <button id="share" type="button">Copy share link</button>
411
+ <button id="create-gist" type="button">Create Gist share</button>
408
412
  </div>
409
413
  </section>
410
414
 
411
- <section class="card">
412
- <div class="card-header row output-header">
413
- <h2>Output</h2>
415
+ <section aria-labelledby="output-heading">
416
+ <div class="editor-label">
417
+ <strong id="output-heading">Output</strong>
418
+ <span id="elapsed" class="hint">Idle.</span>
414
419
  </div>
415
- <div class="card-body">
416
- <div class="output-shell">
417
- <div id="outputGutter" class="line-gutter" aria-hidden="true">1</div>
418
- <pre id="combinedOutput" class="output-view">(no output yet)</pre>
419
- </div>
420
+ <pre id="output" class="output">(no output yet)</pre>
421
+ <div class="status">
422
+ <span id="status">Ready.</span>
423
+ <span id="version">eyelang v…</span>
424
+ </div>
425
+ <div class="panel-body">
426
+ <p class="hint">For local use, serve the checkout with a small HTTP server first; browser modules and example loading usually do not work from <code>file://</code>.</p>
420
427
  </div>
421
428
  </section>
422
429
  </main>
423
430
 
431
+ <footer>
432
+ Powered by <a href="https://github.com/eyereasoner/eyelang">Eyelang</a>.
433
+ </footer>
434
+
424
435
  <script type="module">
425
436
  const EXAMPLES = [
426
- "access-control-policy",
427
- "ackermann",
428
- "age",
429
- "aliases-and-namespaces",
430
- "alignment-demo",
431
- "allen-interval-calculus",
432
- "ancestor",
433
- "animal",
434
- "annotation",
435
- "auroracare",
436
- "backward",
437
- "basic-monadic",
438
- "bayes-diagnosis",
439
- "bayes-therapy",
440
- "beam-deflection",
441
- "blocks-world-planning",
442
- "bmi",
443
- "braking-safety-worlds",
444
- "buck-converter-design",
445
- "cache-performance",
446
- "canary-release",
447
- "cat-koko",
448
- "clinical-trial-screening",
449
- "collatz-1000",
450
- "combinatorics-findall-sort",
451
- "competitive-enzyme-kinetics",
452
- "complex",
453
- "complex-matrix-stability",
454
- "composition-of-injective-functions-is-injective",
455
- "context-association",
456
- "control-system",
457
- "cryptarithmetic-send-more-money",
458
- "cyclic-path",
459
- "d3-group",
460
- "dairy-energy-balance",
461
- "data-negotiation",
462
- "deep-taxonomy-10",
463
- "deep-taxonomy-100",
464
- "deep-taxonomy-1000",
465
- "deep-taxonomy-10000",
466
- "deep-taxonomy-100000",
467
- "delfour",
468
- "dense-hamiltonian-cycle",
469
- "deontic-logic",
470
- "derived-backward-rule",
471
- "derived-rule",
472
- "diamond-property",
473
- "dijkstra",
474
- "dijkstra-findall-sort",
475
- "dijkstra-risk-path",
476
- "dining-philosophers",
477
- "dog",
478
- "drone-corridor-planner",
479
- "easter-computus",
480
- "electrical-rc-filter",
481
- "epidemic-policy",
482
- "equivalence-classes-overlap-implies-same-class",
483
- "eulerian-path",
484
- "ev-range-worlds",
485
- "exact-cover-sudoku",
486
- "existential-rule",
487
- "exoplanet-validation-worlds",
488
- "expression-eval",
489
- "family-cousins",
490
- "fastpow",
491
- "fft8-numeric",
492
- "fibonacci",
493
- "field-nitrogen-balance",
494
- "floating-point",
495
- "flandor",
496
- "four-color-map",
497
- "fundamental-theorem-arithmetic",
498
- "gcd-bezout-identity",
499
- "gd-step-certified",
500
- "gdpr-compliance",
501
- "goldbach-1000",
502
- "good-cobbler",
503
- "gps",
504
- "graph-reachability",
505
- "gray-code-counter",
506
- "greatest-lower-bound-uniqueness",
507
- "group-inverse-uniqueness",
508
- "hamiltonian-cycle",
509
- "hamiltonian-path",
510
- "hamming-code",
511
- "hanoi",
512
- "heat-loss",
513
- "heron-theorem",
514
- "ideal-gas-law",
515
- "illegitimate-reasoning",
516
- "kaprekar",
517
- "law-of-cosines",
518
- "least-squares-regression",
519
- "list-collection",
520
- "lldm",
521
- "manufacturing-quality-control",
522
- "matrix",
523
- "microgrid-dispatch",
524
- "monkey-bananas",
525
- "n-queens",
526
- "network-sla",
527
- "newton-raphson",
528
- "nixon-diamond",
529
- "odrl-dpv-healthcare-risk-ranked",
530
- "odrl-dpv-risk-ranked",
531
- "orbital-transfer-design",
532
- "path-discovery",
533
- "peano-arithmetic",
534
- "peasant",
535
- "pendulum-period",
536
- "polynomial",
537
- "project-portfolio-optimization",
538
- "proof-contrapositive",
539
- "quadratic-formula",
540
- "quine-mccluskey",
541
- "radioactive-decay",
542
- "resilient-city-orchestration",
543
- "riemann-hypothesis",
544
- "sat-dpll",
545
- "security-incident-correlation",
546
- "service-impact",
547
- "sieve",
548
- "skolem-functions",
549
- "socket-age",
550
- "socket-family",
551
- "socrates",
552
- "statistics-summary",
553
- "sudoku",
554
- "superdense-coding",
555
- "traveling-salesman",
556
- "turing",
557
- "vector-similarity",
558
- "witch",
559
- "wolf-goat-cabbage",
560
- "zebra"
561
- ];
562
- const DEFAULT_PROGRAM = "% Socrates is mortal.\n\nmaterialize(type, 2).\nmaterialize(is, 2).\n\ntype(socrates, man).\n\ntype(X, mortal) :-\n type(X, man).\n\nis(test, true) :-\n type(socrates, mortal).";
563
- const STORAGE_KEY = 'eyelang.playground.v7';
564
-
565
- const programInput = document.getElementById('programInput');
566
- const programSyntax = document.getElementById('programSyntax');
567
- const programGutter = document.getElementById('programGutter');
568
- const programErrorBand = document.getElementById('programErrorBand');
569
- const statsToggle = document.getElementById('statsToggle');
570
- const proofToggle = document.getElementById('proofToggle');
571
- const commandPreview = document.getElementById('commandPreview');
572
- const exampleSelect = document.getElementById('exampleSelect');
573
- const loadExampleButton = document.getElementById('loadExampleButton');
574
- const resetButton = document.getElementById('resetButton');
575
- const urlInput = document.getElementById('urlInput');
576
- const loadUrlButton = document.getElementById('loadUrlButton');
577
- const backgroundToggle = document.getElementById('backgroundToggle');
578
- const backgroundNote = document.getElementById('backgroundNote');
579
- const runButton = document.getElementById('runButton');
580
- const stopButton = document.getElementById('stopButton');
581
- const copyLinkButton = document.getElementById('copyLinkButton');
582
- const clearSavedButton = document.getElementById('clearSavedButton');
583
- const statusEl = document.getElementById('status');
584
- const combinedOutput = document.getElementById('combinedOutput');
585
- const outputGutter = document.getElementById('outputGutter');
586
- const fileProtocolNotice = document.getElementById('fileProtocolNotice');
587
- const versionBadge = document.getElementById('versionBadge');
588
-
589
- const workerUrl = new URL('./playground-worker.mjs', location.href).href;
590
-
591
- let backgroundPrograms = [];
592
- let worker = null;
593
- let workerReady = false;
594
- let workerLoadError = null;
595
- let preloadPromise = null;
596
- let preloadResolve = null;
597
- let preloadReject = null;
598
- let currentRunId = null;
599
- let runStarted = 0;
600
- let saveTimer = 0;
601
- let currentProgramUrl = null;
602
- let currentProgramSource = null;
603
-
604
- for (const name of EXAMPLES) {
605
- const option = document.createElement('option');
606
- option.value = name;
607
- option.textContent = name;
608
- if (name === 'socrates') option.selected = true;
609
- exampleSelect.append(option);
610
- }
611
-
612
- function setStatus(text, kind = '') {
613
- statusEl.textContent = text;
614
- statusEl.className = `status ${kind}`;
615
- }
616
-
617
- function showTab(_) {
618
- // Output is a single combined window. Kept as a no-op for older call sites.
437
+ "access-control-policy",
438
+ "ackermann",
439
+ "age",
440
+ "aliases-and-namespaces",
441
+ "alignment-demo",
442
+ "allen-interval-calculus",
443
+ "ancestor",
444
+ "animal",
445
+ "annotation",
446
+ "auroracare",
447
+ "backward",
448
+ "basic-monadic",
449
+ "bayes-diagnosis",
450
+ "bayes-therapy",
451
+ "beam-deflection",
452
+ "binomial-vandermonde",
453
+ "blocks-world-planning",
454
+ "bmi",
455
+ "braking-safety-worlds",
456
+ "buck-converter-design",
457
+ "cache-performance",
458
+ "canary-release",
459
+ "cat-koko",
460
+ "catalan-convolution",
461
+ "chart-parser",
462
+ "clinical-trial-screening",
463
+ "collatz-1000",
464
+ "combinatorics-findall-sort",
465
+ "competitive-enzyme-kinetics",
466
+ "complex",
467
+ "composition-of-injective-functions-is-injective",
468
+ "context-association",
469
+ "context-schema-audit",
470
+ "continued-fraction-sqrt2",
471
+ "control-system",
472
+ "critical-path-schedule",
473
+ "cyclic-path",
474
+ "d3-group",
475
+ "dairy-energy-balance",
476
+ "data-negotiation",
477
+ "deep-taxonomy-10",
478
+ "deep-taxonomy-100",
479
+ "deep-taxonomy-1000",
480
+ "deep-taxonomy-10000",
481
+ "deep-taxonomy-100000",
482
+ "delfour",
483
+ "deontic-logic",
484
+ "derived-backward-rule",
485
+ "derived-rule",
486
+ "diamond-property",
487
+ "dijkstra",
488
+ "dijkstra-findall-sort",
489
+ "dijkstra-risk-path",
490
+ "dining-philosophers",
491
+ "dog",
492
+ "dpv-odrl-purpose-mapping",
493
+ "drone-corridor-planner",
494
+ "easter-computus",
495
+ "electrical-rc-filter",
496
+ "epidemic-policy",
497
+ "equivalence-classes-overlap-implies-same-class",
498
+ "eulerian-path",
499
+ "ev-range-worlds",
500
+ "existential-rule",
501
+ "exoplanet-validation-worlds",
502
+ "expression-eval",
503
+ "family-cousins",
504
+ "fastpow",
505
+ "fft8-numeric",
506
+ "fibonacci",
507
+ "field-nitrogen-balance",
508
+ "flandor",
509
+ "floating-point",
510
+ "four-color-map",
511
+ "fundamental-theorem-arithmetic",
512
+ "gd-step-certified",
513
+ "gdpr-compliance",
514
+ "good-cobbler",
515
+ "gps",
516
+ "graph",
517
+ "graph-reachability",
518
+ "gray-code-counter",
519
+ "greatest-lower-bound-uniqueness",
520
+ "group-inverse-uniqueness",
521
+ "hamiltonian-path",
522
+ "hamming-code",
523
+ "hanoi",
524
+ "heat-loss",
525
+ "heron-theorem",
526
+ "ideal-gas-law",
527
+ "illegitimate-reasoning",
528
+ "integer-partitions",
529
+ "intuitionistic-logic-kripke",
530
+ "job-shop-scheduling",
531
+ "knapsack-optimization",
532
+ "knowledge-engineering-alignment-flow",
533
+ "language",
534
+ "law-of-cosines",
535
+ "least-squares-regression",
536
+ "linear-logic-resources",
537
+ "list-collection",
538
+ "lldm",
539
+ "manufacturing-quality-control",
540
+ "matrix-chain-order",
541
+ "microgrid-dispatch",
542
+ "missionaries-cannibals",
543
+ "modal-logic-kripke",
544
+ "modular-exponentiation",
545
+ "monkey-bananas",
546
+ "n-queens-8",
547
+ "network-sla",
548
+ "newton-raphson",
549
+ "nixon-diamond",
550
+ "observability-log-correlation",
551
+ "odrl-dpv-fpv-trust-flow",
552
+ "odrl-dpv-healthcare-risk-ranked",
553
+ "odrl-dpv-risk-ranked",
554
+ "orbital-transfer-design",
555
+ "path-discovery",
556
+ "peano-arithmetic",
557
+ "peasant",
558
+ "pell-equation",
559
+ "pendulum-period",
560
+ "polynomial",
561
+ "proof-contrapositive",
562
+ "quadratic-formula",
563
+ "radioactive-decay",
564
+ "reusable-builtins",
565
+ "riemann-hypothesis",
566
+ "security-incident-correlation",
567
+ "send-more-money",
568
+ "service-impact",
569
+ "sieve",
570
+ "skolem-functions",
571
+ "socket-age",
572
+ "socket-family",
573
+ "socrates",
574
+ "stable-marriage",
575
+ "statistics-summary",
576
+ "stirling-bell-numbers",
577
+ "sudoku-4x4",
578
+ "superdense-coding",
579
+ "term-tools",
580
+ "totient-summatory",
581
+ "trust-flow-provenance-threshold",
582
+ "turing",
583
+ "vector-similarity",
584
+ "vulnerability-impact",
585
+ "web-names",
586
+ "weighted-interval-scheduling",
587
+ "witch",
588
+ "wolf-goat-cabbage",
589
+ "zebra"
590
+ ];
591
+ const FALLBACK_SOURCE = `materialize(answer, 1).
592
+ answer(ok) :- eq(ok, ok).
593
+ `;
594
+ const HIGHLIGHT_LIMIT = 200000;
595
+ const MAX_SHARE_URL_LENGTH = 1900;
596
+ const GIST_STATE_FILENAME = 'eyelang-playground-state.json';
597
+ const KEYWORDS = new Set(['materialize', 'table']);
598
+ const BUILTINS = new Set([
599
+ "abs",
600
+ "acos",
601
+ "add",
602
+ "aggregate_max",
603
+ "aggregate_min",
604
+ "append",
605
+ "arg",
606
+ "asin",
607
+ "atan2",
608
+ "atom_string",
609
+ "between",
610
+ "ceiling",
611
+ "compound_name_arguments",
612
+ "contains",
613
+ "cos",
614
+ "countall",
615
+ "difference",
616
+ "div",
617
+ "drop",
618
+ "eq",
619
+ "exp",
620
+ "findall",
621
+ "floor",
622
+ "forall",
623
+ "functor",
624
+ "ge",
625
+ "gt",
626
+ "head",
627
+ "holds",
628
+ "join",
629
+ "last",
630
+ "le",
631
+ "length",
632
+ "list_to_set",
633
+ "local_time",
634
+ "log",
635
+ "lowercase",
636
+ "lt",
637
+ "matches",
638
+ "max",
639
+ "max_list",
640
+ "member",
641
+ "min",
642
+ "min_list",
643
+ "mod",
644
+ "mul",
645
+ "neg",
646
+ "neq",
647
+ "not",
648
+ "not_matches",
649
+ "not_member",
650
+ "nth0",
651
+ "number_string",
652
+ "once",
653
+ "pow",
654
+ "replace",
655
+ "rest",
656
+ "reverse",
657
+ "rounded",
658
+ "select",
659
+ "set_nth0",
660
+ "sin",
661
+ "slice",
662
+ "smallest_divisor_from",
663
+ "sort",
664
+ "split",
665
+ "sqrt",
666
+ "str_concat",
667
+ "sub",
668
+ "substring",
669
+ "sum_list",
670
+ "sumall",
671
+ "take",
672
+ "tan",
673
+ "term_string",
674
+ "trim",
675
+ "trunc",
676
+ "uppercase"
677
+ ]);
678
+
679
+ const source = document.querySelector('#source');
680
+ const highlight = document.querySelector('#highlight');
681
+ const lineNumbers = document.querySelector('#line-numbers');
682
+ const lineNumbersInner = lineNumbers.firstElementChild;
683
+ const errorLineMarker = document.querySelector('#error-line-marker');
684
+ const exampleSelect = document.querySelector('#examples');
685
+ const exampleSearch = document.querySelector('#example-search');
686
+ const output = document.querySelector('#output');
687
+ const status = document.querySelector('#status');
688
+ const elapsed = document.querySelector('#elapsed');
689
+ const sourceName = document.querySelector('#source-name');
690
+ const backgroundStatus = document.querySelector('#background-status');
691
+ const loadBackground = document.querySelector('#load-background');
692
+ const proof = document.querySelector('#proof');
693
+ const stats = document.querySelector('#stats');
694
+ const runButton = document.querySelector('#run');
695
+ const stopButton = document.querySelector('#stop');
696
+ let backgroundSource = '';
697
+ let backgroundName = '';
698
+ let activeWorker = null;
699
+ let activeWorkerUrl = null;
700
+ let renderToken = 0;
701
+ let syntaxErrorLine = null;
702
+ let sourceReference = { kind: 'custom' };
703
+ let sourceDirty = false;
704
+ let backgroundReference = null;
705
+
706
+ populateExamples(EXAMPLES);
707
+ await restoreFromHashOrLoadDefault();
708
+ loadVersion();
709
+
710
+ source.addEventListener('input', () => {
711
+ sourceDirty = true;
712
+ sourceReference = { kind: 'custom' };
713
+ clearSyntaxError();
714
+ render();
715
+ });
716
+ source.addEventListener('scroll', syncScroll);
717
+ exampleSearch.addEventListener('input', () => populateExamples(filterExamples(exampleSearch.value)));
718
+ document.querySelector('#load-example').addEventListener('click', () => loadExample(exampleSelect.value));
719
+ document.querySelector('#load-url').addEventListener('click', loadUrl);
720
+ document.querySelector('#clear-background').addEventListener('click', clearBackground);
721
+ document.querySelector('#run').addEventListener('click', runProgram);
722
+ document.querySelector('#stop').addEventListener('click', stopProgram);
723
+ document.querySelector('#copy-source').addEventListener('click', () => copyText(source.value, 'Source copied.'));
724
+ document.querySelector('#copy-output').addEventListener('click', () => copyText(output.textContent, 'Output copied.'));
725
+ document.querySelector('#share').addEventListener('click', copyShareLink);
726
+ document.querySelector('#create-gist').addEventListener('click', createGistShare);
727
+
728
+ function populateExamples(names) {
729
+ const current = exampleSelect.value;
730
+ exampleSelect.replaceChildren(...names.map((name) => {
731
+ const option = document.createElement('option');
732
+ option.value = name;
733
+ option.textContent = name;
734
+ return option;
735
+ }));
736
+ if (names.includes(current)) exampleSelect.value = current;
737
+ else if (names.length) exampleSelect.value = names[0];
738
+ }
739
+
740
+ function filterExamples(query) {
741
+ const needle = query.trim().toLowerCase();
742
+ if (!needle) return EXAMPLES;
743
+ return EXAMPLES.filter((name) => name.includes(needle));
744
+ }
745
+
746
+ async function loadExample(name) {
747
+ if (!name) return;
748
+ try {
749
+ setStatus(`Loading ${name}…`);
750
+ const exampleUrl = new URL(`./examples/${name}.eye`, location.href);
751
+ const response = await fetch(exampleUrl, { cache: 'no-store' });
752
+ if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
753
+ setSource(await response.text(), `examples/${name}.eye`, { kind: 'example', name });
754
+ setStatus(`Loaded examples/${name}.eye.`);
755
+ } catch (error) {
756
+ setSource(FALLBACK_SOURCE, 'fallback program');
757
+ setStatus(`Could not load examples/${name}.eye: ${formatError(error)}`, true);
758
+ }
619
759
  }
620
760
 
621
- function escapeHtml(text) {
622
- return text.replace(/[&<>"']/g, char => ({
623
- '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
624
- })[char]);
625
- }
626
-
627
-
628
- const BUILTIN_NAMES = new Set([
629
- "abs",
630
- "acos",
631
- "add",
632
- "aggregate_max",
633
- "aggregate_min",
634
- "append",
635
- "asin",
636
- "atan",
637
- "between",
638
- "ceil",
639
- "cos",
640
- "countall",
641
- "difference",
642
- "div",
643
- "eq",
644
- "equal",
645
- "exp",
646
- "findall",
647
- "floor",
648
- "formula_atom",
649
- "formula_binary",
650
- "ge",
651
- "greater",
652
- "gt",
653
- "is_list",
654
- "le",
655
- "length",
656
- "local_time",
657
- "log",
658
- "lt",
659
- "max",
660
- "member",
661
- "min",
662
- "mod",
663
- "mul",
664
- "neq",
665
- "not",
666
- "not_equal",
667
- "not_member",
668
- "nth0",
669
- "once",
670
- "pow",
671
- "rest",
672
- "reverse",
673
- "round",
674
- "select",
675
- "set_nth0",
676
- "sin",
677
- "smallest_divisor_from",
678
- "sort",
679
- "sqrt",
680
- "sub",
681
- "sudoku",
682
- "sumall",
683
- "tan"
684
- ]);
685
-
686
- function isAlpha(char) { return /[A-Za-z]/.test(char); }
687
- function isDigit(char) { return /[0-9]/.test(char); }
688
- function isIdentChar(char) { return /[A-Za-z0-9_]/.test(char); }
689
- function nextNonSpace(text, index) {
690
- while (index < text.length && /[ \t\r\n]/.test(text[index])) index++;
691
- return text[index] || '';
692
- }
693
-
694
- function span(className, text) {
695
- return `<span class="${className}">${escapeHtml(text)}</span>`;
696
- }
697
-
698
- function highlightProlog(text) {
699
- let html = '';
700
- let i = 0;
701
-
702
- while (i < text.length) {
703
- const char = text[i];
704
-
705
- if (char === '%') {
706
- let j = i + 1;
707
- while (j < text.length && text[j] !== '\n') j++;
708
- html += span('syn-comment', text.slice(i, j));
709
- i = j;
710
- continue;
761
+ async function loadUrl() {
762
+ const url = document.querySelector('#source-url').value.trim();
763
+ if (!url) return;
764
+ try {
765
+ setStatus(`Loading ${url}…`);
766
+ const response = await fetch(url);
767
+ if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
768
+ const text = await response.text();
769
+ if (loadBackground.checked) {
770
+ backgroundSource = text;
771
+ backgroundName = url;
772
+ backgroundReference = { kind: 'url', url };
773
+ updateBackgroundStatus();
774
+ setStatus(`Loaded background knowledge from ${url}.`);
775
+ } else {
776
+ setSource(text, url, { kind: 'url', url });
777
+ setStatus(`Loaded ${url}.`);
711
778
  }
779
+ } catch (error) {
780
+ setStatus(`Could not load URL: ${formatError(error)}`, true);
781
+ }
782
+ }
783
+
784
+ function clearBackground() {
785
+ backgroundSource = '';
786
+ backgroundName = '';
787
+ backgroundReference = null;
788
+ updateBackgroundStatus();
789
+ setStatus('Background knowledge cleared.');
790
+ }
712
791
 
713
- if (char === '"' || char === "'") {
714
- const quote = char;
792
+ function updateBackgroundStatus() {
793
+ backgroundStatus.textContent = backgroundSource
794
+ ? `Background loaded from ${backgroundName} (${backgroundSource.length.toLocaleString()} chars).`
795
+ : 'No background knowledge loaded.';
796
+ }
797
+
798
+ function setSource(text, name, reference = { kind: 'custom' }) {
799
+ source.value = text;
800
+ sourceName.textContent = name;
801
+ sourceReference = reference;
802
+ sourceDirty = false;
803
+ clearSyntaxError();
804
+ render();
805
+ }
806
+
807
+ function render() {
808
+ const token = ++renderToken;
809
+ const text = source.value;
810
+ requestAnimationFrame(() => {
811
+ if (token !== renderToken) return;
812
+ highlight.firstElementChild.innerHTML = renderHighlightedSource(text);
813
+ updateLineNumbers(text);
814
+ syncScroll();
815
+ });
816
+ }
817
+
818
+ function renderHighlightedSource(text) {
819
+ const rendered = text.length > HIGHLIGHT_LIMIT ? escapeHtml(text) : colorize(text);
820
+ return rendered + (text.endsWith('\n') ? ' ' : '');
821
+ }
822
+
823
+ function syncScroll() {
824
+ highlight.scrollTop = source.scrollTop;
825
+ highlight.scrollLeft = source.scrollLeft;
826
+ lineNumbersInner.style.transform = `translateY(${-source.scrollTop}px)`;
827
+ updateErrorLineMarker();
828
+ }
829
+
830
+ function updateLineNumbers(text = source.value) {
831
+ const count = Math.max(1, text.split('\n').length);
832
+ lineNumbersInner.innerHTML = Array.from({ length: count }, (_, index) => {
833
+ const line = index + 1;
834
+ const className = line === syntaxErrorLine ? 'line-number error' : 'line-number';
835
+ return `<span class="${className}">${line}</span>`;
836
+ }).join('');
837
+ }
838
+
839
+ function colorize(text) {
840
+ let out = '';
841
+ for (let i = 0; i < text.length;) {
842
+ const ch = text[i];
843
+ if (ch === '%') {
844
+ const end = text.indexOf('\n', i);
845
+ const stop = end === -1 ? text.length : end;
846
+ out += span('comment', text.slice(i, stop));
847
+ i = stop;
848
+ } else if (ch === '"' || ch === "'") {
849
+ const quote = ch;
715
850
  let j = i + 1;
716
851
  while (j < text.length) {
717
- if (text[j] === '\\') {
718
- j += 2;
719
- continue;
720
- }
721
- if (quote === "'" && text[j] === "'" && text[j + 1] === "'") {
722
- j += 2;
723
- continue;
724
- }
725
- if (text[j] === quote) {
726
- j++;
727
- break;
728
- }
729
- j++;
852
+ if (text[j] === '\\') j += 2;
853
+ else if (text[j] === quote) { j++; break; }
854
+ else j++;
730
855
  }
731
- html += span(quote === '"' ? 'syn-string' : 'syn-quoted', text.slice(i, j));
856
+ out += span('string', text.slice(i, j));
732
857
  i = j;
733
- continue;
734
- }
735
-
736
- if ((char === '-' && isDigit(text[i + 1] || '')) || isDigit(char)) {
737
- let j = i + (char === '-' ? 1 : 0);
738
- while (isDigit(text[j] || '')) j++;
739
- if (text[j] === '.' && isDigit(text[j + 1] || '')) {
740
- j++;
741
- while (isDigit(text[j] || '')) j++;
742
- }
743
- if ((text[j] === 'e' || text[j] === 'E') && (isDigit(text[j + 1] || '') || ((text[j + 1] === '+' || text[j + 1] === '-') && isDigit(text[j + 2] || '')))) {
744
- j++;
745
- if (text[j] === '+' || text[j] === '-') j++;
746
- while (isDigit(text[j] || '')) j++;
747
- }
748
- html += span('syn-number', text.slice(i, j));
858
+ } else if (/\d/.test(ch)) {
859
+ let j = i + 1;
860
+ while (j < text.length && /[\d.]/.test(text[j])) j++;
861
+ out += span('number', text.slice(i, j));
749
862
  i = j;
750
- continue;
751
- }
752
-
753
- if (isAlpha(char) || char === '_') {
863
+ } else if (ch === '?' && /[A-Za-z_]/.test(text[i + 1] || '')) {
864
+ let j = i + 2;
865
+ while (j < text.length && /[A-Za-z0-9_]/.test(text[j])) j++;
866
+ out += span('variable', text.slice(i, j));
867
+ i = j;
868
+ } else if (/[a-z]/.test(ch)) {
754
869
  let j = i + 1;
755
- while (isIdentChar(text[j] || '')) j++;
870
+ while (j < text.length && /[A-Za-z0-9_]/.test(text[j])) j++;
756
871
  const word = text.slice(i, j);
757
- if (/[A-Z_]/.test(char)) {
758
- html += span('syn-variable', word);
759
- } else if (BUILTIN_NAMES.has(word)) {
760
- html += span('syn-builtin', word);
761
- } else if (nextNonSpace(text, j) === '(') {
762
- html += span('syn-predicate', word);
763
- } else {
764
- html += escapeHtml(word);
765
- }
872
+ if (KEYWORDS.has(word)) out += span('keyword', word);
873
+ else if (BUILTINS.has(word) || text[j] === '(') out += span('predicate', word);
874
+ else out += escapeHtml(word);
766
875
  i = j;
767
- continue;
768
- }
769
-
770
- if (':-.,;()[]{}|'.includes(char)) {
771
- html += span('syn-punctuation', char);
876
+ } else if ('()[]{},.;|:-'.includes(ch)) {
877
+ out += span('punctuation', ch);
878
+ i++;
879
+ } else {
880
+ out += escapeHtml(ch);
772
881
  i++;
773
- continue;
774
882
  }
775
-
776
- html += escapeHtml(char);
777
- i++;
778
883
  }
884
+ return out;
885
+ }
886
+
887
+ function span(kind, text) { return `<span class="tok-${kind}">${escapeHtml(text)}</span>`; }
779
888
 
780
- return html || ' ';
889
+ function escapeHtml(text) {
890
+ return text.replace(/[&<>]/g, (ch) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' }[ch]));
891
+ }
892
+
893
+ function runProgram() {
894
+ stopProgram(false);
895
+ clearSyntaxError();
896
+ output.textContent = '';
897
+ elapsed.textContent = 'Running…';
898
+ setStatus('Running Eyelang…');
899
+ runButton.disabled = true;
900
+ stopButton.disabled = false;
901
+
902
+ const engineUrl = new URL('./src/index.js', location.href).href;
903
+ const workerCode = `
904
+ import { run } from ${JSON.stringify(engineUrl)};
905
+ self.onmessage = (event) => {
906
+ const started = performance.now();
907
+ try {
908
+ const result = run(event.data.source, event.data.options);
909
+ self.postMessage({
910
+ ok: true,
911
+ stdout: result.stdout,
912
+ stats: result.stats,
913
+ elapsedMs: performance.now() - started,
914
+ });
915
+ } catch (error) {
916
+ self.postMessage({ ok: false, error: error?.stack || error?.message || String(error) });
917
+ }
918
+ };
919
+ `;
920
+ activeWorkerUrl = URL.createObjectURL(new Blob([workerCode], { type: 'text/javascript' }));
921
+ activeWorker = new Worker(activeWorkerUrl, { type: 'module' });
922
+ activeWorker.onmessage = (event) => finishRun(event.data);
923
+ activeWorker.onerror = (event) => finishRun({ ok: false, error: event.message || 'worker error' });
924
+ activeWorker.postMessage({
925
+ source: combinedSource(),
926
+ options: { proof: proof.checked, stats: stats.checked },
927
+ });
781
928
  }
782
929
 
783
- let currentErrorLine = 0;
930
+ function combinedSource() {
931
+ if (!backgroundSource.trim()) return source.value;
932
+ return `${backgroundSource}\n${source.value}`;
933
+ }
784
934
 
785
- function lineCount(text) {
786
- return Math.max(1, String(text || '').split('\n').length);
935
+ function extractParseErrorLine(text) {
936
+ const match = String(text).match(/parse line (\d+)/i);
937
+ return match ? Number(match[1]) : null;
787
938
  }
788
939
 
789
- function renderLineNumbers(target, count, errorLine = 0) {
790
- let html = '';
791
- for (let i = 1; i <= count; i++) {
792
- const escaped = String(i);
793
- html += i === errorLine ? `<span class="error-line">${escaped}</span>` : escaped;
794
- if (i < count) html += '\n';
795
- }
796
- target.innerHTML = html;
940
+ function editorLineForParseLine(parseLine) {
941
+ if (!Number.isFinite(parseLine) || parseLine < 1) return null;
942
+ if (!backgroundSource.trim()) return parseLine;
943
+ const backgroundLines = backgroundSource.split('\n').length;
944
+ const editorLine = parseLine - backgroundLines;
945
+ return editorLine >= 1 ? editorLine : null;
797
946
  }
798
947
 
799
- function updateProgramLineNumbers() {
800
- renderLineNumbers(programGutter, lineCount(programInput.value), currentErrorLine);
801
- programGutter.scrollTop = programInput.scrollTop;
802
- updateErrorBand();
948
+ function markSyntaxErrorLine(line) {
949
+ syntaxErrorLine = line;
950
+ updateLineNumbers();
951
+ revealLine(line);
952
+ updateErrorLineMarker();
803
953
  }
804
954
 
805
- function updateErrorBand() {
806
- if (!currentErrorLine) {
807
- programErrorBand.classList.add('hidden');
808
- return;
809
- }
810
- const style = getComputedStyle(programInput);
811
- const lineHeight = parseFloat(style.lineHeight) || (parseFloat(style.fontSize) || 16) * 1.45;
812
- const top = parseFloat(style.paddingTop || '0') + (currentErrorLine - 1) * lineHeight - programInput.scrollTop;
813
- programErrorBand.style.top = `${top}px`;
814
- programErrorBand.style.height = `${lineHeight}px`;
815
- programErrorBand.classList.remove('hidden');
955
+ function clearSyntaxError() {
956
+ syntaxErrorLine = null;
957
+ updateLineNumbers();
958
+ updateErrorLineMarker();
816
959
  }
817
960
 
818
- function clearErrorLine() {
819
- currentErrorLine = 0;
820
- updateProgramLineNumbers();
961
+ function revealLine(line) {
962
+ const metrics = editorMetrics();
963
+ const y = metrics.paddingTop + (line - 1) * metrics.lineHeight;
964
+ const top = source.scrollTop;
965
+ const bottom = top + source.clientHeight - metrics.lineHeight;
966
+ if (y < top || y > bottom) {
967
+ source.scrollTop = Math.max(0, y - source.clientHeight / 3);
968
+ }
821
969
  }
822
970
 
823
- function markErrorLine(line) {
824
- const count = lineCount(programInput.value);
825
- const parsed = Number(line);
826
- if (!Number.isFinite(parsed) || parsed <= 0) {
827
- clearErrorLine();
971
+ function updateErrorLineMarker() {
972
+ if (syntaxErrorLine == null) {
973
+ errorLineMarker.style.display = 'none';
828
974
  return;
829
975
  }
830
- currentErrorLine = Math.min(count, Math.max(1, Math.floor(parsed)));
831
- updateProgramLineNumbers();
832
- const style = getComputedStyle(programInput);
833
- const lineHeight = parseFloat(style.lineHeight) || (parseFloat(style.fontSize) || 16) * 1.45;
834
- programInput.scrollTop = Math.max(0, (currentErrorLine - 3) * lineHeight);
835
- updateProgramLineNumbers();
836
- const lines = programInput.value.split('\n');
837
- let start = 0;
838
- for (let i = 0; i < currentErrorLine - 1; i++) start += lines[i].length + 1;
839
- const end = start + (lines[currentErrorLine - 1] || '').length;
840
- try { programInput.setSelectionRange(start, end); } catch (_) {}
841
- }
842
-
843
- function updateProgramSyntax() {
844
- if (!programSyntax) return;
845
- programSyntax.innerHTML = highlightProlog(programInput.value || ' ');
846
- // Match the textarea's scrollable content height. Without this, the
847
- // passive syntax layer can be clipped to the visible editor height,
848
- // making everything below the first screen look blank.
849
- const scrollHeight = Math.max(programInput.scrollHeight, programInput.clientHeight);
850
- programSyntax.style.minHeight = `${scrollHeight}px`;
851
- programSyntax.style.transform = `translateY(${-programInput.scrollTop}px)`;
852
- }
853
-
854
- function updateProgramHighlight() {
855
- updateProgramSyntax();
856
- updateProgramLineNumbers();
857
- }
858
-
859
- function setProgramValue(value) {
860
- programInput.value = value;
861
- clearErrorLine();
862
- updateProgramHighlight();
863
- }
864
-
865
- function cleanStderr(text) {
866
- const raw = String(text || '').trim();
867
- if (!raw) return '';
868
- if (/Maximum call stack size exceeded|call stack|stack overflow/i.test(raw)) {
869
- return 'eyelang exhausted the browser JavaScript call stack. Try a smaller example in the playground, or run this program with the Node CLI.';
870
- }
871
- return raw;
872
- }
873
-
874
- function extractDiagnosticLine(text) {
875
- const value = String(text || '');
876
- const patterns = [
877
- /(?:line|Line)\s+(\d+)/,
878
- /:(\d+):\d+:/,
879
- /syntax[^\n]*?(\d+)/i,
880
- /parse[^\n]*?(\d+)/i,
881
- ];
882
- for (const pattern of patterns) {
883
- const match = value.match(pattern);
884
- if (match) return Number(match[1]);
976
+ const metrics = editorMetrics();
977
+ errorLineMarker.style.display = 'block';
978
+ errorLineMarker.style.height = `${metrics.lineHeight}px`;
979
+ errorLineMarker.style.top = `${metrics.paddingTop + (syntaxErrorLine - 1) * metrics.lineHeight - source.scrollTop}px`;
980
+ }
981
+
982
+ function editorMetrics() {
983
+ const style = getComputedStyle(source);
984
+ const fontSize = parseFloat(style.fontSize) || 15;
985
+ const lineHeight = parseFloat(style.lineHeight) || fontSize * 1.55;
986
+ const paddingTop = parseFloat(style.paddingTop) || 0;
987
+ return { lineHeight, paddingTop };
988
+ }
989
+
990
+ function finishRun(message) {
991
+ cleanupWorker();
992
+ runButton.disabled = false;
993
+ stopButton.disabled = true;
994
+ if (!message.ok) {
995
+ const errorText = message.error || 'Unknown error.';
996
+ const parseLine = extractParseErrorLine(errorText);
997
+ const editorLine = editorLineForParseLine(parseLine);
998
+ if (editorLine != null) markSyntaxErrorLine(editorLine);
999
+ output.textContent = errorText;
1000
+ elapsed.textContent = 'Failed.';
1001
+ setStatus(editorLine == null ? 'Run failed.' : `Syntax error on line ${editorLine}.`, true);
1002
+ return;
885
1003
  }
886
- return 0;
1004
+ let text = message.stdout || '(no materialized output)\n';
1005
+ if (stats.checked && message.stats) text += '\n% stats\n' + formatStats(message.stats);
1006
+ output.textContent = text;
1007
+ const seconds = (message.elapsedMs / 1000).toFixed(3);
1008
+ elapsed.textContent = `${seconds} sec`;
1009
+ setStatus('Run complete.');
887
1010
  }
888
1011
 
889
- function combinedText(stdout, stderr) {
890
- const out = String(stdout || '').trimEnd();
891
- const err = cleanStderr(stderr);
892
- if (out && err) return `${out}\n\nstderr\n${err}`;
893
- if (out) return out;
894
- if (err) return `stderr\n${err}`;
895
- return '(no output)';
1012
+ function stopProgram(report = true) {
1013
+ if (!activeWorker) return;
1014
+ cleanupWorker();
1015
+ runButton.disabled = false;
1016
+ stopButton.disabled = true;
1017
+ elapsed.textContent = 'Stopped.';
1018
+ if (report) setStatus('Run stopped.');
896
1019
  }
897
1020
 
898
- function setOutputText(text) {
899
- combinedOutput.innerHTML = highlightProlog(String(text || ''));
900
- renderLineNumbers(outputGutter, lineCount(String(text || '')));
901
- outputGutter.scrollTop = combinedOutput.scrollTop;
1021
+ function cleanupWorker() {
1022
+ if (activeWorker) activeWorker.terminate();
1023
+ activeWorker = null;
1024
+ if (activeWorkerUrl) URL.revokeObjectURL(activeWorkerUrl);
1025
+ activeWorkerUrl = null;
902
1026
  }
903
1027
 
904
- function setRunOutput(stdout, stderr) {
905
- const text = combinedText(stdout, stderr);
906
- setOutputText(text);
907
- const line = extractDiagnosticLine(stderr) || extractDiagnosticLine(stdout);
908
- if (line) markErrorLine(line);
1028
+ function formatStats(values) {
1029
+ return Object.entries(values).map(([key, value]) => `${key}: ${value}`).join('\n') + '\n';
909
1030
  }
910
1031
 
911
- function updateBackgroundNote() {
912
- if (!backgroundPrograms.length) {
913
- backgroundNote.classList.add('hidden');
914
- backgroundNote.textContent = '';
1032
+ async function copyText(text, message) {
1033
+ try {
1034
+ await navigator.clipboard.writeText(text);
1035
+ setStatus(message);
1036
+ } catch (_) {
1037
+ setStatus('Clipboard access is not available in this browser.', true);
1038
+ }
1039
+ }
1040
+
1041
+ async function copyShareLink() {
1042
+ const link = buildShareLink();
1043
+ if (link != null) {
1044
+ await copyText(link, 'Share link copied.');
915
1045
  return;
916
1046
  }
917
- const names = backgroundPrograms.map(item => item.name).join(', ');
918
- backgroundNote.classList.remove('hidden');
919
- backgroundNote.innerHTML = `<strong>${backgroundPrograms.length}</strong> background program(s): ${escapeHtml(names)} <button id="clearBackgroundInline" type="button">Clear background</button>`;
920
- document.getElementById('clearBackgroundInline').addEventListener('click', () => {
921
- backgroundPrograms = [];
922
- updateBackgroundNote();
923
- saveState();
1047
+ await createGistShare({
1048
+ reason: 'This program is too large for an inline URL, so Copy share link will create a Gist share instead.',
924
1049
  });
925
1050
  }
926
1051
 
927
- function combinedProgram() {
928
- const parts = backgroundPrograms.map(item => `% background: ${item.name}\n${item.source.trim()}`);
929
- parts.push(programInput.value.trim());
930
- return parts.filter(Boolean).join('\n\n');
1052
+ function buildShareLink() {
1053
+ const referenced = buildReferenceShareLink();
1054
+ if (referenced && referenced.length <= MAX_SHARE_URL_LENGTH) return referenced;
1055
+ const embedded = `${basePlaygroundUrl()}#state=${encodeState(currentShareState())}`;
1056
+ return embedded.length <= MAX_SHARE_URL_LENGTH ? embedded : null;
931
1057
  }
932
1058
 
933
- function saveState() {
934
- clearTimeout(saveTimer);
935
- updateCommandPreview();
936
- saveTimer = setTimeout(() => {
937
- localStorage.setItem(STORAGE_KEY, JSON.stringify({
938
- program: programInput.value,
939
- stats: statsToggle.checked,
940
- proof: proofToggle.checked,
941
- backgroundPrograms,
942
- currentProgramUrl,
943
- }));
944
- }, 150);
1059
+ function buildReferenceShareLink() {
1060
+ const params = new URLSearchParams();
1061
+ if (proof.checked) params.set('proof', '1');
1062
+ if (stats.checked) params.set('stats', '1');
1063
+ if (backgroundSource.trim()) {
1064
+ if (backgroundReference?.kind !== 'url') return null;
1065
+ params.set('background-url', backgroundReference.url);
1066
+ }
1067
+ if (!sourceDirty && sourceReference.kind === 'example') params.set('example', sourceReference.name);
1068
+ else if (!sourceDirty && sourceReference.kind === 'url') params.set('url', sourceReference.url);
1069
+ else return null;
1070
+ return `${basePlaygroundUrl()}#${params.toString()}`;
1071
+ }
1072
+
1073
+ async function createGistShare(options = {}) {
1074
+ const stateText = JSON.stringify(currentShareState(), null, 2);
1075
+ if (options.reason) setStatus(options.reason);
1076
+ const token = prompt(`${options.reason ? `${options.reason}\n\n` : ''}Optional GitHub token with gist scope. It is only sent to api.github.com and is not stored. Leave blank to copy Gist-ready state and open gist.github.com.`);
1077
+ if (token === null) {
1078
+ setStatus('Gist share cancelled.');
1079
+ return;
1080
+ }
1081
+ if (!token.trim()) {
1082
+ await copyText(stateText, `Gist-ready state copied. Create a Gist file named ${GIST_STATE_FILENAME}, paste it, then copy its raw URL into a playground #state-url link.`);
1083
+ window.open('https://gist.github.com/', '_blank', 'noopener');
1084
+ return;
1085
+ }
1086
+
1087
+ try {
1088
+ setStatus('Creating GitHub Gist…');
1089
+ const files = {
1090
+ [GIST_STATE_FILENAME]: { content: stateText },
1091
+ 'program.eye': { content: source.value },
1092
+ };
1093
+ if (backgroundSource.trim()) files['background.eye'] = { content: backgroundSource };
1094
+ const response = await fetch('https://api.github.com/gists', {
1095
+ method: 'POST',
1096
+ headers: {
1097
+ Accept: 'application/vnd.github+json',
1098
+ Authorization: `Bearer ${token.trim()}`,
1099
+ 'Content-Type': 'application/json',
1100
+ },
1101
+ body: JSON.stringify({
1102
+ description: 'Eyelang playground share',
1103
+ public: false,
1104
+ files,
1105
+ }),
1106
+ });
1107
+ const gist = await response.json().catch(() => ({}));
1108
+ if (!response.ok) throw new Error(gist.message || `${response.status} ${response.statusText}`);
1109
+ const rawUrl = gist.files?.[GIST_STATE_FILENAME]?.raw_url;
1110
+ if (!rawUrl) throw new Error('Gist response did not include a raw state URL.');
1111
+ await copyText(`${basePlaygroundUrl()}#state-url=${encodeURIComponent(rawUrl)}`, 'Gist share link copied.');
1112
+ } catch (error) {
1113
+ await copyText(stateText, `Could not create Gist: ${formatError(error)}. Gist-ready state copied instead.`);
1114
+ }
945
1115
  }
946
1116
 
947
- function encodePayload(text) {
948
- const bytes = new TextEncoder().encode(text);
949
- let binary = '';
950
- for (const byte of bytes) binary += String.fromCharCode(byte);
951
- return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
1117
+ function currentShareState() {
1118
+ return {
1119
+ source: source.value,
1120
+ proof: proof.checked,
1121
+ stats: stats.checked,
1122
+ backgroundSource,
1123
+ backgroundName,
1124
+ };
952
1125
  }
953
1126
 
954
- function decodePayload(text) {
955
- const padded = text.replace(/-/g, '+').replace(/_/g, '/').padEnd(Math.ceil(text.length / 4) * 4, '=');
956
- const binary = atob(padded);
957
- const bytes = Uint8Array.from(binary, char => char.charCodeAt(0));
958
- return new TextDecoder().decode(bytes);
1127
+ function encodeState(payload) {
1128
+ const data = new TextEncoder().encode(JSON.stringify(payload));
1129
+ let binary = '';
1130
+ for (const byte of data) binary += String.fromCharCode(byte);
1131
+ return btoa(binary).replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, '');
959
1132
  }
960
1133
 
961
- function parseFlag(value) {
962
- return /^(1|true|yes|on)$/i.test(String(value || ''));
1134
+ function decodeState(encoded) {
1135
+ const base64 = encoded.replaceAll('-', '+').replaceAll('_', '/');
1136
+ const padded = base64 + '='.repeat((4 - base64.length % 4) % 4);
1137
+ const bytes = Uint8Array.from(atob(padded), (ch) => ch.charCodeAt(0));
1138
+ return JSON.parse(new TextDecoder().decode(bytes));
963
1139
  }
964
1140
 
965
- function shellQuote(text) {
966
- if (!text) return "''";
967
- return "'" + String(text).replace(/'/g, "'\\''") + "'";
1141
+ function basePlaygroundUrl() {
1142
+ return location.href.split('#')[0];
968
1143
  }
969
1144
 
970
- function updateCommandPreview() {
971
- const args = ['eyelang'];
972
- if (statsToggle.checked) args.push('--stats');
973
- if (proofToggle.checked) args.push('--proof');
974
- args.push(currentProgramStillMatchesUrl() ? currentProgramUrl : 'input.pl');
975
- commandPreview.textContent = args.join(' ');
1145
+ async function restoreFromHashOrLoadDefault() {
1146
+ if (!(await restoreFromHash())) await loadExample('ancestor');
976
1147
  }
977
1148
 
978
- async function restoreState() {
979
- const searchParams = new URLSearchParams(location.search);
980
- if (searchParams.has('url')) {
981
- const sourceUrl = searchParams.get('url');
982
- urlInput.value = sourceUrl;
983
- statsToggle.checked = parseFlag(searchParams.get('stats') || searchParams.get('s'));
984
- proofToggle.checked = parseFlag(searchParams.get('proof') || searchParams.get('pr'));
985
- updateCommandPreview();
986
- try {
987
- await loadIntoEditor(sourceUrl, false, { save: false });
988
- setStatus(`Loaded ${sourceUrl}.`, 'ok');
989
- return;
990
- } catch (error) {
991
- setStatus(`Could not load URL parameter: ${error.message}`, 'error');
1149
+ async function restoreFromHash() {
1150
+ if (!location.hash || location.hash === '#') return false;
1151
+ const params = new URLSearchParams(location.hash.slice(1));
1152
+ try {
1153
+ if (params.has('state')) {
1154
+ applySharedState(decodeState(params.get('state')), 'shared program');
1155
+ setStatus('Loaded shared program.');
1156
+ return true;
992
1157
  }
993
- }
994
-
995
- const params = new URLSearchParams(location.hash.startsWith('#') ? location.hash.slice(1) : location.hash);
996
- if (params.has('p')) {
997
- try {
998
- setProgramValue(decodePayload(params.get('p')));
999
- statsToggle.checked = parseFlag(params.get('s'));
1000
- proofToggle.checked = parseFlag(params.get('r'));
1001
- currentProgramUrl = null;
1002
- currentProgramSource = null;
1003
- setStatus('Loaded shared program.', 'ok');
1004
- return;
1005
- } catch (error) {
1006
- setStatus(`Could not decode shared link: ${error.message}`, 'error');
1158
+ if (params.has('state-url')) {
1159
+ const stateUrl = params.get('state-url');
1160
+ const response = await fetch(stateUrl);
1161
+ if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
1162
+ applySharedState(await response.json(), `shared state from ${stateUrl}`);
1163
+ setStatus('Loaded shared Gist state.');
1164
+ return true;
1007
1165
  }
1008
- }
1009
- try {
1010
- const raw = localStorage.getItem(STORAGE_KEY) || localStorage.getItem('eyelang.playground.v6') || localStorage.getItem('eyelang.playground.v5') || localStorage.getItem('eyelang.playground.v4') || localStorage.getItem('eyelang.playground.v3') || localStorage.getItem('eyelang.playground.v2') || localStorage.getItem('eyelang.playground.v1');
1011
- if (raw) {
1012
- const payload = JSON.parse(raw);
1013
- setProgramValue(payload.program || DEFAULT_PROGRAM);
1014
- statsToggle.checked = Boolean(payload.stats);
1015
- proofToggle.checked = Boolean(payload.proof);
1016
- backgroundPrograms = Array.isArray(payload.backgroundPrograms) ? payload.backgroundPrograms : [];
1017
- currentProgramUrl = payload.currentProgramUrl || null;
1018
- currentProgramSource = currentProgramUrl ? programInput.value : null;
1019
- if (currentProgramUrl) urlInput.value = currentProgramUrl;
1020
- updateBackgroundNote();
1021
- updateCommandPreview();
1022
- setStatus('Restored autosave.', 'ok');
1023
- return;
1166
+ await restoreBackgroundUrl(params);
1167
+ applyOptionParams(params);
1168
+ if (params.has('example')) {
1169
+ await loadExample(params.get('example'));
1170
+ applyOptionParams(params);
1171
+ return true;
1172
+ }
1173
+ if (params.has('url')) {
1174
+ await loadSourceFromUrl(params.get('url'), false);
1175
+ applyOptionParams(params);
1176
+ return true;
1024
1177
  }
1025
1178
  } catch (error) {
1026
- console.warn(error);
1179
+ setStatus(`Could not read shared state: ${formatError(error)}`, true);
1180
+ return false;
1027
1181
  }
1028
- setProgramValue(DEFAULT_PROGRAM);
1029
- statsToggle.checked = false;
1030
- proofToggle.checked = false;
1031
- currentProgramUrl = null;
1032
- currentProgramSource = null;
1033
- updateCommandPreview();
1182
+ return false;
1034
1183
  }
1035
1184
 
1036
-
1037
- async function loadVersion() {
1038
- if (!versionBadge || location.protocol === 'file:') return;
1039
- try {
1040
- const response = await fetch(new URL('./package.json', location.href), { cache: 'no-store' });
1041
- if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
1042
- const pkg = await response.json();
1043
- if (pkg && pkg.version) versionBadge.textContent = `eyelang ${pkg.version}`;
1044
- } catch (error) {
1045
- console.warn('Could not load eyelang package version:', error);
1046
- }
1185
+ async function restoreBackgroundUrl(params) {
1186
+ const url = params.get('background-url');
1187
+ if (!url) return;
1188
+ await loadSourceFromUrl(url, true);
1047
1189
  }
1048
1190
 
1049
- async function loadText(url) {
1050
- if (location.protocol === 'file:') {
1051
- throw new Error('Local file mode cannot fetch examples or module assets. Serve the directory over HTTP first.');
1052
- }
1053
- const response = await fetch(url, { cache: 'no-store' });
1191
+ async function loadSourceFromUrl(url, asBackground) {
1192
+ const response = await fetch(url);
1054
1193
  if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
1055
- return response.text();
1056
- }
1057
-
1058
- async function loadIntoEditor(url, asBackground = false, options = {}) {
1059
- setStatus(`Loading ${url}…`);
1060
- const source = await loadText(url);
1194
+ const text = await response.text();
1061
1195
  if (asBackground) {
1062
- backgroundPrograms.push({ name: url, source });
1063
- updateBackgroundNote();
1196
+ backgroundSource = text;
1197
+ backgroundName = url;
1198
+ backgroundReference = { kind: 'url', url };
1199
+ updateBackgroundStatus();
1064
1200
  } else {
1065
- setProgramValue(source.trimEnd());
1066
- currentProgramUrl = url;
1067
- currentProgramSource = programInput.value;
1068
- urlInput.value = url;
1069
- updateCommandPreview();
1070
- }
1071
- setStatus(`Loaded ${url}.`, 'ok');
1072
- if (options.save !== false) saveState();
1073
- }
1074
-
1075
- function setRunning(isRunning) {
1076
- // Keep Run clickable while the engine is preloading. A click will wait for
1077
- // preload to finish, which avoids the UI looking dead on slow first loads.
1078
- runButton.disabled = isRunning;
1079
- stopButton.disabled = !isRunning;
1080
- }
1081
-
1082
- function newRequestId() {
1083
- return crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random()}`;
1084
- }
1085
-
1086
- function localFileMessage() {
1087
- return [
1088
- 'This page is open as file://, so the browser cannot reliably load module workers or examples.',
1089
- '',
1090
- 'From the repository directory, run:',
1091
- '',
1092
- ' python3 -m http.server 8000',
1093
- '',
1094
- 'Then open:',
1095
- '',
1096
- ' http://localhost:8000/playground.html',
1097
- ].join('\n');
1098
- }
1099
-
1100
- function buildMissingMessage(error) {
1101
- return [
1102
- error && error.message ? error.message : String(error),
1103
- '',
1104
- 'Expected JavaScript playground files:',
1105
- '',
1106
- ' playground-worker.mjs',
1107
- ' src/index.js',
1108
- ' src/builtins/*.js',
1109
- '',
1110
- 'Serve the repository root over HTTP so browser module imports can resolve.',
1111
- ].join('\n');
1112
- }
1113
-
1114
- function formatWorkerError(error) {
1115
- const message = error && error.message ? String(error.message) : String(error);
1116
- if (/Maximum call stack size exceeded|call stack|stack overflow/i.test(message)) {
1117
- return [
1118
- message,
1119
- '',
1120
- 'eyelang exhausted the browser JavaScript call stack.',
1121
- 'Try a smaller example in the playground, or run this program with the Node CLI.',
1122
- ].join('\n');
1201
+ setSource(text, url, { kind: 'url', url });
1123
1202
  }
1124
- return buildMissingMessage(error);
1125
1203
  }
1126
1204
 
1127
- function handleWorkerMessage(event) {
1128
- const data = event.data || {};
1129
-
1130
- if (data.type === 'ready') {
1131
- workerReady = true;
1132
- workerLoadError = null;
1133
- preloadResolve?.();
1134
- setRunning(false);
1135
- if (!currentRunId) setStatus('Engine ready.', 'ok');
1136
- return;
1137
- }
1138
-
1139
- if (data.type === 'init-error') {
1140
- workerReady = false;
1141
- workerLoadError = data.stderr || 'JavaScript engine could not be loaded.';
1142
- preloadReject?.(new Error(workerLoadError));
1143
- setRunOutput('', buildMissingMessage(new Error(workerLoadError)));
1144
- setStatus('JavaScript engine could not be loaded.', 'error');
1145
- setRunning(false);
1146
- return;
1147
- }
1148
-
1149
- if (data.type !== 'result' || data.id !== currentRunId) return;
1150
-
1151
- const elapsed = Math.max(1, Math.round(performance.now() - runStarted));
1152
- setRunOutput(data.stdout || '', data.stderr || '');
1153
- if (data.exitCode === 0) {
1154
- setStatus(`Finished in ${elapsed} ms.`, 'ok');
1155
- } else {
1156
- setStatus(`Failed while ${data.phase}.`, 'error');
1157
- showTab('stderr');
1158
- }
1159
- currentRunId = null;
1160
- setRunning(false);
1161
- }
1162
-
1163
- function handleWorkerError(error) {
1164
- setRunOutput('', formatWorkerError(error));
1165
- setStatus('JavaScript engine could not be loaded.', 'error');
1166
- currentRunId = null;
1167
- workerReady = false;
1168
- workerLoadError = formatWorkerError(error);
1169
- setRunning(false);
1170
- preloadReject?.(new Error(workerLoadError));
1171
- worker?.terminate();
1172
- worker = null;
1173
- }
1174
-
1175
- function startPlaygroundWorker(statusText = 'Loading engine…') {
1176
- if (location.protocol === 'file:') return Promise.reject(new Error(localFileMessage()));
1177
-
1178
- if (worker) worker.terminate();
1179
- worker = null;
1180
- workerReady = false;
1181
- workerLoadError = null;
1182
- currentRunId = null;
1183
- setRunning(false);
1184
- setStatus(statusText);
1185
-
1186
- preloadPromise = new Promise((resolve, reject) => {
1187
- preloadResolve = resolve;
1188
- preloadReject = reject;
1189
- });
1190
-
1191
- try {
1192
- worker = new Worker(workerUrl, { type: 'module' });
1193
- } catch (error) {
1194
- handleWorkerError(error);
1195
- return preloadPromise;
1196
- }
1197
-
1198
- worker.onmessage = handleWorkerMessage;
1199
- worker.onerror = handleWorkerError;
1200
- worker.postMessage({ type: 'init', id: newRequestId() });
1201
- return preloadPromise;
1205
+ function applySharedState(payload, label) {
1206
+ setSource(String(payload.source || ''), label, { kind: 'custom' });
1207
+ proof.checked = Boolean(payload.proof);
1208
+ stats.checked = Boolean(payload.stats);
1209
+ backgroundSource = String(payload.backgroundSource || '');
1210
+ backgroundName = String(payload.backgroundName || 'shared background');
1211
+ backgroundReference = null;
1212
+ updateBackgroundStatus();
1202
1213
  }
1203
1214
 
1204
- async function runEyelang() {
1205
- if (location.protocol === 'file:') {
1206
- setRunOutput('', localFileMessage());
1207
- setStatus('Serve the playground over HTTP first.', 'error');
1208
- return;
1209
- }
1210
-
1211
- if (currentRunId) return;
1212
- if (!worker || !preloadPromise) startPlaygroundWorker();
1213
-
1214
- if (!workerReady) {
1215
- if (workerLoadError) {
1216
- setRunOutput('', buildMissingMessage(new Error(workerLoadError)));
1217
- setStatus('JavaScript engine could not be loaded.', 'error');
1218
- return;
1219
- }
1220
- try {
1221
- setStatus('Finishing engine load…');
1222
- await preloadPromise;
1223
- } catch (_) {
1224
- return;
1225
- }
1226
- }
1227
-
1228
- runStarted = performance.now();
1229
- clearErrorLine();
1230
- setOutputText('Running…');
1231
- setStatus('Running eyelang…');
1232
- currentRunId = newRequestId();
1233
- setRunning(true);
1234
-
1235
- worker.postMessage({
1236
- type: 'run',
1237
- id: currentRunId,
1238
- program: combinedProgram(),
1239
- stats: statsToggle.checked,
1240
- proof: proofToggle.checked,
1241
- });
1215
+ function applyOptionParams(params) {
1216
+ proof.checked = params.get('proof') === '1' || params.get('proof') === 'true';
1217
+ stats.checked = params.get('stats') === '1' || params.get('stats') === 'true';
1242
1218
  }
1243
1219
 
1244
- async function copyText(text) {
1245
- if (navigator.clipboard && window.isSecureContext) {
1246
- await navigator.clipboard.writeText(text);
1247
- return 'clipboard';
1248
- }
1249
-
1250
- const textarea = document.createElement('textarea');
1251
- textarea.value = text;
1252
- textarea.setAttribute('readonly', '');
1253
- textarea.style.position = 'fixed';
1254
- textarea.style.top = '0';
1255
- textarea.style.left = '-9999px';
1256
- document.body.append(textarea);
1257
- textarea.focus();
1258
- textarea.select();
1259
-
1220
+ async function loadVersion() {
1260
1221
  try {
1261
- if (document.execCommand && document.execCommand('copy')) {
1262
- return 'fallback';
1263
- }
1264
- } finally {
1265
- textarea.remove();
1266
- }
1267
-
1268
- window.prompt('Copy this eyelang playground link:', text);
1269
- return 'manual';
1270
- }
1271
-
1272
- function currentProgramStillMatchesUrl() {
1273
- return currentProgramUrl &&
1274
- currentProgramSource !== null &&
1275
- programInput.value === currentProgramSource &&
1276
- backgroundPrograms.length === 0;
1277
- }
1278
-
1279
- function markProgramEdited() {
1280
- if (currentProgramUrl && programInput.value !== currentProgramSource) {
1281
- currentProgramUrl = null;
1282
- currentProgramSource = null;
1222
+ const response = await fetch('package.json', { cache: 'no-store' });
1223
+ if (!response.ok) return;
1224
+ const pkg = await response.json();
1225
+ if (pkg.version) document.querySelector('#version').textContent = `eyelang v${pkg.version}`;
1226
+ } catch (_) {
1227
+ // Package metadata is optional when the page is copied elsewhere.
1283
1228
  }
1284
- saveState();
1285
1229
  }
1286
1230
 
1287
- async function copyShareLink() {
1288
- const url = new URL(location.href);
1289
- url.hash = '';
1290
-
1291
- if (currentProgramStillMatchesUrl()) {
1292
- url.search = '';
1293
- url.searchParams.set('url', currentProgramUrl);
1294
- if (statsToggle.checked) url.searchParams.set('stats', '1');
1295
- if (proofToggle.checked) url.searchParams.set('proof', '1');
1296
- } else {
1297
- const params = new URLSearchParams();
1298
- params.set('p', encodePayload(programInput.value));
1299
- if (statsToggle.checked) params.set('s', '1');
1300
- if (proofToggle.checked) params.set('r', '1');
1301
- url.search = '';
1302
- url.hash = params.toString();
1303
- }
1304
-
1305
- const method = await copyText(url.href);
1306
- setStatus(method === 'manual' ? 'Share link shown for manual copy.' : 'Share link copied.', 'ok');
1307
- }
1308
-
1309
- loadExampleButton.addEventListener('click', () => loadIntoEditor(`examples/${exampleSelect.value}.pl`, false).catch(error => setStatus(error.message, 'error')));
1310
- resetButton.addEventListener('click', () => {
1311
- setProgramValue(DEFAULT_PROGRAM);
1312
- statsToggle.checked = false;
1313
- proofToggle.checked = false;
1314
- backgroundPrograms = [];
1315
- currentProgramUrl = null;
1316
- currentProgramSource = null;
1317
- urlInput.value = '';
1318
- updateBackgroundNote();
1319
- updateCommandPreview();
1320
- setOutputText('(no output yet)');
1321
- setStatus('Reset to the built-in Socrates example.', 'ok');
1322
- saveState();
1323
- });
1324
- loadUrlButton.addEventListener('click', () => {
1325
- const url = urlInput.value.trim();
1326
- if (!url) return setStatus('Enter a URL first.', 'error');
1327
- loadIntoEditor(url, backgroundToggle.checked).catch(error => setStatus(`Could not load URL: ${error.message}`, 'error'));
1328
- });
1329
- runButton.addEventListener('click', runEyelang);
1330
- stopButton.addEventListener('click', () => {
1331
- if (worker) {
1332
- worker.terminate();
1333
- worker = null;
1334
- }
1335
- currentRunId = null;
1336
- workerReady = false;
1337
- setRunning(false);
1338
- setStatus('Stopped. Reloading engine…', 'error');
1339
- startPlaygroundWorker('Reloading engine…').catch(() => {});
1340
- });
1341
- copyLinkButton.addEventListener('click', () => copyShareLink().catch(error => setStatus(`Could not copy link: ${error.message}`, 'error')));
1342
- clearSavedButton.addEventListener('click', () => {
1343
- localStorage.removeItem(STORAGE_KEY);
1344
- localStorage.removeItem('eyelang.playground.v6');
1345
- localStorage.removeItem('eyelang.playground.v5');
1346
- localStorage.removeItem('eyelang.playground.v4');
1347
- localStorage.removeItem('eyelang.playground.v3');
1348
- localStorage.removeItem('eyelang.playground.v2');
1349
- localStorage.removeItem('eyelang.playground.v1');
1350
- setStatus('Autosave cleared.', 'ok');
1351
- });
1352
- programInput.addEventListener('input', () => { clearErrorLine(); updateProgramSyntax(); markProgramEdited(); });
1353
- programInput.addEventListener('scroll', updateProgramHighlight);
1354
- combinedOutput.addEventListener('scroll', () => { outputGutter.scrollTop = combinedOutput.scrollTop; });
1355
- statsToggle.addEventListener('change', saveState);
1356
- proofToggle.addEventListener('change', saveState);
1357
-
1358
- async function initializePage() {
1359
- updateProgramHighlight();
1360
- setOutputText('(no output yet)');
1361
- loadVersion();
1362
- await restoreState();
1363
- updateCommandPreview();
1364
- if (location.protocol === 'file:') {
1365
- fileProtocolNotice.classList.remove('hidden');
1366
- setStatus('Serve over HTTP before running.', 'error');
1367
- } else {
1368
- startPlaygroundWorker().catch(() => {});
1369
- }
1231
+ function setStatus(message, isError = false) {
1232
+ status.textContent = message;
1233
+ status.classList.toggle('error', isError);
1370
1234
  }
1371
1235
 
1372
- initializePage();
1236
+ function formatError(error) { return error?.message || String(error); }
1373
1237
  </script>
1374
1238
  </body>
1375
1239
  </html>