@@ -1851,7 +1851,7 @@ describe('Parser', () => {
18511851 [ '?g' , '?h' , '?i' , '_:b4' ] ,
18521852 [ '?j' , '?k' , '?l' , '_:b5' ] ) ) ;
18531853
1854- it ( 'should not reuse identifiers of blank nodes within and outside of formulas' ,
1854+ describe ( 'should not reuse identifiers of blank nodes within and outside of formulas' ,
18551855 shouldParse ( parser , '_:a _:b _:c. { _:a _:b _:c } => { { _:a _:b _:c } => { _:a _:b _:c } }.' ,
18561856 [ '_:b0_a' , '_:b0_b' , '_:b0_c' ] ,
18571857 [ '_:b0' , 'http://www.w3.org/2000/10/swap/log#implies' , '_:b1' , '' ] ,
@@ -2058,13 +2058,103 @@ describe('Parser', () => {
20582058 [ '_:b3' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' ] ,
20592059 [ '_:b2' , 'f:son' , 'ex:joe' ] ) ) ;
20602060
2061+ describe ( 'should parse a ! path of length 2 as subject in a list' ,
2062+ shouldParse ( parser , '@prefix : <ex:>. @prefix fam: <f:>.' +
2063+ '(:joe!fam:mother) a fam:Person.' ,
2064+ [ 'ex:joe' , 'f:mother' , '_:b1' ] ,
2065+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first' , '_:b1' ] ,
2066+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' ] ,
2067+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'f:Person' ] ) ) ;
2068+
2069+ describe ( 'should parse a !^ path of length 3 as subject in a list' ,
2070+ shouldParse ( parser , '@prefix : <ex:>. @prefix fam: <f:>.' +
2071+ '(:joe!fam:mother^fam:father) a fam:Person.' ,
2072+ [ 'ex:joe' , 'f:mother' , '_:b1' ] ,
2073+ [ '_:b2' , 'f:father' , '_:b1' ] ,
2074+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first' , '_:b2' ] ,
2075+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' ] ,
2076+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'f:Person' ] ) ) ;
2077+
2078+ describe ( 'should parse a ! path of length 2 starting with an empty list' ,
2079+ shouldParse ( parser , '@prefix : <ex:>. @prefix fam: <f:>.' +
2080+ '()!fam:mother a fam:Person.' ,
2081+ [ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' , 'f:mother' , '_:b0' ] ,
2082+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'f:Person' ] ) ) ;
2083+
2084+ describe ( 'should parse a ! path of length 2 starting with a non-empty list' ,
2085+ shouldParse ( parser , '@prefix : <ex:>. @prefix fam: <f:>.' +
2086+ '( :a )!fam:mother a fam:Person.' ,
2087+ ...list ( [ '_:b0' , 'ex:a' ] ) ,
2088+ [ '_:b0' , 'f:mother' , '_:b1' ] ,
2089+ [ '_:b1' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'f:Person' ] ) ) ;
2090+
2091+ describe ( 'should parse a ! path of length 2 starting with a non-empty list in another list' ,
2092+ shouldParse ( parser , '@prefix : <ex:>. @prefix fam: <f:>.' +
2093+ '(( :a )!fam:mother 1) a fam:Person.' ,
2094+ ...list ( [ '_:b0' , '_:b2' ] , [ '_:b3' , '"1"^^http://www.w3.org/2001/XMLSchema#integer' ] ) ,
2095+ ...list ( [ '_:b1' , 'ex:a' ] ) ,
2096+ [ '_:b1' , 'f:mother' , '_:b2' ] ,
2097+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'f:Person' ] ) ) ;
2098+
2099+ describe ( 'should parse a ! path of length 2 starting with an empty list in another list' ,
2100+ shouldParse ( parser , '@prefix : <ex:>. @prefix fam: <f:>.' +
2101+ '(()!fam:mother 1) a fam:Person.' ,
2102+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'f:Person' ] ,
2103+ ...list ( [ '_:b0' , '_:b1' ] , [ '_:b2' , '"1"^^http://www.w3.org/2001/XMLSchema#integer' ] ) ,
2104+ [ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' , 'f:mother' , '_:b1' ]
2105+ ) ) ;
2106+
2107+ describe ( 'should parse a ! path of length 2 starting with an empty list in another list as second element' ,
2108+ shouldParse ( parser , '@prefix : <ex:>. @prefix fam: <f:>.' +
2109+ '(1 ()!fam:mother) a fam:Person.' ,
2110+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'f:Person' ] ,
2111+ ...list ( [ '_:b0' , '"1"^^http://www.w3.org/2001/XMLSchema#integer' ] , [ '_:b1' , '_:b2' ] ) ,
2112+ [ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' , 'f:mother' , '_:b2' ]
2113+ ) ) ;
2114+
2115+ describe ( 'should parse a ! path of length 2 starting with an empty list in another list of one element' ,
2116+ shouldParse ( parser , '@prefix : <ex:>. @prefix fam: <f:>.' +
2117+ '(()!fam:mother) a fam:Person.' ,
2118+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'f:Person' ] ,
2119+ ...list ( [ '_:b0' , '_:b1' ] ) ,
2120+ [ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' , 'f:mother' , '_:b1' ] ) ) ;
2121+
2122+ describe ( 'should parse a ! path of length 2 as nested subject in a list' ,
2123+ shouldParse ( parser , '@prefix : <ex:>. @prefix fam: <f:>.' +
2124+ '((:joe!fam:mother) 1) a fam:Person.' ,
2125+ [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'f:Person' ] ,
2126+ ...list ( [ '_:b0' , '_:b1' ] , [ '_:b3' , '"1"^^http://www.w3.org/2001/XMLSchema#integer' ] ) ,
2127+ ...list ( [ '_:b1' , '_:b2' ] ) ,
2128+ [ 'ex:joe' , 'f:mother' , '_:b2' ] ) ) ;
2129+
2130+ describe ( 'should parse a birthday rule' ,
2131+ shouldParse ( parser ,
2132+ '@prefix foaf: <http://xmlns.com/foaf/0.1/> .' +
2133+ '@prefix math: <http://www.w3.org/2000/10/swap/math#> .' +
2134+ '@prefix : <http://example.org/> .' +
2135+ '' +
2136+ '{' +
2137+ ' ?x :trueOnDate ?date.' +
2138+ '} <= {' +
2139+ ' ((?date ?s!foaf:birthday)!math:difference 31622400) math:integerQuotient ?age .' +
2140+ '} .' ,
2141+ [ '?x' , 'http://example.org/trueOnDate' , '?date' , '_:b0' ] ,
2142+ // eslint-disable-next-line no-warning-comments
2143+ // FIXME: when merging with https://github.com/rdfjs/N3.js/pull/327
2144+ [ '_:b1' , 'http://www.w3.org/2000/10/swap/log#implies' , '_:b0' ] ,
2145+ ...[
2146+ ...list ( [ '_:b2' , '_:b6' ] , [ '_:b7' , '"31622400"^^http://www.w3.org/2001/XMLSchema#integer' ] ) ,
2147+ [ '_:b2' , 'http://www.w3.org/2000/10/swap/math#integerQuotient' , '?age' ] ,
2148+ ...list ( [ '_:b3' , '?date' ] , [ '_:b4' , '_:b5' ] ) ,
2149+ [ '?s' , 'http://xmlns.com/foaf/0.1/birthday' , '_:b5' ] ,
2150+ [ '_:b3' , 'http://www.w3.org/2000/10/swap/math#difference' , '_:b6' ] ,
2151+ ] . map ( elem => [ ...elem , '_:b1' ] )
2152+ ) ) ;
2153+
20612154 describe ( 'should parse a formula as list item' ,
20622155 shouldParse ( parser , '<a> <findAll> ( <b> { <b> a <type>. <b> <something> <foo> } <o> ).' ,
20632156 [ 'a' , 'findAll' , '_:b0' ] ,
2064- [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first' , 'b' ] ,
2065- [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest' , '_:b2' ] ,
2066- [ '_:b2' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first' , 'o' ] ,
2067- [ '_:b2' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' ] ,
2157+ ...list ( [ '_:b0' , 'b' ] , [ '_:b2' , 'o' ] ) ,
20682158 [ 'b' , 'something' , 'foo' , '_:b1' ] ,
20692159 [ 'b' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'type' , '_:b1' ]
20702160 ) ) ;
@@ -2120,6 +2210,55 @@ describe('Parser', () => {
21202210 it ( 'should not parse nested quads' ,
21212211 shouldNotParse ( parser , '<<_:a <http://ex.org/b> _:b <http://ex.org/b>>> <http://ex.org/b> "c" .' ,
21222212 'Expected >> to follow "_:.b" but got IRI on line 1.' ) ) ;
2213+
2214+ for ( const [ elem , value ] of [
2215+ [ '()' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' ] ,
2216+ [ '( )' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' ] ,
2217+ [ '( )' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' ] ,
2218+ [ '<http://www.w3.org/1999/02/22-rdf-syntax-ns#nil>' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' ] ,
2219+ [ ':joe' , 'ex:joe' ] ,
2220+ [ '<<:joe a :Person>>' , [ 'ex:joe' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'ex:Person' ] ] ,
2221+ ] ) {
2222+ for ( const pathType of [ '!' , '^' ] ) {
2223+ // eslint-disable-next-line no-inner-declarations
2224+ function son ( bnode ) {
2225+ return pathType === '!' ? [ value , 'f:son' , `_:b${ bnode } ` ] : [ `_:b${ bnode } ` , 'f:son' , value ] ;
2226+ }
2227+
2228+ for ( const [ f , triple ] of [
2229+ [ x => `(${ x } ) a :List .` , [ '_:b0' , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' , 'ex:List' ] ] ,
2230+ // [x => `<l> (${x}) <m> .`, ['l', '_:b0', 'm']],
2231+ [ x => `<l> <is> (${ x } ) .` , [ 'l' , 'is' , '_:b0' ] ] ,
2232+ ] ) {
2233+ // eslint-disable-next-line no-inner-declarations
2234+ function check ( content , ...triples ) {
2235+ describe ( `should parse [${ f ( content ) } ]` ,
2236+ shouldParse ( parser , `@prefix : <ex:>. @prefix fam: <f:>.${ f ( content ) } ` ,
2237+ triple , ...triples ) ) ;
2238+ }
2239+
2240+ check ( `${ elem } ${ pathType } fam:son` , ...list ( [ '_:b0' , '_:b1' ] ) , son ( '1' ) ) ;
2241+ check ( `(${ elem } ${ pathType } fam:son)` , ...list ( [ '_:b0' , '_:b1' ] ) , ...list ( [ '_:b1' , '_:b2' ] ) , son ( '2' ) ) ;
2242+
2243+ check ( `${ elem } ${ pathType } fam:son <x> <y>` , ...list ( [ '_:b0' , '_:b1' ] , [ '_:b2' , 'x' ] , [ '_:b3' , 'y' ] ) , son ( '1' ) ) ;
2244+ check ( `<x> ${ elem } ${ pathType } fam:son <y>` , ...list ( [ '_:b0' , 'x' ] , [ '_:b1' , '_:b2' ] , [ '_:b3' , 'y' ] ) , son ( '2' ) ) ;
2245+ check ( `<x> <y> ${ elem } ${ pathType } fam:son` , ...list ( [ '_:b0' , 'x' ] , [ '_:b1' , 'y' ] , [ '_:b2' , '_:b3' ] ) , son ( '3' ) ) ;
2246+
2247+ check ( `(${ elem } ${ pathType } fam:son) <x> <y>` ,
2248+ ...list ( [ '_:b0' , '_:b1' ] , [ '_:b3' , 'x' ] , [ '_:b4' , 'y' ] ) ,
2249+ ...list ( [ '_:b1' , '_:b2' ] ) ,
2250+ son ( '2' ) ) ;
2251+ check ( `<x> (${ elem } ${ pathType } fam:son) <y>` ,
2252+ ...list ( [ '_:b0' , 'x' ] , [ '_:b1' , '_:b2' ] , [ '_:b4' , 'y' ] ) ,
2253+ ...list ( [ '_:b2' , '_:b3' ] ) ,
2254+ son ( '3' ) ) ;
2255+ check ( `<x> <y> (${ elem } ${ pathType } fam:son)` ,
2256+ ...list ( [ '_:b0' , 'x' ] , [ '_:b1' , 'y' ] , [ '_:b2' , '_:b3' ] ) ,
2257+ ...list ( [ '_:b3' , '_:b4' ] ) ,
2258+ son ( '4' ) ) ;
2259+ }
2260+ }
2261+ }
21232262 } ) ;
21242263
21252264 describe ( 'A Parser instance for the N3 format with the explicitQuantifiers option' , ( ) => {
@@ -2638,7 +2777,6 @@ describe('Parser', () => {
26382777function splitAllWays ( result , left , right , chunkSize ) {
26392778 // Push current left + right to the result list
26402779 result . push ( left . concat ( right ) ) ;
2641- // document.write(left.concat(right) + '<br />');
26422780
26432781 // If we still have chars to work with in the right side then keep splitting
26442782 if ( right . length > 1 ) {
@@ -2705,7 +2843,7 @@ function _shouldParseChunks(parser, input, items) {
27052843function shouldParse ( parser , input ) {
27062844 return ( ) => {
27072845 const expected = Array . prototype . slice . call ( arguments , 1 ) ;
2708- // Shift parameters as necessary
2846+ // Shift parameters as necessary
27092847 if ( parser . call )
27102848 expected . shift ( ) ;
27112849 else
@@ -2804,3 +2942,15 @@ function itShouldResolve(baseIRI, relativeIri, expected) {
28042942 } ) ;
28052943 } ) ;
28062944}
2945+
2946+ // creates an RDF list from the input
2947+ function list ( ...elems ) {
2948+ const arr = [ ] ;
2949+ for ( let i = 0 ; i < elems . length ; i ++ ) {
2950+ arr . push (
2951+ [ elems [ i ] [ 0 ] , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first' , elems [ i ] [ 1 ] ] ,
2952+ [ elems [ i ] [ 0 ] , 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest' , i + 1 === elems . length ? 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' : elems [ i + 1 ] [ 0 ] ]
2953+ ) ;
2954+ }
2955+ return arr ;
2956+ }
0 commit comments