summaryrefslogtreecommitdiffstats
path: root/vendor/jsonpath_lib/src/parser/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/jsonpath_lib/src/parser/mod.rs')
-rw-r--r--vendor/jsonpath_lib/src/parser/mod.rs1503
1 files changed, 1503 insertions, 0 deletions
diff --git a/vendor/jsonpath_lib/src/parser/mod.rs b/vendor/jsonpath_lib/src/parser/mod.rs
new file mode 100644
index 000000000..91cd8960b
--- /dev/null
+++ b/vendor/jsonpath_lib/src/parser/mod.rs
@@ -0,0 +1,1503 @@
+mod path_reader;
+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");
+
+ fn validation_bool_value(v: &str) -> bool {
+ let b = v.as_bytes();
+ !b.is_empty() && (b[0] == b't' || b[0] == b'T' || b[0] == b'f' || b[0] == b'F')
+ }
+
+ match tokenizer.next_token() {
+ Ok(Token::Key(_, ref v)) if validation_bool_value(v) => {
+ 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 let Ok(Token::Comma(_)) = tokenizer.peek_token() {
+ 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 let Ok(Token::Comma(_)) = tokenizer.peek_token() {
+ Self::array_keys(tokenizer, val)
+ } else {
+ Ok(Self::node(ParseToken::Key(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 matches!(tokenizer.peek_token(), Ok(Token::Comma(_))) {
+ 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 = matches!(tokenizer.peek_token(), Ok(Token::At(_)));
+
+ let node = Self::term(tokenizer)?;
+ Self::eat_whitespace(tokenizer);
+
+ if matches!(tokenizer.peek_token(),
+ Ok(Token::Equal(_))
+ | Ok(Token::NotEqual(_))
+ | Ok(Token::Little(_))
+ | Ok(Token::LittleOrEqual(_))
+ | Ok(Token::Greater(_))
+ | Ok(Token::GreaterOrEqual(_)))
+ {
+ 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");
+
+ 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),
+ }
+ }
+ Ok(Token::Absolute(_)) => {
+ Self::json_path(tokenizer)
+ }
+ Ok(Token::DoubleQuoted(_, _)) | Ok(Token::SingleQuoted(_, _)) => {
+ Self::array_quote_value(tokenizer)
+ }
+ Ok(Token::Key(_, key)) => {
+ 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.is_match_token_type(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::{FilterToken, NodeVisitor, ParseToken, Parser};
+
+ struct NodeVisitorTestImpl<'a> {
+ input: &'a str,
+ stack: Vec<ParseToken>,
+ }
+
+ impl<'a> NodeVisitorTestImpl<'a> {
+ fn new(input: &'a str) -> Self {
+ NodeVisitorTestImpl {
+ input,
+ stack: Vec::new(),
+ }
+ }
+
+ fn start(&mut self) -> Result<Vec<ParseToken>, String> {
+ let node = Parser::compile(self.input)?;
+ self.visit(&node);
+ Ok(self.stack.split_off(0))
+ }
+ }
+
+ impl<'a> NodeVisitor for NodeVisitorTestImpl<'a> {
+ fn visit_token(&mut self, token: &ParseToken) {
+ self.stack.push(token.clone());
+ }
+ }
+
+ fn setup() {
+ let _ = env_logger::try_init();
+ }
+
+ fn run(input: &str) -> Result<Vec<ParseToken>, String> {
+ let mut interpreter = NodeVisitorTestImpl::new(input);
+ interpreter.start()
+ }
+
+ #[test]
+ fn parse_error() {
+ setup();
+
+ fn invalid(path: &str) {
+ assert!(run(path).is_err());
+ }
+
+ invalid("$[]");
+ invalid("$[a]");
+ invalid("$[?($.a)]");
+ invalid("$[?(@.a > @.b]");
+ invalid("$[?(@.a < @.b&&(@.c < @.d)]");
+ invalid("@.");
+ invalid("$..[?(a <= @.a)]"); // invalid term value
+ invalid("$['a', b]");
+ invalid("$[0, >=]");
+ invalid("$[a:]");
+ invalid("$[:a]");
+ invalid("$[::a]");
+ invalid("$[:>]");
+ invalid("$[1:>]");
+ invalid("$[1,,]");
+ invalid("$[?]");
+ invalid("$[?(1 = 1)]");
+ invalid("$[?(1 = >)]");
+ }
+
+ #[test]
+ fn parse_path() {
+ setup();
+
+ assert_eq!(
+ run("$.aa"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("aa".to_owned())
+ ])
+ );
+
+ assert_eq!(
+ run("$.00.a"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("00".to_owned()),
+ ParseToken::In,
+ ParseToken::Key("a".to_owned())
+ ])
+ );
+
+ assert_eq!(
+ run("$.00.韓창.seok"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("00".to_owned()),
+ ParseToken::In,
+ ParseToken::Key("韓창".to_owned()),
+ ParseToken::In,
+ ParseToken::Key("seok".to_owned())
+ ])
+ );
+
+ assert_eq!(
+ run("$.*"),
+ Ok(vec![ParseToken::Absolute, ParseToken::In, ParseToken::All])
+ );
+
+ assert_eq!(
+ run("$..*"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Leaves,
+ ParseToken::All
+ ])
+ );
+
+ assert_eq!(
+ run("$..[0]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Leaves,
+ ParseToken::Array,
+ ParseToken::Number(0.0),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$.$a"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("$a".to_owned())
+ ])
+ );
+
+ assert_eq!(
+ run("$.['$a']"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Key("$a".to_owned()),
+ ParseToken::ArrayEof,
+ ])
+ );
+
+ if run("$.").is_ok() {
+ panic!();
+ }
+
+ if run("$..").is_ok() {
+ panic!();
+ }
+
+ if run("$. a").is_ok() {
+ panic!();
+ }
+ }
+
+ #[test]
+ fn parse_array_syntax() {
+ setup();
+
+ assert_eq!(
+ run("$.book[?(@.isbn)]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("book".to_string()),
+ ParseToken::Array,
+ ParseToken::Relative,
+ ParseToken::In,
+ ParseToken::Key("isbn".to_string()),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ //
+ // Array도 컨텍스트 In으로 간주 할거라서 중첩되면 하나만
+ //
+ assert_eq!(
+ run("$.[*]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::All,
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$.a[*]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("a".to_owned()),
+ ParseToken::Array,
+ ParseToken::All,
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$.a[*].가"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("a".to_owned()),
+ ParseToken::Array,
+ ParseToken::All,
+ ParseToken::ArrayEof,
+ ParseToken::In,
+ ParseToken::Key("가".to_owned())
+ ])
+ );
+
+ assert_eq!(
+ run("$.a[0][1]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("a".to_owned()),
+ ParseToken::Array,
+ ParseToken::Number(0_f64),
+ ParseToken::ArrayEof,
+ ParseToken::Array,
+ ParseToken::Number(1_f64),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$.a[1,2]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("a".to_owned()),
+ ParseToken::Array,
+ ParseToken::Union(vec![1, 2]),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$.a[10:]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("a".to_owned()),
+ ParseToken::Array,
+ ParseToken::Range(Some(10), None, None),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$.a[:11]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("a".to_owned()),
+ ParseToken::Array,
+ ParseToken::Range(None, Some(11), None),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$.a[-12:13]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("a".to_owned()),
+ ParseToken::Array,
+ ParseToken::Range(Some(-12), Some(13), None),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run(r#"$[0:3:2]"#),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Range(Some(0), Some(3), Some(2)),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run(r#"$[:3:2]"#),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Range(None, Some(3), Some(2)),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run(r#"$[:]"#),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Range(None, None, None),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run(r#"$[::]"#),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Range(None, None, None),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run(r#"$[::2]"#),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Range(None, None, Some(2)),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run(r#"$["a", 'b']"#),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Keys(vec!["a".to_string(), "b".to_string()]),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$.a[?(1>2)]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("a".to_owned()),
+ ParseToken::Array,
+ ParseToken::Number(1_f64),
+ ParseToken::Number(2_f64),
+ ParseToken::Filter(FilterToken::Greater),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$.a[?($.b>3)]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("a".to_owned()),
+ ParseToken::Array,
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("b".to_owned()),
+ ParseToken::Number(3_f64),
+ ParseToken::Filter(FilterToken::Greater),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$[?($.c>@.d && 1==2)]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("c".to_owned()),
+ ParseToken::Relative,
+ ParseToken::In,
+ ParseToken::Key("d".to_owned()),
+ ParseToken::Filter(FilterToken::Greater),
+ ParseToken::Number(1_f64),
+ ParseToken::Number(2_f64),
+ ParseToken::Filter(FilterToken::Equal),
+ ParseToken::Filter(FilterToken::And),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$[?($.c>@.d&&(1==2||3>=4))]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("c".to_owned()),
+ ParseToken::Relative,
+ ParseToken::In,
+ ParseToken::Key("d".to_owned()),
+ ParseToken::Filter(FilterToken::Greater),
+ ParseToken::Number(1_f64),
+ ParseToken::Number(2_f64),
+ ParseToken::Filter(FilterToken::Equal),
+ ParseToken::Number(3_f64),
+ ParseToken::Number(4_f64),
+ ParseToken::Filter(FilterToken::GreaterOrEqual),
+ ParseToken::Filter(FilterToken::Or),
+ ParseToken::Filter(FilterToken::And),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$[?(@.a<@.b)]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Relative,
+ ParseToken::In,
+ ParseToken::Key("a".to_owned()),
+ ParseToken::Relative,
+ ParseToken::In,
+ ParseToken::Key("b".to_owned()),
+ ParseToken::Filter(FilterToken::Little),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$[*][*][*]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::All,
+ ParseToken::ArrayEof,
+ ParseToken::Array,
+ ParseToken::All,
+ ParseToken::ArrayEof,
+ ParseToken::Array,
+ ParseToken::All,
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$['a']['bb']"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Key("a".to_string()),
+ ParseToken::ArrayEof,
+ ParseToken::Array,
+ ParseToken::Key("bb".to_string()),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$.a[?(@.e==true)]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::In,
+ ParseToken::Key("a".to_string()),
+ ParseToken::Array,
+ ParseToken::Relative,
+ ParseToken::In,
+ ParseToken::Key("e".to_string()),
+ ParseToken::Bool(true),
+ ParseToken::Filter(FilterToken::Equal),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run(r#"$[?(@ > 1)]"#),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Relative,
+ ParseToken::Number(1_f64),
+ ParseToken::Filter(FilterToken::Greater),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run("$[:]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Range(None, None, None),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run(r#"$['single\'quote']"#),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Key("single'quote".to_string()),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ assert_eq!(
+ run(r#"$["single\"quote"]"#),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Key(r#"single"quote"#.to_string()),
+ ParseToken::ArrayEof
+ ])
+ );
+ }
+
+ #[test]
+ fn parse_array_float() {
+ setup();
+
+ assert_eq!(
+ run("$[?(1.1<2.1)]"),
+ Ok(vec![
+ ParseToken::Absolute,
+ ParseToken::Array,
+ ParseToken::Number(1.1),
+ ParseToken::Number(2.1),
+ ParseToken::Filter(FilterToken::Little),
+ ParseToken::ArrayEof
+ ])
+ );
+
+ if run("$[1.1]").is_ok() {
+ panic!();
+ }
+
+ if run("$[?(1.1<.2)]").is_ok() {
+ panic!();
+ }
+
+ if run("$[?(1.1<2.)]").is_ok() {
+ panic!();
+ }
+
+ if run("$[?(1.1<2.a)]").is_ok() {
+ panic!();
+ }
+ }
+}
+
+#[cfg(test)]
+mod tokenizer_tests {
+ use parser::tokenizer::{Token, TokenError, TokenReader, Tokenizer};
+
+ fn setup() {
+ let _ = env_logger::try_init();
+ }
+
+ fn collect_token(input: &str) -> (Vec<Token>, Option<TokenError>) {
+ let mut tokenizer = Tokenizer::new(input);
+ let mut vec = vec![];
+ loop {
+ match tokenizer.next_token() {
+ Ok(t) => vec.push(t),
+ Err(e) => return (vec, Some(e)),
+ }
+ }
+ }
+
+ fn run(input: &str, expected: (Vec<Token>, Option<TokenError>)) {
+ let (vec, err) = collect_token(input);
+ assert_eq!((vec, err), expected, "\"{}\"", input);
+ }
+
+ #[test]
+ fn peek() {
+ let mut tokenizer = TokenReader::new("$.a");
+ match tokenizer.next_token() {
+ Ok(t) => assert_eq!(Token::Absolute(0), t),
+ _ => panic!(),
+ }
+
+ match tokenizer.peek_token() {
+ Ok(t) => assert_eq!(&Token::Dot(1), t),
+ _ => panic!(),
+ }
+
+ match tokenizer.peek_token() {
+ Ok(t) => assert_eq!(&Token::Dot(1), t),
+ _ => panic!(),
+ }
+
+ match tokenizer.next_token() {
+ Ok(t) => assert_eq!(Token::Dot(1), t),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn token() {
+ setup();
+
+ run(
+ "$.01.a",
+ (
+ vec![
+ Token::Absolute(0),
+ Token::Dot(1),
+ Token::Key(2, "01".to_string()),
+ Token::Dot(4),
+ Token::Key(5, "a".to_string()),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ "$. []",
+ (
+ vec![
+ Token::Absolute(0),
+ Token::Dot(1),
+ Token::Whitespace(2, 2),
+ Token::OpenArray(5),
+ Token::CloseArray(6),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ "$..",
+ (
+ vec![Token::Absolute(0), Token::Dot(1), Token::Dot(2)],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ "$..ab",
+ (
+ vec![
+ Token::Absolute(0),
+ Token::Dot(1),
+ Token::Dot(2),
+ Token::Key(3, "ab".to_string()),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ "$..가 [",
+ (
+ vec![
+ Token::Absolute(0),
+ Token::Dot(1),
+ Token::Dot(2),
+ Token::Key(3, "가".to_string()),
+ Token::Whitespace(6, 0),
+ Token::OpenArray(7),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ "[-1, 2 ]",
+ (
+ vec![
+ Token::OpenArray(0),
+ Token::Key(1, "-1".to_string()),
+ Token::Comma(3),
+ Token::Whitespace(4, 0),
+ Token::Key(5, "2".to_string()),
+ Token::Whitespace(6, 0),
+ Token::CloseArray(7),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ "[ 1 2 , 3 \"abc\" : -10 ]",
+ (
+ vec![
+ Token::OpenArray(0),
+ Token::Whitespace(1, 0),
+ Token::Key(2, "1".to_string()),
+ Token::Whitespace(3, 0),
+ Token::Key(4, "2".to_string()),
+ Token::Whitespace(5, 0),
+ Token::Comma(6),
+ Token::Whitespace(7, 0),
+ Token::Key(8, "3".to_string()),
+ Token::Whitespace(9, 0),
+ Token::DoubleQuoted(10, "abc".to_string()),
+ Token::Whitespace(15, 0),
+ Token::Split(16),
+ Token::Whitespace(17, 0),
+ Token::Key(18, "-10".to_string()),
+ Token::Whitespace(21, 0),
+ Token::CloseArray(22),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ "?(@.a가 <41.01)",
+ (
+ vec![
+ Token::Question(0),
+ Token::OpenParenthesis(1),
+ Token::At(2),
+ Token::Dot(3),
+ Token::Key(4, "a가".to_string()),
+ Token::Whitespace(8, 0),
+ Token::Little(9),
+ Token::Key(10, "41".to_string()),
+ Token::Dot(12),
+ Token::Key(13, "01".to_string()),
+ Token::CloseParenthesis(15),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ "?(@.a <4a.01)",
+ (
+ vec![
+ Token::Question(0),
+ Token::OpenParenthesis(1),
+ Token::At(2),
+ Token::Dot(3),
+ Token::Key(4, "a".to_string()),
+ Token::Whitespace(5, 0),
+ Token::Little(6),
+ Token::Key(7, "4a".to_string()),
+ Token::Dot(9),
+ Token::Key(10, "01".to_string()),
+ Token::CloseParenthesis(12),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ "?($.c>@.d)",
+ (
+ vec![
+ Token::Question(0),
+ Token::OpenParenthesis(1),
+ Token::Absolute(2),
+ Token::Dot(3),
+ Token::Key(4, "c".to_string()),
+ Token::Greater(5),
+ Token::At(6),
+ Token::Dot(7),
+ Token::Key(8, "d".to_string()),
+ Token::CloseParenthesis(9),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ "$[:]",
+ (
+ vec![
+ Token::Absolute(0),
+ Token::OpenArray(1),
+ Token::Split(2),
+ Token::CloseArray(3),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ r#"$['single\'quote']"#,
+ (
+ vec![
+ Token::Absolute(0),
+ Token::OpenArray(1),
+ Token::SingleQuoted(2, "single\'quote".to_string()),
+ Token::CloseArray(17),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ r#"$['single\'1','single\'2']"#,
+ (
+ vec![
+ Token::Absolute(0),
+ Token::OpenArray(1),
+ Token::SingleQuoted(2, "single\'1".to_string()),
+ Token::Comma(13),
+ Token::SingleQuoted(14, "single\'2".to_string()),
+ Token::CloseArray(25),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+
+ run(
+ r#"$["double\"quote"]"#,
+ (
+ vec![
+ Token::Absolute(0),
+ Token::OpenArray(1),
+ Token::DoubleQuoted(2, "double\"quote".to_string()),
+ Token::CloseArray(17),
+ ],
+ Some(TokenError::Eof),
+ ),
+ );
+ }
+}