Browse Source

refactor: combine invalid member access case in SourceGenerator

akeit0 2 weeks ago
parent
commit
3fcf276026

+ 80 - 25
src/Lua.SourceGenerator/LuaObjectGenerator.Emit.cs

@@ -13,7 +13,8 @@ partial class LuaObjectGenerator
             : "(";
     }
 
-    static bool TryEmit(TypeMetadata typeMetadata, CodeBuilder builder, SymbolReferences references, Compilation compilation, in SourceProductionContext context, Dictionary<INamedTypeSymbol, TypeMetadata> metaDict)
+    static bool TryEmit(TypeMetadata typeMetadata, CodeBuilder builder, SymbolReferences references, Compilation compilation, in SourceProductionContext context, Dictionary<INamedTypeSymbol, TypeMetadata> metaDict,
+        TempCollections tempCollections)
     {
         try
         {
@@ -87,19 +88,19 @@ partial class LuaObjectGenerator
 
             using var _ = builder.BeginBlockScope($"partial {typeDeclarationKeyword} {typeMetadata.TypeName} : global::Lua.ILuaUserData");
 
-            var metamethodSet = new HashSet<LuaObjectMetamethod>();
+            var metamethodSet = tempCollections.Metamethods;
 
             if (!TryEmitMethods(typeMetadata, builder, references, compilation, metamethodSet, context))
             {
                 return false;
             }
 
-            if (!TryEmitIndexMetamethod(typeMetadata, builder, references, compilation, context))
+            if (!TryEmitIndexMetamethod(typeMetadata, builder, references, compilation, context, tempCollections))
             {
                 return false;
             }
 
-            if (!TryEmitNewIndexMetamethod(typeMetadata, builder, references, context))
+            if (!TryEmitNewIndexMetamethod(typeMetadata, builder, references, context, tempCollections))
             {
                 return false;
             }
@@ -269,26 +270,26 @@ partial class LuaObjectGenerator
         return isValid;
     }
 
-    static bool TryEmitIndexMetamethod(TypeMetadata typeMetadata, CodeBuilder builder, SymbolReferences references, Compilation compilation, in SourceProductionContext context)
+    static bool TryEmitIndexMetamethod(TypeMetadata typeMetadata, CodeBuilder builder, SymbolReferences references, Compilation compilation, in SourceProductionContext context, TempCollections tempCollections)
     {
         builder.AppendLine(@"static readonly global::Lua.LuaFunction __metamethod_index = new global::Lua.LuaFunction(""index"", (context, ct) =>");
 
         using (builder.BeginBlockScope())
         {
             builder.AppendLine($"var userData = context.GetArgument<{typeMetadata.FullTypeName}>(0);");
-            builder.AppendLine($"var key = context.GetArgument<global::System.String>(1);");
+            builder.AppendLine("var key = context.GetArgument<global::System.String>(1);");
             builder.AppendLine("var result = key switch");
-
             using (builder.BeginBlockScope())
             {
                 foreach (var propertyMetadata in typeMetadata.Properties)
                 {
                     if (propertyMetadata.IsWriteOnly)
                     {
-                        builder.AppendLine(@$"""{propertyMetadata.LuaMemberName}"" => throw new global::Lua.LuaRuntimeException(context.State, $""'{{key}}' cannot be read.""),");
+                        tempCollections.InvalidMemberNames.Add(propertyMetadata.LuaMemberName);
                         continue;
                     }
 
+
                     var conversionPrefix = GetLuaValuePrefix(propertyMetadata.Type, references, compilation);
                     if (propertyMetadata.IsStatic)
                     {
@@ -306,7 +307,35 @@ partial class LuaObjectGenerator
                     builder.AppendLine(@$"""{methodMetadata.LuaMemberName}"" => new global::Lua.LuaValue(__function_{methodMetadata.LuaMemberName}),");
                 }
 
-                builder.AppendLine(@$"_ => global::Lua.LuaValue.Nil,");
+                builder.Append("_ => ");
+                {
+                    if (tempCollections.InvalidMemberNames.Count > 0)
+                    {
+                        builder.Append("(key is ", false);
+                        for (var index = 0; index < tempCollections.InvalidMemberNames.Count; index++)
+                        {
+                            var name = tempCollections.InvalidMemberNames[index];
+                            builder.Append("\"", false);
+                            builder.Append(name, false);
+                            builder.Append("\"", false);
+                            if (index < tempCollections.InvalidMemberNames.Count - 1)
+                            {
+                                builder.Append(" or ", false);
+                            }
+                        }
+
+                        builder.AppendLine(")", false);
+                        using (builder.BeginIndentScope())
+                        {
+                            builder.AppendLine(@"? throw new global::Lua.LuaRuntimeException(context.State, $""'{key}' cannot be read."")");
+                            builder.AppendLine(": global::Lua.LuaValue.Nil,");
+                        }
+
+                        tempCollections.InvalidMemberNames.Clear();
+                    }
+                    else
+                        builder.AppendLine(@"global::Lua.LuaValue.Nil,");
+                }
             }
 
             builder.AppendLine(";");
@@ -319,29 +348,31 @@ partial class LuaObjectGenerator
         return true;
     }
 
-    static bool TryEmitNewIndexMetamethod(TypeMetadata typeMetadata, CodeBuilder builder, SymbolReferences references, in SourceProductionContext context)
+    static bool TryEmitNewIndexMetamethod(TypeMetadata typeMetadata, CodeBuilder builder, SymbolReferences references, in SourceProductionContext context, TempCollections tempCollections)
     {
         builder.AppendLine(@"static readonly global::Lua.LuaFunction __metamethod_newindex = new global::Lua.LuaFunction(""newindex"", (context, ct) =>");
 
         using (builder.BeginBlockScope())
         {
             builder.AppendLine($"var userData = context.GetArgument<{typeMetadata.FullTypeName}>(0);");
-            builder.AppendLine($"var key = context.GetArgument<global::System.String>(1);");
+            builder.AppendLine("var key = context.GetArgument<global::System.String>(1);");
             builder.AppendLine("switch (key)");
 
             using (builder.BeginBlockScope())
             {
                 foreach (var propertyMetadata in typeMetadata.Properties)
                 {
+                    if (propertyMetadata.IsReadOnly)
+                    {
+                        tempCollections.InvalidMemberNames.Add(propertyMetadata.LuaMemberName);
+                        continue;
+                    }
+
                     builder.AppendLine(@$"case ""{propertyMetadata.LuaMemberName}"":");
 
                     using (builder.BeginIndentScope())
                     {
-                        if (propertyMetadata.IsReadOnly)
-                        {
-                            builder.AppendLine($@"throw new global::Lua.LuaRuntimeException(context.State, $""'{{key}}' cannot overwrite."");");
-                        }
-                        else if (propertyMetadata.IsStatic)
+                        if (propertyMetadata.IsStatic)
                         {
                             if (SymbolEqualityComparer.Default.Equals(propertyMetadata.Type, references.LuaValue))
                             {
@@ -373,19 +404,42 @@ partial class LuaObjectGenerator
                 foreach (var methodMetadata in typeMetadata.Methods
                              .Where(x => x.HasMemberAttribute))
                 {
-                    builder.AppendLine(@$"case ""{methodMetadata.LuaMemberName}"":");
-
-                    using (builder.BeginIndentScope())
-                    {
-                        builder.AppendLine($@"throw new global::Lua.LuaRuntimeException(context.State, $""'{{key}}' cannot overwrite."");");
-                    }
+                    tempCollections.InvalidMemberNames.Add(methodMetadata.LuaMemberName);
                 }
 
-                builder.AppendLine(@$"default:");
+                builder.AppendLine(@"default:");
 
                 using (builder.BeginIndentScope())
                 {
-                    builder.AppendLine(@$"throw new global::Lua.LuaRuntimeException(context.State, $""'{{key}}' not found."");");
+                    if (tempCollections.InvalidMemberNames.Count > 0)
+                    {
+                        builder.AppendLine("throw new global::Lua.LuaRuntimeException(context.State,");
+                        using (builder.BeginIndentScope())
+                        {
+                            builder.Append("(key is ");
+                            for (var index = 0; index < tempCollections.InvalidMemberNames.Count; index++)
+                            {
+                                var name = tempCollections.InvalidMemberNames[index];
+                                builder.Append("\"", false);
+                                builder.Append(name, false);
+                                builder.Append("\"", false);
+                                if (index < tempCollections.InvalidMemberNames.Count - 1)
+                                {
+                                    builder.Append(" or ", false);
+                                }
+                            }
+
+                            builder.AppendLine(")", false);
+                            using (builder.BeginIndentScope())
+                            {
+                                builder.AppendLine(@"? $""'{key}' cannot overwrite.""");
+                                tempCollections.InvalidMemberNames.Clear();
+                                builder.AppendLine(@": $""'{key}' not found."");");
+                            }
+                        }
+                    }
+                    else
+                        builder.AppendLine(@"throw new global::Lua.LuaRuntimeException(context.State, $""'{key}' not found."");");
                 }
             }
 
@@ -477,7 +531,8 @@ partial class LuaObjectGenerator
                     }
                     else
                     {
-                        builder.AppendLine($"var arg{index} = context.HasArgument({index}) ?  context.GetArgument<{parameterType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>({index}) : {syntax.Default!.Value.ToFullString()};");
+                        builder.AppendLine(
+                            $"var arg{index} = context.HasArgument({index}) ?  context.GetArgument<{parameterType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>({index}) : {syntax.Default!.Value.ToFullString()};");
                     }
                 }
                 else

+ 3 - 1
src/Lua.SourceGenerator/LuaObjectGenerator.cs

@@ -39,10 +39,11 @@ public partial class LuaObjectGenerator : IIncrementalGenerator
                     metaDict.Add(symbol, typeMeta);
                 }
 
+                var tempCollections = new TempCollections();
                 foreach (var pair in metaDict)
                 {
                     var typeMeta = pair.Value;
-                    if (TryEmit(typeMeta, builder, references, compilation, in sourceProductionContext, metaDict))
+                    if (TryEmit(typeMeta, builder, references, compilation, in sourceProductionContext, metaDict, tempCollections))
                     {
                         var fullType = typeMeta.FullTypeName
                             .Replace("global::", "")
@@ -52,6 +53,7 @@ public partial class LuaObjectGenerator : IIncrementalGenerator
                         sourceProductionContext.AddSource($"{fullType}.LuaObject.g.cs", builder.ToString());
                     }
 
+                    tempCollections.Clear();
                     builder.Clear();
                 }
             });

+ 12 - 0
src/Lua.SourceGenerator/TempCollections.cs

@@ -0,0 +1,12 @@
+namespace Lua.SourceGenerator;
+
+class TempCollections
+{
+    public readonly HashSet<LuaObjectMetamethod> Metamethods = new();
+    public readonly List<string> InvalidMemberNames = new();
+    public void Clear()
+    {
+        Metamethods.Clear();
+        InvalidMemberNames.Clear();
+    }
+}