n3 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +2 -3
- package/browser/n3.esm.min.js +5 -5
- package/browser/n3.min.js +1 -1
- package/lib/N3Parser.js +82 -41
- package/package.json +1 -1
- package/src/N3Parser.js +93 -40
package/lib/N3Parser.js
CHANGED
|
@@ -97,7 +97,7 @@ class N3Parser {
|
|
|
97
97
|
});
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
|
-
|
|
100
|
+
const context = {
|
|
101
101
|
type,
|
|
102
102
|
subject,
|
|
103
103
|
predicate,
|
|
@@ -107,7 +107,14 @@ class N3Parser {
|
|
|
107
107
|
blankPrefix: this._prefixes._,
|
|
108
108
|
quantified: this._quantified,
|
|
109
109
|
emptyFormula: this._emptyFormula
|
|
110
|
-
}
|
|
110
|
+
};
|
|
111
|
+
// Prefix and base declarations are scoped to their formula
|
|
112
|
+
if (type === 'formula') {
|
|
113
|
+
context.prefixes = this._prefixes;
|
|
114
|
+
context.base = [this._base, this._basePath, this._baseRoot, this._baseScheme];
|
|
115
|
+
this._prefixes = Object.create(this._prefixes);
|
|
116
|
+
}
|
|
117
|
+
this._contextStack.push(context);
|
|
111
118
|
// Every new scope resets the predicate direction
|
|
112
119
|
this._inversePredicate = false;
|
|
113
120
|
// In N3, blank nodes are scoped to a formula
|
|
@@ -138,7 +145,10 @@ class N3Parser {
|
|
|
138
145
|
// Restore N3 context settings
|
|
139
146
|
if (this._n3Mode) {
|
|
140
147
|
this._inversePredicate = context.inverse;
|
|
141
|
-
|
|
148
|
+
if (type === 'formula') {
|
|
149
|
+
this._prefixes = context.prefixes;
|
|
150
|
+
[this._base, this._basePath, this._baseRoot, this._baseScheme] = context.base;
|
|
151
|
+
} else this._prefixes._ = context.blankPrefix;
|
|
142
152
|
this._quantified = context.quantified;
|
|
143
153
|
this._emptyFormula = context.emptyFormula;
|
|
144
154
|
}
|
|
@@ -188,6 +198,28 @@ class N3Parser {
|
|
|
188
198
|
}
|
|
189
199
|
}
|
|
190
200
|
|
|
201
|
+
// ### `_readInFormulaContext` reads a token at the statement level of a formula
|
|
202
|
+
_readInFormulaContext(token) {
|
|
203
|
+
switch (token.type) {
|
|
204
|
+
case 'PREFIX':
|
|
205
|
+
this._sparqlStyle = true;
|
|
206
|
+
case '@prefix':
|
|
207
|
+
return this._readPrefix;
|
|
208
|
+
case 'BASE':
|
|
209
|
+
this._sparqlStyle = true;
|
|
210
|
+
case '@base':
|
|
211
|
+
return this._readBaseIRI;
|
|
212
|
+
default:
|
|
213
|
+
return this._readSubject(token);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ### `_getStatementReader` returns the reader for the current statement scope
|
|
218
|
+
_getStatementReader() {
|
|
219
|
+
const context = this._contextStack[this._contextStack.length - 1];
|
|
220
|
+
return context && context.type === 'formula' ? this._readInFormulaContext : this._readInTopContext;
|
|
221
|
+
}
|
|
222
|
+
|
|
191
223
|
// ### `_readEntity` reads an IRI, prefixed name, blank node, or variable
|
|
192
224
|
_readEntity(token, quantifier) {
|
|
193
225
|
let value;
|
|
@@ -252,7 +284,7 @@ class N3Parser {
|
|
|
252
284
|
// Start a new formula
|
|
253
285
|
if (!this._n3Mode) return this._error('Unexpected graph', token);
|
|
254
286
|
this._saveContext('formula', this._graph, this._graph = this._factory.blankNode(), null, null);
|
|
255
|
-
return this.
|
|
287
|
+
return this._readInFormulaContext;
|
|
256
288
|
case '}':
|
|
257
289
|
// No subject; the graph in which we are reading is closed instead
|
|
258
290
|
return this._readPunctuation(token);
|
|
@@ -302,6 +334,7 @@ class N3Parser {
|
|
|
302
334
|
// ### `_readPredicate` reads a quad's predicate
|
|
303
335
|
_readPredicate(token) {
|
|
304
336
|
const type = token.type;
|
|
337
|
+
let pathable = false;
|
|
305
338
|
switch (type) {
|
|
306
339
|
case 'inverse':
|
|
307
340
|
this._inversePredicate = true;
|
|
@@ -326,6 +359,7 @@ class N3Parser {
|
|
|
326
359
|
this._literalValue = token.value;
|
|
327
360
|
return this._completePredicateLiteral;
|
|
328
361
|
} else this._predicate = this._factory.literal(token.value, this._factory.namedNode(token.prefix));
|
|
362
|
+
pathable = true;
|
|
329
363
|
break;
|
|
330
364
|
case '(':
|
|
331
365
|
// In N3, a list can be a predicate
|
|
@@ -336,14 +370,23 @@ class N3Parser {
|
|
|
336
370
|
this._saveContext('blank', this._graph, this._subject, this._subject = this._factory.blankNode(), null);
|
|
337
371
|
return this._readBlankNodeHead;
|
|
338
372
|
}
|
|
373
|
+
return this._error('Disallowed blank node as predicate', token);
|
|
374
|
+
case '{':
|
|
375
|
+
// In N3, a formula can be a predicate
|
|
376
|
+
if (this._n3Mode) {
|
|
377
|
+
this._saveContext('formula', this._graph, this._subject, this._graph = this._factory.blankNode(), null);
|
|
378
|
+
return this._readSubject;
|
|
379
|
+
}
|
|
380
|
+
return this._readEntity(token);
|
|
339
381
|
case 'blank':
|
|
340
382
|
if (!this._n3Mode) return this._error('Disallowed blank node as predicate', token);
|
|
341
383
|
default:
|
|
342
384
|
if ((this._predicate = this._readEntity(token)) === undefined) return;
|
|
385
|
+
pathable = this._n3Mode;
|
|
343
386
|
}
|
|
344
387
|
this._validAnnotation = true;
|
|
345
388
|
// The next token must be an object
|
|
346
|
-
return this._readObject;
|
|
389
|
+
return pathable ? this._getPathReader(this._readObject, 'predicate') : this._readObject;
|
|
347
390
|
}
|
|
348
391
|
|
|
349
392
|
// ### `_readObject` reads a quad's object
|
|
@@ -372,7 +415,7 @@ class N3Parser {
|
|
|
372
415
|
// Start a new formula
|
|
373
416
|
if (!this._n3Mode) return this._error('Unexpected graph', token);
|
|
374
417
|
this._saveContext('formula', this._graph, this._subject, this._predicate, this._graph = this._factory.blankNode());
|
|
375
|
-
return this.
|
|
418
|
+
return this._readInFormulaContext;
|
|
376
419
|
case '<<(':
|
|
377
420
|
this._saveContext('<<(', this._graph, this._subject, this._predicate, null);
|
|
378
421
|
this._graph = null;
|
|
@@ -432,7 +475,7 @@ class N3Parser {
|
|
|
432
475
|
// If the blank node was the object, restore previous context and read punctuation
|
|
433
476
|
if (this._object !== null) return this._getContextEndReader();
|
|
434
477
|
// If the blank node was the predicate, continue reading the object
|
|
435
|
-
else if (this._predicate !== null) return this._readObject;
|
|
478
|
+
else if (this._predicate !== null) return this._getPathReader(this._readObject, 'predicate');
|
|
436
479
|
// If the blank node was the subject, continue reading the predicate
|
|
437
480
|
else
|
|
438
481
|
// If the blank node was empty, it could be a named graph label
|
|
@@ -504,7 +547,7 @@ class N3Parser {
|
|
|
504
547
|
// Was this list the parent's predicate?
|
|
505
548
|
else if (this._object === null) {
|
|
506
549
|
// The next token is the object
|
|
507
|
-
next = this._readObject;
|
|
550
|
+
next = this._getPathReader(this._readObject, 'predicate');
|
|
508
551
|
// No list tail if this was an empty list
|
|
509
552
|
if (this._predicate === this.RDF_NIL) return next;
|
|
510
553
|
}
|
|
@@ -551,7 +594,7 @@ class N3Parser {
|
|
|
551
594
|
// Stack the current list quad and start the formula
|
|
552
595
|
this._saveContext('formula', this._graph, list, this.RDF_FIRST, this._graph = item);
|
|
553
596
|
this._subject = null;
|
|
554
|
-
return this.
|
|
597
|
+
return this._readInFormulaContext;
|
|
555
598
|
case '<<(':
|
|
556
599
|
this._saveContext('<<(', this._graph, null, null, null);
|
|
557
600
|
this._graph = null;
|
|
@@ -662,12 +705,12 @@ class N3Parser {
|
|
|
662
705
|
this._literalLanguage = undefined;
|
|
663
706
|
token = null;
|
|
664
707
|
}
|
|
665
|
-
if (component === 'subject') {
|
|
666
|
-
// A subject literal implies N3 mode, so
|
|
667
|
-
const
|
|
668
|
-
|
|
708
|
+
if (component === 'subject' || component === 'predicate') {
|
|
709
|
+
// A subject or predicate literal implies N3 mode, so it might start a path
|
|
710
|
+
const next = component === 'subject' ? this._readPredicateOrNamedGraph : this._readObject;
|
|
711
|
+
const reader = this._getPathEndReader(token, next, component);
|
|
712
|
+
return reader || next.call(this, token);
|
|
669
713
|
}
|
|
670
|
-
if (component === 'predicate') return token === null ? this._readObject : this._readObject(token);
|
|
671
714
|
return this._completeObjectLiteralPost(token, listItem);
|
|
672
715
|
}
|
|
673
716
|
|
|
@@ -691,15 +734,12 @@ class N3Parser {
|
|
|
691
734
|
return this._readDirCode;
|
|
692
735
|
}
|
|
693
736
|
|
|
694
|
-
// A subject literal implies N3 mode, so it might start a path.
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
if (reader) return reader;
|
|
698
|
-
}
|
|
737
|
+
// A subject or predicate literal implies N3 mode, so it might start a path.
|
|
738
|
+
const reader = this._getPathEndReader(completed.token, next, component);
|
|
739
|
+
if (reader) return reader;
|
|
699
740
|
|
|
700
|
-
//
|
|
701
|
-
|
|
702
|
-
return completed.token === null ? next : next.call(this, completed.token);
|
|
741
|
+
// Consume the non-path token now
|
|
742
|
+
return next.call(this, completed.token);
|
|
703
743
|
}
|
|
704
744
|
|
|
705
745
|
// Completes a literal in subject position
|
|
@@ -764,12 +804,13 @@ class N3Parser {
|
|
|
764
804
|
// is read as the boolean literal true, following the N3 spec tests
|
|
765
805
|
// and the direction discussed in https://github.com/w3c-cg/N3/issues/185
|
|
766
806
|
if (empty && this._emptyFormulaAsTrue) {
|
|
767
|
-
if (this._subject === formula) this._subject = this.N3_TRUE;else this._object = this.N3_TRUE;
|
|
807
|
+
if (this._subject === formula) this._subject = this.N3_TRUE;else if (this._predicate === formula) this._predicate = this.N3_TRUE;else this._object = this.N3_TRUE;
|
|
768
808
|
}
|
|
769
809
|
|
|
770
|
-
//
|
|
771
|
-
|
|
772
|
-
|
|
810
|
+
// Continue according to the formula's position in the enclosing statement
|
|
811
|
+
if (this._object !== null) return this._getPathReader(this._getContextEndReader(), 'object');
|
|
812
|
+
if (this._predicate !== null) return this._getPathReader(this._readObject, 'predicate');
|
|
813
|
+
return this._getPathReader(this._readPredicate, 'subject');
|
|
773
814
|
}
|
|
774
815
|
|
|
775
816
|
// ### `_readPunctuation` reads punctuation between quads or quad parts
|
|
@@ -789,7 +830,7 @@ class N3Parser {
|
|
|
789
830
|
case '.':
|
|
790
831
|
this._subject = null;
|
|
791
832
|
this._tripleTerm = null;
|
|
792
|
-
next = this.
|
|
833
|
+
next = this._getStatementReader();
|
|
793
834
|
if (inversePredicate) this._inversePredicate = false;
|
|
794
835
|
break;
|
|
795
836
|
// Semicolon means the subject is shared; predicate and object are different
|
|
@@ -947,10 +988,10 @@ class N3Parser {
|
|
|
947
988
|
// SPARQL-style declarations don't have punctuation
|
|
948
989
|
if (this._sparqlStyle) {
|
|
949
990
|
this._sparqlStyle = false;
|
|
950
|
-
return this.
|
|
991
|
+
return this._getStatementReader().call(this, token);
|
|
951
992
|
}
|
|
952
993
|
if (token.type !== '.') return this._error('Expected declaration to end with a dot', token);
|
|
953
|
-
return this.
|
|
994
|
+
return this._getStatementReader();
|
|
954
995
|
}
|
|
955
996
|
|
|
956
997
|
// Reads a list of quantified symbols from a @forSome or @forAll statement
|
|
@@ -995,17 +1036,18 @@ class N3Parser {
|
|
|
995
1036
|
}
|
|
996
1037
|
|
|
997
1038
|
// ### `_getPathReader` reads a potential path and then resumes with the given function
|
|
998
|
-
_getPathReader(afterPath) {
|
|
1039
|
+
_getPathReader(afterPath, position) {
|
|
999
1040
|
this._afterPath = afterPath;
|
|
1041
|
+
this._pathPosition = position || (this._predicate === null ? 'subject' : 'object');
|
|
1000
1042
|
return this._readPath;
|
|
1001
1043
|
}
|
|
1002
1044
|
|
|
1003
1045
|
// ### `_getPathEndReader` continues reading after a term that might start a path,
|
|
1004
1046
|
// given the pending token that follows the term (or `null` if it was consumed)
|
|
1005
|
-
_getPathEndReader(token, afterPath) {
|
|
1047
|
+
_getPathEndReader(token, afterPath, position) {
|
|
1006
1048
|
// Other pending tokens are not handled here
|
|
1007
1049
|
if (token !== null && token.type !== '!' && token.type !== '^') return null;
|
|
1008
|
-
const reader = this._getPathReader(afterPath);
|
|
1050
|
+
const reader = this._getPathReader(afterPath, position);
|
|
1009
1051
|
// If no token is pending, wait for the next one; otherwise, consume it now
|
|
1010
1052
|
return token === null ? reader : reader.call(this, token);
|
|
1011
1053
|
}
|
|
@@ -1021,6 +1063,7 @@ class N3Parser {
|
|
|
1021
1063
|
return this._readBackwardPath;
|
|
1022
1064
|
// Not a path; resume reading where we left off
|
|
1023
1065
|
default:
|
|
1066
|
+
const afterPath = this._afterPath;
|
|
1024
1067
|
const stack = this._contextStack,
|
|
1025
1068
|
parent = stack.length && stack[stack.length - 1];
|
|
1026
1069
|
// If we were reading a list item, we still need to output it
|
|
@@ -1032,7 +1075,9 @@ class N3Parser {
|
|
|
1032
1075
|
// Output the list item
|
|
1033
1076
|
this._emit(this._subject, this.RDF_FIRST, item, this._graph);
|
|
1034
1077
|
}
|
|
1035
|
-
|
|
1078
|
+
this._afterPath = null;
|
|
1079
|
+
this._pathPosition = null;
|
|
1080
|
+
return afterPath.call(this, token);
|
|
1036
1081
|
}
|
|
1037
1082
|
}
|
|
1038
1083
|
|
|
@@ -1042,10 +1087,8 @@ class N3Parser {
|
|
|
1042
1087
|
const object = this._factory.blankNode();
|
|
1043
1088
|
// The next token is the predicate
|
|
1044
1089
|
if ((predicate = this._readEntity(token)) === undefined) return;
|
|
1045
|
-
//
|
|
1046
|
-
if (this.
|
|
1047
|
-
// If we were reading an object, replace the subject by the path's object
|
|
1048
|
-
else subject = this._object, this._object = object;
|
|
1090
|
+
// Replace the path expression with the generated object in its current position
|
|
1091
|
+
if (this._pathPosition === 'subject') subject = this._subject, this._subject = object;else if (this._pathPosition === 'predicate') subject = this._predicate, this._predicate = object;else subject = this._object, this._object = object;
|
|
1049
1092
|
// Emit the path's current quad and read its next section
|
|
1050
1093
|
this._emit(subject, predicate, object, this._graph);
|
|
1051
1094
|
return this._readPath;
|
|
@@ -1057,10 +1100,8 @@ class N3Parser {
|
|
|
1057
1100
|
let predicate, object;
|
|
1058
1101
|
// The next token is the predicate
|
|
1059
1102
|
if ((predicate = this._readEntity(token)) === undefined) return;
|
|
1060
|
-
//
|
|
1061
|
-
if (this.
|
|
1062
|
-
// If we were reading an object, replace the subject by the path's subject
|
|
1063
|
-
else object = this._object, this._object = subject;
|
|
1103
|
+
// Replace the path expression with the generated subject in its current position
|
|
1104
|
+
if (this._pathPosition === 'subject') object = this._subject, this._subject = subject;else if (this._pathPosition === 'predicate') object = this._predicate, this._predicate = subject;else object = this._object, this._object = subject;
|
|
1064
1105
|
// Emit the path's current quad and read its next section
|
|
1065
1106
|
this._emit(subject, predicate, object, this._graph);
|
|
1066
1107
|
return this._readPath;
|
package/package.json
CHANGED
package/src/N3Parser.js
CHANGED
|
@@ -83,14 +83,21 @@ export default class N3Parser {
|
|
|
83
83
|
this._contextStack.push({ type, subject, predicate, object, graph });
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
|
-
|
|
86
|
+
const context = {
|
|
87
87
|
type,
|
|
88
88
|
subject, predicate, object, graph,
|
|
89
89
|
inverse: this._inversePredicate,
|
|
90
90
|
blankPrefix: this._prefixes._,
|
|
91
91
|
quantified: this._quantified,
|
|
92
92
|
emptyFormula: this._emptyFormula,
|
|
93
|
-
}
|
|
93
|
+
};
|
|
94
|
+
// Prefix and base declarations are scoped to their formula
|
|
95
|
+
if (type === 'formula') {
|
|
96
|
+
context.prefixes = this._prefixes;
|
|
97
|
+
context.base = [this._base, this._basePath, this._baseRoot, this._baseScheme];
|
|
98
|
+
this._prefixes = Object.create(this._prefixes);
|
|
99
|
+
}
|
|
100
|
+
this._contextStack.push(context);
|
|
94
101
|
// Every new scope resets the predicate direction
|
|
95
102
|
this._inversePredicate = false;
|
|
96
103
|
// In N3, blank nodes are scoped to a formula
|
|
@@ -122,7 +129,12 @@ export default class N3Parser {
|
|
|
122
129
|
// Restore N3 context settings
|
|
123
130
|
if (this._n3Mode) {
|
|
124
131
|
this._inversePredicate = context.inverse;
|
|
125
|
-
|
|
132
|
+
if (type === 'formula') {
|
|
133
|
+
this._prefixes = context.prefixes;
|
|
134
|
+
[this._base, this._basePath, this._baseRoot, this._baseScheme] = context.base;
|
|
135
|
+
}
|
|
136
|
+
else
|
|
137
|
+
this._prefixes._ = context.blankPrefix;
|
|
126
138
|
this._quantified = context.quantified;
|
|
127
139
|
this._emptyFormula = context.emptyFormula;
|
|
128
140
|
}
|
|
@@ -175,6 +187,28 @@ export default class N3Parser {
|
|
|
175
187
|
}
|
|
176
188
|
}
|
|
177
189
|
|
|
190
|
+
// ### `_readInFormulaContext` reads a token at the statement level of a formula
|
|
191
|
+
_readInFormulaContext(token) {
|
|
192
|
+
switch (token.type) {
|
|
193
|
+
case 'PREFIX':
|
|
194
|
+
this._sparqlStyle = true;
|
|
195
|
+
case '@prefix':
|
|
196
|
+
return this._readPrefix;
|
|
197
|
+
case 'BASE':
|
|
198
|
+
this._sparqlStyle = true;
|
|
199
|
+
case '@base':
|
|
200
|
+
return this._readBaseIRI;
|
|
201
|
+
default:
|
|
202
|
+
return this._readSubject(token);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ### `_getStatementReader` returns the reader for the current statement scope
|
|
207
|
+
_getStatementReader() {
|
|
208
|
+
const context = this._contextStack[this._contextStack.length - 1];
|
|
209
|
+
return context && context.type === 'formula' ? this._readInFormulaContext : this._readInTopContext;
|
|
210
|
+
}
|
|
211
|
+
|
|
178
212
|
// ### `_readEntity` reads an IRI, prefixed name, blank node, or variable
|
|
179
213
|
_readEntity(token, quantifier) {
|
|
180
214
|
let value;
|
|
@@ -245,7 +279,7 @@ export default class N3Parser {
|
|
|
245
279
|
return this._error('Unexpected graph', token);
|
|
246
280
|
this._saveContext('formula', this._graph,
|
|
247
281
|
this._graph = this._factory.blankNode(), null, null);
|
|
248
|
-
return this.
|
|
282
|
+
return this._readInFormulaContext;
|
|
249
283
|
case '}':
|
|
250
284
|
// No subject; the graph in which we are reading is closed instead
|
|
251
285
|
return this._readPunctuation(token);
|
|
@@ -303,6 +337,7 @@ export default class N3Parser {
|
|
|
303
337
|
// ### `_readPredicate` reads a quad's predicate
|
|
304
338
|
_readPredicate(token) {
|
|
305
339
|
const type = token.type;
|
|
340
|
+
let pathable = false;
|
|
306
341
|
switch (type) {
|
|
307
342
|
case 'inverse':
|
|
308
343
|
this._inversePredicate = true;
|
|
@@ -334,6 +369,7 @@ export default class N3Parser {
|
|
|
334
369
|
else
|
|
335
370
|
this._predicate = this._factory.literal(token.value, this._factory.namedNode(token.prefix));
|
|
336
371
|
|
|
372
|
+
pathable = true;
|
|
337
373
|
break;
|
|
338
374
|
case '(':
|
|
339
375
|
// In N3, a list can be a predicate
|
|
@@ -347,16 +383,26 @@ export default class N3Parser {
|
|
|
347
383
|
this._subject = this._factory.blankNode(), null);
|
|
348
384
|
return this._readBlankNodeHead;
|
|
349
385
|
}
|
|
386
|
+
return this._error('Disallowed blank node as predicate', token);
|
|
387
|
+
case '{':
|
|
388
|
+
// In N3, a formula can be a predicate
|
|
389
|
+
if (this._n3Mode) {
|
|
390
|
+
this._saveContext('formula', this._graph, this._subject,
|
|
391
|
+
this._graph = this._factory.blankNode(), null);
|
|
392
|
+
return this._readSubject;
|
|
393
|
+
}
|
|
394
|
+
return this._readEntity(token);
|
|
350
395
|
case 'blank':
|
|
351
396
|
if (!this._n3Mode)
|
|
352
397
|
return this._error('Disallowed blank node as predicate', token);
|
|
353
398
|
default:
|
|
354
399
|
if ((this._predicate = this._readEntity(token)) === undefined)
|
|
355
400
|
return;
|
|
401
|
+
pathable = this._n3Mode;
|
|
356
402
|
}
|
|
357
403
|
this._validAnnotation = true;
|
|
358
404
|
// The next token must be an object
|
|
359
|
-
return this._readObject;
|
|
405
|
+
return pathable ? this._getPathReader(this._readObject, 'predicate') : this._readObject;
|
|
360
406
|
}
|
|
361
407
|
|
|
362
408
|
// ### `_readObject` reads a quad's object
|
|
@@ -389,7 +435,7 @@ export default class N3Parser {
|
|
|
389
435
|
return this._error('Unexpected graph', token);
|
|
390
436
|
this._saveContext('formula', this._graph, this._subject, this._predicate,
|
|
391
437
|
this._graph = this._factory.blankNode());
|
|
392
|
-
return this.
|
|
438
|
+
return this._readInFormulaContext;
|
|
393
439
|
case '<<(':
|
|
394
440
|
this._saveContext('<<(', this._graph, this._subject, this._predicate, null);
|
|
395
441
|
this._graph = null;
|
|
@@ -456,7 +502,7 @@ export default class N3Parser {
|
|
|
456
502
|
return this._getContextEndReader();
|
|
457
503
|
// If the blank node was the predicate, continue reading the object
|
|
458
504
|
else if (this._predicate !== null)
|
|
459
|
-
return this._readObject;
|
|
505
|
+
return this._getPathReader(this._readObject, 'predicate');
|
|
460
506
|
// If the blank node was the subject, continue reading the predicate
|
|
461
507
|
else
|
|
462
508
|
// If the blank node was empty, it could be a named graph label
|
|
@@ -529,7 +575,7 @@ export default class N3Parser {
|
|
|
529
575
|
// Was this list the parent's predicate?
|
|
530
576
|
else if (this._object === null) {
|
|
531
577
|
// The next token is the object
|
|
532
|
-
next = this._readObject;
|
|
578
|
+
next = this._getPathReader(this._readObject, 'predicate');
|
|
533
579
|
// No list tail if this was an empty list
|
|
534
580
|
if (this._predicate === this.RDF_NIL)
|
|
535
581
|
return next;
|
|
@@ -585,7 +631,7 @@ export default class N3Parser {
|
|
|
585
631
|
this._saveContext('formula', this._graph, list, this.RDF_FIRST,
|
|
586
632
|
this._graph = item);
|
|
587
633
|
this._subject = null;
|
|
588
|
-
return this.
|
|
634
|
+
return this._readInFormulaContext;
|
|
589
635
|
case '<<(':
|
|
590
636
|
this._saveContext('<<(', this._graph, null, null, null);
|
|
591
637
|
this._graph = null;
|
|
@@ -706,13 +752,12 @@ export default class N3Parser {
|
|
|
706
752
|
token = null;
|
|
707
753
|
}
|
|
708
754
|
|
|
709
|
-
if (component === 'subject') {
|
|
710
|
-
// A subject literal implies N3 mode, so
|
|
711
|
-
const
|
|
712
|
-
|
|
755
|
+
if (component === 'subject' || component === 'predicate') {
|
|
756
|
+
// A subject or predicate literal implies N3 mode, so it might start a path
|
|
757
|
+
const next = component === 'subject' ? this._readPredicateOrNamedGraph : this._readObject;
|
|
758
|
+
const reader = this._getPathEndReader(token, next, component);
|
|
759
|
+
return reader || next.call(this, token);
|
|
713
760
|
}
|
|
714
|
-
if (component === 'predicate')
|
|
715
|
-
return token === null ? this._readObject : this._readObject(token);
|
|
716
761
|
return this._completeObjectLiteralPost(token, listItem);
|
|
717
762
|
}
|
|
718
763
|
|
|
@@ -739,16 +784,13 @@ export default class N3Parser {
|
|
|
739
784
|
return this._readDirCode;
|
|
740
785
|
}
|
|
741
786
|
|
|
742
|
-
// A subject literal implies N3 mode, so it might start a path.
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
return reader;
|
|
747
|
-
}
|
|
787
|
+
// A subject or predicate literal implies N3 mode, so it might start a path.
|
|
788
|
+
const reader = this._getPathEndReader(completed.token, next, component);
|
|
789
|
+
if (reader)
|
|
790
|
+
return reader;
|
|
748
791
|
|
|
749
|
-
//
|
|
750
|
-
|
|
751
|
-
return completed.token === null ? next : next.call(this, completed.token);
|
|
792
|
+
// Consume the non-path token now
|
|
793
|
+
return next.call(this, completed.token);
|
|
752
794
|
}
|
|
753
795
|
|
|
754
796
|
// Completes a literal in subject position
|
|
@@ -823,13 +865,18 @@ export default class N3Parser {
|
|
|
823
865
|
if (empty && this._emptyFormulaAsTrue) {
|
|
824
866
|
if (this._subject === formula)
|
|
825
867
|
this._subject = this.N3_TRUE;
|
|
868
|
+
else if (this._predicate === formula)
|
|
869
|
+
this._predicate = this.N3_TRUE;
|
|
826
870
|
else
|
|
827
871
|
this._object = this.N3_TRUE;
|
|
828
872
|
}
|
|
829
873
|
|
|
830
|
-
//
|
|
831
|
-
|
|
832
|
-
|
|
874
|
+
// Continue according to the formula's position in the enclosing statement
|
|
875
|
+
if (this._object !== null)
|
|
876
|
+
return this._getPathReader(this._getContextEndReader(), 'object');
|
|
877
|
+
if (this._predicate !== null)
|
|
878
|
+
return this._getPathReader(this._readObject, 'predicate');
|
|
879
|
+
return this._getPathReader(this._readPredicate, 'subject');
|
|
833
880
|
}
|
|
834
881
|
|
|
835
882
|
// ### `_readPunctuation` reads punctuation between quads or quad parts
|
|
@@ -848,7 +895,7 @@ export default class N3Parser {
|
|
|
848
895
|
case '.':
|
|
849
896
|
this._subject = null;
|
|
850
897
|
this._tripleTerm = null;
|
|
851
|
-
next = this.
|
|
898
|
+
next = this._getStatementReader();
|
|
852
899
|
if (inversePredicate) this._inversePredicate = false;
|
|
853
900
|
break;
|
|
854
901
|
// Semicolon means the subject is shared; predicate and object are different
|
|
@@ -1021,12 +1068,12 @@ export default class N3Parser {
|
|
|
1021
1068
|
// SPARQL-style declarations don't have punctuation
|
|
1022
1069
|
if (this._sparqlStyle) {
|
|
1023
1070
|
this._sparqlStyle = false;
|
|
1024
|
-
return this.
|
|
1071
|
+
return this._getStatementReader().call(this, token);
|
|
1025
1072
|
}
|
|
1026
1073
|
|
|
1027
1074
|
if (token.type !== '.')
|
|
1028
1075
|
return this._error('Expected declaration to end with a dot', token);
|
|
1029
|
-
return this.
|
|
1076
|
+
return this._getStatementReader();
|
|
1030
1077
|
}
|
|
1031
1078
|
|
|
1032
1079
|
// Reads a list of quantified symbols from a @forSome or @forAll statement
|
|
@@ -1078,18 +1125,19 @@ export default class N3Parser {
|
|
|
1078
1125
|
}
|
|
1079
1126
|
|
|
1080
1127
|
// ### `_getPathReader` reads a potential path and then resumes with the given function
|
|
1081
|
-
_getPathReader(afterPath) {
|
|
1128
|
+
_getPathReader(afterPath, position) {
|
|
1082
1129
|
this._afterPath = afterPath;
|
|
1130
|
+
this._pathPosition = position || (this._predicate === null ? 'subject' : 'object');
|
|
1083
1131
|
return this._readPath;
|
|
1084
1132
|
}
|
|
1085
1133
|
|
|
1086
1134
|
// ### `_getPathEndReader` continues reading after a term that might start a path,
|
|
1087
1135
|
// given the pending token that follows the term (or `null` if it was consumed)
|
|
1088
|
-
_getPathEndReader(token, afterPath) {
|
|
1136
|
+
_getPathEndReader(token, afterPath, position) {
|
|
1089
1137
|
// Other pending tokens are not handled here
|
|
1090
1138
|
if (token !== null && token.type !== '!' && token.type !== '^')
|
|
1091
1139
|
return null;
|
|
1092
|
-
const reader = this._getPathReader(afterPath);
|
|
1140
|
+
const reader = this._getPathReader(afterPath, position);
|
|
1093
1141
|
// If no token is pending, wait for the next one; otherwise, consume it now
|
|
1094
1142
|
return token === null ? reader : reader.call(this, token);
|
|
1095
1143
|
}
|
|
@@ -1103,6 +1151,7 @@ export default class N3Parser {
|
|
|
1103
1151
|
case '^': return this._readBackwardPath;
|
|
1104
1152
|
// Not a path; resume reading where we left off
|
|
1105
1153
|
default:
|
|
1154
|
+
const afterPath = this._afterPath;
|
|
1106
1155
|
const stack = this._contextStack, parent = stack.length && stack[stack.length - 1];
|
|
1107
1156
|
// If we were reading a list item, we still need to output it
|
|
1108
1157
|
if (parent && parent.type === 'item') {
|
|
@@ -1113,7 +1162,9 @@ export default class N3Parser {
|
|
|
1113
1162
|
// Output the list item
|
|
1114
1163
|
this._emit(this._subject, this.RDF_FIRST, item, this._graph);
|
|
1115
1164
|
}
|
|
1116
|
-
|
|
1165
|
+
this._afterPath = null;
|
|
1166
|
+
this._pathPosition = null;
|
|
1167
|
+
return afterPath.call(this, token);
|
|
1117
1168
|
}
|
|
1118
1169
|
}
|
|
1119
1170
|
|
|
@@ -1124,10 +1175,11 @@ export default class N3Parser {
|
|
|
1124
1175
|
// The next token is the predicate
|
|
1125
1176
|
if ((predicate = this._readEntity(token)) === undefined)
|
|
1126
1177
|
return;
|
|
1127
|
-
//
|
|
1128
|
-
if (this.
|
|
1178
|
+
// Replace the path expression with the generated object in its current position
|
|
1179
|
+
if (this._pathPosition === 'subject')
|
|
1129
1180
|
subject = this._subject, this._subject = object;
|
|
1130
|
-
|
|
1181
|
+
else if (this._pathPosition === 'predicate')
|
|
1182
|
+
subject = this._predicate, this._predicate = object;
|
|
1131
1183
|
else
|
|
1132
1184
|
subject = this._object, this._object = object;
|
|
1133
1185
|
// Emit the path's current quad and read its next section
|
|
@@ -1142,10 +1194,11 @@ export default class N3Parser {
|
|
|
1142
1194
|
// The next token is the predicate
|
|
1143
1195
|
if ((predicate = this._readEntity(token)) === undefined)
|
|
1144
1196
|
return;
|
|
1145
|
-
//
|
|
1146
|
-
if (this.
|
|
1197
|
+
// Replace the path expression with the generated subject in its current position
|
|
1198
|
+
if (this._pathPosition === 'subject')
|
|
1147
1199
|
object = this._subject, this._subject = subject;
|
|
1148
|
-
|
|
1200
|
+
else if (this._pathPosition === 'predicate')
|
|
1201
|
+
object = this._predicate, this._predicate = subject;
|
|
1149
1202
|
else
|
|
1150
1203
|
object = this._object, this._object = subject;
|
|
1151
1204
|
// Emit the path's current quad and read its next section
|