Skip to content

Commit 15ad4d2

Browse files
committed
Add missing scanBlankSpace parsing &&s
Add `lex.scanBlankSpace()` to the loop in `Parser.parseLogicalAndExpr` so that multiple consecutive `&&` comparison expressions delimited by blank spaces will be properly parsed. Add tests to ensure that the multiple consecutive `||` comparison expressions are also properly parsed. Thanks @jarangutan for the report and @jg-rp for the analysis. Resolves #24.
1 parent ac67e0a commit 15ad4d2

File tree

3 files changed

+161
-0
lines changed

3 files changed

+161
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ All notable changes to this project will be documented in this file. It uses the
1919
### 🐞 Bug Fixes
2020

2121
* Allow `true`, `false`, and `null` to be used as selectors, e.g., `$.true`.
22+
* Fixed bug that prevented multiple blank-space delimited ANDed comparison
23+
operations from being parsed. For example, `$[@.x=="hi"&&@.y!=3&&@[1]==1]`
24+
would parse but `$[@.x == "hi" && @.y !=3 && @[1]==1]` would not. Thanks
25+
to @jarangutan for the bug report and @jg-rp for the analysis ([#24]).
2226

2327
### 📔 Notes
2428

@@ -29,6 +33,8 @@ All notable changes to this project will be documented in this file. It uses the
2933

3034
[v0.10.1]: https://github.com/theory/jsonpath/compare/v0.10.0...v0.10.1
3135
[compliance test suite]: https://github.com/jsonpath-standard/jsonpath-compliance-test-suite
36+
[#24]: https://github.com/theory/jsonpath/issues/24
37+
"theory/jsonpath#24 Filter with 2+ consecutive '&&' operators returns parsing error"
3238

3339
## [v0.10.0] — 2025-07-11
3440

parser/parse.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ func (p *parser) parseLogicalAndExpr() (spec.LogicalAnd, error) {
342342
return nil, err
343343
}
344344
ors = append(ors, expr)
345+
lex.scanBlankSpace()
345346
}
346347

347348
return spec.LogicalAnd(ors), nil

parser/parse_test.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,43 @@ func TestParseFilter(t *testing.T) {
383383
)),
384384
)),
385385
},
386+
{
387+
test: "multi_logical_and",
388+
query: `(@["x", 1] && $["y"] && @["a"])`,
389+
filter: spec.Filter(spec.And(
390+
spec.Paren(spec.And(
391+
spec.Existence(spec.Query(
392+
false,
393+
spec.Child(spec.Name("x"), spec.Index(1)),
394+
)),
395+
spec.Existence(spec.Query(
396+
true,
397+
spec.Child(spec.Name("y")),
398+
)),
399+
spec.Existence(spec.Query(
400+
false,
401+
spec.Child(spec.Name("a")),
402+
)),
403+
)),
404+
)),
405+
},
406+
{
407+
test: "logical_and_short_name",
408+
query: `@.x && @.y`,
409+
filter: spec.Filter(spec.And(
410+
spec.Existence(spec.Query(false, spec.Child(spec.Name("x")))),
411+
spec.Existence(spec.Query(false, spec.Child(spec.Name("y")))),
412+
)),
413+
},
414+
{
415+
test: "multi_logical_and_short_name",
416+
query: `@.x && @.y && @.z`,
417+
filter: spec.Filter(spec.And(
418+
spec.Existence(spec.Query(false, spec.Child(spec.Name("x")))),
419+
spec.Existence(spec.Query(false, spec.Child(spec.Name("y")))),
420+
spec.Existence(spec.Query(false, spec.Child(spec.Name("z")))),
421+
)),
422+
},
386423
{
387424
test: "paren_logical_or",
388425
query: `(@["x", 1] || $["y"])`,
@@ -399,6 +436,23 @@ func TestParseFilter(t *testing.T) {
399436
)),
400437
),
401438
},
439+
{
440+
test: "logical_or_short_name",
441+
query: `@.x && @.y`,
442+
filter: spec.Filter(spec.And(
443+
spec.Existence(spec.Query(false, spec.Child(spec.Name("x")))),
444+
spec.Existence(spec.Query(false, spec.Child(spec.Name("y")))),
445+
)),
446+
},
447+
{
448+
test: "multi_logical_and_short_name",
449+
query: `@.x && @.y && @.z`,
450+
filter: spec.Filter(spec.And(
451+
spec.Existence(spec.Query(false, spec.Child(spec.Name("x")))),
452+
spec.Existence(spec.Query(false, spec.Child(spec.Name("y")))),
453+
spec.Existence(spec.Query(false, spec.Child(spec.Name("z")))),
454+
)),
455+
},
402456
// NotParenExistExpr
403457
{
404458
test: "not_paren_current_exists",
@@ -669,6 +723,106 @@ func TestParseFilter(t *testing.T) {
669723
),
670724
)),
671725
},
726+
{
727+
test: "and_compare",
728+
query: `@.x == "hi" && @.y != 3`,
729+
filter: spec.Filter(spec.And(
730+
spec.Comparison(
731+
spec.SingularQuery(false, spec.Name("x")),
732+
spec.EqualTo,
733+
spec.Literal("hi"),
734+
),
735+
spec.Comparison(
736+
spec.SingularQuery(false, spec.Name("y")),
737+
spec.NotEqualTo,
738+
spec.Literal(int64(3)),
739+
),
740+
)),
741+
},
742+
{
743+
test: "multi_and_compare",
744+
query: `@.x == "hi" && @.y != 3 && $[1] == true`,
745+
filter: spec.Filter(spec.And(
746+
spec.Comparison(
747+
spec.SingularQuery(false, spec.Name("x")),
748+
spec.EqualTo,
749+
spec.Literal("hi"),
750+
),
751+
spec.Comparison(
752+
spec.SingularQuery(false, spec.Name("y")),
753+
spec.NotEqualTo,
754+
spec.Literal(int64(3)),
755+
),
756+
spec.Comparison(
757+
spec.SingularQuery(true, spec.Index(1)),
758+
spec.EqualTo,
759+
spec.Literal(true),
760+
),
761+
)),
762+
},
763+
{
764+
test: "multi_and_compare_compact",
765+
query: `@.x=="hi"&&@.y!=3&&$[1]==true`,
766+
filter: spec.Filter(spec.And(
767+
spec.Comparison(
768+
spec.SingularQuery(false, spec.Name("x")),
769+
spec.EqualTo,
770+
spec.Literal("hi"),
771+
),
772+
spec.Comparison(
773+
spec.SingularQuery(false, spec.Name("y")),
774+
spec.NotEqualTo,
775+
spec.Literal(int64(3)),
776+
),
777+
spec.Comparison(
778+
spec.SingularQuery(true, spec.Index(1)),
779+
spec.EqualTo,
780+
spec.Literal(true),
781+
),
782+
)),
783+
},
784+
{
785+
test: "multi_or_compare",
786+
query: `@.x == "hi" || @.y != 3 || $[1] == true`,
787+
filter: spec.Filter(
788+
spec.And(spec.Comparison(
789+
spec.SingularQuery(false, spec.Name("x")),
790+
spec.EqualTo,
791+
spec.Literal("hi"),
792+
)),
793+
spec.And(spec.Comparison(
794+
spec.SingularQuery(false, spec.Name("y")),
795+
spec.NotEqualTo,
796+
spec.Literal(int64(3)),
797+
)),
798+
spec.And(spec.Comparison(
799+
spec.SingularQuery(true, spec.Index(1)),
800+
spec.EqualTo,
801+
spec.Literal(true),
802+
)),
803+
),
804+
},
805+
{
806+
test: "multi_or_compare_compact",
807+
query: `@.x=="hi"||@.y!=3||$[1]==true`,
808+
filter: spec.Filter(
809+
spec.And(spec.Comparison(
810+
spec.SingularQuery(false, spec.Name("x")),
811+
spec.EqualTo,
812+
spec.Literal("hi"),
813+
)),
814+
spec.And(spec.Comparison(
815+
spec.SingularQuery(false, spec.Name("y")),
816+
spec.NotEqualTo,
817+
spec.Literal(int64(3)),
818+
)),
819+
spec.And(spec.Comparison(
820+
spec.SingularQuery(true, spec.Index(1)),
821+
spec.EqualTo,
822+
spec.Literal(true),
823+
)),
824+
),
825+
},
672826
{
673827
test: "invalid_logical_or",
674828
query: `(@["x", 1] || hi)`,

0 commit comments

Comments
 (0)