Skip to content
This repository was archived by the owner on Feb 22, 2024. It is now read-only.

Commit 8f5bc59

Browse files
author
Marko Mikulicic
committed
Implement array access
1 parent 1397caf commit 8f5bc59

File tree

4 files changed

+62
-6
lines changed

4 files changed

+62
-6
lines changed

src/grammar.pest

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ char = {
1818
}
1919

2020
union = { "[" ~ unionElement ~ ("," ~ unionElement)* ~ "]" }
21-
unionElement = _{ unionChild }
21+
unionElement = _{ unionChild | unionArrayIndex }
2222
unionChild = { doubleQuotedString | singleQuotedString }
23+
unionArrayIndex = { "-" ? ~ ASCII_DIGIT+ }
2324

2425
doubleQuotedString = _{ "\"" ~ doubleInner ~ "\"" }
2526
doubleInner = @{ doubleChar* }

src/matchers.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ impl Matcher for ArrayIndex {
8282
self.index as usize
8383
} else {
8484
let abs = (-self.index) as usize;
85-
if abs < len {
85+
if abs <= len {
8686
len - abs
8787
} else {
8888
return Box::new(iter::empty());
@@ -163,6 +163,14 @@ mod tests {
163163
assert_eq!(format!("{:?}", r), "[Number(2)]");
164164
}
165165

166+
#[test]
167+
fn array_index_negative_extreme() {
168+
let s = ArrayIndex::new(-2);
169+
let j = json!([1, 2]);
170+
let r: Vec<&Value> = s.select(&j).collect();
171+
assert_eq!(format!("{:?}", r), "[Number(1)]");
172+
}
173+
166174
#[test]
167175
fn array_index_negative_oob() {
168176
let s = ArrayIndex::new(-10);

src/parser.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,18 @@ fn parse_dot_child_matcher(
7575
fn parse_union(matcher_rule: pest::iterators::Pair<Rule>) -> Vec<Box<dyn matchers::Matcher>> {
7676
let mut ms: Vec<Box<dyn matchers::Matcher>> = Vec::new();
7777
for r in matcher_rule.into_inner() {
78-
if let Rule::unionChild = r.as_rule() {
79-
for m in parse_union_child(r) {
80-
ms.push(m)
78+
match r.as_rule() {
79+
Rule::unionChild => {
80+
for m in parse_union_child(r) {
81+
ms.push(m)
82+
}
83+
}
84+
Rule::unionArrayIndex => {
85+
for m in parse_union_array_index(r) {
86+
ms.push(m)
87+
}
8188
}
89+
_ => {}
8290
}
8391
}
8492
vec![Box::new(matchers::Union::new(ms))]
@@ -102,6 +110,15 @@ fn parse_union_child(matcher_rule: pest::iterators::Pair<Rule>) -> Vec<Box<dyn m
102110
ms
103111
}
104112

113+
fn parse_union_array_index(
114+
matcher_rule: pest::iterators::Pair<Rule>,
115+
) -> Vec<Box<dyn matchers::Matcher>> {
116+
let mut ms: Vec<Box<dyn matchers::Matcher>> = Vec::new();
117+
let i = matcher_rule.as_str().parse().unwrap();
118+
ms.push(Box::new(matchers::ArrayIndex::new(i)));
119+
ms
120+
}
121+
105122
const ESCAPED: &str = "\"'\\/bfnrt";
106123
const UNESCAPED: &str = "\"'\\/\u{0008}\u{000C}\u{000A}\u{000D}\u{0009}";
107124

tests/cts.json

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,5 +461,35 @@
461461
"name": "union child, single quotes, incomplete escape",
462462
"selector": "$['\\']",
463463
"invalid_selector": true
464+
}, {
465+
"name": "union array access",
466+
"selector": "$[0]",
467+
"document": ["first", "second"],
468+
"result": ["first"]
469+
}, {
470+
"name": "union array access, 1",
471+
"selector": "$[1]",
472+
"document": ["first", "second"],
473+
"result": ["second"]
474+
}, {
475+
"name": "union array access, out of bound",
476+
"selector": "$[2]",
477+
"document": ["first", "second"],
478+
"result": []
479+
}, {
480+
"name": "union array access, negative",
481+
"selector": "$[-1]",
482+
"document": ["first", "second"],
483+
"result": ["second"]
484+
}, {
485+
"name": "union array access, more negative",
486+
"selector": "$[-2]",
487+
"document": ["first", "second"],
488+
"result": ["first"]
489+
}, {
490+
"name": "union array access, negative out of bound",
491+
"selector": "$[-3]",
492+
"document": ["first", "second"],
493+
"result": []
464494
}
465-
]}
495+
]}

0 commit comments

Comments
 (0)