eyelang 1.7.4 → 1.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/README.md +1 -0
  2. package/conformance-report.md +26 -0
  3. package/docs/guide.md +5 -2
  4. package/docs/language-reference.md +1 -1
  5. package/package.json +3 -2
  6. package/test/conformance/README.md +11 -5
  7. package/test/conformance/cases/aggregation/aggregate_max_no_answers_fails.eye +2 -0
  8. package/test/conformance/cases/aggregation/aggregate_min_structured_key.eye +5 -0
  9. package/test/conformance/cases/aggregation/countall_zero.eye +2 -0
  10. package/test/conformance/cases/aggregation/findall_empty_bag.eye +2 -0
  11. package/test/conformance/cases/aggregation/sumall_empty_zero.eye +2 -0
  12. package/test/conformance/cases/arithmetic/between_bound_value.eye +2 -0
  13. package/test/conformance/cases/arithmetic/between_singleton.eye +2 -0
  14. package/test/conformance/cases/arithmetic/duration_comparison.eye +2 -0
  15. package/test/conformance/cases/arithmetic/float_add_and_div.eye +3 -0
  16. package/test/conformance/cases/arithmetic/min_max_mixed.eye +3 -0
  17. package/test/conformance/cases/arithmetic/mod_negative_left.eye +2 -0
  18. package/test/conformance/cases/arithmetic/neg_abs_integer.eye +4 -0
  19. package/test/conformance/cases/arithmetic/pow_negative_exponent_fails.eye +2 -0
  20. package/test/conformance/cases/arithmetic/pow_zero_exponent.eye +2 -0
  21. package/test/conformance/cases/arithmetic/rounding_negative_float.eye +5 -0
  22. package/test/conformance/cases/arithmetic/smallest_divisor_prime.eye +2 -0
  23. package/test/conformance/cases/arithmetic/sqrt_negative_fails.eye +2 -0
  24. package/test/conformance/cases/atoms/angle_iri_percent_encoded.eye +2 -0
  25. package/test/conformance/cases/atoms/graphic_atom_predicate.eye +3 -0
  26. package/test/conformance/cases/atoms/iri_as_predicate_name_quoted.eye +3 -0
  27. package/test/conformance/cases/atoms/quoted_relative_iri_not_angle.eye +2 -0
  28. package/test/conformance/cases/context/holds_compound_formula.eye +2 -0
  29. package/test/conformance/cases/context/holds_fails_when_missing.eye +2 -0
  30. package/test/conformance/cases/context/holds_parts_from_formula.eye +2 -0
  31. package/test/conformance/cases/control/double_negation_ground_goal.eye +3 -0
  32. package/test/conformance/cases/control/forall_detects_counterexample.eye +5 -0
  33. package/test/conformance/cases/control/forall_empty_generator_true.eye +2 -0
  34. package/test/conformance/cases/control/negation_with_bound_generator.eye +5 -0
  35. package/test/conformance/cases/control/once_keeps_first_answer.eye +4 -0
  36. package/test/conformance/cases/declarations/det_semidet_do_not_emit_without_materialize.eye +5 -0
  37. package/test/conformance/cases/lists/head_rest_last.eye +4 -0
  38. package/test/conformance/cases/lists/length_empty_and_nested.eye +3 -0
  39. package/test/conformance/cases/lists/list_to_set_structural_duplicates.eye +2 -0
  40. package/test/conformance/cases/lists/min_list_empty_fails.eye +2 -0
  41. package/test/conformance/cases/lists/nth0_known_value.eye +2 -0
  42. package/test/conformance/cases/lists/nth0_out_of_range_fails.eye +2 -0
  43. package/test/conformance/cases/lists/reverse_empty.eye +2 -0
  44. package/test/conformance/cases/lists/select_all_occurrences.eye +2 -0
  45. package/test/conformance/cases/lists/set_nth0_middle.eye +2 -0
  46. package/test/conformance/cases/lists/slice_middle.eye +2 -0
  47. package/test/conformance/cases/lists/slice_out_of_range_fails.eye +2 -0
  48. package/test/conformance/cases/lists/sort_structured_terms.eye +2 -0
  49. package/test/conformance/cases/lists/sum_list_empty_zero.eye +2 -0
  50. package/test/conformance/cases/lists/sum_min_max_list.eye +4 -0
  51. package/test/conformance/cases/lists/take_zero_and_drop_all.eye +3 -0
  52. package/test/conformance/cases/materialize/arity_specific_outputs.eye +4 -0
  53. package/test/conformance/cases/rules/left_to_right_body_binding.eye +4 -0
  54. package/test/conformance/cases/rules/transitive_rule_three_edges.eye +7 -0
  55. package/test/conformance/cases/strings/atom_string_from_string.eye +2 -0
  56. package/test/conformance/cases/strings/casefold_atoms.eye +3 -0
  57. package/test/conformance/cases/strings/contains_empty_needle.eye +2 -0
  58. package/test/conformance/cases/strings/join_mixed_scalars.eye +2 -0
  59. package/test/conformance/cases/strings/matches_simple_alternation.eye +2 -0
  60. package/test/conformance/cases/strings/named_regex_two_groups.eye +2 -0
  61. package/test/conformance/cases/strings/not_matches_simple_pattern.eye +2 -0
  62. package/test/conformance/cases/strings/number_string_from_string.eye +2 -0
  63. package/test/conformance/cases/strings/number_string_rejects_non_numeric.eye +2 -0
  64. package/test/conformance/cases/strings/replace_empty_search_no_change.eye +2 -0
  65. package/test/conformance/cases/strings/split_without_separator_match.eye +2 -0
  66. package/test/conformance/cases/strings/substring_out_of_range_fails.eye +2 -0
  67. package/test/conformance/cases/strings/substring_zero_count.eye +2 -0
  68. package/test/conformance/cases/strings/term_string_nested_term.eye +2 -0
  69. package/test/conformance/cases/strings/trim_tabs_and_spaces.eye +3 -0
  70. package/test/conformance/cases/syntax/comments_inside_program.eye +4 -0
  71. package/test/conformance/cases/syntax/quoted_atom_with_newline_escape.eye +3 -0
  72. package/test/conformance/cases/syntax/string_with_tab_escape.eye +2 -0
  73. package/test/conformance/cases/table/tabled_left_recursion_path.eye +7 -0
  74. package/test/conformance/cases/terms/arg_first_and_second.eye +3 -0
  75. package/test/conformance/cases/terms/arg_zero_fails.eye +2 -0
  76. package/test/conformance/cases/terms/compound_name_arguments_bad_args_fail.eye +2 -0
  77. package/test/conformance/cases/terms/compound_name_arguments_builds_compound.eye +2 -0
  78. package/test/conformance/cases/terms/compound_name_arguments_iri_name.eye +2 -0
  79. package/test/conformance/cases/terms/functor_number_and_string.eye +3 -0
  80. package/test/conformance/cases/terms/term_string_readback_iri_list.eye +2 -0
  81. package/test/conformance/cases/unification/compound_arity_mismatch_fails.eye +2 -0
  82. package/test/conformance/cases/unification/list_tail_binding.eye +2 -0
  83. package/test/conformance/cases/unification/nested_repeated_variable.eye +2 -0
  84. package/test/conformance/cases/unification/scalar_cross_type_same_lexical_value.eye +3 -0
  85. package/test/conformance/cases/variables/clause_local_variable_names.eye +5 -0
  86. package/test/conformance/cases/variables/question_variable_digits_and_underscore.eye +2 -4
  87. package/test/conformance/cases/variables/question_variable_uppercase_name.eye +2 -0
  88. package/test/conformance/errors/atoms/hash_comment_not_atom_at_line_start.eye +1 -0
  89. package/test/conformance/errors/lists/missing_list_tail.eye +1 -0
  90. package/test/conformance/errors/rules/rule_head_cannot_be_empty_parentheses.eye +1 -0
  91. package/test/conformance/errors/syntax/angle_iri_with_space_rejected.eye +1 -0
  92. package/test/conformance/errors/syntax/bad_question_digit_variable.eye +1 -0
  93. package/test/conformance/errors/syntax/bad_question_variable.eye +1 -0
  94. package/test/conformance/errors/syntax/empty_body_after_rule_marker.eye +1 -0
  95. package/test/conformance/errors/syntax/empty_compound_nested.eye +1 -0
  96. package/test/conformance/errors/syntax/missing_period.eye +1 -0
  97. package/test/conformance/errors/syntax/relative_angle_iri_rejected.eye +1 -0
  98. package/test/conformance/errors/syntax/trailing_comma_in_body.eye +1 -0
  99. package/test/conformance/errors/syntax/unclosed_compound.eye +1 -0
  100. package/test/conformance/errors/syntax/unclosed_list.eye +1 -0
  101. package/test/conformance/errors/syntax/unclosed_quoted_atom.eye +1 -0
  102. package/test/conformance/errors/syntax/unclosed_string.eye +1 -0
  103. package/test/conformance/errors/syntax/unquoted_colon_predicate.eye +1 -0
  104. package/test/conformance/errors/syntax/unquoted_dotted_predicate.eye +1 -0
  105. package/test/conformance/errors/variables/bare_underscore_in_list_rejected.eye +1 -0
  106. package/test/conformance/errors/variables/bare_underscore_name_in_compound_rejected.eye +1 -0
  107. package/test/conformance/errors/variables/uppercase_in_body_rejected.eye +1 -0
  108. package/test/conformance/expected/aggregation/aggregate_max_no_answers_fails.eye +1 -0
  109. package/test/conformance/expected/aggregation/aggregate_min_structured_key.eye +1 -0
  110. package/test/conformance/expected/aggregation/countall_zero.eye +1 -0
  111. package/test/conformance/expected/aggregation/findall_empty_bag.eye +1 -0
  112. package/test/conformance/expected/aggregation/sumall_empty_zero.eye +1 -0
  113. package/test/conformance/expected/arithmetic/between_bound_value.eye +1 -0
  114. package/test/conformance/expected/arithmetic/between_singleton.eye +1 -0
  115. package/test/conformance/expected/arithmetic/duration_comparison.eye +1 -0
  116. package/test/conformance/expected/arithmetic/float_add_and_div.eye +2 -0
  117. package/test/conformance/expected/arithmetic/min_max_mixed.eye +2 -0
  118. package/test/conformance/expected/arithmetic/mod_negative_left.eye +1 -0
  119. package/test/conformance/expected/arithmetic/neg_abs_integer.eye +2 -0
  120. package/test/conformance/expected/arithmetic/pow_negative_exponent_fails.eye +1 -0
  121. package/test/conformance/expected/arithmetic/pow_zero_exponent.eye +1 -0
  122. package/test/conformance/expected/arithmetic/rounding_negative_float.eye +4 -0
  123. package/test/conformance/expected/arithmetic/smallest_divisor_prime.eye +1 -0
  124. package/test/conformance/expected/arithmetic/sqrt_negative_fails.eye +1 -0
  125. package/test/conformance/expected/atoms/angle_iri_percent_encoded.eye +0 -0
  126. package/test/conformance/expected/atoms/graphic_atom_predicate.eye +1 -0
  127. package/test/conformance/expected/atoms/iri_as_predicate_name_quoted.eye +1 -0
  128. package/test/conformance/expected/atoms/quoted_relative_iri_not_angle.eye +0 -0
  129. package/test/conformance/expected/context/holds_compound_formula.eye +1 -0
  130. package/test/conformance/expected/context/holds_fails_when_missing.eye +1 -0
  131. package/test/conformance/expected/context/holds_parts_from_formula.eye +2 -0
  132. package/test/conformance/expected/control/double_negation_ground_goal.eye +1 -0
  133. package/test/conformance/expected/control/forall_detects_counterexample.eye +1 -0
  134. package/test/conformance/expected/control/forall_empty_generator_true.eye +1 -0
  135. package/test/conformance/expected/control/negation_with_bound_generator.eye +1 -0
  136. package/test/conformance/expected/control/once_keeps_first_answer.eye +1 -0
  137. package/test/conformance/expected/declarations/det_semidet_do_not_emit_without_materialize.eye +1 -0
  138. package/test/conformance/expected/lists/head_rest_last.eye +3 -0
  139. package/test/conformance/expected/lists/length_empty_and_nested.eye +2 -0
  140. package/test/conformance/expected/lists/list_to_set_structural_duplicates.eye +1 -0
  141. package/test/conformance/expected/lists/min_list_empty_fails.eye +1 -0
  142. package/test/conformance/expected/lists/nth0_known_value.eye +1 -0
  143. package/test/conformance/expected/lists/nth0_out_of_range_fails.eye +1 -0
  144. package/test/conformance/expected/lists/reverse_empty.eye +1 -0
  145. package/test/conformance/expected/lists/select_all_occurrences.eye +3 -0
  146. package/test/conformance/expected/lists/set_nth0_middle.eye +1 -0
  147. package/test/conformance/expected/lists/slice_middle.eye +0 -0
  148. package/test/conformance/expected/lists/slice_out_of_range_fails.eye +1 -0
  149. package/test/conformance/expected/lists/sort_structured_terms.eye +1 -0
  150. package/test/conformance/expected/lists/sum_list_empty_zero.eye +1 -0
  151. package/test/conformance/expected/lists/sum_min_max_list.eye +3 -0
  152. package/test/conformance/expected/lists/take_zero_and_drop_all.eye +2 -0
  153. package/test/conformance/expected/materialize/arity_specific_outputs.eye +0 -0
  154. package/test/conformance/expected/rules/left_to_right_body_binding.eye +1 -0
  155. package/test/conformance/expected/rules/transitive_rule_three_edges.eye +6 -0
  156. package/test/conformance/expected/strings/atom_string_from_string.eye +1 -0
  157. package/test/conformance/expected/strings/casefold_atoms.eye +2 -0
  158. package/test/conformance/expected/strings/contains_empty_needle.eye +1 -0
  159. package/test/conformance/expected/strings/join_mixed_scalars.eye +1 -0
  160. package/test/conformance/expected/strings/matches_simple_alternation.eye +1 -0
  161. package/test/conformance/expected/strings/named_regex_two_groups.eye +1 -0
  162. package/test/conformance/expected/strings/not_matches_simple_pattern.eye +1 -0
  163. package/test/conformance/expected/strings/number_string_from_string.eye +1 -0
  164. package/test/conformance/expected/strings/number_string_rejects_non_numeric.eye +1 -0
  165. package/test/conformance/expected/strings/replace_empty_search_no_change.eye +1 -0
  166. package/test/conformance/expected/strings/split_without_separator_match.eye +1 -0
  167. package/test/conformance/expected/strings/substring_out_of_range_fails.eye +1 -0
  168. package/test/conformance/expected/strings/substring_zero_count.eye +1 -0
  169. package/test/conformance/expected/strings/term_string_nested_term.eye +1 -0
  170. package/test/conformance/expected/strings/trim_tabs_and_spaces.eye +1 -0
  171. package/test/conformance/expected/syntax/comments_inside_program.eye +0 -0
  172. package/test/conformance/expected/syntax/quoted_atom_with_newline_escape.eye +0 -0
  173. package/test/conformance/expected/syntax/string_with_tab_escape.eye +0 -0
  174. package/test/conformance/expected/table/tabled_left_recursion_path.eye +1 -0
  175. package/test/conformance/expected/terms/arg_first_and_second.eye +2 -0
  176. package/test/conformance/expected/terms/arg_zero_fails.eye +1 -0
  177. package/test/conformance/expected/terms/compound_name_arguments_bad_args_fail.eye +1 -0
  178. package/test/conformance/expected/terms/compound_name_arguments_builds_compound.eye +1 -0
  179. package/test/conformance/expected/terms/compound_name_arguments_iri_name.eye +1 -0
  180. package/test/conformance/expected/terms/functor_number_and_string.eye +2 -0
  181. package/test/conformance/expected/terms/term_string_readback_iri_list.eye +1 -0
  182. package/test/conformance/expected/unification/compound_arity_mismatch_fails.eye +1 -0
  183. package/test/conformance/expected/unification/list_tail_binding.eye +1 -0
  184. package/test/conformance/expected/unification/nested_repeated_variable.eye +1 -0
  185. package/test/conformance/expected/unification/scalar_cross_type_same_lexical_value.eye +2 -0
  186. package/test/conformance/expected/variables/clause_local_variable_names.eye +2 -0
  187. package/test/conformance/expected/variables/question_variable_digits_and_underscore.eye +1 -1
  188. package/test/conformance/expected/variables/question_variable_uppercase_name.eye +1 -0
  189. package/test/conformance/expected-errors/atoms/hash_comment_not_atom_at_line_start.txt +1 -0
  190. package/test/conformance/expected-errors/lists/missing_list_tail.txt +1 -0
  191. package/test/conformance/expected-errors/rules/rule_head_cannot_be_empty_parentheses.txt +1 -0
  192. package/test/conformance/expected-errors/syntax/angle_iri_with_space_rejected.txt +1 -0
  193. package/test/conformance/expected-errors/syntax/bad_question_digit_variable.txt +1 -0
  194. package/test/conformance/expected-errors/syntax/bad_question_variable.txt +1 -0
  195. package/test/conformance/expected-errors/syntax/empty_body_after_rule_marker.txt +1 -0
  196. package/test/conformance/expected-errors/syntax/empty_compound_nested.txt +1 -0
  197. package/test/conformance/expected-errors/syntax/missing_period.txt +1 -0
  198. package/test/conformance/expected-errors/syntax/relative_angle_iri_rejected.txt +1 -0
  199. package/test/conformance/expected-errors/syntax/trailing_comma_in_body.txt +1 -0
  200. package/test/conformance/expected-errors/syntax/unclosed_compound.txt +1 -0
  201. package/test/conformance/expected-errors/syntax/unclosed_list.txt +1 -0
  202. package/test/conformance/expected-errors/syntax/unclosed_quoted_atom.txt +1 -0
  203. package/test/conformance/expected-errors/syntax/unclosed_string.txt +1 -0
  204. package/test/conformance/expected-errors/syntax/unquoted_colon_predicate.txt +1 -0
  205. package/test/conformance/expected-errors/syntax/unquoted_dotted_predicate.txt +1 -0
  206. package/test/conformance/expected-errors/variables/bare_underscore_in_list_rejected.txt +1 -0
  207. package/test/conformance/expected-errors/variables/bare_underscore_name_in_compound_rejected.txt +1 -0
  208. package/test/conformance/expected-errors/variables/uppercase_in_body_rejected.txt +1 -0
  209. package/test/conformance/expected-proofs/proofs/bindings_nested_term.eye +16 -0
  210. package/test/conformance/expected-proofs/proofs/builtin_numeric.eye +16 -0
  211. package/test/conformance/expected-proofs/proofs/conjunction_order.eye +19 -0
  212. package/test/conformance/expected-proofs/proofs/iri_atom.eye +16 -0
  213. package/test/conformance/expected-proofs/proofs/list_builtin.eye +20 -0
  214. package/test/conformance/expected-proofs/proofs/once_child.eye +22 -0
  215. package/test/conformance/expected-proofs/proofs/rule_fact.eye +16 -0
  216. package/test/conformance/expected-proofs/proofs/table_recursive.eye +59 -0
  217. package/test/conformance/expected-warnings/negation/stratified_negative_unknown_after_positive_quiet.eye +1 -0
  218. package/test/conformance/expected-warnings/negation/stratified_negative_unknown_after_positive_quiet.txt +0 -0
  219. package/test/conformance/expected-warnings/negation/stratified_two_level_quiet.eye +1 -0
  220. package/test/conformance/expected-warnings/negation/stratified_two_level_quiet.txt +0 -0
  221. package/test/conformance/expected-warnings/negation/unstratified_positive_prefix.eye +0 -0
  222. package/test/conformance/expected-warnings/negation/unstratified_positive_prefix.txt +2 -0
  223. package/test/conformance/expected-warnings/negation/unstratified_two_arity_cycle.eye +0 -0
  224. package/test/conformance/expected-warnings/negation/unstratified_two_arity_cycle.txt +3 -0
  225. package/test/conformance/expected-warnings/negation/unstratified_two_independent_cycles.eye +0 -0
  226. package/test/conformance/expected-warnings/negation/unstratified_two_independent_cycles.txt +5 -0
  227. package/test/conformance/expected-warnings/negation/unstratified_with_iri_predicates.eye +0 -0
  228. package/test/conformance/expected-warnings/negation/unstratified_with_iri_predicates.txt +3 -0
  229. package/test/conformance/expected-warnings/negation/warning_preserves_multiple_stdout_answers.eye +0 -0
  230. package/test/conformance/expected-warnings/negation/warning_preserves_multiple_stdout_answers.txt +3 -0
  231. package/test/conformance/proofs/proofs/bindings_nested_term.eye +4 -0
  232. package/test/conformance/proofs/proofs/builtin_numeric.eye +3 -0
  233. package/test/conformance/proofs/proofs/conjunction_order.eye +5 -0
  234. package/test/conformance/proofs/proofs/iri_atom.eye +4 -0
  235. package/test/conformance/proofs/proofs/list_builtin.eye +3 -0
  236. package/test/conformance/proofs/proofs/once_child.eye +5 -0
  237. package/test/conformance/proofs/proofs/rule_fact.eye +4 -0
  238. package/test/conformance/proofs/proofs/table_recursive.eye +7 -0
  239. package/test/conformance/warnings/negation/stratified_negative_unknown_after_positive_quiet.eye +3 -0
  240. package/test/conformance/warnings/negation/stratified_two_level_quiet.eye +5 -0
  241. package/test/conformance/warnings/negation/unstratified_positive_prefix.eye +5 -0
  242. package/test/conformance/warnings/negation/unstratified_two_arity_cycle.eye +4 -0
  243. package/test/conformance/warnings/negation/unstratified_two_independent_cycles.eye +6 -0
  244. package/test/conformance/warnings/negation/unstratified_with_iri_predicates.eye +4 -0
  245. package/test/conformance/warnings/negation/warning_preserves_multiple_stdout_answers.eye +5 -0
  246. package/test/run-conformance-report.mjs +19 -7
  247. package/test/run-conformance.mjs +29 -0
  248. package/test/run-regression.mjs +12 -2
