From ab4953130619c58f205206dc05503ea325c5ba5e Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 28 Mar 2019 11:46:40 +0100 Subject: [PATCH] Document chain operator Relates to #26 --- README.md | 56 +++++++++++++++++++++++++++++++++++++++--------------- src/lib.rs | 56 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 82 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 34aca65..703b182 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ Supported binary operators: | ^ | 120 | Exponentiation | | != | 80 | Not equal | | && | 75 | Logical and | | , | 40 | Aggregation | | || | 70 | Logical or | | = | 50 | Assignment | +| | | | | ; | 0 | Expression Chaining | Supported unary operators: @@ -141,6 +142,46 @@ use evalexpr::*; assert_eq!(eval("1, 2, 3"), Ok(Value::from(vec![Value::from(1), Value::from(2), Value::from(3)]))); ``` +#### The Assignment Operator + +This crate features the assignment operator, that allows expressions to store their result in a variable in the expression context. +If an expression uses the assignment operator, it must be evaluated with a mutable context. +Note that assignments are type safe, meaning if an identifier is assigned a value of a type once, it cannot be assigned a value of another type. + +```rust +use evalexpr::*; + +let mut context = HashMapContext::new(); +assert_eq!(eval_with_context("a = 5", &context), Err(EvalexprError::ContextNotManipulable)); +assert_eq!(eval_empty_with_context_mut("a = 5", &mut context), Ok(EMPTY_VALUE)); +assert_eq!(eval_empty_with_context_mut("a = 5.0", &mut context), Err(EvalexprError::expected_int(5.0.into()))); +assert_eq!(eval_int_with_context("a", &context), Ok(5)); +assert_eq!(context.get_value("a"), Some(5.into()).as_ref()); +``` + +#### The Expression Chaining Operator + +The expression chaining operator works as one would expect from programming languages that use the semicolon to end statements, like `Rust`, `C` or `Java`. +It has the special feature that it returns the value of the last expression in the expression chain. +If the last expression is terminated by a semicolon as well, then `Value::Empty` is returned. +Expression chaining is useful together with assignment to create small scripts. + +```rust +use evalexpr::*; + +let mut context = HashMapContext::new(); +assert_eq!(eval("1;2;3;4;"), Ok(Value::Empty)); +assert_eq!(eval("1;2;3;4"), Ok(4.into())); + +// Initialization of variables via script. +assert_eq!(eval_empty_with_context_mut("hp = 1; max_hp = 5; heal_amount = 3;", &mut context), Ok(EMPTY_VALUE)); +// Precompile healing script. +let healing_script = build_operator_tree("hp = min(hp + heal_amount, max_hp); hp").unwrap(); // Do proper error handling here +// Execute precompiled healing script. +assert_eq!(healing_script.eval_int_with_context_mut(&mut context), Ok(4)); +assert_eq!(healing_script.eval_int_with_context_mut(&mut context), Ok(5)); +``` + ### Builtin Functions This crate offers a set of builtin functions. @@ -251,21 +292,6 @@ Functions have a precedence of 190. | `true` | no | Expression is interpreted as `Value::Bool` | | `.34` | no | Expression is interpreted as `Value::Float` | -### Assignments - -This crate features the assignment operator, that allows expressions to store their result in a variable in the expression context. -If an expression uses the assignment operator, it must be evaluated with a mutable context. - -```rust -use evalexpr::*; - -let mut context = HashMapContext::new(); -assert_eq!(eval_with_context("a = 5", &context), Err(EvalexprError::ContextNotManipulable)); -assert_eq!(eval_empty_with_context_mut("a = 5", &mut context), Ok(EMPTY_VALUE)); -assert_eq!(eval_int_with_context("a", &context), Ok(5)); -assert_eq!(context.get_value("a"), Some(5.into()).as_ref()); -``` - ### [Serde](https://serde.rs) To use this crate with serde, the serde feature flag has to be set. diff --git a/src/lib.rs b/src/lib.rs index 9db038b..09c1f81 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,6 +108,7 @@ //! | ^ | 120 | Exponentiation | | != | 80 | Not equal | //! | && | 75 | Logical and | | , | 40 | Aggregation | //! | || | 70 | Logical or | | = | 50 | Assignment | +//! | | | | | ; | 0 | Expression Chaining | //! //! Supported unary operators: //! @@ -128,6 +129,46 @@ //! assert_eq!(eval("1, 2, 3"), Ok(Value::from(vec![Value::from(1), Value::from(2), Value::from(3)]))); //! ``` //! +//! #### The Assignment Operator +//! +//! This crate features the assignment operator, that allows expressions to store their result in a variable in the expression context. +//! If an expression uses the assignment operator, it must be evaluated with a mutable context. +//! Note that assignments are type safe, meaning if an identifier is assigned a value of a type once, it cannot be assigned a value of another type. +//! +//! ```rust +//! use evalexpr::*; +//! +//! let mut context = HashMapContext::new(); +//! assert_eq!(eval_with_context("a = 5", &context), Err(EvalexprError::ContextNotManipulable)); +//! assert_eq!(eval_empty_with_context_mut("a = 5", &mut context), Ok(EMPTY_VALUE)); +//! assert_eq!(eval_empty_with_context_mut("a = 5.0", &mut context), Err(EvalexprError::expected_int(5.0.into()))); +//! assert_eq!(eval_int_with_context("a", &context), Ok(5)); +//! assert_eq!(context.get_value("a"), Some(5.into()).as_ref()); +//! ``` +//! +//! #### The Expression Chaining Operator +//! +//! The expression chaining operator works as one would expect from programming languages that use the semicolon to end statements, like `Rust`, `C` or `Java`. +//! It has the special feature that it returns the value of the last expression in the expression chain. +//! If the last expression is terminated by a semicolon as well, then `Value::Empty` is returned. +//! Expression chaining is useful together with assignment to create small scripts. +//! +//! ```rust +//! use evalexpr::*; +//! +//! let mut context = HashMapContext::new(); +//! assert_eq!(eval("1;2;3;4;"), Ok(Value::Empty)); +//! assert_eq!(eval("1;2;3;4"), Ok(4.into())); +//! +//! // Initialization of variables via script. +//! assert_eq!(eval_empty_with_context_mut("hp = 1; max_hp = 5; heal_amount = 3;", &mut context), Ok(EMPTY_VALUE)); +//! // Precompile healing script. +//! let healing_script = build_operator_tree("hp = min(hp + heal_amount, max_hp); hp").unwrap(); // Do proper error handling here +//! // Execute precompiled healing script. +//! assert_eq!(healing_script.eval_int_with_context_mut(&mut context), Ok(4)); +//! assert_eq!(healing_script.eval_int_with_context_mut(&mut context), Ok(5)); +//! ``` +//! //! ### Builtin Functions //! //! This crate offers a set of builtin functions. @@ -238,21 +279,6 @@ //! | `true` | no | Expression is interpreted as `Value::Bool` | //! | `.34` | no | Expression is interpreted as `Value::Float` | //! -//! ### Assignments -//! -//! This crate features the assignment operator, that allows expressions to store their result in a variable in the expression context. -//! If an expression uses the assignment operator, it must be evaluated with a mutable context. -//! -//! ```rust -//! use evalexpr::*; -//! -//! let mut context = HashMapContext::new(); -//! assert_eq!(eval_with_context("a = 5", &context), Err(EvalexprError::ContextNotManipulable)); -//! assert_eq!(eval_empty_with_context_mut("a = 5", &mut context), Ok(EMPTY_VALUE)); -//! assert_eq!(eval_int_with_context("a", &context), Ok(5)); -//! assert_eq!(context.get_value("a"), Some(5.into()).as_ref()); -//! ``` -//! //! ### [Serde](https://serde.rs) //! //! To use this crate with serde, the serde feature flag has to be set.