eyeling 1.10.1 → 1.10.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/eyeling.js +207 -147
- package/lib/engine.js +11 -147
- package/lib/skolem.js +49 -0
- package/lib/time.js +103 -0
- package/lib/trace.js +35 -0
- package/package.json +1 -1
package/eyeling.js
CHANGED
|
@@ -357,6 +357,10 @@ const { liftBlankRuleVars, reorderPremiseForConstraints, isConstraintBuiltin } =
|
|
|
357
357
|
|
|
358
358
|
const { termToN3, tripleToN3 } = require('./printing');
|
|
359
359
|
|
|
360
|
+
const trace = require('./trace');
|
|
361
|
+
const time = require('./time');
|
|
362
|
+
const { deterministicSkolemIdFromKey } = require('./skolem');
|
|
363
|
+
|
|
360
364
|
let version = 'dev';
|
|
361
365
|
try {
|
|
362
366
|
// Node: keep package.json version if available
|
|
@@ -726,146 +730,6 @@ let proofCommentsEnabled = false;
|
|
|
726
730
|
// Super restricted mode: disable *all* builtins except => / <= (log:implies / log:impliedBy)
|
|
727
731
|
let superRestrictedMode = false;
|
|
728
732
|
|
|
729
|
-
// Debug/trace printing support (log:trace)
|
|
730
|
-
let __tracePrefixes = null;
|
|
731
|
-
|
|
732
|
-
function __traceWriteLine(line) {
|
|
733
|
-
// Prefer stderr in Node, fall back to console.error elsewhere.
|
|
734
|
-
try {
|
|
735
|
-
if (__IS_NODE && typeof process !== 'undefined' && process.stderr && typeof process.stderr.write === 'function') {
|
|
736
|
-
process.stderr.write(String(line) + '\n');
|
|
737
|
-
return;
|
|
738
|
-
}
|
|
739
|
-
} catch (_) {}
|
|
740
|
-
try {
|
|
741
|
-
if (typeof console !== 'undefined' && typeof console.error === 'function') console.error(line);
|
|
742
|
-
} catch (_) {}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
// ----------------------------------------------------------------------------
|
|
746
|
-
// Deterministic time support
|
|
747
|
-
// ----------------------------------------------------------------------------
|
|
748
|
-
// If set, overrides time:localTime across the whole run (and across runs if you
|
|
749
|
-
// pass the same value). Store as xsd:dateTime *lexical* string (no quotes).
|
|
750
|
-
let fixedNowLex = null;
|
|
751
|
-
|
|
752
|
-
// If not fixed, we still memoize one value per run to avoid re-firing rules.
|
|
753
|
-
let runNowLex = null;
|
|
754
|
-
|
|
755
|
-
// ===========================================================================
|
|
756
|
-
// Run-level time helpers
|
|
757
|
-
// ===========================================================================
|
|
758
|
-
|
|
759
|
-
function localIsoDateTimeString(d) {
|
|
760
|
-
function pad(n, width = 2) {
|
|
761
|
-
return String(n).padStart(width, '0');
|
|
762
|
-
}
|
|
763
|
-
const year = d.getFullYear();
|
|
764
|
-
const month = d.getMonth() + 1;
|
|
765
|
-
const day = d.getDate();
|
|
766
|
-
const hour = d.getHours();
|
|
767
|
-
const min = d.getMinutes();
|
|
768
|
-
const sec = d.getSeconds();
|
|
769
|
-
const ms = d.getMilliseconds();
|
|
770
|
-
const offsetMin = -d.getTimezoneOffset(); // minutes east of UTC
|
|
771
|
-
const sign = offsetMin >= 0 ? '+' : '-';
|
|
772
|
-
const abs = Math.abs(offsetMin);
|
|
773
|
-
const oh = Math.floor(abs / 60);
|
|
774
|
-
const om = abs % 60;
|
|
775
|
-
const msPart = ms ? '.' + String(ms).padStart(3, '0') : '';
|
|
776
|
-
return (
|
|
777
|
-
pad(year, 4) +
|
|
778
|
-
'-' +
|
|
779
|
-
pad(month) +
|
|
780
|
-
'-' +
|
|
781
|
-
pad(day) +
|
|
782
|
-
'T' +
|
|
783
|
-
pad(hour) +
|
|
784
|
-
':' +
|
|
785
|
-
pad(min) +
|
|
786
|
-
':' +
|
|
787
|
-
pad(sec) +
|
|
788
|
-
msPart +
|
|
789
|
-
sign +
|
|
790
|
-
pad(oh) +
|
|
791
|
-
':' +
|
|
792
|
-
pad(om)
|
|
793
|
-
);
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
function utcIsoDateTimeStringFromEpochSeconds(sec) {
|
|
797
|
-
const ms = sec * 1000;
|
|
798
|
-
const d = new Date(ms);
|
|
799
|
-
function pad(n, w = 2) {
|
|
800
|
-
return String(n).padStart(w, '0');
|
|
801
|
-
}
|
|
802
|
-
const year = d.getUTCFullYear();
|
|
803
|
-
const month = d.getUTCMonth() + 1;
|
|
804
|
-
const day = d.getUTCDate();
|
|
805
|
-
const hour = d.getUTCHours();
|
|
806
|
-
const min = d.getUTCMinutes();
|
|
807
|
-
const s2 = d.getUTCSeconds();
|
|
808
|
-
const ms2 = d.getUTCMilliseconds();
|
|
809
|
-
const msPart = ms2 ? '.' + String(ms2).padStart(3, '0') : '';
|
|
810
|
-
return (
|
|
811
|
-
pad(year, 4) +
|
|
812
|
-
'-' +
|
|
813
|
-
pad(month) +
|
|
814
|
-
'-' +
|
|
815
|
-
pad(day) +
|
|
816
|
-
'T' +
|
|
817
|
-
pad(hour) +
|
|
818
|
-
':' +
|
|
819
|
-
pad(min) +
|
|
820
|
-
':' +
|
|
821
|
-
pad(s2) +
|
|
822
|
-
msPart +
|
|
823
|
-
'+00:00'
|
|
824
|
-
);
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
function getNowLex() {
|
|
828
|
-
if (fixedNowLex) return fixedNowLex;
|
|
829
|
-
if (runNowLex) return runNowLex;
|
|
830
|
-
runNowLex = localIsoDateTimeString(new Date());
|
|
831
|
-
return runNowLex;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
// Deterministic pseudo-UUID from a string key (for log:skolem).
|
|
835
|
-
// Not cryptographically strong, but stable and platform-independent.
|
|
836
|
-
function deterministicSkolemIdFromKey(key) {
|
|
837
|
-
// Four 32-bit FNV-1a style accumulators with slight variation
|
|
838
|
-
let h1 = 0x811c9dc5;
|
|
839
|
-
let h2 = 0x811c9dc5;
|
|
840
|
-
let h3 = 0x811c9dc5;
|
|
841
|
-
let h4 = 0x811c9dc5;
|
|
842
|
-
|
|
843
|
-
for (let i = 0; i < key.length; i++) {
|
|
844
|
-
const c = key.charCodeAt(i);
|
|
845
|
-
|
|
846
|
-
h1 ^= c;
|
|
847
|
-
h1 = (h1 * 0x01000193) >>> 0;
|
|
848
|
-
|
|
849
|
-
h2 ^= c + 1;
|
|
850
|
-
h2 = (h2 * 0x01000193) >>> 0;
|
|
851
|
-
|
|
852
|
-
h3 ^= c + 2;
|
|
853
|
-
h3 = (h3 * 0x01000193) >>> 0;
|
|
854
|
-
|
|
855
|
-
h4 ^= c + 3;
|
|
856
|
-
h4 = (h4 * 0x01000193) >>> 0;
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
const hex = [h1, h2, h3, h4].map((h) => h.toString(16).padStart(8, '0')).join(''); // 32 hex chars
|
|
860
|
-
|
|
861
|
-
// Format like a UUID: 8-4-4-4-12
|
|
862
|
-
return (
|
|
863
|
-
hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20)
|
|
864
|
-
);
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
let runLocalTimeCache = null;
|
|
868
|
-
|
|
869
733
|
// ===========================================================================
|
|
870
734
|
function skolemizeTermForHeadBlanks(t, headBlankLabels, mapping, skCounter, firingKey, globalMap) {
|
|
871
735
|
if (t instanceof Blank) {
|
|
@@ -3157,7 +3021,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
3157
3021
|
const secs = parseNumOrDuration(b0);
|
|
3158
3022
|
if (secs !== null) {
|
|
3159
3023
|
const outSecs = aDt.getTime() / 1000.0 - secs;
|
|
3160
|
-
const lex = utcIsoDateTimeStringFromEpochSeconds(outSecs);
|
|
3024
|
+
const lex = time.utcIsoDateTimeStringFromEpochSeconds(outSecs);
|
|
3161
3025
|
const lit = internLiteral(`"${lex}"^^<${XSD_NS}dateTime>`);
|
|
3162
3026
|
if (g.o instanceof Var) {
|
|
3163
3027
|
const s2 = { ...subst };
|
|
@@ -3693,7 +3557,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
3693
3557
|
// time:localTime
|
|
3694
3558
|
// "" time:localTime ?D. binds ?D to “now” as xsd:dateTime.
|
|
3695
3559
|
if (pv === TIME_NS + 'localTime') {
|
|
3696
|
-
const now = getNowLex();
|
|
3560
|
+
const now = time.getNowLex();
|
|
3697
3561
|
|
|
3698
3562
|
if (g.o instanceof Var) {
|
|
3699
3563
|
const s2 = { ...subst };
|
|
@@ -4599,12 +4463,12 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
4599
4463
|
// Side-effecting debug output (to stderr). Always succeeds once.
|
|
4600
4464
|
// to mimic EYE's fm(...) formatting branch.
|
|
4601
4465
|
if (pv === LOG_NS + 'trace') {
|
|
4602
|
-
const pref =
|
|
4466
|
+
const pref = trace.getTracePrefixes() || PrefixEnv.newDefault();
|
|
4603
4467
|
|
|
4604
4468
|
const xStr = termToN3(g.s, pref);
|
|
4605
4469
|
const yStr = termToN3(g.o, pref);
|
|
4606
4470
|
|
|
4607
|
-
|
|
4471
|
+
trace.writeTraceLine(`${xStr} TRACE ${yStr}`);
|
|
4608
4472
|
return [{ ...subst }];
|
|
4609
4473
|
}
|
|
4610
4474
|
|
|
@@ -5930,7 +5794,7 @@ function reasonStream(n3Text, opts = {}) {
|
|
|
5930
5794
|
let prefixes, triples, frules, brules;
|
|
5931
5795
|
[prefixes, triples, frules, brules] = parser.parseDocument();
|
|
5932
5796
|
// Make the parsed prefixes available to log:trace output
|
|
5933
|
-
|
|
5797
|
+
trace.setTracePrefixes(prefixes);
|
|
5934
5798
|
|
|
5935
5799
|
materializeRdfLists(triples, frules, brules);
|
|
5936
5800
|
|
|
@@ -5995,11 +5859,11 @@ function setSuperRestrictedMode(v) {
|
|
|
5995
5859
|
}
|
|
5996
5860
|
|
|
5997
5861
|
function getTracePrefixes() {
|
|
5998
|
-
return
|
|
5862
|
+
return trace.getTracePrefixes();
|
|
5999
5863
|
}
|
|
6000
5864
|
|
|
6001
5865
|
function setTracePrefixes(v) {
|
|
6002
|
-
|
|
5866
|
+
trace.setTracePrefixes(v);
|
|
6003
5867
|
}
|
|
6004
5868
|
|
|
6005
5869
|
module.exports = {
|
|
@@ -7883,6 +7747,202 @@ module.exports = {
|
|
|
7883
7747
|
reorderPremiseForConstraints,
|
|
7884
7748
|
};
|
|
7885
7749
|
|
|
7750
|
+
};
|
|
7751
|
+
__modules["lib/skolem.js"] = function(require, module, exports){
|
|
7752
|
+
'use strict';
|
|
7753
|
+
|
|
7754
|
+
// Deterministic pseudo-UUID from a string key (for log:skolem).
|
|
7755
|
+
// Not cryptographically strong, but stable and platform-independent.
|
|
7756
|
+
|
|
7757
|
+
function deterministicSkolemIdFromKey(key) {
|
|
7758
|
+
// Four 32-bit FNV-1a style accumulators with slight variation
|
|
7759
|
+
let h1 = 0x811c9dc5;
|
|
7760
|
+
let h2 = 0x811c9dc5;
|
|
7761
|
+
let h3 = 0x811c9dc5;
|
|
7762
|
+
let h4 = 0x811c9dc5;
|
|
7763
|
+
|
|
7764
|
+
for (let i = 0; i < key.length; i++) {
|
|
7765
|
+
const c = key.charCodeAt(i);
|
|
7766
|
+
|
|
7767
|
+
h1 ^= c;
|
|
7768
|
+
h1 = (h1 * 0x01000193) >>> 0;
|
|
7769
|
+
|
|
7770
|
+
h2 ^= c + 1;
|
|
7771
|
+
h2 = (h2 * 0x01000193) >>> 0;
|
|
7772
|
+
|
|
7773
|
+
h3 ^= c + 2;
|
|
7774
|
+
h3 = (h3 * 0x01000193) >>> 0;
|
|
7775
|
+
|
|
7776
|
+
h4 ^= c + 3;
|
|
7777
|
+
h4 = (h4 * 0x01000193) >>> 0;
|
|
7778
|
+
}
|
|
7779
|
+
|
|
7780
|
+
const hex = [h1, h2, h3, h4]
|
|
7781
|
+
.map((h) => h.toString(16).padStart(8, '0'))
|
|
7782
|
+
.join(''); // 32 hex chars
|
|
7783
|
+
|
|
7784
|
+
// Format like a UUID: 8-4-4-4-12
|
|
7785
|
+
return (
|
|
7786
|
+
hex.slice(0, 8) +
|
|
7787
|
+
'-' +
|
|
7788
|
+
hex.slice(8, 12) +
|
|
7789
|
+
'-' +
|
|
7790
|
+
hex.slice(12, 16) +
|
|
7791
|
+
'-' +
|
|
7792
|
+
hex.slice(16, 20) +
|
|
7793
|
+
'-' +
|
|
7794
|
+
hex.slice(20)
|
|
7795
|
+
);
|
|
7796
|
+
}
|
|
7797
|
+
|
|
7798
|
+
module.exports = {
|
|
7799
|
+
deterministicSkolemIdFromKey,
|
|
7800
|
+
};
|
|
7801
|
+
|
|
7802
|
+
};
|
|
7803
|
+
__modules["lib/time.js"] = function(require, module, exports){
|
|
7804
|
+
'use strict';
|
|
7805
|
+
|
|
7806
|
+
// Deterministic time support used by time:* builtins.
|
|
7807
|
+
// This logic is kept in its own module so the core engine stays focused.
|
|
7808
|
+
|
|
7809
|
+
// If set, overrides time:localTime across the whole run.
|
|
7810
|
+
// Store as xsd:dateTime *lexical* string (no quotes).
|
|
7811
|
+
let fixedNowLex = null;
|
|
7812
|
+
|
|
7813
|
+
// If not fixed, memoize one value per run to avoid re-firing rules.
|
|
7814
|
+
let runNowLex = null;
|
|
7815
|
+
|
|
7816
|
+
function localIsoDateTimeString(d) {
|
|
7817
|
+
function pad(n, width = 2) {
|
|
7818
|
+
return String(n).padStart(width, '0');
|
|
7819
|
+
}
|
|
7820
|
+
const year = d.getFullYear();
|
|
7821
|
+
const month = d.getMonth() + 1;
|
|
7822
|
+
const day = d.getDate();
|
|
7823
|
+
const hour = d.getHours();
|
|
7824
|
+
const min = d.getMinutes();
|
|
7825
|
+
const sec = d.getSeconds();
|
|
7826
|
+
const ms = d.getMilliseconds();
|
|
7827
|
+
const offsetMin = -d.getTimezoneOffset(); // minutes east of UTC
|
|
7828
|
+
const sign = offsetMin >= 0 ? '+' : '-';
|
|
7829
|
+
const abs = Math.abs(offsetMin);
|
|
7830
|
+
const oh = Math.floor(abs / 60);
|
|
7831
|
+
const om = abs % 60;
|
|
7832
|
+
const msPart = ms ? '.' + String(ms).padStart(3, '0') : '';
|
|
7833
|
+
return (
|
|
7834
|
+
pad(year, 4) +
|
|
7835
|
+
'-' +
|
|
7836
|
+
pad(month) +
|
|
7837
|
+
'-' +
|
|
7838
|
+
pad(day) +
|
|
7839
|
+
'T' +
|
|
7840
|
+
pad(hour) +
|
|
7841
|
+
':' +
|
|
7842
|
+
pad(min) +
|
|
7843
|
+
':' +
|
|
7844
|
+
pad(sec) +
|
|
7845
|
+
msPart +
|
|
7846
|
+
sign +
|
|
7847
|
+
pad(oh) +
|
|
7848
|
+
':' +
|
|
7849
|
+
pad(om)
|
|
7850
|
+
);
|
|
7851
|
+
}
|
|
7852
|
+
|
|
7853
|
+
function utcIsoDateTimeStringFromEpochSeconds(sec) {
|
|
7854
|
+
const ms = sec * 1000;
|
|
7855
|
+
const d = new Date(ms);
|
|
7856
|
+
function pad(n, w = 2) {
|
|
7857
|
+
return String(n).padStart(w, '0');
|
|
7858
|
+
}
|
|
7859
|
+
const year = d.getUTCFullYear();
|
|
7860
|
+
const month = d.getUTCMonth() + 1;
|
|
7861
|
+
const day = d.getUTCDate();
|
|
7862
|
+
const hour = d.getUTCHours();
|
|
7863
|
+
const min = d.getUTCMinutes();
|
|
7864
|
+
const s2 = d.getUTCSeconds();
|
|
7865
|
+
const ms2 = d.getUTCMilliseconds();
|
|
7866
|
+
const msPart = ms2 ? '.' + String(ms2).padStart(3, '0') : '';
|
|
7867
|
+
return (
|
|
7868
|
+
pad(year, 4) +
|
|
7869
|
+
'-' +
|
|
7870
|
+
pad(month) +
|
|
7871
|
+
'-' +
|
|
7872
|
+
pad(day) +
|
|
7873
|
+
'T' +
|
|
7874
|
+
pad(hour) +
|
|
7875
|
+
':' +
|
|
7876
|
+
pad(min) +
|
|
7877
|
+
':' +
|
|
7878
|
+
pad(s2) +
|
|
7879
|
+
msPart +
|
|
7880
|
+
'+00:00'
|
|
7881
|
+
);
|
|
7882
|
+
}
|
|
7883
|
+
|
|
7884
|
+
function getNowLex() {
|
|
7885
|
+
if (fixedNowLex) return fixedNowLex;
|
|
7886
|
+
if (runNowLex) return runNowLex;
|
|
7887
|
+
runNowLex = localIsoDateTimeString(new Date());
|
|
7888
|
+
return runNowLex;
|
|
7889
|
+
}
|
|
7890
|
+
|
|
7891
|
+
function setFixedNowLex(v) {
|
|
7892
|
+
fixedNowLex = v ? String(v) : null;
|
|
7893
|
+
// When fixed changes, clear memoized run value.
|
|
7894
|
+
runNowLex = null;
|
|
7895
|
+
}
|
|
7896
|
+
|
|
7897
|
+
function resetRunNowLex() {
|
|
7898
|
+
runNowLex = null;
|
|
7899
|
+
}
|
|
7900
|
+
|
|
7901
|
+
module.exports = {
|
|
7902
|
+
getNowLex,
|
|
7903
|
+
setFixedNowLex,
|
|
7904
|
+
resetRunNowLex,
|
|
7905
|
+
utcIsoDateTimeStringFromEpochSeconds,
|
|
7906
|
+
};
|
|
7907
|
+
|
|
7908
|
+
};
|
|
7909
|
+
__modules["lib/trace.js"] = function(require, module, exports){
|
|
7910
|
+
/* eslint-disable no-console */
|
|
7911
|
+
'use strict';
|
|
7912
|
+
|
|
7913
|
+
// Small module for debug/trace printing (log:trace) and its run-level state.
|
|
7914
|
+
// Kept separate from engine.js so browser demo + CLI can share behavior.
|
|
7915
|
+
|
|
7916
|
+
let tracePrefixes = null;
|
|
7917
|
+
|
|
7918
|
+
function getTracePrefixes() {
|
|
7919
|
+
return tracePrefixes;
|
|
7920
|
+
}
|
|
7921
|
+
|
|
7922
|
+
function setTracePrefixes(v) {
|
|
7923
|
+
tracePrefixes = v;
|
|
7924
|
+
}
|
|
7925
|
+
|
|
7926
|
+
function writeTraceLine(line) {
|
|
7927
|
+
// Prefer stderr in Node, fall back to console.error elsewhere.
|
|
7928
|
+
try {
|
|
7929
|
+
// eslint-disable-next-line no-undef
|
|
7930
|
+
if (typeof process !== 'undefined' && process.stderr && typeof process.stderr.write === 'function') {
|
|
7931
|
+
process.stderr.write(String(line) + '\n');
|
|
7932
|
+
return;
|
|
7933
|
+
}
|
|
7934
|
+
} catch (_) {}
|
|
7935
|
+
try {
|
|
7936
|
+
if (typeof console !== 'undefined' && typeof console.error === 'function') console.error(line);
|
|
7937
|
+
} catch (_) {}
|
|
7938
|
+
}
|
|
7939
|
+
|
|
7940
|
+
module.exports = {
|
|
7941
|
+
getTracePrefixes,
|
|
7942
|
+
setTracePrefixes,
|
|
7943
|
+
writeTraceLine,
|
|
7944
|
+
};
|
|
7945
|
+
|
|
7886
7946
|
};
|
|
7887
7947
|
|
|
7888
7948
|
function __normPath(p){
|
package/lib/engine.js
CHANGED
|
@@ -39,6 +39,10 @@ const { liftBlankRuleVars, reorderPremiseForConstraints, isConstraintBuiltin } =
|
|
|
39
39
|
|
|
40
40
|
const { termToN3, tripleToN3 } = require('./printing');
|
|
41
41
|
|
|
42
|
+
const trace = require('./trace');
|
|
43
|
+
const time = require('./time');
|
|
44
|
+
const { deterministicSkolemIdFromKey } = require('./skolem');
|
|
45
|
+
|
|
42
46
|
let version = 'dev';
|
|
43
47
|
try {
|
|
44
48
|
// Node: keep package.json version if available
|
|
@@ -408,146 +412,6 @@ let proofCommentsEnabled = false;
|
|
|
408
412
|
// Super restricted mode: disable *all* builtins except => / <= (log:implies / log:impliedBy)
|
|
409
413
|
let superRestrictedMode = false;
|
|
410
414
|
|
|
411
|
-
// Debug/trace printing support (log:trace)
|
|
412
|
-
let __tracePrefixes = null;
|
|
413
|
-
|
|
414
|
-
function __traceWriteLine(line) {
|
|
415
|
-
// Prefer stderr in Node, fall back to console.error elsewhere.
|
|
416
|
-
try {
|
|
417
|
-
if (__IS_NODE && typeof process !== 'undefined' && process.stderr && typeof process.stderr.write === 'function') {
|
|
418
|
-
process.stderr.write(String(line) + '\n');
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
} catch (_) {}
|
|
422
|
-
try {
|
|
423
|
-
if (typeof console !== 'undefined' && typeof console.error === 'function') console.error(line);
|
|
424
|
-
} catch (_) {}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// ----------------------------------------------------------------------------
|
|
428
|
-
// Deterministic time support
|
|
429
|
-
// ----------------------------------------------------------------------------
|
|
430
|
-
// If set, overrides time:localTime across the whole run (and across runs if you
|
|
431
|
-
// pass the same value). Store as xsd:dateTime *lexical* string (no quotes).
|
|
432
|
-
let fixedNowLex = null;
|
|
433
|
-
|
|
434
|
-
// If not fixed, we still memoize one value per run to avoid re-firing rules.
|
|
435
|
-
let runNowLex = null;
|
|
436
|
-
|
|
437
|
-
// ===========================================================================
|
|
438
|
-
// Run-level time helpers
|
|
439
|
-
// ===========================================================================
|
|
440
|
-
|
|
441
|
-
function localIsoDateTimeString(d) {
|
|
442
|
-
function pad(n, width = 2) {
|
|
443
|
-
return String(n).padStart(width, '0');
|
|
444
|
-
}
|
|
445
|
-
const year = d.getFullYear();
|
|
446
|
-
const month = d.getMonth() + 1;
|
|
447
|
-
const day = d.getDate();
|
|
448
|
-
const hour = d.getHours();
|
|
449
|
-
const min = d.getMinutes();
|
|
450
|
-
const sec = d.getSeconds();
|
|
451
|
-
const ms = d.getMilliseconds();
|
|
452
|
-
const offsetMin = -d.getTimezoneOffset(); // minutes east of UTC
|
|
453
|
-
const sign = offsetMin >= 0 ? '+' : '-';
|
|
454
|
-
const abs = Math.abs(offsetMin);
|
|
455
|
-
const oh = Math.floor(abs / 60);
|
|
456
|
-
const om = abs % 60;
|
|
457
|
-
const msPart = ms ? '.' + String(ms).padStart(3, '0') : '';
|
|
458
|
-
return (
|
|
459
|
-
pad(year, 4) +
|
|
460
|
-
'-' +
|
|
461
|
-
pad(month) +
|
|
462
|
-
'-' +
|
|
463
|
-
pad(day) +
|
|
464
|
-
'T' +
|
|
465
|
-
pad(hour) +
|
|
466
|
-
':' +
|
|
467
|
-
pad(min) +
|
|
468
|
-
':' +
|
|
469
|
-
pad(sec) +
|
|
470
|
-
msPart +
|
|
471
|
-
sign +
|
|
472
|
-
pad(oh) +
|
|
473
|
-
':' +
|
|
474
|
-
pad(om)
|
|
475
|
-
);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
function utcIsoDateTimeStringFromEpochSeconds(sec) {
|
|
479
|
-
const ms = sec * 1000;
|
|
480
|
-
const d = new Date(ms);
|
|
481
|
-
function pad(n, w = 2) {
|
|
482
|
-
return String(n).padStart(w, '0');
|
|
483
|
-
}
|
|
484
|
-
const year = d.getUTCFullYear();
|
|
485
|
-
const month = d.getUTCMonth() + 1;
|
|
486
|
-
const day = d.getUTCDate();
|
|
487
|
-
const hour = d.getUTCHours();
|
|
488
|
-
const min = d.getUTCMinutes();
|
|
489
|
-
const s2 = d.getUTCSeconds();
|
|
490
|
-
const ms2 = d.getUTCMilliseconds();
|
|
491
|
-
const msPart = ms2 ? '.' + String(ms2).padStart(3, '0') : '';
|
|
492
|
-
return (
|
|
493
|
-
pad(year, 4) +
|
|
494
|
-
'-' +
|
|
495
|
-
pad(month) +
|
|
496
|
-
'-' +
|
|
497
|
-
pad(day) +
|
|
498
|
-
'T' +
|
|
499
|
-
pad(hour) +
|
|
500
|
-
':' +
|
|
501
|
-
pad(min) +
|
|
502
|
-
':' +
|
|
503
|
-
pad(s2) +
|
|
504
|
-
msPart +
|
|
505
|
-
'+00:00'
|
|
506
|
-
);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
function getNowLex() {
|
|
510
|
-
if (fixedNowLex) return fixedNowLex;
|
|
511
|
-
if (runNowLex) return runNowLex;
|
|
512
|
-
runNowLex = localIsoDateTimeString(new Date());
|
|
513
|
-
return runNowLex;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// Deterministic pseudo-UUID from a string key (for log:skolem).
|
|
517
|
-
// Not cryptographically strong, but stable and platform-independent.
|
|
518
|
-
function deterministicSkolemIdFromKey(key) {
|
|
519
|
-
// Four 32-bit FNV-1a style accumulators with slight variation
|
|
520
|
-
let h1 = 0x811c9dc5;
|
|
521
|
-
let h2 = 0x811c9dc5;
|
|
522
|
-
let h3 = 0x811c9dc5;
|
|
523
|
-
let h4 = 0x811c9dc5;
|
|
524
|
-
|
|
525
|
-
for (let i = 0; i < key.length; i++) {
|
|
526
|
-
const c = key.charCodeAt(i);
|
|
527
|
-
|
|
528
|
-
h1 ^= c;
|
|
529
|
-
h1 = (h1 * 0x01000193) >>> 0;
|
|
530
|
-
|
|
531
|
-
h2 ^= c + 1;
|
|
532
|
-
h2 = (h2 * 0x01000193) >>> 0;
|
|
533
|
-
|
|
534
|
-
h3 ^= c + 2;
|
|
535
|
-
h3 = (h3 * 0x01000193) >>> 0;
|
|
536
|
-
|
|
537
|
-
h4 ^= c + 3;
|
|
538
|
-
h4 = (h4 * 0x01000193) >>> 0;
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
const hex = [h1, h2, h3, h4].map((h) => h.toString(16).padStart(8, '0')).join(''); // 32 hex chars
|
|
542
|
-
|
|
543
|
-
// Format like a UUID: 8-4-4-4-12
|
|
544
|
-
return (
|
|
545
|
-
hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20)
|
|
546
|
-
);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
let runLocalTimeCache = null;
|
|
550
|
-
|
|
551
415
|
// ===========================================================================
|
|
552
416
|
function skolemizeTermForHeadBlanks(t, headBlankLabels, mapping, skCounter, firingKey, globalMap) {
|
|
553
417
|
if (t instanceof Blank) {
|
|
@@ -2839,7 +2703,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
2839
2703
|
const secs = parseNumOrDuration(b0);
|
|
2840
2704
|
if (secs !== null) {
|
|
2841
2705
|
const outSecs = aDt.getTime() / 1000.0 - secs;
|
|
2842
|
-
const lex = utcIsoDateTimeStringFromEpochSeconds(outSecs);
|
|
2706
|
+
const lex = time.utcIsoDateTimeStringFromEpochSeconds(outSecs);
|
|
2843
2707
|
const lit = internLiteral(`"${lex}"^^<${XSD_NS}dateTime>`);
|
|
2844
2708
|
if (g.o instanceof Var) {
|
|
2845
2709
|
const s2 = { ...subst };
|
|
@@ -3375,7 +3239,7 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
3375
3239
|
// time:localTime
|
|
3376
3240
|
// "" time:localTime ?D. binds ?D to “now” as xsd:dateTime.
|
|
3377
3241
|
if (pv === TIME_NS + 'localTime') {
|
|
3378
|
-
const now = getNowLex();
|
|
3242
|
+
const now = time.getNowLex();
|
|
3379
3243
|
|
|
3380
3244
|
if (g.o instanceof Var) {
|
|
3381
3245
|
const s2 = { ...subst };
|
|
@@ -4281,12 +4145,12 @@ function evalBuiltin(goal, subst, facts, backRules, depth, varGen, maxResults) {
|
|
|
4281
4145
|
// Side-effecting debug output (to stderr). Always succeeds once.
|
|
4282
4146
|
// to mimic EYE's fm(...) formatting branch.
|
|
4283
4147
|
if (pv === LOG_NS + 'trace') {
|
|
4284
|
-
const pref =
|
|
4148
|
+
const pref = trace.getTracePrefixes() || PrefixEnv.newDefault();
|
|
4285
4149
|
|
|
4286
4150
|
const xStr = termToN3(g.s, pref);
|
|
4287
4151
|
const yStr = termToN3(g.o, pref);
|
|
4288
4152
|
|
|
4289
|
-
|
|
4153
|
+
trace.writeTraceLine(`${xStr} TRACE ${yStr}`);
|
|
4290
4154
|
return [{ ...subst }];
|
|
4291
4155
|
}
|
|
4292
4156
|
|
|
@@ -5612,7 +5476,7 @@ function reasonStream(n3Text, opts = {}) {
|
|
|
5612
5476
|
let prefixes, triples, frules, brules;
|
|
5613
5477
|
[prefixes, triples, frules, brules] = parser.parseDocument();
|
|
5614
5478
|
// Make the parsed prefixes available to log:trace output
|
|
5615
|
-
|
|
5479
|
+
trace.setTracePrefixes(prefixes);
|
|
5616
5480
|
|
|
5617
5481
|
materializeRdfLists(triples, frules, brules);
|
|
5618
5482
|
|
|
@@ -5677,11 +5541,11 @@ function setSuperRestrictedMode(v) {
|
|
|
5677
5541
|
}
|
|
5678
5542
|
|
|
5679
5543
|
function getTracePrefixes() {
|
|
5680
|
-
return
|
|
5544
|
+
return trace.getTracePrefixes();
|
|
5681
5545
|
}
|
|
5682
5546
|
|
|
5683
5547
|
function setTracePrefixes(v) {
|
|
5684
|
-
|
|
5548
|
+
trace.setTracePrefixes(v);
|
|
5685
5549
|
}
|
|
5686
5550
|
|
|
5687
5551
|
module.exports = {
|
package/lib/skolem.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Deterministic pseudo-UUID from a string key (for log:skolem).
|
|
4
|
+
// Not cryptographically strong, but stable and platform-independent.
|
|
5
|
+
|
|
6
|
+
function deterministicSkolemIdFromKey(key) {
|
|
7
|
+
// Four 32-bit FNV-1a style accumulators with slight variation
|
|
8
|
+
let h1 = 0x811c9dc5;
|
|
9
|
+
let h2 = 0x811c9dc5;
|
|
10
|
+
let h3 = 0x811c9dc5;
|
|
11
|
+
let h4 = 0x811c9dc5;
|
|
12
|
+
|
|
13
|
+
for (let i = 0; i < key.length; i++) {
|
|
14
|
+
const c = key.charCodeAt(i);
|
|
15
|
+
|
|
16
|
+
h1 ^= c;
|
|
17
|
+
h1 = (h1 * 0x01000193) >>> 0;
|
|
18
|
+
|
|
19
|
+
h2 ^= c + 1;
|
|
20
|
+
h2 = (h2 * 0x01000193) >>> 0;
|
|
21
|
+
|
|
22
|
+
h3 ^= c + 2;
|
|
23
|
+
h3 = (h3 * 0x01000193) >>> 0;
|
|
24
|
+
|
|
25
|
+
h4 ^= c + 3;
|
|
26
|
+
h4 = (h4 * 0x01000193) >>> 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const hex = [h1, h2, h3, h4]
|
|
30
|
+
.map((h) => h.toString(16).padStart(8, '0'))
|
|
31
|
+
.join(''); // 32 hex chars
|
|
32
|
+
|
|
33
|
+
// Format like a UUID: 8-4-4-4-12
|
|
34
|
+
return (
|
|
35
|
+
hex.slice(0, 8) +
|
|
36
|
+
'-' +
|
|
37
|
+
hex.slice(8, 12) +
|
|
38
|
+
'-' +
|
|
39
|
+
hex.slice(12, 16) +
|
|
40
|
+
'-' +
|
|
41
|
+
hex.slice(16, 20) +
|
|
42
|
+
'-' +
|
|
43
|
+
hex.slice(20)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
deterministicSkolemIdFromKey,
|
|
49
|
+
};
|
package/lib/time.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Deterministic time support used by time:* builtins.
|
|
4
|
+
// This logic is kept in its own module so the core engine stays focused.
|
|
5
|
+
|
|
6
|
+
// If set, overrides time:localTime across the whole run.
|
|
7
|
+
// Store as xsd:dateTime *lexical* string (no quotes).
|
|
8
|
+
let fixedNowLex = null;
|
|
9
|
+
|
|
10
|
+
// If not fixed, memoize one value per run to avoid re-firing rules.
|
|
11
|
+
let runNowLex = null;
|
|
12
|
+
|
|
13
|
+
function localIsoDateTimeString(d) {
|
|
14
|
+
function pad(n, width = 2) {
|
|
15
|
+
return String(n).padStart(width, '0');
|
|
16
|
+
}
|
|
17
|
+
const year = d.getFullYear();
|
|
18
|
+
const month = d.getMonth() + 1;
|
|
19
|
+
const day = d.getDate();
|
|
20
|
+
const hour = d.getHours();
|
|
21
|
+
const min = d.getMinutes();
|
|
22
|
+
const sec = d.getSeconds();
|
|
23
|
+
const ms = d.getMilliseconds();
|
|
24
|
+
const offsetMin = -d.getTimezoneOffset(); // minutes east of UTC
|
|
25
|
+
const sign = offsetMin >= 0 ? '+' : '-';
|
|
26
|
+
const abs = Math.abs(offsetMin);
|
|
27
|
+
const oh = Math.floor(abs / 60);
|
|
28
|
+
const om = abs % 60;
|
|
29
|
+
const msPart = ms ? '.' + String(ms).padStart(3, '0') : '';
|
|
30
|
+
return (
|
|
31
|
+
pad(year, 4) +
|
|
32
|
+
'-' +
|
|
33
|
+
pad(month) +
|
|
34
|
+
'-' +
|
|
35
|
+
pad(day) +
|
|
36
|
+
'T' +
|
|
37
|
+
pad(hour) +
|
|
38
|
+
':' +
|
|
39
|
+
pad(min) +
|
|
40
|
+
':' +
|
|
41
|
+
pad(sec) +
|
|
42
|
+
msPart +
|
|
43
|
+
sign +
|
|
44
|
+
pad(oh) +
|
|
45
|
+
':' +
|
|
46
|
+
pad(om)
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function utcIsoDateTimeStringFromEpochSeconds(sec) {
|
|
51
|
+
const ms = sec * 1000;
|
|
52
|
+
const d = new Date(ms);
|
|
53
|
+
function pad(n, w = 2) {
|
|
54
|
+
return String(n).padStart(w, '0');
|
|
55
|
+
}
|
|
56
|
+
const year = d.getUTCFullYear();
|
|
57
|
+
const month = d.getUTCMonth() + 1;
|
|
58
|
+
const day = d.getUTCDate();
|
|
59
|
+
const hour = d.getUTCHours();
|
|
60
|
+
const min = d.getUTCMinutes();
|
|
61
|
+
const s2 = d.getUTCSeconds();
|
|
62
|
+
const ms2 = d.getUTCMilliseconds();
|
|
63
|
+
const msPart = ms2 ? '.' + String(ms2).padStart(3, '0') : '';
|
|
64
|
+
return (
|
|
65
|
+
pad(year, 4) +
|
|
66
|
+
'-' +
|
|
67
|
+
pad(month) +
|
|
68
|
+
'-' +
|
|
69
|
+
pad(day) +
|
|
70
|
+
'T' +
|
|
71
|
+
pad(hour) +
|
|
72
|
+
':' +
|
|
73
|
+
pad(min) +
|
|
74
|
+
':' +
|
|
75
|
+
pad(s2) +
|
|
76
|
+
msPart +
|
|
77
|
+
'+00:00'
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getNowLex() {
|
|
82
|
+
if (fixedNowLex) return fixedNowLex;
|
|
83
|
+
if (runNowLex) return runNowLex;
|
|
84
|
+
runNowLex = localIsoDateTimeString(new Date());
|
|
85
|
+
return runNowLex;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function setFixedNowLex(v) {
|
|
89
|
+
fixedNowLex = v ? String(v) : null;
|
|
90
|
+
// When fixed changes, clear memoized run value.
|
|
91
|
+
runNowLex = null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function resetRunNowLex() {
|
|
95
|
+
runNowLex = null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = {
|
|
99
|
+
getNowLex,
|
|
100
|
+
setFixedNowLex,
|
|
101
|
+
resetRunNowLex,
|
|
102
|
+
utcIsoDateTimeStringFromEpochSeconds,
|
|
103
|
+
};
|
package/lib/trace.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Small module for debug/trace printing (log:trace) and its run-level state.
|
|
5
|
+
// Kept separate from engine.js so browser demo + CLI can share behavior.
|
|
6
|
+
|
|
7
|
+
let tracePrefixes = null;
|
|
8
|
+
|
|
9
|
+
function getTracePrefixes() {
|
|
10
|
+
return tracePrefixes;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function setTracePrefixes(v) {
|
|
14
|
+
tracePrefixes = v;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function writeTraceLine(line) {
|
|
18
|
+
// Prefer stderr in Node, fall back to console.error elsewhere.
|
|
19
|
+
try {
|
|
20
|
+
// eslint-disable-next-line no-undef
|
|
21
|
+
if (typeof process !== 'undefined' && process.stderr && typeof process.stderr.write === 'function') {
|
|
22
|
+
process.stderr.write(String(line) + '\n');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
} catch (_) {}
|
|
26
|
+
try {
|
|
27
|
+
if (typeof console !== 'undefined' && typeof console.error === 'function') console.error(line);
|
|
28
|
+
} catch (_) {}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = {
|
|
32
|
+
getTracePrefixes,
|
|
33
|
+
setTracePrefixes,
|
|
34
|
+
writeTraceLine,
|
|
35
|
+
};
|