package/README.md CHANGED
@@ -63,6 +63,7 @@ python3 -m http.server
63
63
  npm test
64
64
  npm run test:conformance
65
65
  npm run conformance:report
66
+ # release preparation writes conformance-report.md via the preversion script
66
67
  npm run test:examples
67
68
  npm run test:regression
68
69
  ```
@@ -0,0 +1,26 @@
1
+ # Conformance Eyelang report
2
+
3
+ This report summarizes the file-based conformance corpus under `test/conformance/`.
4
+
5
+ | Category | Positive | Errors | Warnings | Proofs | Total |
6
+ |---|---:|---:|---:|---:|---:|
7
+ | aggregation | 5 | 0 | 0 | 0 | 5 |
8
+ | arithmetic | 12 | 0 | 0 | 0 | 12 |
9
+ | atoms | 14 | 5 | 0 | 0 | 19 |
10
+ | builtins | 2 | 0 | 0 | 0 | 2 |
11
+ | context | 3 | 0 | 0 | 0 | 3 |
12
+ | control | 5 | 0 | 0 | 0 | 5 |
13
+ | declarations | 5 | 0 | 0 | 0 | 5 |
14
+ | legacy-numbered | 104 | 0 | 0 | 0 | 104 |
15
+ | lists | 18 | 1 | 0 | 0 | 19 |
16
+ | materialize | 2 | 0 | 0 | 0 | 2 |
17
+ | negation | 3 | 0 | 13 | 0 | 16 |
18
+ | proofs | 0 | 0 | 0 | 8 | 8 |
19
+ | rules | 2 | 1 | 0 | 0 | 3 |
20
+ | strings | 15 | 0 | 0 | 0 | 15 |
21
+ | syntax | 4 | 19 | 0 | 0 | 23 |
22
+ | table | 2 | 0 | 0 | 0 | 2 |
23
+ | terms | 10 | 1 | 0 | 0 | 11 |
24
+ | unification | 4 | 0 | 0 | 0 | 4 |
25
+ | variables | 8 | 8 | 0 | 0 | 16 |
26
+ | **Total** | **218** | **35** | **13** | **8** | **274** |
package/docs/guide.md CHANGED
@@ -503,7 +503,9 @@ Summarize the conformance corpus by category:
503
503
  npm run conformance:report
504
504
  ```
