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
@@ -0,0 +1,3 @@
1
+ eyelang warning: unstratified negation
2
+ p/1 depends negatively on q/1
3
+ q/1 depends negatively on p/1
@@ -0,0 +1,4 @@
1
+ % Reference 12: proof bindings preserve nested compound terms.
2
+ materialize(answer, 1).
3
+ source(pair(a, [b, c])).
4
+ answer(?term) :- source(?term).
@@ -0,0 +1,3 @@
1
+ % Reference 12: built-ins are proof leaves identified by builtin(Name, Arity).
2
+ materialize(answer, 1).
3
+ answer(?x) :- add(2, 3, ?x).
@@ -0,0 +1,5 @@
1
+ % Reference 12: proof output records conjunction children in source goal order.
2
+ materialize(answer, 1).
3
+ left(ok).
4
+ right(ok).
5
+ answer(ok) :- left(ok), right(ok).
@@ -0,0 +1,4 @@
1
+ % Reference 12: proof output preserves angle-bracket IRI atom read-back.
2
+ materialize(label, 2).
3
+ name(<urn:example:a>, "Alice").
4
+ label(?iri, ?name) :- name(?iri, ?name).
@@ -0,0 +1,3 @@
1
+ % Reference 12: proof output preserves list read-back for built-in goals.
2
+ materialize(answer, 1).
3
+ answer(?x) :- member(?x, [a, b]), eq(?x, b).
@@ -0,0 +1,5 @@
1
+ % Reference 12: once/1 proof output includes the proof for the selected child goal.
2
+ materialize(answer, 1).
3
+ choice(a).
4
+ choice(b).
5
+ answer(?x) :- once(choice(?x)).
@@ -0,0 +1,4 @@
1
+ % Reference 12: proof output records the source rule and source fact used for an answer.
2
+ materialize(answer, 1).
3
+ seed(ok).
4
+ answer(?x) :- seed(?x).
@@ -0,0 +1,7 @@
1
+ % Reference 12: tabled recursive proofs still explain the successful derivation path.
2
+ materialize(path, 2).
3
+ table(path, 2).
4
+ edge(a, b).
5
+ edge(b, c).
6
+ path(?x, ?y) :- edge(?x, ?y).
7
+ path(?x, ?z) :- edge(?x, ?y), path(?y, ?z).
@@ -0,0 +1,3 @@
1
+ materialize(answer, 1).
2
+ item(a).
3
+ answer(?x) :- item(?x), not(missing(?x)).
@@ -0,0 +1,5 @@
1
+ materialize(answer, 1).
2
+ base(a).
3
+ blocked(b).
4
+ allowed(?x) :- base(?x), not(blocked(?x)).
5
+ answer(?x) :- allowed(?x).
@@ -0,0 +1,5 @@
1
+ materialize(answer, 1).
2
+ p(a) :- helper(a).
3
+ helper(a) :- not(q(a)).
4
+ q(a) :- p(a).
5
+ answer(ok).
@@ -0,0 +1,4 @@
1
+ materialize(answer, 1).
2
+ p(a, b) :- not(q(a, b)).
3
+ q(a, b) :- not(p(a, b)).
4
+ answer(ok).
@@ -0,0 +1,6 @@
1
+ materialize(answer, 1).
2
+ p(a) :- not(q(a)).
3
+ q(a) :- not(p(a)).
4
+ r(a) :- not(s(a)).
5
+ s(a) :- not(r(a)).
6
+ answer(ok).
@@ -0,0 +1,4 @@
1
+ materialize(answer, 1).
2
+ p(<urn:example:a>) :- not(q(<urn:example:a>)).
3
+ q(<urn:example:a>) :- not(p(<urn:example:a>)).
4
+ answer(ok).
@@ -0,0 +1,5 @@
1
+ materialize(answer, 1).
2
+ p(a) :- not(q(a)).
3
+ q(a) :- not(p(a)).
4
+ answer(a).
5
+ answer(b).
@@ -7,12 +7,14 @@ import path from 'node:path';
7
7
  import { fileURLToPath } from 'node:url';
8
8
 
