Skip to content

Commit dcbd622

Browse files
committed
Fixing bug #7: checking for existing return statements in nested blocks / Moving CodeBlock translation into TranslationContext
1 parent 28dc365 commit dcbd622

34 files changed

+144
-112
lines changed

ReadableExpressions.UnitTests/WhenTranslatingAssignments.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,5 +414,42 @@ public void ShouldTranslateAMultipleLineTernaryAssignment()
414414
}";
415415
Assert.AreEqual(EXPECTED.TrimStart(), translated);
416416
}
417+
418+
// See https://github.com/agileobjects/ReadableExpressions/issues/7
419+
[TestMethod]
420+
public void ShouldTranslateANestedBlockAssignment()
421+
{
422+
Expression<Action> consoleRead = () => Console.Read();
423+
424+
var variableOne = Expression.Variable(typeof(int), "one");
425+
var variableTwo = Expression.Variable(typeof(int), "two");
426+
427+
var variableOneAssignment = Expression.Assign(variableOne, consoleRead.Body);
428+
var variableTwoAssignment = Expression.Assign(variableTwo, consoleRead.Body);
429+
430+
var variableOneMinusTwo = Expression.Subtract(variableOne, variableTwo);
431+
432+
var valueBlock = Expression.Block(
433+
new[] { variableOne, variableTwo },
434+
variableOneAssignment,
435+
variableTwoAssignment,
436+
variableOneMinusTwo);
437+
438+
var wrappingBlock = Expression.Block(valueBlock);
439+
440+
var resultVariable = Expression.Variable(typeof(int), "result");
441+
var resultOneAssignment = Expression.Assign(resultVariable, wrappingBlock);
442+
443+
var translated = resultOneAssignment.ToReadableString();
444+
445+
const string EXPECTED = @"
446+
result =
447+
{
448+
var one = Console.Read();
449+
var two = Console.Read();
450+
return (one - two);
451+
}";
452+
Assert.AreEqual(EXPECTED.TrimStart(), translated);
453+
}
417454
}
418455
}

ReadableExpressions/StringExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ private static string GetStringValue(Expression value, TranslationContext contex
156156
}
157157
}
158158

159-
return context.GetTranslation(value);
159+
return context.Translate(value);
160160
}
161161
}
162162
}

ReadableExpressions/TranslationContext.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace AgileObjects.ReadableExpressions
55
using System.Linq.Expressions;
66
using Extensions;
77
using Translators;
8+
using Translators.Formatting;
89

