Files
PowerToys/src/common/CalculatorEngineCommon/ExprtkEvaluator.cpp

71 lines
2.4 KiB
C++
Raw Normal View History

[CmdPal][AOT] Using ExprTk to make the Cal extension AOT-compatible (#39972) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR replaces the original Mages-based expression evaluation engine with a WinRT-wrapped version of Exprtk in the CmdPalCalculator module. ### Key Changes **Expression Engine:** - All expression parsing and evaluation now use Exprtk (via a WinRT wrapper) instead of Mages. **Base Conversion Handling:** - Since Exprtk does not support non-decimal (binary, octal, hexadecimal) input natively, added logic to convert all such inputs to decimal before evaluation. **Code Structure:** - The overall logic and API surface remain unchanged except for the engine and base conversion handling. - All previous Mages references and dependencies have been removed. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] **Closes:** #xxx - [ ] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end user facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2025-06-13 12:27:53 +08:00
#include "ExprtkEvaluator.h"
#include "exprtk.hpp"
#include <iomanip>
#include <iostream>
#include <sstream>
CmdPal: Make Calculator Great Again (#44594) ## Summary of the Pull Request This PR continues the tradition of alphabetical progress. After [MBGA](#41961), we move on to **MCBA — Make Calculator Better Again!** - Introduces limited automatic correction and completion of expressions. - The goal is to allow uninterrupted typing and avoid disruptions when a partially entered expression is temporarily invalid (which previously caused the result to be replaced by an error message or hidden by the fallback). - The implementation intentionally aims for a sweet spot: - Ignores trailing binary operators. - Automatically closes all opened parentheses. - It is not exhaustive; for example, incomplete constants or functions may still result in an invalid query. - Copy current result to the search bar. - Adds an option to copy the current result to the search bar when the user types `=` at the end of the expression. - Adds a new menu item for the same action. - Fixes the **Save** command to also copy the result to the query. - Adds support for the `factorial(x)` function and the `x!` expression. - Factorial calculations are supported up to `170!` (limited by `double`), but display is constrained by decimal conversion and allows direct display of results up to `20!`. - Adds support for the `sign(x)` function. - Adds support for the `π` symbol as an alternative to the `pi` constant. - Adds a context menu item to the result list item and fallback that displays the octal representation of the result. - Implements beautification of the query: - Converts technical symbols such as `*` or `/` to `×` or `÷`, respectively. - Not enabled for fallbacks for now, since the item text should match the query to keep the score intact. - Implements additional normalization of symbols in the query: - Percent: `%`, `%`, `﹪` - Minus: `−`, `-`, `–`, `—` - Factorial: `!`, `!` - Multiplication: `*`, `×`, `∗`, `·`, `⋅`, `✕`, `✖`, `\u2062` (invisible times) - Division: `/`, `÷`, `➗`, `:` - Allows use of `²` and `³` as alternatives to `^2` and `^3`. - Updates the unit test that was culture sensitive to force en-US output (not an actual fix, but at least it clears false positive for now) - Fixes pre-parsing of scientific notation to prevent capturing minus sign as part of it. - Fixes normalization/rounding of the result, so it can display small values (the current solution turned it into a string with scientific notation and couldn't parse it back). - Updates test with new cases ## Pictures? Moving! Previous behavior: https://github.com/user-attachments/assets/ebcdcd85-797a-44f9-a8b1-a0f2f33c6b42 New behavior: https://github.com/user-attachments/assets/5bd94663-a0d0-4d7d-8032-1030e79926c3 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #43481 - [x] Closes: #43460 - [x] Closes: #42078 - [x] Closes: #41839 - [x] Closes: #39659 - [x] Closes: #40502 - [x] Related to: #41715 <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2026-01-29 04:23:39 +01:00
#include <cmath>
#include <limits>
[CmdPal][AOT] Using ExprTk to make the Cal extension AOT-compatible (#39972) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR replaces the original Mages-based expression evaluation engine with a WinRT-wrapped version of Exprtk in the CmdPalCalculator module. ### Key Changes **Expression Engine:** - All expression parsing and evaluation now use Exprtk (via a WinRT wrapper) instead of Mages. **Base Conversion Handling:** - Since Exprtk does not support non-decimal (binary, octal, hexadecimal) input natively, added logic to convert all such inputs to decimal before evaluation. **Code Structure:** - The overall logic and API surface remain unchanged except for the engine and base conversion handling. - All previous Mages references and dependencies have been removed. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] **Closes:** #xxx - [ ] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end user facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2025-06-13 12:27:53 +08:00
namespace ExprtkCalculator::internal
{
CmdPal: Make Calculator Great Again (#44594) ## Summary of the Pull Request This PR continues the tradition of alphabetical progress. After [MBGA](#41961), we move on to **MCBA — Make Calculator Better Again!** - Introduces limited automatic correction and completion of expressions. - The goal is to allow uninterrupted typing and avoid disruptions when a partially entered expression is temporarily invalid (which previously caused the result to be replaced by an error message or hidden by the fallback). - The implementation intentionally aims for a sweet spot: - Ignores trailing binary operators. - Automatically closes all opened parentheses. - It is not exhaustive; for example, incomplete constants or functions may still result in an invalid query. - Copy current result to the search bar. - Adds an option to copy the current result to the search bar when the user types `=` at the end of the expression. - Adds a new menu item for the same action. - Fixes the **Save** command to also copy the result to the query. - Adds support for the `factorial(x)` function and the `x!` expression. - Factorial calculations are supported up to `170!` (limited by `double`), but display is constrained by decimal conversion and allows direct display of results up to `20!`. - Adds support for the `sign(x)` function. - Adds support for the `π` symbol as an alternative to the `pi` constant. - Adds a context menu item to the result list item and fallback that displays the octal representation of the result. - Implements beautification of the query: - Converts technical symbols such as `*` or `/` to `×` or `÷`, respectively. - Not enabled for fallbacks for now, since the item text should match the query to keep the score intact. - Implements additional normalization of symbols in the query: - Percent: `%`, `%`, `﹪` - Minus: `−`, `-`, `–`, `—` - Factorial: `!`, `!` - Multiplication: `*`, `×`, `∗`, `·`, `⋅`, `✕`, `✖`, `\u2062` (invisible times) - Division: `/`, `÷`, `➗`, `:` - Allows use of `²` and `³` as alternatives to `^2` and `^3`. - Updates the unit test that was culture sensitive to force en-US output (not an actual fix, but at least it clears false positive for now) - Fixes pre-parsing of scientific notation to prevent capturing minus sign as part of it. - Fixes normalization/rounding of the result, so it can display small values (the current solution turned it into a string with scientific notation and couldn't parse it back). - Updates test with new cases ## Pictures? Moving! Previous behavior: https://github.com/user-attachments/assets/ebcdcd85-797a-44f9-a8b1-a0f2f33c6b42 New behavior: https://github.com/user-attachments/assets/5bd94663-a0d0-4d7d-8032-1030e79926c3 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #43481 - [x] Closes: #43460 - [x] Closes: #42078 - [x] Closes: #41839 - [x] Closes: #39659 - [x] Closes: #40502 - [x] Related to: #41715 <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2026-01-29 04:23:39 +01:00
static double factorial(const double n)
{
// Only allow non-negative integers
if (n < 0.0 || std::floor(n) != n)
{
return std::numeric_limits<double>::quiet_NaN();
}
return std::tgamma(n + 1.0);
}
static double sign(const double n)
{
if (n > 0.0) return 1.0;
if (n < 0.0) return -1.0;
return 0.0;
}
[CmdPal][AOT] Using ExprTk to make the Cal extension AOT-compatible (#39972) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR replaces the original Mages-based expression evaluation engine with a WinRT-wrapped version of Exprtk in the CmdPalCalculator module. ### Key Changes **Expression Engine:** - All expression parsing and evaluation now use Exprtk (via a WinRT wrapper) instead of Mages. **Base Conversion Handling:** - Since Exprtk does not support non-decimal (binary, octal, hexadecimal) input natively, added logic to convert all such inputs to decimal before evaluation. **Code Structure:** - The overall logic and API surface remain unchanged except for the engine and base conversion handling. - All previous Mages references and dependencies have been removed. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] **Closes:** #xxx - [ ] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end user facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2025-06-13 12:27:53 +08:00
std::wstring ToWStringFullPrecision(double value)
{
std::wostringstream oss;
oss << std::fixed << std::setprecision(15) << value;
return oss.str();
}
std::wstring EvaluateExpression(
const std::string& expressionText,
const std::unordered_map<std::string, double>& constants)
{
exprtk::symbol_table<double> symbol_table;
for (auto const& [name, value] : constants)
{
symbol_table.add_constant(name, value);
}
CmdPal: Make Calculator Great Again (#44594) ## Summary of the Pull Request This PR continues the tradition of alphabetical progress. After [MBGA](#41961), we move on to **MCBA — Make Calculator Better Again!** - Introduces limited automatic correction and completion of expressions. - The goal is to allow uninterrupted typing and avoid disruptions when a partially entered expression is temporarily invalid (which previously caused the result to be replaced by an error message or hidden by the fallback). - The implementation intentionally aims for a sweet spot: - Ignores trailing binary operators. - Automatically closes all opened parentheses. - It is not exhaustive; for example, incomplete constants or functions may still result in an invalid query. - Copy current result to the search bar. - Adds an option to copy the current result to the search bar when the user types `=` at the end of the expression. - Adds a new menu item for the same action. - Fixes the **Save** command to also copy the result to the query. - Adds support for the `factorial(x)` function and the `x!` expression. - Factorial calculations are supported up to `170!` (limited by `double`), but display is constrained by decimal conversion and allows direct display of results up to `20!`. - Adds support for the `sign(x)` function. - Adds support for the `π` symbol as an alternative to the `pi` constant. - Adds a context menu item to the result list item and fallback that displays the octal representation of the result. - Implements beautification of the query: - Converts technical symbols such as `*` or `/` to `×` or `÷`, respectively. - Not enabled for fallbacks for now, since the item text should match the query to keep the score intact. - Implements additional normalization of symbols in the query: - Percent: `%`, `%`, `﹪` - Minus: `−`, `-`, `–`, `—` - Factorial: `!`, `!` - Multiplication: `*`, `×`, `∗`, `·`, `⋅`, `✕`, `✖`, `\u2062` (invisible times) - Division: `/`, `÷`, `➗`, `:` - Allows use of `²` and `³` as alternatives to `^2` and `^3`. - Updates the unit test that was culture sensitive to force en-US output (not an actual fix, but at least it clears false positive for now) - Fixes pre-parsing of scientific notation to prevent capturing minus sign as part of it. - Fixes normalization/rounding of the result, so it can display small values (the current solution turned it into a string with scientific notation and couldn't parse it back). - Updates test with new cases ## Pictures? Moving! Previous behavior: https://github.com/user-attachments/assets/ebcdcd85-797a-44f9-a8b1-a0f2f33c6b42 New behavior: https://github.com/user-attachments/assets/5bd94663-a0d0-4d7d-8032-1030e79926c3 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #43481 - [x] Closes: #43460 - [x] Closes: #42078 - [x] Closes: #41839 - [x] Closes: #39659 - [x] Closes: #40502 - [x] Related to: #41715 <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2026-01-29 04:23:39 +01:00
symbol_table.add_function("factorial", factorial);
symbol_table.add_function("sign", sign);
[CmdPal][AOT] Using ExprTk to make the Cal extension AOT-compatible (#39972) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR replaces the original Mages-based expression evaluation engine with a WinRT-wrapped version of Exprtk in the CmdPalCalculator module. ### Key Changes **Expression Engine:** - All expression parsing and evaluation now use Exprtk (via a WinRT wrapper) instead of Mages. **Base Conversion Handling:** - Since Exprtk does not support non-decimal (binary, octal, hexadecimal) input natively, added logic to convert all such inputs to decimal before evaluation. **Code Structure:** - The overall logic and API surface remain unchanged except for the engine and base conversion handling. - All previous Mages references and dependencies have been removed. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] **Closes:** #xxx - [ ] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end user facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2025-06-13 12:27:53 +08:00
exprtk::expression<double> expression;
expression.register_symbol_table(symbol_table);
exprtk::parser<double> parser;
// Enable all base functions and arithmetic operators
parser.settings().enable_all_base_functions(); // Enable all base functions like sin, cos, log, etc.
parser.settings().enable_all_arithmetic_ops(); // Enable all arithmetic operators like +, -, *, /, etc.
// Disable all control structures and assignment operators to ensure only expressions are evaluated
parser.settings().disable_all_control_structures(); // Disable control structures like if, for, while, etc.
parser.settings().disable_all_assignment_ops(); // Disable assignment operators like =, +=, -=, etc.
// Disabled for now, but can be enabled later for enhanced functionality
parser.settings().disable_all_logic_ops(); // Disable logical operators like &&, ||, !, etc.
parser.settings().disable_all_inequality_ops(); // Disable inequality operators like <, >, <=, >=, !=, etc.
if (!parser.compile(expressionText, expression))
return L"NaN";
return ToWStringFullPrecision(expression.value());
}
}