From 9d0a77634637cdf5ca1601afda20db6563dc541c Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 13 Apr 2023 14:21:44 +0300 Subject: [PATCH 01/11] Add test for powers of negative numbers. --- tests/integration.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/integration.rs b/tests/integration.rs index 6748fe3..1496477 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -2145,3 +2145,13 @@ fn test_variable_assignment_and_iteration() { variables.sort_unstable(); assert_eq!(variables, vec!["a".to_string(), "b".to_string()],); } + +#[test] +fn test_negative_power() { + assert_eq!(eval("3^-2"), Ok(Value::Float(1.0/9.0))); + assert_eq!(eval("3^(-2)"), Ok(Value::Float(1.0/9.0))); + assert_eq!(eval("-3^2"), Ok(Value::Float(-9.0))); + assert_eq!(eval("-(3)^2"), Ok(Value::Float(-9.0))); + assert_eq!(eval("(-3)^-2"), Ok(Value::Float(1.0/9.0))); + assert_eq!(eval("-(3^-2)"), Ok(Value::Float(-1.0/9.0))); +} \ No newline at end of file From 4fd86751dcfa6cd804a7f709a7f1517eda255a3c Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 13 Apr 2023 14:42:39 +0300 Subject: [PATCH 02/11] Fix unary operator precedence. Before, unary operators that appeared after an operator with higher precedence would be executed after that operator. However, in evalexpr, the two unary operators are prefix operators negation and not, and prefix operators always happen before operators directly left of them. --- src/operator/mod.rs | 5 +++++ src/tree/mod.rs | 20 ++++++++++++++------ tests/integration.rs | 11 ++++++----- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/operator/mod.rs b/src/operator/mod.rs index 5f2be51..13920e1 100644 --- a/src/operator/mod.rs +++ b/src/operator/mod.rs @@ -173,6 +173,11 @@ impl Operator { } } + /// Returns true if this operator is unary, i.e. it requires exactly one argument. + pub(crate) fn is_unary(&self) -> bool { + self.max_argument_amount() == Some(1) && *self != Operator::RootNode + } + /// Evaluates the operator with the given arguments and context. pub(crate) fn eval( &self, diff --git a/src/tree/mod.rs b/src/tree/mod.rs index c225994..a655386 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -459,8 +459,13 @@ impl Node { } fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> EvalexprResult<()> { - // println!("Inserting {:?} into {:?}", node.operator, self.operator()); - if self.operator().precedence() < node.operator().precedence() || is_root_node + println!( + "Inserting {:?} into {:?}, is_root_node = {is_root_node}", + node.operator(), + self.operator() + ); + println!("Self is {:?}", self); + if self.operator().precedence() < node.operator().precedence() || node.operator().is_unary() || is_root_node // Right-to-left chaining || (self.operator().precedence() == node.operator().precedence() && !self.operator().is_left_to_right() && !node.operator().is_left_to_right()) { @@ -471,19 +476,22 @@ impl Node { let last_child_operator = self.children.last().unwrap().operator(); if last_child_operator.precedence() - < node.operator().precedence() + < node.operator().precedence() || node.operator().is_unary() // Right-to-left chaining || (last_child_operator.precedence() == node.operator().precedence() && !last_child_operator.is_left_to_right() && !node.operator().is_left_to_right()) { - // println!("Recursing into {:?}", self.children.last().unwrap().operator()); + println!( + "Recursing into {:?}", + self.children.last().unwrap().operator() + ); // Unwrap cannot fail because is_leaf being false and has_enough_children being true implies that the operator wants and has at least one child self.children .last_mut() .unwrap() .insert_back_prioritized(node, false) } else { - // println!("Rotating"); + println!("Rotating"); if node.operator().is_leaf() { return Err(EvalexprError::AppendedToLeafNode); } @@ -521,7 +529,7 @@ impl Node { Ok(()) } } else { - // println!("Inserting as specified"); + println!("Inserting as specified"); self.children.push(node); Ok(()) } diff --git a/tests/integration.rs b/tests/integration.rs index 1496477..5786f2f 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -2148,10 +2148,11 @@ fn test_variable_assignment_and_iteration() { #[test] fn test_negative_power() { - assert_eq!(eval("3^-2"), Ok(Value::Float(1.0/9.0))); - assert_eq!(eval("3^(-2)"), Ok(Value::Float(1.0/9.0))); + println!("{:?}", build_operator_tree("3^-2").unwrap()); + assert_eq!(eval("3^-2"), Ok(Value::Float(1.0 / 9.0))); + assert_eq!(eval("3^(-2)"), Ok(Value::Float(1.0 / 9.0))); assert_eq!(eval("-3^2"), Ok(Value::Float(-9.0))); assert_eq!(eval("-(3)^2"), Ok(Value::Float(-9.0))); - assert_eq!(eval("(-3)^-2"), Ok(Value::Float(1.0/9.0))); - assert_eq!(eval("-(3^-2)"), Ok(Value::Float(-1.0/9.0))); -} \ No newline at end of file + assert_eq!(eval("(-3)^-2"), Ok(Value::Float(1.0 / 9.0))); + assert_eq!(eval("-(3^-2)"), Ok(Value::Float(-1.0 / 9.0))); +} From ab24e08f28b772c1b091665b7c50298224af14d5 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 13 Apr 2023 14:44:47 +0300 Subject: [PATCH 03/11] Remove superfluous printlns. --- src/tree/mod.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/tree/mod.rs b/src/tree/mod.rs index a655386..347f787 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -459,12 +459,12 @@ impl Node { } fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> EvalexprResult<()> { - println!( - "Inserting {:?} into {:?}, is_root_node = {is_root_node}", - node.operator(), - self.operator() - ); - println!("Self is {:?}", self); + // println!( + // "Inserting {:?} into {:?}, is_root_node = {is_root_node}", + // node.operator(), + // self.operator() + // ); + // println!("Self is {:?}", self); if self.operator().precedence() < node.operator().precedence() || node.operator().is_unary() || is_root_node // Right-to-left chaining || (self.operator().precedence() == node.operator().precedence() && !self.operator().is_left_to_right() && !node.operator().is_left_to_right()) @@ -481,17 +481,17 @@ impl Node { || (last_child_operator.precedence() == node.operator().precedence() && !last_child_operator.is_left_to_right() && !node.operator().is_left_to_right()) { - println!( - "Recursing into {:?}", - self.children.last().unwrap().operator() - ); + // println!( + // "Recursing into {:?}", + // self.children.last().unwrap().operator() + // ); // Unwrap cannot fail because is_leaf being false and has_enough_children being true implies that the operator wants and has at least one child self.children .last_mut() .unwrap() .insert_back_prioritized(node, false) } else { - println!("Rotating"); + // println!("Rotating"); if node.operator().is_leaf() { return Err(EvalexprError::AppendedToLeafNode); } @@ -529,7 +529,7 @@ impl Node { Ok(()) } } else { - println!("Inserting as specified"); + // println!("Inserting as specified"); self.children.push(node); Ok(()) } From 1e14ea14602d3ad66d053ac8fe325ac5ba3ec4c8 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 13 Apr 2023 14:47:22 +0300 Subject: [PATCH 04/11] Update changelog for bugfix release. --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e0c473..c60503f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,18 @@ ### Contributors +## [8.2.1](https://github.com/ISibboI/evalexpr/compare/8.2.0...8.2.1) - 2023-04-13 + +### Fixed + +* Taking numbers to negative powers gave unexpected results (#120) + +### Contributors + +My warmhearted thanks goes to: + +* [Pham Nhat Huy](https://github.com/012e) + ## [8.2.0](https://github.com/ISibboI/evalexpr/compare/8.1.0...8.2.0) - 2023-04-13 ### Added From d3741bfcf2d6f0d84593cdf7903063370822587a Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 13 Apr 2023 14:54:01 +0300 Subject: [PATCH 05/11] Update CI. --- .github/workflows/ci.yml | 235 +++++++++++++++++++++++++-------------- 1 file changed, 153 insertions(+), 82 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb46831..d6fb494 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,112 +1,183 @@ -name: Continuous Integration +name: CI -on: [push, pull_request] +on: + pull_request: + push: + +env: + RUSTFLAGS: -Dwarnings jobs: - build_test_format_lint: - name: ${{matrix.command.name}} (${{matrix.toolchain}}) - runs-on: ubuntu-latest + precheck_default: + name: Check default + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + rust: [stable] + steps: + - uses: actions/checkout@master + + - name: Install ${{ matrix.rust }} + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + components: rustfmt, clippy + override: true + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.os }} + + - name: Check + uses: actions-rs/cargo@v1 + with: + command: check + args: --all --bins --examples --lib + + precheck_all_features: + name: Check all features + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + rust: [stable] + + steps: + - uses: actions/checkout@master + + - name: Install ${{ matrix.rust }} + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + components: rustfmt, clippy + override: true + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.os }} + + - name: Check + uses: actions-rs/cargo@v1 + with: + command: check + args: --all-features --all --benches --bins --examples --tests --lib + + check_msrv: + needs: [precheck_default, precheck_all_features] + name: Check MSRV with all features + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest ] + rust: [ 1.46.0 ] + + steps: + - uses: actions/checkout@master + + - name: Install ${{ matrix.rust }} + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + components: rustfmt, clippy + override: true + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.os }} + + - name: Check + uses: actions-rs/cargo@v1 + with: + command: check + args: --all-features --all --benches --bins --examples --tests --lib + + check_platform_compatibility: + needs: [precheck_default, precheck_all_features] + name: Check platform compatibility + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - toolchain: [stable, beta, nightly, 1.46.0] - command: - - name: Check - command: check - args: --all-features - components: "" - - name: Test - command: test - args: --all-features - components: "" - include: - - toolchain: nightly - command: - name: Format - command: fmt - args: --all -- --check - components: rustfmt - - toolchain: nightly - command: - name: Lint - command: clippy - args: --all-features --tests --benches - components: clippy - - toolchain: stable - command: - name: Sync readme - command: sync-readme - args: --check + os: [ubuntu-latest, macOS-latest, windows-latest] + rust: [stable] steps: - - uses: actions/checkout@v2 - - name: ⚡ Cache - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + - uses: actions/checkout@master - - name: Install toolchain + - name: Install ${{ matrix.rust }} uses: actions-rs/toolchain@v1 with: - toolchain: ${{ matrix.toolchain }} + toolchain: ${{ matrix.rust }} + components: rustfmt, clippy override: true - default: true - components: ${{matrix.command.components}} - - name: Install cargo-sync-readme + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.os }} + + - name: Check uses: actions-rs/cargo@v1 with: - command: install - args: cargo-sync-readme + command: check + args: --all-features --all --benches --bins --examples --tests --lib - - name: ${{matrix.command.name}} - uses: actions-rs/cargo@v1 - with: - command: ${{matrix.command.command}} - args: ${{matrix.command.args}} - - coveralls_io: - name: Coverage - runs-on: ubuntu-latest + detailed_tests: + needs: [precheck_default, precheck_all_features] + name: Check, test, doc, format and lint with all features + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + rust: [stable, beta, nightly] steps: - - uses: actions/checkout@v2 - - name: ⚡ Cache - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + - uses: actions/checkout@master - - name: Install toolchain + - name: Install ${{ matrix.rust }} uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: ${{ matrix.rust }} + components: rustfmt, clippy override: true - default: true - - name: Install cargo-tarpaulin - uses: actions-rs/install@v0.1 + - name: Rust cache + uses: Swatinem/rust-cache@v2 with: - crate: cargo-tarpaulin - version: latest - use-tool-cache: true + key: ${{ matrix.os }} - - name: Coverage Report with tarpaulin + - name: Check uses: actions-rs/cargo@v1 with: - command: tarpaulin - args: --all --all-features --out Lcov -- --test-threads 1 + command: check + args: --all-features --all --benches --bins --examples --tests --lib - - name: Upload Coverage - uses: coverallsapp/github-action@master + - name: Test + uses: actions-rs/cargo@v1 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - path-to-lcov: ./lcov.info \ No newline at end of file + command: test + args: --all-features --all + + - name: Docs + uses: actions-rs/cargo@v1 + with: + command: doc + args: --all-features + + - name: Format + uses: actions-rs/cargo@v1 + with: + command: fmt + args: -- --check + + - name: Lint + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all-features --all-targets \ No newline at end of file From be0e99ffdd1bb6613fd2188d65e24afe2baa2822 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 13 Apr 2023 14:57:39 +0300 Subject: [PATCH 06/11] Update CI. --- .github/workflows/ci.yml | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6fb494..5e1c311 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,7 +64,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: check - args: --all-features --all --benches --bins --examples --tests --lib + args: --all-features --all --bins --examples --tests --lib check_msrv: needs: [precheck_default, precheck_all_features] @@ -94,7 +94,37 @@ jobs: uses: actions-rs/cargo@v1 with: command: check - args: --all-features --all --benches --bins --examples --tests --lib + args: --all-features --all --bins --examples --tests --lib + + check_benches: + needs: [precheck_default, precheck_all_features] + name: Check benches with all features + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest ] + rust: [ nightly ] + + steps: + - uses: actions/checkout@master + + - name: Install ${{ matrix.rust }} + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + components: rustfmt, clippy + override: true + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.os }} + + - name: Check + uses: actions-rs/cargo@v1 + with: + command: check + args: --all-features --all --bins --benches --examples --tests --lib check_platform_compatibility: needs: [precheck_default, precheck_all_features] @@ -125,7 +155,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: check - args: --all-features --all --benches --bins --examples --tests --lib + args: --all-features --all --bins --examples --tests --lib detailed_tests: needs: [precheck_default, precheck_all_features] @@ -156,7 +186,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: check - args: --all-features --all --benches --bins --examples --tests --lib + args: --all-features --all --bins --examples --tests --lib - name: Test uses: actions-rs/cargo@v1 From 1a90ec5f22f1c8c10ce5a84d7b2cf3d9b247db80 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 13 Apr 2023 15:00:55 +0300 Subject: [PATCH 07/11] Update CI. --- .github/workflows/ci.yml | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e1c311..f7e8ff3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,6 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.rust }} - components: rustfmt, clippy override: true - name: Rust cache @@ -52,7 +51,6 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.rust }} - components: rustfmt, clippy override: true - name: Rust cache @@ -82,7 +80,6 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.rust }} - components: rustfmt, clippy override: true - name: Rust cache @@ -112,7 +109,6 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.rust }} - components: rustfmt, clippy override: true - name: Rust cache @@ -126,6 +122,41 @@ jobs: command: check args: --all-features --all --bins --benches --examples --tests --lib + check_sync_readme: + needs: [precheck_default, precheck_all_features] + name: Check sync readme + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest ] + rust: [ stable ] + + steps: + - uses: actions/checkout@master + + - name: Install ${{ matrix.rust }} + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + override: true + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.os }} + + - name: Install cargo-sync-readme + uses: actions-rs/cargo@v1 + with: + command: install + args: cargo-sync-readme + + - name: Sync readme check + uses: actions-rs/cargo@v1 + with: + command: sync-readme + args: --check + check_platform_compatibility: needs: [precheck_default, precheck_all_features] name: Check platform compatibility @@ -143,7 +174,6 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.rust }} - components: rustfmt, clippy override: true - name: Rust cache From d6c09ef7367c4dedd4ae6d6ebbfaa6d4bdb38b8e Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 13 Apr 2023 15:25:47 +0300 Subject: [PATCH 08/11] Update MSRV. --- .github/workflows/ci.yml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7e8ff3..b78de14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,7 @@ jobs: strategy: matrix: os: [ ubuntu-latest ] - rust: [ 1.46.0 ] + rust: [ 1.56.1 ] steps: - uses: actions/checkout@master diff --git a/Cargo.toml b/Cargo.toml index 2e38a1e..3ff05fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/evalexpr" readme = "README.md" license = "MIT" edition = "2018" -rust-version = "1.46.0" +rust-version = "1.56.1" [badges] maintenance = { status = "actively-developed" } From 7ef9306ce36ada4c0a30b1620a709784295745d1 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 13 Apr 2023 15:31:57 +0300 Subject: [PATCH 09/11] Update CI. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b78de14..270a623 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -240,4 +240,4 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy - args: --all-features --all-targets \ No newline at end of file + args: --all-features --bins --examples --tests --lib \ No newline at end of file From 791ac540d2396ea37fb11d4e0695923d93cbd051 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 13 Apr 2023 15:46:44 +0300 Subject: [PATCH 10/11] Update CI. --- .github/workflows/ci.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 270a623..055c3d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,25 +67,19 @@ jobs: check_msrv: needs: [precheck_default, precheck_all_features] name: Check MSRV with all features - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ ubuntu-latest ] - rust: [ 1.56.1 ] + runs-on: ubuntu-latest steps: - uses: actions/checkout@master - - name: Install ${{ matrix.rust }} + - name: Install MSRV toolchain uses: actions-rs/toolchain@v1 with: - toolchain: ${{ matrix.rust }} + toolchain: 1.56.1 override: true - name: Rust cache uses: Swatinem/rust-cache@v2 - with: - key: ${{ matrix.os }} - name: Check uses: actions-rs/cargo@v1 From 87e609ed99fd72dd4cad8893f8c4bb5631450422 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Thu, 13 Apr 2023 15:48:45 +0300 Subject: [PATCH 11/11] Update changelog for 9.0.0 release. --- CHANGELOG.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c60503f..6164f3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,17 +16,18 @@ ### Contributors -## [8.2.1](https://github.com/ISibboI/evalexpr/compare/8.2.0...8.2.1) - 2023-04-13 +## [9.0.0](https://github.com/ISibboI/evalexpr/compare/8.2.0...9.0.0) - 2023-04-13 ### Fixed -* Taking numbers to negative powers gave unexpected results (#120) + * Taking numbers to negative powers gave unexpected results (#120) + * **Update MSRV to 1.56.1 (2021 edition release)** to allow builds with the latest versions of all dependencies. ### Contributors My warmhearted thanks goes to: -* [Pham Nhat Huy](https://github.com/012e) + * [Pham Nhat Huy](https://github.com/012e) ## [8.2.0](https://github.com/ISibboI/evalexpr/compare/8.1.0...8.2.0) - 2023-04-13 @@ -42,8 +43,8 @@ My warmhearted thanks goes to: My warmhearted thanks goes to: -* [Natan Freeman](https://github.com/NatanFreeman) -* [Claus Matzinger](https://github.com/celaus) + * [Natan Freeman](https://github.com/NatanFreeman) + * [Claus Matzinger](https://github.com/celaus) ## [8.1.0](https://github.com/ISibboI/evalexpr/compare/8.0.0...8.1.0) - 2022-07-22