505
505
 
506
- The conformance suite lives in [`test/conformance/`](../test/conformance/) as a file-based eyelang corpus. Positive cases pair `cases/<name>.eye` with exact expected stdout under `expected/<name>.eye`; negative cases pair `errors/<name>.eye` with exact expected error text under `expected-errors/<name>.txt`; warning cases pair `warnings/<name>.eye` with exact `--warnings` stdout and stderr files under `expected-warnings/`. Cases may be grouped in category directories such as `atoms/`, `variables/`, `negation/`, and `syntax/`, so another implementation can reuse the same corpus as an executable language contract. The suite covers the standard language surface from the language reference, including reusable built-ins, standard errors, and standard warnings. The regression suite lives in [`test/run-regression.mjs`](../test/run-regression.mjs) and covers CLI regressions, the public JavaScript API, and white-box invariants for parser, unification, and indexing behavior.
506
+ Release preparation runs the same report and writes [`conformance-report.md`](../conformance-report.md), so each published package carries a current conformance summary.
507
+
508
+ The conformance suite lives in [`test/conformance/`](../test/conformance/) as a file-based eyelang corpus. Positive cases pair `cases/<name>.eye` with exact expected stdout under `expected/<name>.eye`; negative cases pair `errors/<name>.eye` with exact expected error text under `expected-errors/<name>.txt`; warning cases pair `warnings/<name>.eye` with exact `--warnings` stdout and stderr files under `expected-warnings/`; proof cases pair `proofs/<name>.eye` with exact `--proof` output under `expected-proofs/`. Cases may be grouped in category directories such as `arithmetic/`, `strings/`, `lists/`, `terms/`, `atoms/`, `variables/`, `negation/`, and `syntax/`, so another implementation can reuse the same corpus as an executable language contract. The suite covers the standard language surface from the language reference, including reusable built-ins, standard errors, standard warnings, and the machine-readable `why/2` proof-output contract. The regression suite lives in [`test/run-regression.mjs`](../test/run-regression.mjs) and covers CLI regressions, the public JavaScript API, and white-box invariants for parser, unification, and indexing behavior.
507
509
 
