Skip to content

Commit c2ff871

Browse files
committed
updated readme
1 parent 9265a45 commit c2ff871

File tree

3 files changed

+110
-13
lines changed

3 files changed

+110
-13
lines changed

README.md

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -300,17 +300,91 @@ FEC V3 has added powerful diagnostics and code generation tools.
300300

301301
You may pass the optional `CompilerFlags.EnableDelegateDebugInfo` into the `CompileFast` methods.
302302

303-
`EnableDelegateDebugInfo` adds the diagnostic info into the compiled delegate including its source Expression and C# code.
304-
Can be used as following:
303+
`EnableDelegateDebugInfo` adds the diagnostic info into the compiled delegate including its source Expression and compiled IL code.
304+
305+
It can be used as following:
305306

306307
```cs
307-
var f = e.CompileFast(true, CompilerFlags.EnableDelegateDebugInfo);
308-
var di = f.Target as IDelegateDebugInfo;
309-
Asserts.IsNotNull(di.Expression);
310-
Asserts.IsNotNull(di.ExpressionString);
311-
Asserts.IsNotNull(di.CSharpString);
308+
System.Linq.Expressions.Expression<Func<int, Func<int>>> e =
309+
n => () => n + 1;
310+
var f = e.CompileFast(flags: CompilerFlags.EnableDelegateDebugInfo);
311+
var d = f.TryGetDebugInfo();
312+
d.PrintExpression();
313+
d.PrintCSharp();
314+
d.PrintIL(); // available in NET8+
312315
```
313316

