From 8e5f89f13dcd8d9c23b1720860378cbeec8f33a6 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Thu, 23 Mar 2023 20:32:34 +1100 Subject: [PATCH 1/9] chore: add test for failing subject and predicate literal cases --- test/N3Parser-test.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index 80cb2466..a96ee692 100644 --- a/test/N3Parser-test.js +++ b/test/N3Parser-test.js @@ -1756,12 +1756,50 @@ describe('Parser', () => { ['"1"^^http://www.w3.org/2001/XMLSchema#integer', 'greaterThan', '"0"^^http://www.w3.org/2001/XMLSchema#integer', '_:b0'] )); + it('should parse literals with datatype as subject', + shouldParse(parser, '"a"^^ .', + ['"a"^^http://example.org/c', 'greaterThan', 'd'] + )); + + + it('should parse literals with datatype as subject and object', + shouldParse(parser, '"a"^^ "b"^^.', + ['"a"^^http://example.org/c', 'greaterThan', '"b"^^http://example.org/c'] + )); + + it('should parse literals without datatype as subject and object', + shouldParse(parser, '"a" "b".', + ['"a"', 'greaterThan', '"b"'] + )); + + it('should parse literals without datatype as subject', + shouldParse(parser, '"a" .', + ['"a"', 'greaterThan', 'b'] + )); + + it('should parse literals with datatype as predicate', + shouldParse(parser, ' "a"^^ "b"^^.', + ['greaterThan', '"a"^^http://example.org/c', '"b"^^http://example.org/c'] + )); + + it('should parse literals without datatype as predicate', + shouldParse(parser, ' "a" "b".', + ['greaterThan', '"a"', '"b"'] + )); + + it('should parse literals with datatype as subject in graph', shouldParse(parser, ' {"a"^^ "b"^^}.', ['a', 'b', '_:b0'], ['"a"^^http://example.org/c', 'greaterThan', '"b"^^http://example.org/c', '_:b0'] )); + it('should parse literals without datatype as subject in graph', + shouldParse(parser, ' {"a" "b"}.', + ['a', 'b', '_:b0'], + ['"a"', 'greaterThan', '"b"', '_:b0'] + )); + it('should parse literals with language as subject', shouldParse(parser, ' {"bonjour"@fr "hello"@en}.', ['a', 'b', '_:b0'], From 0f0ff97b47a6ea6d91f9d9c055776c5a56871d3b Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Thu, 23 Mar 2023 20:52:35 +1100 Subject: [PATCH 2/9] fix: allow subject literals without a datatype --- src/N3Parser.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/N3Parser.js b/src/N3Parser.js index 1a7d7449..add1f6b8 100644 --- a/src/N3Parser.js +++ b/src/N3Parser.js @@ -547,8 +547,16 @@ export default class N3Parser { // Completes a literal in subject position _completeSubjectLiteral(token) { - this._subject = this._completeLiteral(token).literal; - return this._readPredicateOrNamedGraph; + const completed = this._completeLiteral(token); + + this._subject = completed.literal; + // If the token was consumed, continue with the rest of the input + if (completed.token === null) + return this._readPredicateOrNamedGraph; + // Otherwise, consume the token now + else { + return this._readPredicateOrNamedGraph(completed.token); + } } // Completes a literal in object position From 5e3e8a99b7e5e72e8f170519d2d8691310e31bdf Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Thu, 23 Mar 2023 21:07:26 +1100 Subject: [PATCH 3/9] fix: allow predicate literals in N3 --- src/N3Parser.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/N3Parser.js b/src/N3Parser.js index add1f6b8..7adb3116 100644 --- a/src/N3Parser.js +++ b/src/N3Parser.js @@ -266,6 +266,18 @@ export default class N3Parser { case 'abbreviation': this._predicate = this.ABBREVIATIONS[token.value]; break; + case 'literal': + if (!this._n3Mode) + return this._error('Unexpected literal', token); + + if (token.prefix.length === 0) { + this._literalValue = token.value; + return this._completePredicateLiteral; + } + else + this._subject = this._literal(token.value, this._namedNode(token.prefix)); + + break; case '.': case ']': case '}': @@ -559,6 +571,20 @@ export default class N3Parser { } } + // Completes a literal in subject position + _completePredicateLiteral(token) { + const completed = this._completeLiteral(token); + + this._predicate = completed.literal; + // If the token was consumed, continue with the rest of the input + if (completed.token === null) + return this._readObject; + // Otherwise, consume the token now + else { + return this._readObject(completed.token); + } + } + // Completes a literal in object position _completeObjectLiteral(token, listItem) { const completed = this._completeLiteral(token); From 211db8dc107062c213d3451b0e916d77e588acc3 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Thu, 23 Mar 2023 21:26:28 +1100 Subject: [PATCH 4/9] chore: improve test coverage --- test/N3Parser-test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index a96ee692..61902fd4 100644 --- a/test/N3Parser-test.js +++ b/test/N3Parser-test.js @@ -81,6 +81,12 @@ describe('Parser', () => { ['noturn:a', 'noturn:b', '"x"^^urn:foo'], ['noturn:a', 'noturn:b', '"x"^^noturn:urn:foo'])); + it('should not parse literals with datatype as predicate', + shouldNotParse(' "a"^^ "b"^^.', 'Unexpected literal on line 1.')); + + it('should not parse literals without datatype as predicate', + shouldNotParse(' "a" "b".', 'Unexpected literal on line 1.')); + it('should not parse a triple with a literal and a prefixed name type with an inexistent prefix', shouldNotParse(' "string"^^x:z.', 'Undefined prefix "x:" on line 1.', { @@ -1788,6 +1794,18 @@ describe('Parser', () => { ['greaterThan', '"a"', '"b"'] )); + it('should parse literals with datatype as predicate in graph', + shouldParse(parser, ' { "a"^^ "b"^^}.', + ['x', 'y', '_:b0'], + ['greaterThan', '"a"^^http://example.org/c', '"b"^^http://example.org/c', '_:b0'] + )); + + it('should parse literals without datatype as predicate in graph', + shouldParse(parser, ' { "a" "b"}.', + ['x', 'y', '_:b0'], + ['greaterThan', '"a"', '"b"', '_:b0'] + )); + it('should parse literals with datatype as subject in graph', shouldParse(parser, ' {"a"^^ "b"^^}.', ['a', 'b', '_:b0'], From 5334c44dbbc6ad3632488666b23b0dbc7ae0abfc Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Thu, 23 Mar 2023 21:59:23 +1100 Subject: [PATCH 5/9] fix: allow parsing of integers in predicate position --- src/N3Parser.js | 2 +- test/N3Parser-test.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/N3Parser.js b/src/N3Parser.js index 7adb3116..b8657bc7 100644 --- a/src/N3Parser.js +++ b/src/N3Parser.js @@ -275,7 +275,7 @@ export default class N3Parser { return this._completePredicateLiteral; } else - this._subject = this._literal(token.value, this._namedNode(token.prefix)); + this._predicate = this._literal(token.value, this._namedNode(token.prefix)); break; case '.': diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index 61902fd4..82eacb49 100644 --- a/test/N3Parser-test.js +++ b/test/N3Parser-test.js @@ -1794,6 +1794,16 @@ describe('Parser', () => { ['greaterThan', '"a"', '"b"'] )); + it('should parse subject predicate and object as integer', + shouldParse(parser, '1 1 1.', + ['"1"^^http://www.w3.org/2001/XMLSchema#integer', '"1"^^http://www.w3.org/2001/XMLSchema#integer', '"1"^^http://www.w3.org/2001/XMLSchema#integer'] + )); + + it('should parse literals with integer as predicate', + shouldParse(parser, ' 1 "b".', + ['greaterThan', '"1"^^http://www.w3.org/2001/XMLSchema#integer', '"b"'] + )); + it('should parse literals with datatype as predicate in graph', shouldParse(parser, ' { "a"^^ "b"^^}.', ['x', 'y', '_:b0'], From a198e016e6bff1c6c32327e882797de6dd94417b Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Fri, 24 Mar 2023 10:02:22 +1100 Subject: [PATCH 6/9] Update test/N3Parser-test.js Co-authored-by: Ted Thibodeau Jr --- test/N3Parser-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index 82eacb49..66806321 100644 --- a/test/N3Parser-test.js +++ b/test/N3Parser-test.js @@ -1794,7 +1794,7 @@ describe('Parser', () => { ['greaterThan', '"a"', '"b"'] )); - it('should parse subject predicate and object as integer', + it('should parse subject, predicate, and object as integer', shouldParse(parser, '1 1 1.', ['"1"^^http://www.w3.org/2001/XMLSchema#integer', '"1"^^http://www.w3.org/2001/XMLSchema#integer', '"1"^^http://www.w3.org/2001/XMLSchema#integer'] )); From b1346130019e8b6b3094565275fba1acb10f771c Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Fri, 24 Mar 2023 20:18:00 +1100 Subject: [PATCH 7/9] Update src/N3Parser.js Co-authored-by: Ruben Verborgh --- src/N3Parser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/N3Parser.js b/src/N3Parser.js index b8657bc7..81f8398c 100644 --- a/src/N3Parser.js +++ b/src/N3Parser.js @@ -571,7 +571,7 @@ export default class N3Parser { } } - // Completes a literal in subject position + // Completes a literal in predicate position _completePredicateLiteral(token) { const completed = this._completeLiteral(token); From f32e2c3fb64c71560af18210c1986d1b3bc0f937 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Fri, 24 Mar 2023 20:47:07 +1100 Subject: [PATCH 8/9] chore: refactor '_completeSubjectLiteral' and '_completePredicateLiteral' --- src/N3Parser.js | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/N3Parser.js b/src/N3Parser.js index 81f8398c..58528357 100644 --- a/src/N3Parser.js +++ b/src/N3Parser.js @@ -558,31 +558,27 @@ export default class N3Parser { } // Completes a literal in subject position - _completeSubjectLiteral(token) { - const completed = this._completeLiteral(token); - - this._subject = completed.literal; - // If the token was consumed, continue with the rest of the input - if (completed.token === null) - return this._readPredicateOrNamedGraph; - // Otherwise, consume the token now - else { - return this._readPredicateOrNamedGraph(completed.token); - } + _completeSubjectLiteral(tkn) { + const { literal, token } = this._completeLiteral(tkn); + this._subject = literal; + + return token === null ? + // If the token was consumed, continue with the rest of the input + this._readPredicateOrNamedGraph : + // Otherwise, consume the token now + this._readPredicateOrNamedGraph(token); } // Completes a literal in predicate position - _completePredicateLiteral(token) { - const completed = this._completeLiteral(token); - - this._predicate = completed.literal; - // If the token was consumed, continue with the rest of the input - if (completed.token === null) - return this._readObject; - // Otherwise, consume the token now - else { - return this._readObject(completed.token); - } + _completePredicateLiteral(tkn) { + const { literal, token } = this._completeLiteral(tkn); + this._predicate = literal; + + return token === null ? + // If the token was consumed, continue with the rest of the input + this._readObject : + // Otherwise, consume the token now + this._readObject(token); } // Completes a literal in object position From f2a2fba85d06f3bf23e344f1b52d86e77158b395 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Fri, 24 Mar 2023 20:51:43 +1100 Subject: [PATCH 9/9] chore: add comments --- src/N3Parser.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/N3Parser.js b/src/N3Parser.js index 58528357..bf800080 100644 --- a/src/N3Parser.js +++ b/src/N3Parser.js @@ -229,10 +229,12 @@ export default class N3Parser { if (!this._n3Mode) return this._error('Unexpected literal', token); + // Regular literal, can still get a datatype or language if (token.prefix.length === 0) { this._literalValue = token.value; return this._completeSubjectLiteral; } + // Pre-datatyped string literal (prefix stores the datatype) else this._subject = this._literal(token.value, this._namedNode(token.prefix)); @@ -270,10 +272,12 @@ export default class N3Parser { if (!this._n3Mode) return this._error('Unexpected literal', token); + // Regular literal, can still get a datatype or language if (token.prefix.length === 0) { this._literalValue = token.value; return this._completePredicateLiteral; } + // Pre-datatyped string literal (prefix stores the datatype) else this._predicate = this._literal(token.value, this._namedNode(token.prefix));