필터 && ||

This commit is contained in:
freestrings 2018-12-26 22:45:54 +09:00
parent fbc9c0ce04
commit e7f87a8ad5
2 changed files with 103 additions and 16 deletions

View File

@ -1,5 +1,7 @@
use std::result; use std::result;
use super::path_reader::Error;
use super::tokenizer::{ use super::tokenizer::{
self, self,
Token, Token,
@ -83,6 +85,8 @@ enum FilterContext {
NumValue(isize), NumValue(isize),
StrValue(String), StrValue(String),
Op(FilterOp), Op(FilterOp),
And,
Or,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -289,13 +293,38 @@ fn parse_close_paren(stack: &mut Vec<Context>) -> Result<()> {
fn parse_filter(stack: &mut Vec<Context>, local_stack: &mut Vec<FilterContext>) -> Result<()> { fn parse_filter(stack: &mut Vec<Context>, local_stack: &mut Vec<FilterContext>) -> Result<()> {
stack.pop(); // Token::Question stack.pop(); // Token::Question
stack.push(Context::FilterGroup(vec![Filter::And(
parse_filter_value(local_stack.pop())?,
parse_filter_op(local_stack.pop())?,
parse_filter_value(local_stack.pop())?,
)]));
Ok(()) let mut filters: Vec<Filter> = Vec::new();
loop {
if let Some(v) = local_stack.pop() {
filters.push(match v {
FilterContext::And => {
Filter::And(parse_filter_value(local_stack.pop())?,
parse_filter_op(local_stack.pop())?,
parse_filter_value(local_stack.pop())?)
}
FilterContext::Or => {
Filter::Or(parse_filter_value(local_stack.pop())?,
parse_filter_op(local_stack.pop())?,
parse_filter_value(local_stack.pop())?)
}
_ => {
Filter::And(parse_filter_value(Some(v))?,
parse_filter_op(local_stack.pop())?,
parse_filter_value(local_stack.pop())?)
}
});
} else {
break;
}
}
if filters.is_empty() {
Err("parse_filter: invalid syntax.".to_owned())
} else {
stack.push(Context::FilterGroup(filters));
Ok(())
}
} }
fn parse_path(stack: &mut Vec<Context>, local_stack: &mut Vec<FilterContext>, value: String) -> Result<()> { fn parse_path(stack: &mut Vec<Context>, local_stack: &mut Vec<FilterContext>, value: String) -> Result<()> {
@ -328,7 +357,7 @@ fn parse_close_paren(stack: &mut Vec<Context>) -> Result<()> {
let mut local_stack: Vec<FilterContext> = Vec::new(); let mut local_stack: Vec<FilterContext> = Vec::new();
while let Some(ctx) = stack.pop() { while let Some(ctx) = stack.pop() {
info!("\t{:?}", ctx); info!("\t - {:?}", ctx);
match ctx { match ctx {
Context::Token(Token::OpenParenthesis(_)) Context::Token(Token::OpenParenthesis(_))
@ -348,18 +377,25 @@ fn parse_close_paren(stack: &mut Vec<Context>) -> Result<()> {
/**/if is_match(stack.last(), |c| c.alias_of(RELATIVE) || c.alias_of(RELATIVES)) => { /**/if is_match(stack.last(), |c| c.alias_of(RELATIVE) || c.alias_of(RELATIVES)) => {
parse_path(stack, &mut local_stack, utils::vec_to_string(vec))?; parse_path(stack, &mut local_stack, utils::vec_to_string(vec))?;
} }
Context::Key(ref value) Context::Key(ref value)
/**/if is_match(stack.last(), |c| c.alias_of(RELATIVE) || c.alias_of(RELATIVES)) => { /**/if is_match(stack.last(), |c| c.alias_of(RELATIVE) || c.alias_of(RELATIVES)) => {
parse_path(stack, &mut local_stack, value.clone())?; parse_path(stack, &mut local_stack, value.clone())?;
} }
Context::Token(Token::Key(_, ref vec)) => local_stack.push(FilterContext::NumValue(utils::vec_to_number(&vec)?)), Context::Token(Token::Key(_, ref vec)) => local_stack.push(FilterContext::NumValue(utils::vec_to_number(&vec)?)),
Context::Token(Token::And(_)) => local_stack.push(FilterContext::And),
Context::Token(Token::Or(_)) => local_stack.push(FilterContext::Or),
Context::Token(Token::Equal(_)) => local_stack.push(FilterContext::Op(FilterOp::Equal)), Context::Token(Token::Equal(_)) => local_stack.push(FilterContext::Op(FilterOp::Equal)),
Context::Token(Token::NotEqual(_)) => local_stack.push(FilterContext::Op(FilterOp::NotEqual)), Context::Token(Token::NotEqual(_)) => local_stack.push(FilterContext::Op(FilterOp::NotEqual)),
Context::Token(Token::Little(_)) => local_stack.push(FilterContext::Op(FilterOp::Little)), Context::Token(Token::Little(_)) => local_stack.push(FilterContext::Op(FilterOp::Little)),
Context::Token(Token::LittleOrEqual(_)) => local_stack.push(FilterContext::Op(FilterOp::LittleOrEqual)), Context::Token(Token::LittleOrEqual(_)) => local_stack.push(FilterContext::Op(FilterOp::LittleOrEqual)),
Context::Token(Token::Greater(_)) => local_stack.push(FilterContext::Op(FilterOp::Grater)), Context::Token(Token::Greater(_)) => local_stack.push(FilterContext::Op(FilterOp::Grater)),
Context::Token(Token::GreaterOrEqual(_)) => local_stack.push(FilterContext::Op(FilterOp::GraterOrEqual)), Context::Token(Token::GreaterOrEqual(_)) => local_stack.push(FilterContext::Op(FilterOp::GraterOrEqual)),
_ => {}
_ => unreachable!("{:?} %{:?}", ctx, stack)
} }
} }
@ -398,27 +434,34 @@ impl<'a> Parser<'a> {
match token { match token {
Token::Absolute(_) => self.stack.push(Context::Absolute), Token::Absolute(_) => self.stack.push(Context::Absolute),
Token::Relative(_) Token::Relative(_)
/**/if is_match(self.stack.last(), |c| c.alias_of(RELATIVE)) => { /**/if is_match(self.stack.last(), |c| c.alias_of(RELATIVE)) => {
self.stack.pop(); self.stack.pop();
self.stack.push(Context::Relatives) self.stack.push(Context::Relatives)
} }
Token::Relative(_) => self.stack.push(Context::Relative), Token::Relative(_) => self.stack.push(Context::Relative),
Token::Asterisk(_) Token::Asterisk(_)
/**/if is_match(self.stack.last(), |c| c.alias_of(RELATIVE)) => { /**/if is_match(self.stack.last(), |c| c.alias_of(RELATIVE)) => {
self.stack.pop(); self.stack.pop();
self.stack.push(Context::RelativeValues); self.stack.push(Context::RelativeValues);
} }
Token::Asterisk(_) Token::Asterisk(_)
/**/if is_match(self.stack.last(), |c| c.alias_of(RELATIVES)) => { /**/if is_match(self.stack.last(), |c| c.alias_of(RELATIVES)) => {
self.stack.pop(); self.stack.pop();
self.stack.push(Context::AllValues); self.stack.push(Context::AllValues);
} }
Token::Asterisk(_) => self.stack.push(Context::Token(token)), Token::Asterisk(_) => self.stack.push(Context::Token(token)),
Token::OpenArray(_) Token::OpenArray(_)
/**/ if is_token_match(self.stack.last(), |t| t.alias_of(tokenizer::KEY)) => { /**/ if is_token_match(self.stack.last(), |t| t.alias_of(tokenizer::KEY)) => {
parse_path_key(&mut self.stack, token)? parse_path_key(&mut self.stack, token)?
} }
Token::OpenArray(_) Token::OpenArray(_)
| Token::OpenParenthesis(_) | Token::OpenParenthesis(_)
| Token::Question(_) | Token::Question(_)
@ -428,19 +471,27 @@ impl<'a> Parser<'a> {
| Token::Key(_, _) | Token::Key(_, _)
| Token::DoubleQuoted(_, _) | Token::DoubleQuoted(_, _)
| Token::SingleQuoted(_, _) | Token::SingleQuoted(_, _)
| Token::And(_)
| Token::Or(_)
| Token::Little(_) | Token::Little(_)
| Token::LittleOrEqual(_) | Token::LittleOrEqual(_)
| Token::Greater(_) | Token::Greater(_)
| Token::GreaterOrEqual(_) | Token::GreaterOrEqual(_)
| Token::Equal(_) | Token::Equal(_)
| Token::NotEqual(_) => self.stack.push(Context::Token(token)), | Token::NotEqual(_) => self.stack.push(Context::Token(token)),
Token::CloseParenthesis(_) => parse_close_paren(&mut self.stack)?, Token::CloseParenthesis(_) => parse_close_paren(&mut self.stack)?,
Token::CloseArray(_) => parse_close_array(&mut self.stack)?, Token::CloseArray(_) => parse_close_array(&mut self.stack)?,
_ => unreachable!()
_ => {}
} }
} }
Ok(self.stack.to_vec()) match iter.get_error() {
Some(Error::Position(p)) => Err(format!("Parse error. position:'{}'", p)),
_ => Ok(self.stack.to_vec())
}
} }
@ -474,10 +525,10 @@ impl<'a> Parser<'a> {
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
extern crate env_logger; extern crate env_logger;
use super::*; use super::*;
fn run(input: &str, expected: Vec<Context>, err: Option<String>) { fn run(input: &str, expected: Vec<Context>, err: Option<String>) {
@ -493,7 +544,7 @@ mod tests {
} }
#[test] #[test]
fn parse() { fn filter() {
env_logger::init(); env_logger::init();
run("$..book[?(@.price<10)]", vec![ run("$..book[?(@.price<10)]", vec![
@ -510,5 +561,41 @@ mod tests {
), ),
]) ])
], None); ], None);
run("$..book[?(@.price<)]",
vec![],
Some(format!("Parse error. position:'{}'", 17)));
run("$..book[?(@.price<10 && @.name == \"\" || @.total > 100 )]", vec![
Context::Absolute,
Context::Relatives,
Context::Key("book".to_owned()),
Context::FilterGroup(vec![
Filter::And(
FilterValue::Path(vec![
FilterPath::Relative,
FilterPath::Key("price".to_owned()),
]),
FilterOp::Little,
FilterValue::NumValue(10),
),
Filter::And(
FilterValue::Path(vec![
FilterPath::Relative,
FilterPath::Key("name".to_owned()),
]),
FilterOp::Equal,
FilterValue::StrValue("".to_owned()),
),
Filter::Or(
FilterValue::Path(vec![
FilterPath::Relative,
FilterPath::Key("total".to_owned()),
]),
FilterOp::Grater,
FilterValue::NumValue(100),
),
])
], None);
} }
} }

View File

@ -193,8 +193,8 @@ impl<'a> Tokenizer<'a> {
Ok(Token::GreaterOrEqual(pos)) Ok(Token::GreaterOrEqual(pos))
} }
_ if ch.is_whitespace() _ if ch.is_whitespace()
|| ch == '\'' || ch == CH_SINGLE_QUOTA
|| ch == '"' || ch == CH_DOUBLE_QUOTA
|| ch.is_numeric() || ch.is_numeric()
=> Ok(Token::Greater(pos)), => Ok(Token::Greater(pos)),
_ => Err(Error::Position(pos)) _ => Err(Error::Position(pos))
@ -209,8 +209,8 @@ impl<'a> Tokenizer<'a> {
Ok(Token::LittleOrEqual(pos)) Ok(Token::LittleOrEqual(pos))
} }
_ if ch.is_whitespace() _ if ch.is_whitespace()
|| ch == '\'' || ch == CH_SINGLE_QUOTA
|| ch == '"' || ch == CH_DOUBLE_QUOTA
|| ch.is_numeric() || ch.is_numeric()
=> Ok(Token::Little(pos)), => Ok(Token::Little(pos)),
_ => Err(Error::Position(pos)) _ => Err(Error::Position(pos))