eyeling 1.24.33 → 1.25.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/HANDBOOK.md CHANGED
@@ -793,7 +793,7 @@ Implementation: deterministic Skolem IDs live in `lib/skolem.js`; the per-firing
793
793
  A rule whose conclusion is `false` is treated as a hard failure. During forward chaining:
794
794
 
795
795
  - Eyeling proves the premise (it only needs one solution)
796
- - if the premise is provable, it prints a message and exits with status code 2
796
+ - if the premise is provable, it prints a message and exits with status code 65 (`EX_DATAERR` in Unix `sysexits.h` terminology)
797
797
 
798
798
  This is Eyeling’s way to express hard consistency checks and detect inconsistencies.
799
799
 
@@ -3417,7 +3417,7 @@ So Eyeling is not only implementing the semantics document; it is also defining
3417
3417
 
3418
3418
  #### G.2.4 Inference fuses (`=> false`) are an engine-level procedural feature
3419
3419
 
3420
- The semantics document discusses `false` in relation to implication and constraints. Eyeling turns `{ ... } => false` into an engine-level hard failure with a visible message and failing exit status. That is a practical tooling feature: it lets a rule act like a checked invariant.
3420
+ The semantics document discusses `false` in relation to implication and constraints. Eyeling turns `{ ... } => false` into an engine-level hard failure with a visible message and exit status 65 (`EX_DATAERR`). That is a practical tooling feature: it lets a rule act like a checked invariant.
3421
3421
 
3422
3422
  This is very useful in real programs, but it is an operational behavior of the reasoner, not something a model-theoretic semantics “executes.”
3423
3423
 
@@ -5517,6 +5517,10 @@ const {
5517
5517
  copyQuotedGraphMetadata,
5518
5518
  } = require('./prelude');
5519
5519
 
5520
+ // Inference fuses use sysexits.h EX_DATAERR (65): input/rules made a
5521
+ // forbidden condition provable, rather than a generic usage/runtime error.
5522
+ const INFERENCE_FUSE_EXIT_CODE = 65;
5523
+
5520
5524
  // In N3/Turtle, rdf:nil is the canonical IRI for the empty RDF list.
5521
5525
  // Eyeling represents list literals with ListTerm; ensure rdf:nil unifies with ().
5522
5526
  const RDF_NIL_IRI = RDF_NS + 'nil';
@@ -8445,7 +8449,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
8445
8449
  // Allow dynamic fuses: ... => ?X. where ?X becomes false
8446
8450
  if (dynTerm instanceof Literal && dynTerm.value === 'false') {
8447
8451
  __printTriggeredFuse(r, opts && opts.prefixes, s, 'Dynamic head resolved to false.');
8448
- __exitReasoning(2, 'Inference fuse triggered.');
8452
+ __exitReasoning(INFERENCE_FUSE_EXIT_CODE, 'Inference fuse triggered.');
8449
8453
  }
8450
8454
 
8451
8455
  const dynTriples = __graphTriplesOrTrue(dynTerm);
@@ -8606,7 +8610,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
8606
8610
  // Inference fuse
8607
8611
  if (r.isFuse && sols.length) {
8608
8612
  __printTriggeredFuse(r, opts && opts.prefixes, sols[0]);
8609
- __exitReasoning(2, 'Inference fuse triggered.');
8613
+ __exitReasoning(INFERENCE_FUSE_EXIT_CODE, 'Inference fuse triggered.');
8610
8614
  }
8611
8615
 
8612
8616
  for (const s of sols) {
@@ -9143,6 +9147,7 @@ module.exports = {
9143
9147
  registerBuiltinModule,
9144
9148
  loadBuiltinModule,
9145
9149
  listBuiltinIris,
9150
+ INFERENCE_FUSE_EXIT_CODE,
9146
9151
  };
9147
9152
 
9148
9153
  };
