mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-04-25 09:22:19 +00:00
the clippy lints
This commit is contained in:
commit
cab5177811
@ -14,17 +14,23 @@ branches:
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- rust: stable
|
||||
- rust: nightly
|
||||
os: linux
|
||||
env: RUST_BACKTRACE=1
|
||||
before_cache: |
|
||||
if [[ "$TRAVIS_RUST_VERSION" == stable ]]; then
|
||||
cargo install cargo-tarpaulin -f
|
||||
fi
|
||||
before_script:
|
||||
- rustup component add clippy
|
||||
script:
|
||||
- cargo clean
|
||||
- cargo clippy -- -D warnings
|
||||
- cargo build --verbose --all
|
||||
- cargo clippy --all-targets --all-features -- -D warnings -A clippy::cognitive_complexity
|
||||
- cargo test --verbose --all
|
||||
- cd wasm && cargo clippy -- -D warnings -A clippy::suspicious_else_formatting
|
||||
- cd ../nodejs/native && cargo clippy -- -D warnings
|
||||
after_success: |
|
||||
cargo tarpaulin --exclude-files nodejs wasm parser/mod.rs --out Xml
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
|
@ -109,7 +109,7 @@ fn bench_select_as(b: &mut Bencher) {
|
||||
#[bench]
|
||||
fn bench_delete(b: &mut Bencher) {
|
||||
let json = get_json();
|
||||
let mut selector = SelectorMut::new();
|
||||
let mut selector = SelectorMut::default();
|
||||
let _ = selector.str_path(get_path());
|
||||
|
||||
b.iter(move || {
|
||||
@ -123,13 +123,13 @@ fn bench_delete(b: &mut Bencher) {
|
||||
fn bench_select_to_compare_with_delete(b: &mut Bencher) {
|
||||
let json = &get_json();
|
||||
|
||||
let mut selector = Selector::new();
|
||||
let mut selector = Selector::default();
|
||||
let _ = selector.str_path(get_path());
|
||||
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
let json = json.clone();
|
||||
let mut s = Selector::new();
|
||||
let mut s = Selector::default();
|
||||
let _ = s.compiled_path(selector.node_ref().unwrap()).value(&json);
|
||||
let _ = s.select();
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ fn _selector(b: &mut Bencher, index: usize) {
|
||||
let json = get_json();
|
||||
b.iter(move || {
|
||||
for _ in 1..100 {
|
||||
let mut selector = jsonpath::Selector::new();
|
||||
let mut selector = jsonpath::Selector::default();
|
||||
let _ = selector.str_path(get_path(index));
|
||||
selector.value(&json);
|
||||
let r = selector.select();
|
||||
|
10
build.sh
10
build.sh
@ -28,6 +28,16 @@ __cargo_clean () {
|
||||
cd "${DIR}" && cargo clean
|
||||
}
|
||||
|
||||
if [ "$1" = "clippy" ]
|
||||
then
|
||||
echo
|
||||
__msg "clippy"
|
||||
cargo clippy -- -D warnings && \
|
||||
cargo clippy --all-targets --all-features -- -D warnings -A clippy::cognitive_complexity && \
|
||||
cd "${WASM}" && cargo clippy -- -A clippy::suspicious_else_formatting && \
|
||||
cd "${NODEJS}" && cargo clippy
|
||||
fi
|
||||
|
||||
echo
|
||||
__msg "clean"
|
||||
rm -rf \
|
||||
|
@ -206,7 +206,7 @@ declare_types! {
|
||||
{
|
||||
let guard = ctx.lock();
|
||||
let mut this = this.borrow_mut(&guard);
|
||||
let _ = this.path(&path);
|
||||
this.path(&path);
|
||||
}
|
||||
|
||||
Ok(JsUndefined::new().upcast())
|
||||
@ -219,7 +219,7 @@ declare_types! {
|
||||
{
|
||||
let guard = ctx.lock();
|
||||
let mut this = this.borrow_mut(&guard);
|
||||
let _ = this.value(&json_str);
|
||||
this.value(&json_str);
|
||||
}
|
||||
|
||||
Ok(JsUndefined::new().upcast())
|
||||
|
21
src/lib.rs
21
src/lib.rs
@ -132,7 +132,7 @@ extern crate serde_json;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
pub use parser::parser::{Node, Parser};
|
||||
pub use parser::Parser;
|
||||
pub use select::JsonPathError;
|
||||
pub use select::{Selector, SelectorMut};
|
||||
|
||||
@ -169,10 +169,10 @@ mod select;
|
||||
/// ]);
|
||||
/// ```
|
||||
pub fn compile(path: &str) -> impl FnMut(&Value) -> Result<Vec<&Value>, JsonPathError> {
|
||||
let node = Parser::compile(path);
|
||||
let node = parser::Parser::compile(path);
|
||||
move |json| match &node {
|
||||
Ok(node) => {
|
||||
let mut selector = Selector::new();
|
||||
let mut selector = Selector::default();
|
||||
selector.compiled_path(node).value(json).select()
|
||||
}
|
||||
Err(e) => Err(JsonPathError::Path(e.to_string())),
|
||||
@ -213,8 +213,9 @@ pub fn compile(path: &str) -> impl FnMut(&Value) -> Result<Vec<&Value>, JsonPath
|
||||
/// &json!({"name": "친구2", "age": 20})
|
||||
/// ]);
|
||||
/// ```
|
||||
#[allow(clippy::needless_lifetimes)]
|
||||
pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result<Vec<&Value>, JsonPathError> {
|
||||
let mut selector = Selector::new();
|
||||
let mut selector = Selector::default();
|
||||
let _ = selector.value(json);
|
||||
move |path: &str| selector.str_path(path)?.reset_value().select()
|
||||
}
|
||||
@ -268,7 +269,7 @@ pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result<Vec<&Value
|
||||
pub fn selector_as<T: serde::de::DeserializeOwned>(
|
||||
json: &Value,
|
||||
) -> impl FnMut(&str) -> Result<Vec<T>, JsonPathError> + '_ {
|
||||
let mut selector = Selector::new();
|
||||
let mut selector = Selector::default();
|
||||
let _ = selector.value(json);
|
||||
move |path: &str| selector.str_path(path)?.reset_value().select_as()
|
||||
}
|
||||
@ -299,7 +300,7 @@ pub fn selector_as<T: serde::de::DeserializeOwned>(
|
||||
/// ]);
|
||||
/// ```
|
||||
pub fn select<'a>(json: &'a Value, path: &'a str) -> Result<Vec<&'a Value>, JsonPathError> {
|
||||
Selector::new().str_path(path)?.value(json).select()
|
||||
Selector::default().str_path(path)?.value(json).select()
|
||||
}
|
||||
|
||||
/// It is the same to `select` function but it return the result as string.
|
||||
@ -327,7 +328,7 @@ pub fn select<'a>(json: &'a Value, path: &'a str) -> Result<Vec<&'a Value>, Json
|
||||
/// ```
|
||||
pub fn select_as_str(json_str: &str, path: &str) -> Result<String, JsonPathError> {
|
||||
let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?;
|
||||
let ret = Selector::new().str_path(path)?.value(&json).select()?;
|
||||
let ret = Selector::default().str_path(path)?.value(&json).select()?;
|
||||
serde_json::to_string(&ret).map_err(|e| JsonPathError::Serde(e.to_string()))
|
||||
}
|
||||
|
||||
@ -374,7 +375,7 @@ pub fn select_as<T: serde::de::DeserializeOwned>(
|
||||
path: &str,
|
||||
) -> Result<Vec<T>, JsonPathError> {
|
||||
let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?;
|
||||
Selector::new().str_path(path)?.value(&json).select_as()
|
||||
Selector::default().str_path(path)?.value(&json).select_as()
|
||||
}
|
||||
|
||||
/// Delete(= replace with null) the JSON property using the jsonpath.
|
||||
@ -410,7 +411,7 @@ pub fn select_as<T: serde::de::DeserializeOwned>(
|
||||
/// ]}));
|
||||
/// ```
|
||||
pub fn delete(value: Value, path: &str) -> Result<Value, JsonPathError> {
|
||||
let mut selector = SelectorMut::new();
|
||||
let mut selector = SelectorMut::default();
|
||||
let ret = selector
|
||||
.str_path(path)?
|
||||
.value(value)
|
||||
@ -466,7 +467,7 @@ pub fn replace_with<F>(value: Value, path: &str, fun: &mut F) -> Result<Value, J
|
||||
where
|
||||
F: FnMut(&Value) -> Value,
|
||||
{
|
||||
let mut selector = SelectorMut::new();
|
||||
let mut selector = SelectorMut::default();
|
||||
let ret = selector
|
||||
.str_path(path)?
|
||||
.value(value)
|
||||
|
@ -1,10 +1,695 @@
|
||||
pub mod parser;
|
||||
mod path_reader;
|
||||
pub(crate) mod tokenizer;
|
||||
mod tokenizer;
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use self::tokenizer::*;
|
||||
|
||||
const DUMMY: usize = 0;
|
||||
|
||||
type ParseResult<T> = Result<T, String>;
|
||||
|
||||
mod utils {
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn string_to_num<F, S: FromStr>(string: &str, msg_handler: F) -> Result<S, String>
|
||||
where
|
||||
F: Fn() -> String,
|
||||
{
|
||||
match string.parse() {
|
||||
Ok(n) => Ok(n),
|
||||
_ => Err(msg_handler()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum ParseToken {
|
||||
// '$'
|
||||
Absolute,
|
||||
// '@'
|
||||
Relative,
|
||||
// '.'
|
||||
In,
|
||||
// '..'
|
||||
Leaves,
|
||||
// '*'
|
||||
All,
|
||||
|
||||
Key(String),
|
||||
Keys(Vec<String>),
|
||||
// []
|
||||
Array,
|
||||
// 메타토큰
|
||||
ArrayEof,
|
||||
// ?( filter )
|
||||
Filter(FilterToken),
|
||||
// 1 : 2
|
||||
Range(Option<isize>, Option<isize>, Option<usize>),
|
||||
// 1, 2, 3
|
||||
Union(Vec<isize>),
|
||||
|
||||
Number(f64),
|
||||
|
||||
Bool(bool),
|
||||
|
||||
Eof,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum FilterToken {
|
||||
Equal,
|
||||
NotEqual,
|
||||
Little,
|
||||
LittleOrEqual,
|
||||
Greater,
|
||||
GreaterOrEqual,
|
||||
And,
|
||||
Or,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Node {
|
||||
left: Option<Box<Node>>,
|
||||
right: Option<Box<Node>>,
|
||||
token: ParseToken,
|
||||
}
|
||||
|
||||
pub struct Parser;
|
||||
|
||||
impl Parser {
|
||||
pub fn compile(input: &str) -> ParseResult<Node> {
|
||||
let mut tokenizer = TokenReader::new(input);
|
||||
Ok(Self::json_path(&mut tokenizer)?)
|
||||
}
|
||||
|
||||
fn json_path(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#json_path");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Absolute(_)) => {
|
||||
let node = Self::node(ParseToken::Absolute);
|
||||
Self::paths(node, tokenizer)
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn paths(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#paths");
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Dot(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::paths_dot(prev, tokenizer)
|
||||
}
|
||||
Ok(Token::OpenArray(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
let node = Self::array(prev, tokenizer)?;
|
||||
Self::paths(node, tokenizer)
|
||||
}
|
||||
_ => Ok(prev),
|
||||
}
|
||||
}
|
||||
|
||||
fn paths_dot(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#paths_dot");
|
||||
let node = Self::path(prev, tokenizer)?;
|
||||
Self::paths(node, tokenizer)
|
||||
}
|
||||
|
||||
fn path(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path");
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Dot(_)) => Self::path_leaves(prev, tokenizer),
|
||||
Ok(Token::Asterisk(_)) => Self::path_in_all(prev, tokenizer),
|
||||
Ok(Token::Key(_, _)) => Self::path_in_key(prev, tokenizer),
|
||||
Ok(Token::OpenArray(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::array(prev, tokenizer)
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn path_leaves(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path_leaves");
|
||||
Self::eat_token(tokenizer);
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Asterisk(_)) => Self::path_leaves_all(prev, tokenizer),
|
||||
Ok(Token::OpenArray(_)) => {
|
||||
let mut leaves_node = Self::node(ParseToken::Leaves);
|
||||
leaves_node.left = Some(Box::new(prev));
|
||||
Ok(Self::paths(leaves_node, tokenizer)?)
|
||||
}
|
||||
_ => Self::path_leaves_key(prev, tokenizer),
|
||||
}
|
||||
}
|
||||
|
||||
fn path_leaves_key(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path_leaves_key");
|
||||
Ok(Node {
|
||||
token: ParseToken::Leaves,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::key(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
|
||||
fn path_leaves_all(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path_leaves_all");
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::Leaves,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::node(ParseToken::All))),
|
||||
})
|
||||
}
|
||||
|
||||
fn path_in_all(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path_in_all");
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::In,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::node(ParseToken::All))),
|
||||
})
|
||||
}
|
||||
|
||||
fn path_in_key(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path_in_key");
|
||||
Ok(Node {
|
||||
token: ParseToken::In,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::key(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
|
||||
fn key(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#key");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(_, v)) => Ok(Self::node(ParseToken::Key(v))),
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn boolean(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#boolean");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(_, ref v))
|
||||
if {
|
||||
let b = v.as_bytes();
|
||||
!b.is_empty() && (b[0] == b't' || b[0] == b'T' || b[0] == b'f' || b[0] == b'F')
|
||||
} =>
|
||||
{
|
||||
Ok(Self::node(ParseToken::Bool(v.eq_ignore_ascii_case("true"))))
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn array_keys(tokenizer: &mut TokenReader, first_key: String) -> ParseResult<Node> {
|
||||
let mut keys = vec![first_key];
|
||||
while tokenizer.peek_is(COMMA) {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::SingleQuoted(_, val)) | Ok(Token::DoubleQuoted(_, val)) => {
|
||||
keys.push(val);
|
||||
}
|
||||
_ => return Err(tokenizer.err_msg()),
|
||||
}
|
||||
|
||||
Self::eat_whitespace(tokenizer);
|
||||
}
|
||||
|
||||
Ok(Self::node(ParseToken::Keys(keys)))
|
||||
}
|
||||
|
||||
fn array_quote_value(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_quote_value");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::SingleQuoted(_, val)) | Ok(Token::DoubleQuoted(_, val)) => {
|
||||
if !tokenizer.peek_is(COMMA) {
|
||||
Ok(Self::node(ParseToken::Key(val)))
|
||||
} else {
|
||||
Self::array_keys(tokenizer, val)
|
||||
}
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn array_start(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_start");
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Question(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::Array,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::filter(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
Ok(Token::Asterisk(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::Array,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::node(ParseToken::All))),
|
||||
})
|
||||
}
|
||||
_ => Ok(Node {
|
||||
token: ParseToken::Array,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::array_value(tokenizer)?)),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn array(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array");
|
||||
let ret = Self::array_start(prev, tokenizer)?;
|
||||
Self::eat_whitespace(tokenizer);
|
||||
Self::close_token(ret, Token::CloseArray(DUMMY), tokenizer)
|
||||
}
|
||||
|
||||
fn array_value_key(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_value_key");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref val)) => {
|
||||
let digit = utils::string_to_num(val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Comma(_)) => Self::union(digit, tokenizer),
|
||||
Ok(Token::Split(_)) => Self::range_from(digit, tokenizer),
|
||||
_ => Ok(Self::node(ParseToken::Number(digit as f64))),
|
||||
}
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn array_value(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_value");
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Key(_, _)) => Self::array_value_key(tokenizer),
|
||||
Ok(Token::Split(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::range_to(tokenizer)
|
||||
}
|
||||
Ok(Token::DoubleQuoted(_, _)) | Ok(Token::SingleQuoted(_, _)) => {
|
||||
Self::array_quote_value(tokenizer)
|
||||
}
|
||||
Err(TokenError::Eof) => Ok(Self::node(ParseToken::Eof)),
|
||||
_ => {
|
||||
Self::eat_token(tokenizer);
|
||||
Err(tokenizer.err_msg())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn union(num: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#union");
|
||||
let mut values = vec![num];
|
||||
while match tokenizer.peek_token() {
|
||||
Ok(Token::Comma(_)) => true,
|
||||
_ => false,
|
||||
} {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref val)) => {
|
||||
let digit = utils::string_to_num(val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
values.push(digit);
|
||||
}
|
||||
_ => {
|
||||
return Err(tokenizer.err_msg());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Self::node(ParseToken::Union(values)))
|
||||
}
|
||||
|
||||
fn range_value<S: FromStr>(tokenizer: &mut TokenReader) -> Result<Option<S>, String> {
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Split(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
}
|
||||
_ => {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Key(_, _)) => {}
|
||||
_ => {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, str_step)) => {
|
||||
match utils::string_to_num(&str_step, || tokenizer.err_msg_with_pos(pos)) {
|
||||
Ok(step) => Ok(Some(step)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn range_from(from: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#range_from");
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Key(_, _)) => Self::range(from, tokenizer),
|
||||
Ok(Token::Split(_)) => match Self::range_value(tokenizer)? {
|
||||
Some(step) => Ok(Self::node(ParseToken::Range(Some(from), None, Some(step)))),
|
||||
_ => Ok(Self::node(ParseToken::Range(Some(from), None, None))),
|
||||
},
|
||||
_ => Ok(Self::node(ParseToken::Range(Some(from), None, None))),
|
||||
}
|
||||
}
|
||||
|
||||
fn range_to(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#range_to");
|
||||
|
||||
if let Some(step) = Self::range_value(tokenizer)? {
|
||||
return Ok(Self::node(ParseToken::Range(None, None, Some(step))));
|
||||
}
|
||||
|
||||
if let Ok(Token::CloseArray(_)) = tokenizer.peek_token() {
|
||||
return Ok(Self::node(ParseToken::Range(None, None, None)));
|
||||
}
|
||||
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref to_str)) => {
|
||||
let to = utils::string_to_num(to_str, || tokenizer.err_msg_with_pos(pos))?;
|
||||
let step = Self::range_value(tokenizer)?;
|
||||
Ok(Self::node(ParseToken::Range(None, Some(to), step)))
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn range(from: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#range");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref str_to)) => {
|
||||
let to = utils::string_to_num(str_to, || tokenizer.err_msg_with_pos(pos))?;
|
||||
let step = Self::range_value(tokenizer)?;
|
||||
Ok(Self::node(ParseToken::Range(Some(from), Some(to), step)))
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn filter(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#filter");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::OpenParenthesis(_)) => {
|
||||
let ret = Self::exprs(tokenizer)?;
|
||||
Self::eat_whitespace(tokenizer);
|
||||
Self::close_token(ret, Token::CloseParenthesis(DUMMY), tokenizer)
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn exprs(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
Self::eat_whitespace(tokenizer);
|
||||
debug!("#exprs");
|
||||
let node = match tokenizer.peek_token() {
|
||||
Ok(Token::OpenParenthesis(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
trace!("\t-exprs - open_parenthesis");
|
||||
let ret = Self::exprs(tokenizer)?;
|
||||
Self::eat_whitespace(tokenizer);
|
||||
Self::close_token(ret, Token::CloseParenthesis(DUMMY), tokenizer)?
|
||||
}
|
||||
_ => {
|
||||
trace!("\t-exprs - else");
|
||||
Self::expr(tokenizer)?
|
||||
}
|
||||
};
|
||||
Self::eat_whitespace(tokenizer);
|
||||
Self::condition_expr(node, tokenizer)
|
||||
}
|
||||
|
||||
fn condition_expr(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#condition_expr");
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::And(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::Filter(FilterToken::And),
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::exprs(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
Ok(Token::Or(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::Filter(FilterToken::Or),
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::exprs(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
_ => Ok(prev),
|
||||
}
|
||||
}
|
||||
|
||||
fn expr(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#expr");
|
||||
|
||||
let has_prop_candidate = match tokenizer.peek_token() {
|
||||
Ok(Token::At(_)) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let node = Self::term(tokenizer)?;
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
if match tokenizer.peek_token() {
|
||||
Ok(Token::Equal(_))
|
||||
| Ok(Token::NotEqual(_))
|
||||
| Ok(Token::Little(_))
|
||||
| Ok(Token::LittleOrEqual(_))
|
||||
| Ok(Token::Greater(_))
|
||||
| Ok(Token::GreaterOrEqual(_)) => true,
|
||||
_ => false,
|
||||
} {
|
||||
Self::op(node, tokenizer)
|
||||
} else if has_prop_candidate {
|
||||
Ok(node)
|
||||
} else {
|
||||
Err(tokenizer.err_msg())
|
||||
}
|
||||
}
|
||||
|
||||
fn term_num(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#term_num");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, val)) => match tokenizer.peek_token() {
|
||||
Ok(Token::Dot(_)) => Self::term_num_float(val.as_str(), tokenizer),
|
||||
_ => {
|
||||
let number = utils::string_to_num(&val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
Ok(Self::node(ParseToken::Number(number)))
|
||||
}
|
||||
},
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn term_num_float(num: &str, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#term_num_float");
|
||||
Self::eat_token(tokenizer);
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, frac)) => {
|
||||
let mut f = String::new();
|
||||
f.push_str(&num);
|
||||
f.push('.');
|
||||
f.push_str(frac.as_str());
|
||||
let number = utils::string_to_num(&f, || tokenizer.err_msg_with_pos(pos))?;
|
||||
Ok(Self::node(ParseToken::Number(number)))
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn term(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#term");
|
||||
|
||||
if tokenizer.peek_is(AT) {
|
||||
Self::eat_token(tokenizer);
|
||||
let node = Self::node(ParseToken::Relative);
|
||||
|
||||
return match tokenizer.peek_token() {
|
||||
Ok(Token::Whitespace(_, _)) => {
|
||||
Self::eat_whitespace(tokenizer);
|
||||
Ok(node)
|
||||
}
|
||||
_ => Self::paths(node, tokenizer),
|
||||
};
|
||||
}
|
||||
|
||||
if tokenizer.peek_is(ABSOLUTE) {
|
||||
return Self::json_path(tokenizer);
|
||||
}
|
||||
|
||||
if tokenizer.peek_is(DOUBLE_QUOTE) || tokenizer.peek_is(SINGLE_QUOTE) {
|
||||
return Self::array_quote_value(tokenizer);
|
||||
}
|
||||
|
||||
if tokenizer.peek_is(KEY) {
|
||||
let key = if let Ok(Token::Key(_, k)) = tokenizer.peek_token() {
|
||||
k.clone()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
return match key.as_bytes()[0] {
|
||||
b'-' | b'0'..=b'9' => Self::term_num(tokenizer),
|
||||
_ => Self::boolean(tokenizer),
|
||||
};
|
||||
}
|
||||
|
||||
Err(tokenizer.err_msg())
|
||||
}
|
||||
|
||||
fn op(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#op");
|
||||
let token = match tokenizer.next_token() {
|
||||
Ok(Token::Equal(_)) => ParseToken::Filter(FilterToken::Equal),
|
||||
Ok(Token::NotEqual(_)) => ParseToken::Filter(FilterToken::NotEqual),
|
||||
Ok(Token::Little(_)) => ParseToken::Filter(FilterToken::Little),
|
||||
Ok(Token::LittleOrEqual(_)) => ParseToken::Filter(FilterToken::LittleOrEqual),
|
||||
Ok(Token::Greater(_)) => ParseToken::Filter(FilterToken::Greater),
|
||||
Ok(Token::GreaterOrEqual(_)) => ParseToken::Filter(FilterToken::GreaterOrEqual),
|
||||
_ => {
|
||||
return Err(tokenizer.err_msg());
|
||||
}
|
||||
};
|
||||
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
Ok(Node {
|
||||
token,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::term(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
|
||||
fn eat_whitespace(tokenizer: &mut TokenReader) {
|
||||
while let Ok(Token::Whitespace(_, _)) = tokenizer.peek_token() {
|
||||
let _ = tokenizer.next_token();
|
||||
}
|
||||
}
|
||||
|
||||
fn eat_token(tokenizer: &mut TokenReader) {
|
||||
let _ = tokenizer.next_token();
|
||||
}
|
||||
|
||||
fn node(token: ParseToken) -> Node {
|
||||
Node {
|
||||
left: None,
|
||||
right: None,
|
||||
token,
|
||||
}
|
||||
}
|
||||
|
||||
fn close_token(ret: Node, token: Token, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#close_token");
|
||||
match tokenizer.next_token() {
|
||||
Ok(ref t) if t.partial_eq(token) => Ok(ret),
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NodeVisitor {
|
||||
fn visit(&mut self, node: &Node) {
|
||||
match &node.token {
|
||||
ParseToken::Absolute
|
||||
| ParseToken::Relative
|
||||
| ParseToken::All
|
||||
| ParseToken::Key(_)
|
||||
| ParseToken::Keys(_)
|
||||
| ParseToken::Range(_, _, _)
|
||||
| ParseToken::Union(_)
|
||||
| ParseToken::Number(_)
|
||||
| ParseToken::Bool(_) => {
|
||||
self.visit_token(&node.token);
|
||||
}
|
||||
ParseToken::In | ParseToken::Leaves => {
|
||||
if let Some(n) = &node.left {
|
||||
self.visit(&*n);
|
||||
}
|
||||
|
||||
self.visit_token(&node.token);
|
||||
|
||||
if let Some(n) = &node.right {
|
||||
self.visit(&*n);
|
||||
}
|
||||
}
|
||||
ParseToken::Array => {
|
||||
if let Some(n) = &node.left {
|
||||
self.visit(&*n);
|
||||
}
|
||||
|
||||
self.visit_token(&node.token);
|
||||
|
||||
if let Some(n) = &node.right {
|
||||
self.visit(&*n);
|
||||
}
|
||||
|
||||
self.visit_token(&ParseToken::ArrayEof);
|
||||
}
|
||||
ParseToken::Filter(FilterToken::And) | ParseToken::Filter(FilterToken::Or) => {
|
||||
if let Some(n) = &node.left {
|
||||
self.visit(&*n);
|
||||
}
|
||||
|
||||
if let Some(n) = &node.right {
|
||||
self.visit(&*n);
|
||||
}
|
||||
|
||||
self.visit_token(&node.token);
|
||||
}
|
||||
ParseToken::Filter(_) => {
|
||||
if let Some(n) = &node.left {
|
||||
self.visit(&*n);
|
||||
}
|
||||
|
||||
self.end_term();
|
||||
|
||||
if let Some(n) = &node.right {
|
||||
self.visit(&*n);
|
||||
}
|
||||
|
||||
self.end_term();
|
||||
|
||||
self.visit_token(&node.token);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_token(&mut self, token: &ParseToken);
|
||||
fn end_term(&mut self) {}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod parser_tests {
|
||||
use parser::parser::{FilterToken, NodeVisitor, ParseToken, Parser};
|
||||
use parser::{FilterToken, NodeVisitor, ParseToken, Parser};
|
||||
|
||||
struct NodeVisitorTestImpl<'a> {
|
||||
input: &'a str,
|
||||
@ -46,11 +731,7 @@ mod parser_tests {
|
||||
setup();
|
||||
|
||||
fn invalid(path: &str) {
|
||||
if let Err(_) = run(path) {
|
||||
assert!(true);
|
||||
} else {
|
||||
assert!(false);
|
||||
}
|
||||
assert!(run(path).is_err());
|
||||
}
|
||||
|
||||
invalid("$[]");
|
||||
@ -135,24 +816,21 @@ mod parser_tests {
|
||||
])
|
||||
);
|
||||
|
||||
match run("$.") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
if run("$.").is_ok() {
|
||||
panic!();
|
||||
}
|
||||
|
||||
match run("$..") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
if run("$..").is_ok() {
|
||||
panic!();
|
||||
}
|
||||
|
||||
match run("$. a") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
if run("$. a").is_ok() {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_array_sytax() {
|
||||
fn parse_array_syntax() {
|
||||
setup();
|
||||
|
||||
assert_eq!(
|
||||
@ -525,24 +1203,20 @@ mod parser_tests {
|
||||
])
|
||||
);
|
||||
|
||||
match run("$[1.1]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
if run("$[1.1]").is_ok() {
|
||||
panic!();
|
||||
}
|
||||
|
||||
match run("$[?(1.1<.2)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
if run("$[?(1.1<.2)]").is_ok() {
|
||||
panic!();
|
||||
}
|
||||
|
||||
match run("$[?(1.1<2.)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
if run("$[?(1.1<2.)]").is_ok() {
|
||||
panic!();
|
||||
}
|
||||
|
||||
match run("$[?(1.1<2.a)]") {
|
||||
Ok(_) => panic!(),
|
||||
_ => {}
|
||||
if run("$[?(1.1<2.a)]").is_ok() {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -567,7 +1241,7 @@ mod tokenizer_tests {
|
||||
}
|
||||
|
||||
fn run(input: &str, expected: (Vec<Token>, Option<TokenError>)) {
|
||||
let (vec, err) = collect_token(input.clone());
|
||||
let (vec, err) = collect_token(input);
|
||||
assert_eq!((vec, err), expected, "\"{}\"", input);
|
||||
}
|
||||
|
||||
|
@ -1,696 +0,0 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::tokenizer::*;
|
||||
|
||||
const DUMMY: usize = 0;
|
||||
|
||||
type ParseResult<T> = Result<T, String>;
|
||||
|
||||
mod utils {
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn string_to_num<F, S: FromStr>(string: &String, msg_handler: F) -> Result<S, String>
|
||||
where
|
||||
F: Fn() -> String,
|
||||
{
|
||||
match string.as_str().parse() {
|
||||
Ok(n) => Ok(n),
|
||||
_ => Err(msg_handler()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum ParseToken {
|
||||
// '$'
|
||||
Absolute,
|
||||
// '@'
|
||||
Relative,
|
||||
// '.'
|
||||
In,
|
||||
// '..'
|
||||
Leaves,
|
||||
// '*'
|
||||
All,
|
||||
|
||||
Key(String),
|
||||
Keys(Vec<String>),
|
||||
// []
|
||||
Array,
|
||||
// 메타토큰
|
||||
ArrayEof,
|
||||
// ?( filter )
|
||||
Filter(FilterToken),
|
||||
// 1 : 2
|
||||
Range(Option<isize>, Option<isize>, Option<usize>),
|
||||
// 1, 2, 3
|
||||
Union(Vec<isize>),
|
||||
|
||||
Number(f64),
|
||||
|
||||
Bool(bool),
|
||||
|
||||
Eof,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum FilterToken {
|
||||
Equal,
|
||||
NotEqual,
|
||||
Little,
|
||||
LittleOrEqual,
|
||||
Greater,
|
||||
GreaterOrEqual,
|
||||
And,
|
||||
Or,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Node {
|
||||
left: Option<Box<Node>>,
|
||||
right: Option<Box<Node>>,
|
||||
token: ParseToken,
|
||||
}
|
||||
|
||||
pub struct Parser;
|
||||
|
||||
impl Parser {
|
||||
pub fn compile(input: &str) -> ParseResult<Node> {
|
||||
let mut tokenizer = TokenReader::new(input);
|
||||
Ok(Self::json_path(&mut tokenizer)?)
|
||||
}
|
||||
|
||||
fn json_path(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#json_path");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Absolute(_)) => {
|
||||
let node = Self::node(ParseToken::Absolute);
|
||||
Self::paths(node, tokenizer)
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn paths(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#paths");
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Dot(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::paths_dot(prev, tokenizer)
|
||||
}
|
||||
Ok(Token::OpenArray(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
let node = Self::array(prev, tokenizer)?;
|
||||
Self::paths(node, tokenizer)
|
||||
}
|
||||
_ => Ok(prev),
|
||||
}
|
||||
}
|
||||
|
||||
fn paths_dot(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#paths_dot");
|
||||
let node = Self::path(prev, tokenizer)?;
|
||||
Self::paths(node, tokenizer)
|
||||
}
|
||||
|
||||
fn path(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path");
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Dot(_)) => Self::path_leaves(prev, tokenizer),
|
||||
Ok(Token::Asterisk(_)) => Self::path_in_all(prev, tokenizer),
|
||||
Ok(Token::Key(_, _)) => Self::path_in_key(prev, tokenizer),
|
||||
Ok(Token::OpenArray(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::array(prev, tokenizer)
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn path_leaves(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path_leaves");
|
||||
Self::eat_token(tokenizer);
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Asterisk(_)) => Self::path_leaves_all(prev, tokenizer),
|
||||
Ok(Token::OpenArray(_)) => {
|
||||
let mut leaves_node = Self::node(ParseToken::Leaves);
|
||||
leaves_node.left = Some(Box::new(prev));
|
||||
Ok(Self::paths(leaves_node, tokenizer)?)
|
||||
}
|
||||
_ => Self::path_leaves_key(prev, tokenizer),
|
||||
}
|
||||
}
|
||||
|
||||
fn path_leaves_key(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path_leaves_key");
|
||||
Ok(Node {
|
||||
token: ParseToken::Leaves,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::key(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
|
||||
fn path_leaves_all(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path_leaves_all");
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::Leaves,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::node(ParseToken::All))),
|
||||
})
|
||||
}
|
||||
|
||||
fn path_in_all(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path_in_all");
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::In,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::node(ParseToken::All))),
|
||||
})
|
||||
}
|
||||
|
||||
fn path_in_key(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#path_in_key");
|
||||
Ok(Node {
|
||||
token: ParseToken::In,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::key(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
|
||||
fn key(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#key");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(_, v)) => Ok(Self::node(ParseToken::Key(v))),
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn boolean(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#boolean");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(_, ref v))
|
||||
if {
|
||||
let b = v.as_bytes();
|
||||
b.len() > 0 && (b[0] == b't' || b[0] == b'T' || b[0] == b'f' || b[0] == b'F')
|
||||
} =>
|
||||
{
|
||||
Ok(Self::node(ParseToken::Bool(v.eq_ignore_ascii_case("true"))))
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn array_keys(tokenizer: &mut TokenReader, first_key: String) -> ParseResult<Node> {
|
||||
let mut keys = vec![first_key];
|
||||
while tokenizer.peek_is(COMMA) {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::SingleQuoted(_, val)) | Ok(Token::DoubleQuoted(_, val)) => {
|
||||
keys.push(val);
|
||||
}
|
||||
_ => return Err(tokenizer.err_msg()),
|
||||
}
|
||||
|
||||
Self::eat_whitespace(tokenizer);
|
||||
}
|
||||
|
||||
Ok(Self::node(ParseToken::Keys(keys)))
|
||||
}
|
||||
|
||||
fn array_quote_value(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_quote_value");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::SingleQuoted(_, val)) | Ok(Token::DoubleQuoted(_, val)) => {
|
||||
if !tokenizer.peek_is(COMMA) {
|
||||
Ok(Self::node(ParseToken::Key(val)))
|
||||
} else {
|
||||
Self::array_keys(tokenizer, val)
|
||||
}
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn array_start(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_start");
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Question(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::Array,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::filter(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
Ok(Token::Asterisk(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::Array,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::node(ParseToken::All))),
|
||||
})
|
||||
}
|
||||
_ => Ok(Node {
|
||||
token: ParseToken::Array,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::array_value(tokenizer)?)),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn array(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array");
|
||||
let ret = Self::array_start(prev, tokenizer)?;
|
||||
Self::eat_whitespace(tokenizer);
|
||||
Self::close_token(ret, Token::CloseArray(DUMMY), tokenizer)
|
||||
}
|
||||
|
||||
fn array_value_key(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_value_key");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref val)) => {
|
||||
let digit = utils::string_to_num(val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Comma(_)) => Self::union(digit, tokenizer),
|
||||
Ok(Token::Split(_)) => Self::range_from(digit, tokenizer),
|
||||
_ => Ok(Self::node(ParseToken::Number(digit as f64))),
|
||||
}
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn array_value(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#array_value");
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Key(_, _)) => Self::array_value_key(tokenizer),
|
||||
Ok(Token::Split(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::range_to(tokenizer)
|
||||
}
|
||||
Ok(Token::DoubleQuoted(_, _)) | Ok(Token::SingleQuoted(_, _)) => {
|
||||
Self::array_quote_value(tokenizer)
|
||||
}
|
||||
Err(TokenError::Eof) => Ok(Self::node(ParseToken::Eof)),
|
||||
_ => {
|
||||
Self::eat_token(tokenizer);
|
||||
Err(tokenizer.err_msg())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn union(num: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#union");
|
||||
let mut values = vec![num];
|
||||
while match tokenizer.peek_token() {
|
||||
Ok(Token::Comma(_)) => true,
|
||||
_ => false,
|
||||
} {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref val)) => {
|
||||
let digit = utils::string_to_num(val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
values.push(digit);
|
||||
}
|
||||
_ => {
|
||||
return Err(tokenizer.err_msg());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Self::node(ParseToken::Union(values)))
|
||||
}
|
||||
|
||||
fn range_value<S: FromStr>(tokenizer: &mut TokenReader) -> Result<Option<S>, String> {
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Split(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
}
|
||||
_ => {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Key(_, _)) => {}
|
||||
_ => {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, str_step)) => {
|
||||
match utils::string_to_num(&str_step, || tokenizer.err_msg_with_pos(pos)) {
|
||||
Ok(step) => Ok(Some(step)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn range_from(from: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#range_from");
|
||||
Self::eat_token(tokenizer);
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::Key(_, _)) => Self::range(from, tokenizer),
|
||||
Ok(Token::Split(_)) => match Self::range_value(tokenizer)? {
|
||||
Some(step) => Ok(Self::node(ParseToken::Range(Some(from), None, Some(step)))),
|
||||
_ => Ok(Self::node(ParseToken::Range(Some(from), None, None))),
|
||||
},
|
||||
_ => Ok(Self::node(ParseToken::Range(Some(from), None, None))),
|
||||
}
|
||||
}
|
||||
|
||||
fn range_to(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#range_to");
|
||||
|
||||
match Self::range_value(tokenizer)? {
|
||||
Some(step) => return Ok(Self::node(ParseToken::Range(None, None, Some(step)))),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::CloseArray(_)) => {
|
||||
return Ok(Self::node(ParseToken::Range(None, None, None)));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref to_str)) => {
|
||||
let to = utils::string_to_num(to_str, || tokenizer.err_msg_with_pos(pos))?;
|
||||
let step = Self::range_value(tokenizer)?;
|
||||
Ok(Self::node(ParseToken::Range(None, Some(to), step)))
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn range(from: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#range");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, ref str_to)) => {
|
||||
let to = utils::string_to_num(str_to, || tokenizer.err_msg_with_pos(pos))?;
|
||||
let step = Self::range_value(tokenizer)?;
|
||||
Ok(Self::node(ParseToken::Range(Some(from), Some(to), step)))
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn filter(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#filter");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::OpenParenthesis(_)) => {
|
||||
let ret = Self::exprs(tokenizer)?;
|
||||
Self::eat_whitespace(tokenizer);
|
||||
Self::close_token(ret, Token::CloseParenthesis(DUMMY), tokenizer)
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn exprs(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
Self::eat_whitespace(tokenizer);
|
||||
debug!("#exprs");
|
||||
let node = match tokenizer.peek_token() {
|
||||
Ok(Token::OpenParenthesis(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
trace!("\t-exprs - open_parenthesis");
|
||||
let ret = Self::exprs(tokenizer)?;
|
||||
Self::eat_whitespace(tokenizer);
|
||||
Self::close_token(ret, Token::CloseParenthesis(DUMMY), tokenizer)?
|
||||
}
|
||||
_ => {
|
||||
trace!("\t-exprs - else");
|
||||
Self::expr(tokenizer)?
|
||||
}
|
||||
};
|
||||
Self::eat_whitespace(tokenizer);
|
||||
Self::condition_expr(node, tokenizer)
|
||||
}
|
||||
|
||||
fn condition_expr(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#condition_expr");
|
||||
match tokenizer.peek_token() {
|
||||
Ok(Token::And(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::Filter(FilterToken::And),
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::exprs(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
Ok(Token::Or(_)) => {
|
||||
Self::eat_token(tokenizer);
|
||||
Ok(Node {
|
||||
token: ParseToken::Filter(FilterToken::Or),
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::exprs(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
_ => Ok(prev),
|
||||
}
|
||||
}
|
||||
|
||||
fn expr(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#expr");
|
||||
|
||||
let has_prop_candidate = match tokenizer.peek_token() {
|
||||
Ok(Token::At(_)) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let node = Self::term(tokenizer)?;
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
if match tokenizer.peek_token() {
|
||||
Ok(Token::Equal(_))
|
||||
| Ok(Token::NotEqual(_))
|
||||
| Ok(Token::Little(_))
|
||||
| Ok(Token::LittleOrEqual(_))
|
||||
| Ok(Token::Greater(_))
|
||||
| Ok(Token::GreaterOrEqual(_)) => true,
|
||||
_ => false,
|
||||
} {
|
||||
Self::op(node, tokenizer)
|
||||
} else if has_prop_candidate {
|
||||
Ok(node)
|
||||
} else {
|
||||
return Err(tokenizer.err_msg());
|
||||
}
|
||||
}
|
||||
|
||||
fn term_num(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#term_num");
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, val)) => match tokenizer.peek_token() {
|
||||
Ok(Token::Dot(_)) => Self::term_num_float(val.as_str(), tokenizer),
|
||||
_ => {
|
||||
let number = utils::string_to_num(&val, || tokenizer.err_msg_with_pos(pos))?;
|
||||
Ok(Self::node(ParseToken::Number(number)))
|
||||
}
|
||||
},
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn term_num_float(mut num: &str, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#term_num_float");
|
||||
Self::eat_token(tokenizer);
|
||||
match tokenizer.next_token() {
|
||||
Ok(Token::Key(pos, frac)) => {
|
||||
let mut f = String::new();
|
||||
f.push_str(&mut num);
|
||||
f.push('.');
|
||||
f.push_str(frac.as_str());
|
||||
let number = utils::string_to_num(&f, || tokenizer.err_msg_with_pos(pos))?;
|
||||
Ok(Self::node(ParseToken::Number(number)))
|
||||
}
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
|
||||
fn term(tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#term");
|
||||
|
||||
if tokenizer.peek_is(AT) {
|
||||
Self::eat_token(tokenizer);
|
||||
let node = Self::node(ParseToken::Relative);
|
||||
|
||||
return match tokenizer.peek_token() {
|
||||
Ok(Token::Whitespace(_, _)) => {
|
||||
Self::eat_whitespace(tokenizer);
|
||||
Ok(node)
|
||||
}
|
||||
_ => Self::paths(node, tokenizer),
|
||||
};
|
||||
}
|
||||
|
||||
if tokenizer.peek_is(ABSOLUTE) {
|
||||
return Self::json_path(tokenizer);
|
||||
}
|
||||
|
||||
if tokenizer.peek_is(DOUBLE_QUOTE) || tokenizer.peek_is(SINGLE_QUOTE) {
|
||||
return Self::array_quote_value(tokenizer);
|
||||
}
|
||||
|
||||
if tokenizer.peek_is(KEY) {
|
||||
let key = if let Ok(Token::Key(_, k)) = tokenizer.peek_token() {
|
||||
k.clone()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
return match key.as_bytes()[0] {
|
||||
b'-' | b'0'...b'9' => Self::term_num(tokenizer),
|
||||
_ => Self::boolean(tokenizer),
|
||||
};
|
||||
}
|
||||
|
||||
return Err(tokenizer.err_msg());
|
||||
}
|
||||
|
||||
fn op(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#op");
|
||||
let token = match tokenizer.next_token() {
|
||||
Ok(Token::Equal(_)) => ParseToken::Filter(FilterToken::Equal),
|
||||
Ok(Token::NotEqual(_)) => ParseToken::Filter(FilterToken::NotEqual),
|
||||
Ok(Token::Little(_)) => ParseToken::Filter(FilterToken::Little),
|
||||
Ok(Token::LittleOrEqual(_)) => ParseToken::Filter(FilterToken::LittleOrEqual),
|
||||
Ok(Token::Greater(_)) => ParseToken::Filter(FilterToken::Greater),
|
||||
Ok(Token::GreaterOrEqual(_)) => ParseToken::Filter(FilterToken::GreaterOrEqual),
|
||||
_ => {
|
||||
return Err(tokenizer.err_msg());
|
||||
}
|
||||
};
|
||||
|
||||
Self::eat_whitespace(tokenizer);
|
||||
|
||||
Ok(Node {
|
||||
token,
|
||||
left: Some(Box::new(prev)),
|
||||
right: Some(Box::new(Self::term(tokenizer)?)),
|
||||
})
|
||||
}
|
||||
|
||||
fn eat_whitespace(tokenizer: &mut TokenReader) {
|
||||
while let Ok(Token::Whitespace(_, _)) = tokenizer.peek_token() {
|
||||
let _ = tokenizer.next_token();
|
||||
}
|
||||
}
|
||||
|
||||
fn eat_token(tokenizer: &mut TokenReader) {
|
||||
let _ = tokenizer.next_token();
|
||||
}
|
||||
|
||||
fn node(token: ParseToken) -> Node {
|
||||
Node {
|
||||
left: None,
|
||||
right: None,
|
||||
token,
|
||||
}
|
||||
}
|
||||
|
||||
fn close_token(ret: Node, token: Token, tokenizer: &mut TokenReader) -> ParseResult<Node> {
|
||||
debug!("#close_token");
|
||||
match tokenizer.next_token() {
|
||||
Ok(ref t) if t.partial_eq(token) => Ok(ret),
|
||||
_ => Err(tokenizer.err_msg()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NodeVisitor {
|
||||
fn visit(&mut self, node: &Node) {
|
||||
match &node.token {
|
||||
ParseToken::Absolute
|
||||
| ParseToken::Relative
|
||||
| ParseToken::All
|
||||
| ParseToken::Key(_)
|
||||
| ParseToken::Keys(_)
|
||||
| ParseToken::Range(_, _, _)
|
||||
| ParseToken::Union(_)
|
||||
| ParseToken::Number(_)
|
||||
| ParseToken::Bool(_) => {
|
||||
self.visit_token(&node.token);
|
||||
}
|
||||
ParseToken::In | ParseToken::Leaves => {
|
||||
match &node.left {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.visit_token(&node.token);
|
||||
|
||||
match &node.right {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ParseToken::Array => {
|
||||
match &node.left {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.visit_token(&node.token);
|
||||
|
||||
match &node.right {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
self.visit_token(&ParseToken::ArrayEof);
|
||||
}
|
||||
ParseToken::Filter(FilterToken::And) | ParseToken::Filter(FilterToken::Or) => {
|
||||
match &node.left {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match &node.right {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.visit_token(&node.token);
|
||||
}
|
||||
ParseToken::Filter(_) => {
|
||||
match &node.left {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.end_term();
|
||||
|
||||
match &node.right {
|
||||
Some(n) => self.visit(&*n),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.end_term();
|
||||
|
||||
self.visit_token(&node.token);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_token(&mut self, token: &ParseToken);
|
||||
fn end_term(&mut self) {}
|
||||
}
|
@ -2,29 +2,29 @@ use std::result::Result;
|
||||
|
||||
use super::path_reader::{PathReader, ReaderError};
|
||||
|
||||
pub const ABSOLUTE: &'static str = "$";
|
||||
pub const DOT: &'static str = ".";
|
||||
pub const AT: &'static str = "@";
|
||||
pub const OPEN_ARRAY: &'static str = "[";
|
||||
pub const CLOSE_ARRAY: &'static str = "]";
|
||||
pub const ASTERISK: &'static str = "*";
|
||||
pub const QUESTION: &'static str = "?";
|
||||
pub const COMMA: &'static str = ",";
|
||||
pub const SPLIT: &'static str = ":";
|
||||
pub const OPEN_PARENTHESIS: &'static str = "(";
|
||||
pub const CLOSE_PARENTHESIS: &'static str = ")";
|
||||
pub const KEY: &'static str = "Key";
|
||||
pub const DOUBLE_QUOTE: &'static str = "\"";
|
||||
pub const SINGLE_QUOTE: &'static str = "'";
|
||||
pub const EQUAL: &'static str = "==";
|
||||
pub const GREATER_OR_EQUAL: &'static str = ">=";
|
||||
pub const GREATER: &'static str = ">";
|
||||
pub const LITTLE: &'static str = "<";
|
||||
pub const LITTLE_OR_EQUAL: &'static str = "<=";
|
||||
pub const NOT_EQUAL: &'static str = "!=";
|
||||
pub const AND: &'static str = "&&";
|
||||
pub const OR: &'static str = "||";
|
||||
pub const WHITESPACE: &'static str = " ";
|
||||
pub const ABSOLUTE: &str = "$";
|
||||
pub const DOT: &str = ".";
|
||||
pub const AT: &str = "@";
|
||||
pub const OPEN_ARRAY: &str = "[";
|
||||
pub const CLOSE_ARRAY: &str = "]";
|
||||
pub const ASTERISK: &str = "*";
|
||||
pub const QUESTION: &str = "?";
|
||||
pub const COMMA: &str = ",";
|
||||
pub const SPLIT: &str = ":";
|
||||
pub const OPEN_PARENTHESIS: &str = "(";
|
||||
pub const CLOSE_PARENTHESIS: &str = ")";
|
||||
pub const KEY: &str = "Key";
|
||||
pub const DOUBLE_QUOTE: &str = "\"";
|
||||
pub const SINGLE_QUOTE: &str = "'";
|
||||
pub const EQUAL: &str = "==";
|
||||
pub const GREATER_OR_EQUAL: &str = ">=";
|
||||
pub const GREATER: &str = ">";
|
||||
pub const LITTLE: &str = "<";
|
||||
pub const LITTLE_OR_EQUAL: &str = "<=";
|
||||
pub const NOT_EQUAL: &str = "!=";
|
||||
pub const AND: &str = "&&";
|
||||
pub const OR: &str = "||";
|
||||
pub const WHITESPACE: &str = " ";
|
||||
|
||||
const CH_DOLLA: char = '$';
|
||||
const CH_DOT: char = '.';
|
||||
@ -161,7 +161,7 @@ impl<'a> Tokenizer<'a> {
|
||||
if let Some('\\') = val.chars().last() {
|
||||
self.input.next_char().map_err(to_token_error)?;
|
||||
let _ = val.pop();
|
||||
let (_, mut val_remain) = self
|
||||
let (_, val_remain) = self
|
||||
.input
|
||||
.take_while(|c| *c != ch)
|
||||
.map_err(to_token_error)?;
|
||||
@ -321,7 +321,7 @@ impl<'a> TokenReader<'a> {
|
||||
}
|
||||
Err(e) => {
|
||||
return TokenReader {
|
||||
origin_input: input.clone(),
|
||||
origin_input: input,
|
||||
err: e,
|
||||
err_pos: tokenizer.current_pos(),
|
||||
tokens,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,8 +30,8 @@ pub fn read_contents(path: &str) -> String {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn select_and_then_compare<'a>(path: &str, json: Value, target: Value) {
|
||||
let mut selector = Selector::new();
|
||||
pub fn select_and_then_compare(path: &str, json: Value, target: Value) {
|
||||
let mut selector = Selector::default();
|
||||
let result = selector
|
||||
.str_path(path)
|
||||
.unwrap()
|
||||
@ -50,7 +50,7 @@ pub fn select_and_then_compare<'a>(path: &str, json: Value, target: Value) {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn compare_result<'a>(result: Vec<&Value>, target: Value) {
|
||||
pub fn compare_result(result: Vec<&Value>, target: Value) {
|
||||
let result = serde_json::to_value(result).unwrap();
|
||||
assert_eq!(result, target);
|
||||
}
|
||||
|
@ -624,7 +624,7 @@ fn quote() {
|
||||
fn all_filter() {
|
||||
setup();
|
||||
|
||||
for path in vec![r#"$.*"#, r#"$[*]"#] {
|
||||
for path in &[r#"$.*"#, r#"$[*]"#] {
|
||||
select_and_then_compare(
|
||||
path,
|
||||
json!(["string", 42, { "key": "value" }, [0, 1]]),
|
||||
@ -632,7 +632,7 @@ fn all_filter() {
|
||||
);
|
||||
}
|
||||
|
||||
for path in vec![r#"$..*"#, r#"$..[*]"#] {
|
||||
for path in &[r#"$..*"#, r#"$..[*]"#] {
|
||||
select_and_then_compare(
|
||||
path,
|
||||
json!(["string", 42, { "key": "value" }, [0, 1]]),
|
||||
@ -640,7 +640,7 @@ fn all_filter() {
|
||||
);
|
||||
}
|
||||
|
||||
for path in vec![r#"$.*.*"#, r#"$[*].*"#, r#"$.*[*]"#, r#"$[*][*]"#] {
|
||||
for path in &[r#"$.*.*"#, r#"$[*].*"#, r#"$.*[*]"#, r#"$[*][*]"#] {
|
||||
select_and_then_compare(
|
||||
path,
|
||||
json!(["string", 42, { "key": "value" }, [0, 1]]),
|
||||
@ -648,7 +648,7 @@ fn all_filter() {
|
||||
);
|
||||
}
|
||||
|
||||
for path in vec![r#"$..friends.*"#, r#"$[*].friends.*"#] {
|
||||
for path in &[r#"$..friends.*"#, r#"$[*].friends.*"#] {
|
||||
select_and_then_compare(
|
||||
path,
|
||||
read_json("./benches/data_array.json"),
|
||||
|
@ -37,11 +37,7 @@ fn compile() {
|
||||
|
||||
fn compile_error() {
|
||||
let mut template = jsonpath::compile("$[");
|
||||
if let Err(JsonPathError::Path(_)) = template(&Value::Null) {
|
||||
assert!(true);
|
||||
} else {
|
||||
assert!(false);
|
||||
}
|
||||
assert!(template(&Value::Null).is_err());
|
||||
}
|
||||
|
||||
setup();
|
||||
|
@ -12,7 +12,7 @@ mod common;
|
||||
fn selector_mut() {
|
||||
setup();
|
||||
|
||||
let mut selector_mut = SelectorMut::new();
|
||||
let mut selector_mut = SelectorMut::default();
|
||||
|
||||
let mut nums = Vec::new();
|
||||
let result = selector_mut
|
||||
@ -20,11 +20,8 @@ fn selector_mut() {
|
||||
.unwrap()
|
||||
.value(read_json("./benches/example.json"))
|
||||
.replace_with(&mut |v| {
|
||||
match v {
|
||||
Value::Number(n) => {
|
||||
nums.push(n.as_f64().unwrap());
|
||||
}
|
||||
_ => {}
|
||||
if let Value::Number(n) = v {
|
||||
nums.push(n.as_f64().unwrap());
|
||||
}
|
||||
Value::String("a".to_string())
|
||||
})
|
||||
@ -37,7 +34,7 @@ fn selector_mut() {
|
||||
vec![8.95_f64, 12.99_f64, 8.99_f64, 22.99_f64, 19.95_f64]
|
||||
);
|
||||
|
||||
let mut selector = Selector::new();
|
||||
let mut selector = Selector::default();
|
||||
let result = selector
|
||||
.str_path(r#"$.store..price"#)
|
||||
.unwrap()
|
||||
|
@ -173,7 +173,7 @@ fn readme_selector() {
|
||||
{"name": "친구4"}
|
||||
]});
|
||||
|
||||
let mut selector = Selector::new();
|
||||
let mut selector = Selector::default();
|
||||
|
||||
let result = selector
|
||||
.str_path("$..[?(@.age >= 30)]")
|
||||
@ -211,7 +211,7 @@ fn readme_selector_mut() {
|
||||
{"name": "친구4"}
|
||||
]});
|
||||
|
||||
let mut selector_mut = SelectorMut::new();
|
||||
let mut selector_mut = SelectorMut::default();
|
||||
|
||||
let result = selector_mut
|
||||
.str_path("$..[?(@.age == 20)].age")
|
||||
|
@ -102,7 +102,7 @@ pub fn compile(path: &str) -> JsValue {
|
||||
},
|
||||
Err(e) => JsValue::from_str(&format!("{:?}", e)),
|
||||
}
|
||||
}) as Box<Fn(JsValue) -> JsValue>);
|
||||
}) as Box<dyn Fn(JsValue) -> JsValue>);
|
||||
|
||||
let ret = cb.as_ref().clone();
|
||||
cb.forget();
|
||||
@ -131,8 +131,8 @@ pub fn selector(js_value: JsValue) -> JsValue {
|
||||
Err(e) => JsValue::from_str(&format!("{:?}", e)),
|
||||
}
|
||||
}
|
||||
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e))),
|
||||
}) as Box<Fn(String) -> JsValue>,
|
||||
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Path(e))),
|
||||
}) as Box<dyn Fn(String) -> JsValue>,
|
||||
);
|
||||
|
||||
let ret = cb.as_ref().clone();
|
||||
@ -193,6 +193,7 @@ pub fn replace_with(js_value: JsValue, path: &str, fun: js_sys::Function) -> JsV
|
||||
/// lifetime 제약으로 Selector를 사용 할 수 없다.
|
||||
///
|
||||
#[wasm_bindgen]
|
||||
#[derive(Default)]
|
||||
pub struct Selector {
|
||||
path: Option<String>,
|
||||
value: Option<Value>,
|
||||
@ -202,10 +203,7 @@ pub struct Selector {
|
||||
impl Selector {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
Selector {
|
||||
path: None,
|
||||
value: None,
|
||||
}
|
||||
Selector::default()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(catch)]
|
||||
@ -263,6 +261,7 @@ impl Selector {
|
||||
/// `wasm_bindgen` 제약으로 builder-pattern을 구사 할 수 없다.
|
||||
///
|
||||
#[wasm_bindgen]
|
||||
#[derive(Default)]
|
||||
pub struct SelectorMut {
|
||||
path: Option<String>,
|
||||
value: Option<Value>,
|
||||
@ -272,10 +271,7 @@ pub struct SelectorMut {
|
||||
impl SelectorMut {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
SelectorMut {
|
||||
path: None,
|
||||
value: None,
|
||||
}
|
||||
SelectorMut::default()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(catch)]
|
||||
|
Loading…
x
Reference in New Issue
Block a user