Skip to content

Commit 882cb60

Browse files
committed
C# 9.0 record type & new expression
1 parent 06b336e commit 882cb60

10 files changed

Lines changed: 168 additions & 84 deletions

‎CSharp.lua/CoreSystem.Lua/CoreSystem/Core.lua‎

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ function System.base(this)
942942
return getmetatable(getmetatable(this))
943943
end
944944

945-
local equalsObj, compareObj
945+
local equalsObj, compareObj, toString
946946
if debugsetmetatable then
947947
equalsObj = function (x, y)
948948
if x == y then
@@ -977,7 +977,7 @@ if debugsetmetatable then
977977
throw(System.ArgumentException("Argument_ImplementIComparable"))
978978
end
979979

980-
function System.toString(t)
980+
toString = function (t)
981981
return t ~= nil and t:ToString() or ""
982982
end
983983

@@ -1075,7 +1075,7 @@ else
10751075
throw(System.ArgumentException("Argument_ImplementIComparable"))
10761076
end
10771077

1078-
function System.toString(obj)
1078+
toString = function (obj)
10791079
if obj == nil then return "" end
10801080
local t = type(obj)
10811081
if t == "table" then
@@ -1091,6 +1091,7 @@ end
10911091

10921092
System.equalsObj = equalsObj
10931093
System.compareObj = compareObj
1094+
System.toString = toString
10941095

