eyeling 1.7.7 → 1.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/eyeling.js +116 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -108,6 +108,7 @@ Options:
|
|
|
108
108
|
-n, --no-proof-comments Disable proof explanations (default).
|
|
109
109
|
-s, --super-restricted Disable all builtins except => and <=.
|
|
110
110
|
-a, --ast Print parsed AST as JSON and exit.
|
|
111
|
+
--strings Print log:outputString strings (ordered by key) instead of N3 output.
|
|
111
112
|
```
|
|
112
113
|
|
|
113
114
|
By default, `eyeling`:
|
package/eyeling.js
CHANGED
|
@@ -5300,6 +5300,21 @@ if (pv === LOG_NS + 'conclusion') {
|
|
|
5300
5300
|
return sols.length ? [] : [{ ...subst }];
|
|
5301
5301
|
}
|
|
5302
5302
|
|
|
5303
|
+
// log:outputString
|
|
5304
|
+
// Schema: $s+ log:outputString $o+
|
|
5305
|
+
// Side-effecting output directive. As a builtin goal, we simply succeed
|
|
5306
|
+
// when both sides are bound and the object is a string literal.
|
|
5307
|
+
// Actual printing is handled at the end of a reasoning run (see --strings).
|
|
5308
|
+
if (pv === LOG_NS + 'outputString') {
|
|
5309
|
+
// Require subject to be bound (not a variable) and object to be a concrete string literal.
|
|
5310
|
+
if (g.s instanceof Var) return [];
|
|
5311
|
+
if (g.o instanceof Var) return [];
|
|
5312
|
+
const s = termToJsString(g.o);
|
|
5313
|
+
if (s === null) return [];
|
|
5314
|
+
return [{ ...subst }];
|
|
5315
|
+
}
|
|
5316
|
+
|
|
5317
|
+
|
|
5303
5318
|
// log:collectAllIn (scoped)
|
|
5304
5319
|
if (pv === LOG_NS + 'collectAllIn') {
|
|
5305
5320
|
if (!(g.s instanceof ListTerm) || g.s.elems.length !== 3) return [];
|
|
@@ -6348,6 +6363,97 @@ function formatN3SyntaxError(err, text, path) {
|
|
|
6348
6363
|
// ===========================================================================
|
|
6349
6364
|
// CLI entry point
|
|
6350
6365
|
// ===========================================================================
|
|
6366
|
+
// ===========================================================================
|
|
6367
|
+
// log:outputString support
|
|
6368
|
+
// ===========================================================================
|
|
6369
|
+
|
|
6370
|
+
function __compareOutputStringKeys(a, b, prefixes) {
|
|
6371
|
+
// Deterministic ordering of keys. The spec only requires "order of the subject keys"
|
|
6372
|
+
// and leaves concrete term ordering reasoner-dependent. We implement:
|
|
6373
|
+
// 1) numeric literals (numeric value)
|
|
6374
|
+
// 2) plain literals (lexical form)
|
|
6375
|
+
// 3) IRIs
|
|
6376
|
+
// 4) blank nodes (label)
|
|
6377
|
+
// 5) fallback: skolemKeyFromTerm
|
|
6378
|
+
const aNum = parseNumericLiteralInfo(a);
|
|
6379
|
+
const bNum = parseNumericLiteralInfo(b);
|
|
6380
|
+
if (aNum && bNum) {
|
|
6381
|
+
// bigint or number
|
|
6382
|
+
if (aNum.kind === 'bigint' && bNum.kind === 'bigint') {
|
|
6383
|
+
if (aNum.value < bNum.value) return -1;
|
|
6384
|
+
if (aNum.value > bNum.value) return 1;
|
|
6385
|
+
return 0;
|
|
6386
|
+
}
|
|
6387
|
+
const av = Number(aNum.value);
|
|
6388
|
+
const bv = Number(bNum.value);
|
|
6389
|
+
if (av < bv) return -1;
|
|
6390
|
+
if (av > bv) return 1;
|
|
6391
|
+
return 0;
|
|
6392
|
+
}
|
|
6393
|
+
if (aNum && !bNum) return -1;
|
|
6394
|
+
if (!aNum && bNum) return 1;
|
|
6395
|
+
|
|
6396
|
+
// Plain literal ordering (lexical)
|
|
6397
|
+
if (a instanceof Literal && b instanceof Literal) {
|
|
6398
|
+
const [alex] = literalParts(a.value);
|
|
6399
|
+
const [blex] = literalParts(b.value);
|
|
6400
|
+
if (alex < blex) return -1;
|
|
6401
|
+
if (alex > blex) return 1;
|
|
6402
|
+
return 0;
|
|
6403
|
+
}
|
|
6404
|
+
if (a instanceof Literal && !(b instanceof Literal)) return -1;
|
|
6405
|
+
if (!(a instanceof Literal) && b instanceof Literal) return 1;
|
|
6406
|
+
|
|
6407
|
+
// IRIs
|
|
6408
|
+
if (a instanceof Iri && b instanceof Iri) {
|
|
6409
|
+
if (a.value < b.value) return -1;
|
|
6410
|
+
if (a.value > b.value) return 1;
|
|
6411
|
+
return 0;
|
|
6412
|
+
}
|
|
6413
|
+
if (a instanceof Iri && !(b instanceof Iri)) return -1;
|
|
6414
|
+
if (!(a instanceof Iri) && b instanceof Iri) return 1;
|
|
6415
|
+
|
|
6416
|
+
// Blank nodes
|
|
6417
|
+
if (a instanceof Blank && b instanceof Blank) {
|
|
6418
|
+
if (a.label < b.label) return -1;
|
|
6419
|
+
if (a.label > b.label) return 1;
|
|
6420
|
+
return 0;
|
|
6421
|
+
}
|
|
6422
|
+
if (a instanceof Blank && !(b instanceof Blank)) return -1;
|
|
6423
|
+
if (!(a instanceof Blank) && b instanceof Blank) return 1;
|
|
6424
|
+
|
|
6425
|
+
// Fallback
|
|
6426
|
+
const ak = skolemKeyFromTerm(a);
|
|
6427
|
+
const bk = skolemKeyFromTerm(b);
|
|
6428
|
+
if (ak < bk) return -1;
|
|
6429
|
+
if (ak > bk) return 1;
|
|
6430
|
+
return 0;
|
|
6431
|
+
}
|
|
6432
|
+
|
|
6433
|
+
function __collectOutputStringsFromFacts(facts, prefixes) {
|
|
6434
|
+
// Gather all (key, string) pairs from the saturated fact store.
|
|
6435
|
+
const pairs = [];
|
|
6436
|
+
for (const tr of facts) {
|
|
6437
|
+
if (!(tr && tr.p instanceof Iri)) continue;
|
|
6438
|
+
if (tr.p.value !== LOG_NS + 'outputString') continue;
|
|
6439
|
+
if (!(tr.o instanceof Literal)) continue;
|
|
6440
|
+
|
|
6441
|
+
const s = termToJsString(tr.o);
|
|
6442
|
+
if (s === null) continue;
|
|
6443
|
+
|
|
6444
|
+
pairs.push({ key: tr.s, text: s, idx: pairs.length });
|
|
6445
|
+
}
|
|
6446
|
+
|
|
6447
|
+
pairs.sort((a, b) => {
|
|
6448
|
+
const c = __compareOutputStringKeys(a.key, b.key, prefixes);
|
|
6449
|
+
if (c !== 0) return c;
|
|
6450
|
+
return a.idx - b.idx; // stable tie-breaker
|
|
6451
|
+
});
|
|
6452
|
+
|
|
6453
|
+
return pairs.map((p) => p.text).join('');
|
|
6454
|
+
}
|
|
6455
|
+
|
|
6456
|
+
|
|
6351
6457
|
function main() {
|
|
6352
6458
|
// Drop "node" and script name; keep only user-provided args
|
|
6353
6459
|
const argv = process.argv.slice(2);
|
|
@@ -6364,7 +6470,8 @@ function main() {
|
|
|
6364
6470
|
` -p, --proof-comments Enable proof explanations.\n` +
|
|
6365
6471
|
` -n, --no-proof-comments Disable proof explanations (default).\n` +
|
|
6366
6472
|
` -s, --super-restricted Disable all builtins except => and <=.\n` +
|
|
6367
|
-
` -a, --ast Print parsed AST as JSON and exit.\n
|
|
6473
|
+
` -a, --ast Print parsed AST as JSON and exit.\n` +
|
|
6474
|
+
` --strings Print log:outputString strings (ordered by key) instead of N3 output.\n`;
|
|
6368
6475
|
(toStderr ? console.error : console.log)(msg);
|
|
6369
6476
|
}
|
|
6370
6477
|
|
|
@@ -6385,6 +6492,8 @@ function main() {
|
|
|
6385
6492
|
|
|
6386
6493
|
const showAst = argv.includes('--ast') || argv.includes('-a');
|
|
6387
6494
|
|
|
6495
|
+
const outputStringsMode = argv.includes('--strings');
|
|
6496
|
+
|
|
6388
6497
|
// --proof-comments / -p: enable proof explanations
|
|
6389
6498
|
if (argv.includes('--proof-comments') || argv.includes('-p')) {
|
|
6390
6499
|
proofCommentsEnabled = true;
|
|
@@ -6460,6 +6569,12 @@ function main() {
|
|
|
6460
6569
|
|
|
6461
6570
|
const facts = triples.filter((tr) => isGroundTriple(tr));
|
|
6462
6571
|
const derived = forwardChain(facts, frules, brules);
|
|
6572
|
+
// If requested, print log:outputString values (ordered by subject key) and exit.
|
|
6573
|
+
if (outputStringsMode) {
|
|
6574
|
+
const out = __collectOutputStringsFromFacts(facts, prefixes);
|
|
6575
|
+
if (out) process.stdout.write(out);
|
|
6576
|
+
process.exit(0);
|
|
6577
|
+
}
|
|
6463
6578
|
const derivedTriples = derived.map((df) => df.fact);
|
|
6464
6579
|
const usedPrefixes = prefixes.prefixesUsedForOutput(derivedTriples);
|
|
6465
6580
|
|