[closes gh-125] Implemented (reasonably complete) AST-hover for F#.

This commit is contained in:
Andrey Shchekin 2017-06-21 01:02:09 +12:00
Родитель 6a4467b60c
Коммит 14c5a8b9b8
14 изменённых файлов: 269 добавлений и 173 удалений

Просмотреть файл

@ -15,7 +15,7 @@ namespace SharpLab.Server.Decompilation {
public abstract class AstBasedDecompiler : IDecompiler {
private static readonly ConcurrentDictionary<string, AssemblyDefinition> AssemblyCache = new ConcurrentDictionary<string, AssemblyDefinition>();
public void Decompile(Stream assemblyStream, TextWriter resultWriter) {
public void Decompile(Stream assemblyStream, TextWriter codeWriter) {
// ReSharper disable once AgentHeisenbug.CallToNonThreadSafeStaticMethodInThreadSafeType
var module = ModuleDefinition.ReadModule(assemblyStream);
((BaseAssemblyResolver)module.AssemblyResolver).ResolveFailure += (_, name) => AssemblyCache.GetOrAdd(name.FullName, fullName => {
@ -39,7 +39,7 @@ namespace SharpLab.Server.Decompilation {
RunTransforms(ast, context);
// I cannot use GenerateCode as it re-runs all the transforms
WriteResult(resultWriter, ast.SyntaxTree, context);
WriteResult(codeWriter, ast.SyntaxTree, context);
}
protected abstract void WriteResult(TextWriter writer, AstNode root, DecompilerContext context);

Просмотреть файл

@ -13,19 +13,23 @@ using Microsoft.FSharp.Collections;
using Microsoft.FSharp.Compiler;
using MirrorSharp.Advanced;
using MirrorSharp.FSharp.Advanced;
using SharpLab.Server.Decompilation.Internal;
namespace SharpLab.Server.Decompilation.AstOnly {
public class FSharpAstTarget : IAstTarget {
private delegate void SerializeChildAction<T>(T item, IFastJsonWriter writer, string parentPropertyName, ref bool childrenStarted);
private delegate void SerializeChildrenAction(object parent, IFastJsonWriter writer, ref bool childrenStarted);
private delegate void SerializeChildAction<T>(T item, IFastJsonWriter writer, string parentPropertyName, ref bool childrenStarted, IFSharpSession session);
private delegate void SerializeChildrenAction(object parent, IFastJsonWriter writer, ref bool childrenStarted, IFSharpSession session);
private delegate Range.range GetRangeFunc(object target);
private static readonly ConcurrentDictionary<Type, Lazy<SerializeChildrenAction>> ChildrenSerializers =
new ConcurrentDictionary<Type, Lazy<SerializeChildrenAction>>();
private static readonly ConcurrentDictionary<Type, Lazy<GetRangeFunc>> RangeGetters =
new ConcurrentDictionary<Type, Lazy<GetRangeFunc>>();
private static readonly Lazy<IReadOnlyDictionary<Type, Func<object, string>>> TagNameGetters =
new Lazy<IReadOnlyDictionary<Type, Func<object, string>>>(CompileTagNameGetters, LazyThreadSafetyMode.ExecutionAndPublication);
private static readonly Lazy<IReadOnlyDictionary<Type, Func<Ast.SynConst, string>>> ConstValueGetters =
new Lazy<IReadOnlyDictionary<Type, Func<Ast.SynConst, string>>>(CompileConstValueGetters, LazyThreadSafetyMode.ExecutionAndPublication);
private static readonly Lazy<IReadOnlyDictionary<Type, string>> AstTypeNames =
private static readonly Lazy<IReadOnlyDictionary<Type, string>> AstTypeNames =
new Lazy<IReadOnlyDictionary<Type, string>>(CollectAstTypeNames, LazyThreadSafetyMode.ExecutionAndPublication);
private static class Methods {
@ -56,15 +60,15 @@ namespace SharpLab.Server.Decompilation.AstOnly {
return Task.FromResult((object)(parseTree as Ast.ParsedInput.ImplFile));
}
public void SerializeAst(object ast, IFastJsonWriter writer) {
public void SerializeAst(object ast, IFastJsonWriter writer, IWorkSession session) {
var root = ((Ast.ParsedInput.ImplFile)ast).Item;
writer.WriteStartArray();
var childrenStarted = true;
SerializeNode(root, writer, null, ref childrenStarted);
SerializeNode(root, writer, null, ref childrenStarted, session.FSharp());
writer.WriteEndArray();
}
private static void SerializeNode(object node, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted) {
private static void SerializeNode(object node, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) {
EnsureChildrenStarted(ref parentChildrenStarted, writer);
writer.WriteStartObject();
writer.WriteProperty("kind", AstTypeNames.Value[node.GetType()]);
@ -74,15 +78,19 @@ namespace SharpLab.Server.Decompilation.AstOnly {
if (node is Ast.SynConst @const) {
writer.WriteProperty("type", "token");
if (@const is Ast.SynConst.String @string) {
writer.WriteProperty("value", "\"" + @string.text + "\"");
writer.WritePropertyName("value");
writer.WriteValueFromParts("\"", @string.text, "\"");
}
else if (@const is Ast.SynConst.Char @char) {
writer.WriteProperty("value", "'" + @char.Item + "'");
writer.WritePropertyName("value");
writer.WriteValueFromParts("'", @char.Item, "'");
}
else {
var getter = ConstValueGetters.Value.GetValueOrDefault(@const.GetType());
if (getter != null)
writer.WriteProperty("value", getter(@const));
if (getter != null) {
writer.WritePropertyName("value");
writer.WriteValue(getter(@const));
}
}
}
else {
@ -91,20 +99,23 @@ namespace SharpLab.Server.Decompilation.AstOnly {
if (tagName != null)
writer.WriteProperty("value", tagName);
}
var rangeGetter = GetRangeGetter(node.GetType());
if (rangeGetter != null)
SerializeRangeProperty(rangeGetter(node), writer, session);
var childrenStarted = false;
GetChildrenSerializer(node.GetType()).Invoke(node, writer, ref childrenStarted);
GetChildrenSerializer(node.GetType()).Invoke(node, writer, ref childrenStarted, session);
EnsureChildrenEnded(childrenStarted, writer);
writer.WriteEndObject();
}
private static void SerializeList<T>(FSharpList<T> list, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted) {
private static void SerializeList<T>(FSharpList<T> list, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) {
foreach (var item in list) {
SerializeNode(item, writer, null /* UI does not support list property names at the moment */, ref parentChildrenStarted);
SerializeNode(item, writer, null /* UI does not support list property names at the moment */, ref parentChildrenStarted, session);
}
}
private static void SerializeIdent(Ast.Ident ident, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted) {
private static void SerializeIdent(Ast.Ident ident, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) {
EnsureChildrenStarted(ref parentChildrenStarted, writer);
writer.WriteStartObject();
writer.WriteProperty("type", "token");
@ -112,16 +123,17 @@ namespace SharpLab.Server.Decompilation.AstOnly {
if (parentPropertyName != null)
writer.WriteProperty("property", parentPropertyName);
writer.WriteProperty("value", ident.idText);
SerializeRangeProperty(ident.idRange, writer, session);
writer.WriteEndObject();
}
private static void SerializeIdentList(FSharpList<Ast.Ident> list, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted) {
private static void SerializeIdentList(FSharpList<Ast.Ident> list, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) {
foreach (var ident in list) {
SerializeIdent(ident, writer, parentPropertyName, ref parentChildrenStarted);
SerializeIdent(ident, writer, parentPropertyName, ref parentChildrenStarted, session);
}
}
private static void SerializeEnum<TEnum>(TEnum value, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted)
private static void SerializeEnum<TEnum>(TEnum value, IFastJsonWriter writer, [CanBeNull] string parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session)
where TEnum: struct, IFormattable
{
EnsureChildrenStarted(ref parentChildrenStarted, writer);
@ -137,6 +149,13 @@ namespace SharpLab.Server.Decompilation.AstOnly {
}
}
private static void SerializeRangeProperty(Range.range range, IFastJsonWriter writer, IFSharpSession session) {
writer.WritePropertyName("range");
var startOffset = session.ConvertToOffset(range.StartLine, range.StartColumn);
var endOffset = session.ConvertToOffset(range.EndLine, range.EndColumn);
writer.WriteValueFromParts(startOffset, '-', endOffset);
}
private static void EnsureChildrenStarted(ref bool childrenStarted, IFastJsonWriter writer) {
if (childrenStarted)
return;
@ -149,7 +168,7 @@ namespace SharpLab.Server.Decompilation.AstOnly {
return;
writer.WriteEndArray();
}
private static SerializeChildrenAction GetChildrenSerializer(Type type) {
return ChildrenSerializers.GetOrAdd(
type,
@ -161,6 +180,7 @@ namespace SharpLab.Server.Decompilation.AstOnly {
var nodeAsObject = Expression.Parameter(typeof(object));
var writer = Expression.Parameter(typeof(IFastJsonWriter));
var refChildrenStarted = Expression.Parameter(typeof(bool).MakeByRefType());
var session = Expression.Parameter(typeof(IFSharpSession));
var node = Expression.Variable(type);
var body = new List<Expression> {
@ -178,12 +198,12 @@ namespace SharpLab.Server.Decompilation.AstOnly {
var propertyName = property.Name;
if (Regex.IsMatch(propertyName, @"^Item\d*$"))
propertyName = null;
body.Add(Expression.Call(method, Expression.Property(node, property), writer, Expression.Constant(propertyName, typeof(string)), refChildrenStarted));
body.Add(Expression.Call(method, Expression.Property(node, property), writer, Expression.Constant(propertyName, typeof(string)), refChildrenStarted, session));
}
return Expression.Lambda<SerializeChildrenAction>(
Expression.Block(new[] {node}, body),
nodeAsObject, writer, refChildrenStarted
nodeAsObject, writer, refChildrenStarted, session
).Compile();
}
@ -210,6 +230,24 @@ namespace SharpLab.Server.Decompilation.AstOnly {
return Methods.SerializeNode;
}
private static GetRangeFunc GetRangeGetter(Type type) {
return RangeGetters.GetOrAdd(
type,
t => new Lazy<GetRangeFunc>(() => CompileRangeGetter(t), LazyThreadSafetyMode.ExecutionAndPublication)
).Value;
}
private static GetRangeFunc CompileRangeGetter(Type type) {
var rangeProperty = type.GetProperty("Range");
if (rangeProperty == null)
return null;
var nodeAsObject = Expression.Parameter(typeof(object));
var body = Expression.Property(Expression.Convert(nodeAsObject, type), rangeProperty);
return Expression.Lambda<GetRangeFunc>(body, new[] { nodeAsObject }).Compile();
}
private static bool ShouldSkipNodeProperty(Type type, PropertyInfo property) {
return (type == typeof(Ast.LongIdentWithDots) && property.Name == nameof(Ast.LongIdentWithDots.id));
}

Просмотреть файл

@ -7,7 +7,7 @@ using MirrorSharp.Advanced;
namespace SharpLab.Server.Decompilation.AstOnly {
public interface IAstTarget {
[NotNull, ItemCanBeNull] Task<object> GetAstAsync([NotNull] IWorkSession session, CancellationToken cancellationToken);
void SerializeAst([NotNull] object ast, [NotNull] IFastJsonWriter writer);
void SerializeAst([NotNull] object ast, [NotNull] IFastJsonWriter writer, [NotNull] IWorkSession session);
[NotNull, ItemNotNull] IReadOnlyCollection<string> SupportedLanguageNames { get; }
}

Просмотреть файл

@ -13,8 +13,8 @@ namespace SharpLab.Server.Decompilation.AstOnly {
var document = session.Roslyn.Project.Documents.Single();
return await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
}
public void SerializeAst(object ast, IFastJsonWriter writer) {
public void SerializeAst(object ast, IFastJsonWriter writer, IWorkSession session) {
writer.WriteStartArray();
SerializeNode((SyntaxNode)ast, writer);
writer.WriteEndArray();
@ -90,11 +90,7 @@ namespace SharpLab.Server.Decompilation.AstOnly {
private void SerializeSpanProperty(TextSpan span, IFastJsonWriter writer) {
writer.WritePropertyName("range");
using (var stringWriter = writer.OpenString()) {
stringWriter.Write(span.Start);
stringWriter.Write(":");
stringWriter.Write(span.End);
}
writer.WriteValueFromParts(span.Start, '-', span.End);
}
public IReadOnlyCollection<string> SupportedLanguageNames { get; } = new[] {

Просмотреть файл

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MirrorSharp.Advanced;
namespace SharpLab.Server.Decompilation.Internal
{
public static class FastJsonWriterExtensions {
public static void WriteValueFromParts(this IFastJsonWriter writer, string part1, string part2, string part3) {
using (var stringWriter = writer.OpenString()) {
stringWriter.Write(part1);
stringWriter.Write(part2);
stringWriter.Write(part3);
}
}
public static void WriteValueFromParts(this IFastJsonWriter writer, string part1, char part2, string part3) {
using (var stringWriter = writer.OpenString()) {
stringWriter.Write(part1);
stringWriter.Write(part2);
stringWriter.Write(part3);
}
}
public static void WriteValueFromParts(this IFastJsonWriter writer, int part1, char part2, int part3) {
using (var stringWriter = writer.OpenString()) {
stringWriter.Write(part1);
stringWriter.Write(part2);
stringWriter.Write(part3);
}
}
public static void WriteValueFromParts(this IFastJsonWriter writer, int part1, char part2, int part3, char part4, int part5, char part6, int part7) {
using (var stringWriter = writer.OpenString()) {
stringWriter.Write(part1);
stringWriter.Write(part2);
stringWriter.Write(part3);
stringWriter.Write(part4);
stringWriter.Write(part5);
stringWriter.Write(part6);
stringWriter.Write(part7);
}
}
}
}

Просмотреть файл

@ -71,7 +71,7 @@ namespace SharpLab.Server.MirrorSharp {
if (session.GetTargetName() == AstTargetName) {
var astTarget = _astTargets.GetValueOrDefault(session.LanguageName);
astTarget.SerializeAst(result, writer);
astTarget.SerializeAst(result, writer, session);
return;
}

Просмотреть файл

@ -21,7 +21,7 @@
<PackageReference Include="Microsoft.Owin.Cors" Version="3.0.1" />
<PackageReference Include="Microsoft.Owin.Host.SystemWeb" Version="3.0.1" />
<PackageReference Include="MirrorSharp.Common" Version="0.9.0-pre-20170620" />
<PackageReference Include="MirrorSharp.FSharp" Version="0.9.0-pre-20170523" />
<PackageReference Include="MirrorSharp.FSharp" Version="0.9.0-pre-20170620" />
<PackageReference Include="MirrorSharp.Owin" Version="0.9.0-pre-20170523" />
<PackageReference Include="MirrorSharp.VisualBasic" Version="0.9.0-pre-20170523" />
<PackageReference Include="SharpDisasm" Version="1.1.5" />

Просмотреть файл

@ -7,27 +7,27 @@
{
"type": "node",
"kind": "CompilationUnit",
"range": "0:19",
"range": "0-19",
"children": [
{
"type": "node",
"kind": "ClassDeclaration",
"range": "0:19",
"range": "0-19",
"children": [
{
"type": "token",
"kind": "PublicKeyword",
"range": "0:7",
"range": "0-7",
"children": [
{
"type": "value",
"value": "public",
"range": "0:6"
"range": "0-6"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "6:7",
"range": "6-7",
"value": " "
}
]
@ -36,17 +36,17 @@
"type": "token",
"kind": "ClassKeyword",
"property": "Keyword",
"range": "7:13",
"range": "7-13",
"children": [
{
"type": "value",
"value": "class",
"range": "7:12"
"range": "7-12"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "12:13",
"range": "12-13",
"value": " "
}
]
@ -55,17 +55,17 @@
"type": "token",
"kind": "IdentifierToken",
"property": "Identifier",
"range": "13:15",
"range": "13-15",
"children": [
{
"type": "value",
"value": "C",
"range": "13:14"
"range": "13-14"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "14:15",
"range": "14-15",
"value": " "
}
]
@ -74,17 +74,17 @@
"type": "token",
"kind": "OpenBraceToken",
"property": "OpenBraceToken",
"range": "15:18",
"range": "15-18",
"children": [
{
"type": "value",
"value": "{",
"range": "15:16"
"range": "15-16"
},
{
"type": "trivia",
"kind": "EndOfLineTrivia",
"range": "16:18",
"range": "16-18",
"value": "\r\n"
}
]
@ -93,7 +93,7 @@
"type": "token",
"kind": "CloseBraceToken",
"property": "CloseBraceToken",
"range": "18:19",
"range": "18-19",
"value": "}"
}
]
@ -102,9 +102,10 @@
"type": "token",
"kind": "EndOfFileToken",
"property": "EndOfFileToken",
"range": "19:19",
"range": "19-19",
"value": ""
}
]
}
]

Просмотреть файл

@ -10,36 +10,43 @@
{
"kind": "Ast.SynModuleOrNamespace",
"type": "node",
"range": "0-22",
"children": [
{
"type": "token",
"kind": "Ast.Ident",
"property": "longId",
"value": "_"
"value": "_",
"range": "0-0"
},
{
"kind": "Ast.SynModuleDecl.Types",
"type": "node",
"range": "0-18",
"children": [
{
"kind": "Ast.SynTypeDefn",
"type": "node",
"range": "5-18",
"children": [
{
"kind": "Ast.SynComponentInfo",
"type": "node",
"range": "5-10",
"children": [
{
"type": "token",
"kind": "Ast.Ident",
"property": "longId",
"value": "Empty"
"value": "Empty",
"range": "5-10"
}
]
},
{
"kind": "Ast.SynTypeDefnRepr.ObjectModel",
"type": "node",
"range": "13-18",
"children": [
{
"kind": "Ast.SynTypeDefnKind",

Просмотреть файл

@ -13,28 +13,28 @@ b";
{
"type": "node",
"kind": "CompilationUnit",
"range": "0:102",
"range": "0-102",
"children": [
{
"type": "node",
"kind": "ClassDeclaration",
"range": "0:102",
"range": "0-102",
"children": [
{
"type": "token",
"kind": "ClassKeyword",
"property": "Keyword",
"range": "0:6",
"range": "0-6",
"children": [
{
"type": "value",
"value": "class",
"range": "0:5"
"range": "0-5"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "5:6",
"range": "5-6",
"value": " "
}
]
@ -43,17 +43,17 @@ b";
"type": "token",
"kind": "IdentifierToken",
"property": "Identifier",
"range": "6:8",
"range": "6-8",
"children": [
{
"type": "value",
"value": "C",
"range": "6:7"
"range": "6-7"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "7:8",
"range": "7-8",
"value": " "
}
]
@ -62,17 +62,17 @@ b";
"type": "token",
"kind": "OpenBraceToken",
"property": "OpenBraceToken",
"range": "8:11",
"range": "8-11",
"children": [
{
"type": "value",
"value": "{",
"range": "8:9"
"range": "8-9"
},
{
"type": "trivia",
"kind": "EndOfLineTrivia",
"range": "9:11",
"range": "9-11",
"value": "\r\n"
}
]
@ -80,41 +80,41 @@ b";
{
"type": "node",
"kind": "FieldDeclaration",
"range": "11:27",
"range": "11-27",
"children": [
{
"type": "node",
"kind": "VariableDeclaration",
"property": "Declaration",
"range": "11:24",
"range": "11-24",
"children": [
{
"type": "node",
"kind": "PredefinedType",
"property": "Type",
"range": "11:19",
"range": "11-19",
"children": [
{
"type": "token",
"kind": "IntKeyword",
"property": "Keyword",
"range": "11:19",
"range": "11-19",
"children": [
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "11:15",
"range": "11-15",
"value": " "
},
{
"type": "value",
"value": "int",
"range": "15:18"
"range": "15-18"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "18:19",
"range": "18-19",
"value": " "
}
]
@ -124,23 +124,23 @@ b";
{
"type": "node",
"kind": "VariableDeclarator",
"range": "19:24",
"range": "19-24",
"children": [
{
"type": "token",
"kind": "IdentifierToken",
"property": "Identifier",
"range": "19:21",
"range": "19-21",
"children": [
{
"type": "value",
"value": "i",
"range": "19:20"
"range": "19-20"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "20:21",
"range": "20-21",
"value": " "
}
]
@ -149,23 +149,23 @@ b";
"type": "node",
"kind": "EqualsValueClause",
"property": "Initializer",
"range": "21:24",
"range": "21-24",
"children": [
{
"type": "token",
"kind": "EqualsToken",
"property": "EqualsToken",
"range": "21:23",
"range": "21-23",
"children": [
{
"type": "value",
"value": "=",
"range": "21:22"
"range": "21-22"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "22:23",
"range": "22-23",
"value": " "
}
]
@ -174,13 +174,13 @@ b";
"type": "node",
"kind": "NumericLiteralExpression",
"property": "Value",
"range": "23:24",
"range": "23-24",
"children": [
{
"type": "token",
"kind": "NumericLiteralToken",
"property": "Token",
"range": "23:24",
"range": "23-24",
"value": "1"
}
]
@ -195,17 +195,17 @@ b";
"type": "token",
"kind": "SemicolonToken",
"property": "SemicolonToken",
"range": "24:27",
"range": "24-27",
"children": [
{
"type": "value",
"value": ";",
"range": "24:25"
"range": "24-25"
},
{
"type": "trivia",
"kind": "EndOfLineTrivia",
"range": "25:27",
"range": "25-27",
"value": "\r\n"
}
]
@ -215,41 +215,41 @@ b";
{
"type": "node",
"kind": "FieldDeclaration",
"range": "27:46",
"range": "27-46",
"children": [
{
"type": "node",
"kind": "VariableDeclaration",
"property": "Declaration",
"range": "27:43",
"range": "27-43",
"children": [
{
"type": "node",
"kind": "PredefinedType",
"property": "Type",
"range": "27:36",
"range": "27-36",
"children": [
{
"type": "token",
"kind": "CharKeyword",
"property": "Keyword",
"range": "27:36",
"range": "27-36",
"children": [
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "27:31",
"range": "27-31",
"value": " "
},
{
"type": "value",
"value": "char",
"range": "31:35"
"range": "31-35"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "35:36",
"range": "35-36",
"value": " "
}
]
@ -259,23 +259,23 @@ b";
{
"type": "node",
"kind": "VariableDeclarator",
"range": "36:43",
"range": "36-43",
"children": [
{
"type": "token",
"kind": "IdentifierToken",
"property": "Identifier",
"range": "36:38",
"range": "36-38",
"children": [
{
"type": "value",
"value": "c",
"range": "36:37"
"range": "36-37"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "37:38",
"range": "37-38",
"value": " "
}
]
@ -284,23 +284,23 @@ b";
"type": "node",
"kind": "EqualsValueClause",
"property": "Initializer",
"range": "38:43",
"range": "38-43",
"children": [
{
"type": "token",
"kind": "EqualsToken",
"property": "EqualsToken",
"range": "38:40",
"range": "38-40",
"children": [
{
"type": "value",
"value": "=",
"range": "38:39"
"range": "38-39"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "39:40",
"range": "39-40",
"value": " "
}
]
@ -309,13 +309,13 @@ b";
"type": "node",
"kind": "CharacterLiteralExpression",
"property": "Value",
"range": "40:43",
"range": "40-43",
"children": [
{
"type": "token",
"kind": "CharacterLiteralToken",
"property": "Token",
"range": "40:43",
"range": "40-43",
"value": "'c'"
}
]
@ -330,17 +330,17 @@ b";
"type": "token",
"kind": "SemicolonToken",
"property": "SemicolonToken",
"range": "43:46",
"range": "43-46",
"children": [
{
"type": "value",
"value": ";",
"range": "43:44"
"range": "43-44"
},
{
"type": "trivia",
"kind": "EndOfLineTrivia",
"range": "44:46",
"range": "44-46",
"value": "\r\n"
}
]
@ -350,47 +350,47 @@ b";
{
"type": "node",
"kind": "FieldDeclaration",
"range": "46:75",
"range": "46-75",
"children": [
{
"type": "node",
"kind": "VariableDeclaration",
"property": "Declaration",
"range": "46:72",
"range": "46-72",
"children": [
{
"type": "node",
"kind": "PredefinedType",
"property": "Type",
"range": "46:59",
"range": "46-59",
"children": [
{
"type": "token",
"kind": "StringKeyword",
"property": "Keyword",
"range": "46:59",
"range": "46-59",
"children": [
{
"type": "trivia",
"kind": "EndOfLineTrivia",
"range": "46:48",
"range": "46-48",
"value": "\r\n"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "48:52",
"range": "48-52",
"value": " "
},
{
"type": "value",
"value": "string",
"range": "52:58"
"range": "52-58"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "58:59",
"range": "58-59",
"value": " "
}
]
@ -400,23 +400,23 @@ b";
{
"type": "node",
"kind": "VariableDeclarator",
"range": "59:72",
"range": "59-72",
"children": [
{
"type": "token",
"kind": "IdentifierToken",
"property": "Identifier",
"range": "59:62",
"range": "59-62",
"children": [
{
"type": "value",
"value": "s1",
"range": "59:61"
"range": "59-61"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "61:62",
"range": "61-62",
"value": " "
}
]
@ -425,23 +425,23 @@ b";
"type": "node",
"kind": "EqualsValueClause",
"property": "Initializer",
"range": "62:72",
"range": "62-72",
"children": [
{
"type": "token",
"kind": "EqualsToken",
"property": "EqualsToken",
"range": "62:64",
"range": "62-64",
"children": [
{
"type": "value",
"value": "=",
"range": "62:63"
"range": "62-63"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "63:64",
"range": "63-64",
"value": " "
}
]
@ -450,13 +450,13 @@ b";
"type": "node",
"kind": "StringLiteralExpression",
"property": "Value",
"range": "64:72",
"range": "64-72",
"children": [
{
"type": "token",
"kind": "StringLiteralToken",
"property": "Token",
"range": "64:72",
"range": "64-72",
"value": "\"a\\r\\nb\""
}
]
@ -471,17 +471,17 @@ b";
"type": "token",
"kind": "SemicolonToken",
"property": "SemicolonToken",
"range": "72:75",
"range": "72-75",
"children": [
{
"type": "value",
"value": ";",
"range": "72:73"
"range": "72-73"
},
{
"type": "trivia",
"kind": "EndOfLineTrivia",
"range": "73:75",
"range": "73-75",
"value": "\r\n"
}
]
@ -491,41 +491,41 @@ b";
{
"type": "node",
"kind": "FieldDeclaration",
"range": "75:101",
"range": "75-101",
"children": [
{
"type": "node",
"kind": "VariableDeclaration",
"property": "Declaration",
"range": "75:98",
"range": "75-98",
"children": [
{
"type": "node",
"kind": "PredefinedType",
"property": "Type",
"range": "75:86",
"range": "75-86",
"children": [
{
"type": "token",
"kind": "StringKeyword",
"property": "Keyword",
"range": "75:86",
"range": "75-86",
"children": [
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "75:79",
"range": "75-79",
"value": " "
},
{
"type": "value",
"value": "string",
"range": "79:85"
"range": "79-85"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "85:86",
"range": "85-86",
"value": " "
}
]
@ -535,23 +535,23 @@ b";
{
"type": "node",
"kind": "VariableDeclarator",
"range": "86:98",
"range": "86-98",
"children": [
{
"type": "token",
"kind": "IdentifierToken",
"property": "Identifier",
"range": "86:89",
"range": "86-89",
"children": [
{
"type": "value",
"value": "s2",
"range": "86:88"
"range": "86-88"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "88:89",
"range": "88-89",
"value": " "
}
]
@ -560,23 +560,23 @@ b";
"type": "node",
"kind": "EqualsValueClause",
"property": "Initializer",
"range": "89:98",
"range": "89-98",
"children": [
{
"type": "token",
"kind": "EqualsToken",
"property": "EqualsToken",
"range": "89:91",
"range": "89-91",
"children": [
{
"type": "value",
"value": "=",
"range": "89:90"
"range": "89-90"
},
{
"type": "trivia",
"kind": "WhitespaceTrivia",
"range": "90:91",
"range": "90-91",
"value": " "
}
]
@ -585,13 +585,13 @@ b";
"type": "node",
"kind": "StringLiteralExpression",
"property": "Value",
"range": "91:98",
"range": "91-98",
"children": [
{
"type": "token",
"kind": "StringLiteralToken",
"property": "Token",
"range": "91:98",
"range": "91-98",
"value": "@\"a\r\nb\""
}
]
@ -606,17 +606,17 @@ b";
"type": "token",
"kind": "SemicolonToken",
"property": "SemicolonToken",
"range": "98:101",
"range": "98-101",
"children": [
{
"type": "value",
"value": ";",
"range": "98:99"
"range": "98-99"
},
{
"type": "trivia",
"kind": "EndOfLineTrivia",
"range": "99:101",
"range": "99-101",
"value": "\r\n"
}
]
@ -627,7 +627,7 @@ b";
"type": "token",
"kind": "CloseBraceToken",
"property": "CloseBraceToken",
"range": "101:102",
"range": "101-102",
"value": "}"
}
]
@ -636,7 +636,7 @@ b";
"type": "token",
"kind": "EndOfFileToken",
"property": "EndOfFileToken",
"range": "102:102",
"range": "102-102",
"value": ""
}
]

Просмотреть файл

@ -14,20 +14,24 @@ b"
{
"kind": "Ast.SynModuleOrNamespace",
"type": "node",
"range": "0-14",
"children": [
{
"type": "token",
"kind": "Ast.Ident",
"property": "longId",
"value": "_"
"value": "_",
"range": "0-0"
},
{
"kind": "Ast.SynModuleDecl.DoExpr",
"type": "node",
"range": "0-1",
"children": [
{
"kind": "Ast.SynExpr.Const",
"type": "node",
"range": "0-1",
"children": [
{
"kind": "Ast.SynConst.Int32",
@ -42,10 +46,12 @@ b"
{
"kind": "Ast.SynModuleDecl.DoExpr",
"type": "node",
"range": "3-6",
"children": [
{
"kind": "Ast.SynExpr.Const",
"type": "node",
"range": "3-6",
"children": [
{
"kind": "Ast.SynConst.Char",
@ -60,10 +66,12 @@ b"
{
"kind": "Ast.SynModuleDecl.DoExpr",
"type": "node",
"range": "8-14",
"children": [
{
"kind": "Ast.SynExpr.Const",
"type": "node",
"range": "8-14",
"children": [
{
"kind": "Ast.SynConst.String",
@ -79,4 +87,4 @@ b"
}
]
}
]
]

Просмотреть файл

@ -1,50 +1,50 @@
/// <summary>Test</summary>
#=>
[
{
"type": "node",
"kind": "CompilationUnit",
"range": "0:27",
"range": "0-27",
"children": [
{
"type": "token",
"kind": "EndOfFileToken",
"property": "EndOfFileToken",
"range": "0:27",
"range": "0-27",
"children": [
{
"type": "trivia",
"kind": "SingleLineDocumentationCommentTrivia",
"range": "0:27",
"range": "0-27",
"children": [
{
"type": "node",
"kind": "SingleLineDocumentationCommentTrivia",
"property": "Structure",
"range": "0:27",
"range": "0-27",
"children": [
{
"type": "node",
"kind": "XmlText",
"range": "0:4",
"range": "0-4",
"children": [
{
"type": "token",
"kind": "XmlTextLiteralToken",
"range": "0:4",
"range": "0-4",
"children": [
{
"type": "trivia",
"kind": "DocumentationCommentExteriorTrivia",
"range": "0:3",
"range": "0-3",
"value": "///"
},
{
"type": "value",
"value": " ",
"range": "3:4"
"range": "3-4"
}
]
}
@ -53,32 +53,32 @@
{
"type": "node",
"kind": "XmlElement",
"range": "4:27",
"range": "4-27",
"children": [
{
"type": "node",
"kind": "XmlElementStartTag",
"property": "StartTag",
"range": "4:13",
"range": "4-13",
"children": [
{
"type": "token",
"kind": "LessThanToken",
"property": "LessThanToken",
"range": "4:5",
"range": "4-5",
"value": "<"
},
{
"type": "node",
"kind": "XmlName",
"property": "Name",
"range": "5:12",
"range": "5-12",
"children": [
{
"type": "token",
"kind": "IdentifierToken",
"property": "LocalName",
"range": "5:12",
"range": "5-12",
"value": "summary"
}
]
@ -87,7 +87,7 @@
"type": "token",
"kind": "GreaterThanToken",
"property": "GreaterThanToken",
"range": "12:13",
"range": "12-13",
"value": ">"
}
]
@ -95,12 +95,12 @@
{
"type": "node",
"kind": "XmlText",
"range": "13:17",
"range": "13-17",
"children": [
{
"type": "token",
"kind": "XmlTextLiteralToken",
"range": "13:17",
"range": "13-17",
"value": "Test"
}
]
@ -109,26 +109,26 @@
"type": "node",
"kind": "XmlElementEndTag",
"property": "EndTag",
"range": "17:27",
"range": "17-27",
"children": [
{
"type": "token",
"kind": "LessThanSlashToken",
"property": "LessThanSlashToken",
"range": "17:19",
"range": "17-19",
"value": "</"
},
{
"type": "node",
"kind": "XmlName",
"property": "Name",
"range": "19:26",
"range": "19-26",
"children": [
{
"type": "token",
"kind": "IdentifierToken",
"property": "LocalName",
"range": "19:26",
"range": "19-26",
"value": "summary"
}
]
@ -137,7 +137,7 @@
"type": "token",
"kind": "GreaterThanToken",
"property": "GreaterThanToken",
"range": "26:27",
"range": "26-27",
"value": ">"
}
]
@ -148,7 +148,7 @@
"type": "token",
"kind": "EndOfDocumentationCommentToken",
"property": "EndOfComment",
"range": "27:27",
"range": "27-27",
"value": ""
}
]
@ -158,7 +158,7 @@
{
"type": "value",
"value": "",
"range": "27:27"
"range": "27-27"
}
]
}

Просмотреть файл

@ -54,7 +54,7 @@
<ItemGroup>
<PackageReference Include="AshMind.Extensions" Version="2.0.0-pre-20160719" />
<PackageReference Include="FSharp.Core" Version="4.1.17" />
<PackageReference Include="MirrorSharp.FSharp" version="0.9.0-pre-20170523" />
<PackageReference Include="MirrorSharp.FSharp" version="0.9.0-pre-20170620" />
<PackageReference Include="MirrorSharp.Testing" version="0.9.0-pre-20170527" />
<PackageReference Include="Pedantic.IO.EmbeddedResource" version="0.9.0-pre-02" />
<PackageReference Include="xunit" version="2.1.0" />

Просмотреть файл

@ -57,8 +57,7 @@ function applyAstHover(item) {
this.highlightedCodeRange = null;
return;
}
const [start, end] = item.range.split(':');
const [start, end] = item.range.split('-');
this.highlightedCodeRange = { start, end };
}