forked from microsoft/qsharp-compiler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Utils.cs
126 lines (106 loc) · 5.72 KB
/
Utils.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Quantum.QsCompiler;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Newtonsoft.Json.Linq;
namespace Microsoft.Quantum.QsLanguageServer
{
public static class Utils
{
// language server tools -
// wrapping these into a try .. catch .. to make sure errors don't go unnoticed as they otherwise would
public static T TryJTokenAs<T>(JToken arg) where T : class =>
QsCompilerError.RaiseOnFailure(() =>
arg == null ? throw new ArgumentNullException(nameof(arg)) : arg.ToObject<T>(), "could not cast given JToken");
private static ShowMessageParams AsMessageParams(string text, MessageType severity) =>
text == null ? null : new ShowMessageParams { Message = text, MessageType = severity };
/// <summary>
/// Shows the given text in the editor.
/// Throws an ArgumentNullException if either the server or the text to display is null.
/// </summary>
internal static void ShowInWindow(this QsLanguageServer server, string text, MessageType severity)
{
var message = AsMessageParams(text, severity);
QsCompilerError.Verify(server != null && message != null, "cannot show message - given server or text was null");
if (server == null) throw new ArgumentNullException(nameof(server));
if (message == null) throw new ArgumentNullException(nameof(message));
_ = server.NotifyClientAsync(Methods.WindowShowMessageName, message);
}
/// <summary>
/// Logs the given text in the editor.
/// Throws an ArgumentNullException if either the server or the text to display is null.
/// </summary>
internal static void LogToWindow(this QsLanguageServer server, string text, MessageType severity)
{
var message = AsMessageParams(text, severity);
QsCompilerError.Verify(server != null && message != null, "cannot log message - given server or text was null");
if (server == null) throw new ArgumentNullException(nameof(server));
if (message == null) throw new ArgumentNullException(nameof(message));
_ = server.NotifyClientAsync(Methods.WindowLogMessageName, message);
}
// tools related to project loading and file watching
/// <summary>
/// Attempts to apply the given mapper to each element in the given sequence.
/// Returns a new sequence consisting of all mapped elements for which the mapping succeeded as out parameter,
/// as well as a bool indicating whether the mapping succeeded for all elements.
/// The returned out parameter is non-null even if the mapping failed on some elements.
/// </summary>
internal static bool TryEnumerate<TSource, TResult>(this IEnumerable<TSource> source,
Func<TSource, TResult> mapper, out ImmutableArray<TResult> mapped)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (mapper == null) throw new ArgumentNullException(nameof(mapper));
var succeeded = true;
var enumerator = source.GetEnumerator();
T Try<T>(Func<T> getRes, T fallback)
{
try { return getRes(); }
catch { succeeded = false; return fallback; }
}
bool TryMoveNext() => Try(enumerator.MoveNext, false);
(bool, TResult) ApplyToCurrent() => Try(() => (true, mapper(enumerator.Current)), (false, default(TResult)));
var values = ImmutableArray.CreateBuilder<TResult>();
while (TryMoveNext())
{
var evaluated = ApplyToCurrent();
if (evaluated.Item1) values.Add(evaluated.Item2);
};
mapped = values.ToImmutable();
return succeeded;
}
/// <summary>
/// Attempts to enumerate the given sequence.
/// Returns a new sequence consisting of all elements which could be accessed,
/// as well as a bool indicating whether the enumeration succeeded for all elements.
/// The returned out parameter is non-null even if access failed on some elements.
/// </summary>
internal static bool TryEnumerate<TSource>(this IEnumerable<TSource> source, out ImmutableArray<TSource> enumerated) =>
source.TryEnumerate(element => element, out enumerated);
/// <summary>
/// The given log function is applied to all errors and warning
/// raised by the ms build routine an instance of this class is given to.
/// </summary>
internal class MSBuildLogger : Logger
{
private readonly Action<string, MessageType> logToWindow;
internal MSBuildLogger(Action<string, MessageType> logToWindow) =>
this.logToWindow = logToWindow;
public override void Initialize(IEventSource eventSource)
{
eventSource.ErrorRaised += (sender, args) =>
this.logToWindow?.Invoke(
$"MSBuild error in {args.File}({args.LineNumber},{args.ColumnNumber}): {args.Message}",
MessageType.Error);
eventSource.WarningRaised += (sender, args) =>
this.logToWindow?.Invoke(
$"MSBuild warning in {args.File}({args.LineNumber},{args.ColumnNumber}): {args.Message}",
MessageType.Warning);
}
}
}
}