From 1b3e8eeecfbc27057893c6391b01de6f4bb3aa70 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Tue, 5 Jan 2021 08:45:18 +0000 Subject: [PATCH 01/26] Move test suite to its own repository Fixes https://github.com/jsonpath-standard/jsonpath-reference-implementation/issues/3 --- .github/workflows/quickstart.yml | 6 + .gitmodules | 3 + README.md | 6 +- jsonpath-compliance-test-suite | 1 + tests/cts.json | 748 ------------------------------- tests/cts.rs | 3 +- 6 files changed, 16 insertions(+), 751 deletions(-) create mode 100644 .gitmodules create mode 160000 jsonpath-compliance-test-suite delete mode 100644 tests/cts.json diff --git a/.github/workflows/quickstart.yml b/.github/workflows/quickstart.yml index e211202..f930f67 100644 --- a/.github/workflows/quickstart.yml +++ b/.github/workflows/quickstart.yml @@ -15,6 +15,8 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v2 + with: + submodules: 'true' - name: Install stable toolchain uses: actions-rs/toolchain@v1 @@ -34,6 +36,8 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v2 + with: + submodules: 'true' - name: Install stable toolchain uses: actions-rs/toolchain@v1 @@ -53,6 +57,8 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v2 + with: + submodules: 'true' - name: Install stable toolchain uses: actions-rs/toolchain@v1 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4972b45 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "jsonpath-compliance-test-suite"] + path = jsonpath-compliance-test-suite + url = https://github.com/jsonpath-standard/jsonpath-compliance-test-suite.git diff --git a/README.md b/README.md index 56dc99a..95856f4 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ This Reference Implementation follows, and usually lags behind, the [internet draft](https://jsonpath-standard.github.io/internet-draft/). -See [cts.json](tests/cts.json) for the Compliance Test Suite and [grammar.pest](src/grammar.pest) for the Parsing Expression Grammar of the Reference Implementation. +See [grammar.pest](src/grammar.pest) for the Parsing Expression Grammar of the Reference Implementation. -See the [Developer Guide](./DEVELOPING.md) if you want to run the code against the test suite. See the [Contributor Guide](./CONTRIBUTING.md) if you'd like to submit changes. \ No newline at end of file +See the [Developer Guide](./DEVELOPING.md) if you want to run the code against the test suite. See the [Contributor Guide](./CONTRIBUTING.md) if you'd like to submit changes. + +The Compliance Test Suite is in its own [repository](https://github.com/jsonpath-standard/jsonpath-compliance-test-suite). \ No newline at end of file diff --git a/jsonpath-compliance-test-suite b/jsonpath-compliance-test-suite new file mode 160000 index 0000000..ab56e44 --- /dev/null +++ b/jsonpath-compliance-test-suite @@ -0,0 +1 @@ +Subproject commit ab56e44bf7ea9997f2f3a10bbc60ee317c151a61 diff --git a/tests/cts.json b/tests/cts.json deleted file mode 100644 index b2a796a..0000000 --- a/tests/cts.json +++ /dev/null @@ -1,748 +0,0 @@ -{ "tests": [ - { - "name": "root", - "selector": "$", - "document": ["first", "second"], - "result": [["first", "second"]] - }, { - "name": "dot child", - "selector": "$.a", - "document": {"a" : "A", "b" : "B"}, - "result": ["A"] - }, { - "name": "dot child, ☺ name", - "selector": "$.☺", - "document": {"☺" : "A", "b" : "B"}, - "result": ["A"] - }, { - "name": "dot child, invalid character", - "selector": "$.&", - "invalid_selector": true - }, { - "name": "dot child absent", - "selector": "$.c", - "document": {"a" : "A", "b" : "B"}, - "result": [] - }, { - "name": "dot child of array", - "selector": "$.a", - "document": ["first", "second"], - "result": [] - }, { - "name": "wildcarded child", - "selector": "$.*", - "document": {"a" : "A", "b" : "B"}, - "result": ["A", "B"] - }, { - "name": "wildcarded child of array", - "selector": "$.*", - "document": ["first", "second"], - "result": ["first", "second"] - }, { - "name": "wildcarded child dot child", - "selector": "$.*.a", - "document": {"x": {"a" : "Ax", "b" : "Bx"}, "y": {"a" : "Ay", "b" : "By"}}, - "result": ["Ax", "Ay"] - }, { - "name": "union child, double quotes", - "selector": "$[\"a\"]", - "document": {"a" : "A", "b" : "B"}, - "result": ["A"] - }, { - "name": "union child absent, double quotes", - "selector": "$[\"c\"]", - "document": {"a" : "A", "b" : "B"}, - "result": [] - }, { - "name": "union child of array, double quotes", - "selector": "$[\"a\"]", - "document": ["first", "second"], - "result": [] - }, { - "name": "union child, double quotes, embedded U+0000", - "selector": "$[\"\u0000\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0001", - "selector": "$[\"\u0001\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0002", - "selector": "$[\"\u0002\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0003", - "selector": "$[\"\u0003\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0004", - "selector": "$[\"\u0004\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0005", - "selector": "$[\"\u0005\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0006", - "selector": "$[\"\u0006\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0007", - "selector": "$[\"\u0007\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0008", - "selector": "$[\"\u0008\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0009", - "selector": "$[\"\u0009\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+000A", - "selector": "$[\"\u000A\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+000B", - "selector": "$[\"\u000B\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+000C", - "selector": "$[\"\u000C\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+000D", - "selector": "$[\"\u000D\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+000E", - "selector": "$[\"\u000E\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+000F", - "selector": "$[\"\u000F\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0010", - "selector": "$[\"\u0010\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0011", - "selector": "$[\"\u0011\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0012", - "selector": "$[\"\u0012\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0013", - "selector": "$[\"\u0013\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0014", - "selector": "$[\"\u0014\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0015", - "selector": "$[\"\u0015\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0016", - "selector": "$[\"\u0016\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0017", - "selector": "$[\"\u0017\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0018", - "selector": "$[\"\u0018\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0019", - "selector": "$[\"\u0019\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+001A", - "selector": "$[\"\u001A\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+001B", - "selector": "$[\"\u001B\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+001C", - "selector": "$[\"\u001C\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+001D", - "selector": "$[\"\u001D\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+001E", - "selector": "$[\"\u001E\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+001F", - "selector": "$[\"\u001F\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded U+0020", - "selector": "$[\"\u0020\"]", - "document": {"\u0020" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, escaped double quote", - "selector": "$[\"\\\"\"]", - "document": {"\"" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, escaped reverse solidus", - "selector": "$[\"\\\\\"]", - "document": {"\\" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, escaped solidus", - "selector": "$[\"\\/\"]", - "document": {"/" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, escaped backspace", - "selector": "$[\"\\b\"]", - "document": {"\u0008" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, escaped form feed", - "selector": "$[\"\\f\"]", - "document": {"\u000C" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, escaped line feed", - "selector": "$[\"\\n\"]", - "document": {"\u000A" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, escaped carriage return", - "selector": "$[\"\\r\"]", - "document": {"\u000D" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, escaped tab", - "selector": "$[\"\\t\"]", - "document": {"\u0009" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, escaped ☺", - "selector": "$[\"\\u263A\"]", - "document": {"☺" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, surrogate pair 𝄞", - "selector": "$[\"\\uD834\\uDD1E\"]", - "document": {"𝄞" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, surrogate pair 😀", - "selector": "$[\"\\uD83D\\uDE00\"]", - "document": {"😀" : "A"}, - "result": ["A"] - }, { - "name": "union child, double quotes, invalid escaped ☺", - "selector": "$[\"\\u263a\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, invalid escaped single quote", - "selector": "$[\"\\'\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, embedded double quote", - "selector": "$[\"\"\"]", - "invalid_selector": true - }, { - "name": "union child, double quotes, incomplete escape", - "selector": "$[\"\\\"]", - "invalid_selector": true - }, { - "name": "union child, single quotes", - "selector": "$['a']", - "document": {"a" : "A", "b" : "B"}, - "result": ["A"] - }, { - "name": "union child absent, single quotes", - "selector": "$['c']", - "document": {"a" : "A", "b" : "B"}, - "result": [] - }, { - "name": "union child of array, single quotes", - "selector": "$['a']", - "document": ["first", "second"], - "result": [] - }, { - "name": "union child, single quotes, embedded U+0000", - "selector": "$['\u0000']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0001", - "selector": "$['\u0001']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0002", - "selector": "$['\u0002']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0003", - "selector": "$['\u0003']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0004", - "selector": "$['\u0004']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0005", - "selector": "$['\u0005']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0006", - "selector": "$['\u0006']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0007", - "selector": "$['\u0007']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0008", - "selector": "$['\u0008']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0009", - "selector": "$['\u0009']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+000A", - "selector": "$['\u000A']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+000B", - "selector": "$['\u000B']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+000C", - "selector": "$['\u000C']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+000D", - "selector": "$['\u000D']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+000E", - "selector": "$['\u000E']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+000F", - "selector": "$['\u000F']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0010", - "selector": "$['\u0010']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0011", - "selector": "$['\u0011']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0012", - "selector": "$['\u0012']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0013", - "selector": "$['\u0013']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0014", - "selector": "$['\u0014']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0015", - "selector": "$['\u0015']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0016", - "selector": "$['\u0016']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0017", - "selector": "$['\u0017']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0018", - "selector": "$['\u0018']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0019", - "selector": "$['\u0019']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+001A", - "selector": "$['\u001A']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+001B", - "selector": "$['\u001B']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+001C", - "selector": "$['\u001C']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+001D", - "selector": "$['\u001D']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+001E", - "selector": "$['\u001E']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+001F", - "selector": "$['\u001F']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded U+0020", - "selector": "$['\u0020']", - "document": {"\u0020" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, escaped single quote", - "selector": "$['\\'']", - "document": {"'" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, escaped reverse solidus", - "selector": "$['\\\\']", - "document": {"\\" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, escaped solidus", - "selector": "$['\\/']", - "document": {"/" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, escaped backspace", - "selector": "$['\\b']", - "document": {"\u0008" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, escaped form feed", - "selector": "$['\\f']", - "document": {"\u000C" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, escaped line feed", - "selector": "$['\\n']", - "document": {"\u000A" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, escaped carriage return", - "selector": "$['\\r']", - "document": {"\u000D" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, escaped tab", - "selector": "$['\\t']", - "document": {"\u0009" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, escaped ☺", - "selector": "$['\\u263A']", - "document": {"☺" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, surrogate pair 𝄞", - "selector": "$['\\uD834\\uDD1E']", - "document": {"𝄞" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, surrogate pair 😀", - "selector": "$['\\uD83D\\uDE00']", - "document": {"😀" : "A"}, - "result": ["A"] - }, { - "name": "union child, single quotes, invalid escaped ☺", - "selector": "$['\\u263a']", - "invalid_selector": true - }, { - "name": "union child, single quotes, invalid escaped double quote", - "selector": "$['\\\"']", - "invalid_selector": true - }, { - "name": "union child, single quotes, embedded single quote", - "selector": "$[''']", - "invalid_selector": true - }, { - "name": "union child, single quotes, incomplete escape", - "selector": "$['\\']", - "invalid_selector": true - }, { - "name": "union", - "selector": "$[0,2]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [0, 2] - }, { - "name": "union with whitespace", - "selector": "$[ 0 , 1 ]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [0, 1] - }, { - "name": "empty union", - "selector": "$[]", - "invalid_selector": true - }, { - "name": "union array access", - "selector": "$[0]", - "document": ["first", "second"], - "result": ["first"] - }, { - "name": "union array access, 1", - "selector": "$[1]", - "document": ["first", "second"], - "result": ["second"] - }, { - "name": "union array access, out of bound", - "selector": "$[2]", - "document": ["first", "second"], - "result": [] - }, { - "name": "union array access, overflowing index", - "selector": "$[231584178474632390847141970017375815706539969331281128078915168015826259279872]", - "invalid_selector": true - }, { - "name": "union array access, negative", - "selector": "$[-1]", - "document": ["first", "second"], - "result": ["second"] - }, { - "name": "union array access, more negative", - "selector": "$[-2]", - "document": ["first", "second"], - "result": ["first"] - }, { - "name": "union array access, negative out of bound", - "selector": "$[-3]", - "document": ["first", "second"], - "result": [] - }, { - "name": "union array access, on object", - "selector": "$[0]", - "document": {"foo": 1}, - "result": [] - }, { - "name": "union array access, leading 0", - "selector": "$[01]", - "invalid_selector": true - }, { - "name": "union array access, leading -0", - "selector": "$[-01]", - "invalid_selector": true - }, { - "name": "union array slice", - "selector": "$[1:3]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [1, 2] - }, { - "name": "union array slice with step", - "selector": "$[1:6:2]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [1, 3, 5] - }, { - "name": "union array slice with everything omitted, short form", - "selector": "$[:]", - "document": [0, 1, 2, 3], - "result": [0, 1, 2, 3] - }, { - "name": "union array slice with everything omitted, long form", - "selector": "$[::]", - "document": [0, 1, 2, 3], - "result": [0, 1, 2, 3] - }, { - "name": "union array slice with start omitted", - "selector": "$[:2]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [0, 1] - }, { - "name": "union array slice with start and end omitted", - "selector": "$[::2]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [0, 2, 4, 6, 8] - }, { - "name": "union array slice, last index", - "selector": "$[-1]", - "document": [0, 1, 2, 3], - "result": [3] - }, { - "name": "union array slice, overflowed index", - "selector": "$[4]", - "document": [0, 1, 2, 3], - "result": [] - }, { - "name": "union array slice, underflowed index", - "selector": "$[-5]", - "document": [0, 1, 2, 3], - "result": [] - }, { - "name": "union array slice, negative step with default start and end", - "selector": "$[::-1]", - "document": [0, 1, 2, 3], - "result": [3, 2, 1, 0] - }, { - "name": "union array slice, negative step with default start", - "selector": "$[:0:-1]", - "document": [0, 1, 2, 3], - "result": [3, 2, 1] - }, { - "name": "union array slice, negative step with default end", - "selector": "$[2::-1]", - "document": [0, 1, 2, 3], - "result": [2, 1, 0] - }, { - "name": "union array slice, larger negative step", - "selector": "$[::-2]", - "document": [0, 1, 2, 3], - "result": [3, 1] - }, { - "name": "union array slice, negative range with default step", - "selector": "$[-1:-3]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [] - }, { - "name": "union array slice, negative range with negative step", - "selector": "$[-1:-3:-1]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [9, 8] - }, { - "name": "union array slice, negative range with larger negative step", - "selector": "$[-1:-6:-2]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [9, 7, 5] - }, { - "name": "union array slice, larger negative range with larger negative step", - "selector": "$[-1:-7:-2]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [9, 7, 5] - }, { - "name": "union array slice, negative from, positive to", - "selector": "$[-5:7]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [5, 6] - }, { - "name": "union array slice, negative from", - "selector": "$[-2:]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [8, 9] - }, { - "name": "union array slice, positive from, negative to", - "selector": "$[1:-1]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [1, 2, 3, 4, 5, 6, 7, 8] - }, { - "name": "union array slice, negative from, positive to, negative step", - "selector": "$[-1:1:-1]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [9, 8, 7, 6, 5, 4, 3, 2] - }, { - "name": "union array slice, positive from, negative to, negative step", - "selector": "$[7:-5:-1]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [7, 6] - }, { - "name": "union array slice, too many colons", - "selector": "$[1:2:3:4]", - "invalid_selector": true - }, { - "name": "union array slice, non-integer array index", - "selector": "$[1:2:a]", - "invalid_selector": true - }, { - "name": "union array slice, zero step", - "selector": "$[1:2:0]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [] - }, { - "name": "union array slice, empty range", - "selector": "$[2:2]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [] - }, { - "name": "union array slice, default indices with empty array", - "selector": "$[:]", - "document": [], - "result": [] - }, { - "name": "union array slice, negative step with empty array", - "selector": "$[::-1]", - "document": [], - "result": [] - }, { - "name": "union array slice, maximal range with positive step", - "selector": "$[0:10]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - }, { - "name": "union array slice, maximal range with negative step", - "selector": "$[9:0:-1]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [9, 8, 7, 6, 5, 4, 3, 2, 1] - }, { - "name": "union array slice, excessively large to value", - "selector": "$[2:113667776004]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [2, 3, 4, 5, 6, 7, 8, 9] - }, { - "name": "union array slice, excessively small from value", - "selector": "$[-113667776004:1]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [0] - }, { - "name": "union array slice, excessively large from value with negative step", - "selector": "$[113667776004:0:-1]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [9, 8, 7, 6, 5, 4, 3, 2, 1] - }, { - "name": "union array slice, excessively small to value with negative step", - "selector": "$[3:-113667776004:-1]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [3, 2, 1, 0] - }, { - "name": "union array slice, excessively large step", - "selector": "$[1:10:113667776004]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [1] - }, { - "name": "union array slice, excessively small step", - "selector": "$[-1:-10:-113667776004]", - "document": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - "result": [9] - }, { - "name": "union array slice, overflowing to value", - "selector": "$[2:231584178474632390847141970017375815706539969331281128078915168015826259279872]", - "invalid_selector": true - }, { - "name": "union array slice, underflowing from value", - "selector": "$[-231584178474632390847141970017375815706539969331281128078915168015826259279872:1]", - "invalid_selector": true - }, { - "name": "union array slice, overflowing from value with negative step", - "selector": "$[231584178474632390847141970017375815706539969331281128078915168015826259279872:0:-1]", - "invalid_selector": true - }, { - "name": "union array slice, underflowing to value with negative step", - "selector": "$[3:-231584178474632390847141970017375815706539969331281128078915168015826259279872:-1]", - "invalid_selector": true - }, { - "name": "union array slice, overflowing step", - "selector": "$[1:10:231584178474632390847141970017375815706539969331281128078915168015826259279872]", - "invalid_selector": true - }, { - "name": "union array slice, underflowing step", - "selector": "$[-1:-10:-231584178474632390847141970017375815706539969331281128078915168015826259279872]", - "invalid_selector": true - } -]} diff --git a/tests/cts.rs b/tests/cts.rs index 6b174a4..865aa1c 100644 --- a/tests/cts.rs +++ b/tests/cts.rs @@ -39,7 +39,8 @@ mod tests { #[test] fn compliance_test_suite() { - let cts_json = fs::read_to_string("tests/cts.json").expect("failed to read cts.json"); + let cts_json = fs::read_to_string("jsonpath-compliance-test-suite/cts.json") + .expect("failed to read cts.json"); let suite: TestSuite = serde_json::from_str(&cts_json).expect("failed to deserialize cts.json"); From 7f8fcbf5c2635a5a922c2601edd5babc487b15c8 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Tue, 5 Jan 2021 14:19:38 +0000 Subject: [PATCH 02/26] Bump slyce This allows rust 1.43 to be used. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 856f7e0..1dc052b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,4 @@ pest = "2.1.3" pest_derive = "2.1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.57" -slyce = "0.3.0" +slyce = "0.3.1" From 010790c74bf76e59e0dea1df344a7b80a34be34c Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Tue, 5 Jan 2021 14:35:55 +0000 Subject: [PATCH 03/26] Tolerate rust 1.43.0 This is to ease the maintainance of the reference implementation in the JSONPath comparison project. --- .github/workflows/quickstart.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quickstart.yml b/.github/workflows/quickstart.yml index f930f67..4122c19 100644 --- a/.github/workflows/quickstart.yml +++ b/.github/workflows/quickstart.yml @@ -12,6 +12,9 @@ jobs: check: name: Check runs-on: ubuntu-latest + strategy: + matrix: + toolchain: [ stable, "1.43.0" ] steps: - name: Checkout sources uses: actions/checkout@v2 @@ -22,7 +25,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + toolchain: ${{ matrix.toolchain }} override: true - name: Run cargo check @@ -33,6 +36,9 @@ jobs: test: name: Test Suite runs-on: ubuntu-latest + strategy: + matrix: + toolchain: [ stable, "1.43.0" ] steps: - name: Checkout sources uses: actions/checkout@v2 @@ -43,7 +49,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + toolchain: ${{ matrix.toolchain }} override: true - name: Run cargo test @@ -64,6 +70,7 @@ jobs: uses: actions-rs/toolchain@v1 with: profile: minimal + # lint using only the latest stable toolchain: stable override: true components: rustfmt, clippy From 200f656b2911c4222467cbf24ece279a812f6b3c Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Fri, 26 Mar 2021 05:19:11 +0000 Subject: [PATCH 04/26] Bump CTS --- jsonpath-compliance-test-suite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonpath-compliance-test-suite b/jsonpath-compliance-test-suite index ab56e44..2e62f6f 160000 --- a/jsonpath-compliance-test-suite +++ b/jsonpath-compliance-test-suite @@ -1 +1 @@ -Subproject commit ab56e44bf7ea9997f2f3a10bbc60ee317c151a61 +Subproject commit 2e62f6fb06cdb36dd982a9f39fa3810f385f1ce4 From 66c2af62fe70f93dbd9f6873f16ae6db6c607ab0 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Fri, 26 Mar 2021 14:51:16 +0000 Subject: [PATCH 05/26] Allow lints of pest grammar terminals Terminals such as EOI and WHITESPACE are objected to by clippy. --- .github/workflows/quickstart.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/quickstart.yml b/.github/workflows/quickstart.yml index 4122c19..450b025 100644 --- a/.github/workflows/quickstart.yml +++ b/.github/workflows/quickstart.yml @@ -85,4 +85,4 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy - args: -- -D warnings \ No newline at end of file + args: -- -D warnings -A clippy::upper-case-acronyms From 778aea12cef10896f1fc0434a3a25942cbb72026 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Mon, 28 Feb 2022 16:16:17 +0000 Subject: [PATCH 06/26] Bump Rust edition Drop support for Rust 1.43.0. This was required when the JSONPath comparison project pinned Rust to that version, but now that project uses the latest stable Rust. --- .github/workflows/quickstart.yml | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/quickstart.yml b/.github/workflows/quickstart.yml index 450b025..abc335c 100644 --- a/.github/workflows/quickstart.yml +++ b/.github/workflows/quickstart.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - toolchain: [ stable, "1.43.0" ] + toolchain: [ stable ] steps: - name: Checkout sources uses: actions/checkout@v2 @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - toolchain: [ stable, "1.43.0" ] + toolchain: [ stable ] steps: - name: Checkout sources uses: actions/checkout@v2 diff --git a/Cargo.toml b/Cargo.toml index 1dc052b..9c4be77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "jsonpath_reference_implementation" version = "0.0.1" authors = ["Glyn Normington "] -edition = "2018" +edition = "2021" [dependencies] itertools = "0.9.0" From 63f3db29ae8aef535115127bc1ef67aa6604b0de Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Tue, 1 Mar 2022 20:29:45 +0000 Subject: [PATCH 07/26] Delete extraneous comment This should have been deleted previously as it pertains to an example application rather than ours. --- .github/workflows/quickstart.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/quickstart.yml b/.github/workflows/quickstart.yml index abc335c..3e5945e 100644 --- a/.github/workflows/quickstart.yml +++ b/.github/workflows/quickstart.yml @@ -1,8 +1,4 @@ # Based on https://github.com/actions-rs/meta/blob/master/recipes/quickstart.md -# -# While our "example" application has the platform-specific code, -# for simplicity we are compiling and testing everything on the Ubuntu environment only. -# For multi-OS testing see the `cross.yml` workflow. on: [push, pull_request] From b16a17c2c7a4452cc18380c1711ddbf2c9044af9 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Sat, 16 Apr 2022 18:30:02 +0100 Subject: [PATCH 08/26] Handle leading and trailing whitespace correctly These should cause a parsing error. --- jsonpath-compliance-test-suite | 2 +- src/grammar.pest | 4 ++-- src/parser.rs | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/jsonpath-compliance-test-suite b/jsonpath-compliance-test-suite index 2e62f6f..fc5a04d 160000 --- a/jsonpath-compliance-test-suite +++ b/jsonpath-compliance-test-suite @@ -1 +1 @@ -Subproject commit 2e62f6fb06cdb36dd982a9f39fa3810f385f1ce4 +Subproject commit fc5a04d52b5c4607206f30a2faf2ba3295cabbab diff --git a/src/grammar.pest b/src/grammar.pest index 51f7638..c4b87a8 100644 --- a/src/grammar.pest +++ b/src/grammar.pest @@ -1,7 +1,7 @@ -selector = _{ SOI ~ rootSelector ~ matchers ~ EOI } +selector = ${ SOI ~ rootSelector ~ matchers ~ EOI } matchers = ${ matcher* } -rootSelector = { "$" } +rootSelector = @{ "$" } matcher = !{ dotChild | union } diff --git a/src/parser.rs b/src/parser.rs index 57d3302..c3d45a7 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -16,10 +16,13 @@ struct PathParser; pub fn parse(selector: &str) -> Result { let selector_rule = PathParser::parse(Rule::selector, selector) .map_err(|e| format!("{}", e))? - .nth(1) + .nth(0) .unwrap(); selector_rule + .into_inner() + .nth(1) // skip over Rule::selector + .unwrap() .into_inner() .fold(Ok(Path::Root), |prev, r| match r.as_rule() { Rule::matcher => Ok(Path::Sel( From 78157e2b3b3b403e33a288218ccf28c39fb24bda Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Sat, 16 Apr 2022 18:45:42 +0100 Subject: [PATCH 09/26] Use personal repo for CTS --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 4972b45..88f08b5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "jsonpath-compliance-test-suite"] path = jsonpath-compliance-test-suite - url = https://github.com/jsonpath-standard/jsonpath-compliance-test-suite.git + url = git@github.com:glyn/jsonpath-compliance-test-suite.git From 8cc97c15745b962f9716375ba4461441d5968fa8 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Sun, 17 Apr 2022 13:41:14 +0100 Subject: [PATCH 10/26] fix lint --- src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser.rs b/src/parser.rs index c3d45a7..097fe5e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -16,7 +16,7 @@ struct PathParser; pub fn parse(selector: &str) -> Result { let selector_rule = PathParser::parse(Rule::selector, selector) .map_err(|e| format!("{}", e))? - .nth(0) + .next() .unwrap(); selector_rule From ff9d79fc15dded214fa1a4ac4c64232ef8395d3b Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Wed, 20 Apr 2022 13:10:51 +0100 Subject: [PATCH 11/26] Correct comment --- src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser.rs b/src/parser.rs index 097fe5e..8032499 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -21,7 +21,7 @@ pub fn parse(selector: &str) -> Result { selector_rule .into_inner() - .nth(1) // skip over Rule::selector + .nth(1) // skip over Rule::rootSelector .unwrap() .into_inner() .fold(Ok(Path::Root), |prev, r| match r.as_rule() { From 26133492336e966711abfd5f74f78883cec75ac5 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Wed, 20 Apr 2022 13:19:43 +0100 Subject: [PATCH 12/26] Name find method consistently --- src/ast.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index c2fd948..6624884 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -77,7 +77,7 @@ impl Path { impl Selector { pub fn find<'a>(&'a self, input: &'a Value) -> Iter<'a> { match self { - Selector::Union(indices) => Box::new(indices.iter().flat_map(move |i| i.get(input))), + Selector::Union(indices) => Box::new(indices.iter().flat_map(move |i| i.find(input))), Selector::DotName(name) => Box::new(input.get(name).into_iter()), Selector::DotWildcard => match input { Value::Object(m) => Box::new(m.values()), @@ -89,7 +89,7 @@ impl Selector { } impl UnionElement { - pub fn get<'a>(&self, v: &'a Value) -> Iter<'a> { + pub fn find<'a>(&self, v: &'a Value) -> Iter<'a> { match self { UnionElement::Name(name) => Box::new(v.get(name).into_iter()), UnionElement::Slice(slice) => { From f2d7305ad03bb2e56433c6ac1709c62d1c7a3d4b Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Mon, 30 May 2022 11:00:07 +0100 Subject: [PATCH 13/26] Allow lower case hex in unicode escapes --- jsonpath-compliance-test-suite | 2 +- src/grammar.pest | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jsonpath-compliance-test-suite b/jsonpath-compliance-test-suite index fc5a04d..9235770 160000 --- a/jsonpath-compliance-test-suite +++ b/jsonpath-compliance-test-suite @@ -1 +1 @@ -Subproject commit fc5a04d52b5c4607206f30a2faf2ba3295cabbab +Subproject commit 923577060d75a8111fb3a91bdc0ab8eb2d748f1b diff --git a/src/grammar.pest b/src/grammar.pest index c4b87a8..40caaf2 100644 --- a/src/grammar.pest +++ b/src/grammar.pest @@ -32,16 +32,16 @@ doubleInner = @{ doubleChar* } doubleChar = { !("\"" | "\\" | '\u{00}'..'\u{1F}') ~ ANY | "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") - | "\\" ~ ("u" ~ upperHexDigit{4}) + | "\\" ~ ("u" ~ hexDigit{4}) } -upperHexDigit = _{ ASCII_DIGIT | "A" | "B" | "C" | "D" | "E" | "F" } +hexDigit = _{ ASCII_DIGIT | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f" } singleQuotedString = _{ "'" ~ singleInner ~ "'" } singleInner = @{ singleChar* } singleChar = { !("'" | "\\" | '\u{00}'..'\u{1F}') ~ ANY | "\\" ~ ("'" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") - | "\\" ~ ("u" ~ upperHexDigit{4}) + | "\\" ~ ("u" ~ hexDigit{4}) } WHITESPACE = _{ " " } \ No newline at end of file From 03a6203550bdd6f23f572376198c994e4880590b Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Mon, 1 Aug 2022 11:50:45 +0100 Subject: [PATCH 14/26] Rename Iter to NodeList --- src/ast.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 6624884..14679e7 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -63,10 +63,11 @@ pub enum UnionElement { Index(i64), } -type Iter<'a> = Box + 'a>; +// NodeList is an iterator over references to Values named after the Nodelist term in the spec. +type NodeList<'a> = Box + 'a>; impl Path { - pub fn find<'a>(&'a self, input: &'a Value) -> Iter<'a> { + pub fn find<'a>(&'a self, input: &'a Value) -> NodeList<'a> { match self { Path::Root => Box::new(std::iter::once(input)), Path::Sel(left, sel) => Box::new(left.find(input).flat_map(move |v| sel.find(v))), @@ -75,7 +76,7 @@ impl Path { } impl Selector { - pub fn find<'a>(&'a self, input: &'a Value) -> Iter<'a> { + pub fn find<'a>(&'a self, input: &'a Value) -> NodeList<'a> { match self { Selector::Union(indices) => Box::new(indices.iter().flat_map(move |i| i.find(input))), Selector::DotName(name) => Box::new(input.get(name).into_iter()), @@ -89,7 +90,7 @@ impl Selector { } impl UnionElement { - pub fn find<'a>(&self, v: &'a Value) -> Iter<'a> { + pub fn find<'a>(&self, v: &'a Value) -> NodeList<'a> { match self { UnionElement::Name(name) => Box::new(v.get(name).into_iter()), UnionElement::Slice(slice) => { From e210fad45cab39602e290263ac081f18049cefe3 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Thu, 7 Jul 2022 11:59:47 +0100 Subject: [PATCH 15/26] Bump CTS to obtain descendant selector tests --- jsonpath-compliance-test-suite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonpath-compliance-test-suite b/jsonpath-compliance-test-suite index 9235770..f4ac3fe 160000 --- a/jsonpath-compliance-test-suite +++ b/jsonpath-compliance-test-suite @@ -1 +1 @@ -Subproject commit 923577060d75a8111fb3a91bdc0ab8eb2d748f1b +Subproject commit f4ac3fe9e93c38f31f4b788dd1ecd09332a4c5b9 From a1fe7f8b380293de72b9303529264159b9262f52 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Thu, 7 Jul 2022 13:22:24 +0100 Subject: [PATCH 16/26] Descendant selectors --- src/ast.rs | 17 +++++++++++++++++ src/grammar.pest | 6 +++++- src/parser.rs | 14 ++++++++++++++ tests/cts.rs | 7 +++++-- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 14679e7..9c6bda0 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -54,6 +54,9 @@ pub enum Selector { Union(Vec), DotName(String), DotWildcard, + DescendantDotName(String), + DescendantDotWildcard, + DescendantUnionElement(UnionElement), } #[derive(Debug)] @@ -85,6 +88,20 @@ impl Selector { Value::Array(a) => Box::new(a.iter()), _ => Box::new(std::iter::empty()), }, + Selector::DescendantDotName(name) => Self::traverse(input, move |n: &'a Value| Box::new(n.get(name).into_iter())), + Selector::DescendantDotWildcard => Self::traverse(input, move |n: &'a Value| Box::new(iter::once(n))), + Selector::DescendantUnionElement(element) => Self::traverse(input, move |n: &'a Value| element.find(n)), + } + } + + // traverse applies the given closure to all the descendants of the input value and + // returns a nodelist. + fn traverse<'a, F>(input: &'a Value, f: F) -> NodeList<'a> + where F: Fn(&'a Value) -> NodeList<'a> + Copy + 'a { + match input { + Value::Object(m) => Box::new(m.into_iter().flat_map(move |(_k, v)| (&f)(v).chain(Self::traverse::<'a>(v, f)))), + Value::Array(a) => Box::new(a.iter().flat_map(move |v| (&f)(v).chain(Self::traverse::<'a>(v, f)))), + _ => Box::new(std::iter::empty()), } } } diff --git a/src/grammar.pest b/src/grammar.pest index 40caaf2..2936962 100644 --- a/src/grammar.pest +++ b/src/grammar.pest @@ -3,7 +3,7 @@ selector = ${ SOI ~ rootSelector ~ matchers ~ EOI } matchers = ${ matcher* } rootSelector = @{ "$" } -matcher = !{ dotChild | union } +matcher = !{ dotChild | union | descendant } dotChild = _{ wildcardedDotChild | namedDotChild } wildcardedDotChild = { ".*" } @@ -27,6 +27,10 @@ sliceStart = @{ integer } sliceEnd = @{ integer } sliceStep = @{ integer } +descendant = ${ ".." ~ descendantVariant } +descendantVariant = _{ childName | wildcard | "[" ~ unionElement ~ "]" } +wildcard = { "*" } + doubleQuotedString = _{ "\"" ~ doubleInner ~ "\"" } doubleInner = @{ doubleChar* } doubleChar = { diff --git a/src/parser.rs b/src/parser.rs index 8032499..2c282d0 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -40,6 +40,7 @@ fn parse_selector(matcher_rule: pest::iterators::Pair) -> Result Selector::DotWildcard, Rule::namedDotChild => Selector::DotName(parse_child_name(r)), Rule::union => Selector::Union(parse_union_indices(r)?), + Rule::descendant => parse_descendant(r)?, _ => panic!("invalid parse tree {:?}", r), }) } @@ -115,6 +116,19 @@ fn parse_union_array_slice( })) } +fn parse_descendant(matcher_rule: pest::iterators::Pair) -> Result { + let r = matcher_rule.into_inner().next().unwrap(); + + Ok(match r.as_rule() { + Rule::childName => Selector::DescendantDotName(r.as_str().to_owned()), + Rule::wildcard => Selector::DescendantDotWildcard, + Rule::unionChild => Selector::DescendantUnionElement(parse_union_child(r)), + Rule::unionArraySlice => Selector::DescendantUnionElement(parse_union_array_slice(r)?), + Rule::unionArrayIndex => Selector::DescendantUnionElement(parse_union_array_index(r)?), + _ => panic!("invalid descendant {:?}", r), + }) +} + fn unescape(contents: &str) -> String { let s = format!(r#""{}""#, contents); serde_json::from_str(&s).unwrap() diff --git a/tests/cts.rs b/tests/cts.rs index 865aa1c..20ad5f3 100644 --- a/tests/cts.rs +++ b/tests/cts.rs @@ -90,10 +90,13 @@ mod tests { assert!(false, "find failed") // should not happen } } else { - if !t.invalid_selector { + if t.invalid_selector { + // print failure message + println!("{}: parsing `{}` failed with: {}", t.name, t.selector, path.err().expect("should be an error")); + } else { assert!( path.is_ok(), - "{}: parsing {} should have succeeded but failed: {}", + "{}: parsing `{}` should have succeeded but failed: {}", t.name, t.selector, path.err().expect("should be an error") From ac3346c69a9fd00f75bf2931b87f690bcc585109 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Wed, 3 Aug 2022 17:58:42 +0100 Subject: [PATCH 17/26] cargo fmt --- src/ast.rs | 26 ++++++++++++++++++++------ src/parser.rs | 2 +- tests/cts.rs | 7 ++++++- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 9c6bda0..440c169 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -88,19 +88,33 @@ impl Selector { Value::Array(a) => Box::new(a.iter()), _ => Box::new(std::iter::empty()), }, - Selector::DescendantDotName(name) => Self::traverse(input, move |n: &'a Value| Box::new(n.get(name).into_iter())), - Selector::DescendantDotWildcard => Self::traverse(input, move |n: &'a Value| Box::new(iter::once(n))), - Selector::DescendantUnionElement(element) => Self::traverse(input, move |n: &'a Value| element.find(n)), + Selector::DescendantDotName(name) => { + Self::traverse(input, move |n: &'a Value| Box::new(n.get(name).into_iter())) + } + Selector::DescendantDotWildcard => { + Self::traverse(input, move |n: &'a Value| Box::new(iter::once(n))) + } + Selector::DescendantUnionElement(element) => { + Self::traverse(input, move |n: &'a Value| element.find(n)) + } } } // traverse applies the given closure to all the descendants of the input value and // returns a nodelist. fn traverse<'a, F>(input: &'a Value, f: F) -> NodeList<'a> - where F: Fn(&'a Value) -> NodeList<'a> + Copy + 'a { + where + F: Fn(&'a Value) -> NodeList<'a> + Copy + 'a, + { match input { - Value::Object(m) => Box::new(m.into_iter().flat_map(move |(_k, v)| (&f)(v).chain(Self::traverse::<'a>(v, f)))), - Value::Array(a) => Box::new(a.iter().flat_map(move |v| (&f)(v).chain(Self::traverse::<'a>(v, f)))), + Value::Object(m) => Box::new( + m.into_iter() + .flat_map(move |(_k, v)| (&f)(v).chain(Self::traverse::<'a>(v, f))), + ), + Value::Array(a) => Box::new( + a.iter() + .flat_map(move |v| (&f)(v).chain(Self::traverse::<'a>(v, f))), + ), _ => Box::new(std::iter::empty()), } } diff --git a/src/parser.rs b/src/parser.rs index 2c282d0..649e449 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -40,7 +40,7 @@ fn parse_selector(matcher_rule: pest::iterators::Pair) -> Result Selector::DotWildcard, Rule::namedDotChild => Selector::DotName(parse_child_name(r)), Rule::union => Selector::Union(parse_union_indices(r)?), - Rule::descendant => parse_descendant(r)?, + Rule::descendant => parse_descendant(r)?, _ => panic!("invalid parse tree {:?}", r), }) } diff --git a/tests/cts.rs b/tests/cts.rs index 20ad5f3..5e235ee 100644 --- a/tests/cts.rs +++ b/tests/cts.rs @@ -92,7 +92,12 @@ mod tests { } else { if t.invalid_selector { // print failure message - println!("{}: parsing `{}` failed with: {}", t.name, t.selector, path.err().expect("should be an error")); + println!( + "{}: parsing `{}` failed with: {}", + t.name, + t.selector, + path.err().expect("should be an error") + ); } else { assert!( path.is_ok(), From 296e5ad0c48de038b9971c4d4c65b8f73150f682 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Wed, 3 Aug 2022 17:59:42 +0100 Subject: [PATCH 18/26] Fix lints --- src/ast.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 440c169..c897009 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -109,11 +109,11 @@ impl Selector { match input { Value::Object(m) => Box::new( m.into_iter() - .flat_map(move |(_k, v)| (&f)(v).chain(Self::traverse::<'a>(v, f))), + .flat_map(move |(_k, v)| f(v).chain(Self::traverse::<'a>(v, f))), ), Value::Array(a) => Box::new( a.iter() - .flat_map(move |v| (&f)(v).chain(Self::traverse::<'a>(v, f))), + .flat_map(move |v| f(v).chain(Self::traverse::<'a>(v, f))), ), _ => Box::new(std::iter::empty()), } From 156e2e6751bddcfc1df13f9b871edf05ac32ae97 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Fri, 5 Aug 2022 17:25:44 +0100 Subject: [PATCH 19/26] Add more tests --- jsonpath-compliance-test-suite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonpath-compliance-test-suite b/jsonpath-compliance-test-suite index f4ac3fe..d28bc55 160000 --- a/jsonpath-compliance-test-suite +++ b/jsonpath-compliance-test-suite @@ -1 +1 @@ -Subproject commit f4ac3fe9e93c38f31f4b788dd1ecd09332a4c5b9 +Subproject commit d28bc55954590c8742a0999ad3abaf264113da5e From 81e15310f2dc1ed444102ee022cd1e340b87e84f Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Fri, 5 Aug 2022 17:28:10 +0100 Subject: [PATCH 20/26] Support descendant with wildcarded index --- src/grammar.pest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grammar.pest b/src/grammar.pest index 2936962..0c4d483 100644 --- a/src/grammar.pest +++ b/src/grammar.pest @@ -28,7 +28,7 @@ sliceEnd = @{ integer } sliceStep = @{ integer } descendant = ${ ".." ~ descendantVariant } -descendantVariant = _{ childName | wildcard | "[" ~ unionElement ~ "]" } +descendantVariant = _{ childName | wildcard | "[" ~ wildcard ~ "]" | "[" ~ unionElement ~ "]" } wildcard = { "*" } doubleQuotedString = _{ "\"" ~ doubleInner ~ "\"" } From f8d566325cf5b902d496d9687527e6c2213884b5 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Fri, 5 Aug 2022 18:00:19 +0100 Subject: [PATCH 21/26] More descendant selectors * Index wildcard * List --- src/ast.rs | 6 +++--- src/grammar.pest | 8 +++++--- src/parser.rs | 6 ++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index c897009..779fcd2 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -56,7 +56,7 @@ pub enum Selector { DotWildcard, DescendantDotName(String), DescendantDotWildcard, - DescendantUnionElement(UnionElement), + DescendantUnion(Vec), } #[derive(Debug)] @@ -94,8 +94,8 @@ impl Selector { Selector::DescendantDotWildcard => { Self::traverse(input, move |n: &'a Value| Box::new(iter::once(n))) } - Selector::DescendantUnionElement(element) => { - Self::traverse(input, move |n: &'a Value| element.find(n)) + Selector::DescendantUnion(indices) => { + Self::traverse(input, move |n: &'a Value| Box::new(indices.iter().flat_map(move |i| i.find(n)))) } } } diff --git a/src/grammar.pest b/src/grammar.pest index 0c4d483..64fc5f9 100644 --- a/src/grammar.pest +++ b/src/grammar.pest @@ -3,7 +3,7 @@ selector = ${ SOI ~ rootSelector ~ matchers ~ EOI } matchers = ${ matcher* } rootSelector = @{ "$" } -matcher = !{ dotChild | union | descendant } +matcher = !{ dotChild | union | wildcardedIndex | descendant } dotChild = _{ wildcardedDotChild | namedDotChild } wildcardedDotChild = { ".*" } @@ -17,7 +17,7 @@ char = { | '\u{80}'..'\u{10FFFF}' } -union = { "[" ~ unionElement ~ ("," ~ unionElement)* ~ "]" } +union = !{ "[" ~ unionElement ~ ("," ~ unionElement)* ~ "]" } unionElement = _{ unionChild | unionArraySlice | unionArrayIndex } unionChild = ${ doubleQuotedString | singleQuotedString } unionArrayIndex = @{ integer } @@ -27,8 +27,10 @@ sliceStart = @{ integer } sliceEnd = @{ integer } sliceStep = @{ integer } +wildcardedIndex = { "[" ~ "*" ~ "]" } + descendant = ${ ".." ~ descendantVariant } -descendantVariant = _{ childName | wildcard | "[" ~ wildcard ~ "]" | "[" ~ unionElement ~ "]" } +descendantVariant = _{ childName | wildcard | "[" ~ wildcard ~ "]" | union } wildcard = { "*" } doubleQuotedString = _{ "\"" ~ doubleInner ~ "\"" } diff --git a/src/parser.rs b/src/parser.rs index 649e449..3fb6855 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -40,6 +40,7 @@ fn parse_selector(matcher_rule: pest::iterators::Pair) -> Result Selector::DotWildcard, Rule::namedDotChild => Selector::DotName(parse_child_name(r)), Rule::union => Selector::Union(parse_union_indices(r)?), + Rule::wildcardedIndex => Selector::DotWildcard, Rule::descendant => parse_descendant(r)?, _ => panic!("invalid parse tree {:?}", r), }) @@ -122,10 +123,7 @@ fn parse_descendant(matcher_rule: pest::iterators::Pair) -> Result Selector::DescendantDotName(r.as_str().to_owned()), Rule::wildcard => Selector::DescendantDotWildcard, - Rule::unionChild => Selector::DescendantUnionElement(parse_union_child(r)), - Rule::unionArraySlice => Selector::DescendantUnionElement(parse_union_array_slice(r)?), - Rule::unionArrayIndex => Selector::DescendantUnionElement(parse_union_array_index(r)?), - _ => panic!("invalid descendant {:?}", r), + _ => Selector::DescendantUnion(parse_union_indices(r)?), }) } From 40d8d826d1bddf67173f3b15925fcbc477b516c7 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Fri, 5 Aug 2022 18:03:23 +0100 Subject: [PATCH 22/26] cargo fmt --- src/ast.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 779fcd2..785c6c2 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -94,9 +94,9 @@ impl Selector { Selector::DescendantDotWildcard => { Self::traverse(input, move |n: &'a Value| Box::new(iter::once(n))) } - Selector::DescendantUnion(indices) => { - Self::traverse(input, move |n: &'a Value| Box::new(indices.iter().flat_map(move |i| i.find(n)))) - } + Selector::DescendantUnion(indices) => Self::traverse(input, move |n: &'a Value| { + Box::new(indices.iter().flat_map(move |i| i.find(n))) + }), } } From 22d0c0387a9f98d91d556cccff5a5e560486af53 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Fri, 12 Aug 2022 16:23:34 +0100 Subject: [PATCH 23/26] Bump CTS --- jsonpath-compliance-test-suite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonpath-compliance-test-suite b/jsonpath-compliance-test-suite index d28bc55..b139469 160000 --- a/jsonpath-compliance-test-suite +++ b/jsonpath-compliance-test-suite @@ -1 +1 @@ -Subproject commit d28bc55954590c8742a0999ad3abaf264113da5e +Subproject commit b139469a6bdd83f19ad9e544c4c14db09162f580 From baa8036d2b46b508ce58919e4d29b1387a14c6d4 Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Fri, 12 Aug 2022 16:33:54 +0100 Subject: [PATCH 24/26] Bump CTS --- jsonpath-compliance-test-suite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonpath-compliance-test-suite b/jsonpath-compliance-test-suite index b139469..cc38f23 160000 --- a/jsonpath-compliance-test-suite +++ b/jsonpath-compliance-test-suite @@ -1 +1 @@ -Subproject commit b139469a6bdd83f19ad9e544c4c14db09162f580 +Subproject commit cc38f238767a9bf38e92ced85049915b57ad7fb0 From f809bff96078e1faed8f3f3af91f3e06ef82459d Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Fri, 12 Aug 2022 16:40:01 +0100 Subject: [PATCH 25/26] Bump to include merge commit --- jsonpath-compliance-test-suite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonpath-compliance-test-suite b/jsonpath-compliance-test-suite index cc38f23..267acbf 160000 --- a/jsonpath-compliance-test-suite +++ b/jsonpath-compliance-test-suite @@ -1 +1 @@ -Subproject commit cc38f238767a9bf38e92ced85049915b57ad7fb0 +Subproject commit 267acbf1b0987d164e9b691c589c83d27498db97 From 0ca960b004887d60e8c53e4c54d858213343e05e Mon Sep 17 00:00:00 2001 From: Glyn Normington Date: Thu, 22 Feb 2024 09:32:04 +0000 Subject: [PATCH 26/26] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 95856f4..9dfbe45 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # JSON Path Reference Implementation -**WORK IN PROGRESS** +**STALLED** - See this [blog post](https://underlap.org/jsonpath-from-blog-post-to-rfc-in-17-years) for details. If you want to take this implementation forward, please feel free to fork it or contact @glyn. This Reference Implementation follows, and usually lags behind, the [internet draft](https://jsonpath-standard.github.io/internet-draft/). @@ -8,4 +8,4 @@ See [grammar.pest](src/grammar.pest) for the Parsing Expression Grammar of the R See the [Developer Guide](./DEVELOPING.md) if you want to run the code against the test suite. See the [Contributor Guide](./CONTRIBUTING.md) if you'd like to submit changes. -The Compliance Test Suite is in its own [repository](https://github.com/jsonpath-standard/jsonpath-compliance-test-suite). \ No newline at end of file +The Compliance Test Suite is in its own [repository](https://github.com/jsonpath-standard/jsonpath-compliance-test-suite).