eyelang 1.1.19 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/guide.md +5 -4
- package/docs/language-reference.md +6 -3
- package/examples/complex.pl +22 -15
- package/examples/graph.pl +35 -0
- package/examples/output/complex.pl +6 -1
- package/examples/output/graph.pl +21 -0
- package/examples/output/web-names.pl +10 -0
- package/examples/web-names.pl +83 -0
- package/package.json +1 -1
- package/playground.html +152 -150
- package/src/parser.js +17 -2
- package/src/term.js +1 -1
- package/test/run-regression.mjs +7 -0
package/docs/guide.md
CHANGED
|
@@ -302,10 +302,8 @@ Use `holds/2` when you want to match the member term directly, for example `name
|
|
|
302
302
|
|
|
303
303
|
## Example catalog
|
|
304
304
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
| Example | What it demonstrates | Golden output |
|
|
308
|
-
|---|---|---|
|
|
305
|
+
| Example | Description | Golden output |
|
|
306
|
+
| --- | --- | --- |
|
|
309
307
|
| [`access-control-policy.pl`](../examples/access-control-policy.pl) | Evaluates role and condition based access decisions. | [`output/access-control-policy.pl`](../examples/output/access-control-policy.pl) |
|
|
310
308
|
| [`ackermann.pl`](../examples/ackermann.pl) | Computes Ackermann-style hyperoperation values. | [`output/ackermann.pl`](../examples/output/ackermann.pl) |
|
|
311
309
|
| [`age.pl`](../examples/age.pl) | Checks whether people meet age thresholds. | [`output/age.pl`](../examples/output/age.pl) |
|
|
@@ -385,6 +383,7 @@ Each example has a checked golden output in `examples/output`.
|
|
|
385
383
|
| [`gdpr-compliance.pl`](../examples/gdpr-compliance.pl) | Checks GDPR-style processing compliance. | [`output/gdpr-compliance.pl`](../examples/output/gdpr-compliance.pl) |
|
|
386
384
|
| [`good-cobbler.pl`](../examples/good-cobbler.pl) | Demonstrates term-level structure with a good-cobbler statement. | [`output/good-cobbler.pl`](../examples/output/good-cobbler.pl) |
|
|
387
385
|
| [`gps.pl`](../examples/gps.pl) | Finds and verifies route paths. | [`output/gps.pl`](../examples/output/gps.pl) |
|
|
386
|
+
| [`graph.pl`](../examples/graph.pl) | Derives transitive paths over French-city road links while showing the productive recursive rule order. | [`output/graph.pl`](../examples/output/graph.pl) |
|
|
388
387
|
| [`graph-reachability.pl`](../examples/graph-reachability.pl) | Derives reachable nodes in a graph. | [`output/graph-reachability.pl`](../examples/output/graph-reachability.pl) |
|
|
389
388
|
| [`gray-code-counter.pl`](../examples/gray-code-counter.pl) | Generates Gray-code counter states. | [`output/gray-code-counter.pl`](../examples/output/gray-code-counter.pl) |
|
|
390
389
|
| [`greatest-lower-bound-uniqueness.pl`](../examples/greatest-lower-bound-uniqueness.pl) | Shows uniqueness of greatest lower bounds in a finite order instance. | [`output/greatest-lower-bound-uniqueness.pl`](../examples/output/greatest-lower-bound-uniqueness.pl) |
|
|
@@ -452,10 +451,12 @@ Each example has a checked golden output in `examples/output`.
|
|
|
452
451
|
| [`turing.pl`](../examples/turing.pl) | Simulates a binary-increment Turing machine. | [`output/turing.pl`](../examples/output/turing.pl) |
|
|
453
452
|
| [`vector-similarity.pl`](../examples/vector-similarity.pl) | Computes dot product, norm, and cosine similarity. | [`output/vector-similarity.pl`](../examples/output/vector-similarity.pl) |
|
|
454
453
|
| [`vulnerability-impact.pl`](../examples/vulnerability-impact.pl) | Analyzes vulnerable transitive dependencies and urgent patch impact. | [`output/vulnerability-impact.pl`](../examples/output/vulnerability-impact.pl) |
|
|
454
|
+
| [`web-names.pl`](../examples/web-names.pl) | Uses compact `web(Space, Local)` terms as readable global names and expands selected names to URIs. | [`output/web-names.pl`](../examples/output/web-names.pl) |
|
|
455
455
|
| [`weighted-interval-scheduling.pl`](../examples/weighted-interval-scheduling.pl) | Selects the best non-overlapping weighted intervals with memoized dynamic programming. | [`output/weighted-interval-scheduling.pl`](../examples/output/weighted-interval-scheduling.pl) |
|
|
456
456
|
| [`witch.pl`](../examples/witch.pl) | Derives the classic “burn the witch” rule chain. | [`output/witch.pl`](../examples/output/witch.pl) |
|
|
457
457
|
| [`wolf-goat-cabbage.pl`](../examples/wolf-goat-cabbage.pl) | Solves the wolf-goat-cabbage river crossing. | [`output/wolf-goat-cabbage.pl`](../examples/output/wolf-goat-cabbage.pl) |
|
|
458
458
|
| [`zebra.pl`](../examples/zebra.pl) | Solves the zebra logic puzzle. | [`output/zebra.pl`](../examples/output/zebra.pl) |
|
|
459
|
+
|
|
459
460
|
## Golden outputs, tests, and conformance
|
|
460
461
|
|
|
461
462
|
Golden answer outputs live in [`examples/output`](../examples/output). `npm run test:eyelang` covers the eyelang integration check, conformance cases, regression checks, runnable examples, and proof-output examples. A curated proof-output suite for `.pl` examples lives in [`examples/proof`](../examples/proof). Example tests pin `local_time/1` to `2026-05-30` so date-dependent examples stay deterministic. Regenerate them after an intentional output or explanation change:
|
|
@@ -119,7 +119,7 @@ The punctuation tokens are:
|
|
|
119
119
|
( ) [ ] , | . :-
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
A colon outside `:-` is not part of the language. Namespace-like names SHOULD be written as plain atom constants such as `person_type` or `
|
|
122
|
+
A colon outside `:-` is not part of the language. Namespace-like names SHOULD be written as plain atom constants such as `person_type`, `odrl_permission`, or dotted atom constants such as `org.schema`.
|
|
123
123
|
|
|
124
124
|
### 3.4 Variables
|
|
125
125
|
|
|
@@ -138,12 +138,15 @@ Each `_` anonymous variable occurrence is fresh.
|
|
|
138
138
|
|
|
139
139
|
### 3.5 Atom constants
|
|
140
140
|
|
|
141
|
-
A plain atom constant starts with a lowercase ASCII letter and is followed by zero or more ASCII letters, digits, or underscores.
|
|
141
|
+
A plain atom constant starts with a lowercase ASCII letter and is followed by zero or more ASCII letters, digits, or underscores. For compact globally scoped names, eyelang also permits dot-separated plain atom segments, such as `be.ugent`, `org.schema`, or `eyereasoner.github`. A dot ends a clause only when it is not followed by another lowercase-starting segment. Names such as `a-b` or `http://example` MUST still be quoted if they are meant as one atom constant:
|
|
142
142
|
|
|
143
143
|
```prolog
|
|
144
144
|
pat
|
|
145
145
|
type
|
|
146
146
|
case_123
|
|
147
|
+
be.ugent
|
|
148
|
+
org.schema
|
|
149
|
+
eyereasoner.github
|
|
147
150
|
'a-b'
|
|
148
151
|
'http://example'
|
|
149
152
|
```
|
|
@@ -655,7 +658,7 @@ eyelang source is intended to be a subset of familiar Prolog term and Horn-claus
|
|
|
655
658
|
- no variables in functor or predicate position;
|
|
656
659
|
- no occurs check in unification.
|
|
657
660
|
|
|
658
|
-
Programs intended to be portable to eyelang SHOULD avoid ISO-specific syntax and keep terms explicit. Atom names that are not plain lowercase-starting names or graphic atom tokens SHOULD be written as quoted atoms, for example `'a-b'`.
|
|
661
|
+
Programs intended to be portable to eyelang SHOULD avoid ISO-specific syntax and keep terms explicit. Atom names that are not plain lowercase-starting names, dot-separated plain names, or graphic atom tokens SHOULD be written as quoted atoms, for example `'a-b'`.
|
|
659
662
|
|
|
660
663
|
## 16. Examples
|
|
661
664
|
|
package/examples/complex.pl
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
% The example derives arithmetic identities, polar conversions, powers, roots,
|
|
9
9
|
% exponential/trigonometric functions, and distance/normalization results from
|
|
10
10
|
% a small complex-number toolkit.
|
|
11
|
-
materialize(
|
|
11
|
+
materialize(complex_power, 4).
|
|
12
|
+
materialize(complex_function, 4).
|
|
12
13
|
|
|
13
14
|
% Program structure: facts set up the scenario, and rules derive the materialized conclusions.
|
|
14
15
|
pi(3.141592653589793).
|
|
@@ -110,17 +111,23 @@ complex_dial(X, Y, T, Tp) :-
|
|
|
110
111
|
mul(Pi, 2, Z1),
|
|
111
112
|
sub(Z1, T, Tp).
|
|
112
113
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
complex_exponentiation(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
complex_exponentiation([0, 1], [0, 1],
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
114
|
+
% Named result rows keep the example output readable. Each row records the
|
|
115
|
+
% operation name, the input value(s), and the computed complex result rather
|
|
116
|
+
% than packing all assertions into one large nested term.
|
|
117
|
+
complex_power(sqrt_minus_one, [-1, 0], [0.5, 0], Result) :-
|
|
118
|
+
complex_exponentiation([-1, 0], [0.5, 0], Result).
|
|
119
|
+
|
|
120
|
+
complex_power(e_to_i_pi, [2.718281828459045, 0], [0, 3.141592653589793], Result) :-
|
|
121
|
+
complex_exponentiation([2.718281828459045, 0], [0, 3.141592653589793], Result).
|
|
122
|
+
|
|
123
|
+
complex_power(i_to_i, [0, 1], [0, 1], Result) :-
|
|
124
|
+
complex_exponentiation([0, 1], [0, 1], Result).
|
|
125
|
+
|
|
126
|
+
complex_power(e_to_minus_pi_over_two, [2.718281828459045, 0], [-1.57079632679, 0], Result) :-
|
|
127
|
+
complex_exponentiation([2.718281828459045, 0], [-1.57079632679, 0], Result).
|
|
128
|
+
|
|
129
|
+
complex_function(asin, two, [2, 0], Result) :-
|
|
130
|
+
complex_asin([2, 0], Result).
|
|
131
|
+
|
|
132
|
+
complex_function(acos, two, [2, 0], Result) :-
|
|
133
|
+
complex_acos([2, 0], Result).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
% Transitive graph paths over a small map of French cities.
|
|
2
|
+
%
|
|
3
|
+
% The base relation is directed: oneway(A, B) means there is a road from A
|
|
4
|
+
% to B. The derived relation path(A, B) is the transitive closure: B is
|
|
5
|
+
% reachable from A by one or more directed legs.
|
|
6
|
+
%
|
|
7
|
+
% The recursive rule is written in a productive, right-recursive form:
|
|
8
|
+
%
|
|
9
|
+
% path(A, C) :- oneway(A, B), path(B, C).
|
|
10
|
+
%
|
|
11
|
+
% That order matters in a goal-directed reasoner. A left-recursive closure
|
|
12
|
+
% rule such as `path(A, C) :- path(A, B), path(B, C).` starts by asking for
|
|
13
|
+
% the same open relation it is currently proving, so eyelang's recursion guard
|
|
14
|
+
% must stop it to avoid an infinite loop. The result is under-generation: only
|
|
15
|
+
% direct edges are printed. Starting with the concrete generator `oneway/2`
|
|
16
|
+
% first makes each recursive step smaller and yields the complete closure.
|
|
17
|
+
|
|
18
|
+
materialize(path, 2).
|
|
19
|
+
|
|
20
|
+
oneway(paris, orleans).
|
|
21
|
+
oneway(paris, chartres).
|
|
22
|
+
oneway(paris, amiens).
|
|
23
|
+
oneway(orleans, blois).
|
|
24
|
+
oneway(orleans, bourges).
|
|
25
|
+
oneway(blois, tours).
|
|
26
|
+
oneway(chartres, lemans).
|
|
27
|
+
oneway(lemans, angers).
|
|
28
|
+
oneway(lemans, tours).
|
|
29
|
+
oneway(angers, nantes).
|
|
30
|
+
|
|
31
|
+
path(A, B) :-
|
|
32
|
+
oneway(A, B).
|
|
33
|
+
path(A, C) :-
|
|
34
|
+
oneway(A, B),
|
|
35
|
+
path(B, C).
|
|
@@ -1 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
complex_power(sqrt_minus_one, [-1, 0], [0.5, 0], [6.123233995736766e-17, 1.0]).
|
|
2
|
+
complex_power(e_to_i_pi, [2.718281828459045, 0], [0, 3.141592653589793], [-1.0, 1.2246467991473532e-16]).
|
|
3
|
+
complex_power(i_to_i, [0, 1], [0, 1], [0.20787957635076193, 0.0]).
|
|
4
|
+
complex_power(e_to_minus_pi_over_two, [2.718281828459045, 0], [-1.57079632679, 0], [0.20787957635177984, 0.0]).
|
|
5
|
+
complex_function(asin, two, [2, 0], [1.5707963267948966, 1.3169578969248166]).
|
|
6
|
+
complex_function(acos, two, [2, 0], [0.0, -1.3169578969248166]).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
path(paris, orleans).
|
|
2
|
+
path(paris, chartres).
|
|
3
|
+
path(paris, amiens).
|
|
4
|
+
path(orleans, blois).
|
|
5
|
+
path(orleans, bourges).
|
|
6
|
+
path(blois, tours).
|
|
7
|
+
path(chartres, lemans).
|
|
8
|
+
path(lemans, angers).
|
|
9
|
+
path(lemans, tours).
|
|
10
|
+
path(angers, nantes).
|
|
11
|
+
path(paris, blois).
|
|
12
|
+
path(paris, bourges).
|
|
13
|
+
path(paris, tours).
|
|
14
|
+
path(paris, lemans).
|
|
15
|
+
path(paris, angers).
|
|
16
|
+
path(paris, nantes).
|
|
17
|
+
path(orleans, tours).
|
|
18
|
+
path(chartres, angers).
|
|
19
|
+
path(chartres, tours).
|
|
20
|
+
path(chartres, nantes).
|
|
21
|
+
path(lemans, nantes).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
web_uri(web(be.ugent, jos), "https://data.ugent.be/id/jos").
|
|
2
|
+
web_uri(web(com.example, jos), "https://example.com/id/jos").
|
|
3
|
+
web_uri(web(be.ugent, idlab), "https://data.ugent.be/id/idlab").
|
|
4
|
+
web_uri(web(be.ugent, ugent), "https://data.ugent.be/id/ugent").
|
|
5
|
+
web_uri(web(eyereasoner.github, eyelang), "https://github.com/eyereasoner/eyelang").
|
|
6
|
+
web_uri(web(org.schema, maintainer), "https://schema.org/maintainer").
|
|
7
|
+
affiliated_with(web(be.ugent, jos), web(be.ugent, idlab)).
|
|
8
|
+
affiliated_with(web(be.ugent, jos), web(be.ugent, ugent)).
|
|
9
|
+
project_contact(web(eyereasoner.github, eyelang), web(be.ugent, jos), "josderoo@gmail.com").
|
|
10
|
+
same_local_name(web(be.ugent, jos), web(com.example, jos), jos).
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
% Compact web-style names without full URIs or global prefix tables.
|
|
2
|
+
%
|
|
3
|
+
% RDF-style URIs are globally meaningful but long, while QNames such as
|
|
4
|
+
% schema:Person depend on an external prefix declaration. This example uses an
|
|
5
|
+
% eyelang-native alternative: web(Space, Local). The first argument is a dotted
|
|
6
|
+
% atom that names a vocabulary, organization, or authority; the second argument
|
|
7
|
+
% is the local name inside that space.
|
|
8
|
+
%
|
|
9
|
+
% The important property is that the complete term is self-contained. The local
|
|
10
|
+
% name jos can safely occur in two spaces: web(be.ugent, jos) and
|
|
11
|
+
% web(com.example, jos) are different Herbrand terms, so there is no hidden
|
|
12
|
+
% prefix context and no accidental collision. Tooling can still expand selected
|
|
13
|
+
% web/2 terms to full URI strings when a base is known.
|
|
14
|
+
|
|
15
|
+
materialize(web_uri, 2).
|
|
16
|
+
materialize(affiliated_with, 2).
|
|
17
|
+
materialize(project_contact, 3).
|
|
18
|
+
materialize(same_local_name, 3).
|
|
19
|
+
|
|
20
|
+
% Optional URI bases for spaces that we want to publish or display.
|
|
21
|
+
space_base(be.ugent, "https://data.ugent.be/id/").
|
|
22
|
+
space_base(com.example, "https://example.com/id/").
|
|
23
|
+
space_base(eyereasoner.github, "https://github.com/eyereasoner/").
|
|
24
|
+
space_base(org.schema, "https://schema.org/").
|
|
25
|
+
|
|
26
|
+
% A tiny graph using globally scoped web names as ordinary eyelang terms.
|
|
27
|
+
triple(web(be.ugent, jos), web(org.schema, name), "Jos De Roo").
|
|
28
|
+
triple(web(be.ugent, jos), web(org.schema, email), "josderoo@gmail.com").
|
|
29
|
+
triple(web(be.ugent, jos), web(org.schema, affiliation), web(be.ugent, idlab)).
|
|
30
|
+
triple(web(be.ugent, idlab), web(org.schema, parentOrganization), web(be.ugent, ugent)).
|
|
31
|
+
|
|
32
|
+
triple(web(eyereasoner.github, eyelang), web(org.schema, name), "eyelang").
|
|
33
|
+
triple(web(eyereasoner.github, eyelang), web(org.schema, codeRepository), "https://github.com/eyereasoner/eyelang").
|
|
34
|
+
triple(web(eyereasoner.github, eyelang), web(org.schema, maintainer), web(be.ugent, jos)).
|
|
35
|
+
|
|
36
|
+
% Same local spelling, different global identity.
|
|
37
|
+
triple(web(com.example, jos), web(org.schema, name), "Another Jos in another space").
|
|
38
|
+
|
|
39
|
+
% Keep URI expansion explicit and optional: reasoning uses web/2 terms, while
|
|
40
|
+
% web_uri/2 is only a presentation bridge for selected names.
|
|
41
|
+
published_name(web(be.ugent, jos)).
|
|
42
|
+
published_name(web(com.example, jos)).
|
|
43
|
+
published_name(web(be.ugent, idlab)).
|
|
44
|
+
published_name(web(be.ugent, ugent)).
|
|
45
|
+
published_name(web(eyereasoner.github, eyelang)).
|
|
46
|
+
published_name(web(org.schema, maintainer)).
|
|
47
|
+
|
|
48
|
+
web_uri(web(Space, Local), URI) :-
|
|
49
|
+
published_name(web(Space, Local)),
|
|
50
|
+
space_base(Space, Base),
|
|
51
|
+
atom_string(Local, LocalText),
|
|
52
|
+
str_concat(Base, LocalText, URI).
|
|
53
|
+
|
|
54
|
+
% Organization membership follows parentOrganization links transitively.
|
|
55
|
+
parent_organization(Unit, Org) :-
|
|
56
|
+
triple(Unit, web(org.schema, parentOrganization), Org).
|
|
57
|
+
parent_organization(Unit, Org) :-
|
|
58
|
+
triple(Unit, web(org.schema, parentOrganization), Mid),
|
|
59
|
+
parent_organization(Mid, Org).
|
|
60
|
+
|
|
61
|
+
affiliated_with(Person, Org) :-
|
|
62
|
+
triple(Person, web(org.schema, affiliation), Org).
|
|
63
|
+
affiliated_with(Person, Org) :-
|
|
64
|
+
triple(Person, web(org.schema, affiliation), Unit),
|
|
65
|
+
parent_organization(Unit, Org).
|
|
66
|
+
|
|
67
|
+
% A project contact is derived by joining the project's maintainer with the
|
|
68
|
+
% maintainer's email. The join works because both facts use the same complete
|
|
69
|
+
% web(be.ugent, jos) term.
|
|
70
|
+
project_contact(Project, Person, Email) :-
|
|
71
|
+
triple(Project, web(org.schema, maintainer), Person),
|
|
72
|
+
triple(Person, web(org.schema, email), Email).
|
|
73
|
+
|
|
74
|
+
% Demonstrate that local names are not global names. This reports the deliberate
|
|
75
|
+
% local-name collision without treating the two people as equal.
|
|
76
|
+
local_name(Entity, Local) :-
|
|
77
|
+
triple(Entity, web(org.schema, name), _),
|
|
78
|
+
eq(Entity, web(_, Local)).
|
|
79
|
+
|
|
80
|
+
same_local_name(A, B, Local) :-
|
|
81
|
+
local_name(A, Local),
|
|
82
|
+
local_name(B, Local),
|
|
83
|
+
lt(A, B).
|
package/package.json
CHANGED
package/playground.html
CHANGED
|
@@ -434,156 +434,158 @@
|
|
|
434
434
|
|
|
435
435
|
<script type="module">
|
|
436
436
|
const EXAMPLES = [
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
437
|
+
"access-control-policy",
|
|
438
|
+
"ackermann",
|
|
439
|
+
"age",
|
|
440
|
+
"aliases-and-namespaces",
|
|
441
|
+
"alignment-demo",
|
|
442
|
+
"allen-interval-calculus",
|
|
443
|
+
"ancestor",
|
|
444
|
+
"animal",
|
|
445
|
+
"annotation",
|
|
446
|
+
"auroracare",
|
|
447
|
+
"backward",
|
|
448
|
+
"basic-monadic",
|
|
449
|
+
"bayes-diagnosis",
|
|
450
|
+
"bayes-therapy",
|
|
451
|
+
"beam-deflection",
|
|
452
|
+
"binomial-vandermonde",
|
|
453
|
+
"blocks-world-planning",
|
|
454
|
+
"bmi",
|
|
455
|
+
"braking-safety-worlds",
|
|
456
|
+
"buck-converter-design",
|
|
457
|
+
"cache-performance",
|
|
458
|
+
"canary-release",
|
|
459
|
+
"cat-koko",
|
|
460
|
+
"catalan-convolution",
|
|
461
|
+
"chart-parser",
|
|
462
|
+
"clinical-trial-screening",
|
|
463
|
+
"collatz-1000",
|
|
464
|
+
"combinatorics-findall-sort",
|
|
465
|
+
"competitive-enzyme-kinetics",
|
|
466
|
+
"complex",
|
|
467
|
+
"composition-of-injective-functions-is-injective",
|
|
468
|
+
"context-association",
|
|
469
|
+
"context-schema-audit",
|
|
470
|
+
"continued-fraction-sqrt2",
|
|
471
|
+
"control-system",
|
|
472
|
+
"critical-path-schedule",
|
|
473
|
+
"cyclic-path",
|
|
474
|
+
"d3-group",
|
|
475
|
+
"dairy-energy-balance",
|
|
476
|
+
"data-negotiation",
|
|
477
|
+
"deep-taxonomy-10",
|
|
478
|
+
"deep-taxonomy-100",
|
|
479
|
+
"deep-taxonomy-1000",
|
|
480
|
+
"deep-taxonomy-10000",
|
|
481
|
+
"deep-taxonomy-100000",
|
|
482
|
+
"delfour",
|
|
483
|
+
"deontic-logic",
|
|
484
|
+
"derived-backward-rule",
|
|
485
|
+
"derived-rule",
|
|
486
|
+
"diamond-property",
|
|
487
|
+
"dijkstra",
|
|
488
|
+
"dijkstra-findall-sort",
|
|
489
|
+
"dijkstra-risk-path",
|
|
490
|
+
"dining-philosophers",
|
|
491
|
+
"dog",
|
|
492
|
+
"dpv-odrl-purpose-mapping",
|
|
493
|
+
"drone-corridor-planner",
|
|
494
|
+
"easter-computus",
|
|
495
|
+
"electrical-rc-filter",
|
|
496
|
+
"epidemic-policy",
|
|
497
|
+
"equivalence-classes-overlap-implies-same-class",
|
|
498
|
+
"eulerian-path",
|
|
499
|
+
"ev-range-worlds",
|
|
500
|
+
"existential-rule",
|
|
501
|
+
"exoplanet-validation-worlds",
|
|
502
|
+
"expression-eval",
|
|
503
|
+
"family-cousins",
|
|
504
|
+
"fastpow",
|
|
505
|
+
"fft8-numeric",
|
|
506
|
+
"fibonacci",
|
|
507
|
+
"field-nitrogen-balance",
|
|
508
|
+
"flandor",
|
|
509
|
+
"floating-point",
|
|
510
|
+
"four-color-map",
|
|
511
|
+
"fundamental-theorem-arithmetic",
|
|
512
|
+
"gd-step-certified",
|
|
513
|
+
"gdpr-compliance",
|
|
514
|
+
"good-cobbler",
|
|
515
|
+
"gps",
|
|
516
|
+
"graph",
|
|
517
|
+
"graph-reachability",
|
|
518
|
+
"gray-code-counter",
|
|
519
|
+
"greatest-lower-bound-uniqueness",
|
|
520
|
+
"group-inverse-uniqueness",
|
|
521
|
+
"hamiltonian-path",
|
|
522
|
+
"hamming-code",
|
|
523
|
+
"hanoi",
|
|
524
|
+
"heat-loss",
|
|
525
|
+
"heron-theorem",
|
|
526
|
+
"ideal-gas-law",
|
|
527
|
+
"illegitimate-reasoning",
|
|
528
|
+
"integer-partitions",
|
|
529
|
+
"intuitionistic-logic-kripke",
|
|
530
|
+
"job-shop-scheduling",
|
|
531
|
+
"knapsack-optimization",
|
|
532
|
+
"knowledge-engineering-alignment-flow",
|
|
533
|
+
"law-of-cosines",
|
|
534
|
+
"least-squares-regression",
|
|
535
|
+
"linear-logic-resources",
|
|
536
|
+
"list-collection",
|
|
537
|
+
"lldm",
|
|
538
|
+
"manufacturing-quality-control",
|
|
539
|
+
"matrix-chain-order",
|
|
540
|
+
"microgrid-dispatch",
|
|
541
|
+
"missionaries-cannibals",
|
|
542
|
+
"modal-logic-kripke",
|
|
543
|
+
"modular-exponentiation",
|
|
544
|
+
"monkey-bananas",
|
|
545
|
+
"n-queens-8",
|
|
546
|
+
"network-sla",
|
|
547
|
+
"newton-raphson",
|
|
548
|
+
"nixon-diamond",
|
|
549
|
+
"observability-log-correlation",
|
|
550
|
+
"odrl-dpv-fpv-trust-flow",
|
|
551
|
+
"odrl-dpv-healthcare-risk-ranked",
|
|
552
|
+
"odrl-dpv-risk-ranked",
|
|
553
|
+
"orbital-transfer-design",
|
|
554
|
+
"path-discovery",
|
|
555
|
+
"peano-arithmetic",
|
|
556
|
+
"peasant",
|
|
557
|
+
"pell-equation",
|
|
558
|
+
"pendulum-period",
|
|
559
|
+
"polynomial",
|
|
560
|
+
"proof-contrapositive",
|
|
561
|
+
"quadratic-formula",
|
|
562
|
+
"radioactive-decay",
|
|
563
|
+
"reusable-builtins",
|
|
564
|
+
"riemann-hypothesis",
|
|
565
|
+
"security-incident-correlation",
|
|
566
|
+
"send-more-money",
|
|
567
|
+
"service-impact",
|
|
568
|
+
"sieve",
|
|
569
|
+
"skolem-functions",
|
|
570
|
+
"socket-age",
|
|
571
|
+
"socket-family",
|
|
572
|
+
"socrates",
|
|
573
|
+
"stable-marriage",
|
|
574
|
+
"statistics-summary",
|
|
575
|
+
"stirling-bell-numbers",
|
|
576
|
+
"sudoku-4x4",
|
|
577
|
+
"superdense-coding",
|
|
578
|
+
"term-tools",
|
|
579
|
+
"totient-summatory",
|
|
580
|
+
"trust-flow-provenance-threshold",
|
|
581
|
+
"turing",
|
|
582
|
+
"vector-similarity",
|
|
583
|
+
"vulnerability-impact",
|
|
584
|
+
"web-names",
|
|
585
|
+
"weighted-interval-scheduling",
|
|
586
|
+
"witch",
|
|
587
|
+
"wolf-goat-cabbage",
|
|
588
|
+
"zebra"
|
|
587
589
|
];
|
|
588
590
|
const FALLBACK_SOURCE = `materialize(answer, 1).
|
|
589
591
|
answer(ok) :- eq(ok, ok).
|
package/src/parser.js
CHANGED
|
@@ -23,6 +23,10 @@ function isNameContinueCode(code) {
|
|
|
23
23
|
return code === 95 || isAsciiLetterCode(code) || isDigitCode(code);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
function isDottedAtomContinue(source, pos) {
|
|
27
|
+
return source[pos] === '.' && isPlainAtomStartCode((source[pos + 1] ?? '').charCodeAt(0));
|
|
28
|
+
}
|
|
29
|
+
|
|
26
30
|
function isVariableStart(text) {
|
|
27
31
|
const code = text.charCodeAt(0);
|
|
28
32
|
return code === 95 || (code >= 65 && code <= 90);
|
|
@@ -151,7 +155,18 @@ class Parser {
|
|
|
151
155
|
if (isPlainAtomStartCode(ch.charCodeAt(0))) {
|
|
152
156
|
const start = this.pos;
|
|
153
157
|
this.take();
|
|
154
|
-
while (
|
|
158
|
+
while (true) {
|
|
159
|
+
if (isNameContinueCode(this.peek().charCodeAt(0))) {
|
|
160
|
+
this.take();
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (isDottedAtomContinue(this.source, this.pos)) {
|
|
164
|
+
this.take();
|
|
165
|
+
this.take();
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
155
170
|
return { type: TOK.ATOM, text: this.source.slice(start, this.pos), line };
|
|
156
171
|
}
|
|
157
172
|
|
|
@@ -316,7 +331,7 @@ const SIMPLE_NUMBER = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
|
|
|
316
331
|
const FAST_BINARY_FACT = /^([a-z][A-Za-z0-9_]*)\(\s*([^,\s()[\]|"']+)\s*,\s*([^,\s()[\]|"']+)\s*\)\.$/;
|
|
317
332
|
const FAST_BINARY_RULE = /^([a-z][A-Za-z0-9_]*)\(\s*([^,\s()[\]|"']+)\s*,\s*([^,\s()[\]|"']+)\s*\)\s*:-\s*([a-z][A-Za-z0-9_]*)\(\s*([^,\s()[\]|"']+)\s*,\s*([^,\s()[\]|"']+)\s*\)\.$/;
|
|
318
333
|
const SIMPLE_VARIABLE = /^[_A-Z][A-Za-z0-9_]*$/;
|
|
319
|
-
const SIMPLE_ATOM = /^[a-z][A-Za-z0-9_]*$/;
|
|
334
|
+
const SIMPLE_ATOM = /^[a-z][A-Za-z0-9_]*(?:\.[a-z][A-Za-z0-9_]*)*$/;
|
|
320
335
|
const GRAPHIC_ATOM = /^[#$&*+\-\/<=>?@^~\\]+$/;
|
|
321
336
|
|
|
322
337
|
function parseClausesFastNoSource(source) {
|
package/src/term.js
CHANGED
|
@@ -138,7 +138,7 @@ const graphicAtomChars = new Set('#$&*+-/<=>?@^~\\'.split(''));
|
|
|
138
138
|
function atomNeedsQuotes(name) {
|
|
139
139
|
if (!name) return true;
|
|
140
140
|
if (name === '[]') return false;
|
|
141
|
-
if (/^[a-z][A-Za-z0-9_]*$/.test(name)) return false;
|
|
141
|
+
if (/^[a-z][A-Za-z0-9_]*(?:\.[a-z][A-Za-z0-9_]*)*$/.test(name)) return false;
|
|
142
142
|
for (const ch of name) if (!graphicAtomChars.has(ch)) return true;
|
|
143
143
|
return false;
|
|
144
144
|
}
|
package/test/run-regression.mjs
CHANGED
|
@@ -476,6 +476,13 @@ function whiteBoxCases() {
|
|
|
476
476
|
assertEqual(termToString(goal, new Env(), true), 'member(X, [a, b])', 'goal');
|
|
477
477
|
},
|
|
478
478
|
},
|
|
479
|
+
{
|
|
480
|
+
name: 'parser preserves dotted atom constants for web-style names',
|
|
481
|
+
run: () => {
|
|
482
|
+
const clauses = parseProgramText('p(web(be.ugent, jos), org.schema).\n');
|
|
483
|
+
assertEqual(termToString(clauses[0].head, new Env(), true), 'p(web(be.ugent, jos), org.schema)', 'head');
|
|
484
|
+
},
|
|
485
|
+
},
|
|
479
486
|
{
|
|
480
487
|
name: 'list construction round-trips through properListItems',
|
|
481
488
|
run: () => {
|