130 lines
4.1 KiB
C#
130 lines
4.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text.RegularExpressions;
|
|
using UnityEditor.Compilation;
|
|
|
|
namespace io.github.hatayama.uLoopMCP
|
|
{
|
|
internal static class ExternalCompilerMessageParser
|
|
{
|
|
private static readonly Regex DiagnosticRegex = new(
|
|
@"^(?<file>.+)\((?<line>\d+),(?<column>\d+)\): (?<severity>error|warning) (?<code>[A-Z]+\d+): (?<message>.+)$",
|
|
RegexOptions.Compiled);
|
|
|
|
public static CompilerMessage[] Parse(
|
|
string stdout,
|
|
string stderr,
|
|
int exitCode)
|
|
{
|
|
List<CompilerMessage> messages = new List<CompilerMessage>();
|
|
AddParsedMessages(messages, stdout);
|
|
AddParsedMessages(messages, stderr);
|
|
|
|
if (messages.Count > 0)
|
|
{
|
|
if (exitCode != 0 && !HasError(messages))
|
|
{
|
|
messages.Add(CreateInfrastructureFailureMessage(stdout, stderr, exitCode));
|
|
}
|
|
|
|
return messages.ToArray();
|
|
}
|
|
|
|
if (exitCode == 0)
|
|
{
|
|
return Array.Empty<CompilerMessage>();
|
|
}
|
|
|
|
string combinedOutput = CombineOutput(stdout, stderr);
|
|
return new CompilerMessage[]
|
|
{
|
|
new CompilerMessage
|
|
{
|
|
type = CompilerMessageType.Error,
|
|
message = string.IsNullOrWhiteSpace(combinedOutput)
|
|
? "External C# compiler failed without diagnostics"
|
|
: combinedOutput
|
|
}
|
|
};
|
|
}
|
|
|
|
private static bool HasError(IReadOnlyCollection<CompilerMessage> messages)
|
|
{
|
|
foreach (CompilerMessage message in messages)
|
|
{
|
|
if (message.type == CompilerMessageType.Error)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static CompilerMessage CreateInfrastructureFailureMessage(
|
|
string stdout,
|
|
string stderr,
|
|
int exitCode)
|
|
{
|
|
string combinedOutput = CombineOutput(stdout, stderr);
|
|
string message = $"External C# compiler exited with code {exitCode} without reporting an error diagnostic";
|
|
if (!string.IsNullOrWhiteSpace(combinedOutput))
|
|
{
|
|
message = $"{message}: {combinedOutput}";
|
|
}
|
|
|
|
return new CompilerMessage
|
|
{
|
|
type = CompilerMessageType.Error,
|
|
message = message
|
|
};
|
|
}
|
|
|
|
private static void AddParsedMessages(
|
|
List<CompilerMessage> messages,
|
|
string output)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(output))
|
|
{
|
|
return;
|
|
}
|
|
|
|
string[] lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
|
foreach (string line in lines)
|
|
{
|
|
Match match = DiagnosticRegex.Match(line.Trim());
|
|
if (!match.Success)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
messages.Add(new CompilerMessage
|
|
{
|
|
type = match.Groups["severity"].Value == "warning"
|
|
? CompilerMessageType.Warning
|
|
: CompilerMessageType.Error,
|
|
message = $"{match.Groups["code"].Value}: {match.Groups["message"].Value}",
|
|
file = match.Groups["file"].Value,
|
|
line = int.Parse(match.Groups["line"].Value),
|
|
column = int.Parse(match.Groups["column"].Value)
|
|
});
|
|
}
|
|
}
|
|
|
|
private static string CombineOutput(string stdout, string stderr)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(stdout))
|
|
{
|
|
return stderr?.Trim();
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(stderr))
|
|
{
|
|
return stdout.Trim();
|
|
}
|
|
|
|
return $"{stdout.Trim()}\n{stderr.Trim()}";
|
|
}
|
|
}
|
|
}
|