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

Commit bff8b3c

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

File tree

4 files changed

+79
-15
lines changed

4 files changed

+79
-15
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 } // TODO: add unionArraySlice
2222
unionChild = { doubleQuotedString | singleQuotedString }
23+
unionArrayIndex = { "-" ? ~ ( "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* ) }
2324

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

src/matchers.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,15 @@ impl ArrayIndex {
7373

7474
impl Matcher for ArrayIndex {
7575
fn select<'a>(&self, node: &'a Value) -> Iter<'a> {
76-
let len = if let Value::Array(a) = node {
77-
a.len()
78-
} else {
79-
0
80-
};
8176
let idx = if self.index >= 0 {
8277
self.index as usize
8378
} else {
84-
let abs = (-self.index) as usize;
85-
if abs < len {
86-
len - abs
79+
let len = if let Value::Array(a) = node {
80+
a.len() as i64
8781
} else {
88-
return Box::new(iter::empty());
89-
}
82+
0
83+
};
84+
(len + self.index) as usize
9085
};
9186
Box::new(node.get(idx).into_iter())
9287
}
@@ -163,6 +158,14 @@ mod tests {
163158
assert_eq!(format!("{:?}", r), "[Number(2)]");
164159
}
165160

161+
#[test]
162+
fn array_index_negative_extreme() {
163+
let s = ArrayIndex::new(-2);
164+
let j = json!([1, 2]);
165+
let r: Vec<&Value> = s.select(&j).collect();
166+
assert_eq!(format!("{:?}", r), "[Number(1)]");
167+
}
168+
166169
#[test]
167170
fn array_index_negative_oob() {
168171
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: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,5 +461,48 @@
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": []
494+
}, {
495+
"name": "union array access, on object",
496+
"selector": "$[0]",
497+
"document": {"foo": 1},
498+
"result": []
499+
}, {
500+
"name": "union array access, leading 0",
501+
"selector": "$[01]",
502+
"invalid_selector": true
503+
}, {
504+
"name": "union array access, leading -0",
505+
"selector": "$[-01]",
506+
"invalid_selector": true
464507
}
465-
]}
508+
]}

0 commit comments

Comments
 (0)