diff --git a/src/N3Parser.js b/src/N3Parser.js index 1a7d7449..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)); @@ -266,6 +268,20 @@ export default class N3Parser { case 'abbreviation': this._predicate = this.ABBREVIATIONS[token.value]; break; + case 'literal': + 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)); + + break; case '.': case ']': case '}': @@ -546,9 +562,27 @@ export default class N3Parser { } // Completes a literal in subject position - _completeSubjectLiteral(token) { - this._subject = this._completeLiteral(token).literal; - return this._readPredicateOrNamedGraph; + _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(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 diff --git a/test/N3Parser-test.js b/test/N3Parser-test.js index 80cb2466..66806321 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.', { @@ -1756,12 +1762,72 @@ 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 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'], + ['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'], ['"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'],