Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
davideicardi committed Nov 8, 2014
2 parents e7db4b8 + 7291240 commit 8b5a288
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 13 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,14 @@ Statements can be written using a subset of the C# syntax. Here you can find a l
<tr>
<td>Conditional</td><td><code>?:</code></td>
</tr>
<tr>
<td>Assignment</td><td><code>=</code></td>
</tr>
</tbody>
</table>

Operators precedence is respected following [C# rules (Operator precedence and associativity)](http://msdn.microsoft.com/en-us/library/aa691323(v=vs.71).aspx).

### Literals

<table>
Expand Down Expand Up @@ -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 (<code>=</code>). [#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))
Expand Down
21 changes: 19 additions & 2 deletions src/DynamicExpresso.Core/Parsing/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1852,7 +1869,7 @@ void NextToken()
}
else
{
throw CreateParseException(_parsePosition, ErrorMessages.InvalidCharacter, _parseChar);
t = TokenId.Equal;
}
break;
case '>':
Expand Down
3 changes: 2 additions & 1 deletion src/DynamicExpresso.Core/Parsing/TokenId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ internal enum TokenId
LessThanEqual,
DoubleEqual,
GreaterThanEqual,
DoubleBar
DoubleBar,
Equal
}

}
27 changes: 27 additions & 0 deletions test/DynamicExpresso.UnitTest/InvalidExpressionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
53 changes: 43 additions & 10 deletions test/DynamicExpresso.UnitTest/OperatorsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -434,6 +468,5 @@ public TypeWithoutOverloadedBinaryOperators(int value)
_value = value;
}
}

}
}

0 comments on commit 8b5a288

Please sign in to comment.