Skip to content

fix: support predicates in the list position in Notation3 #345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 30 additions & 17 deletions src/N3Parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,17 @@ export default class N3Parser {
return value;
}

_readList(token, subject, predicate, object) {
// Lists are not allowed inside quoted triples
if (this._contextStack.length > 0 && this._contextStack[this._contextStack.length - 1].type === '<<') {
return this._error('Unexpected list inside quoted triple', token);
}
// Start a new list
this._saveContext('list', this._graph, subject, predicate, object);
this._subject = null;
return this._readListItem;
}

// ### `_readSubject` reads a quad's subject
_readSubject(token) {
this._predicate = null;
Expand All @@ -197,14 +208,7 @@ export default class N3Parser {
this._subject = this._blankNode(), null, null);
return this._readBlankNodeHead;
case '(':
// Lists are not allowed inside quoted triples
if (this._contextStack.length > 0 && this._contextStack[this._contextStack.length - 1].type === '<<') {
return this._error('Unexpected list inside quoted triple', token);
}
// Start a new list
this._saveContext('list', this._graph, this.RDF_NIL, null, null);
this._subject = null;
return this._readListItem;
return this._readList(token, this.RDF_NIL, null, null);
case '{':
// Start a new formula
if (!this._n3Mode)
Expand Down Expand Up @@ -282,6 +286,10 @@ export default class N3Parser {
// Additional semicolons can be safely ignored
return this._predicate !== null ? this._readPredicate :
this._error('Expected predicate but got ;', token);
case '(':
return this._n3Mode ?
this._readList(token, this._subject, this.RDF_NIL, null) :
this._error(`Expected entity but got ${type}`, token);
case '[':
if (this._n3Mode) {
// Start a new quad with a new blank node as subject
Expand Down Expand Up @@ -319,14 +327,7 @@ export default class N3Parser {
this._subject = this._blankNode());
return this._readBlankNodeHead;
case '(':
// Lists are not allowed inside quoted triples
if (this._contextStack.length > 0 && this._contextStack[this._contextStack.length - 1].type === '<<') {
return this._error('Unexpected list inside quoted triple', token);
}
// Start a new list
this._saveContext('list', this._graph, this._subject, this._predicate, this.RDF_NIL);
this._subject = null;
return this._readListItem;
return this._readList(token, this._subject, this._predicate, this.RDF_NIL);
case '{':
// Start a new formula
if (!this._n3Mode)
Expand Down Expand Up @@ -468,6 +469,14 @@ export default class N3Parser {
// No list tail if this was an empty list
if (this._subject === this.RDF_NIL)
return next;
// Was this list the parent's predicate?
}
else if (this._object === null) {
next = this._readObject;

// No list tail if this was an empty list
if (this._predicate === this.RDF_NIL)
return next;
}
// The list was in the parent context's object
else {
Expand Down Expand Up @@ -519,9 +528,13 @@ export default class N3Parser {

// Is this the first element of the list?
if (previousList === null) {
// This list is either the subject or the object of its parent
// This list is the subject of the parent
if (parent.predicate === null)
parent.subject = list;
// The list is the predicate of the parent
else if (parent.object === null)
parent.predicate = list;
// The list is the object of the parent
else
parent.object = list;
}
Expand Down
42 changes: 41 additions & 1 deletion test/N3Parser-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2052,6 +2052,46 @@ describe('Parser', () => {
['_:b0', 'f:knows', '_:b1'],
['_:b1', 'f:son', 'ex:joe']));

describe('should parse an empty list in the subject position',
shouldParse(parser, '@prefix : <ex:>. @prefix fam: <f:>.' +
'() <p> <o> .',
['http://www.w3.org/1999/02/22-rdf-syntax-ns#nil', 'p', 'o']
));

describe('should parse an empty list in the predicate position',
shouldParse(parser, '@prefix : <ex:>. @prefix fam: <f:>.' +
'<s> () <o> .',
['s', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil', 'o']
));

describe('should parse an empty list in the object position',
shouldParse(parser, '@prefix : <ex:>. @prefix fam: <f:>.' +
'<s> <p> () .',
['s', 'p', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil']
));

describe('should parse a single element list in the subject position',
shouldParse(parser, '@prefix : <ex:>. @prefix fam: <f:>.' +
'( <s> ) <p> <o> .',
...list(['_:b0', 's']),
['_:b0', 'p', 'o']
));


describe('should parse a single element list in the predicate position',
shouldParse(parser, '@prefix : <ex:>. @prefix fam: <f:>.' +
'<s> ( <p> ) <o> .',
...list(['_:b0', 'p']),
['s', '_:b0', 'o']
));

describe('should parse a single element list in the object position',
shouldParse(parser, '@prefix : <ex:>. @prefix fam: <f:>.' +
'<s> <p> ( <o> ) .',
...list(['_:b0', 'o']),
['s', 'p', '_:b0']
));

describe('should parse a ! path in a list as subject',
shouldParse(parser, '@prefix : <ex:>. @prefix fam: <f:>.' +
'(<x> :joe!fam:mother <y>) a :List.',
Expand Down Expand Up @@ -2269,7 +2309,7 @@ describe('Parser', () => {

for (const [f, triple] of [
[x => `(${x}) a :List .`, ['_:b0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 'ex:List']],
// [x => `<l> (${x}) <m> .`, ['l', '_:b0', 'm']],
[x => `<l> (${x}) <m> .`, ['l', '_:b0', 'm']],
[x => `<l> <is> (${x}) .`, ['l', 'is', '_:b0']],
]) {
// eslint-disable-next-line no-inner-declarations
Expand Down