n3 1.14.0 → 1.16.1

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/lib/N3Lexer.js CHANGED
@@ -109,7 +109,7 @@ class N3Lexer {
109
109
  _tokenizeToEnd(callback, inputFinished) {
110
110
  // Continue parsing as far as possible; the loop will return eventually
111
111
  let input = this._input;
112
- const outputComments = this._comments;
112
+ let currentLineLength = input.length;
113
113
 
114
114
  while (true) {
115
115
  // Count and skip whitespace lines
@@ -117,14 +117,10 @@ class N3Lexer {
117
117
 
118
118
  while (whiteSpaceMatch = this._newline.exec(input)) {
119
119
  // Try to find a comment
120
- if (outputComments && (comment = this._comment.exec(whiteSpaceMatch[0]))) callback(null, {
121
- line: this._line,
122
- type: 'comment',
123
- value: comment[1],
124
- prefix: ''
125
- }); // Advance the input
120
+ if (this._comments && (comment = this._comment.exec(whiteSpaceMatch[0]))) emitToken('comment', comment[1], '', this._line, whiteSpaceMatch[0].length); // Advance the input
126
121
 
127
122
  input = input.substr(whiteSpaceMatch[0].length, input.length);
123
+ currentLineLength = input.length;
128
124
  this._line++;
129
125
  } // Skip whitespace on current line
130
126
 
@@ -135,18 +131,9 @@ class N3Lexer {
135
131
  // If the input is finished, emit EOF
136
132
  if (inputFinished) {
137
133
  // Try to find a final comment
138
- if (outputComments && (comment = this._comment.exec(input))) callback(null, {
139
- line: this._line,
140
- type: 'comment',
141
- value: comment[1],
142
- prefix: ''
143
- });
144
- callback(input = null, {
145
- line: this._line,
146
- type: 'eof',
147
- value: '',
148
- prefix: ''
149
- });
134
+ if (this._comments && (comment = this._comment.exec(input))) emitToken('comment', comment[1], '', this._line, input.length);
135
+ input = null;
136
+ emitToken('eof', '', '', this._line, 0);
150
137
  }
151
138
 
152
139
  return this._input = input;
@@ -376,17 +363,28 @@ class N3Lexer {
376
363
  } // Emit the parsed token
377
364
 
378
365
 
379
- const token = {
380
- line: line,
381
- type: type,
382
- value: value,
383
- prefix: prefix
384
- };
385
- callback(null, token);
366
+ const length = matchLength || match[0].length;
367
+ const token = emitToken(type, value, prefix, line, length);
386
368
  this.previousToken = token;
387
369
  this._previousMarker = type; // Advance to next part to tokenize
388
370
 
389
- input = input.substr(matchLength || match[0].length, input.length);
371
+ input = input.substr(length, input.length);
372
+ } // Emits the token through the callback
373
+
374
+
375
+ function emitToken(type, value, prefix, line, length) {
376
+ const start = input ? currentLineLength - input.length : currentLineLength;
377
+ const end = start + length;
378
+ const token = {
379
+ type,
380
+ value,
381
+ prefix,
382
+ line,
383
+ start,
384
+ end
385
+ };
386
+ callback(null, token);
387
+ return token;
390
388
  } // Signals the syntax error through the callback
391
389
 
392
390
 
package/lib/N3Parser.js CHANGED
@@ -83,11 +83,11 @@ class N3Parser {
83
83
  const n3Mode = this._n3Mode;
84
84
 
85
85
  this._contextStack.push({
86
- subject: subject,
87
- predicate: predicate,
88
- object: object,
89
- graph: graph,
90
- type: type,
86
+ type,
87
+ subject,
88
+ predicate,
89
+ object,
90
+ graph,
91
91
  inverse: n3Mode ? this._inversePredicate : false,
92
92
  blankPrefix: n3Mode ? this._prefixes._ : '',
93
93
  quantified: n3Mode ? this._quantified : null
@@ -107,16 +107,18 @@ class N3Parser {
107
107
  // when leaving a scope (list, blank node, formula)
108
108
 
109
109
 
110
- _restoreContext() {
111
- const context = this._contextStack.pop(),
112
- n3Mode = this._n3Mode;
110
+ _restoreContext(type, token) {
111
+ // Obtain the previous context
112
+ const context = this._contextStack.pop();
113
+
114
+ if (!context || context.type !== type) return this._error(`Unexpected ${token.type}`, token); // Restore the quad of the previous context
113
115
 
114
116
  this._subject = context.subject;
115
117
  this._predicate = context.predicate;
116
118
  this._object = context.object;
117
- this._graph = context.graph; // The settings below only apply to N3 streams
119
+ this._graph = context.graph; // Restore N3 context settings
118
120
 
119
- if (n3Mode) {
121
+ if (this._n3Mode) {
120
122
  this._inversePredicate = context.inverse;
121
123
  this._prefixes._ = context.blankPrefix;
122
124
  this._quantified = context.quantified;
@@ -406,7 +408,7 @@ class N3Parser {
406
408
 
407
409
  const empty = this._predicate === null;
408
410
 
409
- this._restoreContext(); // If the blank node was the object, restore previous context and read punctuation
411
+ this._restoreContext('blank', token); // If the blank node was the object, restore previous context and read punctuation
410
412
 
411
413
 
412
414
  if (this._object !== null) return this._getContextEndReader(); // If the blank node was the predicate, continue reading the object
@@ -460,7 +462,7 @@ class N3Parser {
460
462
 
461
463
  case ')':
462
464
  // Closing the list; restore the parent context
463
- this._restoreContext(); // If this list is contained within a parent list, return the membership quad here.
465
+ this._restoreContext('list', token); // If this list is contained within a parent list, return the membership quad here.
464
466
  // This will be `<parent list element> rdf:first <this list>.`.
465
467
 
466
468
 
@@ -606,7 +608,7 @@ class N3Parser {
606
608
 
607
609
  if (this._subject !== null) this._emit(this._subject, this._predicate, this._object, this._graph); // Restore the parent context containing this formula
608
610
 
609
- this._restoreContext(); // If the formula was the subject, continue reading the predicate.
611
+ this._restoreContext('formula', token); // If the formula was the subject, continue reading the predicate.
610
612
  // If the formula was the object, read punctuation.
611
613
 
612
614
 
@@ -830,7 +832,7 @@ class N3Parser {
830
832
  // The list item is the remaining subejct after reading the path
831
833
  const item = this._subject; // Switch back to the context of the list
832
834
 
833
- this._restoreContext(); // Output the list item
835
+ this._restoreContext('item', token); // Output the list item
834
836
 
835
837
 
836
838
  this._emit(this._subject, this.RDF_FIRST, item, this._graph);
@@ -890,7 +892,7 @@ class N3Parser {
890
892
 
891
893
  const quad = this._quad(this._subject, this._predicate, this._object, this._graph || this.DEFAULTGRAPH);
892
894
 
893
- this._restoreContext(); // If the triple was the subject, continue by reading the predicate.
895
+ this._restoreContext('<<', token); // If the triple was the subject, continue by reading the predicate.
894
896
 
895
897
 
896
898
  if (this._subject === null) {
package/lib/N3Store.js CHANGED
@@ -92,17 +92,15 @@ class N3Store {
92
92
  // `name0`, `name1`, and `name2` are the names of the keys at each level,
93
93
  // used when reconstructing the resulting quad
94
94
  // (for instance: _subject_, _predicate_, and _object_).
95
- // Finally, `graph` will be the graph of the created quads.
96
- // If `callback` is given, each result is passed through it
97
- // and iteration halts when it returns truthy for any quad.
98
- // If instead `array` is given, each result is added to the array.
95
+ // Finally, `graphId` will be the graph of the created quads.
99
96
 
100
97
 
101
- _findInIndex(index0, key0, key1, key2, name0, name1, name2, graph, callback, array) {
98
+ *_findInIndex(index0, key0, key1, key2, name0, name1, name2, graphId) {
102
99
  let tmp, index1, index2; // Depending on the number of variables, keys or reverse index are faster
103
100
 
104
101
  const varCount = !key0 + !key1 + !key2,
105
- entityKeys = varCount > 1 ? Object.keys(this._ids) : this._entities; // If a key is specified, use only that part of index 0.
102
+ entityKeys = varCount > 1 ? Object.keys(this._ids) : this._entities;
103
+ const graph = (0, _N3DataFactory.termFromId)(graphId, this._factory); // If a key is specified, use only that part of index 0.
106
104
 
107
105
  if (key0) (tmp = index0, index0 = {})[key0] = tmp[key0];
108
106
 
@@ -129,17 +127,12 @@ class N3Store {
129
127
  parts[name0] = (0, _N3DataFactory.termFromId)(entity0, this._factory);
130
128
  parts[name1] = (0, _N3DataFactory.termFromId)(entity1, this._factory);
131
129
  parts[name2] = (0, _N3DataFactory.termFromId)(entityKeys[values[l]], this._factory);
132
-
133
- const quad = this._factory.quad(parts.subject, parts.predicate, parts.object, (0, _N3DataFactory.termFromId)(graph, this._factory));
134
-
135
- if (array) array.push(quad);else if (callback(quad)) return true;
130
+ yield this._factory.quad(parts.subject, parts.predicate, parts.object, graph);
136
131
  }
137
132
  }
138
133
  }
139
134
  }
140
135
  }
141
-
142
- return array;
143
136
  } // ### `_loop` executes the callback on all keys of index 0
144
137
 
145
138
 
@@ -288,13 +281,17 @@ class N3Store {
288
281
  delete(quad) {
289
282
  this.removeQuad(quad);
290
283
  return this;
291
- } // ### `has` determines whether a dataset includes a certain quad.
292
- // Returns true or false as appropriate.
284
+ } // ### `has` determines whether a dataset includes a certain quad or quad pattern.
293
285
 
294
286
 
295
- has(quad) {
296
- const quads = this.getQuads(quad.subject, quad.predicate, quad.object, quad.graph);
297
- return quads.length !== 0;
287
+ has(subjectOrQuad, predicate, object, graph) {
288
+ if (subjectOrQuad && subjectOrQuad.subject) ({
289
+ subject: subjectOrQuad,
290
+ predicate,
291
+ object,
292
+ graph
293
+ } = subjectOrQuad);
294
+ return !this.readQuads(subjectOrQuad, predicate, object, graph).next().done;
298
295
  } // ### `import` adds a stream of quads to the store
299
296
 
300
297
 
@@ -356,7 +353,7 @@ class N3Store {
356
353
  });
357
354
 
358
355
  stream._read = () => {
359
- for (const quad of this.getQuads(subject, predicate, object, graph)) stream.push(quad);
356
+ for (const quad of this.readQuads(subject, predicate, object, graph)) stream.push(quad);
360
357
 
361
358
  stream.push(null);
362
359
  };
@@ -372,19 +369,24 @@ class N3Store {
372
369
 
373
370
 
374
371
  getQuads(subject, predicate, object, graph) {
372
+ return [...this.readQuads(subject, predicate, object, graph)];
373
+ } // ### `readQuads` returns an generator of quads matching a pattern.
374
+ // Setting any field to `undefined` or `null` indicates a wildcard.
375
+
376
+
377
+ *readQuads(subject, predicate, object, graph) {
375
378
  // Convert terms to internal string representation
376
379
  subject = subject && (0, _N3DataFactory.termToId)(subject);
377
380
  predicate = predicate && (0, _N3DataFactory.termToId)(predicate);
378
381
  object = object && (0, _N3DataFactory.termToId)(object);
379
382
  graph = graph && (0, _N3DataFactory.termToId)(graph);
380
383
 
381
- const quads = [],
382
- graphs = this._getGraphs(graph),
384
+ const graphs = this._getGraphs(graph),
383
385
  ids = this._ids;
384
386
 
385
387
  let content, subjectId, predicateId, objectId; // Translate IRIs to internal index keys.
386
388
 
387
- if (isString(subject) && !(subjectId = ids[subject]) || isString(predicate) && !(predicateId = ids[predicate]) || isString(object) && !(objectId = ids[object])) return quads;
389
+ if (isString(subject) && !(subjectId = ids[subject]) || isString(predicate) && !(predicateId = ids[predicate]) || isString(object) && !(objectId = ids[object])) return;
388
390
 
389
391
  for (const graphId in graphs) {
390
392
  // Only if the specified graph contains triples, there can be results
@@ -392,16 +394,14 @@ class N3Store {
392
394
  // Choose the optimal index, based on what fields are present
393
395
  if (subjectId) {
394
396
  if (objectId) // If subject and object are given, the object index will be the fastest
395
- this._findInIndex(content.objects, objectId, subjectId, predicateId, 'object', 'subject', 'predicate', graphId, null, quads);else // If only subject and possibly predicate are given, the subject index will be the fastest
396
- this._findInIndex(content.subjects, subjectId, predicateId, null, 'subject', 'predicate', 'object', graphId, null, quads);
397
+ yield* this._findInIndex(content.objects, objectId, subjectId, predicateId, 'object', 'subject', 'predicate', graphId, null, true);else // If only subject and possibly predicate are given, the subject index will be the fastest
398
+ yield* this._findInIndex(content.subjects, subjectId, predicateId, null, 'subject', 'predicate', 'object', graphId, null, true);
397
399
  } else if (predicateId) // If only predicate and possibly object are given, the predicate index will be the fastest
398
- this._findInIndex(content.predicates, predicateId, objectId, null, 'predicate', 'object', 'subject', graphId, null, quads);else if (objectId) // If only object is given, the object index will be the fastest
399
- this._findInIndex(content.objects, objectId, null, null, 'object', 'subject', 'predicate', graphId, null, quads);else // If nothing is given, iterate subjects and predicates first
400
- this._findInIndex(content.subjects, null, null, null, 'subject', 'predicate', 'object', graphId, null, quads);
400
+ yield* this._findInIndex(content.predicates, predicateId, objectId, null, 'predicate', 'object', 'subject', graphId, null, true);else if (objectId) // If only object is given, the object index will be the fastest
401
+ yield* this._findInIndex(content.objects, objectId, null, null, 'object', 'subject', 'predicate', graphId, null, true);else // If nothing is given, iterate subjects and predicates first
402
+ yield* this._findInIndex(content.subjects, null, null, null, 'subject', 'predicate', 'object', graphId, null, true);
401
403
  }
402
404
  }
403
-
404
- return quads;
405
405
  } // ### `match` returns a new dataset that is comprised of all quads in the current instance matching the given arguments.
406
406
  // The logic described in Quad Matching is applied for each quad in this dataset to check if it should be included in the output dataset.
407
407
  // Note: This method always returns a new DatasetCore, even if that dataset contains no quads.
@@ -480,45 +480,7 @@ class N3Store {
480
480
 
481
481
 
482
482
  some(callback, subject, predicate, object, graph) {
483
- // Convert terms to internal string representation
484
- subject = subject && (0, _N3DataFactory.termToId)(subject);
485
- predicate = predicate && (0, _N3DataFactory.termToId)(predicate);
486
- object = object && (0, _N3DataFactory.termToId)(object);
487
- graph = graph && (0, _N3DataFactory.termToId)(graph);
488
-
489
- const graphs = this._getGraphs(graph),
490
- ids = this._ids;
491
-
492
- let content, subjectId, predicateId, objectId; // Translate IRIs to internal index keys.
493
-
494
- if (isString(subject) && !(subjectId = ids[subject]) || isString(predicate) && !(predicateId = ids[predicate]) || isString(object) && !(objectId = ids[object])) return false;
495
-
496
- for (const graphId in graphs) {
497
- // Only if the specified graph contains triples, there can be results
498
- if (content = graphs[graphId]) {
499
- // Choose the optimal index, based on what fields are present
500
- if (subjectId) {
501
- if (objectId) {
502
- // If subject and object are given, the object index will be the fastest
503
- if (this._findInIndex(content.objects, objectId, subjectId, predicateId, 'object', 'subject', 'predicate', graphId, callback, null)) return true;
504
- } else // If only subject and possibly predicate are given, the subject index will be the fastest
505
- if (this._findInIndex(content.subjects, subjectId, predicateId, null, 'subject', 'predicate', 'object', graphId, callback, null)) return true;
506
- } else if (predicateId) {
507
- // If only predicate and possibly object are given, the predicate index will be the fastest
508
- if (this._findInIndex(content.predicates, predicateId, objectId, null, 'predicate', 'object', 'subject', graphId, callback, null)) {
509
- return true;
510
- }
511
- } else if (objectId) {
512
- // If only object is given, the object index will be the fastest
513
- if (this._findInIndex(content.objects, objectId, null, null, 'object', 'subject', 'predicate', graphId, callback, null)) {
514
- return true;
515
- }
516
- } else // If nothing is given, iterate subjects and predicates first
517
- if (this._findInIndex(content.subjects, null, null, null, 'subject', 'predicate', 'object', graphId, callback, null)) {
518
- return true;
519
- }
520
- }
521
- }
483
+ for (const quad of this.readQuads(subject, predicate, object, graph)) if (callback(quad)) return true;
522
484
 
523
485
  return false;
524
486
  } // ### `getSubjects` returns all subjects that match the pattern.
@@ -772,7 +734,7 @@ class N3Store {
772
734
 
773
735
 
774
736
  *[Symbol.iterator]() {
775
- yield* this.getQuads();
737
+ yield* this.readQuads();
776
738
  }
777
739
 
778
740
  } // Determines whether the argument is a string
@@ -825,7 +787,7 @@ class DatasetCoreAndReadableStream extends _readableStream.Readable {
825
787
  }
826
788
 
827
789
  _read() {
828
- for (const quad of this.filtered.getQuads()) this.push(quad);
790
+ for (const quad of this) this.push(quad);
829
791
 
830
792
  this.push(null);
831
793
  }
@@ -847,7 +809,7 @@ class DatasetCoreAndReadableStream extends _readableStream.Readable {
847
809
  }
848
810
 
849
811
  *[Symbol.iterator]() {
850
- yield* this.filtered.getQuads();
812
+ yield* this._filtered || this.n3Store.readQuads(this.subject, this.predicate, this.object, this.graph);
851
813
  }
852
814
 
853
815
  }
package/lib/N3Util.js CHANGED
@@ -50,7 +50,7 @@ function inDefaultGraph(quad) {
50
50
 
51
51
  function prefix(iri, factory) {
52
52
  return prefixes({
53
- '': iri
53
+ '': iri.value || iri
54
54
  }, factory)('');
55
55
  } // Creates a function that allows registering and expanding prefixes
56
56
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "1.14.0",
3
+ "version": "1.16.1",
4
4
  "description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
5
5
  "author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
6
6
  "keywords": [
package/src/N3Lexer.js CHANGED
@@ -78,16 +78,17 @@ export default class N3Lexer {
78
78
  _tokenizeToEnd(callback, inputFinished) {
79
79
  // Continue parsing as far as possible; the loop will return eventually
80
80
  let input = this._input;
81
- const outputComments = this._comments;
81
+ let currentLineLength = input.length;
82
82
  while (true) {
83
83
  // Count and skip whitespace lines
84
84
  let whiteSpaceMatch, comment;
85
85
  while (whiteSpaceMatch = this._newline.exec(input)) {
86
86
  // Try to find a comment
87
- if (outputComments && (comment = this._comment.exec(whiteSpaceMatch[0])))
88
- callback(null, { line: this._line, type: 'comment', value: comment[1], prefix: '' });
87
+ if (this._comments && (comment = this._comment.exec(whiteSpaceMatch[0])))
88
+ emitToken('comment', comment[1], '', this._line, whiteSpaceMatch[0].length);
89
89
  // Advance the input
90
90
  input = input.substr(whiteSpaceMatch[0].length, input.length);
91
+ currentLineLength = input.length;
91
92
  this._line++;
92
93
  }
93
94
  // Skip whitespace on current line
@@ -99,9 +100,10 @@ export default class N3Lexer {
99
100
  // If the input is finished, emit EOF
100
101
  if (inputFinished) {
101
102
  // Try to find a final comment
102
- if (outputComments && (comment = this._comment.exec(input)))
103
- callback(null, { line: this._line, type: 'comment', value: comment[1], prefix: '' });
104
- callback(input = null, { line: this._line, type: 'eof', value: '', prefix: '' });
103
+ if (this._comments && (comment = this._comment.exec(input)))
104
+ emitToken('comment', comment[1], '', this._line, input.length);
105
+ input = null;
106
+ emitToken('eof', '', '', this._line, 0);
105
107
  }
106
108
  return this._input = input;
107
109
  }
@@ -345,14 +347,23 @@ export default class N3Lexer {
345
347
  }
346
348
 
347
349
  // Emit the parsed token
348
- const token = { line: line, type: type, value: value, prefix: prefix };
349
- callback(null, token);
350
+ const length = matchLength || match[0].length;
351
+ const token = emitToken(type, value, prefix, line, length);
350
352
  this.previousToken = token;
351
353
  this._previousMarker = type;
354
+
352
355
  // Advance to next part to tokenize
353
- input = input.substr(matchLength || match[0].length, input.length);
356
+ input = input.substr(length, input.length);
354
357
  }
355
358
 
359
+ // Emits the token through the callback
360
+ function emitToken(type, value, prefix, line, length) {
361
+ const start = input ? currentLineLength - input.length : currentLineLength;
362
+ const end = start + length;
363
+ const token = { type, value, prefix, line, start, end };
364
+ callback(null, token);
365
+ return token;
366
+ }
356
367
  // Signals the syntax error through the callback
357
368
  function reportSyntaxError(self) { callback(self._syntaxError(/^\S*/.exec(input)[0])); }
358
369
  }
package/src/N3Parser.js CHANGED
@@ -74,8 +74,8 @@ export default class N3Parser {
74
74
  _saveContext(type, graph, subject, predicate, object) {
75
75
  const n3Mode = this._n3Mode;
76
76
  this._contextStack.push({
77
- subject: subject, predicate: predicate, object: object,
78
- graph: graph, type: type,
77
+ type,
78
+ subject, predicate, object, graph,
79
79
  inverse: n3Mode ? this._inversePredicate : false,
80
80
  blankPrefix: n3Mode ? this._prefixes._ : '',
81
81
  quantified: n3Mode ? this._quantified : null,
@@ -94,14 +94,20 @@ export default class N3Parser {
94
94
 
95
95
  // ### `_restoreContext` restores the parent context
96
96
  // when leaving a scope (list, blank node, formula)
97
- _restoreContext() {
98
- const context = this._contextStack.pop(), n3Mode = this._n3Mode;
97
+ _restoreContext(type, token) {
98
+ // Obtain the previous context
99
+ const context = this._contextStack.pop();
100
+ if (!context || context.type !== type)
101
+ return this._error(`Unexpected ${token.type}`, token);
102
+
103
+ // Restore the quad of the previous context
99
104
  this._subject = context.subject;
100
105
  this._predicate = context.predicate;
101
106
  this._object = context.object;
102
107
  this._graph = context.graph;
103
- // The settings below only apply to N3 streams
104
- if (n3Mode) {
108
+
109
+ // Restore N3 context settings
110
+ if (this._n3Mode) {
105
111
  this._inversePredicate = context.inverse;
106
112
  this._prefixes._ = context.blankPrefix;
107
113
  this._quantified = context.quantified;
@@ -374,7 +380,7 @@ export default class N3Parser {
374
380
 
375
381
  // Restore the parent context containing this blank node
376
382
  const empty = this._predicate === null;
377
- this._restoreContext();
383
+ this._restoreContext('blank', token);
378
384
  // If the blank node was the object, restore previous context and read punctuation
379
385
  if (this._object !== null)
380
386
  return this._getContextEndReader();
@@ -425,7 +431,7 @@ export default class N3Parser {
425
431
  break;
426
432
  case ')':
427
433
  // Closing the list; restore the parent context
428
- this._restoreContext();
434
+ this._restoreContext('list', token);
429
435
  // If this list is contained within a parent list, return the membership quad here.
430
436
  // This will be `<parent list element> rdf:first <this list>.`.
431
437
  if (stack.length !== 0 && stack[stack.length - 1].type === 'list')
@@ -576,7 +582,7 @@ export default class N3Parser {
576
582
  this._emit(this._subject, this._predicate, this._object, this._graph);
577
583
 
578
584
  // Restore the parent context containing this formula
579
- this._restoreContext();
585
+ this._restoreContext('formula', token);
580
586
  // If the formula was the subject, continue reading the predicate.
581
587
  // If the formula was the object, read punctuation.
582
588
  return this._object === null ? this._readPredicate : this._getContextEndReader();
@@ -785,7 +791,7 @@ export default class N3Parser {
785
791
  // The list item is the remaining subejct after reading the path
786
792
  const item = this._subject;
787
793
  // Switch back to the context of the list
788
- this._restoreContext();
794
+ this._restoreContext('item', token);
789
795
  // Output the list item
790
796
  this._emit(this._subject, this.RDF_FIRST, item, this._graph);
791
797
  }
@@ -847,7 +853,7 @@ export default class N3Parser {
847
853
  // Read the quad and restore the previous context
848
854
  const quad = this._quad(this._subject, this._predicate, this._object,
849
855
  this._graph || this.DEFAULTGRAPH);
850
- this._restoreContext();
856
+ this._restoreContext('<<', token);
851
857
  // If the triple was the subject, continue by reading the predicate.
852
858
  if (this._subject === null) {
853
859
  this._subject = quad;