add . and [] support.

This commit is contained in:
fengcen 2016-11-21 09:14:40 +08:00
parent 032e57df43
commit 3cb3197f6f
7 changed files with 318 additions and 84 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "eval" name = "eval"
version = "0.2.0" version = "0.2.1"
description = "Expression evaluator" description = "Expression evaluator"
keywords = ["expression", "evaluate", "evaluator", "expr", "template"] keywords = ["expression", "evaluate", "evaluator", "expr", "template"]
authors = ["fengcen <fengcen.love@gmail.com>"] authors = ["fengcen <fengcen.love@gmail.com>"]

View File

@ -1,7 +1,7 @@
eval eval
=== ===
[![docs](https://docs.rs/eval/badge.svg?version=0.2.0 "docs")](https://docs.rs/eval) [![docs](https://docs.rs/eval/badge.svg?version=0.2.1 "docs")](https://docs.rs/eval)
Eval is a powerful expression evaluator. Eval is a powerful expression evaluator.
@ -56,6 +56,23 @@ assert_eq!(Expr::new("foo == bar")
Ok(to_value(true))); Ok(to_value(true)));
``` ```
You can access data like javascript by using `.` and `[]`. `[]` supports expression.
```
use eval::{Expr, to_value};
use std::collections::HashMap;
let mut object = HashMap::new();
object.insert("foos", vec!["Hello", "world", "!"]);
assert_eq!(Expr::new("object.foos[1-1] == 'Hello'")
.value("object", object)
.exec(),
Ok(to_value(true)));
```
You can eval with function: You can eval with function:
``` ```
@ -67,6 +84,7 @@ assert_eq!(Expr::new("say_hello()")
Ok(to_value("Hello world!"))); Ok(to_value("Hello world!")));
``` ```
You can create an array with `[]`: You can create an array with `[]`:
``` ```
@ -75,6 +93,7 @@ use eval::{eval, to_value};
assert_eq!(eval("[1, 2, 3, 4, 5]"), Ok(to_value(vec![1, 2, 3, 4, 5]))); assert_eq!(eval("[1, 2, 3, 4, 5]"), Ok(to_value(vec![1, 2, 3, 4, 5])));
``` ```
You can create an integer array with `n..m`: You can create an integer array with `n..m`:
``` ```

View File

