diff --git a/Generators/Bindings/BindingEmitter.cs b/Generators/Bindings/BindingEmitter.cs index cebf152..cd905de 100644 --- a/Generators/Bindings/BindingEmitter.cs +++ b/Generators/Bindings/BindingEmitter.cs @@ -24,6 +24,8 @@ internal static void Emit(SourceProductionContext context, BindingTransformation private static string GenerateSource(BindingTransformationResult result) { var scopePrinter = new SyntaxNodeScopePrinter(Printer.Default, result.SyntaxNode.Parent); + scopePrinter.Printer.PrintLine("// "); + scopePrinter.Printer.PrintLine("#pragma warning disable CS0109 // Member does not hide an inherited member; new keyword is not required"); scopePrinter.PrintOpen(); var printer = scopePrinter.Printer; @@ -66,6 +68,7 @@ private static string GenerateSource(BindingTransformationResult result) } printer.CloseScope("};"); PrintCreateMemberBinding(printer, className, result); + PrintCreateFieldBindings(printer, className, result); PrintCreatePropertyBindings(printer, className, result); PrintCreateMethodBindings(printer, className, result); } @@ -85,7 +88,7 @@ private static void PrintFactoryClass(Printer printer, string className, Binding printer.PrintLine($"public static {className} {CreateInstanceMethodName}(object[] args)"); printer.OpenScope(); { - // Constructor that takes a single object[] parameter. + // Constructor that takes a single object[] or CLParams parameter. IMethodSymbol paramsConstructor = null; foreach (var method in result.Methods) @@ -93,7 +96,9 @@ private static void PrintFactoryClass(Printer printer, string className, Binding if (method.AttributeData.AttributeClass.Is(Types.Attributes.CLConstructor) == false) continue; - if (method.Symbol.Parameters.Length == 1 && method.Symbol.Parameters[0].Type.ToFullName() == "object[]") + if (method.Symbol.Parameters.Length == 1 && ( + method.Symbol.Parameters[0].Type.ToFullName() == "object[]" || + method.Symbol.Parameters[0].Type.ToFullName() == Types.CLParams)) { paramsConstructor = method.Symbol; break; @@ -102,8 +107,12 @@ private static void PrintFactoryClass(Printer printer, string className, Binding foreach (var method in result.Methods) { - if (method.AttributeData.AttributeClass.Is(Types.Attributes.CLConstructor) == false - || SymbolEqualityComparer.Default.Equals(method.Symbol, paramsConstructor)) + if (method.AttributeData.AttributeClass.Is(Types.Attributes.CLConstructor) == false) + continue; + + if (method.Symbol.Parameters.Length == 1 && ( + method.Symbol.Parameters[0].Type.ToFullName() == "object[]" || + method.Symbol.Parameters[0].Type.ToFullName() == Types.CLParams)) continue; printer.PrintLine($"if (args.Length == {method.Symbol.Parameters.Length})"); @@ -117,8 +126,11 @@ private static void PrintFactoryClass(Printer printer, string className, Binding if (paramsConstructor != null) { - var paramName = paramsConstructor.Parameters[0].Name; - printer.PrintLine($"object[] {paramName} = args;"); + var paramName = GetParameterName(paramsConstructor.Parameters[0]); + var paramType = paramsConstructor.Parameters[0].Type.ToFullName(); + printer.PrintLine(paramType == "object[]" + ? $"{paramType} {paramName} = args;" + : $"{paramType} {paramName} = new {Types.CLParams}(0, args);"); printer.PrintLine($"return new {className}({paramName});"); } else @@ -136,6 +148,12 @@ private static void PrintCreateMemberBinding(Printer printer, string className, { printer.PrintLine("return name switch"); printer.OpenScope(); + + foreach (var field in result.Fields) + { + var name = field.SpecifiedName; + printer.PrintLine($"\"{name}\" => __CreatePropertyBinding__{name}(),"); + } foreach (var property in result.Properties) { @@ -158,7 +176,43 @@ private static void PrintCreateMemberBinding(Printer printer, string className, printer.CloseScope(); } - // todo: PrintCreateFieldBindings + private static void PrintCreateFieldBindings(Printer printer, string className, BindingTransformationResult result) + { + const string instanceParamName = "__i"; + const string valueParamName = "__v"; + + const string getterName = "__getter"; + const string setterName = "__setter"; + + foreach (var field in result.Fields) + { + var exposedName = field.SpecifiedName; + var actualName = field.ActualName; + var type = field.Symbol.Type.ToFullName(); + var isReadonly = Types.Attributes.GetIsReadOnlyOrDefault(field.AttributeData, false); + + printer.PrintLine($"public static {Types.CLPropertyBinding}<{className}> __CreatePropertyBinding__{exposedName}()"); + printer.OpenScope(); + { + var instance = field.Symbol.IsStatic ? className : instanceParamName; + + var getter = getterName; + printer.PrintBeginLine($"static object {getterName}({className} {instanceParamName})"); + printer.PrintEndLine($" => {instance}.{actualName};"); + + var setter = "null"; + if (field.Symbol.IsReadOnly == false && isReadonly == false) + { + setter = setterName; + printer.PrintBeginLine($"static void {setterName}({className} {instanceParamName}, object {valueParamName})"); + printer.PrintEndLine($" => {instance}.{actualName} = global::CustomLogic.CustomLogicEvaluator.ConvertTo<{type}>({valueParamName});"); + } + + printer.PrintLine($"return new {Types.CLPropertyBinding}<{className}>({getter}, {setter});"); + } + printer.CloseScope(); + } + } private static void PrintCreatePropertyBindings(Printer printer, string className, BindingTransformationResult result) { @@ -243,61 +297,82 @@ private static void PrintCreateMethodBindings(Printer printer, string className, private static string PrintParameters(Printer printer, MemberInfo method, string argsParamName) { - if (method.Symbol.Parameters.Length == 1 && method.Symbol.Parameters[0].Type.ToFullName() == "object[]") + if (method.Symbol.Parameters.Length == 1) { - var paramName = method.Symbol.Parameters[0].Name; - printer.PrintLine($"object[] {paramName} = {argsParamName};"); + var paramName = GetParameterName(method.Symbol.Parameters[0]); + var type = method.Symbol.Parameters[0].Type.ToFullName(); + var isObjectArr = type == "object[]"; + var isCLParams = type == Types.CLParams; + + if (isObjectArr || isCLParams) + { + printer.PrintLine(isObjectArr + ? $"{type} {paramName} = {argsParamName};" + : $"{type} {paramName} = new {Types.CLParams}(0, {argsParamName});"); + + return argsParamName; + } } - else + + for (var i = 0; i < method.Symbol.Parameters.Length; i++) { - foreach (var parameter in method.Symbol.Parameters) + var parameter = method.Symbol.Parameters[i]; + var name = GetParameterName(parameter); + + var type = parameter.Type.ToFullName(); + var value = "default"; + + if (i == method.Symbol.Parameters.Length - 1 && type == Types.CLParams) { - var name = parameter.Name; - var type = parameter.Type.ToFullName(); - var value = "default"; - - if (parameter.IsOptional == false) - { - value = type != "object" - ? $"{Types.Evaluator}.ConvertTo<{type}>({argsParamName}[{parameter.Ordinal}])" - : $"{argsParamName}[{parameter.Ordinal}]"; - } - else if (parameter.HasExplicitDefaultValue) + value = $"new {Types.CLParams}({parameter.Ordinal}, {argsParamName})"; + } + else if (parameter.IsOptional == false) + { + value = type != "object" + ? $"{Types.Evaluator}.ConvertTo<{type}>({argsParamName}[{parameter.Ordinal}])" + : $"{argsParamName}[{parameter.Ordinal}]"; + } + else if (parameter.HasExplicitDefaultValue) + { + if (parameter.ExplicitDefaultValue != null) { - if (parameter.ExplicitDefaultValue != null) - { - value = SymbolDisplay.FormatPrimitive(parameter.ExplicitDefaultValue, true, false); - if (type == "float") - value += "f"; - } - else - value = "null"; + value = SymbolDisplay.FormatPrimitive(parameter.ExplicitDefaultValue, true, false); + if (type == "float") + value += "f"; } - - printer.PrintLine($"{type} {name} = {value};"); + else + value = "null"; } - foreach (var parameter in method.Symbol.Parameters) - { - var type = parameter.Type.ToFullName(); + printer.PrintLine($"{type} {name} = {value};"); + } + + foreach (var parameter in method.Symbol.Parameters) + { + var paramName = GetParameterName(parameter); + var type = parameter.Type.ToFullName(); - if (parameter.IsOptional) + if (parameter.IsOptional) + { + printer.PrintLine($"if ({argsParamName}.Length > {parameter.Ordinal})"); + printer.OpenScope(); { - printer.PrintLine($"if ({argsParamName}.Length > {parameter.Ordinal})"); - printer.OpenScope(); - { - var value = type != "object" - ? $"{Types.Evaluator}.ConvertTo<{type}>({argsParamName}[{parameter.Ordinal}])" - : $"{argsParamName}[{parameter.Ordinal}]"; - printer.PrintLine($"{parameter.Name} = {value};"); - } - printer.CloseScope(); + var value = type != "object" + ? $"{Types.Evaluator}.ConvertTo<{type}>({argsParamName}[{parameter.Ordinal}])" + : $"{argsParamName}[{parameter.Ordinal}]"; + printer.PrintLine($"{paramName} = {value};"); } + printer.CloseScope(); } } - var parameters = string.Join(", ", method.Symbol.Parameters.Select(x => x.Name)); + var parameters = string.Join(", ", method.Symbol.Parameters.Select(GetParameterName)); return parameters; } + + private static string GetParameterName(IParameterSymbol symbol) + { + return $"{symbol.Name}__{symbol.Ordinal}"; + } } } \ No newline at end of file diff --git a/Types.cs b/Types.cs index 6f00e8d..e25a319 100644 --- a/Types.cs +++ b/Types.cs @@ -14,6 +14,8 @@ public static class Types public const string CLPropertyBinding = CLRootNamespace + "CLPropertyBinding"; public const string CLMethodBinding = CLRootNamespace + "CLMethodBinding"; + public const string CLParams = CLRootNamespace + "CLParams"; + public const string BuiltinClassInstance = CLRootNamespace + "BuiltinClassInstance"; public static class Attributes