eyeling 1.33.2 → 1.33.4
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/examples/eyelang/README.md +11 -76
- package/examples/eyelang/SPEC.md +1 -2
- package/eyelang.d.ts +0 -12
- package/index.d.ts +0 -4
- package/index.js +1 -5
- package/lib/eyelang/builtins/registry.js +1 -2
- package/lib/eyelang/builtins/search.js +3 -3
- package/lib/eyelang/cli.js +1 -13
- package/lib/eyelang/hash.js +2 -2
- package/lib/eyelang/index.js +0 -1
- package/lib/eyelang/program.js +0 -7
- package/package.json +1 -1
- package/test/eyelang/run-examples.mjs +1 -2
- package/test/eyelang/run-regression.mjs +0 -61
- package/test/run.js +21 -3
- package/examples/eyelang/annotation-rdf12.ttl +0 -12
- package/examples/eyelang/directional-language.ttl +0 -9
- package/examples/eyelang/eyeling-ackermann.n3 +0 -41
- package/examples/eyelang/eyeling-age-threshold.n3 +0 -12
- package/examples/eyelang/eyeling-alignment-demo.n3 +0 -11
- package/examples/eyelang/eyeling-allen-interval-calculus-small.n3 +0 -13
- package/examples/eyelang/eyeling-backward-recursion.n3 +0 -11
- package/examples/eyelang/eyeling-backward.n3 +0 -10
- package/examples/eyelang/eyeling-basic-monadic-small.n3 +0 -11
- package/examples/eyelang/eyeling-bmi.n3 +0 -10
- package/examples/eyelang/eyeling-cat-koko.n3 +0 -15
- package/examples/eyelang/eyeling-collatz-small.n3 +0 -11
- package/examples/eyelang/eyeling-collection.n3 +0 -11
- package/examples/eyelang/eyeling-complex-arithmetic.n3 +0 -10
- package/examples/eyelang/eyeling-context-association.n3 +0 -11
- package/examples/eyelang/eyeling-control-system-small.n3 +0 -11
- package/examples/eyelang/eyeling-crypto-builtins-extra.n3 +0 -10
- package/examples/eyelang/eyeling-crypto-builtins.n3 +0 -8
- package/examples/eyelang/eyeling-deep-taxonomy-10.n3 +0 -18
- package/examples/eyelang/eyeling-derived-backward-rule-flat.n3 +0 -10
- package/examples/eyelang/eyeling-derived-rule-flat.n3 +0 -9
- package/examples/eyelang/eyeling-digital-product-passport-small.n3 +0 -11
- package/examples/eyelang/eyeling-dijkstra-tiny.n3 +0 -14
- package/examples/eyelang/eyeling-dog-license.n3 +0 -13
- package/examples/eyelang/eyeling-drone-corridor-planner-small.n3 +0 -13
- package/examples/eyelang/eyeling-equals.n3 +0 -8
- package/examples/eyelang/eyeling-equivalence-classes.n3 +0 -11
- package/examples/eyelang/eyeling-euler-identity.n3 +0 -9
- package/examples/eyelang/eyeling-existential-rule.n3 +0 -9
- package/examples/eyelang/eyeling-expression-eval.n3 +0 -11
- package/examples/eyelang/eyeling-family-cousins-extended.n3 +0 -12
- package/examples/eyelang/eyeling-fastpow.n3 +0 -10
- package/examples/eyelang/eyeling-fibonacci.n3 +0 -44
- package/examples/eyelang/eyeling-french-cities-reachability.n3 +0 -22
- package/examples/eyelang/eyeling-goldbach-small.n3 +0 -22
- package/examples/eyelang/eyeling-good-cobbler.n3 +0 -9
- package/examples/eyelang/eyeling-list-builtins.n3 +0 -10
- package/examples/eyelang/eyeling-list-collection-extra.n3 +0 -9
- package/examples/eyelang/eyeling-math-builtins.n3 +0 -9
- package/examples/eyelang/eyeling-string-builtins-extra.n3 +0 -9
- package/examples/eyelang/eyeling-string-builtins.n3 +0 -10
- package/examples/eyelang/eyeling-time-builtins.n3 +0 -11
- package/examples/eyelang/eyeling-time-components-extra.n3 +0 -10
- package/examples/eyelang/eyeling-witch.n3 +0 -10
- package/examples/eyelang/family-cousins.n3 +0 -17
- package/examples/eyelang/n3-builtins.n3 +0 -28
- package/examples/eyelang/output/annotation-rdf12.ttl +0 -1
- package/examples/eyelang/output/directional-language.ttl +0 -1
- package/examples/eyelang/output/eyeling-ackermann.n3 +0 -12
- package/examples/eyelang/output/eyeling-age-threshold.n3 +0 -4
- package/examples/eyelang/output/eyeling-alignment-demo.n3 +0 -1
- package/examples/eyelang/output/eyeling-allen-interval-calculus-small.n3 +0 -3
- package/examples/eyelang/output/eyeling-backward-recursion.n3 +0 -9
- package/examples/eyelang/output/eyeling-backward.n3 +0 -1
- package/examples/eyelang/output/eyeling-basic-monadic-small.n3 +0 -8
- package/examples/eyelang/output/eyeling-bmi.n3 +0 -2
- package/examples/eyelang/output/eyeling-cat-koko.n3 +0 -3
- package/examples/eyelang/output/eyeling-collatz-small.n3 +0 -3
- package/examples/eyelang/output/eyeling-collection.n3 +0 -1
- package/examples/eyelang/output/eyeling-complex-arithmetic.n3 +0 -5
- package/examples/eyelang/output/eyeling-context-association.n3 +0 -4
- package/examples/eyelang/output/eyeling-control-system-small.n3 +0 -4
- package/examples/eyelang/output/eyeling-crypto-builtins-extra.n3 +0 -3
- package/examples/eyelang/output/eyeling-crypto-builtins.n3 +0 -2
- package/examples/eyelang/output/eyeling-deep-taxonomy-10.n3 +0 -32
- package/examples/eyelang/output/eyeling-derived-backward-rule-flat.n3 +0 -4
- package/examples/eyelang/output/eyeling-derived-rule-flat.n3 +0 -2
- package/examples/eyelang/output/eyeling-digital-product-passport-small.n3 +0 -3
- package/examples/eyelang/output/eyeling-dijkstra-tiny.n3 +0 -9
- package/examples/eyelang/output/eyeling-dog-license.n3 +0 -1
- package/examples/eyelang/output/eyeling-drone-corridor-planner-small.n3 +0 -5
- package/examples/eyelang/output/eyeling-equals.n3 +0 -1
- package/examples/eyelang/output/eyeling-equivalence-classes.n3 +0 -2
- package/examples/eyelang/output/eyeling-euler-identity.n3 +0 -3
- package/examples/eyelang/output/eyeling-existential-rule.n3 +0 -4
- package/examples/eyelang/output/eyeling-expression-eval.n3 +0 -3
- package/examples/eyelang/output/eyeling-family-cousins-extended.n3 +0 -6
- package/examples/eyelang/output/eyeling-fastpow.n3 +0 -4
- package/examples/eyelang/output/eyeling-fibonacci.n3 +0 -6
- package/examples/eyelang/output/eyeling-french-cities-reachability.n3 +0 -25
- package/examples/eyelang/output/eyeling-goldbach-small.n3 +0 -2
- package/examples/eyelang/output/eyeling-good-cobbler.n3 +0 -2
- package/examples/eyelang/output/eyeling-list-builtins.n3 +0 -6
- package/examples/eyelang/output/eyeling-list-collection-extra.n3 +0 -5
- package/examples/eyelang/output/eyeling-math-builtins.n3 +0 -5
- package/examples/eyelang/output/eyeling-string-builtins-extra.n3 +0 -3
- package/examples/eyelang/output/eyeling-string-builtins.n3 +0 -4
- package/examples/eyelang/output/eyeling-time-builtins.n3 +0 -4
- package/examples/eyelang/output/eyeling-time-components-extra.n3 +0 -5
- package/examples/eyelang/output/eyeling-witch.n3 +0 -2
- package/examples/eyelang/output/family-cousins.n3 +0 -8
- package/examples/eyelang/output/n3-builtins.n3 +0 -6
- package/examples/eyelang/output/socrates.n3 +0 -1
- package/examples/eyelang/output/triple-term.n3 +0 -2
- package/examples/eyelang/socrates.n3 +0 -11
- package/examples/eyelang/triple-term.n3 +0 -9
- package/lib/eyelang/builtins/n3.js +0 -483
- package/lib/eyelang/rdf.js +0 -747
|
@@ -1,483 +0,0 @@
|
|
|
1
|
-
// Practical Notation3/SWAP builtin bridge for RDF/N3 compatibility input.
|
|
2
|
-
// RDF parser lowers body triples with math:, string:, list:, crypto:, time:, and
|
|
3
|
-
// selected log: predicates to n3_* eyelang builtins. The handlers work on the
|
|
4
|
-
// explicit RDF term representation from src/rdf.js.
|
|
5
|
-
import { hashHex } from '../hash.js';
|
|
6
|
-
import { compareLexicalOrNumeric } from './arithmetic.js';
|
|
7
|
-
import { deref, isDecimalInteger, listFromItems, parseFiniteNumber, properListItems, termToString, unify } from '../term.js';
|
|
8
|
-
import { RDF_DIR_LANG_STRING, RDF_LANG_STRING, XSD_BOOLEAN, XSD_DECIMAL, XSD_DOUBLE, XSD_INTEGER, XSD_STRING, rdfIri, rdfLiteral } from '../rdf.js';
|
|
9
|
-
|
|
10
|
-
const XSD_NS = 'http://www.w3.org/2001/XMLSchema#';
|
|
11
|
-
const XSD_DATE_TIME = `${XSD_NS}dateTime`;
|
|
12
|
-
const XSD_DATE_ONLY = `${XSD_NS}date`;
|
|
13
|
-
const XSD_DURATION = `${XSD_NS}duration`;
|
|
14
|
-
const RDF_NS = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
15
|
-
const LOG_NS = 'http://www.w3.org/2000/10/swap/log#';
|
|
16
|
-
const RDF_LIST = `${RDF_NS}List`;
|
|
17
|
-
|
|
18
|
-
export const n3Builtins = {
|
|
19
|
-
register(registry) {
|
|
20
|
-
const deterministic = { deterministic: true };
|
|
21
|
-
|
|
22
|
-
for (const [name, op] of Object.entries({
|
|
23
|
-
greaterThan: 'gt', lessThan: 'lt', notLessThan: 'ge', notGreaterThan: 'le', equalTo: 'eq', notEqualTo: 'ne',
|
|
24
|
-
})) registry.add(`n3_math_${name}`, 2, mathCompare(op), deterministic);
|
|
25
|
-
|
|
26
|
-
for (const [name, fn] of Object.entries({
|
|
27
|
-
sum: mathFold(0, (a, b) => a + b, (a, b) => a + b),
|
|
28
|
-
product: mathFold(1, (a, b) => a * b, (a, b) => a * b),
|
|
29
|
-
difference: mathBinary((a, b) => a - b, false, (a, b) => a - b),
|
|
30
|
-
quotient: mathBinary((a, b) => b === 0 ? null : a / b),
|
|
31
|
-
integerQuotient: mathBinary((a, b) => b === 0 ? null : Math.trunc(a / b), true, (a, b) => b === 0n ? null : a / b),
|
|
32
|
-
remainder: mathBinary((a, b) => b === 0 ? null : a % b, true, (a, b) => b === 0n ? null : a % b),
|
|
33
|
-
exponentiation: mathBinary((a, b) => a ** b, false, bigIntPow),
|
|
34
|
-
max: mathFold(null, (a, b) => Math.max(a, b), (a, b) => a >= b ? a : b),
|
|
35
|
-
min: mathFold(null, (a, b) => Math.min(a, b), (a, b) => a <= b ? a : b),
|
|
36
|
-
})) registry.add(`n3_math_${name}`, 2, fn, deterministic);
|
|
37
|
-
|
|
38
|
-
for (const [name, fn] of Object.entries({
|
|
39
|
-
absoluteValue: mathUnary(Math.abs),
|
|
40
|
-
negation: mathUnary((x) => -x),
|
|
41
|
-
rounded: mathUnary((x) => Math.round(x), true),
|
|
42
|
-
sin: mathUnary(Math.sin), cos: mathUnary(Math.cos), tan: mathUnary(Math.tan),
|
|
43
|
-
asin: mathUnary(Math.asin), acos: mathUnary(Math.acos), atan: mathUnary(Math.atan),
|
|
44
|
-
sinh: mathUnary(Math.sinh), cosh: mathUnary(Math.cosh), tanh: mathUnary(Math.tanh),
|
|
45
|
-
degrees: mathUnary((x) => x * 180 / Math.PI),
|
|
46
|
-
radians: mathUnary((x) => x * Math.PI / 180),
|
|
47
|
-
})) registry.add(`n3_math_${name}`, 2, fn, deterministic);
|
|
48
|
-
|
|
49
|
-
for (const [name, op] of Object.entries({
|
|
50
|
-
contains: 'contains', containsIgnoringCase: 'contains-i', endsWith: 'ends', equalIgnoringCase: 'eq-i',
|
|
51
|
-
greaterThan: 'gt', lessThan: 'lt', matches: 'matches', notEqualIgnoringCase: 'ne-i',
|
|
52
|
-
notGreaterThan: 'le', notLessThan: 'ge', notMatches: 'not-matches', startsWith: 'starts',
|
|
53
|
-
})) registry.add(`n3_string_${name}`, 2, stringTest(op), deterministic);
|
|
54
|
-
|
|
55
|
-
for (const [name, fn] of Object.entries({
|
|
56
|
-
concatenation: stringConcatenation,
|
|
57
|
-
format: stringFormat,
|
|
58
|
-
length: stringLength,
|
|
59
|
-
charAt: stringCharAt,
|
|
60
|
-
replace: stringReplace,
|
|
61
|
-
scrape: stringScrape,
|
|
62
|
-
setCharAt: stringSetCharAt,
|
|
63
|
-
})) registry.add(`n3_string_${name}`, 2, fn, deterministic);
|
|
64
|
-
|
|
65
|
-
for (const [name, fn] of Object.entries({
|
|
66
|
-
append: listAppend,
|
|
67
|
-
first: listFirst,
|
|
68
|
-
rest: listRest,
|
|
69
|
-
in: listIn,
|
|
70
|
-
length: listLength,
|
|
71
|
-
notMember: listNotMember,
|
|
72
|
-
remove: listRemove,
|
|
73
|
-
reverse: listReverse,
|
|
74
|
-
sort: listSort,
|
|
75
|
-
})) registry.add(`n3_list_${name}`, 2, fn, deterministic);
|
|
76
|
-
registry.add('n3_list_member', 2, listMember);
|
|
77
|
-
|
|
78
|
-
for (const name of ['sha', 'md5', 'sha256', 'sha512']) registry.add(`n3_crypto_${name}`, 2, cryptoHash(name), deterministic);
|
|
79
|
-
|
|
80
|
-
for (const name of ['day', 'hour', 'minute', 'month', 'second', 'year']) registry.add(`n3_time_${name}`, 2, timeComponent(name), deterministic);
|
|
81
|
-
registry.add('n3_time_localTime', 2, localTime, deterministic);
|
|
82
|
-
|
|
83
|
-
registry.add('n3_log_equalTo', 2, termCompare(true), deterministic);
|
|
84
|
-
registry.add('n3_log_notEqualTo', 2, termCompare(false), deterministic);
|
|
85
|
-
registry.add('n3_log_uri', 2, logUri, deterministic);
|
|
86
|
-
registry.add('n3_log_dtlit', 2, logDtLit, deterministic);
|
|
87
|
-
registry.add('n3_log_rawType', 2, logRawType, deterministic);
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
function* bindOrCheck(output, term, env) {
|
|
92
|
-
const next = env.clone();
|
|
93
|
-
if (unify(output, term, next)) yield next;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function* ok(env) { yield env; }
|
|
97
|
-
|
|
98
|
-
function rdfLiteralInfo(term, env) {
|
|
99
|
-
const t = deref(term, env);
|
|
100
|
-
if (t?.type === 'compound' && t.name === 'literal' && t.arity === 4) {
|
|
101
|
-
return { lex: t.args[0].name, datatype: iriValue(t.args[1]), lang: t.args[2].name, direction: t.args[3].name, term: t };
|
|
102
|
-
}
|
|
103
|
-
if (t?.type === 'number') return { lex: t.name, datatype: numericDatatype(t.name), lang: '', direction: '', term: t };
|
|
104
|
-
if (t?.type === 'string') return { lex: t.name, datatype: XSD_STRING, lang: '', direction: '', term: t };
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function iriValue(term) {
|
|
109
|
-
if (term?.type === 'compound' && term.name === 'iri' && term.arity === 1) return term.args[0].name;
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function numericDatatype(text) {
|
|
114
|
-
return /[eE]/.test(text) ? XSD_DOUBLE : String(text).includes('.') ? XSD_DECIMAL : XSD_INTEGER;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function numericInfo(term, env) {
|
|
118
|
-
const info = rdfLiteralInfo(term, env);
|
|
119
|
-
if (!info || !isNumericLex(info.lex)) return null;
|
|
120
|
-
return info;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function parseNumber(term, env) {
|
|
124
|
-
const info = numericInfo(term, env);
|
|
125
|
-
if (!info) return null;
|
|
126
|
-
return parseFiniteNumber(info.lex);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function isIntegerLex(term, env) {
|
|
130
|
-
const info = numericInfo(term, env);
|
|
131
|
-
return !!info && isDecimalInteger(info.lex) && (info.datatype === XSD_INTEGER || info.datatype?.startsWith(XSD_NS));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function isNumericLex(text) {
|
|
135
|
-
return /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(String(text ?? ''));
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function numberLiteral(value, forceInteger = false) {
|
|
139
|
-
if (typeof value === 'bigint') return rdfLiteral(value.toString(), XSD_INTEGER, '', '');
|
|
140
|
-
if (typeof value === 'string') {
|
|
141
|
-
if (isDecimalInteger(value)) return rdfLiteral(value, XSD_INTEGER, '', '');
|
|
142
|
-
return rdfLiteral(value, XSD_DECIMAL, '', '');
|
|
143
|
-
}
|
|
144
|
-
if (forceInteger || Number.isInteger(value)) return rdfLiteral(String(Math.trunc(value)), XSD_INTEGER, '', '');
|
|
145
|
-
return rdfLiteral(String(value), XSD_DECIMAL, '', '');
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function jsString(term, env) {
|
|
149
|
-
const t = deref(term, env);
|
|
150
|
-
const lit = rdfLiteralInfo(t, env);
|
|
151
|
-
if (lit) return lit.lex;
|
|
152
|
-
const iri = iriValue(t);
|
|
153
|
-
if (iri != null) return iri;
|
|
154
|
-
if (t?.type === 'atom' || t?.type === 'string' || t?.type === 'number') return t.name;
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function rdfListItems(term, env) {
|
|
159
|
-
return properListItems(deref(term, env), env);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function mathCompare(op) {
|
|
163
|
-
return function* ({ goal, env }) {
|
|
164
|
-
const a = numericInfo(goal.args[0], env);
|
|
165
|
-
const b = numericInfo(goal.args[1], env);
|
|
166
|
-
if (!a || !b) return;
|
|
167
|
-
const cmp = compareLexicalOrNumeric(a.lex, b.lex);
|
|
168
|
-
const pass = op === 'gt' ? cmp > 0 : op === 'lt' ? cmp < 0 : op === 'ge' ? cmp >= 0 : op === 'le' ? cmp <= 0 : op === 'eq' ? cmp === 0 : cmp !== 0;
|
|
169
|
-
if (pass) yield env;
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function mathFold(identity, fn, bigFn = null) {
|
|
174
|
-
return function* ({ goal, env }) {
|
|
175
|
-
const items = rdfListItems(goal.args[0], env);
|
|
176
|
-
if (!items) return;
|
|
177
|
-
if (bigFn && items.every((item) => isIntegerLex(item, env))) {
|
|
178
|
-
let acc = identity === null ? null : BigInt(identity);
|
|
179
|
-
for (const item of items) {
|
|
180
|
-
const n = BigInt(numericInfo(item, env).lex);
|
|
181
|
-
acc = acc === null ? n : bigFn(acc, n);
|
|
182
|
-
}
|
|
183
|
-
if (acc === null) return;
|
|
184
|
-
yield* bindOrCheck(goal.args[1], numberLiteral(acc, true), env);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
let acc = identity === null ? null : identity;
|
|
189
|
-
let allInts = true;
|
|
190
|
-
for (const item of items) {
|
|
191
|
-
const n = parseNumber(item, env);
|
|
192
|
-
if (n == null) return;
|
|
193
|
-
if (!isIntegerLex(item, env)) allInts = false;
|
|
194
|
-
acc = acc === null ? n : fn(acc, n);
|
|
195
|
-
}
|
|
196
|
-
if (acc === null) return;
|
|
197
|
-
yield* bindOrCheck(goal.args[1], numberLiteral(acc, allInts && Number.isInteger(acc)), env);
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function mathBinary(fn, forceInteger = false, bigFn = null) {
|
|
202
|
-
return function* ({ goal, env }) {
|
|
203
|
-
const items = rdfListItems(goal.args[0], env);
|
|
204
|
-
if (!items || items.length !== 2) return;
|
|
205
|
-
if (bigFn && isIntegerLex(items[0], env) && isIntegerLex(items[1], env)) {
|
|
206
|
-
const out = bigFn(BigInt(numericInfo(items[0], env).lex), BigInt(numericInfo(items[1], env).lex));
|
|
207
|
-
if (out == null) return;
|
|
208
|
-
yield* bindOrCheck(goal.args[1], numberLiteral(out, true), env);
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
const a = parseNumber(items[0], env), b = parseNumber(items[1], env);
|
|
212
|
-
if (a == null || b == null) return;
|
|
213
|
-
const out = fn(a, b);
|
|
214
|
-
if (out == null || !Number.isFinite(out)) return;
|
|
215
|
-
yield* bindOrCheck(goal.args[1], numberLiteral(out, forceInteger || (isIntegerLex(items[0], env) && isIntegerLex(items[1], env) && Number.isInteger(out))), env);
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function bigIntPow(a, b) {
|
|
220
|
-
if (b < 0n) return null;
|
|
221
|
-
if (b > 1000000n) return null;
|
|
222
|
-
return a ** b;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function mathUnary(fn, forceInteger = false) {
|
|
226
|
-
return function* ({ goal, env }) {
|
|
227
|
-
if ((fn === Math.abs || forceInteger) && isIntegerLex(goal.args[0], env)) {
|
|
228
|
-
const x = BigInt(numericInfo(goal.args[0], env).lex);
|
|
229
|
-
const out = fn === Math.abs ? (x < 0n ? -x : x) : x;
|
|
230
|
-
yield* bindOrCheck(goal.args[1], numberLiteral(out, true), env);
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
const x = parseNumber(goal.args[0], env);
|
|
234
|
-
if (x == null) return;
|
|
235
|
-
const out = fn(x);
|
|
236
|
-
if (out == null || !Number.isFinite(out)) return;
|
|
237
|
-
yield* bindOrCheck(goal.args[1], numberLiteral(out, forceInteger || Number.isInteger(out)), env);
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
function stringTest(op) {
|
|
242
|
-
return function* ({ goal, env }) {
|
|
243
|
-
const a = jsString(goal.args[0], env), b = jsString(goal.args[1], env);
|
|
244
|
-
if (a == null || b == null) return;
|
|
245
|
-
let pass = false;
|
|
246
|
-
if (op === 'contains') pass = a.includes(b);
|
|
247
|
-
else if (op === 'contains-i') pass = a.toLowerCase().includes(b.toLowerCase());
|
|
248
|
-
else if (op === 'ends') pass = a.endsWith(b);
|
|
249
|
-
else if (op === 'starts') pass = a.startsWith(b);
|
|
250
|
-
else if (op === 'eq-i') pass = a.toLowerCase() === b.toLowerCase();
|
|
251
|
-
else if (op === 'ne-i') pass = a.toLowerCase() !== b.toLowerCase();
|
|
252
|
-
else if (op === 'matches' || op === 'not-matches') {
|
|
253
|
-
let re;
|
|
254
|
-
try { re = new RegExp(b); } catch { return; }
|
|
255
|
-
pass = re.test(a);
|
|
256
|
-
if (op === 'not-matches') pass = !pass;
|
|
257
|
-
} else {
|
|
258
|
-
const cmp = a < b ? -1 : a > b ? 1 : 0;
|
|
259
|
-
pass = op === 'gt' ? cmp > 0 : op === 'lt' ? cmp < 0 : op === 'ge' ? cmp >= 0 : cmp <= 0;
|
|
260
|
-
}
|
|
261
|
-
if (pass) yield env;
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function* stringConcatenation({ goal, env }) {
|
|
266
|
-
const items = rdfListItems(goal.args[0], env);
|
|
267
|
-
if (!items) return;
|
|
268
|
-
const parts = [];
|
|
269
|
-
for (const item of items) {
|
|
270
|
-
const s = jsString(item, env);
|
|
271
|
-
if (s == null) return;
|
|
272
|
-
parts.push(s);
|
|
273
|
-
}
|
|
274
|
-
yield* bindOrCheck(goal.args[1], rdfLiteral(parts.join(''), XSD_STRING, '', ''), env);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function* stringFormat({ goal, env }) {
|
|
278
|
-
const items = rdfListItems(goal.args[0], env);
|
|
279
|
-
if (!items || items.length < 1) return;
|
|
280
|
-
const fmt = jsString(items[0], env);
|
|
281
|
-
if (fmt == null) return;
|
|
282
|
-
let i = 1;
|
|
283
|
-
const out = fmt.replace(/%%|%[sdif]/g, (m) => {
|
|
284
|
-
if (m === '%%') return '%';
|
|
285
|
-
const s = i < items.length ? jsString(items[i++], env) : '';
|
|
286
|
-
return s ?? '';
|
|
287
|
-
});
|
|
288
|
-
yield* bindOrCheck(goal.args[1], rdfLiteral(out, XSD_STRING, '', ''), env);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function* stringLength({ goal, env }) {
|
|
292
|
-
const s = jsString(goal.args[0], env);
|
|
293
|
-
if (s == null) return;
|
|
294
|
-
yield* bindOrCheck(goal.args[1], numberLiteral(s.length, true), env);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function* stringCharAt({ goal, env }) {
|
|
298
|
-
const items = rdfListItems(goal.args[0], env);
|
|
299
|
-
if (!items || items.length !== 2) return;
|
|
300
|
-
const s = jsString(items[0], env), idx = parseNumber(items[1], env);
|
|
301
|
-
if (s == null || idx == null) return;
|
|
302
|
-
const i = Math.trunc(idx);
|
|
303
|
-
yield* bindOrCheck(goal.args[1], rdfLiteral(i >= 0 && i < s.length ? s.charAt(i) : '', XSD_STRING, '', ''), env);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function* stringSetCharAt({ goal, env }) {
|
|
307
|
-
const items = rdfListItems(goal.args[0], env);
|
|
308
|
-
if (!items || items.length !== 3) return;
|
|
309
|
-
const s = jsString(items[0], env), idx = parseNumber(items[1], env), ch = jsString(items[2], env);
|
|
310
|
-
if (s == null || idx == null || ch == null) return;
|
|
311
|
-
const i = Math.trunc(idx);
|
|
312
|
-
const out = i >= 0 && i < s.length ? s.slice(0, i) + (ch[0] ?? '') + s.slice(i + 1) : s;
|
|
313
|
-
yield* bindOrCheck(goal.args[1], rdfLiteral(out, XSD_STRING, '', ''), env);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function* stringReplace({ goal, env }) {
|
|
317
|
-
const items = rdfListItems(goal.args[0], env);
|
|
318
|
-
if (!items || items.length !== 3) return;
|
|
319
|
-
const s = jsString(items[0], env), pattern = jsString(items[1], env), repl = jsString(items[2], env);
|
|
320
|
-
if (s == null || pattern == null || repl == null) return;
|
|
321
|
-
let re;
|
|
322
|
-
try { re = new RegExp(pattern, 'g'); } catch { return; }
|
|
323
|
-
yield* bindOrCheck(goal.args[1], rdfLiteral(s.replace(re, repl), XSD_STRING, '', ''), env);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function* stringScrape({ goal, env }) {
|
|
327
|
-
const items = rdfListItems(goal.args[0], env);
|
|
328
|
-
if (!items || items.length !== 2) return;
|
|
329
|
-
const s = jsString(items[0], env), pattern = jsString(items[1], env);
|
|
330
|
-
if (s == null || pattern == null) return;
|
|
331
|
-
let re;
|
|
332
|
-
try { re = new RegExp(pattern); } catch { return; }
|
|
333
|
-
const m = re.exec(s);
|
|
334
|
-
if (!m || m.length < 2) return;
|
|
335
|
-
yield* bindOrCheck(goal.args[1], rdfLiteral(m[1], XSD_STRING, '', ''), env);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function* listAppend({ goal, env }) {
|
|
339
|
-
const lists = rdfListItems(goal.args[0], env);
|
|
340
|
-
if (!lists) return;
|
|
341
|
-
const out = [];
|
|
342
|
-
for (const l of lists) {
|
|
343
|
-
const xs = rdfListItems(l, env);
|
|
344
|
-
if (!xs) return;
|
|
345
|
-
out.push(...xs);
|
|
346
|
-
}
|
|
347
|
-
yield* bindOrCheck(goal.args[1], listFromItems(out), env);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function* listFirst({ goal, env }) {
|
|
351
|
-
const xs = rdfListItems(goal.args[0], env);
|
|
352
|
-
if (!xs || xs.length === 0) return;
|
|
353
|
-
yield* bindOrCheck(goal.args[1], xs[0], env);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
function* listRest({ goal, env }) {
|
|
357
|
-
const xs = rdfListItems(goal.args[0], env);
|
|
358
|
-
if (!xs || xs.length === 0) return;
|
|
359
|
-
yield* bindOrCheck(goal.args[1], listFromItems(xs.slice(1)), env);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
function* listLength({ goal, env }) {
|
|
363
|
-
const xs = rdfListItems(goal.args[0], env);
|
|
364
|
-
if (!xs) return;
|
|
365
|
-
yield* bindOrCheck(goal.args[1], numberLiteral(xs.length, true), env);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
function* listMember({ goal, env }) {
|
|
369
|
-
const xs = rdfListItems(goal.args[0], env);
|
|
370
|
-
if (!xs) return;
|
|
371
|
-
for (const item of xs) yield* bindOrCheck(goal.args[1], item, env);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
function* listIn({ goal, env }) {
|
|
375
|
-
const xs = rdfListItems(goal.args[1], env);
|
|
376
|
-
if (!xs) return;
|
|
377
|
-
for (const item of xs) yield* bindOrCheck(goal.args[0], item, env);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function* listNotMember({ goal, env }) {
|
|
381
|
-
const xs = rdfListItems(goal.args[0], env);
|
|
382
|
-
if (!xs) return;
|
|
383
|
-
for (const item of xs) {
|
|
384
|
-
const probe = env.clone();
|
|
385
|
-
if (unify(goal.args[1], item, probe)) return;
|
|
386
|
-
}
|
|
387
|
-
yield env;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
function* listRemove({ goal, env }) {
|
|
391
|
-
const items = rdfListItems(goal.args[0], env);
|
|
392
|
-
if (!items || items.length !== 2) return;
|
|
393
|
-
const xs = rdfListItems(items[0], env);
|
|
394
|
-
if (!xs) return;
|
|
395
|
-
const out = xs.filter((x) => {
|
|
396
|
-
const probe = env.clone();
|
|
397
|
-
return !unify(x, items[1], probe);
|
|
398
|
-
});
|
|
399
|
-
yield* bindOrCheck(goal.args[1], listFromItems(out), env);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
function* listReverse({ goal, env }) {
|
|
403
|
-
const xs = rdfListItems(goal.args[0], env);
|
|
404
|
-
if (!xs) return;
|
|
405
|
-
yield* bindOrCheck(goal.args[1], listFromItems([...xs].reverse()), env);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
function* listSort({ goal, env }) {
|
|
409
|
-
const xs = rdfListItems(goal.args[0], env);
|
|
410
|
-
if (!xs) return;
|
|
411
|
-
const sorted = [...xs].sort((a, b) => compareLexicalOrNumeric(sortKey(a, env), sortKey(b, env)));
|
|
412
|
-
yield* bindOrCheck(goal.args[1], listFromItems(sorted), env);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
function sortKey(term, env) {
|
|
416
|
-
const s = jsString(term, env);
|
|
417
|
-
if (s != null) return s;
|
|
418
|
-
return termToString(deref(term, env), env, true);
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function cryptoHash(name) {
|
|
422
|
-
const algo = name === 'sha' ? 'sha1' : name;
|
|
423
|
-
return function* ({ goal, env }) {
|
|
424
|
-
const s = jsString(goal.args[0], env);
|
|
425
|
-
if (s == null) return;
|
|
426
|
-
const out = hashHex(algo, s);
|
|
427
|
-
yield* bindOrCheck(goal.args[1], rdfLiteral(out, XSD_STRING, '', ''), env);
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
function timeParts(term, env) {
|
|
432
|
-
const info = rdfLiteralInfo(term, env);
|
|
433
|
-
if (!info || (info.datatype !== XSD_DATE_TIME && info.datatype !== XSD_DATE_ONLY)) return null;
|
|
434
|
-
const m = /^(-?\d{4,})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?$/.exec(info.lex);
|
|
435
|
-
if (!m) return null;
|
|
436
|
-
return { year: Number(m[1]), month: Number(m[2]), day: Number(m[3]), hour: Number(m[4] ?? 0), minute: Number(m[5] ?? 0), second: Number(m[6] ?? 0) };
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
function timeComponent(name) {
|
|
440
|
-
return function* ({ goal, env }) {
|
|
441
|
-
const parts = timeParts(goal.args[0], env);
|
|
442
|
-
if (!parts) return;
|
|
443
|
-
yield* bindOrCheck(goal.args[1], numberLiteral(parts[name], true), env);
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
function* localTime({ goal, env }) {
|
|
448
|
-
const fixed = typeof process !== 'undefined' ? process.env?.EYELANG_LOCAL_TIME : null;
|
|
449
|
-
const now = fixed || new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
450
|
-
yield* bindOrCheck(goal.args[1], rdfLiteral(now, XSD_DATE_TIME, '', ''), env);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
function termCompare(equal) {
|
|
454
|
-
return function* ({ goal, env }) {
|
|
455
|
-
const probe = env.clone();
|
|
456
|
-
const same = unify(goal.args[0], goal.args[1], probe);
|
|
457
|
-
if (same === equal) yield env;
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
function* logUri({ goal, env }) {
|
|
462
|
-
const iri = iriValue(deref(goal.args[0], env));
|
|
463
|
-
if (iri == null) return;
|
|
464
|
-
yield* bindOrCheck(goal.args[1], rdfLiteral(iri, XSD_STRING, '', ''), env);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
function* logDtLit({ goal, env }) {
|
|
468
|
-
const parts = rdfListItems(goal.args[0], env);
|
|
469
|
-
if (!parts || parts.length !== 2) return;
|
|
470
|
-
const lex = jsString(parts[0], env);
|
|
471
|
-
const datatype = iriValue(deref(parts[1], env));
|
|
472
|
-
if (lex == null || datatype == null) return;
|
|
473
|
-
yield* bindOrCheck(goal.args[1], rdfLiteral(lex, datatype, '', ''), env);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
function* logRawType({ goal, env }) {
|
|
477
|
-
const s = deref(goal.args[0], env);
|
|
478
|
-
let iri;
|
|
479
|
-
if (properListItems(s, env)) iri = RDF_LIST;
|
|
480
|
-
else if (s?.type === 'compound' && s.name === 'literal') iri = `${LOG_NS}Literal`;
|
|
481
|
-
else iri = `${LOG_NS}Other`;
|
|
482
|
-
yield* bindOrCheck(goal.args[1], rdfIri(iri), env);
|
|
483
|
-
}
|