eyeling 1.33.2 → 1.33.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/examples/eyelang/README.md +11 -76
  2. package/examples/eyelang/SPEC.md +1 -2
  3. package/eyelang.d.ts +0 -12
  4. package/index.d.ts +0 -4
  5. package/index.js +1 -5
  6. package/lib/eyelang/builtins/registry.js +1 -2
  7. package/lib/eyelang/builtins/search.js +3 -3
  8. package/lib/eyelang/cli.js +1 -13
  9. package/lib/eyelang/hash.js +2 -2
  10. package/lib/eyelang/index.js +0 -1
  11. package/lib/eyelang/program.js +0 -7
  12. package/package.json +1 -1
  13. package/test/eyelang/run-examples.mjs +1 -2
  14. package/test/eyelang/run-regression.mjs +0 -61
  15. package/examples/eyelang/annotation-rdf12.ttl +0 -12
  16. package/examples/eyelang/directional-language.ttl +0 -9
  17. package/examples/eyelang/eyeling-ackermann.n3 +0 -41
  18. package/examples/eyelang/eyeling-age-threshold.n3 +0 -12
  19. package/examples/eyelang/eyeling-alignment-demo.n3 +0 -11
  20. package/examples/eyelang/eyeling-allen-interval-calculus-small.n3 +0 -13
  21. package/examples/eyelang/eyeling-backward-recursion.n3 +0 -11
  22. package/examples/eyelang/eyeling-backward.n3 +0 -10
  23. package/examples/eyelang/eyeling-basic-monadic-small.n3 +0 -11
  24. package/examples/eyelang/eyeling-bmi.n3 +0 -10
  25. package/examples/eyelang/eyeling-cat-koko.n3 +0 -15
  26. package/examples/eyelang/eyeling-collatz-small.n3 +0 -11
  27. package/examples/eyelang/eyeling-collection.n3 +0 -11
  28. package/examples/eyelang/eyeling-complex-arithmetic.n3 +0 -10
  29. package/examples/eyelang/eyeling-context-association.n3 +0 -11
  30. package/examples/eyelang/eyeling-control-system-small.n3 +0 -11
  31. package/examples/eyelang/eyeling-crypto-builtins-extra.n3 +0 -10
  32. package/examples/eyelang/eyeling-crypto-builtins.n3 +0 -8
  33. package/examples/eyelang/eyeling-deep-taxonomy-10.n3 +0 -18
  34. package/examples/eyelang/eyeling-derived-backward-rule-flat.n3 +0 -10
  35. package/examples/eyelang/eyeling-derived-rule-flat.n3 +0 -9
  36. package/examples/eyelang/eyeling-digital-product-passport-small.n3 +0 -11
  37. package/examples/eyelang/eyeling-dijkstra-tiny.n3 +0 -14
  38. package/examples/eyelang/eyeling-dog-license.n3 +0 -13
  39. package/examples/eyelang/eyeling-drone-corridor-planner-small.n3 +0 -13
  40. package/examples/eyelang/eyeling-equals.n3 +0 -8
  41. package/examples/eyelang/eyeling-equivalence-classes.n3 +0 -11
  42. package/examples/eyelang/eyeling-euler-identity.n3 +0 -9
  43. package/examples/eyelang/eyeling-existential-rule.n3 +0 -9
  44. package/examples/eyelang/eyeling-expression-eval.n3 +0 -11
  45. package/examples/eyelang/eyeling-family-cousins-extended.n3 +0 -12
  46. package/examples/eyelang/eyeling-fastpow.n3 +0 -10
  47. package/examples/eyelang/eyeling-fibonacci.n3 +0 -44
  48. package/examples/eyelang/eyeling-french-cities-reachability.n3 +0 -22
  49. package/examples/eyelang/eyeling-goldbach-small.n3 +0 -22
  50. package/examples/eyelang/eyeling-good-cobbler.n3 +0 -9
  51. package/examples/eyelang/eyeling-list-builtins.n3 +0 -10
  52. package/examples/eyelang/eyeling-list-collection-extra.n3 +0 -9
  53. package/examples/eyelang/eyeling-math-builtins.n3 +0 -9
  54. package/examples/eyelang/eyeling-string-builtins-extra.n3 +0 -9
  55. package/examples/eyelang/eyeling-string-builtins.n3 +0 -10
  56. package/examples/eyelang/eyeling-time-builtins.n3 +0 -11
  57. package/examples/eyelang/eyeling-time-components-extra.n3 +0 -10
  58. package/examples/eyelang/eyeling-witch.n3 +0 -10
  59. package/examples/eyelang/family-cousins.n3 +0 -17
  60. package/examples/eyelang/n3-builtins.n3 +0 -28
  61. package/examples/eyelang/output/annotation-rdf12.ttl +0 -1
  62. package/examples/eyelang/output/directional-language.ttl +0 -1
  63. package/examples/eyelang/output/eyeling-ackermann.n3 +0 -12
  64. package/examples/eyelang/output/eyeling-age-threshold.n3 +0 -4
  65. package/examples/eyelang/output/eyeling-alignment-demo.n3 +0 -1
  66. package/examples/eyelang/output/eyeling-allen-interval-calculus-small.n3 +0 -3
  67. package/examples/eyelang/output/eyeling-backward-recursion.n3 +0 -9
  68. package/examples/eyelang/output/eyeling-backward.n3 +0 -1
  69. package/examples/eyelang/output/eyeling-basic-monadic-small.n3 +0 -8
  70. package/examples/eyelang/output/eyeling-bmi.n3 +0 -2
  71. package/examples/eyelang/output/eyeling-cat-koko.n3 +0 -3
  72. package/examples/eyelang/output/eyeling-collatz-small.n3 +0 -3
  73. package/examples/eyelang/output/eyeling-collection.n3 +0 -1
  74. package/examples/eyelang/output/eyeling-complex-arithmetic.n3 +0 -5
  75. package/examples/eyelang/output/eyeling-context-association.n3 +0 -4
  76. package/examples/eyelang/output/eyeling-control-system-small.n3 +0 -4
  77. package/examples/eyelang/output/eyeling-crypto-builtins-extra.n3 +0 -3
  78. package/examples/eyelang/output/eyeling-crypto-builtins.n3 +0 -2
  79. package/examples/eyelang/output/eyeling-deep-taxonomy-10.n3 +0 -32
  80. package/examples/eyelang/output/eyeling-derived-backward-rule-flat.n3 +0 -4
  81. package/examples/eyelang/output/eyeling-derived-rule-flat.n3 +0 -2
  82. package/examples/eyelang/output/eyeling-digital-product-passport-small.n3 +0 -3
  83. package/examples/eyelang/output/eyeling-dijkstra-tiny.n3 +0 -9
  84. package/examples/eyelang/output/eyeling-dog-license.n3 +0 -1
  85. package/examples/eyelang/output/eyeling-drone-corridor-planner-small.n3 +0 -5
  86. package/examples/eyelang/output/eyeling-equals.n3 +0 -1
  87. package/examples/eyelang/output/eyeling-equivalence-classes.n3 +0 -2
  88. package/examples/eyelang/output/eyeling-euler-identity.n3 +0 -3
  89. package/examples/eyelang/output/eyeling-existential-rule.n3 +0 -4
  90. package/examples/eyelang/output/eyeling-expression-eval.n3 +0 -3
  91. package/examples/eyelang/output/eyeling-family-cousins-extended.n3 +0 -6
  92. package/examples/eyelang/output/eyeling-fastpow.n3 +0 -4
  93. package/examples/eyelang/output/eyeling-fibonacci.n3 +0 -6
  94. package/examples/eyelang/output/eyeling-french-cities-reachability.n3 +0 -25
  95. package/examples/eyelang/output/eyeling-goldbach-small.n3 +0 -2
  96. package/examples/eyelang/output/eyeling-good-cobbler.n3 +0 -2
  97. package/examples/eyelang/output/eyeling-list-builtins.n3 +0 -6
  98. package/examples/eyelang/output/eyeling-list-collection-extra.n3 +0 -5
  99. package/examples/eyelang/output/eyeling-math-builtins.n3 +0 -5
  100. package/examples/eyelang/output/eyeling-string-builtins-extra.n3 +0 -3
  101. package/examples/eyelang/output/eyeling-string-builtins.n3 +0 -4
  102. package/examples/eyelang/output/eyeling-time-builtins.n3 +0 -4
  103. package/examples/eyelang/output/eyeling-time-components-extra.n3 +0 -5
  104. package/examples/eyelang/output/eyeling-witch.n3 +0 -2
  105. package/examples/eyelang/output/family-cousins.n3 +0 -8
  106. package/examples/eyelang/output/n3-builtins.n3 +0 -6
  107. package/examples/eyelang/output/socrates.n3 +0 -1
  108. package/examples/eyelang/output/triple-term.n3 +0 -2
  109. package/examples/eyelang/socrates.n3 +0 -11
  110. package/examples/eyelang/triple-term.n3 +0 -9
  111. package/lib/eyelang/builtins/n3.js +0 -483
  112. 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
- }