n3 1.17.0 → 1.17.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/README.md +10 -6
- package/browser/n3.min.js +1 -1
- package/lib/IRIs.js +4 -5
- package/lib/N3DataFactory.js +121 -137
- package/lib/N3Lexer.js +106 -139
- package/lib/N3Parser.js +275 -403
- package/lib/N3Store.js +294 -317
- package/lib/N3StreamParser.js +11 -14
- package/lib/N3StreamWriter.js +7 -11
- package/lib/N3Util.js +19 -25
- package/lib/N3Writer.js +124 -154
- package/lib/index.js +4 -18
- package/package.json +41 -18
- package/src/N3DataFactory.js +31 -24
- package/src/N3Store.js +68 -49
- package/src/N3Writer.js +2 -2
package/lib/N3Parser.js
CHANGED
|
@@ -4,42 +4,39 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _N3Lexer = _interopRequireDefault(require("./N3Lexer"));
|
|
9
|
-
|
|
10
8
|
var _N3DataFactory = _interopRequireDefault(require("./N3DataFactory"));
|
|
11
|
-
|
|
12
9
|
var _IRIs = _interopRequireDefault(require("./IRIs"));
|
|
13
|
-
|
|
14
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
-
|
|
16
11
|
// **N3Parser** parses N3 documents.
|
|
17
|
-
let blankNodePrefix = 0; // ## Constructor
|
|
18
12
|
|
|
13
|
+
let blankNodePrefix = 0;
|
|
14
|
+
|
|
15
|
+
// ## Constructor
|
|
19
16
|
class N3Parser {
|
|
20
17
|
constructor(options) {
|
|
21
18
|
this._contextStack = [];
|
|
22
|
-
this._graph = null;
|
|
19
|
+
this._graph = null;
|
|
23
20
|
|
|
21
|
+
// Set the document IRI
|
|
24
22
|
options = options || {};
|
|
25
|
-
|
|
26
23
|
this._setBase(options.baseIRI);
|
|
24
|
+
options.factory && initDataFactory(this, options.factory);
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
// Set supported features depending on the format
|
|
30
27
|
const format = typeof options.format === 'string' ? options.format.match(/\w*$/)[0].toLowerCase() : '',
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (!(this._supportsNamedGraphs = !(isTurtle || isN3))) this._readPredicateOrNamedGraph = this._readPredicate;
|
|
38
|
-
|
|
39
|
-
this._supportsQuads = !(isTurtle || isTriG || isNTriples || isN3);
|
|
40
|
-
|
|
41
|
-
this._supportsRDFStar = format === '' || /star|\*$/.test(format);
|
|
42
|
-
|
|
28
|
+
isTurtle = /turtle/.test(format),
|
|
29
|
+
isTriG = /trig/.test(format),
|
|
30
|
+
isNTriples = /triple/.test(format),
|
|
31
|
+
isNQuads = /quad/.test(format),
|
|
32
|
+
isN3 = this._n3Mode = /n3/.test(format),
|
|
33
|
+
isLineMode = isNTriples || isNQuads;
|
|
34
|
+
if (!(this._supportsNamedGraphs = !(isTurtle || isN3))) this._readPredicateOrNamedGraph = this._readPredicate;
|
|
35
|
+
// Support triples in other graphs
|
|
36
|
+
this._supportsQuads = !(isTurtle || isTriG || isNTriples || isN3);
|
|
37
|
+
// Support nesting of triples
|
|
38
|
+
this._supportsRDFStar = format === '' || /star|\*$/.test(format);
|
|
39
|
+
// Disable relative IRIs in N-Triples or N-Quads mode
|
|
43
40
|
if (isLineMode) this._resolveRelativeIRI = iri => {
|
|
44
41
|
return null;
|
|
45
42
|
};
|
|
@@ -47,19 +44,21 @@ class N3Parser {
|
|
|
47
44
|
this._lexer = options.lexer || new _N3Lexer.default({
|
|
48
45
|
lineMode: isLineMode,
|
|
49
46
|
n3: isN3
|
|
50
|
-
});
|
|
51
|
-
|
|
47
|
+
});
|
|
48
|
+
// Disable explicit quantifiers by default
|
|
52
49
|
this._explicitQuantifiers = !!options.explicitQuantifiers;
|
|
53
|
-
}
|
|
54
|
-
// ### `_resetBlankNodePrefix` restarts blank node prefix identification
|
|
50
|
+
}
|
|
55
51
|
|
|
52
|
+
// ## Static class methods
|
|
56
53
|
|
|
54
|
+
// ### `_resetBlankNodePrefix` restarts blank node prefix identification
|
|
57
55
|
static _resetBlankNodePrefix() {
|
|
58
56
|
blankNodePrefix = 0;
|
|
59
|
-
}
|
|
60
|
-
// ### `_setBase` sets the base IRI to resolve relative IRIs
|
|
57
|
+
}
|
|
61
58
|
|
|
59
|
+
// ## Private methods
|
|
62
60
|
|
|
61
|
+
// ### `_setBase` sets the base IRI to resolve relative IRIs
|
|
63
62
|
_setBase(baseIRI) {
|
|
64
63
|
if (!baseIRI) {
|
|
65
64
|
this._base = '';
|
|
@@ -67,21 +66,20 @@ class N3Parser {
|
|
|
67
66
|
} else {
|
|
68
67
|
// Remove fragment if present
|
|
69
68
|
const fragmentPos = baseIRI.indexOf('#');
|
|
70
|
-
if (fragmentPos >= 0) baseIRI = baseIRI.substr(0, fragmentPos);
|
|
71
|
-
|
|
69
|
+
if (fragmentPos >= 0) baseIRI = baseIRI.substr(0, fragmentPos);
|
|
70
|
+
// Set base IRI and its components
|
|
72
71
|
this._base = baseIRI;
|
|
73
72
|
this._basePath = baseIRI.indexOf('/') < 0 ? baseIRI : baseIRI.replace(/[^\/?]*(?:\?.*)?$/, '');
|
|
74
73
|
baseIRI = baseIRI.match(/^(?:([a-z][a-z0-9+.-]*:))?(?:\/\/[^\/]*)?/i);
|
|
75
74
|
this._baseRoot = baseIRI[0];
|
|
76
75
|
this._baseScheme = baseIRI[1];
|
|
77
76
|
}
|
|
78
|
-
}
|
|
79
|
-
// when entering a new scope (list, blank node, formula)
|
|
80
|
-
|
|
77
|
+
}
|
|
81
78
|
|
|
79
|
+
// ### `_saveContext` stores the current parsing context
|
|
80
|
+
// when entering a new scope (list, blank node, formula)
|
|
82
81
|
_saveContext(type, graph, subject, predicate, object) {
|
|
83
82
|
const n3Mode = this._n3Mode;
|
|
84
|
-
|
|
85
83
|
this._contextStack.push({
|
|
86
84
|
type,
|
|
87
85
|
subject,
|
|
@@ -91,41 +89,41 @@ class N3Parser {
|
|
|
91
89
|
inverse: n3Mode ? this._inversePredicate : false,
|
|
92
90
|
blankPrefix: n3Mode ? this._prefixes._ : '',
|
|
93
91
|
quantified: n3Mode ? this._quantified : null
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
});
|
|
93
|
+
// The settings below only apply to N3 streams
|
|
97
94
|
if (n3Mode) {
|
|
98
95
|
// Every new scope resets the predicate direction
|
|
99
|
-
this._inversePredicate = false;
|
|
96
|
+
this._inversePredicate = false;
|
|
97
|
+
// In N3, blank nodes are scoped to a formula
|
|
100
98
|
// (using a dot as separator, as a blank node label cannot start with it)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
this._prefixes._ = this._graph ? `${this._graph.value}.` : '.';
|
|
100
|
+
// Quantifiers are scoped to a formula
|
|
104
101
|
this._quantified = Object.create(this._quantified);
|
|
105
102
|
}
|
|
106
|
-
}
|
|
107
|
-
// when leaving a scope (list, blank node, formula)
|
|
108
|
-
|
|
103
|
+
}
|
|
109
104
|
|
|
105
|
+
// ### `_restoreContext` restores the parent context
|
|
106
|
+
// when leaving a scope (list, blank node, formula)
|
|
110
107
|
_restoreContext(type, token) {
|
|
111
108
|
// Obtain the previous context
|
|
112
109
|
const context = this._contextStack.pop();
|
|
110
|
+
if (!context || context.type !== type) return this._error(`Unexpected ${token.type}`, token);
|
|
113
111
|
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
// Restore the quad of the previous context
|
|
116
113
|
this._subject = context.subject;
|
|
117
114
|
this._predicate = context.predicate;
|
|
118
115
|
this._object = context.object;
|
|
119
|
-
this._graph = context.graph;
|
|
116
|
+
this._graph = context.graph;
|
|
120
117
|
|
|
118
|
+
// Restore N3 context settings
|
|
121
119
|
if (this._n3Mode) {
|
|
122
120
|
this._inversePredicate = context.inverse;
|
|
123
121
|
this._prefixes._ = context.blankPrefix;
|
|
124
122
|
this._quantified = context.quantified;
|
|
125
123
|
}
|
|
126
|
-
}
|
|
127
|
-
|
|
124
|
+
}
|
|
128
125
|
|
|
126
|
+
// ### `_readInTopContext` reads a token when in the top context
|
|
129
127
|
_readInTopContext(token) {
|
|
130
128
|
switch (token.type) {
|
|
131
129
|
// If an EOF token arrives in the top context, signal that we're done
|
|
@@ -134,52 +132,42 @@ class N3Parser {
|
|
|
134
132
|
delete this._prefixes._;
|
|
135
133
|
return this._callback(null, null, this._prefixes);
|
|
136
134
|
// It could be a prefix declaration
|
|
137
|
-
|
|
138
135
|
case 'PREFIX':
|
|
139
136
|
this._sparqlStyle = true;
|
|
140
|
-
|
|
141
137
|
case '@prefix':
|
|
142
138
|
return this._readPrefix;
|
|
143
139
|
// It could be a base declaration
|
|
144
|
-
|
|
145
140
|
case 'BASE':
|
|
146
141
|
this._sparqlStyle = true;
|
|
147
|
-
|
|
148
142
|
case '@base':
|
|
149
143
|
return this._readBaseIRI;
|
|
150
144
|
// It could be a graph
|
|
151
|
-
|
|
152
145
|
case '{':
|
|
153
146
|
if (this._supportsNamedGraphs) {
|
|
154
147
|
this._graph = '';
|
|
155
148
|
this._subject = null;
|
|
156
149
|
return this._readSubject;
|
|
157
150
|
}
|
|
158
|
-
|
|
159
151
|
case 'GRAPH':
|
|
160
152
|
if (this._supportsNamedGraphs) return this._readNamedGraphLabel;
|
|
161
153
|
// Otherwise, the next token must be a subject
|
|
162
|
-
|
|
163
154
|
default:
|
|
164
155
|
return this._readSubject(token);
|
|
165
156
|
}
|
|
166
|
-
}
|
|
167
|
-
|
|
157
|
+
}
|
|
168
158
|
|
|
159
|
+
// ### `_readEntity` reads an IRI, prefixed name, blank node, or variable
|
|
169
160
|
_readEntity(token, quantifier) {
|
|
170
161
|
let value;
|
|
171
|
-
|
|
172
162
|
switch (token.type) {
|
|
173
163
|
// Read a relative or absolute IRI
|
|
174
164
|
case 'IRI':
|
|
175
165
|
case 'typeIRI':
|
|
176
166
|
const iri = this._resolveIRI(token.value);
|
|
177
|
-
|
|
178
167
|
if (iri === null) return this._error('Invalid IRI', token);
|
|
179
168
|
value = this._namedNode(iri);
|
|
180
169
|
break;
|
|
181
170
|
// Read a prefixed name
|
|
182
|
-
|
|
183
171
|
case 'type':
|
|
184
172
|
case 'prefixed':
|
|
185
173
|
const prefix = this._prefixes[token.prefix];
|
|
@@ -187,112 +175,88 @@ class N3Parser {
|
|
|
187
175
|
value = this._namedNode(prefix + token.value);
|
|
188
176
|
break;
|
|
189
177
|
// Read a blank node
|
|
190
|
-
|
|
191
178
|
case 'blank':
|
|
192
179
|
value = this._blankNode(this._prefixes[token.prefix] + token.value);
|
|
193
180
|
break;
|
|
194
181
|
// Read a variable
|
|
195
|
-
|
|
196
182
|
case 'var':
|
|
197
183
|
value = this._variable(token.value.substr(1));
|
|
198
184
|
break;
|
|
199
185
|
// Everything else is not an entity
|
|
200
|
-
|
|
201
186
|
default:
|
|
202
187
|
return this._error(`Expected entity but got ${token.type}`, token);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
|
|
188
|
+
}
|
|
189
|
+
// In N3 mode, replace the entity if it is quantified
|
|
206
190
|
if (!quantifier && this._n3Mode && value.id in this._quantified) value = this._quantified[value.id];
|
|
207
191
|
return value;
|
|
208
|
-
}
|
|
209
|
-
|
|
192
|
+
}
|
|
210
193
|
|
|
194
|
+
// ### `_readSubject` reads a quad's subject
|
|
211
195
|
_readSubject(token) {
|
|
212
196
|
this._predicate = null;
|
|
213
|
-
|
|
214
197
|
switch (token.type) {
|
|
215
198
|
case '[':
|
|
216
199
|
// Start a new quad with a new blank node as subject
|
|
217
200
|
this._saveContext('blank', this._graph, this._subject = this._blankNode(), null, null);
|
|
218
|
-
|
|
219
201
|
return this._readBlankNodeHead;
|
|
220
|
-
|
|
221
202
|
case '(':
|
|
222
203
|
// Start a new list
|
|
223
204
|
this._saveContext('list', this._graph, this.RDF_NIL, null, null);
|
|
224
|
-
|
|
225
205
|
this._subject = null;
|
|
226
206
|
return this._readListItem;
|
|
227
|
-
|
|
228
207
|
case '{':
|
|
229
208
|
// Start a new formula
|
|
230
209
|
if (!this._n3Mode) return this._error('Unexpected graph', token);
|
|
231
|
-
|
|
232
210
|
this._saveContext('formula', this._graph, this._graph = this._blankNode(), null, null);
|
|
233
|
-
|
|
234
211
|
return this._readSubject;
|
|
235
|
-
|
|
236
212
|
case '}':
|
|
237
213
|
// No subject; the graph in which we are reading is closed instead
|
|
238
214
|
return this._readPunctuation(token);
|
|
239
|
-
|
|
240
215
|
case '@forSome':
|
|
241
216
|
if (!this._n3Mode) return this._error('Unexpected "@forSome"', token);
|
|
242
217
|
this._subject = null;
|
|
243
218
|
this._predicate = this.N3_FORSOME;
|
|
244
219
|
this._quantifier = this._blankNode;
|
|
245
220
|
return this._readQuantifierList;
|
|
246
|
-
|
|
247
221
|
case '@forAll':
|
|
248
222
|
if (!this._n3Mode) return this._error('Unexpected "@forAll"', token);
|
|
249
223
|
this._subject = null;
|
|
250
224
|
this._predicate = this.N3_FORALL;
|
|
251
225
|
this._quantifier = this._variable;
|
|
252
226
|
return this._readQuantifierList;
|
|
253
|
-
|
|
254
227
|
case 'literal':
|
|
255
228
|
if (!this._n3Mode) return this._error('Unexpected literal', token);
|
|
256
|
-
|
|
257
229
|
if (token.prefix.length === 0) {
|
|
258
230
|
this._literalValue = token.value;
|
|
259
231
|
return this._completeSubjectLiteral;
|
|
260
232
|
} else this._subject = this._literal(token.value, this._namedNode(token.prefix));
|
|
261
|
-
|
|
262
233
|
break;
|
|
263
|
-
|
|
264
234
|
case '<<':
|
|
265
235
|
if (!this._supportsRDFStar) return this._error('Unexpected RDF* syntax', token);
|
|
266
|
-
|
|
267
236
|
this._saveContext('<<', this._graph, null, null, null);
|
|
268
|
-
|
|
269
237
|
this._graph = null;
|
|
270
238
|
return this._readSubject;
|
|
271
|
-
|
|
272
239
|
default:
|
|
273
240
|
// Read the subject entity
|
|
274
|
-
if ((this._subject = this._readEntity(token)) === undefined) return;
|
|
275
|
-
|
|
241
|
+
if ((this._subject = this._readEntity(token)) === undefined) return;
|
|
242
|
+
// In N3 mode, the subject might be a path
|
|
276
243
|
if (this._n3Mode) return this._getPathReader(this._readPredicateOrNamedGraph);
|
|
277
|
-
}
|
|
278
|
-
// or, if the subject was actually a graph IRI, a named graph
|
|
279
|
-
|
|
244
|
+
}
|
|
280
245
|
|
|
246
|
+
// The next token must be a predicate,
|
|
247
|
+
// or, if the subject was actually a graph IRI, a named graph
|
|
281
248
|
return this._readPredicateOrNamedGraph;
|
|
282
|
-
}
|
|
283
|
-
|
|
249
|
+
}
|
|
284
250
|
|
|
251
|
+
// ### `_readPredicate` reads a quad's predicate
|
|
285
252
|
_readPredicate(token) {
|
|
286
253
|
const type = token.type;
|
|
287
|
-
|
|
288
254
|
switch (type) {
|
|
289
255
|
case 'inverse':
|
|
290
256
|
this._inversePredicate = true;
|
|
291
|
-
|
|
292
257
|
case 'abbreviation':
|
|
293
258
|
this._predicate = this.ABBREVIATIONS[token.value];
|
|
294
259
|
break;
|
|
295
|
-
|
|
296
260
|
case '.':
|
|
297
261
|
case ']':
|
|
298
262
|
case '}':
|
|
@@ -300,31 +264,25 @@ class N3Parser {
|
|
|
300
264
|
if (this._predicate === null) return this._error(`Unexpected ${type}`, token);
|
|
301
265
|
this._subject = null;
|
|
302
266
|
return type === ']' ? this._readBlankNodeTail(token) : this._readPunctuation(token);
|
|
303
|
-
|
|
304
267
|
case ';':
|
|
305
268
|
// Additional semicolons can be safely ignored
|
|
306
269
|
return this._predicate !== null ? this._readPredicate : this._error('Expected predicate but got ;', token);
|
|
307
|
-
|
|
308
270
|
case '[':
|
|
309
271
|
if (this._n3Mode) {
|
|
310
272
|
// Start a new quad with a new blank node as subject
|
|
311
273
|
this._saveContext('blank', this._graph, this._subject, this._subject = this._blankNode(), null);
|
|
312
|
-
|
|
313
274
|
return this._readBlankNodeHead;
|
|
314
275
|
}
|
|
315
|
-
|
|
316
276
|
case 'blank':
|
|
317
277
|
if (!this._n3Mode) return this._error('Disallowed blank node as predicate', token);
|
|
318
|
-
|
|
319
278
|
default:
|
|
320
279
|
if ((this._predicate = this._readEntity(token)) === undefined) return;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
|
|
280
|
+
}
|
|
281
|
+
// The next token must be an object
|
|
324
282
|
return this._readObject;
|
|
325
|
-
}
|
|
326
|
-
|
|
283
|
+
}
|
|
327
284
|
|
|
285
|
+
// ### `_readObject` reads a quad's object
|
|
328
286
|
_readObject(token) {
|
|
329
287
|
switch (token.type) {
|
|
330
288
|
case 'literal':
|
|
@@ -332,64 +290,52 @@ class N3Parser {
|
|
|
332
290
|
if (token.prefix.length === 0) {
|
|
333
291
|
this._literalValue = token.value;
|
|
334
292
|
return this._readDataTypeOrLang;
|
|
335
|
-
}
|
|
293
|
+
}
|
|
294
|
+
// Pre-datatyped string literal (prefix stores the datatype)
|
|
336
295
|
else this._object = this._literal(token.value, this._namedNode(token.prefix));
|
|
337
|
-
|
|
338
296
|
break;
|
|
339
|
-
|
|
340
297
|
case '[':
|
|
341
298
|
// Start a new quad with a new blank node as subject
|
|
342
299
|
this._saveContext('blank', this._graph, this._subject, this._predicate, this._subject = this._blankNode());
|
|
343
|
-
|
|
344
300
|
return this._readBlankNodeHead;
|
|
345
|
-
|
|
346
301
|
case '(':
|
|
347
302
|
// Start a new list
|
|
348
303
|
this._saveContext('list', this._graph, this._subject, this._predicate, this.RDF_NIL);
|
|
349
|
-
|
|
350
304
|
this._subject = null;
|
|
351
305
|
return this._readListItem;
|
|
352
|
-
|
|
353
306
|
case '{':
|
|
354
307
|
// Start a new formula
|
|
355
308
|
if (!this._n3Mode) return this._error('Unexpected graph', token);
|
|
356
|
-
|
|
357
309
|
this._saveContext('formula', this._graph, this._subject, this._predicate, this._graph = this._blankNode());
|
|
358
|
-
|
|
359
310
|
return this._readSubject;
|
|
360
|
-
|
|
361
311
|
case '<<':
|
|
362
312
|
if (!this._supportsRDFStar) return this._error('Unexpected RDF* syntax', token);
|
|
363
|
-
|
|
364
313
|
this._saveContext('<<', this._graph, this._subject, this._predicate, null);
|
|
365
|
-
|
|
366
314
|
this._graph = null;
|
|
367
315
|
return this._readSubject;
|
|
368
|
-
|
|
369
316
|
default:
|
|
370
317
|
// Read the object entity
|
|
371
|
-
if ((this._object = this._readEntity(token)) === undefined) return;
|
|
372
|
-
|
|
318
|
+
if ((this._object = this._readEntity(token)) === undefined) return;
|
|
319
|
+
// In N3 mode, the object might be a path
|
|
373
320
|
if (this._n3Mode) return this._getPathReader(this._getContextEndReader());
|
|
374
321
|
}
|
|
375
|
-
|
|
376
322
|
return this._getContextEndReader();
|
|
377
|
-
}
|
|
378
|
-
|
|
323
|
+
}
|
|
379
324
|
|
|
325
|
+
// ### `_readPredicateOrNamedGraph` reads a quad's predicate, or a named graph
|
|
380
326
|
_readPredicateOrNamedGraph(token) {
|
|
381
327
|
return token.type === '{' ? this._readGraph(token) : this._readPredicate(token);
|
|
382
|
-
}
|
|
383
|
-
|
|
328
|
+
}
|
|
384
329
|
|
|
330
|
+
// ### `_readGraph` reads a graph
|
|
385
331
|
_readGraph(token) {
|
|
386
|
-
if (token.type !== '{') return this._error(`Expected graph but got ${token.type}`, token);
|
|
387
|
-
|
|
332
|
+
if (token.type !== '{') return this._error(`Expected graph but got ${token.type}`, token);
|
|
333
|
+
// The "subject" we read is actually the GRAPH's label
|
|
388
334
|
this._graph = this._subject, this._subject = null;
|
|
389
335
|
return this._readSubject;
|
|
390
|
-
}
|
|
391
|
-
|
|
336
|
+
}
|
|
392
337
|
|
|
338
|
+
// ### `_readBlankNodeHead` reads the head of a blank node
|
|
393
339
|
_readBlankNodeHead(token) {
|
|
394
340
|
if (token.type === ']') {
|
|
395
341
|
this._subject = null;
|
|
@@ -398,26 +344,29 @@ class N3Parser {
|
|
|
398
344
|
this._predicate = null;
|
|
399
345
|
return this._readPredicate(token);
|
|
400
346
|
}
|
|
401
|
-
}
|
|
402
|
-
|
|
347
|
+
}
|
|
403
348
|
|
|
349
|
+
// ### `_readBlankNodeTail` reads the end of a blank node
|
|
404
350
|
_readBlankNodeTail(token) {
|
|
405
|
-
if (token.type !== ']') return this._readBlankNodePunctuation(token);
|
|
351
|
+
if (token.type !== ']') return this._readBlankNodePunctuation(token);
|
|
406
352
|
|
|
407
|
-
|
|
353
|
+
// Store blank node quad
|
|
354
|
+
if (this._subject !== null) this._emit(this._subject, this._predicate, this._object, this._graph);
|
|
408
355
|
|
|
356
|
+
// Restore the parent context containing this blank node
|
|
409
357
|
const empty = this._predicate === null;
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
if (this.
|
|
415
|
-
|
|
416
|
-
else
|
|
358
|
+
this._restoreContext('blank', token);
|
|
359
|
+
// If the blank node was the object, restore previous context and read punctuation
|
|
360
|
+
if (this._object !== null) return this._getContextEndReader();
|
|
361
|
+
// If the blank node was the predicate, continue reading the object
|
|
362
|
+
else if (this._predicate !== null) return this._readObject;
|
|
363
|
+
// If the blank node was the subject, continue reading the predicate
|
|
364
|
+
else
|
|
365
|
+
// If the blank node was empty, it could be a named graph label
|
|
417
366
|
return empty ? this._readPredicateOrNamedGraph : this._readPredicateAfterBlank;
|
|
418
|
-
}
|
|
419
|
-
|
|
367
|
+
}
|
|
420
368
|
|
|
369
|
+
// ### `_readPredicateAfterBlank` reads a predicate after an anonymous blank node
|
|
421
370
|
_readPredicateAfterBlank(token) {
|
|
422
371
|
switch (token.type) {
|
|
423
372
|
case '.':
|
|
@@ -425,203 +374,184 @@ class N3Parser {
|
|
|
425
374
|
// No predicate is coming if the triple is terminated here
|
|
426
375
|
this._subject = null;
|
|
427
376
|
return this._readPunctuation(token);
|
|
428
|
-
|
|
429
377
|
default:
|
|
430
378
|
return this._readPredicate(token);
|
|
431
379
|
}
|
|
432
|
-
}
|
|
433
|
-
|
|
380
|
+
}
|
|
434
381
|
|
|
382
|
+
// ### `_readListItem` reads items from a list
|
|
435
383
|
_readListItem(token) {
|
|
436
384
|
let item = null,
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
385
|
+
// The item of the list
|
|
386
|
+
list = null,
|
|
387
|
+
// The list itself
|
|
388
|
+
next = this._readListItem; // The next function to execute
|
|
442
389
|
const previousList = this._subject,
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
390
|
+
// The previous list that contains this list
|
|
391
|
+
stack = this._contextStack,
|
|
392
|
+
// The stack of parent contexts
|
|
393
|
+
parent = stack[stack.length - 1]; // The parent containing the current list
|
|
447
394
|
|
|
448
395
|
switch (token.type) {
|
|
449
396
|
case '[':
|
|
450
397
|
// Stack the current list quad and start a new quad with a blank node as subject
|
|
451
398
|
this._saveContext('blank', this._graph, list = this._blankNode(), this.RDF_FIRST, this._subject = item = this._blankNode());
|
|
452
|
-
|
|
453
399
|
next = this._readBlankNodeHead;
|
|
454
400
|
break;
|
|
455
|
-
|
|
456
401
|
case '(':
|
|
457
402
|
// Stack the current list quad and start a new list
|
|
458
403
|
this._saveContext('list', this._graph, list = this._blankNode(), this.RDF_FIRST, this.RDF_NIL);
|
|
459
|
-
|
|
460
404
|
this._subject = null;
|
|
461
405
|
break;
|
|
462
|
-
|
|
463
406
|
case ')':
|
|
464
407
|
// Closing the list; restore the parent context
|
|
465
|
-
this._restoreContext('list', token);
|
|
408
|
+
this._restoreContext('list', token);
|
|
409
|
+
// If this list is contained within a parent list, return the membership quad here.
|
|
466
410
|
// This will be `<parent list element> rdf:first <this list>.`.
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
if (stack.length !== 0 && stack[stack.length - 1].type === 'list') this._emit(this._subject, this._predicate, this._object, this._graph); // Was this list the parent's subject?
|
|
470
|
-
|
|
411
|
+
if (stack.length !== 0 && stack[stack.length - 1].type === 'list') this._emit(this._subject, this._predicate, this._object, this._graph);
|
|
412
|
+
// Was this list the parent's subject?
|
|
471
413
|
if (this._predicate === null) {
|
|
472
414
|
// The next token is the predicate
|
|
473
|
-
next = this._readPredicate;
|
|
474
|
-
|
|
415
|
+
next = this._readPredicate;
|
|
416
|
+
// No list tail if this was an empty list
|
|
475
417
|
if (this._subject === this.RDF_NIL) return next;
|
|
476
|
-
}
|
|
418
|
+
}
|
|
419
|
+
// The list was in the parent context's object
|
|
477
420
|
else {
|
|
478
|
-
next = this._getContextEndReader();
|
|
479
|
-
|
|
421
|
+
next = this._getContextEndReader();
|
|
422
|
+
// No list tail if this was an empty list
|
|
480
423
|
if (this._object === this.RDF_NIL) return next;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
|
|
424
|
+
}
|
|
425
|
+
// Close the list by making the head nil
|
|
484
426
|
list = this.RDF_NIL;
|
|
485
427
|
break;
|
|
486
|
-
|
|
487
428
|
case 'literal':
|
|
488
429
|
// Regular literal, can still get a datatype or language
|
|
489
430
|
if (token.prefix.length === 0) {
|
|
490
431
|
this._literalValue = token.value;
|
|
491
432
|
next = this._readListItemDataTypeOrLang;
|
|
492
|
-
}
|
|
433
|
+
}
|
|
434
|
+
// Pre-datatyped string literal (prefix stores the datatype)
|
|
493
435
|
else {
|
|
494
436
|
item = this._literal(token.value, this._namedNode(token.prefix));
|
|
495
437
|
next = this._getContextEndReader();
|
|
496
438
|
}
|
|
497
|
-
|
|
498
439
|
break;
|
|
499
|
-
|
|
500
440
|
case '{':
|
|
501
441
|
// Start a new formula
|
|
502
442
|
if (!this._n3Mode) return this._error('Unexpected graph', token);
|
|
503
|
-
|
|
504
443
|
this._saveContext('formula', this._graph, this._subject, this._predicate, this._graph = this._blankNode());
|
|
505
|
-
|
|
506
444
|
return this._readSubject;
|
|
507
|
-
|
|
508
445
|
default:
|
|
509
446
|
if ((item = this._readEntity(token)) === undefined) return;
|
|
510
|
-
}
|
|
511
|
-
|
|
447
|
+
}
|
|
512
448
|
|
|
513
|
-
|
|
449
|
+
// Create a new blank node if no item head was assigned yet
|
|
450
|
+
if (list === null) this._subject = list = this._blankNode();
|
|
514
451
|
|
|
452
|
+
// Is this the first element of the list?
|
|
515
453
|
if (previousList === null) {
|
|
516
454
|
// This list is either the subject or the object of its parent
|
|
517
455
|
if (parent.predicate === null) parent.subject = list;else parent.object = list;
|
|
518
456
|
} else {
|
|
519
457
|
// Continue the previous list with the current list
|
|
520
458
|
this._emit(previousList, this.RDF_REST, list, this._graph);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
|
|
459
|
+
}
|
|
460
|
+
// If an item was read, add it to the list
|
|
524
461
|
if (item !== null) {
|
|
525
462
|
// In N3 mode, the item might be a path
|
|
526
463
|
if (this._n3Mode && (token.type === 'IRI' || token.type === 'prefixed')) {
|
|
527
464
|
// Create a new context to add the item's path
|
|
528
465
|
this._saveContext('item', this._graph, list, this.RDF_FIRST, item);
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
466
|
+
this._subject = item, this._predicate = null;
|
|
467
|
+
// _readPath will restore the context and output the item
|
|
532
468
|
return this._getPathReader(this._readListItem);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
|
|
469
|
+
}
|
|
470
|
+
// Output the item
|
|
536
471
|
this._emit(list, this.RDF_FIRST, item, this._graph);
|
|
537
472
|
}
|
|
538
|
-
|
|
539
473
|
return next;
|
|
540
|
-
}
|
|
541
|
-
|
|
474
|
+
}
|
|
542
475
|
|
|
476
|
+
// ### `_readDataTypeOrLang` reads an _optional_ datatype or language
|
|
543
477
|
_readDataTypeOrLang(token) {
|
|
544
478
|
return this._completeObjectLiteral(token, false);
|
|
545
|
-
}
|
|
546
|
-
|
|
479
|
+
}
|
|
547
480
|
|
|
481
|
+
// ### `_readListItemDataTypeOrLang` reads an _optional_ datatype or language in a list
|
|
548
482
|
_readListItemDataTypeOrLang(token) {
|
|
549
483
|
return this._completeObjectLiteral(token, true);
|
|
550
|
-
}
|
|
551
|
-
|
|
484
|
+
}
|
|
552
485
|
|
|
486
|
+
// ### `_completeLiteral` completes a literal with an optional datatype or language
|
|
553
487
|
_completeLiteral(token) {
|
|
554
488
|
// Create a simple string literal by default
|
|
555
489
|
let literal = this._literal(this._literalValue);
|
|
556
|
-
|
|
557
490
|
switch (token.type) {
|
|
558
491
|
// Create a datatyped literal
|
|
559
492
|
case 'type':
|
|
560
493
|
case 'typeIRI':
|
|
561
494
|
const datatype = this._readEntity(token);
|
|
562
|
-
|
|
563
495
|
if (datatype === undefined) return; // No datatype means an error occurred
|
|
564
|
-
|
|
565
496
|
literal = this._literal(this._literalValue, datatype);
|
|
566
497
|
token = null;
|
|
567
498
|
break;
|
|
568
499
|
// Create a language-tagged string
|
|
569
|
-
|
|
570
500
|
case 'langcode':
|
|
571
501
|
literal = this._literal(this._literalValue, token.value);
|
|
572
502
|
token = null;
|
|
573
503
|
break;
|
|
574
504
|
}
|
|
575
|
-
|
|
576
505
|
return {
|
|
577
506
|
token,
|
|
578
507
|
literal
|
|
579
508
|
};
|
|
580
|
-
}
|
|
581
|
-
|
|
509
|
+
}
|
|
582
510
|
|
|
511
|
+
// Completes a literal in subject position
|
|
583
512
|
_completeSubjectLiteral(token) {
|
|
584
513
|
this._subject = this._completeLiteral(token).literal;
|
|
585
514
|
return this._readPredicateOrNamedGraph;
|
|
586
|
-
}
|
|
587
|
-
|
|
515
|
+
}
|
|
588
516
|
|
|
517
|
+
// Completes a literal in object position
|
|
589
518
|
_completeObjectLiteral(token, listItem) {
|
|
590
519
|
const completed = this._completeLiteral(token);
|
|
591
|
-
|
|
592
520
|
if (!completed) return;
|
|
593
|
-
this._object = completed.literal;
|
|
594
|
-
// (we could also check the context stack, but passing in a flag is faster)
|
|
521
|
+
this._object = completed.literal;
|
|
595
522
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
if (
|
|
523
|
+
// If this literal was part of a list, write the item
|
|
524
|
+
// (we could also check the context stack, but passing in a flag is faster)
|
|
525
|
+
if (listItem) this._emit(this._subject, this.RDF_FIRST, this._object, this._graph);
|
|
526
|
+
// If the token was consumed, continue with the rest of the input
|
|
527
|
+
if (completed.token === null) return this._getContextEndReader();
|
|
528
|
+
// Otherwise, consume the token now
|
|
599
529
|
else {
|
|
600
530
|
this._readCallback = this._getContextEndReader();
|
|
601
531
|
return this._readCallback(completed.token);
|
|
602
532
|
}
|
|
603
|
-
}
|
|
604
|
-
|
|
533
|
+
}
|
|
605
534
|
|
|
535
|
+
// ### `_readFormulaTail` reads the end of a formula
|
|
606
536
|
_readFormulaTail(token) {
|
|
607
|
-
if (token.type !== '}') return this._readPunctuation(token);
|
|
537
|
+
if (token.type !== '}') return this._readPunctuation(token);
|
|
608
538
|
|
|
609
|
-
|
|
539
|
+
// Store the last quad of the formula
|
|
540
|
+
if (this._subject !== null) this._emit(this._subject, this._predicate, this._object, this._graph);
|
|
610
541
|
|
|
611
|
-
|
|
542
|
+
// Restore the parent context containing this formula
|
|
543
|
+
this._restoreContext('formula', token);
|
|
544
|
+
// If the formula was the subject, continue reading the predicate.
|
|
612
545
|
// If the formula was the object, read punctuation.
|
|
613
|
-
|
|
614
|
-
|
|
615
546
|
return this._object === null ? this._readPredicate : this._getContextEndReader();
|
|
616
|
-
}
|
|
617
|
-
|
|
547
|
+
}
|
|
618
548
|
|
|
549
|
+
// ### `_readPunctuation` reads punctuation between quads or quad parts
|
|
619
550
|
_readPunctuation(token) {
|
|
620
551
|
let next,
|
|
621
|
-
|
|
552
|
+
graph = this._graph;
|
|
622
553
|
const subject = this._subject,
|
|
623
|
-
|
|
624
|
-
|
|
554
|
+
inversePredicate = this._inversePredicate;
|
|
625
555
|
switch (token.type) {
|
|
626
556
|
// A closing brace ends a graph
|
|
627
557
|
case '}':
|
|
@@ -629,325 +559,286 @@ class N3Parser {
|
|
|
629
559
|
if (this._n3Mode) return this._readFormulaTail(token);
|
|
630
560
|
this._graph = null;
|
|
631
561
|
// A dot just ends the statement, without sharing anything with the next
|
|
632
|
-
|
|
633
562
|
case '.':
|
|
634
563
|
this._subject = null;
|
|
635
564
|
next = this._contextStack.length ? this._readSubject : this._readInTopContext;
|
|
636
565
|
if (inversePredicate) this._inversePredicate = false;
|
|
637
566
|
break;
|
|
638
567
|
// Semicolon means the subject is shared; predicate and object are different
|
|
639
|
-
|
|
640
568
|
case ';':
|
|
641
569
|
next = this._readPredicate;
|
|
642
570
|
break;
|
|
643
571
|
// Comma means both the subject and predicate are shared; the object is different
|
|
644
|
-
|
|
645
572
|
case ',':
|
|
646
573
|
next = this._readObject;
|
|
647
574
|
break;
|
|
648
575
|
// {| means that the current triple is annotated with predicate-object pairs.
|
|
649
|
-
|
|
650
576
|
case '{|':
|
|
651
|
-
if (!this._supportsRDFStar) return this._error('Unexpected RDF* syntax', token);
|
|
652
|
-
|
|
577
|
+
if (!this._supportsRDFStar) return this._error('Unexpected RDF* syntax', token);
|
|
578
|
+
// Continue using the last triple as quoted triple subject for the predicate-object pairs.
|
|
653
579
|
const predicate = this._predicate,
|
|
654
|
-
|
|
580
|
+
object = this._object;
|
|
655
581
|
this._subject = this._quad(subject, predicate, object, this.DEFAULTGRAPH);
|
|
656
582
|
next = this._readPredicate;
|
|
657
583
|
break;
|
|
658
584
|
// |} means that the current quoted triple in annotation syntax is finalized.
|
|
659
|
-
|
|
660
585
|
case '|}':
|
|
661
586
|
if (this._subject.termType !== 'Quad') return this._error('Unexpected asserted triple closing', token);
|
|
662
587
|
this._subject = null;
|
|
663
588
|
next = this._readPunctuation;
|
|
664
589
|
break;
|
|
665
|
-
|
|
666
590
|
default:
|
|
667
591
|
// An entity means this is a quad (only allowed if not already inside a graph)
|
|
668
592
|
if (this._supportsQuads && this._graph === null && (graph = this._readEntity(token)) !== undefined) {
|
|
669
593
|
next = this._readQuadPunctuation;
|
|
670
594
|
break;
|
|
671
595
|
}
|
|
672
|
-
|
|
673
596
|
return this._error(`Expected punctuation to follow "${this._object.id}"`, token);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
|
|
597
|
+
}
|
|
598
|
+
// A quad has been completed now, so return it
|
|
677
599
|
if (subject !== null) {
|
|
678
600
|
const predicate = this._predicate,
|
|
679
|
-
|
|
601
|
+
object = this._object;
|
|
680
602
|
if (!inversePredicate) this._emit(subject, predicate, object, graph);else this._emit(object, predicate, subject, graph);
|
|
681
603
|
}
|
|
682
|
-
|
|
683
604
|
return next;
|
|
684
|
-
}
|
|
685
|
-
|
|
605
|
+
}
|
|
686
606
|
|
|
607
|
+
// ### `_readBlankNodePunctuation` reads punctuation in a blank node
|
|
687
608
|
_readBlankNodePunctuation(token) {
|
|
688
609
|
let next;
|
|
689
|
-
|
|
690
610
|
switch (token.type) {
|
|
691
611
|
// Semicolon means the subject is shared; predicate and object are different
|
|
692
612
|
case ';':
|
|
693
613
|
next = this._readPredicate;
|
|
694
614
|
break;
|
|
695
615
|
// Comma means both the subject and predicate are shared; the object is different
|
|
696
|
-
|
|
697
616
|
case ',':
|
|
698
617
|
next = this._readObject;
|
|
699
618
|
break;
|
|
700
|
-
|
|
701
619
|
default:
|
|
702
620
|
return this._error(`Expected punctuation to follow "${this._object.id}"`, token);
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
|
|
621
|
+
}
|
|
622
|
+
// A quad has been completed now, so return it
|
|
706
623
|
this._emit(this._subject, this._predicate, this._object, this._graph);
|
|
707
|
-
|
|
708
624
|
return next;
|
|
709
|
-
}
|
|
710
|
-
|
|
625
|
+
}
|
|
711
626
|
|
|
627
|
+
// ### `_readQuadPunctuation` reads punctuation after a quad
|
|
712
628
|
_readQuadPunctuation(token) {
|
|
713
629
|
if (token.type !== '.') return this._error('Expected dot to follow quad', token);
|
|
714
630
|
return this._readInTopContext;
|
|
715
|
-
}
|
|
716
|
-
|
|
631
|
+
}
|
|
717
632
|
|
|
633
|
+
// ### `_readPrefix` reads the prefix of a prefix declaration
|
|
718
634
|
_readPrefix(token) {
|
|
719
635
|
if (token.type !== 'prefix') return this._error('Expected prefix to follow @prefix', token);
|
|
720
636
|
this._prefix = token.value;
|
|
721
637
|
return this._readPrefixIRI;
|
|
722
|
-
}
|
|
723
|
-
|
|
638
|
+
}
|
|
724
639
|
|
|
640
|
+
// ### `_readPrefixIRI` reads the IRI of a prefix declaration
|
|
725
641
|
_readPrefixIRI(token) {
|
|
726
642
|
if (token.type !== 'IRI') return this._error(`Expected IRI to follow prefix "${this._prefix}:"`, token);
|
|
727
|
-
|
|
728
643
|
const prefixNode = this._readEntity(token);
|
|
729
|
-
|
|
730
644
|
this._prefixes[this._prefix] = prefixNode.value;
|
|
731
|
-
|
|
732
645
|
this._prefixCallback(this._prefix, prefixNode);
|
|
733
|
-
|
|
734
646
|
return this._readDeclarationPunctuation;
|
|
735
|
-
}
|
|
736
|
-
|
|
647
|
+
}
|
|
737
648
|
|
|
649
|
+
// ### `_readBaseIRI` reads the IRI of a base declaration
|
|
738
650
|
_readBaseIRI(token) {
|
|
739
651
|
const iri = token.type === 'IRI' && this._resolveIRI(token.value);
|
|
740
|
-
|
|
741
652
|
if (!iri) return this._error('Expected valid IRI to follow base declaration', token);
|
|
742
|
-
|
|
743
653
|
this._setBase(iri);
|
|
744
|
-
|
|
745
654
|
return this._readDeclarationPunctuation;
|
|
746
|
-
}
|
|
747
|
-
|
|
655
|
+
}
|
|
748
656
|
|
|
657
|
+
// ### `_readNamedGraphLabel` reads the label of a named graph
|
|
749
658
|
_readNamedGraphLabel(token) {
|
|
750
659
|
switch (token.type) {
|
|
751
660
|
case 'IRI':
|
|
752
661
|
case 'blank':
|
|
753
662
|
case 'prefixed':
|
|
754
663
|
return this._readSubject(token), this._readGraph;
|
|
755
|
-
|
|
756
664
|
case '[':
|
|
757
665
|
return this._readNamedGraphBlankLabel;
|
|
758
|
-
|
|
759
666
|
default:
|
|
760
667
|
return this._error('Invalid graph label', token);
|
|
761
668
|
}
|
|
762
|
-
}
|
|
763
|
-
|
|
669
|
+
}
|
|
764
670
|
|
|
671
|
+
// ### `_readNamedGraphLabel` reads a blank node label of a named graph
|
|
765
672
|
_readNamedGraphBlankLabel(token) {
|
|
766
673
|
if (token.type !== ']') return this._error('Invalid graph label', token);
|
|
767
674
|
this._subject = this._blankNode();
|
|
768
675
|
return this._readGraph;
|
|
769
|
-
}
|
|
770
|
-
|
|
676
|
+
}
|
|
771
677
|
|
|
678
|
+
// ### `_readDeclarationPunctuation` reads the punctuation of a declaration
|
|
772
679
|
_readDeclarationPunctuation(token) {
|
|
773
680
|
// SPARQL-style declarations don't have punctuation
|
|
774
681
|
if (this._sparqlStyle) {
|
|
775
682
|
this._sparqlStyle = false;
|
|
776
683
|
return this._readInTopContext(token);
|
|
777
684
|
}
|
|
778
|
-
|
|
779
685
|
if (token.type !== '.') return this._error('Expected declaration to end with a dot', token);
|
|
780
686
|
return this._readInTopContext;
|
|
781
|
-
}
|
|
782
|
-
|
|
687
|
+
}
|
|
783
688
|
|
|
689
|
+
// Reads a list of quantified symbols from a @forSome or @forAll statement
|
|
784
690
|
_readQuantifierList(token) {
|
|
785
691
|
let entity;
|
|
786
|
-
|
|
787
692
|
switch (token.type) {
|
|
788
693
|
case 'IRI':
|
|
789
694
|
case 'prefixed':
|
|
790
695
|
if ((entity = this._readEntity(token, true)) !== undefined) break;
|
|
791
|
-
|
|
792
696
|
default:
|
|
793
697
|
return this._error(`Unexpected ${token.type}`, token);
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
698
|
+
}
|
|
699
|
+
// Without explicit quantifiers, map entities to a quantified entity
|
|
700
|
+
if (!this._explicitQuantifiers) this._quantified[entity.id] = this._quantifier(this._blankNode().value);
|
|
701
|
+
// With explicit quantifiers, output the reified quantifier
|
|
798
702
|
else {
|
|
799
703
|
// If this is the first item, start a new quantifier list
|
|
800
|
-
if (this._subject === null) this._emit(this._graph || this.DEFAULTGRAPH, this._predicate, this._subject = this._blankNode(), this.QUANTIFIERS_GRAPH);
|
|
801
|
-
|
|
802
|
-
|
|
704
|
+
if (this._subject === null) this._emit(this._graph || this.DEFAULTGRAPH, this._predicate, this._subject = this._blankNode(), this.QUANTIFIERS_GRAPH);
|
|
705
|
+
// Otherwise, continue the previous list
|
|
706
|
+
else this._emit(this._subject, this.RDF_REST, this._subject = this._blankNode(), this.QUANTIFIERS_GRAPH);
|
|
707
|
+
// Output the list item
|
|
803
708
|
this._emit(this._subject, this.RDF_FIRST, entity, this.QUANTIFIERS_GRAPH);
|
|
804
709
|
}
|
|
805
710
|
return this._readQuantifierPunctuation;
|
|
806
|
-
}
|
|
807
|
-
|
|
711
|
+
}
|
|
808
712
|
|
|
713
|
+
// Reads punctuation from a @forSome or @forAll statement
|
|
809
714
|
_readQuantifierPunctuation(token) {
|
|
810
715
|
// Read more quantifiers
|
|
811
|
-
if (token.type === ',') return this._readQuantifierList;
|
|
716
|
+
if (token.type === ',') return this._readQuantifierList;
|
|
717
|
+
// End of the quantifier list
|
|
812
718
|
else {
|
|
813
719
|
// With explicit quantifiers, close the quantifier list
|
|
814
720
|
if (this._explicitQuantifiers) {
|
|
815
721
|
this._emit(this._subject, this.RDF_REST, this.RDF_NIL, this.QUANTIFIERS_GRAPH);
|
|
816
|
-
|
|
817
722
|
this._subject = null;
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
|
|
723
|
+
}
|
|
724
|
+
// Read a dot
|
|
821
725
|
this._readCallback = this._getContextEndReader();
|
|
822
726
|
return this._readCallback(token);
|
|
823
727
|
}
|
|
824
|
-
}
|
|
825
|
-
|
|
728
|
+
}
|
|
826
729
|
|
|
730
|
+
// ### `_getPathReader` reads a potential path and then resumes with the given function
|
|
827
731
|
_getPathReader(afterPath) {
|
|
828
732
|
this._afterPath = afterPath;
|
|
829
733
|
return this._readPath;
|
|
830
|
-
}
|
|
831
|
-
|
|
734
|
+
}
|
|
832
735
|
|
|
736
|
+
// ### `_readPath` reads a potential path
|
|
833
737
|
_readPath(token) {
|
|
834
738
|
switch (token.type) {
|
|
835
739
|
// Forward path
|
|
836
740
|
case '!':
|
|
837
741
|
return this._readForwardPath;
|
|
838
742
|
// Backward path
|
|
839
|
-
|
|
840
743
|
case '^':
|
|
841
744
|
return this._readBackwardPath;
|
|
842
745
|
// Not a path; resume reading where we left off
|
|
843
|
-
|
|
844
746
|
default:
|
|
845
747
|
const stack = this._contextStack,
|
|
846
|
-
|
|
847
|
-
|
|
748
|
+
parent = stack.length && stack[stack.length - 1];
|
|
749
|
+
// If we were reading a list item, we still need to output it
|
|
848
750
|
if (parent && parent.type === 'item') {
|
|
849
751
|
// The list item is the remaining subejct after reading the path
|
|
850
|
-
const item = this._subject;
|
|
851
|
-
|
|
852
|
-
this._restoreContext('item', token);
|
|
853
|
-
|
|
854
|
-
|
|
752
|
+
const item = this._subject;
|
|
753
|
+
// Switch back to the context of the list
|
|
754
|
+
this._restoreContext('item', token);
|
|
755
|
+
// Output the list item
|
|
855
756
|
this._emit(this._subject, this.RDF_FIRST, item, this._graph);
|
|
856
757
|
}
|
|
857
|
-
|
|
858
758
|
return this._afterPath(token);
|
|
859
759
|
}
|
|
860
|
-
}
|
|
861
|
-
|
|
760
|
+
}
|
|
862
761
|
|
|
762
|
+
// ### `_readForwardPath` reads a '!' path
|
|
863
763
|
_readForwardPath(token) {
|
|
864
764
|
let subject, predicate;
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
if (
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
765
|
+
const object = this._blankNode();
|
|
766
|
+
// The next token is the predicate
|
|
767
|
+
if ((predicate = this._readEntity(token)) === undefined) return;
|
|
768
|
+
// If we were reading a subject, replace the subject by the path's object
|
|
769
|
+
if (this._predicate === null) subject = this._subject, this._subject = object;
|
|
770
|
+
// If we were reading an object, replace the subject by the path's object
|
|
771
|
+
else subject = this._object, this._object = object;
|
|
772
|
+
// Emit the path's current quad and read its next section
|
|
874
773
|
this._emit(subject, predicate, object, this._graph);
|
|
875
|
-
|
|
876
774
|
return this._readPath;
|
|
877
|
-
}
|
|
878
|
-
|
|
775
|
+
}
|
|
879
776
|
|
|
777
|
+
// ### `_readBackwardPath` reads a '^' path
|
|
880
778
|
_readBackwardPath(token) {
|
|
881
779
|
const subject = this._blankNode();
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
else object = this._object, this._object = subject;
|
|
889
|
-
|
|
780
|
+
let predicate, object;
|
|
781
|
+
// The next token is the predicate
|
|
782
|
+
if ((predicate = this._readEntity(token)) === undefined) return;
|
|
783
|
+
// If we were reading a subject, replace the subject by the path's subject
|
|
784
|
+
if (this._predicate === null) object = this._subject, this._subject = subject;
|
|
785
|
+
// If we were reading an object, replace the subject by the path's subject
|
|
786
|
+
else object = this._object, this._object = subject;
|
|
787
|
+
// Emit the path's current quad and read its next section
|
|
890
788
|
this._emit(subject, predicate, object, this._graph);
|
|
891
|
-
|
|
892
789
|
return this._readPath;
|
|
893
|
-
}
|
|
894
|
-
|
|
790
|
+
}
|
|
895
791
|
|
|
792
|
+
// ### `_readRDFStarTailOrGraph` reads the graph of a nested RDF* quad or the end of a nested RDF* triple
|
|
896
793
|
_readRDFStarTailOrGraph(token) {
|
|
897
794
|
if (token.type !== '>>') {
|
|
898
795
|
// An entity means this is a quad (only allowed if not already inside a graph)
|
|
899
796
|
if (this._supportsQuads && this._graph === null && (this._graph = this._readEntity(token)) !== undefined) return this._readRDFStarTail;
|
|
900
797
|
return this._error(`Expected >> to follow "${this._object.id}"`, token);
|
|
901
798
|
}
|
|
902
|
-
|
|
903
799
|
return this._readRDFStarTail(token);
|
|
904
|
-
}
|
|
905
|
-
|
|
800
|
+
}
|
|
906
801
|
|
|
802
|
+
// ### `_readRDFStarTail` reads the end of a nested RDF* triple
|
|
907
803
|
_readRDFStarTail(token) {
|
|
908
|
-
if (token.type !== '>>') return this._error(`Expected >> but got ${token.type}`, token);
|
|
909
|
-
|
|
804
|
+
if (token.type !== '>>') return this._error(`Expected >> but got ${token.type}`, token);
|
|
805
|
+
// Read the quad and restore the previous context
|
|
910
806
|
const quad = this._quad(this._subject, this._predicate, this._object, this._graph || this.DEFAULTGRAPH);
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
807
|
+
this._restoreContext('<<', token);
|
|
808
|
+
// If the triple was the subject, continue by reading the predicate.
|
|
915
809
|
if (this._subject === null) {
|
|
916
810
|
this._subject = quad;
|
|
917
811
|
return this._readPredicate;
|
|
918
|
-
}
|
|
812
|
+
}
|
|
813
|
+
// If the triple was the object, read context end.
|
|
919
814
|
else {
|
|
920
815
|
this._object = quad;
|
|
921
816
|
return this._getContextEndReader();
|
|
922
817
|
}
|
|
923
|
-
}
|
|
924
|
-
|
|
818
|
+
}
|
|
925
819
|
|
|
820
|
+
// ### `_getContextEndReader` gets the next reader function at the end of a context
|
|
926
821
|
_getContextEndReader() {
|
|
927
822
|
const contextStack = this._contextStack;
|
|
928
823
|
if (!contextStack.length) return this._readPunctuation;
|
|
929
|
-
|
|
930
824
|
switch (contextStack[contextStack.length - 1].type) {
|
|
931
825
|
case 'blank':
|
|
932
826
|
return this._readBlankNodeTail;
|
|
933
|
-
|
|
934
827
|
case 'list':
|
|
935
828
|
return this._readListItem;
|
|
936
|
-
|
|
937
829
|
case 'formula':
|
|
938
830
|
return this._readFormulaTail;
|
|
939
|
-
|
|
940
831
|
case '<<':
|
|
941
832
|
return this._readRDFStarTailOrGraph;
|
|
942
833
|
}
|
|
943
|
-
}
|
|
944
|
-
|
|
834
|
+
}
|
|
945
835
|
|
|
836
|
+
// ### `_emit` sends a quad through the callback
|
|
946
837
|
_emit(subject, predicate, object, graph) {
|
|
947
838
|
this._callback(null, this._quad(subject, predicate, object, graph || this.DEFAULTGRAPH));
|
|
948
|
-
}
|
|
949
|
-
|
|
839
|
+
}
|
|
950
840
|
|
|
841
|
+
// ### `_error` emits an error message through the callback
|
|
951
842
|
_error(message, token) {
|
|
952
843
|
const err = new Error(`${message} on line ${token.line}.`);
|
|
953
844
|
err.context = {
|
|
@@ -955,79 +846,71 @@ class N3Parser {
|
|
|
955
846
|
line: token.line,
|
|
956
847
|
previousToken: this._lexer.previousToken
|
|
957
848
|
};
|
|
958
|
-
|
|
959
849
|
this._callback(err);
|
|
960
|
-
|
|
961
850
|
this._callback = noop;
|
|
962
|
-
}
|
|
963
|
-
|
|
851
|
+
}
|
|
964
852
|
|
|
853
|
+
// ### `_resolveIRI` resolves an IRI against the base path
|
|
965
854
|
_resolveIRI(iri) {
|
|
966
855
|
return /^[a-z][a-z0-9+.-]*:/i.test(iri) ? iri : this._resolveRelativeIRI(iri);
|
|
967
|
-
}
|
|
968
|
-
// assuming that a base path has been set and that the IRI is indeed relative
|
|
969
|
-
|
|
856
|
+
}
|
|
970
857
|
|
|
858
|
+
// ### `_resolveRelativeIRI` resolves an IRI against the base path,
|
|
859
|
+
// assuming that a base path has been set and that the IRI is indeed relative
|
|
971
860
|
_resolveRelativeIRI(iri) {
|
|
972
861
|
// An empty relative IRI indicates the base IRI
|
|
973
|
-
if (!iri.length) return this._base;
|
|
974
|
-
|
|
862
|
+
if (!iri.length) return this._base;
|
|
863
|
+
// Decide resolving strategy based in the first character
|
|
975
864
|
switch (iri[0]) {
|
|
976
865
|
// Resolve relative fragment IRIs against the base IRI
|
|
977
866
|
case '#':
|
|
978
867
|
return this._base + iri;
|
|
979
868
|
// Resolve relative query string IRIs by replacing the query string
|
|
980
|
-
|
|
981
869
|
case '?':
|
|
982
870
|
return this._base.replace(/(?:\?.*)?$/, iri);
|
|
983
871
|
// Resolve root-relative IRIs at the root of the base IRI
|
|
984
|
-
|
|
985
872
|
case '/':
|
|
986
873
|
// Resolve scheme-relative IRIs to the scheme
|
|
987
874
|
return (iri[1] === '/' ? this._baseScheme : this._baseRoot) + this._removeDotSegments(iri);
|
|
988
875
|
// Resolve all other IRIs at the base IRI's path
|
|
989
|
-
|
|
990
876
|
default:
|
|
991
877
|
// Relative IRIs cannot contain a colon in the first path segment
|
|
992
878
|
return /^[^/:]*:/.test(iri) ? null : this._removeDotSegments(this._basePath + iri);
|
|
993
879
|
}
|
|
994
|
-
}
|
|
995
|
-
|
|
880
|
+
}
|
|
996
881
|
|
|
882
|
+
// ### `_removeDotSegments` resolves './' and '../' path segments in an IRI as per RFC3986
|
|
997
883
|
_removeDotSegments(iri) {
|
|
998
884
|
// Don't modify the IRI if it does not contain any dot segments
|
|
999
|
-
if (!/(^|\/)\.\.?($|[/#?])/.test(iri)) return iri;
|
|
885
|
+
if (!/(^|\/)\.\.?($|[/#?])/.test(iri)) return iri;
|
|
1000
886
|
|
|
887
|
+
// Start with an imaginary slash before the IRI in order to resolve trailing './' and '../'
|
|
1001
888
|
const length = iri.length;
|
|
1002
889
|
let result = '',
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
890
|
+
i = -1,
|
|
891
|
+
pathStart = -1,
|
|
892
|
+
segmentStart = 0,
|
|
893
|
+
next = '/';
|
|
1008
894
|
while (i < length) {
|
|
1009
895
|
switch (next) {
|
|
1010
896
|
// The path starts with the first slash after the authority
|
|
1011
897
|
case ':':
|
|
1012
898
|
if (pathStart < 0) {
|
|
1013
899
|
// Skip two slashes before the authority
|
|
1014
|
-
if (iri[++i] === '/' && iri[++i] === '/')
|
|
900
|
+
if (iri[++i] === '/' && iri[++i] === '/')
|
|
901
|
+
// Skip to slash after the authority
|
|
1015
902
|
while ((pathStart = i + 1) < length && iri[pathStart] !== '/') i = pathStart;
|
|
1016
903
|
}
|
|
1017
|
-
|
|
1018
904
|
break;
|
|
1019
905
|
// Don't modify a query string or fragment
|
|
1020
|
-
|
|
1021
906
|
case '?':
|
|
1022
907
|
case '#':
|
|
1023
908
|
i = length;
|
|
1024
909
|
break;
|
|
1025
910
|
// Handle '/.' or '/..' path segments
|
|
1026
|
-
|
|
1027
911
|
case '/':
|
|
1028
912
|
if (iri[i + 1] === '.') {
|
|
1029
913
|
next = iri[++i + 1];
|
|
1030
|
-
|
|
1031
914
|
switch (next) {
|
|
1032
915
|
// Remove a '/.' segment
|
|
1033
916
|
case '/':
|
|
@@ -1035,38 +918,32 @@ class N3Parser {
|
|
|
1035
918
|
segmentStart = i + 1;
|
|
1036
919
|
break;
|
|
1037
920
|
// Remove a trailing '/.' segment
|
|
1038
|
-
|
|
1039
921
|
case undefined:
|
|
1040
922
|
case '?':
|
|
1041
923
|
case '#':
|
|
1042
924
|
return result + iri.substring(segmentStart, i) + iri.substr(i + 1);
|
|
1043
925
|
// Remove a '/..' segment
|
|
1044
|
-
|
|
1045
926
|
case '.':
|
|
1046
927
|
next = iri[++i + 1];
|
|
1047
|
-
|
|
1048
928
|
if (next === undefined || next === '/' || next === '?' || next === '#') {
|
|
1049
|
-
result += iri.substring(segmentStart, i - 2);
|
|
1050
|
-
|
|
1051
|
-
if ((segmentStart = result.lastIndexOf('/')) >= pathStart) result = result.substr(0, segmentStart);
|
|
1052
|
-
|
|
929
|
+
result += iri.substring(segmentStart, i - 2);
|
|
930
|
+
// Try to remove the parent path from result
|
|
931
|
+
if ((segmentStart = result.lastIndexOf('/')) >= pathStart) result = result.substr(0, segmentStart);
|
|
932
|
+
// Remove a trailing '/..' segment
|
|
1053
933
|
if (next !== '/') return `${result}/${iri.substr(i + 1)}`;
|
|
1054
934
|
segmentStart = i + 1;
|
|
1055
935
|
}
|
|
1056
|
-
|
|
1057
936
|
}
|
|
1058
937
|
}
|
|
1059
|
-
|
|
1060
938
|
}
|
|
1061
|
-
|
|
1062
939
|
next = iri[++i];
|
|
1063
940
|
}
|
|
1064
|
-
|
|
1065
941
|
return result + iri.substring(segmentStart);
|
|
1066
|
-
}
|
|
1067
|
-
// ### `parse` parses the N3 input and emits each parsed quad through the callback
|
|
942
|
+
}
|
|
1068
943
|
|
|
944
|
+
// ## Public methods
|
|
1069
945
|
|
|
946
|
+
// ### `parse` parses the N3 input and emits each parsed quad through the callback
|
|
1070
947
|
parse(input, quadCallback, prefixCallback) {
|
|
1071
948
|
// The read callback is the next function to be executed when a token arrives.
|
|
1072
949
|
// We start reading in the top context.
|
|
@@ -1076,40 +953,35 @@ class N3Parser {
|
|
|
1076
953
|
this._prefixes._ = this._blankNodePrefix ? this._blankNodePrefix.substr(2) : `b${blankNodePrefix++}_`;
|
|
1077
954
|
this._prefixCallback = prefixCallback || noop;
|
|
1078
955
|
this._inversePredicate = false;
|
|
1079
|
-
this._quantified = Object.create(null);
|
|
956
|
+
this._quantified = Object.create(null);
|
|
1080
957
|
|
|
958
|
+
// Parse synchronously if no quad callback is given
|
|
1081
959
|
if (!quadCallback) {
|
|
1082
960
|
const quads = [];
|
|
1083
961
|
let error;
|
|
1084
|
-
|
|
1085
962
|
this._callback = (e, t) => {
|
|
1086
963
|
e ? error = e : t && quads.push(t);
|
|
1087
964
|
};
|
|
1088
|
-
|
|
1089
965
|
this._lexer.tokenize(input).every(token => {
|
|
1090
966
|
return this._readCallback = this._readCallback(token);
|
|
1091
967
|
});
|
|
1092
|
-
|
|
1093
968
|
if (error) throw error;
|
|
1094
969
|
return quads;
|
|
1095
|
-
}
|
|
1096
|
-
|
|
970
|
+
}
|
|
1097
971
|
|
|
972
|
+
// Parse asynchronously otherwise, executing the read callback when a token arrives
|
|
1098
973
|
this._callback = quadCallback;
|
|
1099
|
-
|
|
1100
974
|
this._lexer.tokenize(input, (error, token) => {
|
|
1101
975
|
if (error !== null) this._callback(error), this._callback = noop;else if (this._readCallback) this._readCallback = this._readCallback(token);
|
|
1102
976
|
});
|
|
1103
977
|
}
|
|
978
|
+
}
|
|
1104
979
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
980
|
+
// The empty function
|
|
1108
981
|
exports.default = N3Parser;
|
|
982
|
+
function noop() {}
|
|
1109
983
|
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
984
|
+
// Initializes the parser with the given data factory
|
|
1113
985
|
function initDataFactory(parser, factory) {
|
|
1114
986
|
// Set factory methods
|
|
1115
987
|
const namedNode = factory.namedNode;
|
|
@@ -1118,8 +990,9 @@ function initDataFactory(parser, factory) {
|
|
|
1118
990
|
parser._literal = factory.literal;
|
|
1119
991
|
parser._variable = factory.variable;
|
|
1120
992
|
parser._quad = factory.quad;
|
|
1121
|
-
parser.DEFAULTGRAPH = factory.defaultGraph();
|
|
993
|
+
parser.DEFAULTGRAPH = factory.defaultGraph();
|
|
1122
994
|
|
|
995
|
+
// Set common named nodes
|
|
1123
996
|
parser.RDF_FIRST = namedNode(_IRIs.default.rdf.first);
|
|
1124
997
|
parser.RDF_REST = namedNode(_IRIs.default.rdf.rest);
|
|
1125
998
|
parser.RDF_NIL = namedNode(_IRIs.default.rdf.nil);
|
|
@@ -1132,5 +1005,4 @@ function initDataFactory(parser, factory) {
|
|
|
1132
1005
|
};
|
|
1133
1006
|
parser.QUANTIFIERS_GRAPH = namedNode('urn:n3:quantifiers');
|
|
1134
1007
|
}
|
|
1135
|
-
|
|
1136
1008
|
initDataFactory(N3Parser.prototype, _N3DataFactory.default);
|