From 729124086b4e710cbce69424f14bd0d068c7e4f2 Mon Sep 17 00:00:00 2001 From: Davide Icardi Date: Sat, 8 Nov 2014 19:37:39 +0100 Subject: [PATCH] Added support for equal assignement operator (=). #24 --- README.md | 9 ++++ src/DynamicExpresso.Core/Parsing/Parser.cs | 21 +++++++- src/DynamicExpresso.Core/Parsing/TokenId.cs | 3 +- .../InvalidExpressionTest.cs | 27 ++++++++++ .../DynamicExpresso.UnitTest/OperatorsTest.cs | 53 +++++++++++++++---- 5 files changed, 100 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 884e98bb..2537ba86 100644 --- a/README.md +++ b/README.md @@ -216,9 +216,14 @@ Statements can be written using a subset of the C# syntax. Here you can find a l Conditional?: + + Assignment= + +Operators precedence is respected following [C# rules (Operator precedence and associativity)](http://msdn.microsoft.com/en-us/library/aa691323(v=vs.71).aspx). + ### Literals @@ -397,6 +402,10 @@ For one reason or another none of these projects exactly fit my needs so I decid ## Release notes +- 1.1.0 + + - Added support for equal assignement operator (=). [#24](https://github.com/davideicardi/DynamicExpresso/issues/24) + - 1.0.0 - Added Interpreter.DetectIdentifiers method to discovery identifiers (variables, parameters, types) used in expression before parsing it. ([#23](https://github.com/davideicardi/DynamicExpresso/issues/23)) diff --git a/src/DynamicExpresso.Core/Parsing/Parser.cs b/src/DynamicExpresso.Core/Parsing/Parser.cs index 13f72714..5be682b2 100644 --- a/src/DynamicExpresso.Core/Parsing/Parser.cs +++ b/src/DynamicExpresso.Core/Parsing/Parser.cs @@ -79,9 +79,26 @@ Expression ParseExpressionSegment(Type returnType) Expression ParseExpressionSegment() { // The following methods respect the operator precedence as defined in + // MSDN C# "Operator precedence and associativity" // http://msdn.microsoft.com/en-us/library/aa691323(v=vs.71).aspx - return ParseConditional(); + return ParseAssignement(); + } + + // = operator + Expression ParseAssignement() + { + int errorPos = _token.pos; + Expression left = ParseConditional(); + if (_token.id == TokenId.Equal) + { + Token op = _token; + NextToken(); + Expression right = ParseAssignement(); + CheckAndPromoteOperands(typeof(ParseSignatures.IEqualitySignatures), op.text, ref left, ref right, op.pos); + left = Expression.Assign(left, right); + } + return left; } // ?: operator @@ -1852,7 +1869,7 @@ void NextToken() } else { - throw CreateParseException(_parsePosition, ErrorMessages.InvalidCharacter, _parseChar); + t = TokenId.Equal; } break; case '>': diff --git a/src/DynamicExpresso.Core/Parsing/TokenId.cs b/src/DynamicExpresso.Core/Parsing/TokenId.cs index b9b0dcfa..553e8714 100644 --- a/src/DynamicExpresso.Core/Parsing/TokenId.cs +++ b/src/DynamicExpresso.Core/Parsing/TokenId.cs @@ -36,7 +36,8 @@ internal enum TokenId LessThanEqual, DoubleEqual, GreaterThanEqual, - DoubleBar + DoubleBar, + Equal } } diff --git a/test/DynamicExpresso.UnitTest/InvalidExpressionTest.cs b/test/DynamicExpresso.UnitTest/InvalidExpressionTest.cs index f75a1512..a59d766b 100644 --- a/test/DynamicExpresso.UnitTest/InvalidExpressionTest.cs +++ b/test/DynamicExpresso.UnitTest/InvalidExpressionTest.cs @@ -18,6 +18,33 @@ public void Not_existing_variable() target.Eval("not_existing"); } + [TestMethod] + [ExpectedException(typeof(ParseException))] + public void Invalid_equal_assignment_operator_left() + { + var target = new Interpreter(); + + target.Eval("=234"); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentException))] + public void Invalid_equal_assignment_operator_left_is_literal() + { + var target = new Interpreter(); + + target.Eval("352=234"); + } + + [TestMethod] + [ExpectedException(typeof(ParseException))] + public void Unkonwn_operator_triple_equal() + { + var target = new Interpreter(); + + target.Eval("352===234"); + } + [TestMethod] [ExpectedException(typeof(UnknownIdentifierException))] public void Not_existing_function() diff --git a/test/DynamicExpresso.UnitTest/OperatorsTest.cs b/test/DynamicExpresso.UnitTest/OperatorsTest.cs index 73340e7d..6686535f 100644 --- a/test/DynamicExpresso.UnitTest/OperatorsTest.cs +++ b/test/DynamicExpresso.UnitTest/OperatorsTest.cs @@ -144,6 +144,49 @@ public void Comparison_Operators() Assert.IsFalse((bool)target.Eval("\"dav\" == \"jack\"")); } + [TestMethod] + public void Assignment_Operator_Equal() + { + var x = new TypeWithProperty(); + + var target = new Interpreter() + .SetVariable("x", x); + + // simple assignment + target.Eval("x.Property1 = 156"); + Assert.AreEqual(156, x.Property1); + + // assignment without space + target.Eval("x.Property1=156"); + Assert.AreEqual(156, x.Property1); + + // assignment with many spaces + target.Eval("x.Property1 = 156"); + Assert.AreEqual(156, x.Property1); + + // assignment should return the assigned value + var returnValue = target.Eval("x.Property1 = 81"); + Assert.AreEqual(81, x.Property1); + Assert.AreEqual(x.Property1, returnValue); + + // assignment can be chained + returnValue = target.Eval("x.Property1 = x.Property2 = 2014"); + Assert.AreEqual(2014, x.Property1); + Assert.AreEqual(x.Property1, x.Property2); + + // assignment can be nested with other operators + returnValue = target.Eval("x.Property1 = (486 + 4) * 10"); + Assert.AreEqual(4900, x.Property1); + Assert.AreEqual(x.Property1, returnValue); + + // right member is not modified + x.Property2 = 2; + returnValue = target.Eval("x.Property1 = x.Property2 * 10"); + Assert.AreEqual(20, x.Property1); + Assert.AreEqual(2, x.Property2); + } + class TypeWithProperty { public int Property1 { get; set; } public int Property2 { get; set; } } + [TestMethod] public void Can_compare_numeric_parameters_of_different_compatible_types() { @@ -196,15 +239,6 @@ public void If_Operators() Assert.AreEqual(10 < 3 ? "yes" : "no", target.Eval("10 < 3 ? \"yes\" : \"no\"")); } - [TestMethod] - [ExpectedException(typeof(ParseException))] - public void Operator_Equal_Is_Not_Supported() - { - var target = new Interpreter(); - - target.Parse("5 = 4"); - } - [TestMethod] [ExpectedException(typeof(ParseException))] public void Operator_LessGreater_Is_Not_Supported() @@ -434,6 +468,5 @@ public TypeWithoutOverloadedBinaryOperators(int value) _value = value; } } - } }