@ -4,70 +4,90 @@ use operator::Operator;
quick_error! { quick_error! {
/// Expression parsing error /// Expression parsing error
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Error { pub enum Error {
/// Unsupported operator yet. /// Unsupported operator yet.
UnsupportedOperator(operator: String) { UnsupportedOperator(operator: String) {
display("Unsupported operator: {:?}", operator) display("Unsupported operator: {:?}", operator)
} }
/// This operator does not support execution. /// This operator does not support execution.
CanNotExec(operator: Operator) { CanNotExec(operator: Operator) {
display("This operator does not support execution: {:?}", operator) display("This operator does not support execution: {:?}", operator)
} }
/// Your expression may start with non-value operator like ( + * ) /// Your expression may start with non-value operator like ( + * )
StartWithNonValueOperator { StartWithNonValueOperator {
display("Your expression may start with non-value operator like ( + * ).") display("Your expression may start with non-value operator like ( + * ).")
} }
/// Unpaired brackets, left brackets count does not equal right brackets count /// Unpaired brackets, left brackets count does not equal right brackets count
UnpairedBrackets { UnpairedBrackets {
display("Unpaired brackets, left brackets count does not equal right brackets count.") display("Unpaired brackets, left brackets count does not equal right brackets count.")
} }
/// Duplicate values node, you may have (2 3) but there is no operators between them /// Duplicate values node, you may have (2 3) but there is no operators between them
DuplicateValueNode { DuplicateValueNode {
display("Duplicate values node, you may have (2 3) but there is no operators between them.") display("Duplicate values node, you may have (2 3) but there is no operators between them.")
} }
/// Duplicate operators node, you may have (+ +) but there is no values between them /// Duplicate operators node, you may have (+ +) but there is no values between them
DuplicateOperatorNode { DuplicateOperatorNode {
display("Duplicate operators node, you may have (+ +) but there is no values between them.") display("Duplicate operators node, you may have (+ +) but there is no values between them.")
} }
/// You have a comma(,) , but there is no function in front of it. /// You have a comma(,) , but there is no function in front of it.
CommaNotWithFunction { CommaNotWithFunction {
display("You have a comma(,) , but there is no function in front of it.") display("You have a comma(,) , but there is no function in front of it.")
} }
/// You have empty brackets () , but there is no function in front of it. /// You have empty brackets () , but there is no function in front of it.
BracketNotWithFunction { BracketNotWithFunction {
display("You have empty brackets () , but there is no function in front of it.") display("You have empty brackets () , but there is no function in front of it.")
} }
/// Function not exists. /// Function not exists.
FunctionNotExists(ident: String) { FunctionNotExists(ident: String) {
display("Function not exists: {}", ident) display("Function not exists: {}", ident)
} }
/// Expected boolean type but the given value isn't. /// Expected a boolean but the given value isn't.
NotBoolean(value: Value) { ExpectedBoolean(value: Value) {
display("Expected boolean type, found: {}", value) display("Expected a boolean, found: {}", value)
} }
/// Failed to parse, no final expression. /// Expected ident.
ExpectedIdentifier {
display("Expected ident.")
}
/// Expected array.
ExpectedArray {
display("Expected array.")
}
/// Expected object.
ExpectedObject {
display("Expected object.")
}
/// Expect number.
ExpectedNumber {
display("Expected number.")
}
/// Failed to parse, no final expression.
NoFinalNode { NoFinalNode {
display("Failed to parse, no final expression.") display("Failed to parse, no final expression.")
} }
/// The number of arguments is greater than the maximum limit. /// The number of arguments is greater than the maximum limit.
ArgumentsGreater(max: usize) { ArgumentsGreater(max: usize) {
display("The number of arguments is greater than the maximum limit: {}", max) display("The number of arguments is greater than the maximum limit: {}", max)
} }
/// The number of arguments is less than the minimum limit. /// The number of arguments is less than the minimum limit.
ArgumentsLess(min: usize) { ArgumentsLess(min: usize) {
display("The number of arguments is less than the minimum limit: {}", min) display("The number of arguments is less than the minimum limit: {}", min)
} }
/// This two value types are different or do not support mathematical calculations. /// This two value types are different or do not support mathematical calculations.
UnsupportedTypes(a: String, b: String) { UnsupportedTypes(a: String, b: String) {
display("This two value types are different or do not support mathematical calculations: {}, {}", a, b) display("This two value types are different or do not support mathematical calculations: {}, {}", a, b)
} }
/// Invalid range expression like `1..2..3` /// Invalid range expression like `1..2..3`
InvalidRange(ident: String) { InvalidRange(ident: String) {
display("Invalid range expression: {}", ident) display("Invalid range expression: {}", ident)
} }
/// Custom error. /// Can not add child node.
CanNotAddChild {
display("Can not add child node.")
}
/// Custom error.
Custom(detail: String) { Custom(detail: String) {
display("{}", detail) display("{}", detail)
} }

View File

@ -1,9 +1,9 @@
//! Eval is a powerful expression evaluator. //! Eval is a powerful expression evaluator.
//! //!
//! Supported operators: `!` `!=` `""` `''` `()` `[]` `,` `>` `<` `>=` `<=` //! Supported operators: `!` `!=` `""` `''` `()` `[]` `.` `,` `>` `<` `>=` `<=`
//! `==` `+` `-` `*` `/` `%` `&&` `||` `n..m`. //! `==` `+` `-` `*` `/` `%` `&&` `||` `n..m`.
//! //!
//! Built-in functions: `min()` `max()` `len()` `is_empty()`. //! Built-in functions: `min()` `max()` `len()` `is_empty()` `array()`.
//! //!
//! ## Examples //! ## Examples
//! //!
@ -30,6 +30,21 @@
//! Ok(to_value(true))); //! Ok(to_value(true)));
//! ``` //! ```
//! //!
//! You can access data like javascript by using `.` and `[]`. `[]` supports expression.
//!
//! ```
//! use eval::{Expr, to_value};
//! use std::collections::HashMap;
//!
//! let mut object = HashMap::new();
//! object.insert("foos", vec!["Hello", "world", "!"]);
//!
//! assert_eq!(Expr::new("object.foos[2-1] == 'world'") // Access field `foos` and index `2-1`
//! .value("object", object)
//! .exec(),
//! Ok(to_value(true)));
//! ```
//!
//! You can eval with function: //! You can eval with function:
//! //!
//! ``` //! ```
@ -41,12 +56,12 @@
//! Ok(to_value("Hello world!"))); //! Ok(to_value("Hello world!")));
//! ``` //! ```
//! //!
//! You can create an array with `[]`: //! You can create an array with `array()`:
//! //!
//! ``` //! ```
//! use eval::{eval, to_value}; //! use eval::{eval, to_value};
//! //!
//! assert_eq!(eval("[1, 2, 3, 4, 5]"), Ok(to_value(vec![1, 2, 3, 4, 5]))); //! assert_eq!(eval("array(1, 2, 3, 4, 5)"), Ok(to_value(vec![1, 2, 3, 4, 5])));
//! ``` //! ```
//! //!
//! You can create an integer array with `n..m`: //! You can create an integer array with `n..m`:
@ -69,7 +84,10 @@
//! Accept single arguments and return the length of value. Only accept String, Array, Object and Null. //! Accept single arguments and return the length of value. Only accept String, Array, Object and Null.
//! //!
//! ### is_empty() //! ### is_empty()
//! Accept single arguments and return the a boolean. Check whether the value is empty or not. //! Accept single arguments and return a boolean. Check whether the value is empty or not.
//!
//! ### array()
//! Accept multiple arguments and return an array.
//! //!
//! //!
#![recursion_limit="100"] #![recursion_limit="100"]
@ -122,6 +140,7 @@ mod tests {
use error::Error; use error::Error;
use Expr; use Expr;
use tree::Tree; use tree::Tree;
use Value;
use eval; use eval;
use std::collections::HashMap; use std::collections::HashMap;
@ -204,7 +223,7 @@ mod tests {
#[test] #[test]
fn test_len_array() { fn test_len_array() {
assert_eq!(eval("len([2, 3, 4, 5, 6])"), Ok(to_value(5))); assert_eq!(eval("len(array(2, 3, 4, 5, 6))"), Ok(to_value(5)));
} }
#[test] #[test]
@ -320,17 +339,16 @@ mod tests {
#[test] #[test]
fn test_array() { fn test_array() {
assert_eq!(eval("[1, 2, 3, 4]"), Ok(to_value(vec![1, 2, 3, 4])));
assert_eq!(eval("array(1, 2, 3, 4)"), Ok(to_value(vec![1, 2, 3, 4]))); assert_eq!(eval("array(1, 2, 3, 4)"), Ok(to_value(vec![1, 2, 3, 4])));
} }
#[test] #[test]
fn test_array_ident() { fn test_range() {
assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4]))); assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4])));
} }
#[test] #[test]
fn test_array_ident_and_min() { fn test_range_and_min() {
assert_eq!(eval("min(0..5)"), Ok(to_value(0))); assert_eq!(eval("min(0..5)"), Ok(to_value(0)));
} }
@ -403,12 +421,58 @@ mod tests {
assert_eq!(eval("(!(1 == 2)) == true"), Ok(to_value(true))); assert_eq!(eval("(!(1 == 2)) == true"), Ok(to_value(true)));
} }
#[test]
fn test_object_access() {
let mut object = HashMap::new();
object.insert("foo", "Foo, hello world!");
object.insert("bar", "Bar, hello world!");
assert_eq!(Expr::new("object.foo == 'Foo, hello world!'")
.value("object", object)
.exec(),
Ok(to_value(true)));
}
#[test]
fn test_object_dynamic_access() {
let mut object = HashMap::new();
object.insert("foo", "Foo, hello world!");
object.insert("bar", "Bar, hello world!");
assert_eq!(Expr::new("object['foo'] == 'Foo, hello world!'")
.value("object", object)
.exec(),
Ok(to_value(true)));
}
#[test]
fn test_object_dynamic_access_2() {
let mut object = HashMap::new();
object.insert("foo", "Foo, hello world!");
object.insert("bar", "Bar, hello world!");
assert_eq!(Expr::new("object[foo] == 'Foo, hello world!'")
.value("object", object)
.value("foo", "foo")
.exec(),
Ok(to_value(true)));
}
#[test]
fn test_path() {
assert_eq!(Expr::new("array[2-2].foo[2-2]").exec(), Ok(Value::Null));
}
#[test]
fn test_array_access() {
let array = vec!["hello", "world", "!"];
assert_eq!(Expr::new("array[1-1] == 'hello' && array[1] == 'world' && array[2] == '!'")
.value("array", array)
.exec(),
Ok(to_value(true)));
}
#[test] #[test]
fn test_builtin_is_empty() { fn test_builtin_is_empty() {
assert_eq!(Expr::new("is_empty(array)") assert_eq!(Expr::new("is_empty(array)")
.value("array", Vec::<String>::new()) .value("array", Vec::<String>::new())
.compile()
.unwrap()
.exec(), .exec(),
Ok(to_value(true))); Ok(to_value(true)));
} }
@ -417,8 +481,6 @@ mod tests {
fn test_builtin_min() { fn test_builtin_min() {
assert_eq!(Expr::new("min(array)") assert_eq!(Expr::new("min(array)")
.value("array", vec![23, 34, 45, 2]) .value("array", vec![23, 34, 45, 2])
.compile()
.unwrap()
.exec(), .exec(),
Ok(to_value(2))); Ok(to_value(2)));
} }
@ -428,8 +490,6 @@ mod tests {
assert_eq!(Expr::new("output()") assert_eq!(Expr::new("output()")
.function("output", .function("output",
|_| Ok(to_value("This is custom function's output"))) |_| Ok(to_value("This is custom function's output")))
.compile()
.unwrap()
.exec(), .exec(),
Ok(to_value("This is custom function's output"))); Ok(to_value("This is custom function's output")));
} }

