eyeprolog 0.5.14 → 0.5.16
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.
- package/README.md +2 -0
- package/conformance-report.md +2 -2
- package/examples/output/aliases-and-namespaces.pl +1 -1
- package/examples/output/dijkstra-findall-sort.pl +1 -1
- package/examples/output/dijkstra.pl +16 -16
- package/examples/output/drone-corridor-planner.pl +17 -17
- package/examples/output/iso-atomic-conversion.pl +1 -1
- package/examples/output/list-collection.pl +2 -2
- package/examples/proof/aliases-and-namespaces.pl +5 -5
- package/examples/proof/graph-reachability.pl +22 -22
- package/examples/proof/list-collection.pl +13 -13
- package/examples/proof/term-tools.pl +1 -1
- package/index.d.ts +5 -2
- package/package.json +1 -1
- package/src/cli.js +17 -9
- package/src/index.js +15 -5
- package/src/iso.js +1 -0
- package/src/parser.js +57 -12
- package/src/program.js +8 -5
- package/src/solver.js +11 -3
- package/src/term.js +41 -10
- package/src/write.js +6 -0
- package/test/conformance/README.md +1 -1
- package/test/conformance/cases/arithmetic/082_comparison_semantics.pl +2 -2
- package/test/conformance/cases/arithmetic/extra_le_equal_string.pl +1 -1
- package/test/conformance/cases/context/extra_context_ignores_string_parts.pl +1 -1
- package/test/conformance/cases/iso/double_quoted_lists.pl +27 -0
- package/test/conformance/cases/strings/023_quoted_escapes_readback.pl +2 -3
- package/test/conformance/cases/terms/003_terms_and_readback.pl +1 -1
- package/test/conformance/cases/terms/073_term_introspection_edges.pl +1 -1
- package/test/conformance/cases/terms/096_functor_scalar_edges.pl +2 -2
- package/test/conformance/cases/terms/extra_functor_string_scalar.pl +1 -1
- package/test/conformance/cases/terms/functor_number_and_string.pl +1 -1
- package/test/conformance/cases/unification/extra_eq_scalar_string_number.pl +1 -1
- package/test/conformance/cases/unification/scalar_cross_type_same_lexical_value.pl +2 -2
- package/test/conformance/expected/aggregation/044_findall_user_goal.pl +1 -1
- package/test/conformance/expected/arithmetic/082_comparison_semantics.pl +1 -1
- package/test/conformance/expected/arithmetic/extra_le_equal_string.pl +1 -1
- package/test/conformance/expected/context/extra_context_atom_parts.pl +1 -1
- package/test/conformance/expected/context/extra_context_ignores_string_parts.pl +1 -0
- package/test/conformance/expected/context/extra_context_list_parts.pl +1 -1
- package/test/conformance/expected/iso/atomic_term_processing.pl +1 -1
- package/test/conformance/expected/iso/double_quoted_lists.pl +8 -0
- package/test/conformance/expected/iso/exceptions_and_flags.pl +1 -1
- package/test/conformance/expected/iso/grouped_solutions_and_clauses.pl +1 -1
- package/test/conformance/expected/iso/logtalk_atom_chars.pl +1 -1
- package/test/conformance/expected/iso/logtalk_number_chars.pl +1 -1
- package/test/conformance/expected/iso/logtalk_prolog_flags.pl +1 -1
- package/test/conformance/expected/iso/logtalk_univ.pl +1 -1
- package/test/conformance/expected/iso/scryer_lexical_terms.pl +1 -1
- package/test/conformance/expected/lists/005_list_deconstruction.pl +1 -1
- package/test/conformance/expected/lists/031_lists_aggregation_ordering.pl +4 -4
- package/test/conformance/expected/lists/035_list_relations.pl +3 -3
- package/test/conformance/expected/lists/036_append_splits.pl +3 -3
- package/test/conformance/expected/lists/045_sort_deduplicates_atoms.pl +1 -1
- package/test/conformance/expected/lists/046_append_bound_prefix_suffix.pl +2 -2
- package/test/conformance/expected/lists/048_set_nth0_edges.pl +2 -2
- package/test/conformance/expected/lists/049_select_duplicate_occurrences.pl +2 -2
- package/test/conformance/expected/lists/067_list_edges.pl +1 -1
- package/test/conformance/expected/lists/068_list_generation_order.pl +6 -6
- package/test/conformance/expected/lists/084_append_and_select_composition.pl +9 -9
- package/test/conformance/expected/lists/085_nth_and_update_edges.pl +1 -1
- package/test/conformance/expected/lists/087_sort_reverse_length.pl +2 -2
- package/test/conformance/expected/lists/extra_append_all_splits_three.pl +4 -4
- package/test/conformance/expected/lists/extra_list_to_set_stable_order.pl +1 -1
- package/test/conformance/expected/lists/extra_reverse_nested_terms.pl +1 -1
- package/test/conformance/expected/lists/extra_slice_end.pl +1 -1
- package/test/conformance/expected/lists/extra_take_all.pl +1 -1
- package/test/conformance/expected/lists/list_pattern_last.pl +1 -1
- package/test/conformance/expected/lists/select_all_occurrences.pl +3 -3
- package/test/conformance/expected/lists/set_nth0_middle.pl +1 -1
- package/test/conformance/expected/rules/077_recursive_path_with_lists.pl +3 -3
- package/test/conformance/expected/strings/023_quoted_escapes_readback.pl +1 -1
- package/test/conformance/expected/strings/071_string_edges.pl +1 -1
- package/test/conformance/expected/strings/extra_split_empty_separator.pl +1 -1
- package/test/conformance/expected/terms/003_terms_and_readback.pl +3 -3
- package/test/conformance/expected/terms/065_reusable_term_control_builtins.pl +1 -1
- package/test/conformance/expected/terms/073_term_introspection_edges.pl +2 -2
- package/test/conformance/expected/terms/095_term_introspection_roundtrip.pl +1 -1
- package/test/conformance/expected/terms/096_functor_scalar_edges.pl +1 -1
- package/test/conformance/expected/terms/extra_compound_name_arguments_decompose_list.pl +1 -1
- package/test/conformance/expected/terms/extra_functor_string_scalar.pl +1 -1
- package/test/conformance/expected/terms/functor_number_and_string.pl +1 -1
- package/test/conformance/expected/unification/012_nested_compound_unification.pl +1 -1
- package/test/conformance/expected/unification/034_equality_and_inequality.pl +1 -1
- package/test/conformance/expected/unification/extra_eq_list_tail_binding.pl +1 -1
- package/test/conformance/expected/unification/list_tail_binding.pl +1 -1
- package/test/conformance/expected-proofs/proofs/bindings_nested_term.pl +5 -5
- package/test/conformance/expected-proofs/proofs/extra_compound_name_arguments.pl +4 -4
- package/test/conformance/expected-proofs/proofs/extra_findall_builtin.pl +5 -5
- package/test/conformance/expected-proofs/proofs/extra_nested_list_binding.pl +5 -5
- package/test/conformance/expected-proofs/proofs/extra_once_member.pl +2 -2
- package/test/conformance/expected-proofs/proofs/list_builtin.pl +1 -1
- package/test/run-playground.mjs +2 -2
- package/test/run-regression.mjs +70 -12
- package/the-art-of-eyeprolog.md +305 -61
package/README.md
CHANGED
|
@@ -28,6 +28,8 @@ eyeprolog --goal 'type(socrates, mortal)' examples/socrates.pl
|
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
Programs may declare their default queries with `%% goal:` comments.
|
|
31
|
+
Double-quoted text follows the ISO `double_quotes` flag and defaults to a
|
|
32
|
+
proper list of one-character atoms (`chars`), matching Trealla and Scryer.
|
|
31
33
|
|
|
32
34
|
## Portable library
|
|
33
35
|
|
package/conformance-report.md
CHANGED
|
@@ -11,7 +11,7 @@ This report summarizes the file-based conformance corpus under `test/conformance
|
|
|
11
11
|
| builtins | 11 | 0 | 0 | 0 | 11 |
|
|
12
12
|
| context | 11 | 0 | 0 | 0 | 11 |
|
|
13
13
|
| control | 15 | 0 | 0 | 0 | 15 |
|
|
14
|
-
| iso |
|
|
14
|
+
| iso | 121 | 159 | 0 | 0 | 280 |
|
|
15
15
|
| lists | 52 | 3 | 0 | 0 | 55 |
|
|
16
16
|
| negation | 8 | 0 | 19 | 0 | 27 |
|
|
17
17
|
| proofs | 0 | 0 | 0 | 21 | 21 |
|
|
@@ -22,4 +22,4 @@ This report summarizes the file-based conformance corpus under `test/conformance
|
|
|
22
22
|
| terms | 26 | 3 | 0 | 0 | 29 |
|
|
23
23
|
| unification | 18 | 0 | 0 | 0 | 18 |
|
|
24
24
|
| variables | 16 | 9 | 0 | 0 | 25 |
|
|
25
|
-
| **Total** | **
|
|
25
|
+
| **Total** | **434** | **212** | **19** | **21** | **686** |
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
shortestPath(dijkstra_findall_sort,
|
|
1
|
+
shortestPath(dijkstra_findall_sort, "acbdef").
|
|
2
2
|
cost(dijkstra_findall_sort, 13).
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
edge(
|
|
2
|
-
edge(
|
|
3
|
-
edge(
|
|
4
|
-
edge(
|
|
5
|
-
edge(
|
|
6
|
-
edge(
|
|
7
|
-
edge(
|
|
8
|
-
edge(
|
|
9
|
-
edge(
|
|
10
|
-
path(
|
|
11
|
-
path(
|
|
12
|
-
path(
|
|
13
|
-
path(
|
|
14
|
-
path(
|
|
15
|
-
path(
|
|
16
|
-
path(
|
|
1
|
+
edge("ba", 4).
|
|
2
|
+
edge("ca", 2).
|
|
3
|
+
edge("cb", 1).
|
|
4
|
+
edge("db", 5).
|
|
5
|
+
edge("dc", 8).
|
|
6
|
+
edge("ec", 10).
|
|
7
|
+
edge("ed", 2).
|
|
8
|
+
edge("fd", 6).
|
|
9
|
+
edge("fe", 3).
|
|
10
|
+
path("af", ["abdef", 14]).
|
|
11
|
+
path("af", ["abdf", 15]).
|
|
12
|
+
path("af", ["acdef", 15]).
|
|
13
|
+
path("af", ["acdf", 16]).
|
|
14
|
+
path("af", ["acef", 15]).
|
|
15
|
+
path("af", ["acbdef", 13]).
|
|
16
|
+
path("af", ["acbdf", 14]).
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
gps_plan(d1, plan([fly_gent_brugge, public_coastline_brugge_oostende], 2800.0, 0.012, 0.96029999999999993, 0.95039999999999991, low, none,
|
|
2
|
-
gps_plan(d1, plan([fly_gent_brugge, buy_permit_brugge, public_coastline_brugge_oostende], 3250.0, 0.014, 0.94109399999999999, 0.95039999999999991, low, yes,
|
|
3
|
-
gps_plan(d1, plan([fly_gent_brugge, buy_permit_brugge, topup_brugge, cross_corridor_brugge_oostende], 3250.0, 0.015000000000000001, 0.94984520399999994, 0.97019999999999995, mid, yes,
|
|
4
|
-
gps_plan(d1, plan([fly_gent_brugge, buy_permit_brugge, topup_brugge, public_coastline_brugge_oostende], 3550.0, 0.017000000000000001, 0.94499905500000003, 0.931392, mid, yes,
|
|
5
|
-
gps_plan(d1, plan([fly_gent_brugge, topup_brugge, public_coastline_brugge_oostende], 3100.0, 0.015000000000000001, 0.96428475000000002, 0.931392, mid, none,
|
|
6
|
-
gps_plan(d1, plan([fly_gent_brugge, topup_brugge, buy_permit_brugge, cross_corridor_brugge_oostende], 3250.0, 0.015000000000000001, 0.94984520399999994, 0.97019999999999995, mid, yes,
|
|
7
|
-
gps_plan(d1, plan([fly_gent_brugge, topup_brugge, buy_permit_brugge, public_coastline_brugge_oostende], 3550.0, 0.017000000000000001, 0.94499905500000003, 0.931392, mid, yes,
|
|
8
|
-
gps_plan(d1, plan([train_gent_brugge, public_coastline_brugge_oostende], 2900.0, 0.018000000000000002, 0.97402500000000003, 0.95519999999999994, mid, none,
|
|
9
|
-
gps_plan(d1, plan([train_gent_brugge, buy_permit_brugge, cross_corridor_brugge_oostende], 3050.0, 0.018000000000000002, 0.95943959999999995, 0.995, mid, yes,
|
|
10
|
-
gps_plan(d1, plan([train_gent_brugge, buy_permit_brugge, public_coastline_brugge_oostende], 3350.0, 0.02, 0.95454450000000002, 0.95519999999999994, mid, yes,
|
|
11
|
-
gps_plan(d1, plan([fly_gent_kortrijk, fly_kortrijk_brugge, buy_permit_brugge, quick_charge_brugge, cross_corridor_brugge_oostende], 5150.0, 0.024, 0.94034675195999995, 0.9506969999999999, mid, yes,
|
|
12
|
-
gps_plan(d1, plan([fly_gent_kortrijk, fly_kortrijk_brugge, quick_charge_brugge, public_coastline_brugge_oostende], 5000.0, 0.024, 0.95464190250000003, 0.91266911999999989, mid, none,
|
|
13
|
-
gps_plan(d1, plan([fly_gent_kortrijk, fly_kortrijk_brugge, quick_charge_brugge, buy_permit_brugge, cross_corridor_brugge_oostende], 5150.0, 0.024, 0.94034675195999995, 0.9506969999999999, mid, yes,
|
|
14
|
-
gps_plan(d1, plan([fly_gent_kortrijk, get_zone_permit_kortrijk, fly_kortrijk_brugge, quick_charge_brugge, cross_corridor_brugge_oostende], 5000.0, 0.023, 0.95857796449800003, 0.9506969999999999, mid, yes,
|
|
15
|
-
gps_plan(d1, plan([fly_gent_kortrijk, get_zone_permit_kortrijk, fly_kortrijk_brugge, quick_charge_brugge, public_coastline_brugge_oostende], 5300.0, 0.025000000000000001, 0.95368726059749998, 0.91266911999999989, mid, yes,
|
|
16
|
-
gps_plan(d1, plan([fly_gent_kortrijk, get_zone_permit_kortrijk, emergency_charge_kortrijk, direct_corridor_kortrijk_oostende], 3500.0, 0.02, 0.94356004544999994, 0.86526000000000003, mid, yes,
|
|
17
|
-
gps_plan(d1, plan([fly_gent_kortrijk, emergency_charge_kortrijk, get_zone_permit_kortrijk, direct_corridor_kortrijk_oostende], 3500.0, 0.019999999999999997, 0.94356004544999994, 0.86526000000000003, mid, yes,
|
|
1
|
+
gps_plan(d1, plan([fly_gent_brugge, public_coastline_brugge_oostende], 2800.0, 0.012, 0.96029999999999993, 0.95039999999999991, low, none, "ttttt")).
|
|
2
|
+
gps_plan(d1, plan([fly_gent_brugge, buy_permit_brugge, public_coastline_brugge_oostende], 3250.0, 0.014, 0.94109399999999999, 0.95039999999999991, low, yes, "tttt")).
|
|
3
|
+
gps_plan(d1, plan([fly_gent_brugge, buy_permit_brugge, topup_brugge, cross_corridor_brugge_oostende], 3250.0, 0.015000000000000001, 0.94984520399999994, 0.97019999999999995, mid, yes, "ttt")).
|
|
4
|
+
gps_plan(d1, plan([fly_gent_brugge, buy_permit_brugge, topup_brugge, public_coastline_brugge_oostende], 3550.0, 0.017000000000000001, 0.94499905500000003, 0.931392, mid, yes, "ttt")).
|
|
5
|
+
gps_plan(d1, plan([fly_gent_brugge, topup_brugge, public_coastline_brugge_oostende], 3100.0, 0.015000000000000001, 0.96428475000000002, 0.931392, mid, none, "tttt")).
|
|
6
|
+
gps_plan(d1, plan([fly_gent_brugge, topup_brugge, buy_permit_brugge, cross_corridor_brugge_oostende], 3250.0, 0.015000000000000001, 0.94984520399999994, 0.97019999999999995, mid, yes, "ttt")).
|
|
7
|
+
gps_plan(d1, plan([fly_gent_brugge, topup_brugge, buy_permit_brugge, public_coastline_brugge_oostende], 3550.0, 0.017000000000000001, 0.94499905500000003, 0.931392, mid, yes, "ttt")).
|
|
8
|
+
gps_plan(d1, plan([train_gent_brugge, public_coastline_brugge_oostende], 2900.0, 0.018000000000000002, 0.97402500000000003, 0.95519999999999994, mid, none, "ttttt")).
|
|
9
|
+
gps_plan(d1, plan([train_gent_brugge, buy_permit_brugge, cross_corridor_brugge_oostende], 3050.0, 0.018000000000000002, 0.95943959999999995, 0.995, mid, yes, "tttt")).
|
|
10
|
+
gps_plan(d1, plan([train_gent_brugge, buy_permit_brugge, public_coastline_brugge_oostende], 3350.0, 0.02, 0.95454450000000002, 0.95519999999999994, mid, yes, "tttt")).
|
|
11
|
+
gps_plan(d1, plan([fly_gent_kortrijk, fly_kortrijk_brugge, buy_permit_brugge, quick_charge_brugge, cross_corridor_brugge_oostende], 5150.0, 0.024, 0.94034675195999995, 0.9506969999999999, mid, yes, "tt")).
|
|
12
|
+
gps_plan(d1, plan([fly_gent_kortrijk, fly_kortrijk_brugge, quick_charge_brugge, public_coastline_brugge_oostende], 5000.0, 0.024, 0.95464190250000003, 0.91266911999999989, mid, none, "ttt")).
|
|
13
|
+
gps_plan(d1, plan([fly_gent_kortrijk, fly_kortrijk_brugge, quick_charge_brugge, buy_permit_brugge, cross_corridor_brugge_oostende], 5150.0, 0.024, 0.94034675195999995, 0.9506969999999999, mid, yes, "tt")).
|
|
14
|
+
gps_plan(d1, plan([fly_gent_kortrijk, get_zone_permit_kortrijk, fly_kortrijk_brugge, quick_charge_brugge, cross_corridor_brugge_oostende], 5000.0, 0.023, 0.95857796449800003, 0.9506969999999999, mid, yes, "tt")).
|
|
15
|
+
gps_plan(d1, plan([fly_gent_kortrijk, get_zone_permit_kortrijk, fly_kortrijk_brugge, quick_charge_brugge, public_coastline_brugge_oostende], 5300.0, 0.025000000000000001, 0.95368726059749998, 0.91266911999999989, mid, yes, "tt")).
|
|
16
|
+
gps_plan(d1, plan([fly_gent_kortrijk, get_zone_permit_kortrijk, emergency_charge_kortrijk, direct_corridor_kortrijk_oostende], 3500.0, 0.02, 0.94356004544999994, 0.86526000000000003, mid, yes, "ttt")).
|
|
17
|
+
gps_plan(d1, plan([fly_gent_kortrijk, emergency_charge_kortrijk, get_zone_permit_kortrijk, direct_corridor_kortrijk_oostende], 3500.0, 0.019999999999999997, 0.94356004544999994, 0.86526000000000003, mid, yes, "ttt")).
|
|
@@ -44,16 +44,16 @@ why(
|
|
|
44
44
|
)
|
|
45
45
|
).
|
|
46
46
|
|
|
47
|
-
tail(nativeList,
|
|
47
|
+
tail(nativeList, "bc").
|
|
48
48
|
why(
|
|
49
|
-
tail(nativeList,
|
|
49
|
+
tail(nativeList, "bc"),
|
|
50
50
|
proof(
|
|
51
|
-
goal(tail(nativeList,
|
|
51
|
+
goal(tail(nativeList, "bc")),
|
|
52
52
|
by(rule("aliases-and-namespaces.pl", clause(4))),
|
|
53
|
-
bindings([binding("Tail",
|
|
53
|
+
bindings([binding("Tail", "bc"), binding("_head", a)]),
|
|
54
54
|
uses([
|
|
55
55
|
proof(
|
|
56
|
-
goal(=(
|
|
56
|
+
goal(=("abc", "abc")),
|
|
57
57
|
by(builtin(=, 2))
|
|
58
58
|
)
|
|
59
59
|
])
|
|
@@ -11,48 +11,48 @@ why(
|
|
|
11
11
|
bindings([binding("Start", a), binding("Goal", f)]),
|
|
12
12
|
uses([
|
|
13
13
|
proof(
|
|
14
|
-
goal(reachable(a, f,
|
|
14
|
+
goal(reachable(a, f, "a")),
|
|
15
15
|
by(rule("graph-reachability.pl", clause(9))),
|
|
16
|
-
bindings([binding("Start", a), binding("Goal", f), binding("Visited",
|
|
16
|
+
bindings([binding("Start", a), binding("Goal", f), binding("Visited", "a"), binding("Next", b)]),
|
|
17
17
|
uses([
|
|
18
18
|
proof(
|
|
19
19
|
goal(edge(a, b)),
|
|
20
20
|
by(fact("graph-reachability.pl", clause(1)))
|
|
21
21
|
),
|
|
22
22
|
proof(
|
|
23
|
-
goal('\\+'(member(b,
|
|
23
|
+
goal('\\+'(member(b, "a"))),
|
|
24
24
|
by(builtin('\\+', 1))
|
|
25
25
|
),
|
|
26
26
|
proof(
|
|
27
|
-
goal(reachable(b, f,
|
|
27
|
+
goal(reachable(b, f, "ba")),
|
|
28
28
|
by(rule("graph-reachability.pl", clause(9))),
|
|
29
|
-
bindings([binding("Start", b), binding("Goal", f), binding("Visited",
|
|
29
|
+
bindings([binding("Start", b), binding("Goal", f), binding("Visited", "ba"), binding("Next", d)]),
|
|
30
30
|
uses([
|
|
31
31
|
proof(
|
|
32
32
|
goal(edge(b, d)),
|
|
33
33
|
by(fact("graph-reachability.pl", clause(3)))
|
|
34
34
|
),
|
|
35
35
|
proof(
|
|
36
|
-
goal('\\+'(member(d,
|
|
36
|
+
goal('\\+'(member(d, "ba"))),
|
|
37
37
|
by(builtin('\\+', 1))
|
|
38
38
|
),
|
|
39
39
|
proof(
|
|
40
|
-
goal(reachable(d, f,
|
|
40
|
+
goal(reachable(d, f, "dba")),
|
|
41
41
|
by(rule("graph-reachability.pl", clause(9))),
|
|
42
|
-
bindings([binding("Start", d), binding("Goal", f), binding("Visited",
|
|
42
|
+
bindings([binding("Start", d), binding("Goal", f), binding("Visited", "dba"), binding("Next", f)]),
|
|
43
43
|
uses([
|
|
44
44
|
proof(
|
|
45
45
|
goal(edge(d, f)),
|
|
46
46
|
by(fact("graph-reachability.pl", clause(5)))
|
|
47
47
|
),
|
|
48
48
|
proof(
|
|
49
|
-
goal('\\+'(member(f,
|
|
49
|
+
goal('\\+'(member(f, "dba"))),
|
|
50
50
|
by(builtin('\\+', 1))
|
|
51
51
|
),
|
|
52
52
|
proof(
|
|
53
|
-
goal(reachable(f, f,
|
|
53
|
+
goal(reachable(f, f, "fdba")),
|
|
54
54
|
by(fact("graph-reachability.pl", clause(8))),
|
|
55
|
-
bindings([binding("Node", f), binding("_visited",
|
|
55
|
+
bindings([binding("Node", f), binding("_visited", "fdba")])
|
|
56
56
|
)
|
|
57
57
|
])
|
|
58
58
|
)
|
|
@@ -79,48 +79,48 @@ why(
|
|
|
79
79
|
bindings([binding("Start", c), binding("Goal", g)]),
|
|
80
80
|
uses([
|
|
81
81
|
proof(
|
|
82
|
-
goal(reachable(c, g,
|
|
82
|
+
goal(reachable(c, g, "c")),
|
|
83
83
|
by(rule("graph-reachability.pl", clause(9))),
|
|
84
|
-
bindings([binding("Start", c), binding("Goal", g), binding("Visited",
|
|
84
|
+
bindings([binding("Start", c), binding("Goal", g), binding("Visited", "c"), binding("Next", e)]),
|
|
85
85
|
uses([
|
|
86
86
|
proof(
|
|
87
87
|
goal(edge(c, e)),
|
|
88
88
|
by(fact("graph-reachability.pl", clause(4)))
|
|
89
89
|
),
|
|
90
90
|
proof(
|
|
91
|
-
goal('\\+'(member(e,
|
|
91
|
+
goal('\\+'(member(e, "c"))),
|
|
92
92
|
by(builtin('\\+', 1))
|
|
93
93
|
),
|
|
94
94
|
proof(
|
|
95
|
-
goal(reachable(e, g,
|
|
95
|
+
goal(reachable(e, g, "ec")),
|
|
96
96
|
by(rule("graph-reachability.pl", clause(9))),
|
|
97
|
-
bindings([binding("Start", e), binding("Goal", g), binding("Visited",
|
|
97
|
+
bindings([binding("Start", e), binding("Goal", g), binding("Visited", "ec"), binding("Next", f)]),
|
|
98
98
|
uses([
|
|
99
99
|
proof(
|
|
100
100
|
goal(edge(e, f)),
|
|
101
101
|
by(fact("graph-reachability.pl", clause(6)))
|
|
102
102
|
),
|
|
103
103
|
proof(
|
|
104
|
-
goal('\\+'(member(f,
|
|
104
|
+
goal('\\+'(member(f, "ec"))),
|
|
105
105
|
by(builtin('\\+', 1))
|
|
106
106
|
),
|
|
107
107
|
proof(
|
|
108
|
-
goal(reachable(f, g,
|
|
108
|
+
goal(reachable(f, g, "fec")),
|
|
109
109
|
by(rule("graph-reachability.pl", clause(9))),
|
|
110
|
-
bindings([binding("Start", f), binding("Goal", g), binding("Visited",
|
|
110
|
+
bindings([binding("Start", f), binding("Goal", g), binding("Visited", "fec"), binding("Next", g)]),
|
|
111
111
|
uses([
|
|
112
112
|
proof(
|
|
113
113
|
goal(edge(f, g)),
|
|
114
114
|
by(fact("graph-reachability.pl", clause(7)))
|
|
115
115
|
),
|
|
116
116
|
proof(
|
|
117
|
-
goal('\\+'(member(g,
|
|
117
|
+
goal('\\+'(member(g, "fec"))),
|
|
118
118
|
by(builtin('\\+', 1))
|
|
119
119
|
),
|
|
120
120
|
proof(
|
|
121
|
-
goal(reachable(g, g,
|
|
121
|
+
goal(reachable(g, g, "gfec")),
|
|
122
122
|
by(fact("graph-reachability.pl", clause(8))),
|
|
123
|
-
bindings([binding("Node", g), binding("_visited",
|
|
123
|
+
bindings([binding("Node", g), binding("_visited", "gfec")])
|
|
124
124
|
)
|
|
125
125
|
])
|
|
126
126
|
)
|
|
@@ -78,20 +78,20 @@ why(
|
|
|
78
78
|
)
|
|
79
79
|
).
|
|
80
80
|
|
|
81
|
-
collectionAppend(letters,
|
|
81
|
+
collectionAppend(letters, "abc").
|
|
82
82
|
why(
|
|
83
|
-
collectionAppend(letters,
|
|
83
|
+
collectionAppend(letters, "abc"),
|
|
84
84
|
proof(
|
|
85
|
-
goal(collectionAppend(letters,
|
|
85
|
+
goal(collectionAppend(letters, "abc")),
|
|
86
86
|
by(rule("list-collection.pl", clause(5))),
|
|
87
|
-
bindings([binding("Extended",
|
|
87
|
+
bindings([binding("Extended", "abc"), binding("List", "ab")]),
|
|
88
88
|
uses([
|
|
89
89
|
proof(
|
|
90
|
-
goal(collection(letters,
|
|
90
|
+
goal(collection(letters, "ab")),
|
|
91
91
|
by(fact("list-collection.pl", clause(2)))
|
|
92
92
|
),
|
|
93
93
|
proof(
|
|
94
|
-
goal(append(
|
|
94
|
+
goal(append("ab", "c", "abc")),
|
|
95
95
|
by(library(append, 3))
|
|
96
96
|
)
|
|
97
97
|
])
|
|
@@ -104,26 +104,26 @@ why(
|
|
|
104
104
|
proof(
|
|
105
105
|
goal(head(letters, a)),
|
|
106
106
|
by(rule("list-collection.pl", clause(6))),
|
|
107
|
-
bindings([binding("Head", a), binding("_tail",
|
|
107
|
+
bindings([binding("Head", a), binding("_tail", "b")]),
|
|
108
108
|
uses([
|
|
109
109
|
proof(
|
|
110
|
-
goal(collection(letters,
|
|
110
|
+
goal(collection(letters, "ab")),
|
|
111
111
|
by(fact("list-collection.pl", clause(2)))
|
|
112
112
|
)
|
|
113
113
|
])
|
|
114
114
|
)
|
|
115
115
|
).
|
|
116
116
|
|
|
117
|
-
tail(letters,
|
|
117
|
+
tail(letters, "b").
|
|
118
118
|
why(
|
|
119
|
-
tail(letters,
|
|
119
|
+
tail(letters, "b"),
|
|
120
120
|
proof(
|
|
121
|
-
goal(tail(letters,
|
|
121
|
+
goal(tail(letters, "b")),
|
|
122
122
|
by(rule("list-collection.pl", clause(7))),
|
|
123
|
-
bindings([binding("Tail",
|
|
123
|
+
bindings([binding("Tail", "b"), binding("_head", a)]),
|
|
124
124
|
uses([
|
|
125
125
|
proof(
|
|
126
|
-
goal(collection(letters,
|
|
126
|
+
goal(collection(letters, "ab")),
|
|
127
127
|
by(fact("list-collection.pl", clause(2)))
|
|
128
128
|
)
|
|
129
129
|
])
|
package/index.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export interface EyePrologRunOptions {
|
|
|
16
16
|
sourceMetadata?: boolean;
|
|
17
17
|
strictNegation?: boolean;
|
|
18
18
|
analyzeNegation?: boolean;
|
|
19
|
+
/** Initial ISO interpretation of double-quoted list notation. Defaults to chars. */
|
|
20
|
+
doubleQuotes?: 'chars' | 'codes' | 'atom';
|
|
19
21
|
ioOptions?: {
|
|
20
22
|
input?: string;
|
|
21
23
|
write?: (text: string) => void;
|
|
@@ -88,6 +90,7 @@ export class Program {
|
|
|
88
90
|
constructor(clauses?: EyePrologClause[], options?: EyePrologRunOptions);
|
|
89
91
|
clauses: EyePrologClause[];
|
|
90
92
|
groups: Map<string, EyePrologPredicateGroup>;
|
|
93
|
+
doubleQuotes: 'chars' | 'codes' | 'atom';
|
|
91
94
|
negationDependencies: Array<{ from: string; to: string; negative: boolean }>;
|
|
92
95
|
negationStratificationErrors: Array<{ from: string; to: string }>;
|
|
93
96
|
stratifiedNegation: boolean;
|
|
@@ -101,7 +104,7 @@ export class Program {
|
|
|
101
104
|
assertStratifiedNegation(): true;
|
|
102
105
|
isStratifiedNegation(): boolean;
|
|
103
106
|
groupHasRule(group: EyePrologPredicateGroup): boolean;
|
|
104
|
-
sourceFactLines(predicateKeys?: Set<string> | null): Set<string>;
|
|
107
|
+
sourceFactLines(predicateKeys?: Set<string> | null, options?: { doubleQuotes?: 'chars' | 'codes' | 'atom' }): Set<string>;
|
|
105
108
|
}
|
|
106
109
|
|
|
107
110
|
export interface BuiltinDefinition {
|
|
@@ -181,7 +184,7 @@ export function compareNumberText(left: string, right: string): number;
|
|
|
181
184
|
export function makeProgram(source: string, options?: EyePrologRunOptions): Program;
|
|
182
185
|
export function parseClauses(source: string, options?: EyePrologRunOptions): EyePrologClause[];
|
|
183
186
|
export function parseProgramText(source: string, options?: EyePrologRunOptions): EyePrologClause[];
|
|
184
|
-
export function parseGoalText(source: string): EyePrologTerm;
|
|
187
|
+
export function parseGoalText(source: string, options?: EyePrologRunOptions): EyePrologTerm;
|
|
185
188
|
export function createDefaultRegistry(): BuiltinRegistry;
|
|
186
189
|
export function createEyePrologRegistry(): BuiltinRegistry;
|
|
187
190
|
export function getDefaultRegistry(): BuiltinRegistry;
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -128,22 +128,27 @@ async function loadExplanation() {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
async function runDefault(engine, program, options) {
|
|
131
|
+
const registry = engine.getEyePrologRegistry();
|
|
132
|
+
const solver = new engine.Solver(program, {
|
|
133
|
+
registry,
|
|
134
|
+
ioOptions: { write: (text) => process.stdout.write(String(text)) },
|
|
135
|
+
});
|
|
136
|
+
program = solver.program;
|
|
131
137
|
const goals = options.goals.map((text) => {
|
|
132
|
-
const goal = engine.parseGoalText(text
|
|
138
|
+
const goal = engine.parseGoalText(text, {
|
|
139
|
+
doubleQuotes: solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
|
|
140
|
+
});
|
|
133
141
|
if (goal.type === 'var') throw new engine.PrologError('instantiation_error');
|
|
134
142
|
if (goal.type !== 'atom' && goal.type !== 'compound') throw new engine.PrologError('type_error(callable)', goal);
|
|
135
143
|
return goal;
|
|
136
144
|
});
|
|
137
145
|
const queriedKeys = new Set(goals.map((goal) => `${goal.name}/${goal.arity}`));
|
|
138
|
-
const
|
|
146
|
+
const writeOptions = {
|
|
147
|
+
doubleQuotes: solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
|
|
148
|
+
};
|
|
149
|
+
const facts = program.sourceFactLines(queriedKeys, writeOptions);
|
|
139
150
|
const lines = new Set();
|
|
140
|
-
const registry = engine.getEyePrologRegistry();
|
|
141
151
|
const explanation = options.proof ? await loadExplanation() : null;
|
|
142
|
-
const solver = new engine.Solver(program, {
|
|
143
|
-
registry,
|
|
144
|
-
ioOptions: { write: (text) => process.stdout.write(String(text)) },
|
|
145
|
-
});
|
|
146
|
-
program = solver.program;
|
|
147
152
|
try {
|
|
148
153
|
solver.runInitializations();
|
|
149
154
|
for (const goal of goals) {
|
|
@@ -151,7 +156,10 @@ async function runDefault(engine, program, options) {
|
|
|
151
156
|
for (const env of solver.solve([goal], new engine.Env(), 0)) {
|
|
152
157
|
if (!engine.termIsGround(goal, env)) continue;
|
|
153
158
|
|
|
154
|
-
const
|
|
159
|
+
const currentWriteOptions = {
|
|
160
|
+
doubleQuotes: solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
|
|
161
|
+
};
|
|
162
|
+
const line = `${engine.termToString(goal, env, true, currentWriteOptions)}.\n`;
|
|
155
163
|
if (facts.has(line) || lines.has(line)) continue;
|
|
156
164
|
|
|
157
165
|
lines.add(line);
|
package/src/index.js
CHANGED
|
@@ -47,9 +47,12 @@ export function run(source, options = {}) {
|
|
|
47
47
|
},
|
|
48
48
|
});
|
|
49
49
|
program = solver.program;
|
|
50
|
-
const goals = normalizeGoals(options);
|
|
50
|
+
const goals = normalizeGoals(options, solver);
|
|
51
|
+
const writeOptions = {
|
|
52
|
+
doubleQuotes: solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
|
|
53
|
+
};
|
|
51
54
|
const queriedKeys = new Set(goals.map((goal) => `${goal.name}/${goal.arity}`));
|
|
52
|
-
const facts = program.sourceFactLines(queriedKeys);
|
|
55
|
+
const facts = program.sourceFactLines(queriedKeys, writeOptions);
|
|
53
56
|
const seen = new Set();
|
|
54
57
|
let haltCode = null;
|
|
55
58
|
try {
|
|
@@ -59,7 +62,10 @@ export function run(source, options = {}) {
|
|
|
59
62
|
for (const env of solver.solve([goal], new Env(), 0)) {
|
|
60
63
|
const resolved = copyResolved(goal, env);
|
|
61
64
|
if (!termIsGround(resolved)) continue;
|
|
62
|
-
const
|
|
65
|
+
const currentWriteOptions = {
|
|
66
|
+
doubleQuotes: solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
|
|
67
|
+
};
|
|
68
|
+
const line = `${termToString(resolved, new Env(), true, currentWriteOptions)}.\n`;
|
|
63
69
|
if (facts.has(line) || seen.has(line)) continue;
|
|
64
70
|
seen.add(line);
|
|
65
71
|
output.push(line);
|
|
@@ -73,10 +79,14 @@ export function run(source, options = {}) {
|
|
|
73
79
|
return { stdout: output.join(''), stats: solver.stats, haltCode };
|
|
74
80
|
}
|
|
75
81
|
|
|
76
|
-
function normalizeGoals(options) {
|
|
82
|
+
function normalizeGoals(options, solver) {
|
|
77
83
|
const requested = options.goals ?? (options.goal == null ? [] : [options.goal]);
|
|
78
84
|
return requested.map((requestedGoal) => {
|
|
79
|
-
const goal = typeof requestedGoal === 'string'
|
|
85
|
+
const goal = typeof requestedGoal === 'string'
|
|
86
|
+
? parseGoalText(requestedGoal, {
|
|
87
|
+
doubleQuotes: solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
|
|
88
|
+
})
|
|
89
|
+
: requestedGoal;
|
|
80
90
|
if (goal.type === VAR) throw new PrologError('instantiation_error');
|
|
81
91
|
if (goal.type !== ATOM && goal.type !== COMPOUND) throw new PrologError('type_error(callable)', goal);
|
|
82
92
|
return goal;
|
package/src/iso.js
CHANGED
|
@@ -920,6 +920,7 @@ function readTermFromStream(stream, solver) {
|
|
|
920
920
|
const clauses = parseClauses(convertedTermText(candidate.text, solver), {
|
|
921
921
|
sourceMetadata: false,
|
|
922
922
|
operatorState,
|
|
923
|
+
doubleQuotes: solver.prologFlags.get('double_quotes')?.value?.name ?? 'chars',
|
|
923
924
|
});
|
|
924
925
|
if (clauses.length !== 1 || clauses[0].body.length) throw new Error('bad term');
|
|
925
926
|
stream.position = candidate.end;
|
package/src/parser.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Tokenizer and recursive-descent parser for the EyeProlog source language.
|
|
2
2
|
// It preserves the compact Prolog-like syntax while producing Term objects for the solver.
|
|
3
|
-
import { atom, compound, cons, emptyList, numberTerm,
|
|
3
|
+
import { atom, compound, cons, emptyList, numberTerm, variable } from './term.js';
|
|
4
4
|
|
|
5
5
|
const TOK = {
|
|
6
6
|
EOF: 'eof', ATOM: 'atom', VAR: 'var', STRING: 'string', NUMBER: 'number',
|
|
@@ -143,6 +143,12 @@ class Parser {
|
|
|
143
143
|
this.line = 1;
|
|
144
144
|
this.anonymous = 0;
|
|
145
145
|
this.sourceMetadata = options.sourceMetadata !== false;
|
|
146
|
+
this.parserFlagState = options.parserFlagState ?? {
|
|
147
|
+
doubleQuotes: options.doubleQuotes ?? 'chars',
|
|
148
|
+
};
|
|
149
|
+
if (!['chars', 'codes', 'atom'].includes(this.parserFlagState.doubleQuotes)) {
|
|
150
|
+
throw new Error(`invalid double_quotes parser flag: ${this.parserFlagState.doubleQuotes}`);
|
|
151
|
+
}
|
|
146
152
|
const operatorState = options.operatorState ?? createParserOperatorState(
|
|
147
153
|
options.operatorDefinitions ?? [],
|
|
148
154
|
options.includeDefaultOperators !== false,
|
|
@@ -174,6 +180,14 @@ class Parser {
|
|
|
174
180
|
for (const name of names) this.defineOperator(priority, specifierTerm.name, name);
|
|
175
181
|
return true;
|
|
176
182
|
}
|
|
183
|
+
applyParserFlagDirective(directive) {
|
|
184
|
+
if (directive.type !== 'compound' || directive.name !== 'set_prolog_flag' || directive.arity !== 2) return;
|
|
185
|
+
const [flag, value] = directive.args;
|
|
186
|
+
if (flag.type === 'atom' && flag.name === 'double_quotes' &&
|
|
187
|
+
value.type === 'atom' && ['chars', 'codes', 'atom'].includes(value.name)) {
|
|
188
|
+
this.parserFlagState.doubleQuotes = value.name;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
177
191
|
peek(offset = 0) {
|
|
178
192
|
return this.source[this.pos + offset] ?? '';
|
|
179
193
|
}
|
|
@@ -494,7 +508,31 @@ class Parser {
|
|
|
494
508
|
if (this.token.type === TOK.STRING) {
|
|
495
509
|
const value = this.token.text;
|
|
496
510
|
this.advance();
|
|
497
|
-
|
|
511
|
+
if (this.parserFlagState.doubleQuotes === 'atom') {
|
|
512
|
+
if (this.token.type === TOK.LPAREN) {
|
|
513
|
+
this.advance();
|
|
514
|
+
const args = [];
|
|
515
|
+
if (this.token.type === TOK.RPAREN) {
|
|
516
|
+
throw new Error(`parse line ${this.token.line}: zero-arity compound syntax is not supported; use atom ${JSON.stringify(value)} for arity zero data`);
|
|
517
|
+
}
|
|
518
|
+
while (true) {
|
|
519
|
+
args.push(this.parseTerm(0, false));
|
|
520
|
+
if (this.token.type !== TOK.COMMA) break;
|
|
521
|
+
this.advance();
|
|
522
|
+
}
|
|
523
|
+
this.expect(TOK.RPAREN, ')');
|
|
524
|
+
this.advance();
|
|
525
|
+
return compound(value, args);
|
|
526
|
+
}
|
|
527
|
+
return atom(value);
|
|
528
|
+
}
|
|
529
|
+
const items = Array.from(value, (character) =>
|
|
530
|
+
this.parserFlagState.doubleQuotes === 'chars'
|
|
531
|
+
? atom(character)
|
|
532
|
+
: numberTerm(character.codePointAt(0)));
|
|
533
|
+
let list = emptyList();
|
|
534
|
+
for (let i = items.length - 1; i >= 0; i--) list = cons(items[i], list);
|
|
535
|
+
return list;
|
|
498
536
|
}
|
|
499
537
|
if (this.token.type === TOK.NUMBER) {
|
|
500
538
|
const value = this.token.text;
|
|
@@ -544,6 +582,7 @@ class Parser {
|
|
|
544
582
|
throw new Error(`parse line ${line}: bad term`);
|
|
545
583
|
}
|
|
546
584
|
this.expect(TOK.DOT, '.');
|
|
585
|
+
this.applyParserFlagDirective(directive);
|
|
547
586
|
this.advance();
|
|
548
587
|
const clause = { head: compound(':-', [directive]), body: [] };
|
|
549
588
|
clauseNumber++;
|
|
@@ -588,11 +627,17 @@ function listAtomNames(term) {
|
|
|
588
627
|
|
|
589
628
|
|
|
590
629
|
export function parseClauses(source, options = {}) {
|
|
630
|
+
const ownsParserFlagState = options.parserFlagState == null;
|
|
631
|
+
const initialDoubleQuotes = options.doubleQuotes ?? 'chars';
|
|
632
|
+
const parserOptions = ownsParserFlagState
|
|
633
|
+
? { ...options, parserFlagState: { doubleQuotes: initialDoubleQuotes } }
|
|
634
|
+
: options;
|
|
591
635
|
if (options.sourceMetadata === false) {
|
|
592
|
-
const clauses = parseClausesFastNoSource(source);
|
|
636
|
+
const clauses = parseClausesFastNoSource(source, null, null, parserOptions);
|
|
593
637
|
if (clauses) return clauses;
|
|
638
|
+
if (ownsParserFlagState) parserOptions.parserFlagState.doubleQuotes = initialDoubleQuotes;
|
|
594
639
|
}
|
|
595
|
-
return new Parser(source,
|
|
640
|
+
return new Parser(source, parserOptions).parseProgram();
|
|
596
641
|
}
|
|
597
642
|
|
|
598
643
|
// Streaming parser entry points used by ProgramBuilder. The ordinary public
|
|
@@ -602,8 +647,8 @@ export function parseClausesInto(source, options = {}, emit) {
|
|
|
602
647
|
new Parser(source, options).parseProgram(emit);
|
|
603
648
|
}
|
|
604
649
|
|
|
605
|
-
export function tryParseClausesFastInto(source, emit, emitBinary = null) {
|
|
606
|
-
return parseClausesFastNoSource(source, emit, emitBinary) !== null;
|
|
650
|
+
export function tryParseClausesFastInto(source, emit, emitBinary = null, options = {}) {
|
|
651
|
+
return parseClausesFastNoSource(source, emit, emitBinary, options) !== null;
|
|
607
652
|
}
|
|
608
653
|
|
|
609
654
|
function isSimpleName(text) {
|
|
@@ -624,7 +669,7 @@ const SIMPLE_VARIABLE = /^(?:_|[A-Z_][A-Za-z0-9_]*)$/;
|
|
|
624
669
|
const SIMPLE_ATOM = /^[a-z][A-Za-z0-9_]*$/;
|
|
625
670
|
const GRAPHIC_ATOM = /^[#$&*+\-\/<=>@^~\\]+$/;
|
|
626
671
|
|
|
627
|
-
function parseClausesFastNoSource(source, emit = null, emitBinary = null) {
|
|
672
|
+
function parseClausesFastNoSource(source, emit = null, emitBinary = null, options = {}) {
|
|
628
673
|
source = String(source ?? '');
|
|
629
674
|
const numberCache = new Map();
|
|
630
675
|
const stringCache = new Map();
|
|
@@ -896,7 +941,7 @@ function parseClausesFastNoSource(source, emit = null, emitBinary = null) {
|
|
|
896
941
|
return true;
|
|
897
942
|
}
|
|
898
943
|
try {
|
|
899
|
-
const parsed = new Parser(text, { sourceMetadata: false }).parseProgram();
|
|
944
|
+
const parsed = new Parser(text, { ...options, sourceMetadata: false }).parseProgram();
|
|
900
945
|
for (const clause of parsed) accept(clause);
|
|
901
946
|
return true;
|
|
902
947
|
} catch (_) {
|
|
@@ -938,12 +983,12 @@ function parseClausesFastNoSource(source, emit = null, emitBinary = null) {
|
|
|
938
983
|
return clauses ?? true;
|
|
939
984
|
}
|
|
940
985
|
|
|
941
|
-
export function parseProgramText(source) {
|
|
942
|
-
return parseClauses(source);
|
|
986
|
+
export function parseProgramText(source, options = {}) {
|
|
987
|
+
return parseClauses(source, options);
|
|
943
988
|
}
|
|
944
989
|
|
|
945
|
-
export function parseGoalText(text) {
|
|
946
|
-
const clauses = parseClauses(`zz_goal((${text}))
|
|
990
|
+
export function parseGoalText(text, options = {}) {
|
|
991
|
+
const clauses = parseClauses(`zz_goal((${text})).`, options);
|
|
947
992
|
const head = clauses[0]?.head;
|
|
948
993
|
if (clauses.length !== 1 || head?.type !== 'compound' ||
|
|
949
994
|
head.name !== 'zz_goal' || head.arity !== 1 || clauses[0].body.length !== 0) {
|