317+
<details><summary>Expand to see the output of the above code...</summary>
318+
319+
320+
Output of `d.PrintExpression()` is the valid C#:
321+
322+
```cs
323+
var p = new ParameterExpression[1]; // the parameter expressions
324+
var e = new Expression[3]; // the unique expressions
325+
var expr = Lambda<Func<int, Func<int>>>(
326+
e[0]=Lambda<Func<int>>(
327+
e[1]=MakeBinary(ExpressionType.Add,
328+
p[0]=Parameter(typeof(int), "n"),
329+
e[2]=Constant(1)), new ParameterExpression[0]),
330+
p[0 // (int n)
331+
]);
332+
```
333+
334+
Output of `d.PrintCSharp()` is the valid C#:
335+
336+
```cs
337+
var @cs = (Func<int, Func<int>>)((int n) => //Func<int>
338+
(Func<int>)(() => //int
339+
n + 1));
340+
```
341+
342+
Output of `d.PrintIL()` (includes the IL of the nested lambda):
343+
344+
```
345+
<Caller>
346+
0 ldarg.0
347+
1 ldfld object[] ExpressionCompiler.ArrayClosure.ConstantsAndNestedLambdas
348+
6 stloc.0
349+
7 ldloc.0
350+
8 ldc.i4.0
351+
9 ldelem.ref
352+
10 stloc.1
353+
11 ldloc.1
354+
12 ldc.i4.1
355+
13 newarr object
356+
18 stloc.2
357+
19 ldloc.2
358+
20 stfld object[] ExpressionCompiler.NestedLambdaForNonPassedParams.NonPassedParams
359+
25 ldloc.2
360+
26 ldc.i4.0
361+
27 ldarg.1
362+
28 box int
363+
33 stelem.ref
364+
34 ldloc.1
365+
35 ldfld object ExpressionCompiler.NestedLambdaForNonPassedParams.NestedLambda
366+
40 ldloc.2
367+
41 ldloc.1
368+
42 ldfld object[] ExpressionCompiler.NestedLambdaForNonPassedParamsWithConstants.ConstantsAndNestedLambdas
369+
47 newobj ExpressionCompiler.ArrayClosureWithNonPassedParams(System.Object[], System.Object[])
370+
52 call Func<int> ExpressionCompiler.CurryClosureFuncs.Curry(System.Func`2[FastExpressionCompiler.LightExpression.ExpressionCompiler+ArrayClosure,System.Int32], ArrayClosure)
371+
57 ret
372+
</Caller>
373+
<0_nested_in_Caller>
374+
0 ldarg.0
375+
1 ldfld object[] ExpressionCompiler.ArrayClosureWithNonPassedParams.NonPassedParams
376+
6 ldc.i4.0
377+
7 ldelem.ref
378+
8 unbox.any int
379+
13 ldc.i4.1
380+
14 add
381+
15 ret
382+
</0_nested_in_Caller>
383+
```
384+
385+
</details>
386+
387+
314388
### ThrowOnNotSupportedExpression and NotSupported_ flags
315389

316390
FEC V3.1 has added the compiler flag `CompilerFlags.ThrowOnNotSupportedExpression`.

src/FastExpressionCompiler/TestTools.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,12 @@ public static void AssertOpCodes(this IEnumerable<ILInstruction> il, params OpCo
6565
#endif
6666
}
6767

68-
public static void PrintExpression(this Expression expr, bool completeTypeNames = false)
68+
public static void PrintExpression(this Expression expr, bool completeTypeNames = false,
69+
[CallerMemberName] string caller = "", [CallerFilePath] string filePath = "")
6970
{
7071
if (!AllowPrintExpression) return;
72+
Console.WriteLine();
73+
Console.WriteLine($"//{Path.GetFileNameWithoutExtension(filePath)}.{caller}");
7174
Console.WriteLine(
7275
expr.ToExpressionString(out var _, out var _, out var _,
7376
stripNamespace: true,
@@ -76,6 +79,10 @@ public static void PrintExpression(this Expression expr, bool completeTypeNames
7679
);
7780
}
7881

82+
public static void PrintExpression(this IDelegateDebugInfo debugInfo, bool completeTypeNames = false,
83+
[CallerMemberName] string caller = "", [CallerFilePath] string filePath = "") =>
84+
PrintExpression(debugInfo.Expression, completeTypeNames, caller, filePath);
85+
7986
public static void PrintCSharp(this Expression expr, bool completeTypeNames = false,
8087
[CallerMemberName] string caller = "", [CallerFilePath] string filePath = "")
8188
{
@@ -129,8 +136,9 @@ public static void PrintCSharp(this Expression expr, ref string result)
129136
/// In case of nested lambda represented in the expression of the Constant Delegate,
130137
/// and the Delegate.Target being IDelegateDebugInfo, you may call `IDelegateDebugInfo.EnumerateNestedLambdas()`
131138
/// and output C# for each nested lambda</summary>
132-
public static void PrintCSharp(this IDelegateDebugInfo debugInfo) =>
133-
debugInfo.Expression.PrintCSharp();
139+
public static void PrintCSharp(this IDelegateDebugInfo debugInfo, bool completeTypeNames = false,
140+
[CallerMemberName] string caller = "", [CallerFilePath] string filePath = "") =>
141+
debugInfo.Expression.PrintCSharp(completeTypeNames, caller, filePath);
134142

135143
public static void PrintIL(this Delegate dlg, [CallerMemberName] string tag = null)
136144
{
@@ -178,10 +186,10 @@ private static void PrintIL(IDelegateDebugInfo debugInfo,
178186
{
179187
ref var printedTag = ref uniquePrinted.AddOrGetValueRef(nested, out var printed);
180188
if (printed)
181-
PrintIL($"{printedTag}", "already printed", static (ap, s) => s.Append(ap));
189+
PrintIL($"{printedTag}", "printed already", static (ap, s) => s.Append(ap));
182190
else
183191
{
184-
printedTag = $"{n}_{tag}";
192+
printedTag = $"{n}_nested_in_{tag}";
185193
PrintIL(nested, ref totalNestedCount, ref uniquePrinted, printedTag);
186194
}
187195
++n;

test/FastExpressionCompiler.IssueTests/Issue347_InvalidProgramException_on_compiling_an_expression_that_returns_a_record_which_implements_IList.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,27 @@ public class Issue347_InvalidProgramException_on_compiling_an_expression_that_re
2121
{
2222
public int Run()
2323
{
24+
Issue478_Test_diagnostics();
2425
Test_struct_parameter_in_closure_of_the_nested_lambda();
2526
Test_passing_struct_item_in_object_array_parameter();
2627
Test_nullable_param_in_closure_of_the_nested_lambda();
2728
Test_nullable_of_struct_and_struct_field_in_the_nested_lambda();
2829
Test_original();
29-
return 5;
30+
return 6;
31+
}
32+
33+
public void Issue478_Test_diagnostics()
34+
{
35+
System.Linq.Expressions.Expression<Func<int, Func<int>>> expr = n => () => n + 1;
36+
var e = expr.FromSysExpression();
37+
e.PrintExpression();
38+
e.PrintCSharp();
39+
40+
var f = e.CompileFast(flags: CompilerFlags.EnableDelegateDebugInfo);
41+
var d = f.TryGetDebugInfo();
42+
d.PrintExpression();
43+
d.PrintCSharp();
44+
d.PrintIL();
3045
}
3146

3247
public void Test_passing_struct_item_in_object_array_parameter()

0 commit comments

Comments
 (0)