add .
and []
support.
This commit is contained in:
parent
032e57df43
commit
3cb3197f6f
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "eval"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
description = "Expression evaluator"
|
||||
keywords = ["expression", "evaluate", "evaluator", "expr", "template"]
|
||||
authors = ["fengcen <fengcen.love@gmail.com>"]
|
||||
|
21
README.md
21
README.md
@ -1,7 +1,7 @@
|
||||
|
||||
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.
|
||||
|
||||
@ -56,6 +56,23 @@ assert_eq!(Expr::new("foo == bar")
|
||||
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:
|
||||
|
||||
```
|
||||
@ -67,6 +84,7 @@ assert_eq!(Expr::new("say_hello()")
|
||||
Ok(to_value("Hello world!")));
|
||||
```
|
||||
|
||||
|
||||
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])));
|
||||
```
|
||||
|
||||
|
||||
You can create an integer array with `n..m`:
|
||||
|
||||
```
|
||||
|
@ -4,70 +4,90 @@ use operator::Operator;
|
||||
|
||||
|
||||
quick_error! {
|
||||
/// Expression parsing error
|
||||
/// Expression parsing error
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
/// Unsupported operator yet.
|
||||
/// Unsupported operator yet.
|
||||
UnsupportedOperator(operator: String) {
|
||||
display("Unsupported operator: {:?}", operator)
|
||||
}
|
||||
/// This operator does not support execution.
|
||||
/// This operator does not support execution.
|
||||
CanNotExec(operator: 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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
display("You have empty brackets () , but there is no function in front of it.")
|
||||
}
|
||||
/// Function not exists.
|
||||
/// Function not exists.
|
||||
FunctionNotExists(ident: String) {
|
||||
display("Function not exists: {}", ident)
|
||||
}
|
||||
/// Expected boolean type but the given value isn't.
|
||||
NotBoolean(value: Value) {
|
||||
display("Expected boolean type, found: {}", value)
|
||||
/// Expected a boolean but the given value isn't.
|
||||
ExpectedBoolean(value: 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 {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
display("Invalid range expression: {}", ident)
|
||||
}
|
||||
/// Custom error.
|
||||
/// Can not add child node.
|
||||
CanNotAddChild {
|
||||
display("Can not add child node.")
|
||||
}
|
||||
/// Custom error.
|
||||
Custom(detail: String) {
|
||||
display("{}", detail)
|
||||
}
|
||||
|
90
src/lib.rs
90
src/lib.rs
@ -1,9 +1,9 @@
|
||||
//! Eval is a powerful expression evaluator.
|
||||
//!
|
||||
//! Supported operators: `!` `!=` `""` `''` `()` `[]` `,` `>` `<` `>=` `<=`
|
||||
//! Supported operators: `!` `!=` `""` `''` `()` `[]` `.` `,` `>` `<` `>=` `<=`
|
||||
//! `==` `+` `-` `*` `/` `%` `&&` `||` `n..m`.
|
||||
//!
|
||||
//! Built-in functions: `min()` `max()` `len()` `is_empty()`.
|
||||
//! Built-in functions: `min()` `max()` `len()` `is_empty()` `array()`.
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
@ -30,6 +30,21 @@
|
||||
//! 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:
|
||||
//!
|
||||
//! ```
|
||||
@ -41,12 +56,12 @@
|
||||
//! Ok(to_value("Hello world!")));
|
||||
//! ```
|
||||
//!
|
||||
//! You can create an array with `[]`:
|
||||
//! You can create an array with `array()`:
|
||||
//!
|
||||
//! ```
|
||||
//! 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`:
|
||||
@ -69,7 +84,10 @@
|
||||
//! Accept single arguments and return the length of value. Only accept String, Array, Object and Null.
|
||||
//!
|
||||
//! ### 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"]
|
||||
@ -122,6 +140,7 @@ mod tests {
|
||||
use error::Error;
|
||||
use Expr;
|
||||
use tree::Tree;
|
||||
use Value;
|
||||
use eval;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -204,7 +223,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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]
|
||||
@ -320,17 +339,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_ident() {
|
||||
fn test_range() {
|
||||
assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_ident_and_min() {
|
||||
fn test_range_and_min() {
|
||||
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)));
|
||||
}
|
||||
|
||||
#[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]
|
||||
fn test_builtin_is_empty() {
|
||||
assert_eq!(Expr::new("is_empty(array)")
|
||||
.value("array", Vec::<String>::new())
|
||||
.compile()
|
||||
.unwrap()
|
||||
.exec(),
|
||||
Ok(to_value(true)));
|
||||
}
|
||||
@ -417,8 +481,6 @@ mod tests {
|
||||
fn test_builtin_min() {
|
||||
assert_eq!(Expr::new("min(array)")
|
||||
.value("array", vec![23, 34, 45, 2])
|
||||
.compile()
|
||||
.unwrap()
|
||||
.exec(),
|
||||
Ok(to_value(2)));
|
||||
}
|
||||
@ -428,8 +490,6 @@ mod tests {
|
||||
assert_eq!(Expr::new("output()")
|
||||
.function("output",
|
||||
|_| Ok(to_value("This is custom function's output")))
|
||||
.compile()
|
||||
.unwrap()
|
||||
.exec(),
|
||||
Ok(to_value("This is custom function's output")));
|
||||
}
|
||||
|
@ -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) {
|
||||
self.children.push(node);
|
||||
}
|
||||
|
@ -21,9 +21,10 @@ pub enum Operator {
|
||||
Le(u8),
|
||||
And(u8),
|
||||
Or(u8),
|
||||
Dot(u8),
|
||||
LeftParenthesis,
|
||||
RightParenthesis,
|
||||
LeftSquareBracket,
|
||||
LeftSquareBracket(u8),
|
||||
RightSquareBracket,
|
||||
DoubleQuotes,
|
||||
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 {
|
||||
match *self {
|
||||
Operator::Value(_) |
|
||||
@ -130,6 +145,9 @@ impl Operator {
|
||||
Operator::And(_) |
|
||||
Operator::Or(_) |
|
||||
Operator::Ge(_) |
|
||||
Operator::Not(_) |
|
||||
Operator::Dot(_) |
|
||||
Operator::LeftSquareBracket(_) |
|
||||
Operator::Le(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
@ -138,7 +156,7 @@ impl Operator {
|
||||
pub fn is_left(&self) -> bool {
|
||||
match *self {
|
||||
Operator::LeftParenthesis |
|
||||
Operator::LeftSquareBracket => true,
|
||||
Operator::LeftSquareBracket(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -146,7 +164,7 @@ impl Operator {
|
||||
pub fn get_left(&self) -> Operator {
|
||||
match *self {
|
||||
Operator::RightParenthesis => Operator::LeftParenthesis,
|
||||
Operator::RightSquareBracket => Operator::LeftSquareBracket,
|
||||
Operator::RightSquareBracket => Operator::LeftSquareBracket(100),
|
||||
_ => panic!("not bracket"),
|
||||
}
|
||||
}
|
||||
@ -161,9 +179,9 @@ impl Operator {
|
||||
node
|
||||
}
|
||||
|
||||
pub fn get_identifier(&self) -> String {
|
||||
pub fn get_identifier(&self) -> &str {
|
||||
match *self {
|
||||
Operator::Identifier(ref ident) => ident.to_owned(),
|
||||
Operator::Identifier(ref ident) => ident,
|
||||
_ => panic!("not identifier"),
|
||||
}
|
||||
}
|
||||
@ -181,8 +199,9 @@ impl FromStr for Operator {
|
||||
"%" => Ok(Operator::Rem(10)),
|
||||
"(" => Ok(Operator::LeftParenthesis),
|
||||
")" => Ok(Operator::RightParenthesis),
|
||||
"[" => Ok(Operator::LeftSquareBracket),
|
||||
"[" => Ok(Operator::LeftSquareBracket(100)),
|
||||
"]" => Ok(Operator::RightSquareBracket),
|
||||
"." => Ok(Operator::Dot(100)),
|
||||
"\"" => Ok(Operator::DoubleQuotes),
|
||||
"'" => Ok(Operator::SingleQuote),
|
||||
" " => Ok(Operator::WhiteSpace),
|
||||
|
175
src/tree/mod.rs
175
src/tree/mod.rs
@ -31,7 +31,7 @@ impl Tree {
|
||||
for (index, cur) in self.raw.chars().enumerate() {
|
||||
match cur {
|
||||
'(' | ')' | '+' | '-' | '*' | '/' | ',' | ' ' | '!' | '=' | '>' | '<' | '\'' |
|
||||
'[' | ']' | '%' | '&' | '|' => {
|
||||
'[' | ']' | '.' | '%' | '&' | '|' => {
|
||||
if !found_quote {
|
||||
pos.push(index);
|
||||
pos.push(index + 1);
|
||||
@ -57,9 +57,9 @@ impl Tree {
|
||||
let mut start;
|
||||
let mut end = 0;
|
||||
let mut parenthesis = 0;
|
||||
let mut square_brackets = 0;
|
||||
let mut quote = None;
|
||||
let mut prev = String::new();
|
||||
let mut number = String::new();
|
||||
|
||||
for pos_ref in &self.pos {
|
||||
let pos = *pos_ref;
|
||||
@ -72,6 +72,10 @@ impl Tree {
|
||||
|
||||
let raw = self.raw[start..end].to_owned();
|
||||
|
||||
if raw.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let operator = Operator::from_str(&raw).unwrap();
|
||||
match operator {
|
||||
Operator::DoubleQuotes | Operator::SingleQuote => {
|
||||
@ -96,8 +100,12 @@ impl Tree {
|
||||
continue;
|
||||
}
|
||||
|
||||
if raw.is_empty() {
|
||||
if parse_number(&raw).is_some() || operator.is_dot() {
|
||||
number += &raw;
|
||||
continue;
|
||||
} else if !number.is_empty() {
|
||||
operators.push(Operator::from_str(&number).unwrap());
|
||||
number.clear();
|
||||
}
|
||||
|
||||
if raw == "=" {
|
||||
@ -137,19 +145,14 @@ impl Tree {
|
||||
}
|
||||
|
||||
match operator {
|
||||
Operator::LeftSquareBracket => {
|
||||
square_brackets += 1;
|
||||
operators.push(Operator::Function("array".to_owned()));
|
||||
operators.push(operator);
|
||||
continue;
|
||||
}
|
||||
Operator::LeftParenthesis => {
|
||||
parenthesis += 1;
|
||||
|
||||
if !operators.is_empty() {
|
||||
let prev_operator = operators.pop().unwrap();
|
||||
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);
|
||||
continue;
|
||||
} else {
|
||||
@ -158,7 +161,6 @@ impl Tree {
|
||||
}
|
||||
}
|
||||
Operator::RightParenthesis => parenthesis -= 1,
|
||||
Operator::RightSquareBracket => square_brackets -= 1,
|
||||
Operator::WhiteSpace => continue,
|
||||
_ => (),
|
||||
}
|
||||
@ -167,7 +169,11 @@ impl Tree {
|
||||
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)
|
||||
} else {
|
||||
self.operators = operators;
|
||||
@ -193,6 +199,8 @@ impl Tree {
|
||||
Operator::And(priority) |
|
||||
Operator::Or(priority) |
|
||||
Operator::Le(priority) |
|
||||
Operator::Dot(priority) |
|
||||
Operator::LeftSquareBracket(priority) |
|
||||
Operator::Rem(priority) => {
|
||||
if !parsing_nodes.is_empty() {
|
||||
let prev = parsing_nodes.pop().unwrap();
|
||||
@ -215,15 +223,14 @@ impl Tree {
|
||||
}
|
||||
}
|
||||
Operator::Function(_) |
|
||||
Operator::LeftParenthesis |
|
||||
Operator::LeftSquareBracket => parsing_nodes.push(operator.to_node()),
|
||||
Operator::LeftParenthesis => parsing_nodes.push(operator.to_node()),
|
||||
Operator::Comma => close_comma(&mut parsing_nodes)?,
|
||||
Operator::RightParenthesis |
|
||||
Operator::RightSquareBracket => {
|
||||
close_bracket(&mut parsing_nodes, operator.get_left())?
|
||||
}
|
||||
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 {
|
||||
Value::Bool(boolean) => Ok(Value::Bool(!boolean)),
|
||||
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) => {
|
||||
@ -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)
|
||||
-> Result<(), Error> {
|
||||
let mut node = operator.to_node();
|
||||
node.closed = true;
|
||||
|
||||
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);
|
||||
} else if prev.is_enough() {
|
||||
parsing_nodes.push(prev);
|
||||
parsing_nodes.push(node);
|
||||
} else {
|
||||
} else if prev.operator.can_have_child() {
|
||||
prev.add_child(node);
|
||||
parsing_nodes.push(prev);
|
||||
} else {
|
||||
return Err(Error::CanNotAddChild);
|
||||
}
|
||||
} else {
|
||||
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 {
|
||||
let last = parsing_nodes.pop().unwrap();
|
||||
let mut prev = parsing_nodes.pop().unwrap();
|
||||
if prev.operator.can_have_child() {
|
||||
prev.add_child(last);
|
||||
parsing_nodes.push(prev);
|
||||
} else {
|
||||
return Err(Error::CanNotAddChild);
|
||||
}
|
||||
}
|
||||
|
||||
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 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() {
|
||||
prev.closed = true;
|
||||
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> {
|
||||
for context in contexts.iter().rev() {
|
||||
let value = get(context, key);
|
||||
match value {
|
||||
Some(_) => return value,
|
||||
match context.get(key) {
|
||||
Some(value) => return Some(value.clone()),
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
@ -513,23 +625,6 @@ fn find(contexts: &[Context], key: &str) -> Option<Value> {
|
||||
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 {
|
||||
ident.contains("..")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user