Skip to content

Commit

Permalink
Implicit conversion of operands for ternary operator - implementation…
Browse files Browse the repository at this point in the history
… with respective tests provided.
  • Loading branch information
jwaliszko committed Sep 16, 2017
1 parent e8876b7 commit fa765b3
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 9 deletions.
21 changes: 18 additions & 3 deletions src/ExpressiveAnnotations.Tests/ParserTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ public void verify_logic_without_context()
Assert.True(parser.Parse<bool>("false ? false : true").Invoke());

Assert.True(parser.Parse<bool>("(true ? 1 : 2) == 1").Invoke());
Assert.True(parser.Parse<bool>("(false ? 1 : 2) == 2").Invoke());
Assert.True(parser.Parse<bool>("(false ? 1 : 2.2) == 2.2").Invoke());
Assert.True(parser.Parse<bool>("(true ? null : null) == null").Invoke());

Assert.True(parser.Parse<bool>("(1 > 0 ? true : false) ? (1 > 0 ? true : false) : (false ? false : false)").Invoke());
Assert.True(parser.Parse<bool>("(1 > 0 ? false : true) ? (false ? false : false) : (1 > 0 ? true : false)").Invoke());
Expand Down Expand Up @@ -580,6 +581,8 @@ public void verify_logic_with_context()
Assert.Equal(expectedMethods.Length, parsedMethods.Count);
Assert.True(!expectedMethods.Except(parsedMethods).Any());

Assert.True(parser.Parse<Model, bool>("(true ? Number : -1.1) == 0").Invoke(model));

Assert.True(parser.Parse<Model, bool>("Array[0] != null && Array[1] != null").Invoke(model));
Assert.True(parser.Parse<Model, bool>("Array[0].Number + Array[0].Array[0].Number + Array[1].Number + Array[1].Array[0].Number == 0").Invoke(model));

Expand Down Expand Up @@ -1561,10 +1564,22 @@ public void verify_various_parsing_errors()
Assert.Equal("Expected subproperty identifier. Unexpected end of expression.", e.Error);
Assert.Equal(new Location(1, 6), e.Location, new LocationComparer());

e = Assert.Throws<ParseErrorException>(() => parser.Parse<object, bool>("[0][1 > 0 ? 0*2.0 : 0^2] == 1"));
Assert.Equal("Argument types must match.", e.Error);
e = Assert.Throws<ParseErrorException>(() => parser.Parse<object, bool>("[0][1 > 0 ? 0*2.0 : ''] == 1"));
Assert.Equal("Type of conditional expression cannot be determined because there is no implicit conversion between 'System.Double' and 'System.String'.", e.Error);
Assert.Equal(new Location(1, 11), e.Location, new LocationComparer());

e = Assert.Throws<ParseErrorException>(() => parser.Parse<object, bool>("[0][1 > 0 ? '' : 0*2.0] == 1"));
Assert.Equal("Type of conditional expression cannot be determined because there is no implicit conversion between 'System.String' and 'System.Double'.", e.Error);
Assert.Equal(new Location(1, 11), e.Location, new LocationComparer());

e = Assert.Throws<ParseErrorException>(() => parser.Parse<object, bool>("true ? null : 1"));
Assert.Equal("Type of conditional expression cannot be determined because there is no implicit conversion between 'null' and 'System.Int32'.", e.Error);
Assert.Equal(new Location(1, 6), e.Location, new LocationComparer());

e = Assert.Throws<ParseErrorException>(() => parser.Parse<object, bool>("true ? 1 : null"));
Assert.Equal("Type of conditional expression cannot be determined because there is no implicit conversion between 'System.Int32' and 'null'.", e.Error);
Assert.Equal(new Location(1, 6), e.Location, new LocationComparer());

e = Assert.Throws<ParseErrorException>(() => parser.Parse<Model, bool>("Collection[true ? 0 : 1].Collection[true ? [0][0] : 1].Unknown == -2"));
Assert.Equal("Only public properties, constants and enums are accepted. Identifier 'Unknown' not known.", e.Error);
Assert.Equal(new Location(1, 56), e.Location, new LocationComparer());
Expand Down
8 changes: 6 additions & 2 deletions src/ExpressiveAnnotations/Analysis/Expr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ public Expression Multiply(Expression arg1, Expression arg2, Token oper)
var type1 = arg1.Type;
var type2 = arg2.Type;
TypeAdapter.MakeTypesCompatible(arg1, arg2, out arg1, out arg2, oper.Type);
Wall.Mul(arg1, arg2, type1, type2, oper);
Wall.Mul(arg1, arg2, type1, type2, oper);

try
{
Expand Down Expand Up @@ -364,7 +364,11 @@ public Expression OnesComplement(Expression arg, Token oper)
public Expression Condition(Expression arg1, Expression arg2, Expression arg3, Token start, Token oper)
{
Wall.OfType<bool>(arg1, start.Location);
Wall.TypesMatch(arg2, arg3, oper.Location);

var type2 = arg2.Type;
var type3 = arg3.Type;
TypeAdapter.MakeTypesCompatible(arg2, arg3, out arg2, out arg3, oper.Type);
Wall.Cond(arg2, arg3, type2, type3, oper.Location);

return Expression.Condition(arg1, arg2, arg3);
}
Expand Down
10 changes: 8 additions & 2 deletions src/ExpressiveAnnotations/Analysis/TypeWall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,17 @@ public void Unary(Expression arg, Token oper)
$"Operator '{oper.Value}' cannot be applied to operand of type 'null'.", ExprString, oper.Location);
}

public void TypesMatch(Expression arg1, Expression arg2, Location pos)
public void Cond(Expression arg1, Expression arg2, Type type1, Type type2, Location pos)
{
if (arg1.IsNullLiteral() && !arg2.IsNullLiteral())
throw new ParseErrorException(
$"Type of conditional expression cannot be determined because there is no implicit conversion between 'null' and '{type2}'.", ExprString, pos);
if (!arg1.IsNullLiteral() && arg2.IsNullLiteral())
throw new ParseErrorException(
$"Type of conditional expression cannot be determined because there is no implicit conversion between '{type1}' and 'null'.", ExprString, pos);
if (arg1.Type != arg2.Type)
throw new ParseErrorException(
"Argument types must match.", ExprString, pos);
$"Type of conditional expression cannot be determined because there is no implicit conversion between '{type1}' and '{type2}'.", ExprString, pos);
}

public void OfType<T>(Expression arg, Location pos)
Expand Down
4 changes: 2 additions & 2 deletions src/ExpressiveAnnotations/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.7.3.0")]
[assembly: AssemblyFileVersion("2.7.3.0")]
[assembly: AssemblyVersion("2.7.4.0")]
[assembly: AssemblyFileVersion("2.7.4.0")]

0 comments on commit fa765b3

Please sign in to comment.