Skip to content

Commit 83d886d

Browse files
author
maximv
committed
added the working Type ToCode and logo!
1 parent 3326b8c commit 83d886d

File tree

6 files changed

+217
-45
lines changed

6 files changed

+217
-45
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# FastExpressionCompiler
22

3+
<img src="./logo.png" alt="logo"/>
4+
35
[DryIoc]: https://github.com/dadhi/DryIoc
46
[ExpressionToCodeLib]: https://github.com/EamonNerbonne/ExpressionToCode
57
[ExpressionTree]: https://msdn.microsoft.com/en-us/library/mt654263.aspx
@@ -263,3 +265,7 @@ expression at hand and may optimize for delegate with the closure or for "static
263265

264266
Both optimizations are visible in benchmark results: search for `LightExpression` and
265267
`FastCompiledLambdaWithPreCreatedClosure` respectively.
268+
269+
270+
---
271+
<a target="_blank" href="https://icons8.com/icons/set/bitten-ice-pop">Bitten Ice Pop icon</a> icon by <a target="_blank" href="https://icons8.com">Icons8</a>

logo.png

1.74 KB
Loading

src/FastExpressionCompiler.LightExpression/Expression.cs

+123-37
Original file line numberDiff line numberDiff line change
@@ -1488,69 +1488,155 @@ internal static StringBuilder AppendName<T>(this StringBuilder sb, string name,
14881488
: sb.Append(type.ToCode(true, null)).Append('_').Append(identity.GetHashCode());
14891489

14901490
/// <summary>Converts the <paramref name="type"/> into the proper C# representation.</summary>
1491-
public static string ToCode(this Type type, bool stripNamespace = false, Func<Type, string, string> printType = null)
1491+
public static string ToCode(this Type type,
1492+
bool stripNamespace = false, Func<Type, string, string> printType = null, bool printGenericTypeArgs = false)
14921493
{
1494+
if (type.IsGenericParameter)
1495+
return !printGenericTypeArgs ? string.Empty
1496+
: (printType?.Invoke(type, type.Name) ?? type.Name);
1497+
1498+
Type arrayType = null;
1499+
if (type.IsArray)
1500+
{
1501+
// store the original type for the later and process its element type further here
1502+
arrayType = type;
1503+
type = type.GetElementType();
1504+
}
1505+
14931506
// the default handling of the built-in types
1507+
string buildInTypeString = null;
14941508
if (type == typeof(void))
1495-
return "void";
1509+
buildInTypeString = "void";
14961510
if (type == typeof(object))
1497-
return "object";
1511+
buildInTypeString = "object";
14981512
if (type == typeof(bool))
1499-
return "bool";
1513+
buildInTypeString = "bool";
15001514
if (type == typeof(int))
1501-
return "int";
1515+
buildInTypeString = "int";
15021516
if (type == typeof(short))
1503-
return "short";
1517+
buildInTypeString = "short";
15041518
if (type == typeof(byte))
1505-
return "byte";
1519+
buildInTypeString = "byte";
15061520
if (type == typeof(double))
1507-
return "double";
1521+
buildInTypeString = "double";
15081522
if (type == typeof(float))
1509-
return "float";
1523+
buildInTypeString = "float";
15101524
if (type == typeof(char))
1511-
return "char";
1525+
buildInTypeString = "char";
15121526
if (type == typeof(string))
1513-
return "string";
1527+
buildInTypeString = "string";
15141528

1515-
var isArray = type.IsArray;
1516-
if (isArray)
1517-
type = type.GetElementType();
1529+
if (buildInTypeString != null)
1530+
return printType?.Invoke(arrayType ?? type, buildInTypeString) ?? buildInTypeString;
15181531

1519-
var typeString = stripNamespace ? type.Name : type.FullName ?? type.Name;
1532+
var parentCount = 0;
1533+
for (var ti = type.GetTypeInfo(); ti.IsNested; ti = ti.DeclaringType.GetTypeInfo())
1534+
++parentCount;
15201535

1521-
typeString = typeString.Replace('+', '.'); // handling the nested types
1536+
Type[] parentTypes = null;
1537+
if (parentCount > 0)
1538+
{
1539+
parentTypes = new Type[parentCount];
1540+
var pt = type.DeclaringType;
1541+
for (var i = 0; i < parentTypes.Length; i++, pt = pt.DeclaringType)
1542+
parentTypes[i] = pt;
1543+
}
15221544

15231545
var typeInfo = type.GetTypeInfo();
1524-
if (!typeInfo.IsGenericType)
1546+
Type[] typeArgs = null;
1547+
var isTypeClosedGeneric = false;
1548+
if (type.IsGenericType)
15251549
{
1526-
if (printType != null)
1527-
typeString = printType.Invoke(type, typeString);
1528-
return isArray ? typeString + "[]" : typeString;
1550+
isTypeClosedGeneric = !typeInfo.IsGenericTypeDefinition;
1551+
typeArgs = isTypeClosedGeneric ? typeInfo.GenericTypeArguments : typeInfo.GenericTypeParameters;
15291552
}
15301553

1554+
var typeArgsConsumedByParentsCount = 0;
15311555
var s = new StringBuilder();
1532-
var tickIndex = typeString.IndexOf('`');
1533-
if (tickIndex == -1)
1534-
s.Append(typeString);
1535-
else
1536-
s.Append(typeString.Substring(0, tickIndex));
1537-
1538-
s.Append('<'); // todo: handling the generics in the nested type
1556+
if (!stripNamespace)
1557+
s.Append(type.Namespace).Append('.');
15391558

1540-
var genericArgs = typeInfo.GetGenericTypeParametersOrArguments();
1541-
if (typeInfo.IsGenericTypeDefinition)
1542-
s.Append(',', genericArgs.Length - 1);
1543-
else
1544-
for (var i = 0; i < genericArgs.Length; i++)
1545-
(i > 0 ? s.Append(", ") : s).Append(genericArgs[i].ToCode(stripNamespace, printType));
1559+
if (parentTypes != null)
1560+
{
1561+
for (var p = parentTypes.Length - 1; p >= 0; --p)
1562+
{
1563+
var parentType = parentTypes[p];
1564+
var parentTypeInfo = parentType.GetTypeInfo();
15461565

1547-
s.Append('>');
1566+
if (!parentType.IsGenericType)
1567+
{
1568+
s.Append(parentType.Name).Append('.');
1569+
}
1570+
else
1571+
{
1572+
Type[] parentTypeArgs = null;
1573+
if (parentTypeInfo.IsGenericTypeDefinition)
1574+
{
1575+
parentTypeArgs = parentTypeInfo.GenericTypeParameters;
1576+
1577+
// replace the open parent args with the closed child args,
1578+
// and close the parent
1579+
if (isTypeClosedGeneric)
1580+
for (var t = 0; t < parentTypeArgs.Length; ++t)
1581+
parentTypeArgs[t] = typeArgs[t];
1582+
1583+
var parentTypeArgCount = parentTypeArgs.Length;
1584+
if (typeArgsConsumedByParentsCount > 0)
1585+
{
1586+
int ownArgCount = parentTypeArgCount - typeArgsConsumedByParentsCount;
1587+
if (ownArgCount == 0)
1588+
parentTypeArgs = null;
1589+
else
1590+
{
1591+
var ownArgs = new Type[ownArgCount];
1592+
for (var a = 0; a < ownArgs.Length; ++a)
1593+
ownArgs[a] = parentTypeArgs[a + typeArgsConsumedByParentsCount];
1594+
parentTypeArgs = ownArgs;
1595+
}
1596+
}
1597+
typeArgsConsumedByParentsCount = parentTypeArgCount;
1598+
}
1599+
else
1600+
{
1601+
parentTypeArgs = parentTypeInfo.GenericTypeArguments;
1602+
}
1603+
1604+
var parentTickIndex = parentType.Name.IndexOf('`');
1605+
s.Append(parentType.Name.Substring(0, parentTickIndex));
1606+
1607+
// The owned parentTypeArgs maybe empty because all args are defined in the parent's parents
1608+
if (parentTypeArgs?.Length > 0)
1609+
{
1610+
s.Append('<');
1611+
for (var t = 0; t < parentTypeArgs.Length; ++t)
1612+
(t == 0 ? s : s.Append(", "))
1613+
.Append(parentTypeArgs[t].ToCode(stripNamespace, printType, printGenericTypeArgs));
1614+
s.Append('>');
1615+
}
1616+
s.Append('.');
1617+
}
1618+
}
1619+
}
1620+
1621+
if (typeArgs != null && typeArgsConsumedByParentsCount < typeArgs.Length)
1622+
{
1623+
var tickIndex = type.Name.IndexOf('`');
1624+
s.Append(type.Name.Substring(0, tickIndex)).Append('<');
1625+
for (var i = 0; i < typeArgs.Length - typeArgsConsumedByParentsCount; ++i)
1626+
(i == 0 ? s : s.Append(", "))
1627+
.Append(typeArgs[i + typeArgsConsumedByParentsCount]
1628+
.ToCode(stripNamespace, printType, printGenericTypeArgs));
1629+
s.Append('>');
1630+
}
1631+
else
1632+
{
1633+
s.Append(type.Name);
1634+
}
15481635

1549-
if (isArray)
1636+
if (arrayType != null)
15501637
s.Append("[]");
15511638

1552-
typeString = s.ToString();
1553-
return printType?.Invoke(type, typeString) ?? typeString;
1639+
return printType?.Invoke(arrayType ?? type, s.ToString()) ?? s.ToString();
15541640
}
15551641

15561642
/// Prints valid C# Boolean

src/FastExpressionCompiler/FastExpressionCompiler.cs

+7-4
Original file line numberDiff line numberDiff line change
@@ -2623,7 +2623,6 @@ private static bool TryEmitNotNullConstant(
26232623
if (constIndex == -1)
26242624
return false;
26252625

2626-
// todo: @incomplete - are we still using the usage to decide for the vars?
26272626
var varIndex = closure.ConstantUsageThenVarIndex.Items[constIndex] - 1;
26282627
if (varIndex > 0)
26292628
EmitLoadLocalVariable(il, varIndex);
@@ -3737,13 +3736,17 @@ private static bool TryEmitNestedLambda(LambdaExpression lambdaExpr,
37373736
private static bool TryEmitInvoke(InvocationExpression expr,
37383737
IReadOnlyList<ParameterExpression> paramExprs, ILGenerator il, ref ClosureInfo closure, ParentFlags parent)
37393738
{
3740-
var lambda = expr.Expression; // todo: @perf check if that a Constant or LambdaExpression and call the their emit methods directly
3741-
var delegateInvokeMethod = lambda.Type.FindDelegateInvokeMethod();
3742-
3739+
var lambda = expr.Expression;
37433740
var useResult = parent & ~ParentFlags.IgnoreResult;
3741+
3742+
// if (lambda is ConstantExpression cl) {
3743+
// // todo: @perf call directly
3744+
// }
37443745
if (!TryEmit(lambda, paramExprs, il, ref closure, useResult))
37453746
return false;
37463747

3748+
var delegateInvokeMethod = lambda.Type.FindDelegateInvokeMethod();
3749+
37473750
#if LIGHT_EXPRESSION
37483751
if (expr is OneArgumentInvocationExpression oneArgExpr)
37493752
{

test/FastExpressionCompiler.IssueTests/IssueXXX_Loop_wih_conditions_fails.cs

+79-3
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,87 @@ public class IssueXXX_Loop_wih_conditions_fails : ITest
1818
{
1919
public int Run()
2020
{
21-
Test1();
22-
return 1;
21+
#if LIGHT_EXPRESSION
22+
Test_nested_generic_type_output();
23+
Test_triple_nested_non_generic();
24+
Test_triple_nested_open_generic();
25+
Test_non_generic_classes();
26+
#endif
27+
// Test1();
28+
return 4;
29+
}
30+
31+
32+
#if LIGHT_EXPRESSION
33+
[Test]
34+
public void Test_nested_generic_type_output()
35+
{
36+
var s = typeof(ReadMethods<Test[], BufferedStream, Settings_1449479367_b6fc048b>.ReadSealed)
37+
.ToCode(true, (_, x) => x.Replace("IssueXXX_Loop_wih_conditions_fails.", ""));
38+
39+
Assert.AreEqual("ReadMethods<Test[], BufferedStream, Settings_1449479367_b6fc048b>.ReadSealed", s);
40+
}
41+
42+
[Test]
43+
public void Test_triple_nested_non_generic()
44+
{
45+
var s = typeof(A<int>.B<string>.Z).ToCode(true);
46+
Assert.AreEqual("IssueXXX_Loop_wih_conditions_fails.A<int>.B<string>.Z", s);
47+
48+
s = typeof(A<int>.B<string>.Z).ToCode();
49+
Assert.AreEqual("FastExpressionCompiler.LightExpression.IssueTests.IssueXXX_Loop_wih_conditions_fails.A<int>.B<string>.Z", s);
50+
51+
s = typeof(A<int>.B<string>.Z[]).ToCode(true);
52+
Assert.AreEqual("IssueXXX_Loop_wih_conditions_fails.A<int>.B<string>.Z[]", s);
53+
54+
s = typeof(A<int>.B<string>.Z[]).ToCode(true, (_, x) => x.Replace("IssueXXX_Loop_wih_conditions_fails.", ""));
55+
Assert.AreEqual("A<int>.B<string>.Z[]", s);
56+
}
57+
58+
[Test]
59+
public void Test_triple_nested_open_generic()
60+
{
61+
var s = typeof(A<>).ToCode(true, (_, x) => x.Replace("IssueXXX_Loop_wih_conditions_fails.", ""));
62+
Assert.AreEqual("A<>", s);
63+
64+
s = typeof(A<>).ToCode(true, (_, x) => x.Replace("IssueXXX_Loop_wih_conditions_fails.", ""), true);
65+
Assert.AreEqual("A<X>", s);
66+
67+
s = typeof(A<>.B<>).ToCode(true, (_, x) => x.Replace("IssueXXX_Loop_wih_conditions_fails.", ""));
68+
Assert.AreEqual("A<>.B<>", s);
69+
70+
s = typeof(A<>.B<>.Z).ToCode(true, (_, x) => x.Replace("IssueXXX_Loop_wih_conditions_fails.", ""));
71+
Assert.AreEqual("A<>.B<>.Z", s);
72+
73+
s = typeof(A<>.B<>.Z).ToCode(true, (_, x) => x.Replace("IssueXXX_Loop_wih_conditions_fails.", ""), true);
74+
Assert.AreEqual("A<X>.B<Y>.Z", s);
2375
}
2476

2577
[Test]
78+
public void Test_non_generic_classes()
79+
{
80+
var s = typeof(A.B.C).ToCode(true, (_, x) => x.Replace("IssueXXX_Loop_wih_conditions_fails.", ""));
81+
Assert.AreEqual("A.B.C", s);
82+
}
83+
84+
class A
85+
{
86+
public class B
87+
{
88+
public class C {}
89+
}
90+
}
91+
92+
class A<X>
93+
{
94+
public class B<Y>
95+
{
96+
public class Z {}
97+
}
98+
}
99+
100+
#endif
101+
// [Test]
26102
public void Test1()
27103
{
28104
// var e = new Expression[63]; // unique expressions
@@ -46,7 +122,7 @@ public void Test1()
46122
// e[8] = MakeBinary(ExpressionType.Assign,
47123
// e[4]/*Parameter*/,
48124
// e[9] = Call(
49-
// e[6]/*Parameter*/,
125+
// e[6]/*Parameter*/
50126
// typeof(BufferedStream)/*.Read*/.GetMethods()[10].MakeGenericMethod(typeof(int)))),
51127
// e[10] = MakeBinary(ExpressionType.Assign,
52128
// e[1]/*Parameter*/,

test/FastExpressionCompiler.TestsRunner/Program.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ public class Program
1010
public static void Main()
1111
{
1212
RunAllTests();
13-
// new Issue156_InvokeAction().Run();
13+
14+
// new FastExpressionCompiler.LightExpression.IssueTests.IssueXXX_Loop_wih_conditions_fails().Run();
1415
// new FastExpressionCompiler.LightExpression.IssueTests.Issue156_InvokeAction().Run();
1516
// new FastExpressionCompiler.LightExpression.IssueTests.Issue215_Assign_to_member_test().Run();
1617
// new FastExpressionCompiler.LightExpression.IssueTests.Issue237_Trying_to_implement_For_Foreach_loop_but_getting_an_InvalidProgramException_thrown().Run();

0 commit comments

Comments
 (0)