9
9
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)));
10
+ const packageRoot = path.resolve(root, '..');
10
11
  const conformanceRoot = path.join(root, 'conformance');
11
12
 
12
13
  const KINDS = [
13
14
  { kind: 'cases', expectedKind: 'expected', expectedExt: '.eye', column: 'positive' },
14
15
  { kind: 'errors', expectedKind: 'expected-errors', expectedExt: '.txt', column: 'errors' },
15
16
  { kind: 'warnings', expectedKind: 'expected-warnings', expectedExt: '.eye', column: 'warnings' },
17
+ { kind: 'proofs', expectedKind: 'expected-proofs', expectedExt: '.eye', column: 'proofs' },
16
18
  ];
17
19
 
18
20
  export function buildConformanceReport() {
@@ -45,8 +47,9 @@ export function buildConformanceReport() {
45
47
  positive: acc.positive + row.positive,
46
48
  errors: acc.errors + row.errors,
47
49
  warnings: acc.warnings + row.warnings,
50
+ proofs: acc.proofs + row.proofs,
48
51
  total: acc.total + row.total,
49
- }), { positive: 0, errors: 0, warnings: 0, total: 0 });
52
+ }), { positive: 0, errors: 0, warnings: 0, proofs: 0, total: 0 });
50
53
 
51
54
  return { rows, total, issues: issues.sort() };
52
55
  }
@@ -57,14 +60,14 @@ export function formatConformanceReport(report = buildConformanceReport()) {
57
60
  '',
58
61
  'This report summarizes the file-based conformance corpus under `test/conformance/`.',
59
62
  '',
60
- '| Category | Positive | Errors | Warnings | Total |',
61
- '|---|---:|---:|---:|---:|',
63
+ '| Category | Positive | Errors | Warnings | Proofs | Total |',
64
+ '|---|---:|---:|---:|---:|---:|',
62
65
  ];
63
66
 
64
67
  for (const row of report.rows) {
65
- lines.push(`| ${row.category} | ${row.positive} | ${row.errors} | ${row.warnings} | ${row.total} |`);
68
+ lines.push(`| ${row.category} | ${row.positive} | ${row.errors} | ${row.warnings} | ${row.proofs} | ${row.total} |`);
66
69
  }
67
- lines.push(`| **Total** | **${report.total.positive}** | **${report.total.errors}** | **${report.total.warnings}** | **${report.total.total}** |`);
70
+ lines.push(`| **Total** | **${report.total.positive}** | **${report.total.errors}** | **${report.total.warnings}** | **${report.total.proofs}** | **${report.total.total}** |`);
68
71
 
