提交 705514c1 编写于 作者: A Andrew Casey

Expose ObjectFormatter as a public API

...and a host object property on InteractiveScriptGlobals.

This is a first cut and my main goal at this point is forward
compatibility.  The existing unit tests all pass.

TODO: Make some improvements to the existing behavior.
TODO: Update the existing test baselines.
TODO: Introduce new tests.

This branch should be buddy testable - tweak the existing formatter by
subtyping (e.g.) `CSharpObjectFormatter` and assigning an instance of your
subtype to the global `ObjectFormatter` property.  It should be consumed
by subsequent submissions.
上级 522e1e0d
......@@ -30,7 +30,7 @@ internal static int Main(string[] args)
ConsoleIO.Default,
compiler,
CSharpScriptCompiler.Instance,
CSharpObjectFormatter.Instance);
new CSharpObjectFormatter());
return runner.RunInteractive();
}
......
......@@ -17,7 +17,7 @@ public CSharpReplServiceProvider()
{
}
public override ObjectFormatter ObjectFormatter => CSharpObjectFormatter.Instance;
public override ObjectFormatter ObjectFormatter { get; } = new CSharpObjectFormatter();
public override CommandLineParser CommandLineParser => CSharpCommandLineParser.ScriptRunner;
public override DiagnosticFormatter DiagnosticFormatter => CSharpDiagnosticFormatter.Instance;
......
......@@ -33,11 +33,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Interactive
End Get
End Property
Public Overrides ReadOnly Property ObjectFormatter As ObjectFormatter
Get
Return VisualBasicObjectFormatter.Instance
End Get
End Property
Public Overrides ReadOnly Property ObjectFormatter As ObjectFormatter = New VisualBasicObjectFormatter()
Public Overrides Function CreateScript(Of T)(code As String, options As ScriptOptions, globalsTypeOpt As Type, assemblyLoader As InteractiveAssemblyLoader) As Script(Of T)
Return VisualBasicScript.Create(Of T)(code, options, globalsTypeOpt, assemblyLoader)
......
......@@ -552,17 +552,6 @@ private static void ReportUnhandledException(Exception e)
#region Operations
// TODO (tomat): testing only
public void SetTestObjectFormattingOptions()
{
_globals.PrintOptions = new ObjectFormattingOptions(
memberFormat: MemberDisplayFormat.Inline,
quoteStrings: true,
useHexadecimalNumbers: false,
maxOutputLength: int.MaxValue,
memberIndentation: " ");
}
/// <summary>
/// Loads references, set options and execute files specified in the initialization file.
/// Also prints logo unless <paramref name="isRestarting"/> is true.
......
......@@ -48,8 +48,6 @@ public InteractiveHostTests()
var remoteService = Host.TryGetService();
Assert.NotNull(remoteService);
remoteService.SetTestObjectFormattingOptions();
Host.SetPathsAsync(new[] { s_fxDir }, new[] { s_homeDir }, s_homeDir).Wait();
// assert and remove logo:
......
......@@ -24,7 +24,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting
ConsoleIO.Default,
compiler,
VisualBasicScriptCompiler.Instance,
VisualBasicObjectFormatter.Instance)
New VisualBasicObjectFormatter())
Return runner.RunInteractive()
Catch ex As Exception
......
......@@ -47,6 +47,8 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Hosting\CommandLine\Csi.cs" />
<Compile Include="Hosting\ObjectFormatter\CSharpPrimitiveFormatter.cs" />
<Compile Include="Hosting\ObjectFormatter\CSharpTypeNameFormatter.cs" />
<Compile Include="Hosting\ObjectFormatter\CSharpObjectFormatter.cs" />
<Compile Include="CSharpScript.cs" />
<Compile Include="CSharpScriptCompiler.cs" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text;
using Microsoft.CodeAnalysis.CSharp;
using System.Reflection;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Scripting.Hosting;
using System.Globalization;
namespace Microsoft.CodeAnalysis.CSharp.Scripting.Hosting
{
public sealed class CSharpObjectFormatter : ObjectFormatter
public class CSharpObjectFormatter : CommonObjectFormatter
{
public static CSharpObjectFormatter Instance { get; } = new CSharpObjectFormatter();
protected override CommonTypeNameFormatter TypeNameFormatter { get; }
protected override CommonPrimitiveFormatter PrimitiveFormatter { get; }
private CSharpObjectFormatter()
public CSharpObjectFormatter()
{
PrimitiveFormatter = new CSharpPrimitiveFormatter();
TypeNameFormatter = new CSharpTypeNameFormatter(PrimitiveFormatter);
}
internal override object VoidDisplayString => "<void>";
internal override string NullLiteral => ObjectDisplay.NullLiteral;
internal override string GenericParameterOpening => "<";
internal override string GenericParameterClosing => ">";
internal override string FormatLiteral(bool value)
{
return ObjectDisplay.FormatLiteral(value);
}
internal override string FormatLiteral(string value, bool quote, bool useHexadecimalNumbers = false)
{
var options = ObjectDisplayOptions.EscapeNonPrintableCharacters;
if (quote)
{
options |= ObjectDisplayOptions.UseQuotes;
}
if (useHexadecimalNumbers)
{
options |= ObjectDisplayOptions.UseHexadecimalNumbers;
}
return ObjectDisplay.FormatLiteral(value, options);
}
internal override string FormatLiteral(char c, bool quote, bool includeCodePoints = false, bool useHexadecimalNumbers = false)
{
var options = ObjectDisplayOptions.EscapeNonPrintableCharacters;
if (quote)
{
options |= ObjectDisplayOptions.UseQuotes;
}
if (includeCodePoints)
{
options |= ObjectDisplayOptions.IncludeCodePoints;
}
if (useHexadecimalNumbers)
{
options |= ObjectDisplayOptions.UseHexadecimalNumbers;
}
return ObjectDisplay.FormatLiteral(c, options);
}
internal override string FormatLiteral(sbyte value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture);
}
internal override string FormatLiteral(byte value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture);
}
internal override string FormatLiteral(short value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture);
}
internal override string FormatLiteral(ushort value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture);
}
internal override string FormatLiteral(int value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture);
}
internal override string FormatLiteral(uint value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture);
}
internal override string FormatLiteral(long value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture);
}
internal override string FormatLiteral(ulong value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture);
}
internal override string FormatLiteral(double value)
{
return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None, UIFormatCulture);
}
internal override string FormatLiteral(float value)
{
return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None, UIFormatCulture);
}
internal override string FormatLiteral(decimal value)
{
return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None, UIFormatCulture);
}
internal override string FormatLiteral(DateTime value)
{
// DateTime is not primitive in C#
return null;
}
internal override string GetPrimitiveTypeName(SpecialType type)
{
switch (type)
{
case SpecialType.System_Boolean: return "bool";
case SpecialType.System_Byte: return "byte";
case SpecialType.System_Char: return "char";
case SpecialType.System_Decimal: return "decimal";
case SpecialType.System_Double: return "double";
case SpecialType.System_Int16: return "short";
case SpecialType.System_Int32: return "int";
case SpecialType.System_Int64: return "long";
case SpecialType.System_SByte: return "sbyte";
case SpecialType.System_Single: return "float";
case SpecialType.System_String: return "string";
case SpecialType.System_UInt16: return "ushort";
case SpecialType.System_UInt32: return "uint";
case SpecialType.System_UInt64: return "ulong";
case SpecialType.System_Object: return "object";
default:
return null;
}
}
internal override string FormatGeneratedTypeName(Type type)
{
string stateMachineName;
if (GeneratedNames.TryParseSourceMethodNameFromGeneratedName(type.Name, GeneratedNameKind.StateMachineType, out stateMachineName))
{
return stateMachineName;
}
return null;
}
internal override string FormatArrayTypeName(Type arrayType, Array arrayOpt, ObjectFormattingOptions options)
{
StringBuilder sb = new StringBuilder();
// print the inner-most element type first:
Type elementType = arrayType.GetElementType();
while (elementType.IsArray)
{
elementType = elementType.GetElementType();
}
sb.Append(FormatTypeName(elementType, options));
// print all components of a jagged array:
Type type = arrayType;
do
{
if (arrayOpt != null)
{
sb.Append('[');
int rank = type.GetArrayRank();
bool anyNonzeroLowerBound = false;
for (int i = 0; i < rank; i++)
{
if (arrayOpt.GetLowerBound(i) > 0)
{
anyNonzeroLowerBound = true;
break;
}
}
for (int i = 0; i < rank; i++)
{
int lowerBound = arrayOpt.GetLowerBound(i);
int length = arrayOpt.GetLength(i);
if (i > 0)
{
sb.Append(", ");
}
if (anyNonzeroLowerBound)
{
AppendArrayBound(sb, lowerBound, options.UseHexadecimalNumbers);
sb.Append("..");
AppendArrayBound(sb, length + lowerBound, options.UseHexadecimalNumbers);
}
else
{
AppendArrayBound(sb, length, options.UseHexadecimalNumbers);
}
}
sb.Append(']');
arrayOpt = null;
}
else
{
AppendArrayRank(sb, type);
}
type = type.GetElementType();
}
while (type.IsArray);
return sb.ToString();
}
private void AppendArrayBound(StringBuilder sb, long bound, bool useHexadecimalNumbers)
{
if (bound <= int.MaxValue)
{
sb.Append(FormatLiteral((int)bound, useHexadecimalNumbers));
}
else
{
sb.Append(FormatLiteral(bound, useHexadecimalNumbers));
}
}
private static void AppendArrayRank(StringBuilder sb, Type arrayType)
protected override bool IsHiddenMember(MemberInfo member)
{
sb.Append('[');
int rank = arrayType.GetArrayRank();
if (rank > 1)
{
sb.Append(',', rank - 1);
}
sb.Append(']');
// Generated fields, e.g. "<property_name>k__BackingField"
return GeneratedNames.IsGeneratedMemberName(member.Name);
}
internal override string FormatMemberName(System.Reflection.MemberInfo member)
protected override string FormatRefKind(ParameterInfo parameter)
{
return member.Name;
return parameter.IsOut
? parameter.IsIn
? "ref"
: "out"
: "";
}
internal override bool IsHiddenMember(System.Reflection.MemberInfo member)
protected override bool TryFormatCompositeObject(object obj, out string value, out bool suppressMembers)
{
// Generated fields, e.g. "<property_name>k__BackingField"
return GeneratedNames.IsGeneratedMemberName(member.Name);
value = null;
suppressMembers = false;
return false;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Scripting.Hosting;
namespace Microsoft.CodeAnalysis.CSharp.Scripting.Hosting
{
using static ObjectFormatterHelpers;
public class CSharpPrimitiveFormatter : CommonPrimitiveFormatter
{
protected override string NullLiteral => ObjectDisplay.NullLiteral;
protected override string FormatLiteral(bool value)
{
return ObjectDisplay.FormatLiteral(value);
}
protected override string FormatLiteral(string value, bool quote, bool useHexadecimalNumbers = false)
{
var options = ObjectDisplayOptions.None;
if (quote)
{
options |= ObjectDisplayOptions.UseQuotes;
}
if (useHexadecimalNumbers)
{
options |= ObjectDisplayOptions.UseHexadecimalNumbers;
}
return ObjectDisplay.FormatLiteral(value, options);
}
protected override string FormatLiteral(char c, bool quote, bool includeCodePoints = false, bool useHexadecimalNumbers = false)
{
var options = ObjectDisplayOptions.None;
if (quote)
{
options |= ObjectDisplayOptions.UseQuotes;
}
if (includeCodePoints)
{
options |= ObjectDisplayOptions.IncludeCodePoints;
}
if (useHexadecimalNumbers)
{
options |= ObjectDisplayOptions.UseHexadecimalNumbers;
}
return ObjectDisplay.FormatLiteral(c, options);
}
protected override string FormatLiteral(sbyte value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers));
}
protected override string FormatLiteral(byte value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers));
}
protected override string FormatLiteral(short value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers));
}
protected override string FormatLiteral(ushort value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers));
}
protected override string FormatLiteral(int value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers));
}
protected override string FormatLiteral(uint value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers));
}
protected override string FormatLiteral(long value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers));
}
protected override string FormatLiteral(ulong value, bool useHexadecimalNumbers = false)
{
return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers));
}
protected override string FormatLiteral(double value)
{
return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None);
}
protected override string FormatLiteral(float value)
{
return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None);
}
protected override string FormatLiteral(decimal value)
{
return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None);
}
protected override string FormatLiteral(DateTime value)
{
// DateTime is not primitive in C#
return null;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Scripting.Hosting;
namespace Microsoft.CodeAnalysis.CSharp.Scripting.Hosting
{
public class CSharpTypeNameFormatter : CommonTypeNameFormatter
{
protected override CommonPrimitiveFormatter PrimitiveFormatter { get; }
public CSharpTypeNameFormatter(CommonPrimitiveFormatter primitiveFormatter)
{
PrimitiveFormatter = primitiveFormatter;
}
protected override string GenericParameterOpening => "<";
protected override string GenericParameterClosing => ">";
protected override string ArrayOpening => "[";
protected override string ArrayClosing => "]";
protected override string GetPrimitiveTypeName(SpecialType type)
{
switch (type)
{
case SpecialType.System_Boolean: return "bool";
case SpecialType.System_Byte: return "byte";
case SpecialType.System_Char: return "char";
case SpecialType.System_Decimal: return "decimal";
case SpecialType.System_Double: return "double";
case SpecialType.System_Int16: return "short";
case SpecialType.System_Int32: return "int";
case SpecialType.System_Int64: return "long";
case SpecialType.System_SByte: return "sbyte";
case SpecialType.System_Single: return "float";
case SpecialType.System_String: return "string";
case SpecialType.System_UInt16: return "ushort";
case SpecialType.System_UInt32: return "uint";
case SpecialType.System_UInt64: return "ulong";
case SpecialType.System_Object: return "object";
default:
return null;
}
}
public override string FormatTypeName(Type type, bool useHexadecimalArrayBounds)
{
string stateMachineName;
if (GeneratedNames.TryParseSourceMethodNameFromGeneratedName(type.Name, GeneratedNameKind.StateMachineType, out stateMachineName))
{
return stateMachineName;
}
return base.FormatTypeName(type, useHexadecimalArrayBounds);
}
}
}
......@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.Scripting.Hosting.UnitTests;
using Xunit;
using VB = Microsoft.CodeAnalysis.VisualBasic;
using Formatter = Microsoft.CodeAnalysis.Scripting.Hosting.UnitTests.TestCSharpObjectFormatter;
namespace Microsoft.CodeAnalysis.CSharp.Scripting.Hosting.UnitTests
{
......@@ -17,7 +18,7 @@ public class ObjectFormatterTests : ObjectFormatterTestBase
public void DebuggerProxy_FrameworkTypes_ArrayList()
{
var obj = new ArrayList { 1, 2, true, "foo" };
var str = CSharpObjectFormatter.Instance.FormatObject(obj, s_inline);
var str = Formatter.SingleLine.FormatObject(obj);
Assert.Equal("ArrayList(4) { 1, 2, true, \"foo\" }", str);
}
......@@ -30,7 +31,7 @@ public void DebuggerProxy_FrameworkTypes_Hashtable()
{ new byte[] { 1, 2 }, new[] { 1,2,3 } },
};
var str = CSharpObjectFormatter.Instance.FormatObject(obj, s_memberList);
var str = Formatter.SeparateLines.FormatObject(obj);
AssertMembers(str, "Hashtable(1)",
"{ byte[2] { 1, 2 }, int[3] { 1, 2, 3 } }"
......@@ -45,7 +46,7 @@ public void DebuggerProxy_FrameworkTypes_Queue()
obj.Enqueue(2);
obj.Enqueue(3);
var str = CSharpObjectFormatter.Instance.FormatObject(obj, s_inline);
var str = Formatter.SingleLine.FormatObject(obj);
Assert.Equal("Queue(3) { 1, 2, 3 }", str);
}
......@@ -57,7 +58,7 @@ public void DebuggerProxy_FrameworkTypes_Stack()
obj.Push(2);
obj.Push(3);
var str = CSharpObjectFormatter.Instance.FormatObject(obj, s_inline);
var str = Formatter.SingleLine.FormatObject(obj);
Assert.Equal("Stack(3) { 3, 2, 1 }", str);
}
......@@ -69,13 +70,13 @@ public void DebuggerProxy_FrameworkTypes_SortedList()
obj.Add(1, 5);
obj.Add(2, 6);
var str = CSharpObjectFormatter.Instance.FormatObject(obj, s_inline);
var str = Formatter.SingleLine.FormatObject(obj);
Assert.Equal("SortedList(3) { { 1, 5 }, { 2, 6 }, { 3, 4 } }", str);
obj = new SortedList();
obj.Add(new[] { 3 }, new int[] { 4 });
str = CSharpObjectFormatter.Instance.FormatObject(obj, s_inline);
str = Formatter.SingleLine.FormatObject(obj);
Assert.Equal("SortedList(1) { { int[1] { 3 }, int[1] { 4 } } }", str);
}
......@@ -108,7 +109,7 @@ End Class
var c = a.GetType("C");
var obj = Activator.CreateInstance(c);
var str = CSharpObjectFormatter.Instance.FormatObject(obj, s_memberList);
var str = Formatter.SeparateLines.FormatObject(obj);
AssertMembers(str, "C",
"A: 0",
"WE: null"
......
......@@ -45,7 +45,7 @@ public class CommandLineRunnerTests : TestBase
args ?? DefaultArgs,
new NotImplementedAnalyzerLoader());
return new CommandLineRunner(io, compiler, CSharpScriptCompiler.Instance, CSharpObjectFormatter.Instance);
return new CommandLineRunner(io, compiler, CSharpScriptCompiler.Instance, new CSharpObjectFormatter());
}
[Fact]
......@@ -182,8 +182,33 @@ > div(10, 2)
> div(10, 0)
«Red»
{new System.DivideByZeroException().Message}
«DarkRed»
+ Submission#0.div(Int32 a, Int32 b)
+ Submission#0.div(int, int)
«Gray»
> ", runner.Console.Out.ToString());
}
[Fact]
public void ExceptionInGeneric()
{
var runner = CreateRunner(input:
@"static class C<T> { public static int div<U>(int a, int b) => a/b; }
C<string>.div<bool>(10, 2)
C<string>.div<bool>(10, 0)
");
Assert.Equal(0, runner.RunInteractive());
Assert.Equal(
$@"Microsoft (R) Visual C# Interactive Compiler version {CompilerVersion}
Copyright (C) Microsoft Corporation. All rights reserved.
Type ""#help"" for more information.
> static class C<T> {{ public static int div<U>(int a, int b) => a/b; }}
> C<string>.div<bool>(10, 2)
5
> C<string>.div<bool>(10, 0)
«Red»
{new System.DivideByZeroException().Message}
+ Submission#0.C<T>.div<U>(int, int)
«Gray»
> ", runner.Console.Out.ToString());
}
......
......@@ -9,8 +9,6 @@
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis.Text;
......@@ -326,44 +324,7 @@ private void DisplayException(Exception e)
try
{
_console.ForegroundColor = ConsoleColor.Red;
_console.Out.WriteLine(e.Message);
_console.ForegroundColor = ConsoleColor.DarkRed;
var trace = new StackTrace(e, needFileInfo: true);
foreach (var frame in trace.GetFrames())
{
if (!frame.HasMethod())
{
continue;
}
var method = frame.GetMethod();
var type = method.DeclaringType;
if (type == typeof(CommandLineRunner))
{
break;
}
string methodDisplay = _objectFormatter.FormatMethodSignature(method);
// TODO: we don't want to include awaiter helpers, shouldn't they be marked by DebuggerHidden in FX?
if (methodDisplay == null || IsTaskAwaiter(type) || IsTaskAwaiter(type.DeclaringType))
{
continue;
}
_console.Out.Write(" + ");
_console.Out.Write(methodDisplay);
if (frame.HasSource())
{
_console.Out.Write(string.Format(CultureInfo.CurrentUICulture, ScriptingResources.AtFileLine, frame.GetFileName(), frame.GetFileLineNumber()));
}
_console.Out.WriteLine();
}
_console.Out.Write(_objectFormatter.FormatRaisedException(e));
}
finally
{
......@@ -371,22 +332,6 @@ private void DisplayException(Exception e)
}
}
private static bool IsTaskAwaiter(Type type)
{
if (type == typeof(TaskAwaiter) || type == typeof(ConfiguredTaskAwaitable))
{
return true;
}
if (type?.GetTypeInfo().IsGenericType == true)
{
var genericDef = type.GetTypeInfo().GetGenericTypeDefinition();
return genericDef == typeof(TaskAwaiter<>) || type == typeof(ConfiguredTaskAwaitable<>);
}
return false;
}
private static bool IsHelpCommand(string text)
{
const string helpCommand = "#help";
......
......@@ -18,23 +18,22 @@ namespace Microsoft.CodeAnalysis.Scripting.Hosting
public class CommandLineScriptGlobals
{
private readonly TextWriter _outputWriter;
private readonly ObjectFormatter _objectFormatter;
/// <summary>
/// Arguments given to the script.
/// </summary>
public IList<string> Args { get; }
public ObjectFormatter ObjectFormatter { get; }
/// <summary>
/// Pretty-prints an object.
/// </summary>
public void Print(object value)
{
_outputWriter.WriteLine(_objectFormatter.FormatObject(value, PrintOptions));
_outputWriter.WriteLine(ObjectFormatter.FormatObject(value));
}
internal ObjectFormattingOptions PrintOptions { get; }
public CommandLineScriptGlobals(TextWriter outputWriter, ObjectFormatter objectFormatter)
{
if (outputWriter == null)
......@@ -47,10 +46,8 @@ public CommandLineScriptGlobals(TextWriter outputWriter, ObjectFormatter objectF
throw new ArgumentNullException(nameof(objectFormatter));
}
PrintOptions = ObjectFormattingOptions.Default;
_outputWriter = outputWriter;
_objectFormatter = objectFormatter;
ObjectFormatter = objectFormatter;
Args = new List<string>();
}
......
......@@ -20,7 +20,6 @@ namespace Microsoft.CodeAnalysis.Scripting.Hosting
public class InteractiveScriptGlobals
{
private readonly TextWriter _outputWriter;
private readonly ObjectFormatter _objectFormatter;
/// <summary>
/// Arguments given to the script.
......@@ -32,13 +31,13 @@ public class InteractiveScriptGlobals
/// </summary>
public void Print(object value)
{
_outputWriter.WriteLine(_objectFormatter.FormatObject(value, PrintOptions));
_outputWriter.WriteLine(ObjectFormatter.FormatObject(value));
}
public IList<string> ReferencePaths { get; }
public IList<string> SourcePaths { get; }
internal ObjectFormattingOptions PrintOptions { get; set; }
public ObjectFormatter ObjectFormatter { get; set; }
public InteractiveScriptGlobals(TextWriter outputWriter, ObjectFormatter objectFormatter)
{
......@@ -59,9 +58,8 @@ public InteractiveScriptGlobals(TextWriter outputWriter, ObjectFormatter objectF
SourcePaths = new SearchPaths();
Args = new List<string>();
PrintOptions = ObjectFormattingOptions.Default;
ObjectFormatter = objectFormatter;
_outputWriter = outputWriter;
_objectFormatter = objectFormatter;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text;
namespace Microsoft.CodeAnalysis.Scripting.Hosting
{
/// <summary>
/// Object pretty printer.
/// </summary>
public abstract partial class CommonObjectFormatter
{
private sealed class Builder
{
private readonly StringBuilder _sb;
private readonly bool _insertEllipsis;
private readonly BuilderOptions _options;
private int _currentLimit;
public Builder(BuilderOptions options, bool insertEllipsis)
{
_sb = new StringBuilder();
_insertEllipsis = insertEllipsis;
_options = insertEllipsis ? options.SubtractEllipsisLength() : options;
_currentLimit = Math.Min(_options.LineLengthLimit, _options.TotalLengthLimit);
}
public bool LimitReached
{
get { return _sb.Length == _options.TotalLengthLimit; }
}
public int Remaining
{
get { return _options.TotalLengthLimit - _sb.Length; }
}
// can be negative (the min value is -Ellipsis.Length - 1)
private int CurrentRemaining
{
get { return _currentLimit - _sb.Length; }
}
public void AppendLine()
{
// remove line length limit so that we can insert a new line even
// if the previous one hit maxed out the line limit:
_currentLimit = _options.TotalLengthLimit;
Append(_options.NewLine);
// recalc limit for the next line:
_currentLimit = (int)Math.Min((long)_sb.Length + _options.LineLengthLimit, _options.TotalLengthLimit);
}
private void AppendEllipsis()
{
if (_sb.Length > 0 && _sb[_sb.Length - 1] != ' ')
{
_sb.Append(' ');
}
_sb.Append(_options.Ellipsis);
}
public void Append(char c, int count = 1)
{
if (CurrentRemaining < 0)
{
return;
}
int length = Math.Min(count, CurrentRemaining);
_sb.Append(c, length);
if (_insertEllipsis && length < count)
{
AppendEllipsis();
}
}
public void Append(string str, int start = 0, int count = Int32.MaxValue)
{
if (str == null || CurrentRemaining < 0)
{
return;
}
count = Math.Min(count, str.Length - start);
int length = Math.Min(count, CurrentRemaining);
_sb.Append(str, start, length);
if (_insertEllipsis && length < count)
{
AppendEllipsis();
}
}
public void AppendFormat(string format, params object[] args)
{
Append(string.Format(format, args));
}
public void AppendGroupOpening()
{
Append('{');
}
public void AppendGroupClosing(bool inline)
{
if (inline)
{
Append(" }");
}
else
{
AppendLine();
Append('}');
AppendLine();
}
}
public void AppendCollectionItemSeparator(bool isFirst, bool inline)
{
if (isFirst)
{
if (inline)
{
Append(' ');
}
else
{
AppendLine();
}
}
else
{
if (inline)
{
Append(", ");
}
else
{
Append(',');
AppendLine();
}
}
if (!inline)
{
Append(_options.Indentation);
}
}
/// <remarks>
/// This is for conveying cyclic dependencies to the user, not for detecting them.
/// </remarks>
internal void AppendInfiniteRecursionMarker()
{
AppendGroupOpening();
AppendCollectionItemSeparator(isFirst: true, inline: true);
Append(_options.Ellipsis);
AppendGroupClosing(inline: true);
}
public override string ToString()
{
return _sb.ToString();
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.CodeAnalysis.Scripting.Hosting
{
/// <summary>
/// Object pretty printer.
/// </summary>
public abstract partial class CommonObjectFormatter
{
/// <remarks>
/// Internal for testing.
/// </remarks>
internal struct BuilderOptions
{
public readonly string Indentation;
public readonly string NewLine;
public readonly string Ellipsis;
public readonly int LineLengthLimit;
public readonly int TotalLengthLimit;
public BuilderOptions(string indentation, string newLine, string ellipsis, int lineLengthLimit, int totalLengthLimit)
{
Indentation = indentation;
NewLine = newLine;
Ellipsis = ellipsis;
LineLengthLimit = lineLengthLimit;
TotalLengthLimit = totalLengthLimit;
}
public BuilderOptions WithTotalLengthLimit(int totalLengthLimit)
{
return new BuilderOptions(
Indentation,
NewLine,
Ellipsis,
LineLengthLimit,
totalLengthLimit);
}
public BuilderOptions SubtractEllipsisLength()
{
return new BuilderOptions(
Indentation,
NewLine,
Ellipsis,
Math.Max(0, LineLengthLimit - Ellipsis.Length - 1),
Math.Max(0, TotalLengthLimit - Ellipsis.Length - 1));
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.Scripting.Hosting
{
public abstract partial class CommonObjectFormatter
{
private sealed partial class Visitor
{
private struct FormattedMember
{
// Non-negative if the member is an inlined element of an array (DebuggerBrowsableState.RootHidden applied on a member of array type).
public readonly int Index;
// Formatted name of the member or null if it doesn't have a name (Index is >=0 then).
public readonly string Name;
// Formatted value of the member.
public readonly string Value;
public FormattedMember(int index, string name, string value)
{
Debug.Assert((name != null) || (index >= 0));
Name = name;
Index = index;
Value = value;
}
/// <remarks>
/// Doesn't (and doesn't need to) reflect the number of digits in <see cref="Index"/> since
/// it's only used for a conservative approximation (shorter is more conservative when trying
/// to determine the minimum number of members that will fill the output).
/// </remarks>
public int MinimalLength
{
get { return (Name != null ? Name.Length : "[0]".Length) + Value.Length; }
}
public string GetDisplayName()
{
return Name ?? "[" + Index.ToString() + "]";
}
public bool HasKeyName()
{
return Index >= 0 && Name != null && Name.Length >= 2 && Name[0] == '[' && Name[Name.Length - 1] == ']';
}
public bool AppendAsCollectionEntry(Builder result)
{
// Some BCL collections use [{key.ToString()}]: {value.ToString()} pattern to display collection entries.
// We want them to be printed initializer-style, i.e. { <key>, <value> }
if (HasKeyName())
{
result.AppendGroupOpening();
result.AppendCollectionItemSeparator(isFirst: true, inline: true);
result.Append(Name, 1, Name.Length - 2);
result.AppendCollectionItemSeparator(isFirst: false, inline: true);
result.Append(Value);
result.AppendGroupClosing(inline: true);
}
else
{
result.Append(Value);
}
return true;
}
public bool Append(Builder result, string separator)
{
result.Append(GetDisplayName());
result.Append(separator);
result.Append(Value);
return true;
}
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Collections;
namespace Microsoft.CodeAnalysis.Scripting.Hosting
{
using static ObjectFormatterHelpers;
// TODO (acasey): input validation
/// <summary>
/// Object pretty printer.
/// </summary>
public abstract partial class CommonObjectFormatter : ObjectFormatter
{
public override string FormatObject(object obj)
{
var formatter = new Visitor(this, InternalBuilderOptions, PrimitiveOptions, MemberDisplayFormat);
return formatter.FormatObject(obj);
}
internal virtual BuilderOptions InternalBuilderOptions =>
new BuilderOptions(
indentation: " ",
newLine: Environment.NewLine,
ellipsis: "...",
lineLengthLimit: int.MaxValue,
totalLengthLimit: 1024);
protected virtual CommonPrimitiveFormatter.Options PrimitiveOptions => default(CommonPrimitiveFormatter.Options);
protected virtual MemberDisplayFormat MemberDisplayFormat => default(MemberDisplayFormat);
protected abstract CommonTypeNameFormatter TypeNameFormatter { get; }
protected abstract CommonPrimitiveFormatter PrimitiveFormatter { get; }
protected abstract bool TryFormatCompositeObject(object obj, out string value, out bool suppressMembers);
public override string FormatRaisedException(Exception e)
{
if (e == null)
{
throw new ArgumentNullException(nameof(e));
}
var pooled = PooledStringBuilder.GetInstance();
var builder = pooled.Builder;
builder.AppendLine(e.Message);
var trace = new StackTrace(e, needFileInfo: true);
foreach (var frame in trace.GetFrames())
{
if (!frame.HasMethod())
{
continue;
}
var method = frame.GetMethod();
var type = method.DeclaringType;
// TODO (https://github.com/dotnet/roslyn/issues/5250): look for other types indicating that we're in Roslyn code
if (type == typeof(CommandLineRunner))
{
break;
}
// TODO: we don't want to include awaiter helpers, shouldn't they be marked by DebuggerHidden in FX?
if (IsTaskAwaiter(type) || IsTaskAwaiter(type.DeclaringType))
{
continue;
}
string methodDisplay = FormatMethodSignature(method, PrimitiveOptions.UseHexadecimalNumbers);
if (methodDisplay == null)
{
continue;
}
builder.Append(" + ");
builder.Append(methodDisplay);
if (frame.HasSource())
{
builder.Append(string.Format(CultureInfo.CurrentUICulture, ScriptingResources.AtFileLine, frame.GetFileName(), frame.GetFileLineNumber()));
}
builder.AppendLine();
}
return pooled.ToStringAndFree();
}
/// <summary>
/// Returns a method signature display string. Used to display stack frames.
/// </summary>
/// <returns>Null if the method is a compiler generated method that shouldn't be displayed to the user.</returns>
internal virtual string FormatMethodSignature(MethodBase method, bool useHexadecimalArrayBounds)
{
var declaringType = method.DeclaringType;
if (IsHiddenMember(declaringType.GetTypeInfo()) ||
IsHiddenMember(method) ||
method.GetCustomAttributes<DebuggerHiddenAttribute>().Any() ||
declaringType.GetTypeInfo().GetCustomAttributes<DebuggerHiddenAttribute>().Any())
{
return null;
}
var pooled = PooledStringBuilder.GetInstance();
var builder = pooled.Builder;
builder.Append(TypeNameFormatter.FormatTypeName(declaringType, useHexadecimalArrayBounds));
builder.Append('.');
builder.Append(method.Name);
builder.Append(TypeNameFormatter.FormatTypeArguments(method.GetGenericArguments(), useHexadecimalArrayBounds));
builder.Append('(');
bool first = true;
foreach (var parameter in method.GetParameters())
{
if (first)
{
first = false;
}
else
{
builder.Append(", ");
}
builder.Append(FormatRefKind(parameter));
builder.Append(TypeNameFormatter.FormatTypeName(parameter.ParameterType, useHexadecimalArrayBounds));
}
builder.Append(')');
return pooled.ToStringAndFree();
}
/// <summary>
/// Returns true if the member shouldn't be displayed (e.g. it's a compiler generated field).
/// </summary>
protected abstract bool IsHiddenMember(MemberInfo member);
protected abstract string FormatRefKind(ParameterInfo parameter);
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Scripting.Hosting
{
public abstract partial class CommonPrimitiveFormatter
{
public struct Options
{
public readonly bool UseHexadecimalNumbers;
public readonly bool IncludeCharacterCodePoints;
public readonly bool OmitStringQuotes;
public Options(bool useHexadecimalNumbers, bool includeCodePoints, bool omitStringQuotes)
{
UseHexadecimalNumbers = useHexadecimalNumbers;
IncludeCharacterCodePoints = includeCodePoints;
OmitStringQuotes = omitStringQuotes;
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Scripting.Hosting
{
using static ObjectFormatterHelpers;
public abstract partial class CommonPrimitiveFormatter
{
/// <summary>
/// String that describes "null" literal in the language.
/// </summary>
protected abstract string NullLiteral { get; }
protected abstract string FormatLiteral(bool value);
protected abstract string FormatLiteral(string value, bool quote, bool useHexadecimalNumbers = false);
protected abstract string FormatLiteral(char value, bool quote, bool includeCodePoints = false, bool useHexadecimalNumbers = false);
protected abstract string FormatLiteral(sbyte value, bool useHexadecimalNumbers = false);
protected abstract string FormatLiteral(byte value, bool useHexadecimalNumbers = false);
protected abstract string FormatLiteral(short value, bool useHexadecimalNumbers = false);
protected abstract string FormatLiteral(ushort value, bool useHexadecimalNumbers = false);
protected abstract string FormatLiteral(int value, bool useHexadecimalNumbers = false);
protected abstract string FormatLiteral(uint value, bool useHexadecimalNumbers = false);
protected abstract string FormatLiteral(long value, bool useHexadecimalNumbers = false);
protected abstract string FormatLiteral(ulong value, bool useHexadecimalNumbers = false);
protected abstract string FormatLiteral(double value);
protected abstract string FormatLiteral(float value);
protected abstract string FormatLiteral(decimal value);
protected abstract string FormatLiteral(DateTime value);
/// <summary>
/// Returns null if the type is not considered primitive in the target language.
/// </summary>
public string FormatPrimitive(object obj, Options options)
{
if (ReferenceEquals(obj, VoidValue))
{
return string.Empty;
}
if (obj == null)
{
return NullLiteral;
}
var type = obj.GetType();
if (type.GetTypeInfo().IsEnum)
{
return obj.ToString();
}
switch (GetPrimitiveSpecialType(type))
{
case SpecialType.System_Int32:
return FormatLiteral((int)obj, options.UseHexadecimalNumbers);
case SpecialType.System_String:
return FormatLiteral((string)obj, !options.OmitStringQuotes, options.UseHexadecimalNumbers);
case SpecialType.System_Boolean:
return FormatLiteral((bool)obj);
case SpecialType.System_Char:
return FormatLiteral((char)obj, !options.OmitStringQuotes, options.IncludeCharacterCodePoints, options.UseHexadecimalNumbers);
case SpecialType.System_Int64:
return FormatLiteral((long)obj, options.UseHexadecimalNumbers);
case SpecialType.System_Double:
return FormatLiteral((double)obj);
case SpecialType.System_Byte:
return FormatLiteral((byte)obj, options.UseHexadecimalNumbers);
case SpecialType.System_Decimal:
return FormatLiteral((decimal)obj);
case SpecialType.System_UInt32:
return FormatLiteral((uint)obj, options.UseHexadecimalNumbers);
case SpecialType.System_UInt64:
return FormatLiteral((ulong)obj, options.UseHexadecimalNumbers);
case SpecialType.System_Single:
return FormatLiteral((float)obj);
case SpecialType.System_Int16:
return FormatLiteral((short)obj, options.UseHexadecimalNumbers);
case SpecialType.System_UInt16:
return FormatLiteral((ushort)obj, options.UseHexadecimalNumbers);
case SpecialType.System_DateTime:
return FormatLiteral((DateTime)obj);
case SpecialType.System_SByte:
return FormatLiteral((sbyte)obj, options.UseHexadecimalNumbers);
case SpecialType.System_Object:
case SpecialType.System_Void:
case SpecialType.None:
return null;
default:
throw ExceptionUtilities.UnexpectedValue(GetPrimitiveSpecialType(type));
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Reflection;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Collections;
namespace Microsoft.CodeAnalysis.Scripting.Hosting
{
using static ObjectFormatterHelpers;
using TypeInfo = System.Reflection.TypeInfo;
public abstract class CommonTypeNameFormatter
{
protected abstract string GetPrimitiveTypeName(SpecialType type);
protected abstract string GenericParameterOpening { get; }
protected abstract string GenericParameterClosing { get; }
protected abstract string ArrayOpening { get; }
protected abstract string ArrayClosing { get; }
protected abstract CommonPrimitiveFormatter PrimitiveFormatter { get; }
// TODO (tomat): Use DebuggerDisplay.Type if specified?
public virtual string FormatTypeName(Type type, bool useHexadecimalArrayBounds)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
string result = GetPrimitiveTypeName(GetPrimitiveSpecialType(type));
if (result != null)
{
return result;
}
if (type.IsArray)
{
return FormatArrayTypeName(type, arrayOpt: null, useHexadecimalArrayBounds: useHexadecimalArrayBounds);
}
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsGenericType)
{
return FormatGenericTypeName(typeInfo, useHexadecimalArrayBounds);
}
if (typeInfo.DeclaringType != null)
{
return typeInfo.Name.Replace('+', '.');
}
return typeInfo.Name;
}
public virtual string FormatTypeArguments(Type[] typeArguments, bool useHexadecimalArrayBounds)
{
if (typeArguments == null)
{
throw new ArgumentNullException(nameof(typeArguments));
}
if (typeArguments.Length == 0)
{
return "";
}
var pooled = PooledStringBuilder.GetInstance();
var builder = pooled.Builder;
builder.Append(GenericParameterOpening);
var first = true;
foreach (var typeArgument in typeArguments)
{
if (first)
{
first = false;
}
else
{
builder.Append(", ");
}
builder.Append(FormatTypeName(typeArgument, useHexadecimalArrayBounds));
}
builder.Append(GenericParameterClosing);
return pooled.ToStringAndFree();
}
/// <summary>
/// Formats an array type name (vector or multidimensional).
/// </summary>
public virtual string FormatArrayTypeName(Type arrayType, Array arrayOpt, bool useHexadecimalArrayBounds)
{
if (arrayType == null)
{
throw new ArgumentNullException(nameof(arrayType));
}
StringBuilder sb = new StringBuilder();
// print the inner-most element type first:
Type elementType = arrayType.GetElementType();
while (elementType.IsArray)
{
elementType = elementType.GetElementType();
}
sb.Append(FormatTypeName(elementType, useHexadecimalArrayBounds));
// print all components of a jagged array:
Type type = arrayType;
do
{
if (arrayOpt != null)
{
sb.Append(ArrayOpening);
int rank = type.GetArrayRank();
bool anyNonzeroLowerBound = false;
for (int i = 0; i < rank; i++)
{
if (arrayOpt.GetLowerBound(i) > 0)
{
anyNonzeroLowerBound = true;
break;
}
}
for (int i = 0; i < rank; i++)
{
int lowerBound = arrayOpt.GetLowerBound(i);
int length = arrayOpt.GetLength(i);
if (i > 0)
{
sb.Append(", ");
}
if (anyNonzeroLowerBound)
{
AppendArrayBound(sb, lowerBound, useHexadecimalArrayBounds);
sb.Append("..");
AppendArrayBound(sb, length + lowerBound, useHexadecimalArrayBounds);
}
else
{
AppendArrayBound(sb, length, useHexadecimalArrayBounds);
}
}
sb.Append(ArrayClosing);
arrayOpt = null;
}
else
{
AppendArrayRank(sb, type);
}
type = type.GetElementType();
}
while (type.IsArray);
return sb.ToString();
}
private void AppendArrayBound(StringBuilder sb, long bound, bool useHexadecimalNumbers)
{
var options = new CommonPrimitiveFormatter.Options(useHexadecimalNumbers, includeCodePoints: false, omitStringQuotes: false);
var formatted = int.MinValue <= bound && bound <= int.MaxValue
? PrimitiveFormatter.FormatPrimitive((int)bound, options)
: PrimitiveFormatter.FormatPrimitive(bound, options);
sb.Append(formatted);
}
private void AppendArrayRank(StringBuilder sb, Type arrayType)
{
sb.Append('[');
int rank = arrayType.GetArrayRank();
if (rank > 1)
{
sb.Append(',', rank - 1);
}
sb.Append(']');
}
private string FormatGenericTypeName(TypeInfo typeInfo, bool useHexadecimalArrayBounds)
{
var pooledBuilder = PooledStringBuilder.GetInstance();
var builder = pooledBuilder.Builder;
// TODO (https://github.com/dotnet/roslyn/issues/5250): shouldn't need parameters, but StackTrace gives us unconstructed symbols.
// consolidated generic arguments (includes arguments of all declaring types):
Type[] genericArguments = typeInfo.IsGenericTypeDefinition ? typeInfo.GenericTypeParameters : typeInfo.GenericTypeArguments;
if (typeInfo.DeclaringType != null)
{
var nestedTypes = ArrayBuilder<TypeInfo>.GetInstance();
do
{
nestedTypes.Add(typeInfo);
typeInfo = typeInfo.DeclaringType?.GetTypeInfo();
}
while (typeInfo != null);
int typeArgumentIndex = 0;
for (int i = nestedTypes.Count - 1; i >= 0; i--)
{
AppendTypeInstantiation(builder, nestedTypes[i], genericArguments, ref typeArgumentIndex, useHexadecimalArrayBounds);
if (i > 0)
{
builder.Append('.');
}
}
nestedTypes.Free();
}
else
{
int typeArgumentIndex = 0;
AppendTypeInstantiation(builder, typeInfo, genericArguments, ref typeArgumentIndex, useHexadecimalArrayBounds);
}
return pooledBuilder.ToStringAndFree();
}
private void AppendTypeInstantiation(StringBuilder builder, TypeInfo typeInfo, Type[] genericArguments, ref int genericArgIndex, bool useHexadecimalArrayBounds)
{
// generic arguments of all the outer types and the current type;
int currentArgCount = (typeInfo.IsGenericTypeDefinition ? typeInfo.GenericTypeParameters.Length : typeInfo.GenericTypeArguments.Length) - genericArgIndex;
if (currentArgCount > 0)
{
string name = typeInfo.Name;
int backtick = name.IndexOf('`');
if (backtick > 0)
{
builder.Append(name.Substring(0, backtick));
}
else
{
builder.Append(name);
}
builder.Append(GenericParameterOpening);
for (int i = 0; i < currentArgCount; i++)
{
if (i > 0)
{
builder.Append(", ");
}
builder.Append(FormatTypeName(genericArguments[genericArgIndex++], useHexadecimalArrayBounds));
}
builder.Append(GenericParameterClosing);
}
else
{
builder.Append(typeInfo.Name);
}
}
}
}
......@@ -2,37 +2,32 @@
namespace Microsoft.CodeAnalysis.Scripting.Hosting
{
internal enum MemberDisplayFormat
// TODO (https://github.com/dotnet/roslyn/issues/6689): change default to SeparateLines
public enum MemberDisplayFormat
{
/// <summary>
/// Display just a simple description of the object, like type name or ToString(). Don't
/// display any members or items of the object.
/// </summary>
NoMembers,
/// <summary>
/// Display structure of the object on a single line.
/// </summary>
Inline,
SingleLine,
/// <summary>
/// Display structure of the object on a single line, where the object is displayed as a value of its container's member.
/// E.g. { a = ... }
/// Displays a simple description of the object followed by list of members. Each member is
/// displayed on a separate line.
/// </summary>
InlineValue,
SeparateLines,
/// <summary>
/// Displays a simple description of the object followed by list of members. Each member is
/// displayed on a separate line.
/// Display just a simple description of the object, like type name or ToString(). Don't
/// display any members or items of the object.
/// </summary>
List,
Hidden,
}
internal static partial class EnumBounds
{
internal static bool IsValid(this MemberDisplayFormat value)
{
return value >= MemberDisplayFormat.NoMembers && value <= MemberDisplayFormat.List;
return MemberDisplayFormat.SingleLine <= value && value <= MemberDisplayFormat.Hidden;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Scripting.Hosting
{
using TypeInfo = System.Reflection.TypeInfo;
internal static class ObjectFormatterHelpers
{
internal static readonly object VoidValue = new object();
internal static bool HasOverriddenToString(TypeInfo type)
{
if (type.IsInterface)
{
return false;
}
while (type.AsType() != typeof(object))
{
if (type.GetDeclaredMethod("ToString", Type.EmptyTypes) != null)
{
return true;
}
type = type.BaseType.GetTypeInfo();
}
return false;
}
internal static DebuggerDisplayAttribute GetApplicableDebuggerDisplayAttribute(MemberInfo member)
{
// Includes inherited attributes. The debugger uses the first attribute if multiple are applied.
var result = member.GetCustomAttributes<DebuggerDisplayAttribute>().FirstOrDefault();
if (result != null)
{
return result;
}
// TODO (tomat): which assembly should we look at for dd attributes?
var type = member as TypeInfo;
if (type != null)
{
foreach (DebuggerDisplayAttribute attr in type.Assembly.GetCustomAttributes<DebuggerDisplayAttribute>())
{
if (IsApplicableAttribute(type, attr.Target.GetTypeInfo(), attr.TargetTypeName))
{
return attr;
}
}
}
return null;
}
private static DebuggerTypeProxyAttribute GetApplicableDebuggerTypeProxyAttribute(TypeInfo type)
{
// includes inherited attributes. The debugger uses the first attribute if multiple are applied.
var result = type.GetCustomAttributes<DebuggerTypeProxyAttribute>().FirstOrDefault();
if (result != null)
{
return result;
}
// TODO (tomat): which assembly should we look at for proxy attributes?
foreach (DebuggerTypeProxyAttribute attr in type.Assembly.GetCustomAttributes<DebuggerTypeProxyAttribute>())
{
if (IsApplicableAttribute(type, attr.Target.GetTypeInfo(), attr.TargetTypeName))
{
return attr;
}
}
return null;
}
private static bool IsApplicableAttribute(TypeInfo type, TypeInfo targetType, string targetTypeName)
{
return type != null && AreEquivalent(targetType, type)
|| targetTypeName != null && type.FullName == targetTypeName;
}
private static bool AreEquivalent(TypeInfo type, TypeInfo other)
{
// TODO: Unify NoPIA interfaces
// https://github.com/dotnet/corefx/issues/2101
return type.Equals(other);
}
internal static object GetDebuggerTypeProxy(object obj)
{
// use proxy type if defined:
var type = obj.GetType().GetTypeInfo();
var debuggerTypeProxy = GetApplicableDebuggerTypeProxyAttribute(type);
if (debuggerTypeProxy != null)
{
try
{
var proxyType = Type.GetType(debuggerTypeProxy.ProxyTypeName, throwOnError: false, ignoreCase: false);
if (proxyType != null)
{
if (proxyType.GetTypeInfo().IsGenericTypeDefinition)
{
proxyType = proxyType.MakeGenericType(type.GenericTypeArguments);
}
return Activator.CreateInstance(proxyType, new object[] { obj });
}
}
catch (Exception)
{
// no-op, ignore proxy if it is implemented incorrectly or can't be loaded
}
}
return null;
}
internal static MemberInfo ResolveMember(object obj, string memberName, bool callableOnly)
{
TypeInfo type = obj.GetType().GetTypeInfo();
// case-sensitive:
TypeInfo currentType = type;
while (true)
{
if (!callableOnly)
{
var field = currentType.GetDeclaredField(memberName);
if (field != null)
{
return field;
}
var property = currentType.GetDeclaredProperty(memberName);
if (property != null)
{
var getter = property.GetMethod;
if (getter != null)
{
return getter;
}
}
}
var method = currentType.GetDeclaredMethod(memberName, Type.EmptyTypes);
if (method != null)
{
return method;
}
if (currentType.BaseType == null)
{
break;
}
currentType = currentType.BaseType.GetTypeInfo();
}
// case-insensitive:
currentType = type;
while (true)
{
IEnumerable<MemberInfo> members;
if (callableOnly)
{
members = type.DeclaredMethods;
}
else
{
members = ((IEnumerable<MemberInfo>)type.DeclaredFields).Concat(type.DeclaredProperties);
}
MemberInfo candidate = null;
foreach (var member in members)
{
if (StringComparer.OrdinalIgnoreCase.Equals(memberName, member.Name))
{
if (candidate != null)
{
return null;
}
MethodInfo method;
if (member is FieldInfo)
{
candidate = member;
}
else if ((method = member as MethodInfo) != null)
{
if (method.GetParameters().Length == 0)
{
candidate = member;
}
}
else
{
var getter = ((PropertyInfo)member).GetMethod;
if (getter?.GetParameters().Length == 0)
{
candidate = member;
}
}
}
}
if (candidate != null)
{
return candidate;
}
if (currentType.BaseType == null)
{
break;
}
currentType = currentType.BaseType.GetTypeInfo();
}
return null;
}
internal static object GetMemberValue(MemberInfo member, object obj, out Exception exception)
{
exception = null;
try
{
FieldInfo field;
MethodInfo method;
if ((field = member as FieldInfo) != null)
{
return field.GetValue(obj);
}
if ((method = member as MethodInfo) != null)
{
return (method.ReturnType == typeof(void)) ? VoidValue : method.Invoke(obj, SpecializedCollections.EmptyObjects);
}
var property = (PropertyInfo)member;
if (property.GetMethod == null)
{
return null;
}
return property.GetValue(obj, SpecializedCollections.EmptyObjects);
}
catch (TargetInvocationException e)
{
exception = e.InnerException;
}
return null;
}
internal static bool IsTaskAwaiter(Type type)
{
if (type == typeof(TaskAwaiter) || type == typeof(ConfiguredTaskAwaitable))
{
return true;
}
if (type?.GetTypeInfo().IsGenericType == true)
{
var genericDef = type.GetTypeInfo().GetGenericTypeDefinition();
return genericDef == typeof(TaskAwaiter<>) || type == typeof(ConfiguredTaskAwaitable<>);
}
return false;
}
internal static SpecialType GetPrimitiveSpecialType(Type type)
{
Debug.Assert(type != null);
if (type == typeof(int))
{
return SpecialType.System_Int32;
}
if (type == typeof(string))
{
return SpecialType.System_String;
}
if (type == typeof(bool))
{
return SpecialType.System_Boolean;
}
if (type == typeof(char))
{
return SpecialType.System_Char;
}
if (type == typeof(long))
{
return SpecialType.System_Int64;
}
if (type == typeof(double))
{
return SpecialType.System_Double;
}
if (type == typeof(byte))
{
return SpecialType.System_Byte;
}
if (type == typeof(decimal))
{
return SpecialType.System_Decimal;
}
if (type == typeof(uint))
{
return SpecialType.System_UInt32;
}
if (type == typeof(ulong))
{
return SpecialType.System_UInt64;
}
if (type == typeof(float))
{
return SpecialType.System_Single;
}
if (type == typeof(short))
{
return SpecialType.System_Int16;
}
if (type == typeof(ushort))
{
return SpecialType.System_UInt16;
}
if (type == typeof(DateTime))
{
return SpecialType.System_DateTime;
}
if (type == typeof(sbyte))
{
return SpecialType.System_SByte;
}
if (type == typeof(object))
{
return SpecialType.System_Object;
}
if (type == typeof(void))
{
return SpecialType.System_Void;
}
return SpecialType.None;
}
internal static ObjectDisplayOptions GetObjectDisplayOptions(bool useHexadecimalNumbers)
{
return useHexadecimalNumbers ? ObjectDisplayOptions.UseHexadecimalNumbers : ObjectDisplayOptions.None;
}
// Parses
// <clr-member-name>
// <clr-member-name> ',' 'nq'
// <clr-member-name> '(' ')'
// <clr-member-name> '(' ')' ',' 'nq'
internal static string ParseSimpleMemberName(string str, int start, int end, out bool noQuotes, out bool isCallable)
{
Debug.Assert(str != null && start >= 0 && end >= start);
isCallable = false;
noQuotes = false;
// no-quotes suffix:
if (end - 3 >= start && str[end - 2] == 'n' && str[end - 1] == 'q')
{
int j = end - 3;
while (j >= start && Char.IsWhiteSpace(str[j]))
{
j--;
}
if (j >= start && str[j] == ',')
{
noQuotes = true;
end = j;
}
}
int i = end - 1;
EatTrailingWhiteSpace(str, start, ref i);
if (i > start && str[i] == ')')
{
int closingParen = i;
i--;
EatTrailingWhiteSpace(str, start, ref i);
if (str[i] != '(')
{
i = closingParen;
}
else
{
i--;
EatTrailingWhiteSpace(str, start, ref i);
isCallable = true;
}
}
EatLeadingWhiteSpace(str, ref start, i);
return str.Substring(start, i - start + 1);
}
private static void EatTrailingWhiteSpace(string str, int start, ref int i)
{
while (i >= start && Char.IsWhiteSpace(str[i]))
{
i--;
}
}
private static void EatLeadingWhiteSpace(string str, ref int i, int end)
{
while (i < end && Char.IsWhiteSpace(str[i]))
{
i++;
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.CodeAnalysis.Scripting.Hosting
{
internal sealed class ObjectFormattingOptions
{
public static ObjectFormattingOptions Default { get; } = new ObjectFormattingOptions();
internal bool QuoteStrings { get; }
internal MemberDisplayFormat MemberFormat { get; }
internal int MaxLineLength { get; }
internal int MaxOutputLength { get; }
internal bool UseHexadecimalNumbers { get; }
internal string MemberIndentation { get; }
internal string Ellipsis { get; }
internal string NewLine { get; }
internal bool IncludeCodePoints { get; }
internal ObjectFormattingOptions(
MemberDisplayFormat memberFormat = MemberDisplayFormat.Inline,
bool quoteStrings = true,
bool useHexadecimalNumbers = false,
bool includeCodePoints = false,
int maxLineLength = int.MaxValue,
int maxOutputLength = 1024,
string memberIndentation = null,
string ellipsis = null,
string lineBreak = null)
{
if (!memberFormat.IsValid())
{
throw new ArgumentOutOfRangeException(nameof(memberFormat));
}
this.MemberFormat = memberFormat;
this.QuoteStrings = quoteStrings;
this.IncludeCodePoints = includeCodePoints;
this.MaxOutputLength = maxOutputLength;
this.MaxLineLength = maxLineLength;
this.UseHexadecimalNumbers = useHexadecimalNumbers;
this.MemberIndentation = memberIndentation ?? " ";
this.Ellipsis = ellipsis ?? "...";
this.NewLine = lineBreak ?? Environment.NewLine;
}
internal ObjectFormattingOptions Copy(
MemberDisplayFormat? memberFormat = null,
bool? quoteStrings = null,
bool? useHexadecimalNumbers = null,
bool? includeCodePoints = null,
int? maxLineLength = null,
int? maxOutputLength = null,
string memberIndentation = null,
string ellipsis = null,
string newLine = null)
{
return new ObjectFormattingOptions(
memberFormat ?? this.MemberFormat,
quoteStrings ?? this.QuoteStrings,
useHexadecimalNumbers ?? this.UseHexadecimalNumbers,
includeCodePoints ?? this.IncludeCodePoints,
maxLineLength ?? this.MaxLineLength,
maxOutputLength ?? this.MaxOutputLength,
memberIndentation ?? this.MemberIndentation,
ellipsis ?? this.Ellipsis,
newLine ?? this.NewLine);
}
}
}
......@@ -78,6 +78,14 @@
<Compile Include="Hosting\CommandLine\ConsoleIO.cs" />
<Compile Include="Hosting\CommandLine\NotImplementedAnalyzerLoader.cs" />
<Compile Include="Hosting\InteractiveScriptGlobals.cs" />
<Compile Include="Hosting\ObjectFormatter\CommonObjectFormatter.BuilderOptions.cs" />
<Compile Include="Hosting\ObjectFormatter\CommonPrimitiveFormatter.Options.cs" />
<Compile Include="Hosting\ObjectFormatter\CommonPrimitiveFormatter.cs" />
<Compile Include="Hosting\ObjectFormatter\CommonTypeNameFormatter.cs" />
<Compile Include="Hosting\ObjectFormatter\ObjectFormatter.cs" />
<Compile Include="Hosting\ObjectFormatter\ObjectFormatterHelpers.cs" />
<Compile Include="Hosting\ObjectFormatter\CommonObjectFormatter.Builder.cs" />
<Compile Include="Hosting\ObjectFormatter\CommonObjectFormatter.Visitor.FormattedMember.cs" />
<Compile Include="Hosting\Resolvers\RuntimeMetadataReferenceResolver.cs" />
<Compile Include="Hosting\AssemblyLoader\InteractiveAssemblyLoader.cs" />
<Compile Include="Hosting\AssemblyLoader\MetadataShadowCopy.cs" />
......@@ -94,13 +102,12 @@
<DependentUpon>ScriptingResources.resx</DependentUpon>
</Compile>
<Compile Include="ScriptRunner.cs" />
<Compile Include="Hosting\ObjectFormatter\ObjectFormatter.cs" />
<Compile Include="Hosting\ObjectFormatter\ObjectFormatter.Formatter.cs" />
<Compile Include="Hosting\ObjectFormatter\CommonObjectFormatter.cs" />
<Compile Include="Hosting\ObjectFormatter\CommonObjectFormatter.Visitor.cs" />
<Compile Include="Script.cs" />
<Compile Include="ScriptBuilder.cs" />
<Compile Include="CompilationErrorException.cs" />
<Compile Include="Hosting\ObjectFormatter\MemberDisplayFormat.cs" />
<Compile Include="Hosting\ObjectFormatter\ObjectFormattingOptions.cs" />
<Compile Include="ScriptExecutionState.cs" />
<Compile Include="ScriptOptions.cs" />
<Compile Include="ScriptSourceResolver.cs" />
......
......@@ -8,10 +8,6 @@ namespace Microsoft.CodeAnalysis.Scripting.Hosting.UnitTests
{
public abstract class ObjectFormatterTestBase
{
internal static readonly ObjectFormattingOptions s_hexa = new ObjectFormattingOptions(useHexadecimalNumbers: true, maxOutputLength: int.MaxValue);
internal static readonly ObjectFormattingOptions s_memberList = new ObjectFormattingOptions(memberFormat: MemberDisplayFormat.List, maxOutputLength: int.MaxValue);
internal static readonly ObjectFormattingOptions s_inline = new ObjectFormattingOptions(memberFormat: MemberDisplayFormat.Inline, maxOutputLength: int.MaxValue);
public void AssertMembers(string str, params string[] expected)
{
int i = 0;
......
......@@ -51,6 +51,10 @@
<Project>{066F0DBD-C46C-4C20-AFEC-99829A172625}</Project>
<Name>CSharpScripting</Name>
</ProjectReference>
<ProjectReference Include="..\VisualBasic\BasicScripting.vbproj">
<Project>{3e7dea65-317b-4f43-a25d-62f18d96cfd7}</Project>
<Name>BasicScripting</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
</PropertyGroup>
......@@ -67,6 +71,8 @@
<Compile Include="ScriptTaskExtensions.cs" />
<Compile Include="TestCompilationFactory.cs" />
<Compile Include="TestConsoleIO.cs" />
<Compile Include="TestVisualBasicObjectFormatter.cs" />
<Compile Include="TestCSharpObjectFormatter.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.CSharp.Scripting.Hosting;
namespace Microsoft.CodeAnalysis.Scripting.Hosting.UnitTests
{
public sealed class TestCSharpObjectFormatter : CSharpObjectFormatter
{
public static readonly CommonObjectFormatter SeparateLines = new TestCSharpObjectFormatter(MemberDisplayFormat.SeparateLines);
public static readonly CommonObjectFormatter SingleLine = new TestCSharpObjectFormatter(MemberDisplayFormat.SingleLine);
public static readonly CommonObjectFormatter Hidden = new TestCSharpObjectFormatter(MemberDisplayFormat.Hidden);
public TestCSharpObjectFormatter(
MemberDisplayFormat memberDisplayFormat = default(MemberDisplayFormat),
bool useHexadecimalNumbers = false,
int lineLengthLimit = int.MaxValue,
int totalLengthLimit = int.MaxValue)
{
MemberDisplayFormat = memberDisplayFormat;
PrimitiveOptions = new CommonPrimitiveFormatter.Options(useHexadecimalNumbers, includeCodePoints: false, omitStringQuotes: false);
InternalBuilderOptions = new BuilderOptions(
indentation: " ",
newLine: Environment.NewLine,
ellipsis: "...",
lineLengthLimit: lineLengthLimit,
totalLengthLimit: totalLengthLimit);
}
protected override MemberDisplayFormat MemberDisplayFormat { get; }
protected override CommonPrimitiveFormatter.Options PrimitiveOptions { get; }
internal override BuilderOptions InternalBuilderOptions { get; }
}
}
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting;
namespace Microsoft.CodeAnalysis.Scripting.Hosting.UnitTests
{
public sealed class TestVisualBasicObjectFormatter : VisualBasicObjectFormatter
{
public static readonly CommonObjectFormatter SeparateLines = new TestVisualBasicObjectFormatter(MemberDisplayFormat.SeparateLines);
public static readonly CommonObjectFormatter SingleLine = new TestVisualBasicObjectFormatter(MemberDisplayFormat.SingleLine);
public static readonly CommonObjectFormatter Hidden = new TestVisualBasicObjectFormatter(MemberDisplayFormat.Hidden);
public TestVisualBasicObjectFormatter(
MemberDisplayFormat memberDisplayFormat = default(MemberDisplayFormat),
bool useHexadecimalNumbers = false,
bool omitStringQuotes = false,
int lineLengthLimit = int.MaxValue,
int totalLengthLimit = int.MaxValue)
{
MemberDisplayFormat = memberDisplayFormat;
PrimitiveOptions = new CommonPrimitiveFormatter.Options(useHexadecimalNumbers, includeCodePoints: false, omitStringQuotes: omitStringQuotes);
InternalBuilderOptions = new BuilderOptions(
indentation: " ",
newLine: Environment.NewLine,
ellipsis: "...",
lineLengthLimit: lineLengthLimit,
totalLengthLimit: totalLengthLimit);
}
protected override MemberDisplayFormat MemberDisplayFormat { get; }
protected override CommonPrimitiveFormatter.Options PrimitiveOptions { get; }
internal override BuilderOptions InternalBuilderOptions { get; }
}
}
\ No newline at end of file
......@@ -43,6 +43,8 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Hosting\CommandLine\Vbi.vb" />
<Compile Include="Hosting\ObjectFormatter\VisualBasicPrimitiveFormatter.vb" />
<Compile Include="Hosting\ObjectFormatter\VisualBasicTypeNameFormatter.vb" />
<Compile Include="VBScriptingResources.Designer.vb">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Reflection
Imports System.Text
Imports Microsoft.CodeAnalysis.Scripting.Hosting
Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting
Public NotInheritable Class VisualBasicObjectFormatter
Inherits ObjectFormatter
Public Class VisualBasicObjectFormatter
Inherits CommonObjectFormatter
Public Shared ReadOnly Property Instance As VisualBasicObjectFormatter = New VisualBasicObjectFormatter()
Protected Overrides ReadOnly Property TypeNameFormatter As CommonTypeNameFormatter
Protected Overrides ReadOnly Property PrimitiveFormatter As CommonPrimitiveFormatter
Private Sub New()
Public Sub New()
PrimitiveFormatter = New VisualBasicPrimitiveFormatter()
TypeNameFormatter = New VisualBasicTypeNameFormatter(PrimitiveFormatter)
End Sub
Friend Overrides ReadOnly Property VoidDisplayString As Object
Get
' TODO
Return ""
End Get
End Property
Friend Overrides ReadOnly Property NullLiteral As String
Get
Return "Nothing"
End Get
End Property
Friend Overrides Function FormatLiteral(value As Boolean) As String
Return ObjectDisplay.FormatLiteral(value)
End Function
Friend Overrides Function FormatLiteral(value As Date) As String
Return ObjectDisplay.FormatLiteral(value)
End Function
Friend Overrides Function FormatLiteral(value As String, quote As Boolean, Optional useHexadecimalNumbers As Boolean = False) As String
Dim options = ObjectDisplayOptions.None
If quote Then
options = options Or ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableCharacters
End If
If useHexadecimalNumbers Then
options = options Or ObjectDisplayOptions.UseHexadecimalNumbers
End If
Return ObjectDisplay.FormatLiteral(value, options)
End Function
Friend Overrides Function FormatLiteral(c As Char, quote As Boolean, Optional includeCodePoints As Boolean = False, Optional useHexadecimalNumbers As Boolean = False) As String
Dim options = ObjectDisplayOptions.None
If quote Then
options = options Or ObjectDisplayOptions.UseQuotes Or ObjectDisplayOptions.EscapeNonPrintableCharacters
End If
If includeCodePoints Then
options = options Or ObjectDisplayOptions.IncludeCodePoints
End If
If useHexadecimalNumbers Then
options = options Or ObjectDisplayOptions.UseHexadecimalNumbers
End If
Return ObjectDisplay.FormatLiteral(c, options)
End Function
Friend Overrides Function FormatLiteral(value As SByte, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture)
End Function
Friend Overrides Function FormatLiteral(value As Byte, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture)
End Function
Friend Overrides Function FormatLiteral(value As Short, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture)
End Function
Friend Overrides Function FormatLiteral(value As UShort, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture)
End Function
Friend Overrides Function FormatLiteral(value As Integer, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture)
End Function
Friend Overrides Function FormatLiteral(value As UInteger, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture)
End Function
Friend Overrides Function FormatLiteral(value As Long, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture)
End Function
Friend Overrides Function FormatLiteral(value As ULong, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers), UIFormatCulture)
End Function
Friend Overrides Function FormatLiteral(value As Double) As String
Return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None, UIFormatCulture)
End Function
Friend Overrides Function FormatLiteral(value As Single) As String
Return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None, UIFormatCulture)
End Function
Friend Overrides Function FormatLiteral(value As Decimal) As String
Return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None, UIFormatCulture)
End Function
Friend Overrides Function GetPrimitiveTypeName(type As SpecialType) As String
Select Case type
Case SpecialType.System_Boolean
Return "Boolean"
Case SpecialType.System_Byte
Return "Byte"
Case SpecialType.System_Char
Return "Char"
Case SpecialType.System_Decimal
Return "Decimal"
Case SpecialType.System_Double
Return "Double"
Case SpecialType.System_Int16
Return "Short"
Case SpecialType.System_Int32
Return "Integer"
Case SpecialType.System_Int64
Return "Long"
Case SpecialType.System_SByte
Return "SByte"
Case SpecialType.System_Single
Return "Single"
Case SpecialType.System_String
Return "String"
Case SpecialType.System_UInt16
Return "UShort"
Case SpecialType.System_UInt32
Return "UInteger"
Case SpecialType.System_UInt64
Return "ULong"
Case SpecialType.System_DateTime
Return "Date"
Case SpecialType.System_Object
Return "Object"
Case Else
Return Nothing
End Select
End Function
Friend Overrides ReadOnly Property GenericParameterOpening As String
Get
Return "(Of "
End Get
End Property
Friend Overrides ReadOnly Property GenericParameterClosing As String
Get
Return ")"
End Get
End Property
Friend Overrides Function FormatGeneratedTypeName(type As Type) As String
' TODO: https://github.com/dotnet/roslyn/issues/3739
Return Nothing
End Function
Friend Overrides Function FormatArrayTypeName(arrayType As Type, arrayOpt As Array, options As ObjectFormattingOptions) As String
Dim sb As StringBuilder = New StringBuilder()
' print the inner-most element type first:
Dim elementType As Type = arrayType.GetElementType()
While elementType.IsArray
elementType = elementType.GetElementType()
End While
sb.Append(FormatTypeName(elementType, options))
' print all components of a jagged array:
Dim type As Type = arrayType
Do
If arrayOpt IsNot Nothing Then
sb.Append("("c)
Dim rank As Integer = type.GetArrayRank()
Dim anyNonzeroLowerBound As Boolean = False
For i = 0 To rank - 1
If arrayOpt.GetLowerBound(i) > 0 Then
anyNonzeroLowerBound = True
Exit Do
End If
i = i + 1
Next
For i = 0 To rank - 1
Dim lowerBound As Integer = arrayOpt.GetLowerBound(i)
Dim length As Integer = arrayOpt.GetLength(i)
If i > 0 Then
sb.Append(", ")
End If
If anyNonzeroLowerBound Then
AppendArrayBound(sb, lowerBound, options.UseHexadecimalNumbers)
sb.Append("..")
AppendArrayBound(sb, length + lowerBound, options.UseHexadecimalNumbers)
Else
AppendArrayBound(sb, length, options.UseHexadecimalNumbers)
End If
i = i + 1
Next
sb.Append(")"c)
arrayOpt = Nothing
Else
AppendArrayRank(sb, type)
End If
type = type.GetElementType()
Loop While type.IsArray
Return sb.ToString()
Protected Overrides Function IsHiddenMember(member As MemberInfo) As Boolean
' TODO (tomat)
Return False
End Function
Private Sub AppendArrayBound(sb As StringBuilder, bound As Long, useHexadecimalNumbers As Boolean)
If bound <= Int32.MaxValue Then
sb.Append(FormatLiteral(CType(bound, Integer), useHexadecimalNumbers))
Else
sb.Append(FormatLiteral(bound, useHexadecimalNumbers))
End If
End Sub
Private Shared Sub AppendArrayRank(sb As StringBuilder, arrayType As Type)
sb.Append("["c)
Dim rank As Integer = arrayType.GetArrayRank()
If rank > 1 Then
sb.Append(","c, rank - 1)
End If
sb.Append("]"c)
End Sub
Friend Overrides Function FormatMemberName(member As MemberInfo) As String
Return member.Name
Protected Overrides Function FormatRefKind(parameter As ParameterInfo) As String
Return If(parameter.IsOut, "ByRef", "")
End Function
Friend Overrides Function IsHiddenMember(member As MemberInfo) As Boolean
' TODO (tomat)
Protected Overrides Function TryFormatCompositeObject(obj As Object, ByRef value As String, ByRef suppressMembers As Boolean) As Boolean
Return False
End Function
End Class
End Namespace
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.Scripting.Hosting
Imports Microsoft.CodeAnalysis.Scripting.Hosting.ObjectFormatterHelpers
Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting
Public Class VisualBasicPrimitiveFormatter
Inherits CommonPrimitiveFormatter
Protected Overrides ReadOnly Property NullLiteral As String
Get
Return "Nothing"
End Get
End Property
Protected Overrides Function FormatLiteral(value As Boolean) As String
Return ObjectDisplay.FormatLiteral(value)
End Function
Protected Overrides Function FormatLiteral(value As Date) As String
Return ObjectDisplay.FormatLiteral(value)
End Function
Protected Overrides Function FormatLiteral(value As String, quote As Boolean, Optional useHexadecimalNumbers As Boolean = False) As String
Dim options = ObjectDisplayOptions.None
If quote Then
options = options Or ObjectDisplayOptions.UseQuotes
End If
If useHexadecimalNumbers Then
options = options Or ObjectDisplayOptions.UseHexadecimalNumbers
End If
Return ObjectDisplay.FormatLiteral(value, options)
End Function
Protected Overrides Function FormatLiteral(c As Char, quote As Boolean, Optional includeCodePoints As Boolean = False, Optional useHexadecimalNumbers As Boolean = False) As String
Dim options = ObjectDisplayOptions.None
If quote Then
options = options Or ObjectDisplayOptions.UseQuotes
End If
If includeCodePoints Then
options = options Or ObjectDisplayOptions.IncludeCodePoints
End If
If useHexadecimalNumbers Then
options = options Or ObjectDisplayOptions.UseHexadecimalNumbers
End If
Return ObjectDisplay.FormatLiteral(c, options)
End Function
Protected Overrides Function FormatLiteral(value As SByte, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers))
End Function
Protected Overrides Function FormatLiteral(value As Byte, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers))
End Function
Protected Overrides Function FormatLiteral(value As Short, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers))
End Function
Protected Overrides Function FormatLiteral(value As UShort, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers))
End Function
Protected Overrides Function FormatLiteral(value As Integer, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers))
End Function
Protected Overrides Function FormatLiteral(value As UInteger, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers))
End Function
Protected Overrides Function FormatLiteral(value As Long, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers))
End Function
Protected Overrides Function FormatLiteral(value As ULong, Optional useHexadecimalNumbers As Boolean = False) As String
Return ObjectDisplay.FormatLiteral(value, GetObjectDisplayOptions(useHexadecimalNumbers))
End Function
Protected Overrides Function FormatLiteral(value As Double) As String
Return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None)
End Function
Protected Overrides Function FormatLiteral(value As Single) As String
Return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None)
End Function
Protected Overrides Function FormatLiteral(value As Decimal) As String
Return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None)
End Function
End Class
End Namespace
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.Scripting.Hosting
Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting
Public Class VisualBasicTypeNameFormatter
Inherits CommonTypeNameFormatter
Protected Overrides ReadOnly Property PrimitiveFormatter As CommonPrimitiveFormatter
Public Sub New(pFormatter As CommonPrimitiveFormatter)
PrimitiveFormatter = pFormatter
End Sub
Protected Overrides Function GetPrimitiveTypeName(type As SpecialType) As String
Select Case type
Case SpecialType.System_Boolean
Return "Boolean"
Case SpecialType.System_Byte
Return "Byte"
Case SpecialType.System_Char
Return "Char"
Case SpecialType.System_Decimal
Return "Decimal"
Case SpecialType.System_Double
Return "Double"
Case SpecialType.System_Int16
Return "Short"
Case SpecialType.System_Int32
Return "Integer"
Case SpecialType.System_Int64
Return "Long"
Case SpecialType.System_SByte
Return "SByte"
Case SpecialType.System_Single
Return "Single"
Case SpecialType.System_String
Return "String"
Case SpecialType.System_UInt16
Return "UShort"
Case SpecialType.System_UInt32
Return "UInteger"
Case SpecialType.System_UInt64
Return "ULong"
Case SpecialType.System_DateTime
Return "Date"
Case SpecialType.System_Object
Return "Object"
Case Else
Return Nothing
End Select
End Function
Protected Overrides ReadOnly Property GenericParameterOpening As String
Get
Return "(Of "
End Get
End Property
Protected Overrides ReadOnly Property GenericParameterClosing As String
Get
Return ")"
End Get
End Property
Protected Overrides ReadOnly Property ArrayOpening As String
Get
Return "("
End Get
End Property
Protected Overrides ReadOnly Property ArrayClosing As String
Get
Return ")"
End Get
End Property
Public Overrides Function FormatTypeName(type As Type, useHexadecimalArrayBounds As Boolean) As String
' TODO (https://github.com/dotnet/roslyn/issues/3739): handle generated type names (e.g. state machines as in C#)
Return MyBase.FormatTypeName(type, useHexadecimalArrayBounds)
End Function
End Class
End Namespace
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.Scripting.Hosting.UnitTests
Imports ObjectFormatterFixtures
Imports Xunit
Imports Formatter = Microsoft.CodeAnalysis.Scripting.Hosting.UnitTests.TestVisualBasicObjectFormatter
Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting.UnitTests
......@@ -12,14 +12,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting.UnitTests
<Fact>
Public Sub DebuggerProxy_FrameworkTypes_ArrayList()
Dim obj = New ArrayList From {1, 2, True, "foo"}
Dim str = VisualBasicObjectFormatter.Instance.FormatObject(obj, s_inline)
Dim str = Formatter.SingleLine.FormatObject(obj)
Assert.Equal("ArrayList(4) { 1, 2, True, ""foo"" }", str)
End Sub
<Fact>
Public Sub DebuggerProxy_FrameworkTypes_Hashtable()
Dim obj = New Hashtable From {{New Byte() {1, 2}, {1, 2, 3}}}
Dim str = VisualBasicObjectFormatter.Instance.FormatObject(obj, s_memberList)
Dim str = Formatter.SeparateLines.FormatObject(obj)
AssertMembers(str, "Hashtable(1)", "{ Byte(2) { 1, 2 }, Integer(3) { 1, 2, 3 } }")
End Sub
......@@ -30,7 +30,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting.UnitTests
obj.Enqueue(2)
obj.Enqueue(3)
Dim str = VisualBasicObjectFormatter.Instance.FormatObject(obj, s_inline)
Dim str = Formatter.SingleLine.FormatObject(obj)
Assert.Equal("Queue(3) { 1, 2, 3 }", str)
End Sub
......@@ -41,7 +41,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting.UnitTests
obj.Push(2)
obj.Push(3)
Dim str = VisualBasicObjectFormatter.Instance.FormatObject(obj, s_inline)
Dim str = Formatter.SingleLine.FormatObject(obj)
Assert.Equal("Stack(3) { 3, 2, 1 }", str)
End Sub
......@@ -52,12 +52,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting.UnitTests
obj.Add(1, 5)
obj.Add(2, 6)
Dim str = VisualBasicObjectFormatter.Instance.FormatObject(obj, s_inline)
Dim str = Formatter.SingleLine.FormatObject(obj)
Assert.Equal("SortedList(3) { { 1, 5 }, { 2, 6 }, { 3, 4 } }", str)
obj = New SortedList()
obj.Add({3}, New Integer() {4})
str = VisualBasicObjectFormatter.Instance.FormatObject(obj, s_inline)
str = Formatter.SingleLine.FormatObject(obj)
Assert.Equal("SortedList(1) { { Integer(1) { 3 }, Integer(1) { 4 } } }", str)
End Sub
End Class
......
......@@ -4,6 +4,7 @@ Imports Microsoft.CodeAnalysis.Scripting.Hosting
Imports Microsoft.CodeAnalysis.Scripting.Hosting.UnitTests
Imports ObjectFormatterFixtures
Imports Xunit
Imports Formatter = Microsoft.CodeAnalysis.Scripting.Hosting.UnitTests.TestVisualBasicObjectFormatter
Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting.UnitTests
......@@ -12,17 +13,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting.UnitTests
<Fact()>
Public Sub InlineCharacters()
Assert.Equal("ChrW(20)", VisualBasicObjectFormatter.Instance.FormatObject(ChrW(20), s_inline))
Assert.Equal("vbBack", VisualBasicObjectFormatter.Instance.FormatObject(ChrW(&H8), s_inline))
Assert.Equal("ChrW(20)", Formatter.SingleLine.FormatObject(ChrW(20)))
Assert.Equal("vbBack", Formatter.SingleLine.FormatObject(ChrW(&H8)))
End Sub
<Fact(Skip:="IDK")>
Public Sub QuotedStrings()
Dim s = "a" & ChrW(&HFFFE) & ChrW(&HFFFF) & vbCrLf & "b"
Dim withQuotes = New Formatter(useHexadecimalNumbers:=True, omitStringQuotes:=False)
Dim withoutQuotes = New Formatter(useHexadecimalNumbers:=True, omitStringQuotes:=True)
' ObjectFormatter should substitute spaces for non-printable characters
Assert.Equal("""a"" & ChrW(&HABCF) & ChrW(&HABCD) & vbCrLf & ""b""", VisualBasicObjectFormatter.Instance.FormatObject(s, s_hexa.Copy(quoteStrings:=True)))
Assert.Equal("a b", VisualBasicObjectFormatter.Instance.FormatObject(s, s_hexa.Copy(quoteStrings:=False)))
Assert.Equal("""a"" & ChrW(&HABCF) & ChrW(&HABCD) & vbCrLf & ""b""", withQuotes.FormatObject(s))
Assert.Equal("a b", withoutQuotes.FormatObject(s))
End Sub
<Fact>
......@@ -30,41 +34,41 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting.UnitTests
Dim str As String
Dim nested As Object = New Outer.Nested(Of Integer)()
str = VisualBasicObjectFormatter.Instance.FormatObject(nested, s_inline)
str = Formatter.SingleLine.FormatObject(nested)
Assert.Equal("Outer.Nested(Of Integer) { A=1, B=2 }", str)
str = VisualBasicObjectFormatter.Instance.FormatObject(nested, New ObjectFormattingOptions(memberFormat:=MemberDisplayFormat.NoMembers))
str = Formatter.Hidden.FormatObject(nested)
Assert.Equal("Outer.Nested(Of Integer)", str)
str = VisualBasicObjectFormatter.Instance.FormatObject(A(Of Integer).X, New ObjectFormattingOptions(memberFormat:=MemberDisplayFormat.NoMembers))
str = Formatter.Hidden.FormatObject(A(Of Integer).X)
Assert.Equal("A(Of Integer).B(Of Integer)", str)
Dim obj As Object = New A(Of Integer).B(Of Boolean).C.D(Of String, Double).E()
str = VisualBasicObjectFormatter.Instance.FormatObject(obj, New ObjectFormattingOptions(memberFormat:=MemberDisplayFormat.NoMembers))
str = Formatter.Hidden.FormatObject(obj)
Assert.Equal("A(Of Integer).B(Of Boolean).C.D(Of String, Double).E", str)
Dim sort = New Sort()
str = VisualBasicObjectFormatter.Instance.FormatObject(sort, New ObjectFormattingOptions(maxLineLength:=51, memberFormat:=MemberDisplayFormat.Inline))
str = New Formatter(MemberDisplayFormat.SingleLine, lineLengthLimit:=51).FormatObject(sort)
Assert.Equal("Sort { aB=-1, ab=1, Ac=-1, Ad=1, ad=-1, aE=1, a ...", str)
Assert.Equal(51, str.Length)
str = VisualBasicObjectFormatter.Instance.FormatObject(sort, New ObjectFormattingOptions(maxLineLength:=5, memberFormat:=MemberDisplayFormat.Inline))
str = New Formatter(MemberDisplayFormat.SingleLine, lineLengthLimit:=5).FormatObject(sort)
Assert.Equal("S ...", str)
Assert.Equal(5, str.Length)
str = VisualBasicObjectFormatter.Instance.FormatObject(sort, New ObjectFormattingOptions(maxLineLength:=4, memberFormat:=MemberDisplayFormat.Inline))
str = New Formatter(MemberDisplayFormat.SingleLine, lineLengthLimit:=4).FormatObject(sort)
Assert.Equal("...", str)
str = VisualBasicObjectFormatter.Instance.FormatObject(sort, New ObjectFormattingOptions(maxLineLength:=3, memberFormat:=MemberDisplayFormat.Inline))
str = New Formatter(MemberDisplayFormat.SingleLine, lineLengthLimit:=3).FormatObject(sort)
Assert.Equal("...", str)
str = VisualBasicObjectFormatter.Instance.FormatObject(sort, New ObjectFormattingOptions(maxLineLength:=2, memberFormat:=MemberDisplayFormat.Inline))
str = New Formatter(MemberDisplayFormat.SingleLine, lineLengthLimit:=2).FormatObject(sort)
Assert.Equal("...", str)
str = VisualBasicObjectFormatter.Instance.FormatObject(sort, New ObjectFormattingOptions(maxLineLength:=1, memberFormat:=MemberDisplayFormat.Inline))
str = New Formatter(MemberDisplayFormat.SingleLine, lineLengthLimit:=1).FormatObject(sort)
Assert.Equal("...", str)
str = VisualBasicObjectFormatter.Instance.FormatObject(sort, New ObjectFormattingOptions(maxLineLength:=80, memberFormat:=MemberDisplayFormat.Inline))
str = New Formatter(MemberDisplayFormat.SingleLine, lineLengthLimit:=80).FormatObject(sort)
Assert.Equal("Sort { aB=-1, ab=1, Ac=-1, Ad=1, ad=-1, aE=1, aF=-1, AG=1 }", str)
End Sub
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册