508
510
  ## Development and release
509
511
 
@@ -531,7 +533,8 @@ For a release:
531
533
  2. update `README.md` and the language reference;
532
534
  3. regenerate golden outputs if behavior changed;
533
535
  4. run `npm run test:eyelang`;
534
- 5. publish the repository with the browser playground assets if publishing the playground. The playground includes controls equivalent to CLI `--stats` and `--proof`.
536
+ 5. run `npm run conformance:report -- conformance-report.md`;
537
+ 6. publish the repository with the browser playground assets if publishing the playground. The playground includes controls equivalent to CLI `--stats` and `--proof`.
535
538
 
536
539
  ## Relationship to Eyeling
537
540
 
@@ -702,7 +702,7 @@ A conforming eyelang implementation supports the standard language described abo
702
702
 
703
703
  Browser execution, package layout, CLI URL loading, and any implementation-specific built-ins described in host documentation are outside this conformance surface unless separately standardized.
704
704
 
705
- Conformance cases live in the repository under `test/conformance/`. They are run by `npm test` before the example suite, and can be run alone with `node test/run-conformance.mjs`. Positive cases have input programs under `conformance/cases/` and exact expected standard-output files under `conformance/expected/`; both use `.eye` so expected output remains eyelang-readable. Expected-error cases live under `conformance/errors/` with exact messages under `conformance/expected-errors/`. Expected-warning cases live under `conformance/warnings/` with exact `--warnings` stdout and stderr files under `conformance/expected-warnings/`.
705
+ Conformance cases live in the repository under `test/conformance/`. They are run by `npm test` before the example suite, and can be run alone with `node test/run-conformance.mjs`. Positive cases have input programs under `conformance/cases/` and exact expected standard-output files under `conformance/expected/`; both use `.eye` so expected output remains eyelang-readable. Expected-error cases live under `conformance/errors/` with exact messages under `conformance/expected-errors/`. Expected-warning cases live under `conformance/warnings/` with exact `--warnings` stdout and stderr files under `conformance/expected-warnings/`. The corpus is grouped by language area, including arithmetic, strings, lists, terms, atoms, variables, negation, declarations, materialization, rules, syntax, and errors.
706
706
 