69
72
  if (report.issues.length > 0) {
70
73
  lines.push('', '## Corpus issues', '');
@@ -95,7 +98,7 @@ function categoryOf(file) {
95
98
  function ensureCategory(categories, category) {
96
99
  let counts = categories.get(category);
97
100
  if (!counts) {
98
- counts = { positive: 0, errors: 0, warnings: 0, total: 0 };
101
+ counts = { positive: 0, errors: 0, warnings: 0, proofs: 0, total: 0 };
99
102
  categories.set(category, counts);
100
103
  }
101
104
  return counts;
@@ -103,6 +106,15 @@ function ensureCategory(categories, category) {
103
106
 
104
107
  if (process.argv[1] != null && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
105
108
  const report = buildConformanceReport();
106
- process.stdout.write(formatConformanceReport(report));
109
+ const text = formatConformanceReport(report);
110
+ const outputPath = process.argv[2] ?? null;
111
+ if (outputPath == null) {
112
+ process.stdout.write(text);
113
+ } else {
114
+ const resolved = path.resolve(packageRoot, outputPath);
115
+ fs.mkdirSync(path.dirname(resolved), { recursive: true });
116
+ fs.writeFileSync(resolved, text);
117
+ process.stdout.write(`wrote ${path.relative(packageRoot, resolved)}\n`);
118
+ }
107
119
  if (report.issues.length > 0) process.exit(1);
108
120
  }
@@ -20,6 +20,7 @@ export function runConformance(reporter = new TestReporter(), requestedFilter =
20
20
  for (const file of listCaseFiles('cases', filter)) runCaseFile(reporter, file);
21
21
  for (const file of listCaseFiles('errors', filter)) runErrorFile(reporter, file);
22
22
  for (const file of listCaseFiles('warnings', filter)) runWarningFile(reporter, file);
23
+ for (const file of listCaseFiles('proofs', filter)) runProofFile(reporter, file);
23
24
  reporter.sectionTotal(`conformance ${label}`);
24
25
  }
25
26
 
@@ -70,6 +71,11 @@ function runWarningFile(reporter, file) {
70
71
  reporter.test(`warning/${name}`, () => runWarningCase(name, file));
71
72
  }
72
73
 
74
+ function runProofFile(reporter, file) {
75
+ const name = file.slice(0, -4);
76
+ reporter.test(`proof/${name}`, () => runProofCase(name, file));
77
+ }
78
+
73
79
  function runCase(name, file) {
74
80
  const casesDir = path.join(root, 'conformance', 'cases');
75
81
  const expectedDir = path.join(root, 'conformance', 'expected');
@@ -122,6 +128,29 @@ function runWarningCase(name, file) {
122
128
  compareExpectedFile(expectedStderr, result.stderr, name, 'warning stderr');
123
129
  }
124
130
 
131
+ function runProofCase(name, file) {
132
+ const proofsDir = path.join(root, 'conformance', 'proofs');
133
+ const expectedDir = path.join(root, 'conformance', 'expected-proofs');
134
+ const programFile = path.join(proofsDir, file);
135
+ const expected = path.join(expectedDir, `${name}.eye`);
136
+ const text = fs.readFileSync(programFile, 'utf8');
137
+ const result = spawnSync(process.execPath, [cliBin, '--proof', '-'], {
138
+ cwd: packageRoot,
139
+ input: text,
140
+ encoding: 'utf8',
141
+ });
142
+
143
+ if (result.status !== 0) {
144
+ throw new Error(`proof case ${name} exited with ${result.status}\n${result.stderr}`.trimEnd());
145
+ }
146
+ if (result.stderr !== '') {
147
+ throw new Error(`proof case ${name} wrote unexpected stderr\n${result.stderr}`.trimEnd());
148
+ }
149
+
150
+ compareExpectedFile(expected, result.stdout, name, 'proof output');
151
+ Program.parse(result.stdout);
152
+ }
153
+
125
154
  function compareExpectedFile(expected, actual, name, kind) {
126
155
  if (!fs.existsSync(expected)) {
127
156
  throw new Error(`missing expected ${kind} file: ${path.relative(root, expected)}`);
@@ -371,13 +371,23 @@ function documentationSyncCases() {
371
371
  run: () => {
372
372
  const report = buildConformanceReport();
373
373
  assertArrayEqual(report.issues, [], 'conformance report issues');
374
- assertEqual(report.total.total >= 150, true, 'conformance case count');
375
- assertEqual(report.total.positive + report.total.errors + report.total.warnings, report.total.total, 'conformance total');
374
+ assertEqual(report.total.total >= 250, true, 'conformance case count');
375
+ assertEqual(report.total.positive + report.total.errors + report.total.warnings + report.total.proofs, report.total.total, 'conformance total');
376
376
  const text = formatConformanceReport(report);
377
377
  assertIncludes(text, '| variables |', 'report');
378
+ assertIncludes(text, '| Proofs |', 'report');
378
379
  assertIncludes(text, '| **Total** |', 'report');
379
380
  },
380
381
  },
382
+
383
+ {
384
+ name: 'committed conformance report is current',
385
+ run: () => {
386
+ const reportFile = path.join(packageRoot, 'conformance-report.md');
387
+ assertEqual(fs.existsSync(reportFile), true, 'conformance-report.md exists');
388
+ assertEqual(fs.readFileSync(reportFile, 'utf8'), formatConformanceReport(buildConformanceReport()), 'conformance-report.md');
389
+ },
390
+ },
381
391
  {
382
392
  name: 'source-checkout setup docs match package bin',
383
393
  run: () => {