910
public class TranslationContext
1011
{
@@ -24,11 +25,48 @@ public static TranslationContext For(Expression expression, Translator globalTra
2425

2526
public IEnumerable<ParameterExpression> JoinedAssignmentVariables => _analyzer.AssignedVariables;
2627

27-
public string GetTranslation(Expression expression)
28+
public string Translate(Expression expression)
2829
{
2930
return _globalTranslator.Invoke(expression, this);
3031
}
3132

33+
internal CodeBlock TranslateCodeBlock(Expression expression)
34+
{
35+
return TranslateBlock(expression as BlockExpression) ?? TranslateSingle(expression);
36+
}
37+
38+
private CodeBlock TranslateBlock(BlockExpression block)
39+
{
40+
if (block == null)
41+
{
42+
return null;
43+
}
44+
45+
if (block.Expressions.Count == 1)
46+
{
47+
return TranslateSingle(block);
48+
}
49+
50+
var blockString = Translate(block);
51+
var blockLines = blockString.SplitToLines();
52+
53+
return new CodeBlock(block, blockLines);
54+
}
55+
56+
private CodeBlock TranslateSingle(Expression body)
57+
{
58+
var bodyString = Translate(body).WithoutSurroundingParentheses(body);
59+
60+
return new CodeBlock(body, bodyString);
61+
}
62+
63+
internal ParameterSet TranslateParameters(
64+
IEnumerable<Expression> parameters,
65+
IMethodInfo method = null)
66+
{
67+
return new ParameterSet(method, parameters, this);
68+
}
69+
3270
public bool IsNotJoinedAssignment(Expression expression)
3371
{
3472
return (expression.NodeType != ExpressionType.Assign) ||

ReadableExpressions/Translators/ArrayLengthExpressionTranslator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ internal ArrayLengthExpressionTranslator()
1111

1212
public override string Translate(Expression expression, TranslationContext context)
1313
{
14-
var arrayAccess = context.GetTranslation(((UnaryExpression)expression).Operand);
14+
var arrayAccess = context.Translate(((UnaryExpression)expression).Operand);
1515

1616
return arrayAccess + ".Length";
1717
}

ReadableExpressions/Translators/AssignmentExpressionTranslator.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ internal AssignmentExpressionTranslator(DefaultExpressionTranslator defaultTrans
4141
public override string Translate(Expression expression, TranslationContext context)
4242
{
4343
var assignment = (BinaryExpression)expression;
44-
var target = context.GetTranslation(assignment.Left);
44+
var target = context.Translate(assignment.Left);
4545

4646
return GetAssignment(target, expression.NodeType, assignment.Right, context);
4747
}
@@ -65,9 +65,9 @@ internal string GetAssignment(
6565
return assignment;
6666
}
6767

68-
private string GetValueTranslation(Expression value, TranslationContext context)
68+
private static string GetValueTranslation(Expression value, TranslationContext context)
6969
{
70-
var valueBlock = GetTranslatedExpressionBody(value, context);
70+
var valueBlock = context.TranslateCodeBlock(value);
7171

7272
if (valueBlock.IsASingleStatement)
7373
{

ReadableExpressions/Translators/BinaryExpressionTranslator.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public override string Translate(Expression expression, TranslationContext conte
6767
: Translate(binary, context);
6868
}
6969

70-
private string Translate(BinaryExpression binary, TranslationContext context)
70+
private static string Translate(BinaryExpression binary, TranslationContext context)
7171
{
7272
var left = TranslateOperand(binary.Left, context);
7373
var @operator = _operatorsByNodeType[binary.NodeType];
@@ -78,16 +78,16 @@ private string Translate(BinaryExpression binary, TranslationContext context)
7878
return AdjustForCheckedOperatorIfAppropriate(binary.NodeType, operation);
7979
}
8080

81-
private string TranslateOperand(Expression expression, TranslationContext context)
81+
private static string TranslateOperand(Expression expression, TranslationContext context)
8282
{
83-
var operand = GetTranslatedExpressionBody(expression, context);
83+
var operand = context.TranslateCodeBlock(expression);
8484

8585
if (!operand.IsASingleStatement)
8686
{
8787
return operand.WithCurlyBraces();
8888
}
8989

90-
var translation = context.GetTranslation(expression);
90+
var translation = context.Translate(expression);
9191

9292
if (expression.IsAssignment() && !translation.HasSurroundingParentheses())
9393
{

ReadableExpressions/Translators/BlockExpressionTranslator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ private static bool Include(Expression expression)
6464

6565
private static string GetTerminatedStatementOrNull(Expression expression, TranslationContext context)
6666
{
67-
var translation = context.GetTranslation(expression);
67+
var translation = context.Translate(expression);
6868

6969
if (translation == null)
7070
{

ReadableExpressions/Translators/CastExpressionTranslator.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ private static string TranslateCast(Expression expression, TranslationContext co
3636
if (expression.Type == typeof(object))
3737
{
3838
// Don't bother showing a boxing operation:
39-
return context.GetTranslation(operand);
39+
return context.Translate(operand);
4040
}
4141

4242
MethodCallExpression methodCall;
@@ -50,7 +50,7 @@ private static string TranslateCast(Expression expression, TranslationContext co
5050

5151
var methodSubject = subjectMethod.IsStatic
5252
? subjectMethod.DeclaringType.GetFriendlyName()
53-
: context.GetTranslation(methodCall.Arguments.ElementAtOrDefault(1));
53+
: context.Translate(methodCall.Arguments.ElementAtOrDefault(1));
5454

5555
return methodSubject + "." + subjectMethod.Name;
5656
}
@@ -62,7 +62,7 @@ private static string TranslateCastCore(Expression expression, TranslationContex
6262
{
6363
var cast = (UnaryExpression)expression;
6464
var typeName = cast.Type.GetFriendlyName();
65-
var subject = context.GetTranslation(cast.Operand);
65+
var subject = context.Translate(cast.Operand);
6666

6767
if (cast.Operand.NodeType == ExpressionType.Assign)
6868
{
@@ -76,7 +76,7 @@ private static string TranslateTypeAs(Expression expression, TranslationContext
7676
{
7777
var typeAs = (UnaryExpression)expression;
7878
var typeName = typeAs.Type.GetFriendlyName();
79-
var subject = context.GetTranslation(typeAs.Operand);
79+
var subject = context.Translate(typeAs.Operand);
8080

8181
return $"({subject} as {typeName})";
8282
}
@@ -85,7 +85,7 @@ private static string TranslateTypeIs(Expression expression, TranslationContext
8585
{
8686
var typeIs = (TypeBinaryExpression)expression;
8787
var typeName = typeIs.TypeOperand.GetFriendlyName();
88-
var subject = context.GetTranslation(typeIs.Expression);
88+
var subject = context.Translate(typeIs.Expression);
8989

9090
return $"({subject} is {typeName})";
9191
}

ReadableExpressions/Translators/ConditionalExpressionTranslator.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@ public override string Translate(Expression expression, TranslationContext conte
1515
{
1616
var conditional = (ConditionalExpression)expression;
1717

18-
var test = GetTest(context.GetTranslation(conditional.Test));
18+
var test = GetTest(context.Translate(conditional.Test));
1919
var hasNoElseCondition = HasNoElseCondition(conditional);
2020

21-
var ifTrueBlock = GetTranslatedExpressionBody(conditional.IfTrue, context);
21+
var ifTrueBlock = context.TranslateCodeBlock(conditional.IfTrue);
2222

2323
if (hasNoElseCondition)
2424
{
2525
return IfStatement(test, ifTrueBlock.WithCurlyBraces());
2626
}
2727

28-
var ifFalseBlock = GetTranslatedExpressionBody(conditional.IfFalse, context);
28+
var ifFalseBlock = context.TranslateCodeBlock(conditional.IfFalse);
2929

3030
if (IsTernary(conditional))
3131
{

ReadableExpressions/Translators/DebugInfoExpressionTranslator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public override string Translate(Expression expression, TranslationContext conte
3434

3535
var debugInfoComment = ReadableExpression.Comment(debugInfoText);
3636

37-
return context.GetTranslation(debugInfoComment);
37+
return context.Translate(debugInfoComment);
3838
}
3939
}
4040
}

0 commit comments

Comments
 (0)