707
707
  ## 15. Relationship to ISO Prolog
708
708
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyelang",
3
- "version": "1.7.4",
3
+ "version": "1.7.6",
4
4
  "description": "A small Prolog-like logic programming language for rules, goals, answers, and proofs.",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -30,6 +30,7 @@
30
30
  "playground.html",
31
31
  "bin",
32
32
  "src",
33
+ "conformance-report.md",
33
34
  "docs",
34
35
  "examples",
35
36
  "test"
@@ -43,7 +44,7 @@
43
44
  "test:conformance": "node test/run-conformance.mjs",
44
45
  "test:examples": "node test/run-examples.mjs",
45
46
  "test:regression": "node test/run-regression.mjs",
46
- "preversion": "npm test",
47
+ "preversion": "npm test && npm run conformance:report -- conformance-report.md",
47
48
  "postversion": "git push origin HEAD --follow-tags",
48
49
  "conformance:report": "node test/run-conformance-report.mjs"
49
50
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  This directory contains the executable conformance cases for the Eyelang language and reference engine. The normative language description is in the [Eyelang language reference](../../../docs/language-reference.md).
4
4
 
5
- The suite is intentionally file-based so another implementation can run the same programs and compare exact standard output, expected errors, and expected warnings. The conformance corpus is part of the public language contract, not just an implementation smoke test.
5
+ The suite is intentionally file-based so another implementation can run the same programs and compare exact standard output, expected errors, expected warnings, and expected proof output. The conformance corpus is part of the public language contract, not just an implementation smoke test.
6
6
 
7
7
  A normal positive case consists of:
8
8
 
@@ -20,7 +20,12 @@ Expected-warning cases consist of:
20
20
  - `conformance/expected-warnings/<name>.eye` — exact expected standard output;
21
21
  - `conformance/expected-warnings/<name>.txt` — exact expected standard error.
22
22
 
23
- Case names may be nested in category directories such as `atoms/`, `variables/`, `negation/`, or `syntax/`. Expected files mirror the same relative path.
23
+ Expected-proof cases consist of:
24
+
25
+ - `conformance/proofs/<name>.eye` — input program run through the CLI with `--proof`;
26
+ - `conformance/expected-proofs/<name>.eye` — exact expected standard output, including both answer facts and `why/2` proof facts.
27
+
28
+ Case names may be nested in category directories such as `arithmetic/`, `strings/`, `lists/`, `terms/`, `atoms/`, `variables/`, `negation/`, or `syntax/`. Expected files mirror the same relative path.
24
29
 
25
30
  ## Running the suite
26
31
 
@@ -40,6 +45,7 @@ Summarize conformance coverage by category:
40
45
 
41
46
  ```sh
42
47
  npm run conformance:report
48
+ npm run conformance:report -- conformance-report.md
43
49
  ```
44
50
 
45
51
  Run matching conformance cases by passing a filename or directory fragment:
@@ -51,14 +57,14 @@ node test/run-conformance.mjs variables/
51
57
  node test/run-conformance.mjs error/variables
