eyeling 1.25.2 → 1.25.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.
@@ -4965,12 +4965,14 @@ function main() {
4965
4965
  outTriples = res.queryTriples;
4966
4966
  outDerived = res.queryDerived;
4967
4967
  } else {
4968
+ const skipDerivedCollection = mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled();
4968
4969
  derived = engine.forwardChain(facts, frules, brules, null, {
4969
4970
  captureExplanations: engine.getProofCommentsEnabled(),
4971
+ collectDerived: !skipDerivedCollection,
4970
4972
  prefixes,
4971
4973
  });
4972
4974
  outDerived = derived;
4973
- outTriples = derived.map((df) => df.fact);
4975
+ outTriples = skipDerivedCollection ? [] : derived.map((df) => df.fact);
4974
4976
  }
4975
4977
 
4976
4978
  const renderedOutputTriples = hasQueries ? outTriples : facts;
@@ -8388,6 +8390,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
8388
8390
  __attachGoalTable(backRules, goalTable);
8389
8391
 
8390
8392
  const captureExplanations = !(opts && opts.captureExplanations === false);
8393
+ const collectDerived = !(opts && opts.collectDerived === false);
8394
+ const hasDerivedCallback = typeof onDerived === 'function';
8391
8395
  const derivedForward = [];
8392
8396
  const varGen = [0];
8393
8397
  const skCounter = [0];
@@ -8566,8 +8570,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
8566
8570
  if (!hasFactIndexed(facts, instantiated)) {
8567
8571
  pushFactIndexed(facts, instantiated);
8568
8572
  const df = makeDerivedRecord(instantiated, r, getInstantiatedPremises(), s, captureExplanations);
8569
- derivedForward.push(df);
8570
- if (typeof onDerived === 'function') onDerived(df);
8573
+ if (collectDerived) derivedForward.push(df);
8574
+ if (hasDerivedCallback) onDerived(df);
8571
8575
  changedHere = true;
8572
8576
  }
8573
8577
 
@@ -8630,8 +8634,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
8630
8634
 
8631
8635
  pushFactIndexed(facts, inst);
8632
8636
  const df = makeDerivedRecord(inst, r, getInstantiatedPremises(), s, captureExplanations);
8633
- derivedForward.push(df);
8634
- if (typeof onDerived === 'function') onDerived(df);
8637
+ if (collectDerived) derivedForward.push(df);
8638
+ if (hasDerivedCallback) onDerived(df);
8635
8639
 
8636
8640
  changedHere = true;
8637
8641
  }
