From 6237104c5acb3238a8eeb3abd682c7162c76c485 Mon Sep 17 00:00:00 2001 From: miroiu Date: Tue, 23 Jan 2024 20:48:54 +0200 Subject: [PATCH 1/6] Fix unnecessary allocations --- StringMath/MathContext.cs | 49 ++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/StringMath/MathContext.cs b/StringMath/MathContext.cs index 371eebd..4f7b6ee 100644 --- a/StringMath/MathContext.cs +++ b/StringMath/MathContext.cs @@ -10,7 +10,6 @@ public sealed class MathContext : IMathContext private readonly Dictionary> _binaryEvaluators = new Dictionary>(StringComparer.Ordinal); private readonly Dictionary> _unaryEvaluators = new Dictionary>(StringComparer.Ordinal); private readonly Dictionary _binaryPrecedence = new Dictionary(StringComparer.Ordinal); - private readonly HashSet _operators = new HashSet(StringComparer.Ordinal); /// The global instance used by methods. public static readonly IMathContext Default = new MathContext(); @@ -28,25 +27,25 @@ static MathContext() Default.RegisterBinary("*", (a, b) => a * b, Precedence.Multiplication); Default.RegisterBinary("/", (a, b) => a / b, Precedence.Multiplication); Default.RegisterBinary("%", (a, b) => a % b, Precedence.Multiplication); - Default.RegisterBinary("^", (a, b) => Math.Pow(a, b), Precedence.Power); - Default.RegisterBinary("log", (a, b) => Math.Log(a, b), Precedence.Logarithmic); - Default.RegisterBinary("max", (a, b) => Math.Max(a, b), Precedence.UserDefined); - Default.RegisterBinary("min", (a, b) => Math.Min(a, b), Precedence.UserDefined); + Default.RegisterBinary("^", Math.Pow, Precedence.Power); + Default.RegisterBinary("log", Math.Log, Precedence.Logarithmic); + Default.RegisterBinary("max", Math.Max, Precedence.UserDefined); + Default.RegisterBinary("min", Math.Min, Precedence.UserDefined); Default.RegisterUnary("-", a => -a); - Default.RegisterUnary("!", a => ComputeFactorial(a)); - Default.RegisterUnary("sqrt", a => Math.Sqrt(a)); - Default.RegisterUnary("sin", a => Math.Sin(a)); - Default.RegisterUnary("asin", a => Math.Asin(a)); - Default.RegisterUnary("cos", a => Math.Cos(a)); - Default.RegisterUnary("acos", a => Math.Acos(a)); - Default.RegisterUnary("tan", a => Math.Tan(a)); - Default.RegisterUnary("atan", a => Math.Atan(a)); - Default.RegisterUnary("ceil", a => Math.Ceiling(a)); - Default.RegisterUnary("floor", a => Math.Floor(a)); - Default.RegisterUnary("round", a => Math.Round(a)); - Default.RegisterUnary("exp", a => Math.Exp(a)); - Default.RegisterUnary("abs", a => Math.Abs(a)); + Default.RegisterUnary("!", ComputeFactorial); + Default.RegisterUnary("sqrt", Math.Sqrt); + Default.RegisterUnary("sin", Math.Sin); + Default.RegisterUnary("asin", Math.Asin); + Default.RegisterUnary("cos", Math.Cos); + Default.RegisterUnary("acos", Math.Acos); + Default.RegisterUnary("tan", Math.Tan); + Default.RegisterUnary("atan", Math.Atan); + Default.RegisterUnary("ceil", Math.Ceiling); + Default.RegisterUnary("floor", Math.Floor); + Default.RegisterUnary("round", Math.Round); + Default.RegisterUnary("exp", Math.Exp); + Default.RegisterUnary("abs", Math.Abs); Default.RegisterUnary("rad", a => rad * a); Default.RegisterUnary("deg", a => deg * a); } @@ -70,8 +69,8 @@ public bool IsBinary(string operatorName) /// public Precedence GetBinaryPrecedence(string operatorName) { - return _binaryPrecedence.ContainsKey(operatorName) - ? _binaryPrecedence[operatorName] + return _binaryPrecedence.TryGetValue(operatorName, out var value) + ? value : Parent?.GetBinaryPrecedence(operatorName) ?? throw MathException.MissingBinaryOperator(operatorName); } @@ -84,7 +83,6 @@ public void RegisterBinary(string operatorName, Func ope _binaryEvaluators[operatorName] = operation; _binaryPrecedence[operatorName] = precedence ?? Precedence.UserDefined; - _operators.Add(operatorName); } /// @@ -94,14 +92,13 @@ public void RegisterUnary(string operatorName, Func operation) operation.EnsureNotNull(nameof(operation)); _unaryEvaluators[operatorName] = operation; - _operators.Add(operatorName); } /// public double EvaluateBinary(string op, double a, double b) { - double result = _binaryEvaluators.ContainsKey(op) - ? _binaryEvaluators[op](a, b) + double result = _binaryEvaluators.TryGetValue(op, out var value) + ? value(a, b) : Parent?.EvaluateBinary(op, a, b) ?? throw MathException.MissingBinaryOperator(op); @@ -111,8 +108,8 @@ public double EvaluateBinary(string op, double a, double b) /// public double EvaluateUnary(string op, double a) { - double result = _unaryEvaluators.ContainsKey(op) - ? _unaryEvaluators[op](a) + double result = _unaryEvaluators.TryGetValue(op, out var value) + ? value(a) : Parent?.EvaluateUnary(op, a) ?? throw MathException.MissingUnaryOperator(op); From b93a28d3f2eefd56bf0dc48500982154fd1b372c Mon Sep 17 00:00:00 2001 From: Emanuel Miroiu Date: Wed, 24 Apr 2024 10:05:10 +0300 Subject: [PATCH 2/6] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7bc2fe..fd46493 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > **NEW!** Boolean math example: https://github.com/miroiu/string-math/pull/6/files -# String Math [![NuGet](https://img.shields.io/nuget/v/StringMath?style=flat-square&logo=nuget)](https://www.nuget.org/packages/StringMath/) [![Downloads](https://img.shields.io/nuget/dt/StringMath?label=downloads&style=flat-square&logo=nuget)](https://www.nuget.org/packages/StringMath) ![.NET](https://img.shields.io/static/v1?label=%20&message=Framework%204.6.1%20to%20NET%206&color=5C2D91&style=flat-square&logo=.net) ![](https://img.shields.io/static/v1?label=%20&message=documentation&color=yellow&style=flat-square) +# String Math [![NuGet](https://img.shields.io/nuget/v/StringMath?style=flat-square&logo=nuget)](https://www.nuget.org/packages/StringMath/) [![Downloads](https://img.shields.io/nuget/dt/StringMath?label=downloads&style=flat-square&logo=nuget)](https://www.nuget.org/packages/StringMath) ![.NET](https://img.shields.io/static/v1?label=%20&message=Framework%204.6.1%20to%20NET%208&color=5C2D91&style=flat-square&logo=.net) ![](https://img.shields.io/static/v1?label=%20&message=documentation&color=yellow&style=flat-square) Calculates the value of a math expression from a string returning a double. Supports variables, user defined operators and expression compilation. From b809543496c7dc35f203462b203560399761883d Mon Sep 17 00:00:00 2001 From: miroiu Date: Tue, 1 Jul 2025 17:44:01 +0300 Subject: [PATCH 3/6] Fix binary + unary operator without space not parsing correctly --- StringMath.Benchmarks/Benchmarks.cs | 9 +++++--- StringMath.Tests/Extensions.cs | 4 ++-- StringMath.Tests/MathExprTests.cs | 3 ++- StringMath.Tests/ParserTests.cs | 32 ++++++++++++++++------------- StringMath.Tests/TokenizerTests.cs | 26 ++++++++++++++++------- StringMath/Extensions.cs | 2 +- StringMath/Parser/SourceText.cs | 2 +- StringMath/Parser/Tokenizer.cs | 29 ++++++++++++++++++++++++-- 8 files changed, 76 insertions(+), 31 deletions(-) diff --git a/StringMath.Benchmarks/Benchmarks.cs b/StringMath.Benchmarks/Benchmarks.cs index 32e3d5c..a629286 100644 --- a/StringMath.Benchmarks/Benchmarks.cs +++ b/StringMath.Benchmarks/Benchmarks.cs @@ -10,7 +10,9 @@ public class Benchmarks [Benchmark] public void Tokenize() { - var tokenizer = new Tokenizer("1.23235456576878798 - ((3 + {b}) max .1) ^ sqrt(-999 / 2 * 3 max 5) + !5 - 0.00000000002 / {ahghghh}"); + var context = MathContext.Default; + + var tokenizer = new Tokenizer("1.23235456576878798 - ((3 + {b}) max .1) ^ sqrt(-999 / 2 * 3 max 5) + !5 - 0.00000000002 / {ahghghh}", context); Token token; @@ -24,8 +26,9 @@ public void Tokenize() [Benchmark] public void Parse() { - var tokenizer = new Tokenizer("1.23235456576878798 - ((3 + {b}) max .1) ^ sqrt(-999 / 2 * 3 max 5) + !5 - 0.00000000002 / {ahghghh}"); - var parser = new Parser(tokenizer, MathContext.Default); + var context = MathContext.Default; + var tokenizer = new Tokenizer("1.23235456576878798 - ((3 + {b}) max .1) ^ sqrt(-999 / 2 * 3 max 5) + !5 - 0.00000000002 / {ahghghh}", context); + var parser = new Parser(tokenizer, context); _ = parser.Parse(); } diff --git a/StringMath.Tests/Extensions.cs b/StringMath.Tests/Extensions.cs index aa3c6d3..c90f5e3 100644 --- a/StringMath.Tests/Extensions.cs +++ b/StringMath.Tests/Extensions.cs @@ -4,9 +4,9 @@ namespace StringMath.Tests { static class Extensions { - public static List ReadAllTokens(this string input) + public static List ReadAllTokens(this string input, IMathContext context) { - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, context); List tokens = new List(); Token t; diff --git a/StringMath.Tests/MathExprTests.cs b/StringMath.Tests/MathExprTests.cs index 670f5e1..def060e 100644 --- a/StringMath.Tests/MathExprTests.cs +++ b/StringMath.Tests/MathExprTests.cs @@ -154,10 +154,11 @@ public void SetOperator_Unary_Should_Not_Overwrite_Global_Operator() [TestCase("1 + sqrt 4", 3)] [TestCase("sind(90) + sind 30", 1.5)] [TestCase("((1 + 1) + ((1 + 1) + (((1) + 1)) + 1))", 7)] + [TestCase("719.04+sin(60)", 718.735d)] public void Evaluate(string input, double expected) { double result = input.Eval(); - Assert.AreEqual(expected, result); + Assert.AreEqual(expected, result, 0.001); } [TestCase("{b}+3*{a}", 3, 2, 11)] diff --git a/StringMath.Tests/ParserTests.cs b/StringMath.Tests/ParserTests.cs index b1821a4..eabe901 100644 --- a/StringMath.Tests/ParserTests.cs +++ b/StringMath.Tests/ParserTests.cs @@ -23,9 +23,12 @@ public void Setup() [TestCase("1.15215345346", "1.15215345346")] [TestCase("0", "0")] [TestCase("!2", "2!")] + [TestCase("--1", "-(-1)")] + [TestCase("1+sin(3)", "1 + sin(3)")] + [TestCase("1+sin 3", "1 + sin(3)")] public void ParseMathExpression(string input, string expected) { - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); Parser parser = new Parser(tokenizer, _context); IExpression result = parser.Parse(); @@ -56,8 +59,9 @@ public void ParseMathExpression(string input, string expected) [TestCase("1+")] [TestCase("1.")] [TestCase("1..1")] - [TestCase("--1")] + [TestCase("-*1")] [TestCase("-+1")] + [TestCase("+-1")] [TestCase("{")] [TestCase("}")] [TestCase("asd")] @@ -67,7 +71,7 @@ public void ParseMathExpression(string input, string expected) [TestCase("1 + 2 1")] public void ParseBadExpression_Exception(string input) { - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); Parser parser = new Parser(tokenizer, _context); MathException exception = Assert.Throws(() => parser.Parse()); @@ -84,7 +88,7 @@ public void ParseExpression_CustomOperators(string input, string expected) context.RegisterBinary("pow", (a, b) => a); context.RegisterUnary("rand", (a) => a); - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); Parser parser = new Parser(tokenizer, context); IExpression result = parser.Parse(); @@ -100,7 +104,7 @@ public void ParseExpression_CustomOperators_Exception(string expected) { MathContext context = new MathContext(); - Tokenizer tokenizer = new Tokenizer(expected); + Tokenizer tokenizer = new Tokenizer(expected, _context); Parser parser = new Parser(tokenizer, context); MathException exception = Assert.Throws(() => parser.Parse()); @@ -119,7 +123,7 @@ public void ParseExpression_CustomOperators_Exception(string expected) [TestCase("{a13}", "a13")] public void ParseVariableExpression(string expected, string name) { - Tokenizer tokenizer = new Tokenizer(expected); + Tokenizer tokenizer = new Tokenizer(expected, _context); Parser parser = new Parser(tokenizer, _context); IExpression result = parser.Parse(); @@ -139,7 +143,7 @@ public void ParseVariableExpression(string expected, string name) [TestCase("{-a}")] public void ParseVariableExpression_Exception(string expected) { - Tokenizer tokenizer = new Tokenizer(expected); + Tokenizer tokenizer = new Tokenizer(expected, _context); Parser parser = new Parser(tokenizer, _context); MathException exception = Assert.Throws(() => parser.Parse()); @@ -159,7 +163,7 @@ public void ParseVariableExpression_Exception(string expected) [TestCase("1 / 2 / 3", "1 / 2 / 3")] public void ParseBinaryExpression(string input, string expected) { - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); Parser parser = new Parser(tokenizer, _context); IExpression result = parser.Parse(); @@ -183,7 +187,7 @@ public void ParseBinaryExpression(string input, string expected) [TestCase("sqrt{a}", "sqrt({a})")] public void ParseUnaryExpression(string input, string expected) { - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); Parser parser = new Parser(tokenizer, _context); IExpression result = parser.Parse(); @@ -199,7 +203,7 @@ public void ParseUnaryExpression(string input, string expected) [TestCase("+5")] public void ParseUnaryExpression_Exception(string input) { - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); Parser parser = new Parser(tokenizer, _context); MathException exception = Assert.Throws(() => parser.Parse()); @@ -213,7 +217,7 @@ public void ParseUnaryExpression_Exception(string input) [TestCase("9999999", "9999999")] public void ParseConstantExpression(string input, string expected) { - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); Parser parser = new Parser(tokenizer, _context); IExpression result = parser.Parse(); @@ -231,7 +235,7 @@ public void ParseConstantExpression(string input, string expected) [TestCase("9.01+")] public void ParseConstantExpression_Exception(string expected) { - Tokenizer tokenizer = new Tokenizer(expected); + Tokenizer tokenizer = new Tokenizer(expected, _context); Parser parser = new Parser(tokenizer, _context); MathException exception = Assert.Throws(() => parser.Parse()); @@ -250,7 +254,7 @@ public void ParseConstantExpression_Exception(string expected) [TestCase("((5 - 2) + ((-1 + 2) * 3))", "5 - 2 + (-1 + 2) * 3")] public void ParseGroupingExpression(string input, string expected) { - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); Parser parser = new Parser(tokenizer, _context); IExpression result = parser.Parse(); @@ -271,7 +275,7 @@ public void ParseGroupingExpression(string input, string expected) [TestCase("({a} + (1 + 2)")] public void ParseGroupingExpression_Fail(string expected) { - Tokenizer tokenizer = new Tokenizer(expected); + Tokenizer tokenizer = new Tokenizer(expected, _context); Parser parser = new Parser(tokenizer, _context); MathException exception = Assert.Throws(() => parser.Parse()); diff --git a/StringMath.Tests/TokenizerTests.cs b/StringMath.Tests/TokenizerTests.cs index a9759ea..d295e44 100644 --- a/StringMath.Tests/TokenizerTests.cs +++ b/StringMath.Tests/TokenizerTests.cs @@ -7,15 +7,25 @@ namespace StringMath.Tests [TestFixture] internal class TokenizerTests { + private IMathContext _context; + + [OneTimeSetUp] + public void Setup() + { + _context = MathContext.Default; + } + [Test] [TestCase("-1 * 3.5", new[] { TokenType.Operator, TokenType.Number, TokenType.Operator, TokenType.Number })] [TestCase("2 pow 3", new[] { TokenType.Number, TokenType.Operator, TokenType.Number })] [TestCase("{a} + 2", new[] { TokenType.Identifier, TokenType.Operator, TokenType.Number })] [TestCase("(-1) + 2", new[] { TokenType.OpenParen, TokenType.Operator, TokenType.Number, TokenType.CloseParen, TokenType.Operator, TokenType.Number })] [TestCase("5!", new[] { TokenType.Number, TokenType.Exclamation })] + [TestCase("1+sin(3)", new[] { TokenType.Number, TokenType.Operator, TokenType.Operator, TokenType.OpenParen, TokenType.Number, TokenType.CloseParen })] + [TestCase("1+sin 3", new[] { TokenType.Number, TokenType.Operator, TokenType.Operator, TokenType.Number })] public void ReadToken(string input, TokenType[] expected) { - IEnumerable actualTokens = input.ReadAllTokens() + IEnumerable actualTokens = input.ReadAllTokens(_context) .Where(token => token.Type != TokenType.EndOfCode) .Select(t => t.Type); Assert.That(actualTokens, Is.EquivalentTo(expected)); @@ -29,7 +39,7 @@ public void ReadToken(string input, TokenType[] expected) public void ReadToken_IgnoresWhitespace(string input) { // Arrange - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); // Act Token token1 = tokenizer.ReadToken(); @@ -53,7 +63,7 @@ public void ReadToken_IgnoresWhitespace(string input) public void ReadIdentifier(string input) { // Arrange - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); // Act Token token = tokenizer.ReadToken(); @@ -75,7 +85,7 @@ public void ReadIdentifier(string input) public void ReadIdentifier_Exception(string input) { // Arrange - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); // Act & Assert MathException exception = Assert.Throws(() => tokenizer.ReadToken()); @@ -91,8 +101,10 @@ public void ReadIdentifier_Exception(string input) [TestCase("a@a")] public void ReadOperator(string input) { + _context.RegisterBinary("**", (a, b) => a * b, Precedence.Multiplication); + // Arrange - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); // Act Token token = tokenizer.ReadToken(); @@ -113,7 +125,7 @@ public void ReadOperator(string input) public void ReadNumber(string input) { // Arrange - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); // Act Token token = tokenizer.ReadToken(); @@ -133,7 +145,7 @@ public void ReadNumber(string input) public void ReadNumber_Exception(string input) { // Arrange - Tokenizer tokenizer = new Tokenizer(input); + Tokenizer tokenizer = new Tokenizer(input, _context); // Act & Assert MathException exception = Assert.Throws(() => tokenizer.ReadToken()); diff --git a/StringMath/Extensions.cs b/StringMath/Extensions.cs index 3469763..aa5e39e 100644 --- a/StringMath/Extensions.cs +++ b/StringMath/Extensions.cs @@ -40,7 +40,7 @@ public static IExpression Parse(this string text, IMathContext context) { text.EnsureNotNull(nameof(text)); - Tokenizer tokenizer = new Tokenizer(text); + Tokenizer tokenizer = new Tokenizer(text, context); Parser parser = new Parser(tokenizer, context); return parser.Parse(); } diff --git a/StringMath/Parser/SourceText.cs b/StringMath/Parser/SourceText.cs index 3fda914..8d7b2a7 100644 --- a/StringMath/Parser/SourceText.cs +++ b/StringMath/Parser/SourceText.cs @@ -6,7 +6,7 @@ namespace StringMath internal sealed class SourceText : IEnumerator { public string Text { get; } - public int Position { get; private set; } + public int Position { get; set; } public char Current => Text[Position]; object IEnumerator.Current => Current; diff --git a/StringMath/Parser/Tokenizer.cs b/StringMath/Parser/Tokenizer.cs index c24eb49..48e11e0 100644 --- a/StringMath/Parser/Tokenizer.cs +++ b/StringMath/Parser/Tokenizer.cs @@ -7,6 +7,7 @@ namespace StringMath internal sealed partial class Tokenizer { private readonly SourceText _text; + private readonly IMathContext _context; // Excluded characters for custom operators private static readonly HashSet _invalidOperatorCharacters = new HashSet @@ -16,14 +17,17 @@ internal sealed partial class Tokenizer /// Creates a new instance of the tokenizer. /// The text to tokenize. - public Tokenizer(SourceText text) + /// The math context. + public Tokenizer(SourceText text, IMathContext context) { _text = text; + _context = context; } /// Creates a new instance of the tokenizer. /// The text to tokenize. - public Tokenizer(string text) : this(new SourceText(text)) + /// The math context. + public Tokenizer(string text, IMathContext context) : this(new SourceText(text), context) { } @@ -139,9 +143,30 @@ private string ReadOperator(SourceText stream) stream.MoveNext(); } + string op = builder.ToString(); + if (IsOperator(op)) + { + return builder.ToString(); + } + + for (int i = 0; i < op.Length; i++) + { + var possibleOperator = builder.ToString(0, i); + if (IsOperator(possibleOperator)) + { + stream.Position -= op.Length - i; + return possibleOperator; + } + } + return builder.ToString(); } + private bool IsOperator(string text) + { + return _context.IsBinary(text) || _context.IsUnary(text); + } + private string ReadNumber(SourceText stream) { StringBuilder builder = new StringBuilder(8); From 04499a6a3e114749e364b28a6fe5d706de0c6762 Mon Sep 17 00:00:00 2001 From: Emanuel Miroiu Date: Tue, 1 Jul 2025 18:18:33 +0300 Subject: [PATCH 4/6] Update dotnet.yml --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index e02a66f..0eb1189 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -9,7 +9,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: windows-latest steps: - uses: actions/checkout@v2 From 23f6cb48ac9931e7046a06137415bab97e80600a Mon Sep 17 00:00:00 2001 From: Emanuel Miroiu Date: Tue, 1 Jul 2025 18:24:01 +0300 Subject: [PATCH 5/6] Update publish.yml --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0d57fd7..31c8fb1 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -8,7 +8,7 @@ on: jobs: publish: - runs-on: ubuntu-latest + runs-on: windows-latest steps: - uses: actions/checkout@v2 From d907d8194711b744d265aa5a348f9f5e12694201 Mon Sep 17 00:00:00 2001 From: miroiu Date: Tue, 1 Jul 2025 18:52:54 +0300 Subject: [PATCH 6/6] Bump version for release --- StringMath/StringMath.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StringMath/StringMath.csproj b/StringMath/StringMath.csproj index f330116..0b298c9 100644 --- a/StringMath/StringMath.csproj +++ b/StringMath/StringMath.csproj @@ -12,8 +12,8 @@ Supports variables and user defined operators. https://github.com/miroiu/string-math https://github.com/miroiu/string-math expression-evaluator calculator string-math math string-calculator user-defined-operators operators custom-operators - 4.1.2 - Fixed compiled expressions not using variables that are not passed as arguments + 4.1.3 + Fixed a parsing error for some operators. true enable