eyelang 1.2.1 → 1.2.2
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 +1 -1
- package/docs/language-reference.md +5 -5
- package/examples/output/web-names.pl +10 -10
- package/examples/web-names.pl +32 -32
- package/package.json +1 -1
- package/src/parser.js +2 -16
- package/src/term.js +1 -1
- package/test/run-regression.mjs +11 -3
package/docs/guide.md
CHANGED
|
@@ -451,7 +451,7 @@ Use `holds/2` when you want to match the member term directly, for example `name
|
|
|
451
451
|
| [`turing.pl`](../examples/turing.pl) | Simulates a binary-increment Turing machine. | [`output/turing.pl`](../examples/output/turing.pl) |
|
|
452
452
|
| [`vector-similarity.pl`](../examples/vector-similarity.pl) | Computes dot product, norm, and cosine similarity. | [`output/vector-similarity.pl`](../examples/output/vector-similarity.pl) |
|
|
453
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
|
|
454
|
+
| [`web-names.pl`](../examples/web-names.pl) | Uses compact ISO-compatible `web(Space, Local)` terms as readable global identifiers and expands selected terms 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) |
|
|
@@ -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
|
|
122
|
+
A colon outside `:-` is not part of the language. Namespace-like names SHOULD be written as ISO-compatible atom constants such as `person_type`, `odrl_permission`, or quoted atoms such as `'org.schema'`.
|
|
123
123
|
|
|
124
124
|
### 3.4 Variables
|
|
125
125
|
|
|
@@ -138,15 +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. A dot is not part of a plain atom in the ISO-compatible subset; dotted web spaces such as `'be.ugent'` or `'org.schema'` MUST be quoted if they are meant as one atom constant. Names such as `a-b` or `http://example` MUST also 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
|
+
'be.ugent'
|
|
148
|
+
'org.schema'
|
|
149
|
+
'eyereasoner.github'
|
|
150
150
|
'a-b'
|
|
151
151
|
'http://example'
|
|
152
152
|
```
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
web_uri(web(be.ugent, josd), "https://data.ugent.be/id/josd").
|
|
2
|
-
web_uri(web(com.example, josd), "https://example.com/id/josd").
|
|
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, josd), web(be.ugent, idlab)).
|
|
8
|
-
affiliated_with(web(be.ugent, josd), web(be.ugent, ugent)).
|
|
9
|
-
project_contact(web(eyereasoner.github, eyelang), web(be.ugent, josd), "josderoo@gmail.com").
|
|
10
|
-
same_local_name(web(be.ugent, josd), web(com.example, josd), josd).
|
|
1
|
+
web_uri(web('be.ugent', josd), "https://data.ugent.be/id/josd").
|
|
2
|
+
web_uri(web('com.example', josd), "https://example.com/id/josd").
|
|
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', josd), web('be.ugent', idlab)).
|
|
8
|
+
affiliated_with(web('be.ugent', josd), web('be.ugent', ugent)).
|
|
9
|
+
project_contact(web('eyereasoner.github', eyelang), web('be.ugent', josd), "josderoo@gmail.com").
|
|
10
|
+
same_local_name(web('be.ugent', josd), web('com.example', josd), josd).
|
package/examples/web-names.pl
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
%
|
|
3
3
|
% RDF-style URIs are globally meaningful but long, while QNames such as
|
|
4
4
|
% schema:Person depend on an external prefix declaration. This example uses an
|
|
5
|
-
% eyelang-native alternative: web(Space, Local). The first argument is
|
|
6
|
-
% atom
|
|
7
|
-
% is the local name inside that space.
|
|
5
|
+
% eyelang-native alternative: web(Space, Local). The first argument is an
|
|
6
|
+
% ISO-compatible quoted atom naming a vocabulary, organization, or authority;
|
|
7
|
+
% the second argument is the local name inside that space.
|
|
8
8
|
%
|
|
9
9
|
% The important property is that the complete term is self-contained. The local
|
|
10
|
-
% name josd can safely occur in two spaces: web(be.ugent, josd) and
|
|
11
|
-
% web(com.example, josd) are different Herbrand terms, so there is no hidden
|
|
10
|
+
% name josd can safely occur in two spaces: web('be.ugent', josd) and
|
|
11
|
+
% web('com.example', josd) are different Herbrand terms, so there is no hidden
|
|
12
12
|
% prefix context and no accidental collision. Tooling can still expand selected
|
|
13
13
|
% web/2 terms to full URI strings when a base is known.
|
|
14
14
|
|
|
@@ -18,32 +18,32 @@ materialize(project_contact, 3).
|
|
|
18
18
|
materialize(same_local_name, 3).
|
|
19
19
|
|
|
20
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/").
|
|
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
25
|
|
|
26
|
-
% A tiny graph using globally scoped web
|
|
27
|
-
triple(web(be.ugent, josd), web(org.schema, name), "Jos De Roo").
|
|
28
|
-
triple(web(be.ugent, josd), web(org.schema, email), "josderoo@gmail.com").
|
|
29
|
-
triple(web(be.ugent, josd), web(org.schema, affiliation), web(be.ugent, idlab)).
|
|
30
|
-
triple(web(be.ugent, idlab), web(org.schema, parentOrganization), web(be.ugent, ugent)).
|
|
26
|
+
% A tiny graph using globally scoped web terms as ordinary eyelang terms.
|
|
27
|
+
triple(web('be.ugent', josd), web('org.schema', name), "Jos De Roo").
|
|
28
|
+
triple(web('be.ugent', josd), web('org.schema', email), "josderoo@gmail.com").
|
|
29
|
+
triple(web('be.ugent', josd), web('org.schema', affiliation), web('be.ugent', idlab)).
|
|
30
|
+
triple(web('be.ugent', idlab), web('org.schema', parentOrganization), web('be.ugent', ugent)).
|
|
31
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, josd)).
|
|
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', josd)).
|
|
35
35
|
|
|
36
36
|
% Same local spelling, different global identity.
|
|
37
|
-
triple(web(com.example, josd), web(org.schema, name), "Another JosD in another space").
|
|
37
|
+
triple(web('com.example', josd), web('org.schema', name), "Another JosD in another space").
|
|
38
38
|
|
|
39
39
|
% Keep URI expansion explicit and optional: reasoning uses web/2 terms, while
|
|
40
40
|
% web_uri/2 is only a presentation bridge for selected names.
|
|
41
|
-
published_name(web(be.ugent, josd)).
|
|
42
|
-
published_name(web(com.example, josd)).
|
|
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)).
|
|
41
|
+
published_name(web('be.ugent', josd)).
|
|
42
|
+
published_name(web('com.example', josd)).
|
|
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
47
|
|
|
48
48
|
web_uri(web(Space, Local), URI) :-
|
|
49
49
|
published_name(web(Space, Local)),
|
|
@@ -53,28 +53,28 @@ web_uri(web(Space, Local), URI) :-
|
|
|
53
53
|
|
|
54
54
|
% Organization membership follows parentOrganization links transitively.
|
|
55
55
|
parent_organization(Unit, Org) :-
|
|
56
|
-
triple(Unit, web(org.schema, parentOrganization), Org).
|
|
56
|
+
triple(Unit, web('org.schema', parentOrganization), Org).
|
|
57
57
|
parent_organization(Unit, Org) :-
|
|
58
|
-
triple(Unit, web(org.schema, parentOrganization), Mid),
|
|
58
|
+
triple(Unit, web('org.schema', parentOrganization), Mid),
|
|
59
59
|
parent_organization(Mid, Org).
|
|
60
60
|
|
|
61
61
|
affiliated_with(Person, Org) :-
|
|
62
|
-
triple(Person, web(org.schema, affiliation), Org).
|
|
62
|
+
triple(Person, web('org.schema', affiliation), Org).
|
|
63
63
|
affiliated_with(Person, Org) :-
|
|
64
|
-
triple(Person, web(org.schema, affiliation), Unit),
|
|
64
|
+
triple(Person, web('org.schema', affiliation), Unit),
|
|
65
65
|
parent_organization(Unit, Org).
|
|
66
66
|
|
|
67
67
|
% A project contact is derived by joining the project's maintainer with the
|
|
68
68
|
% maintainer's email. The join works because both facts use the same complete
|
|
69
|
-
% web(be.ugent, josd) term.
|
|
69
|
+
% web('be.ugent', josd) term.
|
|
70
70
|
project_contact(Project, Person, Email) :-
|
|
71
|
-
triple(Project, web(org.schema, maintainer), Person),
|
|
72
|
-
triple(Person, web(org.schema, email), Email).
|
|
71
|
+
triple(Project, web('org.schema', maintainer), Person),
|
|
72
|
+
triple(Person, web('org.schema', email), Email).
|
|
73
73
|
|
|
74
74
|
% Demonstrate that local names are not global names. This reports the deliberate
|
|
75
75
|
% local-name collision without treating the two people as equal.
|
|
76
76
|
local_name(Entity, Local) :-
|
|
77
|
-
triple(Entity, web(org.schema, name), _),
|
|
77
|
+
triple(Entity, web('org.schema', name), _),
|
|
78
78
|
eq(Entity, web(_, Local)).
|
|
79
79
|
|
|
80
80
|
same_local_name(A, B, Local) :-
|
package/package.json
CHANGED
package/src/parser.js
CHANGED
|
@@ -23,9 +23,6 @@ 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
27
|
function isVariableStart(text) {
|
|
31
28
|
const code = text.charCodeAt(0);
|
|
@@ -155,18 +152,7 @@ class Parser {
|
|
|
155
152
|
if (isPlainAtomStartCode(ch.charCodeAt(0))) {
|
|
156
153
|
const start = this.pos;
|
|
157
154
|
this.take();
|
|
158
|
-
while (
|
|
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
|
+
while (isNameContinueCode(this.peek().charCodeAt(0))) this.take();
|
|
170
156
|
return { type: TOK.ATOM, text: this.source.slice(start, this.pos), line };
|
|
171
157
|
}
|
|
172
158
|
|
|
@@ -331,7 +317,7 @@ const SIMPLE_NUMBER = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
|
|
|
331
317
|
const FAST_BINARY_FACT = /^([a-z][A-Za-z0-9_]*)\(\s*([^,\s()[\]|"']+)\s*,\s*([^,\s()[\]|"']+)\s*\)\.$/;
|
|
332
318
|
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*\)\.$/;
|
|
333
319
|
const SIMPLE_VARIABLE = /^[_A-Z][A-Za-z0-9_]*$/;
|
|
334
|
-
const SIMPLE_ATOM = /^[a-z][A-Za-z0-9_]
|
|
320
|
+
const SIMPLE_ATOM = /^[a-z][A-Za-z0-9_]*$/;
|
|
335
321
|
const GRAPHIC_ATOM = /^[#$&*+\-\/<=>?@^~\\]+$/;
|
|
336
322
|
|
|
337
323
|
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_]
|
|
141
|
+
if (/^[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
|
@@ -477,10 +477,18 @@ function whiteBoxCases() {
|
|
|
477
477
|
},
|
|
478
478
|
},
|
|
479
479
|
{
|
|
480
|
-
name: 'parser
|
|
480
|
+
name: 'parser rejects unquoted dotted atoms to stay ISO-compatible',
|
|
481
481
|
run: () => {
|
|
482
|
-
|
|
483
|
-
|
|
482
|
+
let threw = false;
|
|
483
|
+
try { parseProgramText('p(web(be.ugent, josd)).\n'); } catch (_) { threw = true; }
|
|
484
|
+
assertEqual(threw, true, 'unquoted dotted atoms must be quoted');
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
name: 'parser preserves quoted dotted atoms for web-style terms',
|
|
489
|
+
run: () => {
|
|
490
|
+
const clauses = parseProgramText("p(web('be.ugent', josd), 'org.schema').\n");
|
|
491
|
+
assertEqual(termToString(clauses[0].head, new Env(), true), "p(web('be.ugent', josd), 'org.schema')", 'head');
|
|
484
492
|
},
|
|
485
493
|
},
|
|
486
494
|
{
|