@@ -10727,7 +10731,9 @@ function lex(inputText, opts = {}) {
10727
10731
  // Avoid copying large ASCII/BMP inputs into an Array. Array.from() is
10728
10732
  // only needed when the text contains surrogate pairs and we want the old
10729
10733
  // code-point iteration behavior for non-BMP characters.
10730
- const chars = /[\uD800-\uDFFF]/.test(inputText) ? Array.from(inputText) : inputText;
10734
+ const hasSurrogates = /[\uD800-\uDFFF]/.test(inputText);
10735
+ const inputMayContainInvalidStringChar = hasSurrogates || /[\u0000\uFFFE\uFFFF]/.test(inputText);
10736
+ const chars = hasSurrogates ? Array.from(inputText) : inputText;
10731
10737
  const n = chars.length;
10732
10738
  let i = 0;
10733
10739
  const tokens = [];
@@ -10762,14 +10768,47 @@ function lex(inputText, opts = {}) {
10762
10768
  // Hard stops: delimiters cannot appear unescaped inside PNAME tokens.
10763
10769
  if (cc === '{' || cc === '}' || cc === '(' || cc === ')' || cc === '[' || cc === ']' || cc === ';' || cc === ',') break;
10764
10770
 
10765
- // Dot is allowed inside PN_LOCAL, but not at the end.
10766
- if (cc === '.') {
10767
- if (!canContinueAfterDot(peek(1))) break;
10768
- if (out !== null) out.push('.');
10771
+ const code = cc.charCodeAt(0);
10772
+
10773
+ // Common ASCII QName/identifier characters. Keep this branch inline so
10774
+ // ordinary N3 files do not call through the full Unicode PN_CHARS predicate
10775
+ // for every character.
10776
+ if (
10777
+ code === 58 || // ':'
10778
+ code === 95 || // '_'
10779
+ code === 45 || // '-'
10780
+ (code >= 48 && code <= 57) ||
10781
+ (code >= 65 && code <= 90) ||
10782
+ (code >= 97 && code <= 122)
10783
+ ) {
10784
+ if (out !== null) out.push(cc);
10769
10785
  i++;
10770
10786
  continue;
10771
10787
  }
10772
10788
 
10789
+ // Dot is allowed inside PN_LOCAL, but not at the end.
10790
+ if (cc === '.') {
10791
+ const next = peek(1);
10792
+ if (next === null) break;
10793
+ const ncode = next.charCodeAt(0);
10794
+ if (
10795
+ next === '%' ||
10796
+ next === '\\' ||
10797
+ ncode === 58 ||
10798
+ ncode === 95 ||
10799
+ ncode === 45 ||
10800
+ (ncode >= 48 && ncode <= 57) ||
10801
+ (ncode >= 65 && ncode <= 90) ||
10802
+ (ncode >= 97 && ncode <= 122) ||
10803
+ isIdentChar(next)
10804
+ ) {
10805
+ if (out !== null) out.push('.');
10806
+ i++;
10807
+ continue;
10808
+ }
10809
+ break;
10810
+ }
10811
+
10773
10812
  // Percent escape: %HH
10774
10813
  if (cc === '%') {
10775
10814
  const h1 = peek(1);
@@ -11017,7 +11056,7 @@ function lex(inputText, opts = {}) {
11017
11056
  }
11018
11057
  const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
11019
11058
  const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
11020
- assertValidStringLiteralValue(decoded, start);
11059
+ if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
11021
11060
  const s = JSON.stringify(decoded); // canonical short quoted form
11022
11061
  tokens.push(new Token('Literal', s, start));
11023
11062
  continue;
@@ -11107,7 +11146,7 @@ function lex(inputText, opts = {}) {
11107
11146
  }
11108
11147
  const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
11109
11148
  const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
11110
- assertValidStringLiteralValue(decoded, start);
11149
+ if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
11111
11150
  const s = JSON.stringify(decoded); // canonical short quoted form
11112
11151
  tokens.push(new Token('Literal', s, start));
11113
11152
  continue;
@@ -12217,15 +12256,21 @@ class Parser {
12217
12256
 
12218
12257
  while (true) {
12219
12258
  const { verb, invert } = this.parseStatementVerb();
12220
- const objects = this.parseObjectList();
12221
12259
 
12222
- // If VERB or OBJECTS contained paths, their helper triples must come
12223
- // before the triples that consume the path results (Easter depends on this).
12224
- this.flushPendingTriples(out);
12260
+ while (true) {
12261
+ const o = this.parseTerm();
12262
+ const postTriples = this.pendingTriplesAfter;
12263
+ this.pendingTriplesAfter = [];
12264
+
12265
+ // If VERB or OBJECT contained paths, their helper triples must come
12266
+ // before the triple that consumes the path result (Easter depends on this).
12267
+ this.flushPendingTriples(out);
12225
12268
 
12226
- for (const { term: o, postTriples } of objects) {
12227
12269
  out.push(new Triple(invert ? o : subject, verb, invert ? subject : o));
12228
- if (postTriples && postTriples.length) out.push(...postTriples);
12270
+ if (postTriples.length) out.push(...postTriples);
12271
+
12272
+ if (this.peek().typ !== 'Comma') break;
12273
+ this.next();
12229
12274
  }
12230
12275
 
12231
12276
  if (this.peek().typ === 'Semicolon') {
@@ -12239,27 +12284,6 @@ class Parser {
12239
12284
  return out;
12240
12285
  }
12241
12286
 
12242
- parseObjectList() {
12243
- // Capture any trailing property-list triples produced while parsing each
12244
- // object term so we can emit them *after* the triple that references the
12245
- // term. (See pendingTriplesAfter in the constructor.)
12246
-
12247
- const objs = [];
12248
- const readObj = () => {
12249
- const o = this.parseTerm();
12250
- const post = this.pendingTriplesAfter;
12251
- this.pendingTriplesAfter = [];
12252
- objs.push({ term: o, postTriples: post });
12253
- };
12254
-
12255
- readObj();
12256
- while (this.peek().typ === 'Comma') {
12257
- this.next();
12258
- readObj();
12259
- }
12260
- return objs;
12261
- }
12262
-
12263
12287
  makeRule(left, right, isForward) {
12264
12288
  let premiseTerm, conclTerm;
12265
12289
 
package/eyeling.js CHANGED
@@ -4965,12 +4965,14 @@ function main() {
4965
4965
  outTriples = res.queryTriples;
4966
4966
  outDerived = res.queryDerived;
4967
4967
  } else {
4968
+ const skipDerivedCollection = mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled();
4968
4969
  derived = engine.forwardChain(facts, frules, brules, null, {
4969
4970
  captureExplanations: engine.getProofCommentsEnabled(),
4971
+ collectDerived: !skipDerivedCollection,
4970
4972
  prefixes,
4971
4973
  });
4972
4974
  outDerived = derived;
4973
- outTriples = derived.map((df) => df.fact);
4975
+ outTriples = skipDerivedCollection ? [] : derived.map((df) => df.fact);
4974
4976
  }
4975
4977
 
4976
4978
  const renderedOutputTriples = hasQueries ? outTriples : facts;
@@ -8388,6 +8390,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
8388
8390
  __attachGoalTable(backRules, goalTable);
8389
8391
 
8390
8392
  const captureExplanations = !(opts && opts.captureExplanations === false);
8393
+ const collectDerived = !(opts && opts.collectDerived === false);
8394
+ const hasDerivedCallback = typeof onDerived === 'function';
8391
8395
  const derivedForward = [];
8392
8396
  const varGen = [0];
8393
8397
  const skCounter = [0];
@@ -8566,8 +8570,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
8566
8570
  if (!hasFactIndexed(facts, instantiated)) {
8567
8571
  pushFactIndexed(facts, instantiated);
8568
8572
  const df = makeDerivedRecord(instantiated, r, getInstantiatedPremises(), s, captureExplanations);
8569
- derivedForward.push(df);
8570
- if (typeof onDerived === 'function') onDerived(df);
8573
+ if (collectDerived) derivedForward.push(df);
8574
+ if (hasDerivedCallback) onDerived(df);
8571
8575
  changedHere = true;
8572
8576
  }
8573
8577
 
@@ -8630,8 +8634,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
8630
8634
 
8631
8635
  pushFactIndexed(facts, inst);
8632
8636
  const df = makeDerivedRecord(inst, r, getInstantiatedPremises(), s, captureExplanations);
8633
- derivedForward.push(df);
8634
- if (typeof onDerived === 'function') onDerived(df);
8637
+ if (collectDerived) derivedForward.push(df);
8638
+ if (hasDerivedCallback) onDerived(df);
8635
8639
 
8636
8640
  changedHere = true;
8637
8641
  }
@@ -10727,7 +10731,9 @@ function lex(inputText, opts = {}) {
10727
10731
  // Avoid copying large ASCII/BMP inputs into an Array. Array.from() is
10728
10732
  // only needed when the text contains surrogate pairs and we want the old
10729
10733
  // code-point iteration behavior for non-BMP characters.
10730
- const chars = /[\uD800-\uDFFF]/.test(inputText) ? Array.from(inputText) : inputText;
10734
+ const hasSurrogates = /[\uD800-\uDFFF]/.test(inputText);
10735
+ const inputMayContainInvalidStringChar = hasSurrogates || /[\u0000\uFFFE\uFFFF]/.test(inputText);
10736
+ const chars = hasSurrogates ? Array.from(inputText) : inputText;
10731
10737
  const n = chars.length;
10732
10738
  let i = 0;
10733
10739
  const tokens = [];
@@ -10762,14 +10768,47 @@ function lex(inputText, opts = {}) {
10762
10768
  // Hard stops: delimiters cannot appear unescaped inside PNAME tokens.
10763
10769
  if (cc === '{' || cc === '}' || cc === '(' || cc === ')' || cc === '[' || cc === ']' || cc === ';' || cc === ',') break;
10764
10770
 
10765
- // Dot is allowed inside PN_LOCAL, but not at the end.
10766
- if (cc === '.') {
10767
- if (!canContinueAfterDot(peek(1))) break;
10768
- if (out !== null) out.push('.');
10771
+ const code = cc.charCodeAt(0);
10772
+
10773
+ // Common ASCII QName/identifier characters. Keep this branch inline so
10774
+ // ordinary N3 files do not call through the full Unicode PN_CHARS predicate
10775
+ // for every character.
10776
+ if (
10777
+ code === 58 || // ':'
10778
+ code === 95 || // '_'
10779
+ code === 45 || // '-'
10780
+ (code >= 48 && code <= 57) ||
10781
+ (code >= 65 && code <= 90) ||
10782
+ (code >= 97 && code <= 122)
10783
+ ) {
10784
+ if (out !== null) out.push(cc);
10769
10785
  i++;
10770
10786
  continue;
10771
10787
  }
10772
10788
 
10789
+ // Dot is allowed inside PN_LOCAL, but not at the end.
10790
+ if (cc === '.') {
10791
+ const next = peek(1);
10792
+ if (next === null) break;
10793
+ const ncode = next.charCodeAt(0);
10794
+ if (
10795
+ next === '%' ||
10796
+ next === '\\' ||
10797
+ ncode === 58 ||
10798
+ ncode === 95 ||
10799
+ ncode === 45 ||
10800
+ (ncode >= 48 && ncode <= 57) ||
10801
+ (ncode >= 65 && ncode <= 90) ||
10802
+ (ncode >= 97 && ncode <= 122) ||
10803
+ isIdentChar(next)
10804
+ ) {
10805
+ if (out !== null) out.push('.');
10806
+ i++;
10807
+ continue;
10808
+ }
10809
+ break;
10810
+ }
10811
+
10773
10812
  // Percent escape: %HH
10774
10813
  if (cc === '%') {
10775
10814
  const h1 = peek(1);
@@ -11017,7 +11056,7 @@ function lex(inputText, opts = {}) {
11017
11056
  }
11018
11057
  const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
11019
11058
  const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
11020
- assertValidStringLiteralValue(decoded, start);
11059
+ if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
11021
11060
  const s = JSON.stringify(decoded); // canonical short quoted form
11022
11061
  tokens.push(new Token('Literal', s, start));
11023
11062
  continue;
@@ -11107,7 +11146,7 @@ function lex(inputText, opts = {}) {
11107
11146
  }
11108
11147
  const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
11109
11148
  const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
11110
- assertValidStringLiteralValue(decoded, start);
11149
+ if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
11111
11150
  const s = JSON.stringify(decoded); // canonical short quoted form
11112
11151
  tokens.push(new Token('Literal', s, start));
11113
11152
  continue;
@@ -12217,15 +12256,21 @@ class Parser {
12217
12256
 
12218
12257
  while (true) {
12219
12258
  const { verb, invert } = this.parseStatementVerb();
12220
- const objects = this.parseObjectList();
12221
12259
 
12222
- // If VERB or OBJECTS contained paths, their helper triples must come
12223
- // before the triples that consume the path results (Easter depends on this).
12224
- this.flushPendingTriples(out);
12260
+ while (true) {
12261
+ const o = this.parseTerm();
12262
+ const postTriples = this.pendingTriplesAfter;
12263
+ this.pendingTriplesAfter = [];
12264
+
12265
+ // If VERB or OBJECT contained paths, their helper triples must come
12266
+ // before the triple that consumes the path result (Easter depends on this).
12267
+ this.flushPendingTriples(out);
12225
12268
 
12226
- for (const { term: o, postTriples } of objects) {
12227
12269
  out.push(new Triple(invert ? o : subject, verb, invert ? subject : o));
12228
- if (postTriples && postTriples.length) out.push(...postTriples);
12270
+ if (postTriples.length) out.push(...postTriples);
12271
+
12272
+ if (this.peek().typ !== 'Comma') break;
12273
+ this.next();
12229
12274
  }
12230
12275
 
12231
12276
  if (this.peek().typ === 'Semicolon') {
@@ -12239,27 +12284,6 @@ class Parser {
12239
12284
  return out;
12240
12285
  }
12241
12286
 
12242
- parseObjectList() {
12243
- // Capture any trailing property-list triples produced while parsing each
12244
- // object term so we can emit them *after* the triple that references the
12245
- // term. (See pendingTriplesAfter in the constructor.)
12246
-
12247
- const objs = [];
12248
- const readObj = () => {
12249
- const o = this.parseTerm();
12250
- const post = this.pendingTriplesAfter;
12251
- this.pendingTriplesAfter = [];
12252
- objs.push({ term: o, postTriples: post });
12253
- };
12254
-
12255
- readObj();
12256
- while (this.peek().typ === 'Comma') {
12257
- this.next();
12258
- readObj();
12259
- }
12260
- return objs;
12261
- }
12262
-
12263
12287
  makeRule(left, right, isForward) {
12264
12288
  let premiseTerm, conclTerm;
12265
12289
 
package/lib/cli.js CHANGED
@@ -350,12 +350,14 @@ function main() {
350
350
  outTriples = res.queryTriples;
351
351
  outDerived = res.queryDerived;
352
352
  } else {
353
+ const skipDerivedCollection = mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled();
353
354
  derived = engine.forwardChain(facts, frules, brules, null, {
354
355
  captureExplanations: engine.getProofCommentsEnabled(),
356
+ collectDerived: !skipDerivedCollection,
355
357
  prefixes,
356
358
  });
357
359
  outDerived = derived;
358
- outTriples = derived.map((df) => df.fact);
360
+ outTriples = skipDerivedCollection ? [] : derived.map((df) => df.fact);
359
361
  }
360
362
 
361
363
  const renderedOutputTriples = hasQueries ? outTriples : facts;
package/lib/engine.js CHANGED
@@ -2901,6 +2901,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
2901
2901
  __attachGoalTable(backRules, goalTable);
2902
2902
 
2903
2903
  const captureExplanations = !(opts && opts.captureExplanations === false);
2904
+ const collectDerived = !(opts && opts.collectDerived === false);
2905
+ const hasDerivedCallback = typeof onDerived === 'function';
2904
2906
  const derivedForward = [];
2905
2907
  const varGen = [0];
2906
2908
  const skCounter = [0];
@@ -3079,8 +3081,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
3079
3081
  if (!hasFactIndexed(facts, instantiated)) {
3080
3082
  pushFactIndexed(facts, instantiated);
3081
3083
  const df = makeDerivedRecord(instantiated, r, getInstantiatedPremises(), s, captureExplanations);
3082
- derivedForward.push(df);
3083
- if (typeof onDerived === 'function') onDerived(df);
3084
+ if (collectDerived) derivedForward.push(df);
3085
+ if (hasDerivedCallback) onDerived(df);
3084
3086
  changedHere = true;
3085
3087
  }
3086
3088
 
@@ -3143,8 +3145,8 @@ function forwardChain(facts, forwardRules, backRules, onDerived /* optional */,
3143
3145
 
3144
3146
  pushFactIndexed(facts, inst);
3145
3147
  const df = makeDerivedRecord(inst, r, getInstantiatedPremises(), s, captureExplanations);
3146
- derivedForward.push(df);
3147
- if (typeof onDerived === 'function') onDerived(df);
3148
+ if (collectDerived) derivedForward.push(df);
3149
+ if (hasDerivedCallback) onDerived(df);
3148
3150
 
3149
3151
  changedHere = true;
3150
3152
  }
package/lib/lexer.js CHANGED
@@ -121,15 +121,6 @@ function isIdentChar(c) {
121
121
  return c === ':' || isPnChars(c);
122
122
  }
123
123
 
124
- function canContinueAfterDot(next) {
125
- // PN_LOCAL allows '.' but it cannot appear at the end.
126
- // We include '.' only if it is followed by something that could continue a name.
127
- if (next === null) return false;
128
- if (isIdentChar(next)) return true;
129
- if (next === '%' || next === '\\') return true;
130
- return false;
131
- }
132
-
133
124
  function isForbiddenNoncharacterCodePoint(cp) {
134
125
  return (cp & 0xffff) === 0xfffe || (cp & 0xffff) === 0xffff;
135
126
  }
@@ -1205,7 +1196,9 @@ function lex(inputText, opts = {}) {
1205
1196
  // Avoid copying large ASCII/BMP inputs into an Array. Array.from() is
1206
1197
  // only needed when the text contains surrogate pairs and we want the old
1207
1198
  // code-point iteration behavior for non-BMP characters.
1208
- const chars = /[\uD800-\uDFFF]/.test(inputText) ? Array.from(inputText) : inputText;
1199
+ const hasSurrogates = /[\uD800-\uDFFF]/.test(inputText);
1200
+ const inputMayContainInvalidStringChar = hasSurrogates || /[\u0000\uFFFE\uFFFF]/.test(inputText);
1201
+ const chars = hasSurrogates ? Array.from(inputText) : inputText;
1209
1202
  const n = chars.length;
1210
1203
  let i = 0;
1211
1204
  const tokens = [];
@@ -1240,14 +1233,47 @@ function lex(inputText, opts = {}) {
1240
1233
  // Hard stops: delimiters cannot appear unescaped inside PNAME tokens.
1241
1234
  if (cc === '{' || cc === '}' || cc === '(' || cc === ')' || cc === '[' || cc === ']' || cc === ';' || cc === ',') break;
1242
1235
 
1243
- // Dot is allowed inside PN_LOCAL, but not at the end.
1244
- if (cc === '.') {
1245
- if (!canContinueAfterDot(peek(1))) break;
1246
- if (out !== null) out.push('.');
1236
+ const code = cc.charCodeAt(0);
1237
+
1238
+ // Common ASCII QName/identifier characters. Keep this branch inline so
1239
+ // ordinary N3 files do not call through the full Unicode PN_CHARS predicate
1240
+ // for every character.
1241
+ if (
1242
+ code === 58 || // ':'
1243
+ code === 95 || // '_'
1244
+ code === 45 || // '-'
1245
+ (code >= 48 && code <= 57) ||
1246
+ (code >= 65 && code <= 90) ||
1247
+ (code >= 97 && code <= 122)
1248
+ ) {
1249
+ if (out !== null) out.push(cc);
1247
1250
  i++;
1248
1251
  continue;
1249
1252
  }
1250
1253
 
1254
+ // Dot is allowed inside PN_LOCAL, but not at the end.
1255
+ if (cc === '.') {
1256
+ const next = peek(1);
1257
+ if (next === null) break;
1258
+ const ncode = next.charCodeAt(0);
1259
+ if (
1260
+ next === '%' ||
1261
+ next === '\\' ||
1262
+ ncode === 58 ||
1263
+ ncode === 95 ||
1264
+ ncode === 45 ||
1265
+ (ncode >= 48 && ncode <= 57) ||
1266
+ (ncode >= 65 && ncode <= 90) ||
1267
+ (ncode >= 97 && ncode <= 122) ||
1268
+ isIdentChar(next)
1269
+ ) {
1270
+ if (out !== null) out.push('.');
1271
+ i++;
1272
+ continue;
1273
+ }
1274
+ break;
1275
+ }
1276
+
1251
1277
  // Percent escape: %HH
1252
1278
  if (cc === '%') {
1253
1279
  const h1 = peek(1);
@@ -1495,7 +1521,7 @@ function lex(inputText, opts = {}) {
1495
1521
  }
1496
1522
  const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
1497
1523
  const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
1498
- assertValidStringLiteralValue(decoded, start);
1524
+ if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
1499
1525
  const s = JSON.stringify(decoded); // canonical short quoted form
1500
1526
  tokens.push(new Token('Literal', s, start));
1501
1527
  continue;
@@ -1585,7 +1611,7 @@ function lex(inputText, opts = {}) {
1585
1611
  }
1586
1612
  const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
1587
1613
  const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
1588
- assertValidStringLiteralValue(decoded, start);
1614
+ if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
1589
1615
  const s = JSON.stringify(decoded); // canonical short quoted form
1590
1616
  tokens.push(new Token('Literal', s, start));
1591
1617
  continue;
package/lib/parser.js CHANGED
@@ -642,15 +642,21 @@ class Parser {
642
642
 
643
643
  while (true) {
644
644
  const { verb, invert } = this.parseStatementVerb();
645
- const objects = this.parseObjectList();
646
645
 
647
- // If VERB or OBJECTS contained paths, their helper triples must come
648
- // before the triples that consume the path results (Easter depends on this).
649
- this.flushPendingTriples(out);
646
+ while (true) {
647
+ const o = this.parseTerm();
648
+ const postTriples = this.pendingTriplesAfter;
649
+ this.pendingTriplesAfter = [];
650
+
651
+ // If VERB or OBJECT contained paths, their helper triples must come
652
+ // before the triple that consumes the path result (Easter depends on this).
653
+ this.flushPendingTriples(out);
650
654
 
651
- for (const { term: o, postTriples } of objects) {
652
655
  out.push(new Triple(invert ? o : subject, verb, invert ? subject : o));
653
- if (postTriples && postTriples.length) out.push(...postTriples);
656
+ if (postTriples.length) out.push(...postTriples);
657
+
658
+ if (this.peek().typ !== 'Comma') break;
659
+ this.next();
654
660
  }
655
661
 
656
662
  if (this.peek().typ === 'Semicolon') {
@@ -664,27 +670,6 @@ class Parser {
664
670
  return out;
665
671
  }
666
672
 
667
- parseObjectList() {
668
- // Capture any trailing property-list triples produced while parsing each
669
- // object term so we can emit them *after* the triple that references the
670
- // term. (See pendingTriplesAfter in the constructor.)
671
-
672
- const objs = [];
673
- const readObj = () => {
674
- const o = this.parseTerm();
675
- const post = this.pendingTriplesAfter;
676
- this.pendingTriplesAfter = [];
677
- objs.push({ term: o, postTriples: post });
678
- };
679
-
680
- readObj();
681
- while (this.peek().typ === 'Comma') {
682
- this.next();
683
- readObj();
684
- }
685
- return objs;
686
- }
687
-
688
673
  makeRule(left, right, isForward) {
689
674
  let premiseTerm, conclTerm;
690
675
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.25.2",
3
+ "version": "1.25.3",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [