Skip to content

Commit cbe9348

Browse files
author
Maksim Volkau
committed
related to #487: removing parens for the root expr in some cases; removing end ; from the ToCSharpString; add ; in PrintCSharp; avoid unnecessary ; after braced blocks; avoid double ;; at last block expr.
1 parent 33f64cb commit cbe9348

File tree

7 files changed

+56
-51
lines changed

7 files changed

+56
-51
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"Ldtoken",
3434
"Ldvirtftn",
3535
"Maksim",
36+
"NETCOREAPP",
3637
"NETFRAMEWORK",
3738
"Newarr",
3839
"Newobj",

src/FastExpressionCompiler/FastExpressionCompiler.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8226,7 +8226,7 @@ public static string GetArithmeticBinaryOperatorMethodName(this ExpressionType n
82268226
};
82278227

82288228
[MethodImpl((MethodImplOptions)256)]
8229-
internal static bool IsBlockLike(this ExpressionType nodeType) =>
8229+
internal static bool IsBracedBlockLike(this ExpressionType nodeType) =>
82308230
nodeType == ExpressionType.Try |
82318231
nodeType == ExpressionType.Switch |
82328232
nodeType == ExpressionType.Block |
@@ -8237,12 +8237,12 @@ internal static bool IsReturnable(this ExpressionType nodeType) =>
82378237
nodeType != ExpressionType.Goto &
82388238
nodeType != ExpressionType.Label &
82398239
nodeType != ExpressionType.Throw &&
8240-
!IsBlockLike(nodeType);
8240+
!IsBracedBlockLike(nodeType);
82418241

82428242
[MethodImpl((MethodImplOptions)256)]
82438243
internal static bool IsBlockLikeOrConditional(this ExpressionType nodeType) =>
82448244
nodeType == ExpressionType.Conditional | nodeType == ExpressionType.Coalesce ||
8245-
IsBlockLike(nodeType);
8245+
IsBracedBlockLike(nodeType);
82468246

