diff --git a/benches/bench_example.rs b/benches/bench_example.rs index 1d00866..dd77bca 100644 --- a/benches/bench_example.rs +++ b/benches/bench_example.rs @@ -1,5 +1,4 @@ #![feature(test)] - extern crate bencher; extern crate jsonpath_lib as jsonpath; extern crate serde; diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 253252f..4c76103 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -76,7 +76,6 @@ pub struct Node { pub struct Parser; impl Parser { - pub fn compile(input: &str) -> ParseResult { let mut tokenizer = TokenReader::new(input); Ok(Self::json_path(&mut tokenizer)?) @@ -531,43 +530,54 @@ impl Parser { } } + fn peek_key(tokenizer: &mut TokenReader) -> Option { + if let Ok(Token::Key(_, k)) = tokenizer.peek_token() { + Some(k.clone()) + } else { + None + } + } + fn term(tokenizer: &mut TokenReader) -> ParseResult { debug!("#term"); - match tokenizer.peek_token() { - Ok(Token::At(_)) => { - Self::eat_token(tokenizer); - let node = Self::node(ParseToken::Relative); - match tokenizer.peek_token() { - Ok(Token::Whitespace(_, _)) => { - Self::eat_whitespace(tokenizer); - Ok(node) - } - _ => { - Self::paths(node, tokenizer) - } + 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) } - } - Ok(Token::Absolute(_)) => { - Self::json_path(tokenizer) - } - Ok(Token::DoubleQuoted(_, _)) - | Ok(Token::SingleQuoted(_, _)) => { - Self::array_quota_value(tokenizer) - } - Ok(Token::Key(_, k)) => { - match k.chars().next() { + _ => { + Self::paths(node, tokenizer) + } + }; + } + + if tokenizer.peek_is(ABSOLUTE) { + return Self::json_path(tokenizer); + } + + if tokenizer.peek_is(DOUBLE_QUOTA) || tokenizer.peek_is(SINGLE_QUOTA) { + return Self::array_quota_value(tokenizer); + } + + if tokenizer.peek_is(KEY) { + return match Self::peek_key(tokenizer) { + Some(key) => match key.chars().next() { Some(ch) => match ch { '-' | '0'...'9' => Self::term_num(tokenizer), _ => Self::boolean(tokenizer) } _ => Err(tokenizer.err_msg()) - } - } - _ => { - Err(tokenizer.err_msg()) - } + }, + _ => Err(tokenizer.err_msg()) + }; } + + return Err(tokenizer.err_msg()); } fn op(prev: Node, tokenizer: &mut TokenReader) -> ParseResult { diff --git a/src/parser/tokenizer.rs b/src/parser/tokenizer.rs index 4a777f2..23a3ac7 100644 --- a/src/parser/tokenizer.rs +++ b/src/parser/tokenizer.rs @@ -3,29 +3,29 @@ use std::result::Result; use super::path_reader::{PathReader, ReaderError}; -const ABSOLUTE: &'static str = "$"; -const DOT: &'static str = "."; -const AT: &'static str = "@"; -const OPEN_ARRAY: &'static str = "["; -const CLOSE_ARRAY: &'static str = "]"; -const ASTERISK: &'static str = "*"; -const QUESTION: &'static str = "?"; -const COMMA: &'static str = ","; -const SPLIT: &'static str = ":"; -const OPEN_PARENTHESIS: &'static str = "("; -const CLOSE_PARENTHESIS: &'static str = ")"; -const KEY: &'static str = "Key"; -const DOUBLE_QUOTA: &'static str = "\""; -const SINGLE_QUOTA: &'static str = "'"; -const EQUAL: &'static str = "=="; -const GREATER_OR_EQUAL: &'static str = ">="; -const GREATER: &'static str = ">"; -const LITTLE: &'static str = "<"; -const LITTLE_OR_EQUAL: &'static str = "<="; -const NOT_EQUAL: &'static str = "!="; -const AND: &'static str = "&&"; -const OR: &'static str = "||"; -const WHITESPACE: &'static str = " "; +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_QUOTA: &'static str = "\""; +pub const SINGLE_QUOTA: &'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 = " "; const CH_DOLLA: char = '$'; const CH_DOT: char = '.'; @@ -91,6 +91,10 @@ impl Token { self.to_simple() == other.to_simple() } + pub fn simple_eq(&self, str_token: &str) -> bool { + self.to_simple() == str_token + } + fn to_simple(&self) -> &'static str { match self { Token::Absolute(_) => ABSOLUTE, @@ -305,6 +309,13 @@ impl<'a> TokenReader<'a> { } } + pub fn peek_is(&self, simple_token: &str) -> bool { + match self.peek_token() { + Ok(t) => t.simple_eq(simple_token), + _ => false + } + } + pub fn peek_token(&self) -> Result<&Token, TokenError> { match self.tokens.last() { Some((_, t)) => { diff --git a/src/select/mod.rs b/src/select/mod.rs index ab4ec93..f2b19ea 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1004,6 +1004,49 @@ pub struct SelectorMut { value: Option, } +fn replace_value Value>(tokens: Vec, value: &mut Value, fun: &mut F) { + let mut target = value; + + for (i, token) in tokens.iter().enumerate() { + let target_once = target; + let is_last = i == tokens.len() - 1; + let target_opt = match *target_once { + Value::Object(ref mut map) => { + if is_last { + let v = if let Some(v) = map.get(token) { + fun(v) + } else { + return; + }; + + map.insert(token.clone(), v); + return; + } + map.get_mut(token) + } + Value::Array(ref mut vec) => { + if let Ok(x) = token.parse::() { + if is_last { + let v = { fun(&vec[x]) }; + vec[x] = v; + return; + } + vec.get_mut(x) + } else { + None + } + } + _ => None, + }; + + if let Some(t) = target_opt { + target = t; + } else { + break; + } + } +} + impl SelectorMut { pub fn new() -> Self { SelectorMut { path: None, value: None } @@ -1014,11 +1057,6 @@ impl SelectorMut { Ok(self) } - pub fn compiled_path(&mut self, node: Node) -> &mut Self { - self.path = Some(node); - self - } - pub fn value(&mut self, value: Value) -> &mut Self { self.value = Some(value); self @@ -1080,76 +1118,33 @@ impl SelectorMut { self.replace_with(&mut |_| Value::Null) } - pub fn replace_with Value>(&mut self, fun: &mut F) -> Result<&mut Self, JsonPathError> { - if self.path.is_none() { - return Err(JsonPathError::EmptyPath); - } + fn select(&self) -> Result, JsonPathError> { + if let Some(node) = &self.path { + let mut selector = Selector::new(); + selector.compiled_path(&node); - let node = self.path.take().unwrap(); - - let mut selector = Selector::new(); - selector.compiled_path(&node); - - if let Some(value) = &self.value { - selector.value(value); - } - - let result = selector.select(); - - self.path = Some(node); - - let paths = self.compute_paths(result?); - - if let Some(mut value) = self.value.take() { - for tokens in paths { - self.replace_value(tokens, &mut value, fun); + if let Some(value) = &self.value { + selector.value(value); + } + + Ok(selector.select()?) + } else { + Err(JsonPathError::EmptyPath) + } + } + + pub fn replace_with Value>(&mut self, fun: &mut F) -> Result<&mut Self, JsonPathError> { + let paths = { + let result = self.select()?; + self.compute_paths(result) + }; + + if let Some(ref mut value) = &mut self.value { + for tokens in paths { + replace_value(tokens, value, fun); } - self.value = Some(value); } Ok(self) } - - fn replace_value Value>(&mut self, tokens: Vec, value: &mut Value, fun: &mut F) { - let mut target = value; - - for (i, token) in tokens.iter().enumerate() { - let target_once = target; - let is_last = i == tokens.len() - 1; - let target_opt = match *target_once { - Value::Object(ref mut map) => { - if is_last { - let v = if let Some(v) = map.get(token) { - fun(v) - } else { - return; - }; - - map.insert(token.clone(), v); - return; - } - map.get_mut(token) - } - Value::Array(ref mut vec) => { - if let Ok(x) = token.parse::() { - if is_last { - let v = &vec[x]; - vec[x] = fun(v); - return; - } - vec.get_mut(x) - } else { - None - } - } - _ => None, - }; - - if let Some(t) = target_opt { - target = t; - } else { - break; - } - } - } } \ No newline at end of file diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index f21c7ea..25abf1c 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -86,15 +86,18 @@ pub fn compile(path: &str) -> JsValue { let node = Parser::compile(path); let cb = Closure::wrap(Box::new(move |js_value: JsValue| { - let mut selector = _Selector::new(); - match &node { - Ok(node) => selector.compiled_path(node), - Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone()))) - }; let json = match into_serde_json(&js_value) { Ok(json) => json, Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))) }; + + let mut selector = _Selector::new(); + + match &node { + Ok(node) => selector.compiled_path(node), + Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone()))) + }; + match selector.value(&json).select() { Ok(ret) => match JsValue::from_serde(&ret) { Ok(ret) => ret,