From 7e79b01fda9469d4f52c748729df1e3fde864258 Mon Sep 17 00:00:00 2001 From: Peter Ohler Date: Mon, 30 Oct 2023 19:23:09 -0400 Subject: [PATCH] Jp exists bug (#148) * Fix jp exists bug --- CHANGELOG.md | 4 ++++ jp/parse.go | 16 ++++++++++++---- jp/parse_test.go | 5 +++++ jp/script_test.go | 4 ++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad55c1b..b50eac5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm The structure and content of this file follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [1.20.2] - 2023-10-30 +### Fixed +- A script of `@.x` is now read correctly as `@.x exists true`. + ## [1.20.1] - 2023-10-20 ### Fixed - Calling jp.Set on a map or struct with a nil value no longer panics diff --git a/jp/parse.go b/jp/parse.go index a531b7a..2566e35 100644 --- a/jp/parse.go +++ b/jp/parse.go @@ -581,8 +581,12 @@ func (p *parser) readEquation() (eq *Equation) { p.readFunc(search, eq) default: eq.left = p.readEqValue() - eq.o = p.readEqOp() - eq.right = p.readEqValue() + var right bool + if eq.o, right = p.readEqOp(); right { + eq.right = &Equation{result: true} + } else { + eq.right = p.readEqValue() + } } for p.pos < len(p.buf) { b = p.nextNonSpace() @@ -593,7 +597,7 @@ func (p *parser) readEquation() (eq *Equation) { case ']': return } - o := p.readEqOp() + o, _ := p.readEqOp() if eq.o.prec <= o.prec { eq = &Equation{left: eq, o: o} eq.right = p.readEqValue() @@ -716,9 +720,13 @@ func partialOp(token []byte, b byte) bool { return false } -func (p *parser) readEqOp() (o *op) { +func (p *parser) readEqOp() (o *op, right bool) { var token []byte b := p.nextNonSpace() + switch b { + case 0, ']', ')', '(': + return exists, true + } for { if eqMap[b] != 'o' { if len(token) == 0 || !partialOp(token, b) { diff --git a/jp/parse_test.go b/jp/parse_test.go index 98ec09a..87e76b7 100644 --- a/jp/parse_test.go +++ b/jp/parse_test.go @@ -30,6 +30,9 @@ func TestParse(t *testing.T) { {src: "@..", expect: "@.."}, {src: "@..x.y", expect: "@..x.y"}, {src: "@.*", expect: "@.*"}, + {src: "@['x']", expect: "@.x"}, + {src: "@['@x']", expect: "@['@x']"}, + {src: "[?@['@type'] == 'something']", expect: "[?(@['@type'] == 'something')]"}, {src: "[1,2]", expect: "[1,2]"}, {src: "abc..def", expect: "abc..def"}, {src: "abc[*].def", expect: "abc[*].def"}, @@ -57,6 +60,8 @@ func TestParse(t *testing.T) { {src: "$[ 1, 'a' , 2 ,'b' ]", expect: "$[1,'a',2,'b']"}, {src: "$[?(@.x == 'abc')]", expect: "$[?(@.x == 'abc')]"}, {src: "$[?(1==1)]", expect: "$[?(1 == 1)]"}, + {src: "$[?(@.x)]", expect: "$[?(@.x exists true)]"}, + {src: "$[?@.x]", expect: "$[?(@.x exists true)]"}, {src: `['a\\b']`, expect: `['a\\b']`}, {src: `[:]`, expect: `[:]`}, {src: `[::]`, expect: `[:]`}, diff --git a/jp/script_test.go b/jp/script_test.go index 9a8cde4..1c198e5 100644 --- a/jp/script_test.go +++ b/jp/script_test.go @@ -61,6 +61,8 @@ func TestScriptParse(t *testing.T) { {src: "(@.x<5)", expect: "(@.x < 5)"}, {src: "(@.x<123)", expect: "(@.x < 123)"}, {src: "(@.x == 3)", expect: "(@.x == 3)"}, + {src: "(@['x'] == 3)", expect: "(@.x == 3)"}, + {src: "(@['@x'] == 3)", expect: "(@['@x'] == 3)"}, {src: "(@.*.xyz==true)", expect: "(@.*.xyz == true)"}, {src: "(@.x.* == 3)", expect: "(@.x.* == 3)"}, {src: "(@.. == 3)", expect: "(@.. == 3)"}, @@ -83,6 +85,8 @@ func TestScriptParse(t *testing.T) { {src: "(@ empty true)", expect: "(@ empty true)"}, {src: "(@ has true)", expect: "(@ has true)"}, {src: "(@ exists true)", expect: "(@ exists true)"}, + {src: "(@)", expect: "(@ exists true)"}, + {src: "@", expect: "(@ exists true)"}, {src: "(@ =~ /abc/)", expect: "(@ ~= /abc/)"}, {src: "(@ ~= /a\\/c/)", expect: "(@ ~= /a\\/c/)"},