use super::{ParseError, ParseErrorKind};
use crate::jsonpath::ast::selector::{
ArraySliceSelector, FilterSelector, IndexSelector, NameSelector, Selector, WildcardSelector,
};
use crate::jsonpath::parser::expr::logical_or_expr;
use crate::jsonpath::parser::literal::number::try_integer;
use crate::jsonpath::parser::literal::string::try_parse as try_string_literal;
use crate::jsonpath::parser::primitives::{match_str, skip_whitespace};
use hurl_core::reader::Reader;
use super::ParseResult;
pub fn parse(reader: &mut Reader) -> ParseResult<Vec<Selector>> {
let mut selectors = vec![];
loop {
let selector = selector(reader)?;
selectors.push(selector);
skip_whitespace(reader);
if !match_str(",", reader) {
break;
}
skip_whitespace(reader);
}
Ok(selectors)
}
pub fn selector(reader: &mut Reader) -> ParseResult<Selector> {
let initial_state = reader.cursor();
if let Some(name_selector) = try_name_selector(reader)? {
return Ok(Selector::Name(name_selector));
} else if let Some(wildcard_selector) = try_wildcard_selector(reader) {
return Ok(Selector::Wildcard(wildcard_selector));
} else if let Some(array_slice_selector) = try_array_slice_selector(reader)? {
return Ok(Selector::ArraySlice(array_slice_selector));
} else if let Some(index_selector) = try_index_selector(reader)? {
return Ok(Selector::Index(index_selector));
} else if let Some(filter_selector) = try_filter_selector(reader)? {
return Ok(Selector::Filter(filter_selector));
}
Err(ParseError::new(
initial_state.pos,
ParseErrorKind::Expecting("a selector".to_string()),
))
}
pub fn try_name_selector(reader: &mut Reader) -> ParseResult<Option<NameSelector>> {
let value = try_string_literal(reader)?;
Ok(value.map(NameSelector::new))
}
fn try_wildcard_selector(reader: &mut Reader) -> Option<WildcardSelector> {
if match_str("*", reader) {
Some(WildcardSelector)
} else {
None
}
}
fn try_index_selector(reader: &mut Reader) -> ParseResult<Option<IndexSelector>> {
let value = try_integer(reader)?;
Ok(value.map(IndexSelector::new))
}
fn try_array_slice_selector(reader: &mut Reader) -> ParseResult<Option<ArraySliceSelector>> {
let save = reader.cursor();
let start = if let Some(value) = try_integer(reader)? {
skip_whitespace(reader);
Some(value)
} else {
None
};
if !match_str(":", reader) {
reader.seek(save);
return Ok(None);
}
skip_whitespace(reader);
let end = if let Some(value) = try_integer(reader)? {
skip_whitespace(reader);
Some(value)
} else {
None
};
let step = if match_str(":", reader) {
skip_whitespace(reader);
try_integer(reader)?.unwrap_or(1)
} else {
1
};
Ok(Some(ArraySliceSelector::new(start, end, step)))
}
fn try_filter_selector(reader: &mut Reader) -> ParseResult<Option<FilterSelector>> {
if match_str("?", reader) {
skip_whitespace(reader);
let expr = logical_or_expr(reader)?;
Ok(Some(FilterSelector::new(expr)))
} else {
Ok(None)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::jsonpath::ast::{
comparison::{Comparable, ComparisonExpr, ComparisonOp},
expr::{LogicalExpr, TestExpr, TestExprKind},
literal::{Literal, Number},
query::{Query, RelativeQuery},
segment::{ChildSegment, Segment},
singular_query::{RelativeSingularQuery, SingularQuery},
};
use hurl_core::reader::{CharPos, Reader};
#[test]
pub fn test_parse() {
let mut reader = Reader::new("'store',0");
assert_eq!(
parse(&mut reader).unwrap(),
vec![
Selector::Name(NameSelector::new("store".to_string())),
Selector::Index(IndexSelector::new(0))
]
);
assert_eq!(reader.cursor().index, CharPos(9));
let mut reader = Reader::new("1,5:7");
assert_eq!(
parse(&mut reader).unwrap(),
vec![
Selector::Index(IndexSelector::new(1)),
Selector::ArraySlice(ArraySliceSelector::new(Some(5), Some(7), 1))
]
);
assert_eq!(reader.cursor().index, CharPos(5));
}
#[test]
pub fn test_selector() {
let mut reader = Reader::new("'store'");
assert_eq!(
selector(&mut reader).unwrap(),
Selector::Name(NameSelector::new("store".to_string()))
);
assert_eq!(reader.cursor().index, CharPos(7));
}
#[test]
pub fn test_name_selector() {
let mut reader = Reader::new("'store'");
assert_eq!(
try_name_selector(&mut reader).unwrap().unwrap(),
NameSelector::new("store".to_string())
);
assert_eq!(reader.cursor().index, CharPos(7));
}
#[test]
pub fn test_wildcard_selector() {
let mut reader = Reader::new("*");
assert_eq!(
try_wildcard_selector(&mut reader).unwrap(),
WildcardSelector
);
assert_eq!(reader.cursor().index, CharPos(1));
}
#[test]
pub fn test_index_selector() {
let mut reader = Reader::new("1");
assert_eq!(
try_index_selector(&mut reader).unwrap().unwrap(),
IndexSelector::new(1)
);
assert_eq!(reader.cursor().index, CharPos(1));
}
#[test]
pub fn test_array_slice_selector() {
let mut reader = Reader::new("1:3");
assert_eq!(
try_array_slice_selector(&mut reader).unwrap().unwrap(),
ArraySliceSelector::new(Some(1), Some(3), 1)
);
assert_eq!(reader.cursor().index, CharPos(3));
let mut reader = Reader::new("5:");
assert_eq!(
try_array_slice_selector(&mut reader).unwrap().unwrap(),
ArraySliceSelector::new(Some(5), None, 1)
);
assert_eq!(reader.cursor().index, CharPos(2));
let mut reader = Reader::new("1:5:2");
assert_eq!(
try_array_slice_selector(&mut reader).unwrap().unwrap(),
ArraySliceSelector::new(Some(1), Some(5), 2)
);
assert_eq!(reader.cursor().index, CharPos(5));
let mut reader = Reader::new("1:5:-2");
assert_eq!(
try_array_slice_selector(&mut reader).unwrap().unwrap(),
ArraySliceSelector::new(Some(1), Some(5), -2)
);
assert_eq!(reader.cursor().index, CharPos(6));
let mut reader = Reader::new("::-1");
assert_eq!(
try_array_slice_selector(&mut reader).unwrap().unwrap(),
ArraySliceSelector::new(None, None, -1)
);
assert_eq!(reader.cursor().index, CharPos(4));
let mut reader = Reader::new(":2"); assert_eq!(
try_array_slice_selector(&mut reader).unwrap().unwrap(),
ArraySliceSelector::new(None, Some(2), 1)
);
assert_eq!(reader.cursor().index, CharPos(2));
let mut reader = Reader::new("::-1"); assert_eq!(
try_array_slice_selector(&mut reader).unwrap().unwrap(),
ArraySliceSelector::new(None, None, -1)
);
assert_eq!(reader.cursor().index, CharPos(4));
let mut reader = Reader::new("2"); assert!(try_array_slice_selector(&mut reader).unwrap().is_none());
assert_eq!(reader.cursor().index, CharPos(0));
let mut reader = Reader::new("?@['isbn']]");
assert!(try_array_slice_selector(&mut reader).unwrap().is_none());
}
#[test]
pub fn test_filter_selector() {
let mut reader = Reader::new("?@['isbn']");
assert_eq!(
try_filter_selector(&mut reader).unwrap().unwrap(),
FilterSelector::new(LogicalExpr::Test(TestExpr::new(
false,
TestExprKind::FilterQuery(Query::RelativeQuery(RelativeQuery::new(vec![
Segment::Child(ChildSegment::new(vec![Selector::Name(NameSelector::new(
"isbn".to_string()
))]))
])))
)))
);
assert_eq!(reader.cursor().index, CharPos(10));
let mut reader = Reader::new("?@>3]");
assert_eq!(
try_filter_selector(&mut reader).unwrap().unwrap(),
FilterSelector::new(LogicalExpr::Comparison(ComparisonExpr::new(
Comparable::SingularQuery(SingularQuery::Relative(RelativeSingularQuery::new(
vec![]
))),
Comparable::Literal(Literal::Number(Number::Integer(3))),
ComparisonOp::Greater
)))
);
assert_eq!(reader.cursor().index, CharPos(4));
}
}