@@ -9170,6 +9175,7 @@ module.exports = {
9170
9175
  rdfjs: dataFactory,
9171
9176
  main: engine.main,
9172
9177
  version: engine.version,
9178
+ INFERENCE_FUSE_EXIT_CODE: engine.INFERENCE_FUSE_EXIT_CODE,
9173
9179
 
9174
9180
  // internals for playground.html
9175
9181
  lex: engine.lex,
@@ -10,6 +10,8 @@ function getBrowserApi() {
10
10
  return api;
11
11
  }
12
12
 
13
+ export const INFERENCE_FUSE_EXIT_CODE = 65;
14
+
13
15
  export function reasonStream(input, opts) {
14
16
  return getBrowserApi().reasonStream(input, opts);
15
17
  }
@@ -64,6 +66,7 @@ const eyeling = {
64
66
  get version() {
65
67
  return getBrowserApi().version;
66
68
  },
69
+ INFERENCE_FUSE_EXIT_CODE,
67
70
  reasonStream,
68
71
  reasonRdfJs,
69
72
  rdfjs,
package/examples/fuse.n3 CHANGED
@@ -2,7 +2,7 @@
2
2
  # Inference fuse
3
3
  # ==============
4
4
 
5
- # expect-exit: 2
5
+ # expect-exit: 65
6
6
 
7
7
  @prefix : <https://eyereasoner.github.io/ns#>.
8
8
 
package/examples/liar.n3 CHANGED
@@ -3,7 +3,7 @@
3
3
  # Example from Patrick Hochstenbach
4
4
  # =================================
5
5
 
6
- # expect-exit: 2
6
+ # expect-exit: 65
7
7
 
8
8
  @prefix : <https://eyereasoner.github.io/ns#>.
9
9
  @prefix log: <http://www.w3.org/2000/10/swap/log#>.
package/eyeling.js CHANGED
@@ -5517,6 +5517,10 @@ const {
5517
5517
  copyQuotedGraphMetadata,
5518
5518
  } = require('./prelude');
5519
5519
 
5520
+ // Inference fuses use sysexits.h EX_DATAERR (65): input/rules made a
5521
+ // forbidden condition provable, rather than a generic usage/runtime error.
5522
+ const INFERENCE_FUSE_EXIT_CODE = 65;
5523
+
5520
5524
  // In N3/Turtle, rdf:nil is the canonical IRI for the empty RDF list.
5521
5525
  // Eyeling represents list literals with ListTerm; ensure rdf:nil unifies with ().
5522
5526
  const RDF_NIL_IRI = RDF_NS + 'nil';
@@ -8445,7 +8449,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
8445
8449
  // Allow dynamic fuses: ... => ?X. where ?X becomes false
8446
8450
  if (dynTerm instanceof Literal && dynTerm.value === 'false') {
8447
8451
  __printTriggeredFuse(r, opts && opts.prefixes, s, 'Dynamic head resolved to false.');
8448
- __exitReasoning(2, 'Inference fuse triggered.');
8452
+ __exitReasoning(INFERENCE_FUSE_EXIT_CODE, 'Inference fuse triggered.');
8449
8453
  }
8450
8454
 
8451
8455
  const dynTriples = __graphTriplesOrTrue(dynTerm);
@@ -8606,7 +8610,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
8606
8610
  // Inference fuse
8607
8611
  if (r.isFuse && sols.length) {
8608
8612
  __printTriggeredFuse(r, opts && opts.prefixes, sols[0]);
8609
- __exitReasoning(2, 'Inference fuse triggered.');
8613
+ __exitReasoning(INFERENCE_FUSE_EXIT_CODE, 'Inference fuse triggered.');
8610
8614
  }
8611
8615
 
8612
8616
  for (const s of sols) {
@@ -9143,6 +9147,7 @@ module.exports = {
9143
9147
  registerBuiltinModule,
9144
9148
  loadBuiltinModule,
9145
9149
  listBuiltinIris,
9150
+ INFERENCE_FUSE_EXIT_CODE,
9146
9151
  };
9147
9152
 
9148
9153
  };
@@ -9170,6 +9175,7 @@ module.exports = {
9170
9175
  rdfjs: dataFactory,
9171
9176
  main: engine.main,
9172
9177
  version: engine.version,
9178
+ INFERENCE_FUSE_EXIT_CODE: engine.INFERENCE_FUSE_EXIT_CODE,
9173
9179
 
9174
9180
  // internals for playground.html
9175
9181
  lex: engine.lex,
package/index.d.ts CHANGED
@@ -209,6 +209,7 @@ declare module 'eyeling' {
209
209
  opts?: Omit<ReasonStreamOptions, 'rdfjs' | 'onDerived'>,
210
210
  ): AsyncIterable<RdfJsQuad>;
211
211
 
212
+ export const INFERENCE_FUSE_EXIT_CODE: 65;
212
213
  export const rdfjs: RdfJsDataFactory;
213
214
  export function registerBuiltin(iri: string, handler: BuiltinHandler): BuiltinHandler;
214
215
  export function unregisterBuiltin(iri: string): boolean;
@@ -237,6 +238,7 @@ declare module 'eyeling/browser' {
237
238
  opts?: Omit<ReasonStreamOptions, 'rdfjs' | 'onDerived'>,
238
239
  ): AsyncIterable<RdfJsQuad>;
239
240
 
241
+ export const INFERENCE_FUSE_EXIT_CODE: 65;
240
242
  export const rdfjs: RdfJsDataFactory;
241
243
  export function registerBuiltin(iri: string, handler: BuiltinHandler): BuiltinHandler;
242
244
  export function unregisterBuiltin(iri: string): boolean;
@@ -247,6 +249,7 @@ declare module 'eyeling/browser' {
247
249
  readonly version: string;
248
250
  reasonStream: typeof reasonStream;
249
251
  reasonRdfJs: typeof reasonRdfJs;
252
+ readonly INFERENCE_FUSE_EXIT_CODE: typeof INFERENCE_FUSE_EXIT_CODE;
250
253
  rdfjs: typeof rdfjs;
251
254
  registerBuiltin: typeof registerBuiltin;
252
255
  unregisterBuiltin: typeof unregisterBuiltin;
package/lib/engine.js CHANGED
@@ -30,6 +30,10 @@ const {
30
30
  copyQuotedGraphMetadata,
31
31
  } = require('./prelude');
32
32
 
33
+ // Inference fuses use sysexits.h EX_DATAERR (65): input/rules made a
34
+ // forbidden condition provable, rather than a generic usage/runtime error.
35
+ const INFERENCE_FUSE_EXIT_CODE = 65;
36
+
33
37
  // In N3/Turtle, rdf:nil is the canonical IRI for the empty RDF list.
34
38
  // Eyeling represents list literals with ListTerm; ensure rdf:nil unifies with ().
35
39
  const RDF_NIL_IRI = RDF_NS + 'nil';
@@ -2958,7 +2962,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
2958
2962
  // Allow dynamic fuses: ... => ?X. where ?X becomes false
2959
2963
  if (dynTerm instanceof Literal && dynTerm.value === 'false') {
2960
2964
  __printTriggeredFuse(r, opts && opts.prefixes, s, 'Dynamic head resolved to false.');
2961
- __exitReasoning(2, 'Inference fuse triggered.');
2965
+ __exitReasoning(INFERENCE_FUSE_EXIT_CODE, 'Inference fuse triggered.');
2962
2966
  }
2963
2967
 
2964
2968
  const dynTriples = __graphTriplesOrTrue(dynTerm);
@@ -3119,7 +3123,7 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
3119
3123
  // Inference fuse
3120
3124
  if (r.isFuse && sols.length) {
3121
3125
  __printTriggeredFuse(r, opts && opts.prefixes, sols[0]);
3122
- __exitReasoning(2, 'Inference fuse triggered.');
3126
+ __exitReasoning(INFERENCE_FUSE_EXIT_CODE, 'Inference fuse triggered.');
3123
3127
  }
3124
3128
 
3125
3129
  for (const s of sols) {
@@ -3656,4 +3660,5 @@ module.exports = {
3656
3660
  registerBuiltinModule,
3657
3661
  loadBuiltinModule,
3658
3662
  listBuiltinIris,
3663
+ INFERENCE_FUSE_EXIT_CODE,
3659
3664
  };
package/lib/entry.js CHANGED
@@ -21,6 +21,7 @@ module.exports = {
21
21
  rdfjs: dataFactory,
22
22
  main: engine.main,
23
23
  version: engine.version,
24
+ INFERENCE_FUSE_EXIT_CODE: engine.INFERENCE_FUSE_EXIT_CODE,
24
25
 
25
26
  // internals for playground.html
26
27
  lex: engine.lex,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.24.33",
3
+ "version": "1.25.0",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [
package/test/api.test.js CHANGED
@@ -457,13 +457,13 @@ ${U('s')} ${U('p')} ${U('o')}.
457
457
  notExpect: [/^#/m],
458
458
  },
459
459
  {
460
- name: '11 negative entailment: rule derives false (expect exit 2 => throws)',
460
+ name: '11 negative entailment: rule derives false (expect exit 65 => throws)',
461
461
  opt: { proofComments: false },
462
462
  input: `
463
463
  { ${U('a')} ${U('p')} ${U('b')}. } => false.
464
464
  ${U('a')} ${U('p')} ${U('b')}.
465
465
  `,
466
- expectErrorCode: 2,
466
+ expectErrorCode: 65,
467
467
  },
468
468
  {
469
469
  name: '12 invalid syntax should throw (non-zero exit)',
@@ -987,10 +987,10 @@ ${transitiveClosureN3('sub')}
987
987
  ],
988
988
  },
989
989
  {
990
- name: '25 heavier negative entailment: batch + forbidden => false (expect exit 2)',
990
+ name: '25 heavier negative entailment: batch + forbidden => false (expect exit 65)',
991
991
  opt: { proofComments: false, maxBuffer: 200 * 1024 * 1024 },
992
992
  input: negativeEntailmentBatchN3(200),
993
- expectErrorCode: 2,
993
+ expectErrorCode: 65,
994
994
  },
995
995
  {
996
996
  name: '26 sanity: no rules => no newly derived facts',
@@ -1108,7 +1108,7 @@ ${U('a')} ${U('p')} ${U('b')}.
1108
1108
  { ${U('a')} ${U('p')} ${U('b')}. } => { ${U('a')} ${U('q')} ${U('b')}. }.
1109
1109
  { ${U('a')} ${U('q')} ${U('b')}. } => false.
1110
1110
  `,
1111
- expectErrorCode: 2,
1111
+ expectErrorCode: 65,
1112
1112
  },
1113
1113
 
1114
1114
  {
@@ -79,12 +79,12 @@ function normalizeMarkdownForCompare(text) {
79
79
 
80
80
  // Expectation logic (shared with test/examples.test.js):
81
81
  // 1) If file contains: # expect-exit: N -> use N
82
- // 2) Else, if it contains "=> false" -> expect exit 2
82
+ // 2) Else, if it contains "=> false" -> expect exit 65
83
83
  // 3) Else -> expect exit 0
84
84
  function expectedExitCode(n3Text) {
85
85
  const m = n3Text.match(/^[ \t]*#[: ]*expect-exit:[ \t]*([0-9]+)\b/m);
86
86
  if (m) return parseInt(m[1], 10);
87
- if (/=>\s*false\b/.test(n3Text)) return 2;
87
+ if (/=>\s*false\b/.test(n3Text)) return 65;
88
88
  return 0;
89
89
  }
90
90
 
package/tools/bundle.js CHANGED
@@ -229,6 +229,8 @@ function getBrowserApi() {
229
229
  return api;
230
230
  }
231
231
 
232
+ export const INFERENCE_FUSE_EXIT_CODE = 65;
233
+
232
234
  export function reasonStream(input, opts) {
233
235
  return getBrowserApi().reasonStream(input, opts);
234
236
  }
@@ -283,6 +285,7 @@ const eyeling = {
283
285
  get version() {
284
286
  return getBrowserApi().version;
285
287
  },
288
+ INFERENCE_FUSE_EXIT_CODE,
286
289
  reasonStream,
287
290
  reasonRdfJs,
288
291
  rdfjs,