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

Array slices #22

Merged
merged 8 commits into from
Nov 4, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Test unrepresentable array indices and slice parameters
2^257=231584178474632390847141970017375815706539969331281128078915168015826259279872

will overflow signed 256 bit integers. This can be increased if implementations
surface which can cope with such values.
  • Loading branch information
glyn committed Oct 28, 2020
commit bfe83b79a5920488b79a722d43db1010f14c45e1
1 change: 1 addition & 0 deletions src/jsonpath.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub fn parse(selector: &str) -> Result<Path, SyntaxError> {
Ok(Path(p))
}

#[derive(Debug)]
pub struct Path(ast::Path);

impl Path {
Expand Down
50 changes: 30 additions & 20 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
pub use crate::ast::*;
use crate::pest::Parser;
use slyce::Slice;
use std::num::ParseIntError;

#[derive(Parser)]
#[grammar = "grammar.pest"]
Expand All @@ -18,23 +19,26 @@ pub fn parse(selector: &str) -> Result<Path, String> {
.nth(1)
.unwrap();

Ok(selector_rule
selector_rule
.into_inner()
.fold(Path::Root, |prev, r| match r.as_rule() {
Rule::matcher => Path::Sel(Box::new(prev), parse_selector(r)),
.fold(Ok(Path::Root), |prev, r| match r.as_rule() {
Rule::matcher => Ok(Path::Sel(
Box::new(prev?),
parse_selector(r).map_err(|e| format!("{}", e))?,
)),
_ => panic!("invalid parse tree {:?}", r),
}))
})
}

fn parse_selector(matcher_rule: pest::iterators::Pair<Rule>) -> Selector {
fn parse_selector(matcher_rule: pest::iterators::Pair<Rule>) -> Result<Selector, ParseIntError> {
let r = matcher_rule.into_inner().next().unwrap();

match r.as_rule() {
Ok(match r.as_rule() {
Rule::wildcardedDotChild => Selector::DotWildcard,
Rule::namedDotChild => Selector::DotName(parse_child_name(r)),
Rule::union => Selector::Union(parse_union_indices(r)),
Rule::union => Selector::Union(parse_union_indices(r)?),
_ => panic!("invalid parse tree {:?}", r),
}
})
}

fn parse_child_name(matcher_rule: pest::iterators::Pair<Rule>) -> String {
Expand All @@ -46,16 +50,18 @@ fn parse_child_name(matcher_rule: pest::iterators::Pair<Rule>) -> String {
}
}

fn parse_union_indices(matcher_rule: pest::iterators::Pair<Rule>) -> Vec<UnionElement> {
fn parse_union_indices(
matcher_rule: pest::iterators::Pair<Rule>,
) -> Result<Vec<UnionElement>, ParseIntError> {
matcher_rule
.into_inner()
.map(|r| match r.as_rule() {
Rule::unionChild => parse_union_child(r),
Rule::unionChild => Ok(parse_union_child(r)),
Rule::unionArraySlice => parse_union_array_slice(r),
Rule::unionArrayIndex => parse_union_array_index(r),
_ => panic!("invalid parse tree {:?}", r),
})
.collect()
.collect::<Result<Vec<UnionElement>, ParseIntError>>()
}

fn parse_union_child(matcher_rule: pest::iterators::Pair<Rule>) -> UnionElement {
Expand All @@ -68,38 +74,42 @@ fn parse_union_child(matcher_rule: pest::iterators::Pair<Rule>) -> UnionElement
})
}

fn parse_union_array_index(matcher_rule: pest::iterators::Pair<Rule>) -> UnionElement {
let i = matcher_rule.as_str().parse().unwrap();
UnionElement::Index(i)
fn parse_union_array_index(
matcher_rule: pest::iterators::Pair<Rule>,
) -> Result<UnionElement, ParseIntError> {
let i = matcher_rule.as_str().parse()?;
Ok(UnionElement::Index(i))
}

fn parse_union_array_slice(matcher_rule: pest::iterators::Pair<Rule>) -> UnionElement {
fn parse_union_array_slice(
matcher_rule: pest::iterators::Pair<Rule>,
) -> Result<UnionElement, ParseIntError> {
let mut start: Option<isize> = None;
let mut end: Option<isize> = None;
let mut step: Option<isize> = None;
for r in matcher_rule.into_inner() {
match r.as_rule() {
Rule::sliceStart => {
start = Some(r.as_str().parse().unwrap());
start = Some(r.as_str().parse()?);
}

Rule::sliceEnd => {
end = Some(r.as_str().parse().unwrap());
end = Some(r.as_str().parse()?);
}

Rule::sliceStep => {
step = Some(r.as_str().parse().unwrap());
step = Some(r.as_str().parse()?);
}

_ => panic!("invalid parse tree {:?}", r),
}
}

UnionElement::Slice(Slice {
Ok(UnionElement::Slice(Slice {
start: start.into(),
end: end.into(),
step,
})
}))
}

fn unescape(contents: &str) -> String {
Expand Down
30 changes: 29 additions & 1 deletion tests/cts.json
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,10 @@
"selector": "$[2]",
"document": ["first", "second"],
"result": []
}, {
"name": "union array access, overflowing index",
"selector": "$[231584178474632390847141970017375815706539969331281128078915168015826259279872]",
"invalid_selector": true
}, {
"name": "union array access, negative",
"selector": "$[-1]",
Expand Down Expand Up @@ -716,5 +720,29 @@
"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
}
]}
4 changes: 2 additions & 2 deletions tests/cts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ mod tests {
let result = panic::catch_unwind(|| {
if t.invalid_selector {
println!(
"testcase name = `{}`, selector = `{}`, expected invalid selector.",
"testcase name = `{}`, selector = `{}`, expecting invalid selector.",
t.name, t.selector
);
} else {
println!(
"testcase name = `{}`, selector = `{}`, document:\n{:#}\nexpected result = `{}`.",
"testcase name = `{}`, selector = `{}`, document:\n{:#}\nexpecting result = `{}`.",
t.name, t.selector, t.document, t.result
);
}
Expand Down