@@ -32,7 +32,7 @@ function parse(str) {
3232 if ( result . failPosition ) {
3333 pos = result . failPosition - 1
3434 }
35- return { type : 'error' , position : pos }
35+ return { type : 'error' , message : 'Unexpected end of query' , position : pos }
3636 }
3737 delete result . position
3838 delete result . failPosition
@@ -48,7 +48,7 @@ function parseExpr(str, pos, level) {
4848 // while handling the RHS of the multiplication in `1 + 2 * 3 + 4` we only parse `3`.
4949 //
5050 // `lhsLevel` is the precedence level of the currently parsed expression on
51- // the left-hand side. This is mainly used to handle non-associcativeness .
51+ // the left-hand side. This is mainly used to handle non-associativeness .
5252
5353 // This means that you'll see code like:
5454 // - `if (level > PREC_XXX) break`: Operator is at this precedence level.
@@ -77,34 +77,12 @@ function parseExpr(str, pos, level) {
7777 break
7878 }
7979 case '(' : {
80- let rhs = parseExpr ( str , skipWS ( str , pos + 1 ) , 0 )
81- if ( rhs . type === 'error' ) return rhs
82- pos = skipWS ( str , rhs . position )
83- switch ( str [ pos ] ) {
84- case ',' : {
85- // Tuples
86- marks = [ { name : 'tuple' , position : startPos } ] . concat ( rhs . marks )
87- pos = skipWS ( str , pos + 1 )
88- while ( true ) {
89- rhs = parseExpr ( str , pos , 0 )
90- if ( rhs . type === 'error' ) return rhs
91- pos = skipWS ( str , rhs . position )
92- if ( str [ pos ] !== ',' ) break
93- pos = skipWS ( str , pos + 1 )
94- }
95- if ( str [ pos ] !== ')' ) return { type : 'error' , position : pos }
96- pos ++
97- marks . push ( { name : 'tuple_end' , position : pos } )
98- break
99- }
100- case ')' : {
101- pos ++
102- marks = [ { name : 'group' , position : startPos } ] . concat ( rhs . marks )
103- break
104- }
105- default :
106- return { type : 'error' , position : pos }
107- }
80+ let result = parseGroupOrTuple ( str , pos )
81+ if ( result . type === 'error' ) return result
82+
83+ pos = result . position
84+ marks = result . marks
85+
10886 break
10987 }
11088 case '!' : {
@@ -147,7 +125,7 @@ function parseExpr(str, pos, level) {
147125 pos ++
148126 marks . push ( { name : 'array_end' , position : pos } )
149127 } else {
150- return { type : 'error' , position : pos }
128+ return { type : 'error' , message : 'Expected "]" after array expression' , position : pos }
151129 }
152130
153131 break
@@ -210,7 +188,7 @@ function parseExpr(str, pos, level) {
210188 pos ++
211189 }
212190 let expLen = parseRegex ( str , pos , NUM )
213- if ( ! expLen ) return { type : 'error' , position : pos }
191+ if ( ! expLen ) return { type : 'error' , message : 'Exponent must be a number' , position : pos }
214192 pos += expLen
215193 }
216194
@@ -249,7 +227,7 @@ function parseExpr(str, pos, level) {
249227 }
250228
251229 if ( ! marks ) {
252- return { type : 'error' , position : pos }
230+ return { type : 'error' , message : 'Expected expression' , position : pos }
253231 }
254232
255233 let lhsLevel = 12
@@ -272,7 +250,7 @@ function parseExpr(str, pos, level) {
272250 }
273251 marks . push ( { name : 'traversal_end' , position : pos } )
274252 continue
275- }
253+ } // ignore if type === 'error'
276254
277255 let token = str [ innerPos ]
278256 switch ( token ) {
@@ -401,7 +379,7 @@ function parseExpr(str, pos, level) {
401379 // pipe call
402380 let identPos = skipWS ( str , innerPos + 1 )
403381 let identLen = parseRegex ( str , identPos , IDENT )
404- if ( ! identLen ) return { type : 'error' , position : identPos }
382+ if ( ! identLen ) return { type : 'error' , message : 'Expected identifier' , position : identPos }
405383 pos = identPos + identLen
406384 if ( str [ pos ] === '(' || str [ pos ] === ':' ) {
407385 let result = parseFuncCall ( str , identPos , pos )
@@ -440,7 +418,7 @@ function parseExpr(str, pos, level) {
440418 break
441419 }
442420 case 'd' : {
443- // asc
421+ // desc
444422 if ( str . slice ( innerPos , innerPos + 4 ) !== 'desc' ) break loop
445423 if ( level > PREC_ORDER || lhsLevel < PREC_ORDER ) break loop
446424 marks . unshift ( { name : 'desc' , position : startPos } )
@@ -502,7 +480,8 @@ function parseExpr(str, pos, level) {
502480
503481 if ( isGroup ) {
504482 pos = skipWS ( str , pos )
505- if ( str [ pos ] !== ')' ) return { type : 'error' , position : pos }
483+ if ( str [ pos ] !== ')' )
484+ return { type : 'error' , message : 'Expected ")" in group' , position : pos }
506485 pos ++
507486 }
508487
@@ -534,14 +513,57 @@ function parseExpr(str, pos, level) {
534513 return { type : 'success' , marks, position : pos , failPosition}
535514}
536515
516+ function parseGroupOrTuple ( str , pos ) {
517+ const startPos = pos
518+ let marks
519+ let rhs = parseExpr ( str , skipWS ( str , pos + 1 ) , 0 )
520+ if ( rhs . type === 'error' ) return rhs
521+ pos = skipWS ( str , rhs . position )
522+ switch ( str [ pos ] ) {
523+ case ',' : {
524+ // Tuples
525+ marks = [ { name : 'tuple' , position : startPos } ] . concat ( rhs . marks )
526+ pos = skipWS ( str , pos + 1 )
527+ while ( true ) {
528+ rhs = parseExpr ( str , pos , 0 )
529+ if ( rhs . type === 'error' ) return rhs
530+ marks . push ( ...rhs . marks )
531+ pos = skipWS ( str , rhs . position )
532+ if ( str [ pos ] !== ',' ) break
533+ pos = skipWS ( str , pos + 1 )
534+ }
535+ if ( str [ pos ] !== ')' )
536+ return { type : 'error' , message : 'Expected ")" after tuple expression' , position : pos }
537+ pos ++
538+ marks . push ( { name : 'tuple_end' , position : pos } )
539+ break
540+ }
541+ case ')' : {
542+ pos ++
543+ marks = [ { name : 'group' , position : startPos } ] . concat ( rhs . marks )
544+ break
545+ }
546+ default :
547+ return { type : 'error' , message : `Unexpected character "${ str [ pos ] } "` , position : pos }
548+ }
549+
550+ return { type : 'success' , marks, position : pos }
551+ }
552+
537553function parseTraversal ( str , pos ) {
538554 let startPos = pos
539555 switch ( str [ pos ] ) {
540556 case '.' : {
541557 pos = skipWS ( str , pos + 1 )
558+
559+ // TODO: allow tuples/groups in a traversal for selectors
560+ // if (str[pos] === '(') {
561+ // return parseGroupOrTuple(str, pos)
562+ // }
563+
542564 let identStart = pos
543565 let identLen = parseRegex ( str , pos , IDENT )
544- if ( ! identLen ) return { type : 'error' , position : pos }
566+ if ( ! identLen ) return { type : 'error' , message : 'Expected identifier after "."' , position : pos }
545567 pos += identLen
546568
547569 return {
@@ -555,7 +577,8 @@ function parseTraversal(str, pos) {
555577 }
556578 }
557579 case '-' :
558- if ( str [ pos + 1 ] !== '>' ) return { type : 'error' , position : pos }
580+ if ( str [ pos + 1 ] !== '>' )
581+ return { type : 'error' , message : 'Expected ">" in reference' , position : pos }
559582 // ->
560583
561584 let marks = [ { name : 'deref' , position : startPos } ]
@@ -607,7 +630,8 @@ function parseTraversal(str, pos) {
607630 let rhs = parseExpr ( str , pos , 0 )
608631 if ( rhs . type === 'error' ) return rhs
609632 pos = skipWS ( str , rhs . position )
610- if ( str [ pos ] !== ']' ) return { type : 'error' , position : pos }
633+ if ( str [ pos ] !== ']' )
634+ return { type : 'error' , message : 'Expected "]" after array expression' , position : pos }
611635
612636 return {
613637 type : 'success' ,
@@ -619,7 +643,8 @@ function parseTraversal(str, pos) {
619643 }
620644 }
621645
622- if ( str [ pos ] !== ']' ) return { type : 'error' , position : pos }
646+ if ( str [ pos ] !== ']' )
647+ return { type : 'error' , message : 'Expected "]" after array expression' , position : pos }
623648
624649 return {
625650 type : 'success' ,
@@ -645,7 +670,7 @@ function parseTraversal(str, pos) {
645670 }
646671 }
647672
648- return { type : 'error' , position : pos }
673+ return { type : 'error' , message : 'Unexpected character in traversal' , position : pos }
649674}
650675
651676function parseFuncCall ( str , startPos , pos ) {
@@ -658,10 +683,11 @@ function parseFuncCall(str, startPos, pos) {
658683 marks . push ( { name : 'ident' , position : startPos } , { name : 'ident_end' , position : pos } )
659684 pos = skipWS ( str , pos + 2 )
660685 let nameLen = parseRegex ( str , pos , IDENT )
661- if ( ! nameLen ) return { type : 'error' , position : pos }
686+ if ( ! nameLen ) return { type : 'error' , message : 'Expected function name' , position : pos }
662687 marks . push ( { name : 'ident' , position : pos } , { name : 'ident_end' , position : pos + nameLen } )
663688 pos = skipWS ( str , pos + nameLen )
664- if ( str [ pos ] !== '(' ) return { type : 'error' , position : pos }
689+ if ( str [ pos ] !== '(' )
690+ return { type : 'error' , message : 'Expected "(" after function name' , position : pos }
665691 pos ++
666692 // Consume any whitespace in front of the function argument.
667693 pos = skipWS ( str , pos )
@@ -679,6 +705,17 @@ function parseFuncCall(str, startPos, pos) {
679705 marks = marks . concat ( result . marks )
680706 lastPos = result . position
681707 pos = skipWS ( str , result . position )
708+
709+ // TODO: allow traversals in function arguments for selectors
710+ // if (str[pos] === '.') {
711+ // result = parseTraversal(str, pos)
712+ // if (result.type === 'error') return result
713+ // TODO: what to do with type === 'warning'?
714+ // marks = marks.concat(result.marks)
715+ // lastPos = result.position
716+ // pos = skipWS(str, result.position)
717+ // }
718+
682719 if ( str [ pos ] !== ',' ) break
683720 pos = skipWS ( str , pos + 1 )
684721 // Also allow trailing commas
@@ -687,7 +724,7 @@ function parseFuncCall(str, startPos, pos) {
687724 }
688725
689726 if ( str [ pos ] !== ')' ) {
690- return { type : 'error' , position : pos }
727+ return { type : 'error' , message : 'Expected ")" after function arguments' , position : pos }
691728 }
692729
693730 // NOTE: a bit arbitrary the func_args_end points comes before the whitespace.
@@ -739,7 +776,7 @@ function parseObject(str, pos) {
739776 }
740777
741778 if ( str [ pos ] !== '}' ) {
742- return { type : 'error' , position : pos }
779+ return { type : 'error' , message : 'Expected "}" after object' , position : pos }
743780 }
744781
745782 pos ++
@@ -752,7 +789,7 @@ function parseString(str, pos) {
752789 pos = pos + 1
753790 const marks = [ { name : 'str' , position : pos } ]
754791 str: for ( ; ; pos ++ ) {
755- if ( pos > str . length ) return { type : 'error' , position : pos }
792+ if ( pos > str . length ) return { type : 'error' , message : 'Unexpected end of query' , position : pos }
756793
757794 switch ( str [ pos ] ) {
758795 case token : {
0 commit comments