JensKrumsieck/ChemSharp

View on GitHub
Generators/ChemSharp.Generator/MathFGenerator.cs

Summary

Maintainability
A
0 mins
Test Coverage
using System.Globalization;
using System.Reflection;
using System.Text;
using ChemSharp.Generator.Extension;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

namespace ChemSharp.Generator;

[Generator]
public class MathFGenerator : ISourceGenerator
{
    private const string Indent = "    ";

    /// <summary>
    ///     To make sure it does not generate with higher NET Version
    ///     May be changed in future
    /// </summary>
    private readonly string[] _filter =
    {
        "Sin", "Cos", "Tan", "Atan", "Acos", "Asin", "Atan2", "Sqrt", "Pow", "Log", "Exp"
    };

    public void Initialize(GeneratorInitializationContext context)
    {
    }

    public void Execute(GeneratorExecutionContext context)
    {
        var math = typeof(Math);
        var methods = math.GetMethods(BindingFlags.Static | BindingFlags.Public)
                          .Where(m => _filter.Contains(m.Name) && m.ReturnType == typeof(double)).ToArray();
        var constants = math.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);

        var src = new StringBuilder();
        src.AppendLine("//Auto Generated Code");
        src.AppendLine("#if NETSTANDARD2_0");
        src.AppendLine("namespace ChemSharp.Mathematics");
        src.AppendLine("{");
        src.AppendLine($"{Indent}public static class MathF");
        src.AppendLine($"{Indent}{{");

        AppendConstants(src, constants);
        AppendMethods(src, methods);

        src.AppendLine($"{Indent}}}"); //close class
        src.AppendLine("}"); //close ns
        src.AppendLine("#endif");

        context.AddSource("MathF.cs", SourceText.From(src.ToString(), Encoding.UTF8));
    }

    private static void AppendMethods(StringBuilder src, MethodInfo[] methods)
    {
        foreach (var m in methods.DistinctBy(s => s.Name))
        {
            var head = $"public static float {m.Name} (";
            var body = $"(float)System.Math.{m.Name}(";
            var param = m.GetParameters().Where(s => s.ParameterType == typeof(double)).ToArray();
            var signatures = string.Join(",", param.Select(s => "float " + s.Name));
            var call = string.Join(",", param.Select(s => s.Name));
            head += signatures + ")";
            body += call + ");";

            src.AppendLine($"{Indent}{Indent}{head} => {body}");
        }
    }

    private static void AppendConstants(StringBuilder src, FieldInfo[] fields)
    {
        foreach (var f in fields)
            if (f.IsLiteral && !f.IsInitOnly && f.FieldType == typeof(double))
                src.AppendLine($"{Indent}{Indent}public const float {f.Name} = {Convert.ToDouble(f.GetRawConstantValue()).ToString(CultureInfo.InvariantCulture)}f;");
    }
}