diff --git a/source/Server/Decompilation/AstOnly/FSharpAstTarget.cs b/source/Server/Decompilation/AstOnly/FSharpAstTarget.cs index 68ec27f..024ef27 100644 --- a/source/Server/Decompilation/AstOnly/FSharpAstTarget.cs +++ b/source/Server/Decompilation/AstOnly/FSharpAstTarget.cs @@ -25,6 +25,8 @@ namespace SharpLab.Server.Decompilation.AstOnly { new Lazy>>(CompileTagNameGetters, LazyThreadSafetyMode.ExecutionAndPublication); private static readonly Lazy>> ConstValueGetters = new Lazy>>(CompileConstValueGetters, LazyThreadSafetyMode.ExecutionAndPublication); + private static readonly Lazy> AstTypeNames = + new Lazy>(CollectAstTypeNames, LazyThreadSafetyMode.ExecutionAndPublication); private static class Methods { // ReSharper disable MemberHidesStaticFromOuterClass @@ -43,6 +45,12 @@ namespace SharpLab.Server.Decompilation.AstOnly { // ReSharper restore MemberHidesStaticFromOuterClass } + private static class EnumCache + where TEnum : struct, IFormattable + { + public static readonly IReadOnlyDictionary Strings = Enum.GetValues(typeof(TEnum)).Cast().ToDictionary(e => e, e => e.ToString("G", null)); + } + public Task GetAstAsync(IWorkSession session, CancellationToken cancellationToken) { var parseTree = session.FSharp().GetLastParseResults()?.ParseTree?.Value; return Task.FromResult((object)(parseTree as Ast.ParsedInput.ImplFile)); @@ -59,7 +67,7 @@ namespace SharpLab.Server.Decompilation.AstOnly { private static void SerializeNode(object node, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted) { EnsureChildrenStarted(ref parentChildrenStarted, writer); writer.WriteStartObject(); - writer.WriteProperty("kind", GetFullName(node.GetType())); + writer.WriteProperty("kind", AstTypeNames.Value[node.GetType()]); if (parentPropertyName != null) writer.WriteProperty("property", parentPropertyName); @@ -114,18 +122,18 @@ namespace SharpLab.Server.Decompilation.AstOnly { } private static void SerializeEnum(TEnum value, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted) - where TEnum: IFormattable + where TEnum: struct, IFormattable { EnsureChildrenStarted(ref parentChildrenStarted, writer); if (parentPropertyName != null) { writer.WriteStartObject(); writer.WriteProperty("type", "value"); writer.WriteProperty("property", parentPropertyName); - writer.WriteProperty("value", value.ToString("G", null)); + writer.WriteProperty("value", EnumCache.Strings[value]); writer.WriteEndObject(); } else { - writer.WriteValue(value.ToString("G", null)); + writer.WriteValue(EnumCache.Strings[value]); } } @@ -214,12 +222,6 @@ namespace SharpLab.Server.Decompilation.AstOnly { && !(type.Name.StartsWith("SequencePoint")); } - private static string GetFullName(Type astType) { - if (astType == typeof(Ast)) - return "Ast"; - return GetFullName(astType.DeclaringType) + "." + astType.Name; - } - private static string GetTagName(object node) { var getter = TagNameGetters.Value.GetValueOrDefault(node.GetType()); return getter?.Invoke(node); @@ -275,6 +277,21 @@ namespace SharpLab.Server.Decompilation.AstOnly { return getters; } + private static IReadOnlyDictionary CollectAstTypeNames() { + var results = new Dictionary(); + void CollectRecusive(Type astType, string parentPrefix) { + var name = parentPrefix + astType.Name; + var prefix = name + "."; + results.Add(astType, name); + foreach (var nested in astType.GetNestedTypes()) { + CollectRecusive(nested, prefix); + } + } + + CollectRecusive(typeof(Ast), ""); + return results; + } + public IReadOnlyCollection SupportedLanguageNames { get; } = new[] {"F#"}; } }