10951096
Object = defCls("System.Object", {
10961097
__call = new,
@@ -1280,42 +1281,6 @@ local ValueTuple = defStc("System.ValueTuple", {
12801281
local valueTupleMetaTable = setmetatable({ __index = ValueType, __call = tupleCreate }, ValueType)
12811282
setmetatable(ValueTuple, valueTupleMetaTable)
12821283

1283-
local function recordToString(t)
1284-
local a = { t.__name__, "{" }
1285-
local count = 3
1286-
local k, v
1287-
while true do
1288-
k, v = next(t, k)
1289-
if k == nil then
1290-
break
1291-
end
1292-
a[count] = k
1293-
a[count + 1] = '='
1294-
local i = v
1295-
k, v = next(t, k)
1296-
if i ~= nil then
1297-
if k ~= nil then
1298-
a[count + 2] = i:ToString() .. ','
1299-
count = count + 3
1300-
else
1301-
a[count + 2] = i:ToString()
1302-
count = count + 3
1303-
break
1304-
end
1305-
else
1306-
if k ~= nil then
1307-
a[count + 2] = ','
1308-
count = count + 3
1309-
else
1310-
count = count + 2
1311-
break
1312-
end
1313-
end
1314-
end
1315-
a[count] = "}"
1316-
return tconcat(a, ' ')
1317-
end
1318-
13191284
local function recordEquals(t, other)
13201285
if getmetatable(t) == getmetatable(other) then
13211286
for k, v in pairs(t) do
@@ -1328,11 +1293,55 @@ local function recordEquals(t, other)
13281293
return false
13291294
end
13301295

1331-
local RecordType
1332-
RecordType = defCls("System.RecordType", {
1333-
ToString = recordToString,
1296+
defCls("System.RecordType", {
13341297
__eq = recordEquals,
13351298
Equals = recordEquals,
1299+
PrintMembers = function (this, builder)
1300+
local p = pack(this.__members__())
1301+
local n = p.n
1302+
for i = 2, n do
1303+
local k = p[i]
1304+
local v = this[k]
1305+
builder:Append(k)
1306+
builder:Append(" = ")
1307+
if v ~= nil then
1308+
builder:Append(toString(v))
1309+
end
1310+
if i ~= n then
1311+
builder:Append(", ")
1312+
end
1313+
end
1314+
end,
1315+
ToString = function (this)
1316+
local p = pack(this.__members__())
1317+
local n = p.n
1318+
local t = { p[1], "{" }
1319+
local count = 3
1320+
for i = 2, n do
1321+
local k = p[i]
1322+
local v = this[k]
1323+
t[count] = k
1324+
t[count + 1] = "="
1325+
if v ~= nil then
1326+
if i ~= n then
1327+
t[count + 2] = toString(v) .. ','
1328+
else
1329+
t[count + 2] = toString(v)
1330+
end
1331+
else
1332+
if i ~= n then
1333+
t[count + 2] = ','
1334+
end
1335+
end
1336+
if v == nil and i == n then
1337+
count = count + 2
1338+
else
1339+
count = count + 3
1340+
end
1341+
end
1342+
t[count] = "}"
1343+
return tconcat(t, ' ')
1344+
end
13361345
})
13371346

13381347
local Attribute = defCls("System.Attribute")

‎CSharp.lua/CoreSystem.Lua/CoreSystem/Text/StringBuilder.lua‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,3 @@ local StringBuilder = System.define("System.Text.StringBuilder", {
210210
end
211211
})
212212
System.StringBuilder = StringBuilder
213-
214-
System.RecordType.PrintMembers = function (t, sb)
215-
end

‎CSharp.lua/LuaAst/LuaExpressionSyntax.cs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ public static implicit operator LuaExpressionSyntax(double number) {
3838
LuaNumberLiteralExpressionSyntax numberLiteral = number;
3939
return numberLiteral;
4040
}
41-
41+
42+
public LuaExpressionStatementSyntax ToStatementSyntax() {
43+
return this;
44+
}
45+
4246
public LuaBinaryExpressionSyntax Plus(LuaExpressionSyntax right) {
4347
return Binary(Tokens.Plus, right);
4448
}

‎CSharp.lua/LuaAst/LuaIdentifierNameSyntax.cs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public class LuaIdentifierNameSyntax : LuaExpressionSyntax {
9595
public static readonly LuaIdentifierNameSyntax Clone = "__clone__";
9696
public static readonly LuaIdentifierNameSyntax NullableClone = "System.Nullable.clone";
9797
public static readonly LuaIdentifierNameSyntax CopyThis = "__copy__";
98+
public static readonly LuaIdentifierNameSyntax RecordMembers = "__members__";
9899
public static readonly LuaIdentifierNameSyntax ValueType = "System.ValueType";
99100
public static readonly LuaIdentifierNameSyntax DateTime = "System.DateTime";
100101
public static readonly LuaIdentifierNameSyntax TimeSpan = "System.TimeSpan";
@@ -149,6 +150,8 @@ public static implicit operator LuaIdentifierNameSyntax(string valueText) {
149150
internal override void Render(LuaRenderer renderer) {
150151
renderer.Render(this);
151152
}
153+
154+
internal LuaStringLiteralExpressionSyntax ToStringLiteral() => new LuaStringLiteralExpressionSyntax(this);
152155
}
153156

154157
public sealed class LuaPropertyOrEventIdentifierNameSyntax : LuaIdentifierNameSyntax {

‎CSharp.lua/LuaSyntaxGenerator.cs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,6 +1566,9 @@ private bool IsPropertyFieldInternal(IPropertySymbol symbol) {
15661566
case SyntaxKind.AnonymousObjectMemberDeclarator: {
15671567
return true;
15681568
}
1569+
case SyntaxKind.Parameter: {
1570+
return true;
1571+
}
15691572
default: {
15701573
throw new InvalidOperationException();
15711574
}

‎CSharp.lua/LuaSyntaxNodeTransform.Helper.cs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1793,7 +1793,9 @@ public int GetConstructorIndex(IMethodSymbol symbool) {
17931793
}
17941794
} else {
17951795
if (typeSymbol.IsRecordType()) {
1796-
ctors.RemoveAt(0);
1796+
int posIndex = ctors.FindIndex(i => i.Parameters.Length == 1 && i.Parameters[0].Type.EQ(typeSymbol));
1797+
Contract.Assert(posIndex != -1);
1798+
ctors.RemoveAt(posIndex);
17971799
if (ctors.Count <= 1) {
17981800
return 0;
17991801
}

‎CSharp.lua/LuaSyntaxNodeTransform.Object.cs‎

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,39 @@ namespace CSharpLua {
2828
public sealed partial class LuaSyntaxNodeTransform {
2929
private readonly Stack<LuaIdentifierNameSyntax> conditionalTemps_ = new Stack<LuaIdentifierNameSyntax>();
3030

31+
private LuaExpressionSyntax GetObjectCreationExpression(IMethodSymbol symbol, BaseObjectCreationExpressionSyntax node) {
32+
LuaExpressionSyntax creationExpression;
33+
var expression = GetTypeName(symbol.ContainingType);
34+
var invokeExpression = BuildObjectCreationInvocation(symbol, expression);
35+
if (node.ArgumentList != null) {
36+
var refOrOutArguments = new List<RefOrOutArgument>();
37+
var arguments = BuildArgumentList(symbol, symbol.Parameters, node.ArgumentList, refOrOutArguments);
38+
TryRemoveNilArgumentsAtTail(symbol, arguments);
39+
invokeExpression.AddArguments(arguments);
40+
if (refOrOutArguments.Count > 0) {
41+
creationExpression = BuildInvokeRefOrOut(node, invokeExpression, refOrOutArguments);
42+
} else {
43+
creationExpression = invokeExpression;
44+
}
45+
} else {
46+
creationExpression = invokeExpression;
47+
}
48+
return creationExpression;
49+
}
50+
51+
private LuaExpressionSyntax GetObjectCreationInitializer(LuaExpressionSyntax creationExpression, BaseObjectCreationExpressionSyntax node) {
52+
if (node.Initializer == null) {
53+
return creationExpression;
54+
} else {
55+
int prevTempCount = CurFunction.TempCount;
56+
var temp = GetTempIdentifier();
57+
CurBlock.AddStatement(new LuaLocalVariableDeclaratorSyntax(temp, creationExpression));
58+
FillObjectInitializerExpression(temp, node.Initializer);
59+
ReleaseTempIdentifiers(prevTempCount);
60+
return !node.Parent.IsKind(SyntaxKind.ExpressionStatement) ? temp : LuaExpressionSyntax.EmptyExpression;
61+
}
62+
}
63+
3164
public override LuaSyntaxNode VisitObjectCreationExpression(ObjectCreationExpressionSyntax node) {
3265
var constExpression = GetConstExpression(node);
3366
if (constExpression != null) {
@@ -48,21 +81,7 @@ public override LuaSyntaxNode VisitObjectCreationExpression(ObjectCreationExpres
4881
var expressions = node.ArgumentList.Arguments.Select(i => i.Expression.AcceptExpression(this));
4982
creationExpression = BuildValueTupleCreateExpression(expressions);
5083
} else {
51-
var expression = node.Type.AcceptExpression(this);
52-
var invokeExpression = BuildObjectCreationInvocation(symbol, expression);
53-
if (node.ArgumentList != null) {
54-
var refOrOutArguments = new List<RefOrOutArgument>();
55-
var arguments = BuildArgumentList(symbol, symbol.Parameters, node.ArgumentList, refOrOutArguments);
56-
TryRemoveNilArgumentsAtTail(symbol, arguments);
57-
invokeExpression.AddArguments(arguments);
58-
if (refOrOutArguments.Count > 0) {
59-
creationExpression = BuildInvokeRefOrOut(node, invokeExpression, refOrOutArguments);
60-
} else {
61-
creationExpression = invokeExpression;
62-
}
63-
} else {
64-
creationExpression = invokeExpression;
65-
}
84+
creationExpression = GetObjectCreationExpression(symbol, node);
6685
}
6786
} else {
6887
var type = semanticModel_.GetSymbolInfo(node.Type).Symbol;
@@ -80,16 +99,7 @@ public override LuaSyntaxNode VisitObjectCreationExpression(ObjectCreationExpres
8099
creationExpression = new LuaInvocationExpressionSyntax(expression);
81100
}
82101

83-
if (node.Initializer == null) {
84-
return creationExpression;
85-
} else {
86-
int prevTempCount = CurFunction.TempCount;
87-
var temp = GetTempIdentifier();
88-
CurBlock.AddStatement(new LuaLocalVariableDeclaratorSyntax(temp, creationExpression));
89-
FillObjectInitializerExpression(temp, node.Initializer);
90-
ReleaseTempIdentifiers(prevTempCount);
91-
return !node.Parent.IsKind(SyntaxKind.ExpressionStatement) ? temp : LuaExpressionSyntax.EmptyExpression;
92-
}
102+
return GetObjectCreationInitializer(creationExpression, node);
93103
}
94104

95105
private void FillObjectInitializerExpression(LuaIdentifierNameSyntax temp, InitializerExpressionSyntax node) {
@@ -153,6 +163,12 @@ public override LuaSyntaxNode VisitAnonymousObjectCreationExpression(AnonymousOb
153163
return LuaIdentifierNameSyntax.AnonymousType.Invocation(table);
154164
}
155165

166+
public override LuaSyntaxNode VisitImplicitObjectCreationExpression(ImplicitObjectCreationExpressionSyntax node) {
167+
var symbol = (IMethodSymbol)semanticModel_.GetSymbolInfo(node).Symbol;
168+
var creationExpression = GetObjectCreationExpression(symbol, node);
169+
return GetObjectCreationInitializer(creationExpression, node);
170+
}
171+
156172
public override LuaSyntaxNode VisitInitializerExpression(InitializerExpressionSyntax node) {
157173
Contract.Assert(node.IsKind(SyntaxKind.ArrayInitializerExpression));
158174
var arrayType = (IArrayTypeSymbol)semanticModel_.GetTypeInfo(node).ConvertedType;

‎CSharp.lua/LuaSyntaxNodeTransform.cs‎

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,11 @@ limitations under the License.
2727

2828
namespace CSharpLua {
2929
public sealed partial class LuaSyntaxNodeTransform : CSharpSyntaxVisitor<LuaSyntaxNode> {
30-
public const int kStringConstInlineCount = 15;
30+
public const int kStringConstInlineCount = 27;
3131

3232
private sealed class MethodInfo {
3333
public IMethodSymbol Symbol { get; }
3434
public IList<LuaExpressionSyntax> RefOrOutParameters { get; }
35-
3635
public List<LuaIdentifierNameSyntax> InliningReturnVars { get; set; }
3736
public bool IsInlining => InliningReturnVars != null;
3837
public bool HasYield;
@@ -375,14 +374,15 @@ private void BuildTypeDeclaration(INamedTypeSymbol typeSymbol, TypeDeclarationSy
375374
BuildBaseTypes(typeSymbol, typeDeclaration, node.BaseList.Types, false);
376375
}
377376

378-
BuildTypeMembers(typeDeclaration, node);
379-
CheckTypeDeclaration(typeSymbol, typeDeclaration, attributes);
380-
377+
CheckRecordParameterCtor(typeSymbol, node, typeDeclaration);
378+
BuildTypeMembers(typeDeclaration, node);
379+
CheckTypeDeclaration(typeSymbol, typeDeclaration, attributes, node);
380+
381381
typeDeclarations_.Pop();
382382
CurCompilationUnit.AddTypeDeclarationCount();
383383
}
384384

385-
private void CheckTypeDeclaration(INamedTypeSymbol typeSymbol, LuaTypeDeclarationSyntax typeDeclaration, List<LuaExpressionSyntax> attributes) {
385+
private void CheckTypeDeclaration(INamedTypeSymbol typeSymbol, LuaTypeDeclarationSyntax typeDeclaration, List<LuaExpressionSyntax> attributes, BaseTypeDeclarationSyntax node) {
386386
if (typeDeclaration.IsNoneCtros) {
387387
var baseTypeSymbol = typeSymbol.BaseType;
388388
if (baseTypeSymbol != null) {
@@ -408,8 +408,11 @@ private void CheckTypeDeclaration(INamedTypeSymbol typeSymbol, LuaTypeDeclaratio
408408
typeDeclaration.AddCtor(function, true);
409409
}
410410

411-
if (typeSymbol.BaseType != null && typeSymbol.BaseType.SpecialType == SpecialType.System_Object && typeSymbol.IsRecordType()) {
412-
typeDeclaration.AddBaseTypes(LuaIdentifierNameSyntax.RecordType.ArrayOf(GetRecordInerfaceTypeName(typeSymbol)), null, null);
411+
if (typeSymbol.IsRecordType()) {
412+
if (typeSymbol.BaseType != null && typeSymbol.BaseType.SpecialType == SpecialType.System_Object) {
413+
typeDeclaration.AddBaseTypes(LuaIdentifierNameSyntax.RecordType.ArrayOf(GetRecordInerfaceTypeName(typeSymbol)), null, null);
414+
}
415+
BuildRecordMembers(typeSymbol, typeDeclaration);
413416
}
414417

415418
if (typeDeclaration.IsIgnoreExport) {
@@ -425,6 +428,42 @@ private void CheckTypeDeclaration(INamedTypeSymbol typeSymbol, LuaTypeDeclaratio
425428
}
426429
}
427430

431+
private void CheckRecordParameterCtor(INamedTypeSymbol typeSymbol, TypeDeclarationSyntax node, LuaTypeDeclarationSyntax typeDeclaration) {
432+
if (typeSymbol.IsRecordType()) {
433+
var recordDeclaration = (RecordDeclarationSyntax)node;
434+
if (recordDeclaration.ParameterList != null) {
435+
BuildRecordParameterCtor(typeSymbol, typeDeclaration, recordDeclaration);
436+
}
437+
}
438+
}
439+
440+
private void BuildRecordParameterCtor(INamedTypeSymbol typeSymbol, LuaTypeDeclarationSyntax typeDeclaration, RecordDeclarationSyntax recordDeclaration) {
441+
var parameterList = recordDeclaration.ParameterList.Accept<LuaParameterListSyntax>(this);
442+
var function = new LuaConstructorAdapterExpressionSyntax();
443+
function.AddParameter(LuaIdentifierNameSyntax.This);
444+
function.AddParameters(parameterList.Parameters);
445+
function.AddStatements(parameterList.Parameters.Select(i => LuaIdentifierNameSyntax.This.MemberAccess(i).Assignment(i).ToStatementSyntax()));
446+
typeDeclaration.AddCtor(function, false);
447+
var ctor = typeSymbol.InstanceConstructors.First();
448+
int index = 0;
449+
foreach (var p in ctor.Parameters) {
450+
var expression = GetFieldValueExpression(p.Type, null, out bool isLiteral, out _);
451+
if (expression != null) {
452+
typeDeclaration.AddField(parameterList.Parameters[index], expression, p.Type.IsImmutable() && isLiteral, false, false, true, null, false);
453+
}
454+
++index;
455+
}
456+
}
457+
458+
private void BuildRecordMembers(INamedTypeSymbol typeSymbol, LuaTypeDeclarationSyntax typeDeclaration) {
459+
var propertys = typeSymbol.GetMembers().OfType<IPropertySymbol>().Skip(1);
460+
var exprssions = new List<LuaExpressionSyntax>() { typeSymbol.Name.ToStringLiteral() };
461+
exprssions.AddRange(propertys.Select(i => GetMemberName(i).ToStringLiteral()));
462+
var function = new LuaFunctionExpressionSyntax();
463+
function.AddStatement(new LuaReturnStatementSyntax(exprssions));
464+
typeDeclaration.AddMethod(LuaIdentifierNameSyntax.RecordMembers, function, false);
465+
}
466+
428467
private INamedTypeSymbol VisitTypeDeclaration(INamedTypeSymbol typeSymbol, TypeDeclarationSyntax node, LuaTypeDeclarationSyntax typeDeclaration) {
429468
if (node.Modifiers.IsPartial()) {
430469
if (typeSymbol.DeclaringSyntaxReferences.Length > 1) {
@@ -485,7 +524,7 @@ internal void AcceptPartialType(PartialTypeDeclaration major, IEnumerable<Partia
485524
BuildTypeMembers(major.TypeDeclaration, typeDeclaration.Node);
486525
}
487526

488-
CheckTypeDeclaration(major.Symbol, major.TypeDeclaration, attributes);
527+
CheckTypeDeclaration(major.Symbol, major.TypeDeclaration, attributes, major.Node);
489528
typeDeclarations_.Pop();
490529
compilationUnits_.Pop();
491530

@@ -528,7 +567,7 @@ private void VisitEnumDeclaration(INamedTypeSymbol typeSymbol, EnumDeclarationSy
528567
var statement = member.Accept<LuaKeyValueTableItemSyntax>(this);
529568
enumDeclaration.Add(statement);
530569
}
531-
CheckTypeDeclaration(typeSymbol, enumDeclaration, attributes);
570+
CheckTypeDeclaration(typeSymbol, enumDeclaration, attributes, node);
532571
typeDeclarations_.Pop();
533572
generator_.AddEnumDeclaration(typeSymbol, enumDeclaration);
534573
}

0 commit comments

Comments
 (0)