52
58
  ```
53
59
 
54
- The runner executes normal materialized programs in-process through the public JavaScript API so small conformance cases avoid measuring Node startup overhead. Warning cases intentionally use the CLI because warning output is a host-interface contract.
60
+ The runner executes normal materialized programs in-process through the public JavaScript API so small conformance cases avoid measuring Node startup overhead. Warning and proof cases intentionally use the CLI because warning output and `why/2` proof output are host-interface contracts.
55
61
 
56
62
  ## Scope
57
63
 
58
- The conformance corpus is a single eyelang suite. It covers the standard language described by the language reference: lexical syntax, facts, definite clauses, first-order terms, lists, conjunction, structured unification, left-to-right goal-directed proof search, materialized output, read-back printing, standard built-ins, declarations, warnings, errors, and standard host behavior.
64
+ The conformance corpus is a single eyelang suite. It covers the standard language described by the language reference: lexical syntax, facts, definite clauses, first-order terms, lists, conjunction, structured unification, left-to-right goal-directed proof search, materialized output, read-back printing, standard built-ins, declarations, warnings, errors, proof output, and standard host behavior.
59
65
 
60
66
  The suite deliberately does not separate `core` and `extension` profiles. Reusable built-ins such as arithmetic, strings, lists, aggregation, context terms, term inspection, and search control are part of the standard eyelang conformance surface. Implementation-specific built-ins may still exist in downstream hosts, but they should have their own tests outside this corpus unless they are standardized.
61
67
 
62
68
  ## Updating expected output
63
69
 
64
- There is no committed auto-accept mode. To update an expected file, run the matching case with the conformance runner, inspect the result, and replace the corresponding file under `conformance/expected/`, `conformance/expected-errors/`, or `conformance/expected-warnings/` deliberately.
70
+ There is no committed auto-accept mode. To update an expected file, run the matching case with the conformance runner, inspect the result, and replace the corresponding file under `conformance/expected/`, `conformance/expected-errors/`, `conformance/expected-warnings/`, or `conformance/expected-proofs/` deliberately.
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(aggregate_max(?key, ?value, missing(?value), ?bestKey, ?bestValue)).
@@ -0,0 +1,5 @@
1
+ materialize(answer, 2).
2
+ candidate(a, 3).
3
+ candidate(b, 1).
4
+ candidate(c, 2).
5
+ answer(?key, ?value) :- aggregate_min(score(?score), ?name, candidate(?name, ?score), ?key, ?value).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?n) :- countall(missing(?x), ?n).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?bag) :- findall(?x, missing(?x), ?bag).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?n) :- sumall(?x, missing(?x), ?n).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- between(1, 5, 3).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- between(4, 4, ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- lt("P1Y", "P2Y"), gt("P1Y2M", "P1Y1M").
@@ -0,0 +1,3 @@
1
+ materialize(answer, 2).
2
+ answer(add, ?x) :- add(1.5, 2.25, ?x).
3
+ answer(div, ?x) :- div(7, 2, ?x).
@@ -0,0 +1,3 @@
1
+ materialize(answer, 2).
2
+ answer(min, ?x) :- min(3, 2.5, ?x).
3
+ answer(max, ?x) :- max(3, 2.5, ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- mod(-7, 3, ?x).
@@ -0,0 +1,4 @@
1
+ % Integer-preserving unary arithmetic.
2
+ materialize(answer, 2).
3
+ answer(neg, ?x) :- neg(7, ?x).
4
+ answer(abs, ?x) :- abs(-7, ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(pow(2, -1, ?x)).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- pow(9, 0, ?x).
@@ -0,0 +1,5 @@
1
+ materialize(answer, 2).
2
+ answer(floor, ?x) :- floor(-1.2, ?x).
3
+ answer(ceiling, ?x) :- ceiling(-1.2, ?x).
4
+ answer(trunc, ?x) :- trunc(-1.8, ?x).
5
+ answer(rounded, ?x) :- rounded(-1.5, ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- smallest_divisor_from(17, 2, ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(sqrt(-1, ?x)).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(<https://example.org/a%20b?x=1#frag>).
@@ -0,0 +1,3 @@
1
+ materialize(answer, 1).
2
+ '<=>'(ok).
3
+ answer(ok) :- '<=>'(ok).
@@ -0,0 +1,3 @@
1
+ materialize(answer, 1).
2
+ '<urn:example:predicate>'(ok).
3
+ answer(ok) :- '<urn:example:predicate>'(ok).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer('example:relative').
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- holds((likes(alice, tea), likes(bob, coffee)), likes(alice, tea)).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(holds((p(a), q(b)), r(c))).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 3).
2
+ answer(?name, ?left, ?right) :- holds((edge(a, b), label(a, "A")), ?name, [?left, ?right]).
@@ -0,0 +1,3 @@
1
+ materialize(answer, 1).
2
+ seed(a).
3
+ answer(ok) :- not(not(seed(a))).
@@ -0,0 +1,5 @@
1
+ materialize(answer, 1).
2
+ item(a).
3
+ item(b).
4
+ good(a).
5
+ answer(ok) :- not(forall(item(?x), good(?x))).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- forall(missing(?x), fail(?x)).
@@ -0,0 +1,5 @@
1
+ materialize(answer, 1).
2
+ item(a).
3
+ item(b).
4
+ blocked(b).
5
+ answer(?x) :- item(?x), not(blocked(?x)).
@@ -0,0 +1,4 @@
1
+ materialize(answer, 1).
2
+ choice(a).
3
+ choice(b).
4
+ answer(?x) :- once(choice(?x)).
@@ -0,0 +1,5 @@
1
+ materialize(answer, 1).
2
+ det(answer, 1).
3
+ semidet(aux, 1).
4
+ aux(ok).
5
+ answer(ok) :- aux(ok).
@@ -0,0 +1,4 @@
1
+ materialize(answer, 2).
2
+ answer(head, ?x) :- head([a, b, c], ?x).
3
+ answer(rest, ?x) :- rest([a, b, c], ?x).
4
+ answer(last, ?x) :- last([a, b, c], ?x).
@@ -0,0 +1,3 @@
1
+ materialize(answer, 2).
2
+ answer(empty, ?x) :- length([], ?x).
3
+ answer(nested, ?x) :- length([[a], [b, c]], ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- list_to_set([pair(a, 1), pair(a, 1), pair(a, 2)], ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(min_list([], ?x)).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- nth0(2, [a, b, c], c).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(nth0(5, [a], ?x)).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- reverse([], ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 2).
2
+ answer(?item, ?rest) :- select(?item, [a, b, a], ?rest).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- set_nth0(1, [a, b, c], z, ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- slice([a, b, c, d], 1, 2, ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(slice([a], 1, 2, ?x)).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- sort([b(2), a(3), a(1)], ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- sum_list([], ?x).
@@ -0,0 +1,4 @@
1
+ materialize(answer, 2).
2
+ answer(sum, ?x) :- sum_list([5, -2, 7], ?x).
3
+ answer(min, ?x) :- min_list([5, -2, 7], ?x).
4
+ answer(max, ?x) :- max_list([5, -2, 7], ?x).
@@ -0,0 +1,3 @@
1
+ materialize(answer, 2).
2
+ answer(take, ?x) :- take(0, [a, b], ?x).
3
+ answer(drop, ?x) :- drop(2, [a, b], ?x).
@@ -0,0 +1,4 @@
1
+ materialize(answer, 1).
2
+ answer(one).
3
+ answer(two, ignored).
4
+ answer(three, ignored, ignored).
@@ -0,0 +1,4 @@
1
+ materialize(answer, 2).
2
+ parent(alice, bob).
3
+ parent(bob, clara).
4
+ answer(?x, ?z) :- parent(?x, ?y), parent(?y, ?z).
@@ -0,0 +1,7 @@
1
+ materialize(path, 2).
2
+ table(path, 2).
3
+ edge(a, b).
4
+ edge(b, c).
5
+ edge(c, d).
6
+ path(?x, ?y) :- edge(?x, ?y).
7
+ path(?x, ?z) :- edge(?x, ?y), path(?y, ?z).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?atom) :- atom_string(?atom, "hello_world").
@@ -0,0 +1,3 @@
1
+ materialize(answer, 2).
2
+ answer(lower, ?x) :- lowercase("HelloWorld", ?x).
3
+ answer(upper, ?x) :- uppercase(helloWorld, ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- contains("abc", "").
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?text) :- join([a, "b", 3], "-", ?text).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- matches("beta", "alpha|beta").
@@ -0,0 +1,2 @@
1
+ materialize(answer, 2).
2
+ answer(?first, ?last) :- matches("Ada Lovelace", "^(?<first>[A-Za-z]+) (?<last>[A-Za-z]+)$", ?ctx), holds(?ctx, first, ?first), holds(?ctx, last, ?last).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not_matches("abc", "x|y").
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?n) :- number_string(?n, "42").
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(number_string(?n, "four")).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?text) :- replace("abc", "", "X", ?text).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?parts) :- split("abc", ",", ?parts).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(substring("abc", 2, 5, ?text)).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?text) :- substring("abcdef", 2, 0, ?text).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?text) :- term_string(pair(<urn:example:a>, [1, two]), ?text).
@@ -0,0 +1,3 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- trim(" hello
3
+ ", ?x).
@@ -0,0 +1,4 @@
1
+ % Leading comment.
2
+ materialize(answer, 1). % trailing comment
3
+
4
+ answer(ok). % another trailing comment
@@ -0,0 +1,3 @@
1
+ materialize(answer, 1).
2
+ answer('line
3
+ break').
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer("a b").
@@ -0,0 +1,7 @@
1
+ materialize(answer, 1).
2
+ table(reachable, 2).
3
+ edge(a, b).
4
+ edge(b, c).
5
+ reachable(?x, ?z) :- reachable(?x, ?y), edge(?y, ?z).
6
+ reachable(?x, ?y) :- edge(?x, ?y).
7
+ answer(?x) :- reachable(a, ?x).
@@ -0,0 +1,3 @@
1
+ materialize(answer, 2).
2
+ answer(first, ?x) :- arg(1, pair(a, b), ?x).
3
+ answer(second, ?x) :- arg(2, pair(a, b), ?x).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(arg(0, pair(a, b), ?x)).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(compound_name_arguments(?x, pair, [a | b])).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- compound_name_arguments(?x, pair, [a, b]).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 2).
2
+ answer(?name, ?args) :- compound_name_arguments(<urn:example:a>, ?name, ?args).
@@ -0,0 +1,3 @@
1
+ materialize(answer, 3).
2
+ answer(number, ?name, ?arity) :- functor(42, ?name, ?arity).
3
+ answer(string, ?name, ?arity) :- functor("hi", ?name, ?arity).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?text) :- term_string([<urn:example:a>, <urn:example:b>], ?text).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(ok) :- not(eq(pair(a), pair(a, b))).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?tail) :- eq([a, b, c], [a | ?tail]).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?x) :- eq(pair(?x, box(?x)), pair(a, box(a))).
@@ -0,0 +1,3 @@
1
+ materialize(answer, 1).
2
+ answer(atom_number) :- eq(a, "a").
3
+ answer(number_string) :- eq(7, "7").
@@ -0,0 +1,5 @@
1
+ materialize(answer, 1).
2
+ helper(a).
3
+ helper(b).
4
+ answer(?x) :- helper(?x).
5
+ answer(?x) :- helper(?x), eq(?x, c).
@@ -1,4 +1,2 @@
1
- % Variable names may continue with digits and underscores after the leading name character.
2
- materialize(answer, 2).
3
- pair(a, b).
4
- answer(?x_1, ?y2) :- pair(?x_1, ?y2).
1
+ materialize(answer, 1).
2
+ answer(?x_1) :- eq(?x_1, ok).
@@ -0,0 +1,2 @@
1
+ materialize(answer, 1).
2
+ answer(?X) :- eq(?X, ok).
@@ -0,0 +1 @@
1
+ answer([a | ]).
@@ -0,0 +1 @@
1
+ answer(<urn:example:a b>).
@@ -0,0 +1 @@
1
+ answer(pair(nil())).
@@ -0,0 +1 @@
1
+ answer(ok)
@@ -0,0 +1 @@
1
+ answer(<relative>).
@@ -0,0 +1 @@
1
+ answer(ok) :- seed(ok), .
@@ -0,0 +1 @@
1
+ answer(pair(a, b).
@@ -0,0 +1 @@
1
+ answer([a, b).
@@ -0,0 +1 @@
1
+ answer('abc).
@@ -0,0 +1 @@
1
+ answer("abc).