82478247
internal static Expression StripConvertRecursively(this Expression expr) =>
82488248
expr is UnaryExpression convert && convert.NodeType == ExpressionType.Convert
@@ -9940,11 +9940,11 @@ public static class ToCSharpPrinter
99409940
{
99419941
/// <summary>Tries hard to convert the expression into the valid C# code. Avoids parens by default for the root expr.</summary>
99429942
public static string ToCSharpString(this Expression expr, EnclosedIn enclosedIn = EnclosedIn.AvoidParens) =>
9943-
expr.ToCSharpString(new StringBuilder(1024), enclosedIn, stripNamespace: true).Append(';').ToString();
9943+
expr.ToCSharpString(new StringBuilder(1024), enclosedIn, stripNamespace: true).ToString();
99449944

99459945
/// <summary>Tries hard to convert the expression into the valid C# code. Avoids parens by default for the root expr.</summary>
99469946
public static string ToCSharpString(this Expression expr, ObjectToCode notRecognizedToCode, EnclosedIn enclosedIn = EnclosedIn.AvoidParens) =>
9947-
expr.ToCSharpString(new StringBuilder(1024), stripNamespace: true, notRecognizedToCode: notRecognizedToCode).Append(';').ToString();
9947+
expr.ToCSharpString(new StringBuilder(1024), stripNamespace: true, notRecognizedToCode: notRecognizedToCode).ToString();
99489948

99499949
/// <summary>Tries hard to convert the expression into the valid C# code</summary>
99509950
public static StringBuilder ToCSharpString(this Expression e, StringBuilder sb, EnclosedIn enclosedIn = EnclosedIn.ParensByDefault,
@@ -10421,7 +10421,7 @@ void PrintPart(Expression part, ref TNamed named)
1042110421
sb.Append("return ");
1042210422
part.ToCSharpString(sb, EnclosedIn.AvoidParens, ref named,
1042310423
incIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
10424-
sb.AppendSemicolonOnce();
10424+
sb.AppendSemicolonOnce(part);
1042510425
}
1042610426
}
1042710427

@@ -10546,13 +10546,13 @@ void PrintPart(Expression part, ref TNamed named)
1054610546
{
1054710547
var bodyIn = caseBody.Type != typeof(void) ? EnclosedIn.Return : EnclosedIn.AvoidParens;
1054810548
caseBody.ToCSharpString(bodyIn == EnclosedIn.Return ? sb.Append("return ") : sb, bodyIn, ref named,
10549-
caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).AppendSemicolonOnce();
10549+
caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).AppendSemicolonOnce(caseBody);
1055010550
}
1055110551
}
1055210552
else
1055310553
{
1055410554
caseBody.ToCSharpString(sb, enclosedIn, ref named,
10555-
caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).AppendSemicolonOnce();
10555+
caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).AppendSemicolonOnce(caseBody);
1055610556
sb.NewLineIndent(caseBodyIndent).Append("break;");
1055710557
}
1055810558
}
@@ -10571,13 +10571,13 @@ void PrintPart(Expression part, ref TNamed named)
1057110571
{
1057210572
var bodyIn = defaultBody.Type != typeof(void) ? EnclosedIn.Return : EnclosedIn.AvoidParens;
1057310573
defaultBody.ToCSharpString(bodyIn == EnclosedIn.Return ? sb.Append("return ") : sb, bodyIn, ref named,
10574-
caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).AppendSemicolonOnce();
10574+
caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).AppendSemicolonOnce(defaultBody);
1057510575
}
1057610576
}
1057710577
else
1057810578
{
1057910579
defaultBody.ToCSharpString(sb, enclosedIn, ref named,
10580-
caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).AppendSemicolonOnce();
10580+
caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).AppendSemicolonOnce(defaultBody);
1058110581
sb.NewLineIndent(caseBodyIndent).Append("break;");
1058210582
}
1058310583
}
@@ -10831,7 +10831,7 @@ private static StringBuilder ToCSharpBlock<TNamed>(this Expression expr, StringB
1083110831
sb.NewLineIndent(lineIndent + indentSpaces);
1083210832
sb = expr?.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
1083310833
lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode) ?? sb.Append("null");
10834-
sb.AppendSemicolonOnce();
10834+
sb.AppendSemicolonOnce(expr);
1083510835
}
1083610836
return sb.NewLineIndent(lineIndent).Append('}');
1083710837
}
@@ -10841,7 +10841,7 @@ private static StringBuilder ToCSharpExpression<TNamed>(this Expression expr,
1084110841
bool newLineExpr, int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode notRecognizedToCode)
1084210842
where TNamed : struct, ISmallList<NamedWithIndex>
1084310843
{
10844-
if (!expr.NodeType.IsBlockLike())
10844+
if (!expr.NodeType.IsBracedBlockLike())
1084510845
{
1084610846
if (!newLineExpr)
1084710847
return expr.ToCSharpString(sb, enclosedIn, ref named,
@@ -10870,8 +10870,8 @@ private static StringBuilder ToCSharpExpression<TNamed>(this Expression expr,
1087010870
return sb.NewLineIndent(lineIndent).Append("})");
1087110871
}
1087210872

10873-
internal static StringBuilder AppendSemicolonOnce(this StringBuilder sb) =>
10874-
sb[sb.Length - 1] != ';' ? sb.Append(";") : sb;
10873+
internal static StringBuilder AppendSemicolonOnce(this StringBuilder sb, Expression expr = null) =>
10874+
expr?.NodeType.IsBracedBlockLike() == true ? sb : sb[sb.Length - 1] != ';' ? sb.Append(";") : sb;
1087510875

1087610876
internal static StringBuilder AppendNewLineOnce(this StringBuilder sb)
1087710877
{
@@ -11099,7 +11099,7 @@ private static StringBuilder BlockToCSharpString<TNamed>(this BlockExpression b,
1109911099
}
1110011100
}
1110111101

11102-
if (lastExpr.NodeType.IsBlockLike() ||
11102+
if (lastExpr.NodeType.IsBracedBlockLike() ||
1110311103
lastExpr is DefaultExpression d && d.Type == typeof(void))
1110411104
{
1110511105
lastExpr.ToCSharpString(sb, EnclosedIn.Block, ref named,

src/FastExpressionCompiler/TestTools.cs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public static void PrintExpression(this IDelegateDebugInfo debugInfo, bool compl
9090
[CallerMemberName] string caller = "", [CallerFilePath] string filePath = "") =>
9191
PrintExpression(debugInfo.Expression, completeTypeNames, caller, filePath);
9292

93-
public static void PrintCSharp(this Expression expr, bool completeTypeNames = false,
93+
public static void PrintCSharp(this Expression expr, bool completeTypeNames = false, bool stripNamespace = true,
9494
[CallerMemberName] string caller = "", [CallerFilePath] string filePath = "")
9595
{
9696
if (!AllowPrintIL) return;
@@ -107,45 +107,51 @@ public static void PrintCSharp(this Expression expr, bool completeTypeNames = fa
107107
sb.Append("var @cs = ");
108108
sb = expr.ToCSharpString(sb,
109109
lineIndent: 0,
110-
stripNamespace: true,
110+
stripNamespace: stripNamespace,
111111
printType: completeTypeNames ? null : CodePrinter.PrintTypeStripOuterClasses,
112112
indentSpaces: 4);
113-
sb.Append(';');
113+
sb.AppendSemicolonOnce();
114114
Console.WriteLine(sb.ToString());
115115
}
116116

117-
public static void PrintCSharp(this Expression expr, Func<string, string> transform,
117+
public static void PrintCSharp(this Expression expr, Func<string, string> transform, bool stripNamespace = true,
118118
[CallerMemberName] string caller = "", [CallerFilePath] string filePath = "")
119119
{
120120
if (!AllowPrintCS) return;
121121
Console.WriteLine();
122122
Console.WriteLine($"//{Path.GetFileNameWithoutExtension(filePath)}.{caller}");
123-
Console.WriteLine(transform(expr.ToCSharpString()));
123+
var sb = expr.ToCSharpString(new StringBuilder(1024), ToCSharpPrinter.EnclosedIn.AvoidParens, stripNamespace: stripNamespace).AppendSemicolonOnce();
124+
var str = transform(sb.ToString());
125+
Console.WriteLine(str);
124126
}
125127

126-
public static void PrintCSharp(this Expression expr, CodePrinter.ObjectToCode objectToCode,
128+
public static void PrintCSharp(this Expression expr, CodePrinter.ObjectToCode objectToCode, bool stripNamespace = true,
127129
[CallerMemberName] string caller = "", [CallerFilePath] string filePath = "")
128130
{
129131
if (!AllowPrintCS) return;
130132

131133
Console.WriteLine();
132134
Console.WriteLine($"//{Path.GetFileNameWithoutExtension(filePath)}.{caller}");
133-
Console.WriteLine(expr.ToCSharpString(objectToCode));
135+
var sb = expr.ToCSharpString(new StringBuilder(1024), ToCSharpPrinter.EnclosedIn.AvoidParens, notRecognizedToCode: objectToCode, stripNamespace: stripNamespace).AppendSemicolonOnce();
136+
var str = sb.ToString();
137+
Console.WriteLine(str);
134138
}
135139

136-
public static void PrintCSharp(this Expression expr, ref string result)
140+
public static void PrintCSharp(this Expression expr, ref string result, bool stripNamespace = true)
137141
{
138142
if (!AllowPrintCS) return;
139-
Console.WriteLine(result = expr.ToCSharpString());
143+
var sb = expr.ToCSharpString(new StringBuilder(1024), ToCSharpPrinter.EnclosedIn.AvoidParens, stripNamespace: stripNamespace).AppendSemicolonOnce();
144+
result = sb.ToString();
145+
Console.WriteLine(result);
140146
}
141147

142148
/// <summary>The method outputs the whole code of the expression including the code of the nested lambdas.
143149
/// In case of nested lambda represented in the expression of the Constant Delegate,
144150
/// and the Delegate.Target being IDelegateDebugInfo, you may call `IDelegateDebugInfo.EnumerateNestedLambdas()`
145151
/// and output C# for each nested lambda</summary>
146-
public static void PrintCSharp(this IDelegateDebugInfo debugInfo, bool completeTypeNames = false,
152+
public static void PrintCSharp(this IDelegateDebugInfo debugInfo, bool completeTypeNames = false, bool stripNamespace = true,
147153
[CallerMemberName] string caller = "", [CallerFilePath] string filePath = "") =>
148-
debugInfo.Expression.PrintCSharp(completeTypeNames, caller, filePath);
154+
debugInfo.Expression.PrintCSharp(completeTypeNames, stripNamespace, caller, filePath);
149155

150156
public static void PrintIL(this Delegate dlg, [CallerMemberName] string tag = null, ILFormat format = ILFormat.Default)
151157
{

test/FastExpressionCompiler.IssueTests/Issue458_Support_TryFault.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public void Original_case2()
6767
);
6868

6969
expr.PrintCSharp();
70+
7071
// outputs
7172
var @cs = (Func<int>)(() => //int
7273
{
@@ -87,7 +88,6 @@ public void Original_case2()
8788
x = 2;
8889
}
8990
}
90-
;
9191
}
9292
catch (Exception)
9393
{

test/FastExpressionCompiler.IssueTests/Issue487_Fix_ToCSharpString_output_for_boolean_equality_expressions.cs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,17 @@ public class TestClass
3030
public void Original_case(TestContext t)
3131
{
3232
var input = new TestClass() { MyTestBool = true };
33-
var parameter = Expression.Parameter(input.GetType(), "x");
34-
var property = Expression.Property(parameter, nameof(TestClass.MyTestBool));
35-
var expr = Expression.Equal(property, Expression.Constant(true));
33+
var parameter = Parameter(input.GetType(), "x");
34+
var property = Property(parameter, nameof(TestClass.MyTestBool));
35+
var expr = Equal(property, Constant(true));
3636

37-
var str = expr.ToString(); // => (x.MyTestBool == True)
38-
var cs = expr.ToCSharpString(); // => (x.MyTestBool;
37+
var str = expr.ToString();
38+
t.AreEqual("(x.MyTestBool == True)", str);
3939

40-
expr.PrintCSharp();
41-
42-
// var fs = expr.CompileSys();
43-
// fs.PrintIL(format: ILDecoder.ILFormat.AssertOpCodes);
40+
var cs = expr.ToCSharpString();
41+
t.AreEqual("x.MyTestBool", cs);
4442

45-
// var ff = expr.CompileFast(false);
46-
// ff.PrintIL(format: ILDecoder.ILFormat.AssertOpCodes);
43+
expr.PrintCSharp();
4744
}
4845
}
4946
#endif

test/FastExpressionCompiler.TestsRunner/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ public static void Main()
1414
// ILGeneratorTools.DisableILGeneratorPooling = true;
1515
// LightExpression.ILGeneratorTools.DisableILGeneratorPooling = true;
1616

17-
// new Issue127_Switch_is_supported().Run();
17+
new Issue458_Support_TryFault().Run();
1818

19+
// new Issue127_Switch_is_supported().Run();
1920
// new Issue316_in_parameter().Run();
2021
// new LightExpression.IssueTests.Issue347_InvalidProgramException_on_compiling_an_expression_that_returns_a_record_which_implements_IList().Run();
2122
// new LightExpression.UnitTests.NestedLambdasSharedToExpressionCodeStringTest().Run();

test/FastExpressionCompiler.UnitTests/ToCSharpStringTests.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,22 @@ public void Outputs_type_equals()
4242
var eArray = TypeEqual(p, typeof(object[]));
4343
var eOpen = TypeEqual(p, typeof(System.Collections.Generic.List<string>));
4444

45-
Asserts.AreEqual("(p is string);", eSealed.ToCSharpString());
46-
Asserts.AreEqual("(p is int);", eStruct.ToCSharpString());
47-
Asserts.AreEqual("(p.GetType() == typeof(object[]));", eArray.ToCSharpString());
48-
Asserts.AreEqual("(p.GetType() == typeof(List<string>));", eOpen.ToCSharpString());
45+
Asserts.AreEqual("(p is string)", eSealed.ToCSharpString());
46+
Asserts.AreEqual("(p is int)", eStruct.ToCSharpString());
47+
Asserts.AreEqual("(p.GetType() == typeof(object[]))", eArray.ToCSharpString());
48+
Asserts.AreEqual("(p.GetType() == typeof(List<string>))", eOpen.ToCSharpString());
4949
}
5050

5151
public void Outputs_default_null_for_reference_types()
5252
{
53-
Asserts.AreEqual("(string)null;", Constant(null, typeof(string)).ToCSharpString());
54-
Asserts.AreEqual("(string)null;", Default(typeof(string)).ToCSharpString());
55-
Asserts.AreEqual("(List<string>)null;", Constant(null, typeof(System.Collections.Generic.List<string>)).ToCSharpString());
56-
Asserts.AreEqual("(List<string>)null;", Default(typeof(System.Collections.Generic.List<string>)).ToCSharpString());
57-
Asserts.AreEqual("(int?)null;", Constant(null, typeof(int?)).ToCSharpString());
58-
Asserts.AreEqual("(int?)null;", Default(typeof(int?)).ToCSharpString());
53+
Asserts.AreEqual("(string)null", Constant(null, typeof(string)).ToCSharpString());
54+
Asserts.AreEqual("(string)null", Default(typeof(string)).ToCSharpString());
55+
Asserts.AreEqual("(List<string>)null", Constant(null, typeof(System.Collections.Generic.List<string>)).ToCSharpString());
56+
Asserts.AreEqual("(List<string>)null", Default(typeof(System.Collections.Generic.List<string>)).ToCSharpString());
57+
Asserts.AreEqual("(int?)null", Constant(null, typeof(int?)).ToCSharpString());
58+
Asserts.AreEqual("(int?)null", Default(typeof(int?)).ToCSharpString());
5959

60-
Asserts.AreEqual("default(int);", Default(typeof(int)).ToCSharpString());
60+
Asserts.AreEqual("default(int)", Default(typeof(int)).ToCSharpString());
6161

6262
var e = Block(
6363
new[] { Variable(typeof(int), "integer"), Variable(typeof(int?), "maybe_integer"), Variable(typeof(string), "str") },
@@ -67,7 +67,7 @@ public void Outputs_default_null_for_reference_types()
6767
Asserts.AreEqual(
6868
"int integer = default;" + Environment.NewLine +
6969
"int? maybe_integer = null;" + Environment.NewLine +
70-
"string str = null;;",
70+
"string str = null;",
7171
e.ToCSharpString().Trim());
7272
}
7373

0 commit comments

Comments
 (0)