View File

@ -64,6 +64,27 @@ impl Node {
} }
} }
pub fn is_unclosed_square_bracket(&self) -> bool {
match self.operator {
Operator::LeftSquareBracket(_) => !self.closed,
_ => false,
}
}
pub fn is_left_square_bracket(&self) -> bool {
match self.operator {
Operator::LeftSquareBracket(_) => true,
_ => false,
}
}
pub fn is_dot(&self) -> bool {
match self.operator {
Operator::Dot(_) => true,
_ => false,
}
}
pub fn add_child(&mut self, node: Node) { pub fn add_child(&mut self, node: Node) {
self.children.push(node); self.children.push(node);
} }

View File

@ -21,9 +21,10 @@ pub enum Operator {
Le(u8), Le(u8),
And(u8), And(u8),
Or(u8), Or(u8),
Dot(u8),
LeftParenthesis, LeftParenthesis,
RightParenthesis, RightParenthesis,
LeftSquareBracket, LeftSquareBracket(u8),
RightSquareBracket, RightSquareBracket,
DoubleQuotes, DoubleQuotes,
SingleQuote, SingleQuote,
@ -107,6 +108,20 @@ impl Operator {
} }
} }
pub fn is_left_square_bracket(&self) -> bool {
match *self {
Operator::LeftSquareBracket(_) => true,
_ => false,
}
}
pub fn is_dot(&self) -> bool {
match *self {
Operator::Dot(_) => true,
_ => false,
}
}
pub fn is_value_or_ident(&self) -> bool { pub fn is_value_or_ident(&self) -> bool {
match *self { match *self {
Operator::Value(_) | Operator::Value(_) |
@ -130,6 +145,9 @@ impl Operator {
Operator::And(_) | Operator::And(_) |
Operator::Or(_) | Operator::Or(_) |
Operator::Ge(_) | Operator::Ge(_) |
Operator::Not(_) |
Operator::Dot(_) |
Operator::LeftSquareBracket(_) |
Operator::Le(_) => true, Operator::Le(_) => true,
_ => false, _ => false,
} }
@ -138,7 +156,7 @@ impl Operator {
pub fn is_left(&self) -> bool { pub fn is_left(&self) -> bool {
match *self { match *self {
Operator::LeftParenthesis | Operator::LeftParenthesis |
Operator::LeftSquareBracket => true, Operator::LeftSquareBracket(_) => true,
_ => false, _ => false,
} }
} }
@ -146,7 +164,7 @@ impl Operator {
pub fn get_left(&self) -> Operator { pub fn get_left(&self) -> Operator {
match *self { match *self {
Operator::RightParenthesis => Operator::LeftParenthesis, Operator::RightParenthesis => Operator::LeftParenthesis,
Operator::RightSquareBracket => Operator::LeftSquareBracket, Operator::RightSquareBracket => Operator::LeftSquareBracket(100),
_ => panic!("not bracket"), _ => panic!("not bracket"),
} }
} }
@ -161,9 +179,9 @@ impl Operator {
node node
} }
pub fn get_identifier(&self) -> String { pub fn get_identifier(&self) -> &str {
match *self { match *self {
Operator::Identifier(ref ident) => ident.to_owned(), Operator::Identifier(ref ident) => ident,
_ => panic!("not identifier"), _ => panic!("not identifier"),
} }
} }
@ -181,8 +199,9 @@ impl FromStr for Operator {
"%" => Ok(Operator::Rem(10)), "%" => Ok(Operator::Rem(10)),
"(" => Ok(Operator::LeftParenthesis), "(" => Ok(Operator::LeftParenthesis),
")" => Ok(Operator::RightParenthesis), ")" => Ok(Operator::RightParenthesis),
"[" => Ok(Operator::LeftSquareBracket), "[" => Ok(Operator::LeftSquareBracket(100)),
"]" => Ok(Operator::RightSquareBracket), "]" => Ok(Operator::RightSquareBracket),
"." => Ok(Operator::Dot(100)),
"\"" => Ok(Operator::DoubleQuotes), "\"" => Ok(Operator::DoubleQuotes),
"'" => Ok(Operator::SingleQuote), "'" => Ok(Operator::SingleQuote),
" " => Ok(Operator::WhiteSpace), " " => Ok(Operator::WhiteSpace),

View File

@ -31,7 +31,7 @@ impl Tree {
for (index, cur) in self.raw.chars().enumerate() { for (index, cur) in self.raw.chars().enumerate() {
match cur { match cur {
'(' | ')' | '+' | '-' | '*' | '/' | ',' | ' ' | '!' | '=' | '>' | '<' | '\'' | '(' | ')' | '+' | '-' | '*' | '/' | ',' | ' ' | '!' | '=' | '>' | '<' | '\'' |
'[' | ']' | '%' | '&' | '|' => { '[' | ']' | '.' | '%' | '&' | '|' => {
if !found_quote { if !found_quote {
pos.push(index); pos.push(index);
pos.push(index + 1); pos.push(index + 1);
@ -57,9 +57,9 @@ impl Tree {
let mut start; let mut start;
let mut end = 0; let mut end = 0;
let mut parenthesis = 0; let mut parenthesis = 0;
let mut square_brackets = 0;
let mut quote = None; let mut quote = None;
let mut prev = String::new(); let mut prev = String::new();
let mut number = String::new();
for pos_ref in &self.pos { for pos_ref in &self.pos {
let pos = *pos_ref; let pos = *pos_ref;
@ -72,6 +72,10 @@ impl Tree {
let raw = self.raw[start..end].to_owned(); let raw = self.raw[start..end].to_owned();
if raw.is_empty() {
continue;
}
let operator = Operator::from_str(&raw).unwrap(); let operator = Operator::from_str(&raw).unwrap();
match operator { match operator {
Operator::DoubleQuotes | Operator::SingleQuote => { Operator::DoubleQuotes | Operator::SingleQuote => {
@ -96,8 +100,12 @@ impl Tree {
continue; continue;
} }
if raw.is_empty() { if parse_number(&raw).is_some() || operator.is_dot() {
number += &raw;
continue; continue;
} else if !number.is_empty() {
operators.push(Operator::from_str(&number).unwrap());
number.clear();
} }
if raw == "=" { if raw == "=" {
@ -137,19 +145,14 @@ impl Tree {
} }
match operator { match operator {
Operator::LeftSquareBracket => {
square_brackets += 1;
operators.push(Operator::Function("array".to_owned()));
operators.push(operator);
continue;
}
Operator::LeftParenthesis => { Operator::LeftParenthesis => {
parenthesis += 1; parenthesis += 1;
if !operators.is_empty() { if !operators.is_empty() {
let prev_operator = operators.pop().unwrap(); let prev_operator = operators.pop().unwrap();
if prev_operator.is_identifier() { if prev_operator.is_identifier() {
operators.push(Operator::Function(prev_operator.get_identifier())); operators.push(Operator::Function(prev_operator.get_identifier()
.to_owned()));
operators.push(operator); operators.push(operator);
continue; continue;
} else { } else {
@ -158,7 +161,6 @@ impl Tree {
} }
} }
Operator::RightParenthesis => parenthesis -= 1, Operator::RightParenthesis => parenthesis -= 1,
Operator::RightSquareBracket => square_brackets -= 1,
Operator::WhiteSpace => continue, Operator::WhiteSpace => continue,
_ => (), _ => (),
} }
@ -167,7 +169,11 @@ impl Tree {
operators.push(operator); operators.push(operator);
} }
if parenthesis != 0 || square_brackets != 0 { if !number.is_empty() {
operators.push(Operator::from_str(&number).unwrap());
}
if parenthesis != 0 {
Err(Error::UnpairedBrackets) Err(Error::UnpairedBrackets)
} else { } else {
self.operators = operators; self.operators = operators;
@ -193,6 +199,8 @@ impl Tree {
Operator::And(priority) | Operator::And(priority) |
Operator::Or(priority) | Operator::Or(priority) |
Operator::Le(priority) | Operator::Le(priority) |
Operator::Dot(priority) |
Operator::LeftSquareBracket(priority) |
Operator::Rem(priority) => { Operator::Rem(priority) => {
if !parsing_nodes.is_empty() { if !parsing_nodes.is_empty() {
let prev = parsing_nodes.pop().unwrap(); let prev = parsing_nodes.pop().unwrap();
@ -215,15 +223,14 @@ impl Tree {
} }
} }
Operator::Function(_) | Operator::Function(_) |
Operator::LeftParenthesis | Operator::LeftParenthesis => parsing_nodes.push(operator.to_node()),
Operator::LeftSquareBracket => parsing_nodes.push(operator.to_node()),
Operator::Comma => close_comma(&mut parsing_nodes)?, Operator::Comma => close_comma(&mut parsing_nodes)?,
Operator::RightParenthesis | Operator::RightParenthesis |
Operator::RightSquareBracket => { Operator::RightSquareBracket => {
close_bracket(&mut parsing_nodes, operator.get_left())? close_bracket(&mut parsing_nodes, operator.get_left())?
} }
Operator::Value(_) | Operator::Value(_) |
Operator::Identifier(_) => append_child_to_last_node(&mut parsing_nodes, operator)?, Operator::Identifier(_) => append_value_to_last_node(&mut parsing_nodes, operator)?,
_ => (), _ => (),
} }
} }
@ -337,7 +344,93 @@ impl Tree {
match value { match value {
Value::Bool(boolean) => Ok(Value::Bool(!boolean)), Value::Bool(boolean) => Ok(Value::Bool(!boolean)),
Value::Null => Ok(Value::Bool(true)), Value::Null => Ok(Value::Bool(true)),
_ => Err(Error::NotBoolean(value)), _ => Err(Error::ExpectedBoolean(value)),
}
}
Operator::Dot(_) => {
let mut value = None;
for child in &node.children {
if value.is_none() {
let name = exec_node(child, builtin, contexts, functions)?;
if name.is_string() {
value = find(contexts, name.as_str().unwrap());
if value.is_none() {
return Ok(Value::Null);
}
} else if name.is_object() {
value = Some(name);
} else if name.is_null() {
return Ok(Value::Null);
} else {
return Err(Error::ExpectedObject);
}
} else {
if child.operator.is_identifier() {
value = value.as_ref()
.unwrap()
.find(child.operator.get_identifier())
.cloned();
} else {
return Err(Error::ExpectedIdentifier);
}
}
}
if value.is_some() {
return Ok(value.unwrap());
} else {
return Ok(Value::Null);
}
}
Operator::LeftSquareBracket(_) => {
let mut value = None;
for child in &node.children {
let name = exec_node(child, builtin, contexts, functions)?;
if value.is_none() {
if name.is_string() {
value = find(contexts, name.as_str().unwrap());
if value.is_none() {
return Ok(Value::Null);
}
} else if name.is_array() {
value = Some(name);
} else if name.is_object() {
value = Some(name);
} else if name.is_null() {
return Ok(Value::Null);
} else {
return Err(Error::ExpectedArray);
}
} else if value.as_ref().unwrap().is_object() {
if name.is_string() {
value = value.as_ref()
.unwrap()
.find(name.as_str().unwrap())
.cloned();
} else {
return Err(Error::ExpectedIdentifier);
}
} else {
if name.is_u64() {
if value.as_ref().unwrap().is_array() {
value = value.as_ref()
.unwrap()
.as_array()
.unwrap()
.get(name.as_u64().unwrap() as usize)
.cloned();
} else {
return Err(Error::ExpectedArray);
}
} else {
return Err(Error::ExpectedNumber);
}
}
}
if value.is_some() {
return Ok(value.unwrap());
} else {
return Ok(Value::Null);
} }
} }
Operator::Identifier(ref ident) => { Operator::Identifier(ref ident) => {
@ -360,21 +453,30 @@ impl Tree {
} }
} }
fn append_child_to_last_node(parsing_nodes: &mut Vec<Node>, fn append_value_to_last_node(parsing_nodes: &mut Vec<Node>,
operator: &Operator) operator: &Operator)
-> Result<(), Error> { -> Result<(), Error> {
let mut node = operator.to_node(); let mut node = operator.to_node();
node.closed = true; node.closed = true;
if let Some(mut prev) = parsing_nodes.pop() { if let Some(mut prev) = parsing_nodes.pop() {
if prev.is_value_or_enough() { if prev.is_dot() {
prev.add_child(node);
prev.closed = true;
parsing_nodes.push(prev);
} else if prev.is_left_square_bracket() {
parsing_nodes.push(prev);
parsing_nodes.push(node);
} else if prev.is_value_or_enough() {
return Err(Error::DuplicateValueNode); return Err(Error::DuplicateValueNode);
} else if prev.is_enough() { } else if prev.is_enough() {
parsing_nodes.push(prev); parsing_nodes.push(prev);
parsing_nodes.push(node); parsing_nodes.push(node);
} else { } else if prev.operator.can_have_child() {
prev.add_child(node); prev.add_child(node);
parsing_nodes.push(prev); parsing_nodes.push(prev);
} else {
return Err(Error::CanNotAddChild);
} }
} else { } else {
parsing_nodes.push(node); parsing_nodes.push(node);
@ -391,8 +493,12 @@ fn get_final_node(mut parsing_nodes: Vec<Node>) -> Result<Node, Error> {
while parsing_nodes.len() != 1 { while parsing_nodes.len() != 1 {
let last = parsing_nodes.pop().unwrap(); let last = parsing_nodes.pop().unwrap();
let mut prev = parsing_nodes.pop().unwrap(); let mut prev = parsing_nodes.pop().unwrap();
if prev.operator.can_have_child() {
prev.add_child(last); prev.add_child(last);
parsing_nodes.push(prev); parsing_nodes.push(prev);
} else {
return Err(Error::CanNotAddChild);
}
} }
Ok(parsing_nodes.pop().unwrap()) Ok(parsing_nodes.pop().unwrap())
@ -403,7 +509,14 @@ fn close_bracket(parsing_nodes: &mut Vec<Node>, bracket: Operator) -> Result<(),
let mut current = parsing_nodes.pop().unwrap(); let mut current = parsing_nodes.pop().unwrap();
let mut prev = parsing_nodes.pop().unwrap(); let mut prev = parsing_nodes.pop().unwrap();
if current.operator == bracket { if current.operator.is_left_square_bracket() {
return Err(Error::BracketNotWithFunction);
} else if prev.operator.is_left_square_bracket() {
prev.add_child(current);
prev.closed = true;
parsing_nodes.push(prev);
break;
} else if current.operator == bracket {
if prev.is_unclosed_function() { if prev.is_unclosed_function() {
prev.closed = true; prev.closed = true;
parsing_nodes.push(prev); parsing_nodes.push(prev);
@ -503,9 +616,8 @@ fn rob_to(mut was_robed: Node, mut rober: Node) -> Vec<Node> {
fn find(contexts: &[Context], key: &str) -> Option<Value> { fn find(contexts: &[Context], key: &str) -> Option<Value> {
for context in contexts.iter().rev() { for context in contexts.iter().rev() {
let value = get(context, key); match context.get(key) {
match value { Some(value) => return Some(value.clone()),
Some(_) => return value,
None => continue, None => continue,
} }
} }
@ -513,23 +625,6 @@ fn find(contexts: &[Context], key: &str) -> Option<Value> {
None None
} }
fn get(context: &Context, key: &str) -> Option<Value> {
let mut keys = key.split('.').collect::<Vec<_>>();
let context_key = keys.remove(0);
let context_value_option = context.get(context_key);
if context_value_option.is_none() {
None
} else if !keys.is_empty() {
match context_value_option.unwrap().search(&keys.join(".")) {
Some(value) => Some(value.clone()),
None => None,
}
} else {
Some(context_value_option.unwrap().clone())
}
}
fn is_range(ident: &str) -> bool { fn is_range(ident: &str) -> bool {
ident.contains("..") ident.contains("..")
} }