diff --git a/VSRAD.Package/BuildTools/Errors/Parser.cs b/VSRAD.Package/BuildTools/Errors/Parser.cs index ab2290307..87c2977a8 100644 --- a/VSRAD.Package/BuildTools/Errors/Parser.cs +++ b/VSRAD.Package/BuildTools/Errors/Parser.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; +using System.Linq; using static VSRAD.BuildTools.IPCBuildResult; namespace VSRAD.Package.BuildTools.Errors @@ -15,21 +16,17 @@ public static ICollection ParseStderr(IEnumerable outputs) { using (var reader = new StringReader(output)) { - Message lastMessage = null; - string line; while ((line = reader.ReadLine()) != null) { - var message = ParseScriptMessage(line) ?? ParseKeywordMessage(line) ?? ParseClangMessage(line); + var message = + ParseAsmMessage(line) ?? + ParseScriptMessage(line) ?? + ParseClangMessage(line); if (message != null) - { - lastMessage = message; messages.Add(message); - } - else if (lastMessage != null) - { - lastMessage.Text += Environment.NewLine + line; - } + else if (messages.Count > 0) + messages.Last().Text += Environment.NewLine + line; } } } @@ -53,51 +50,53 @@ private static Message ParseClangMessage(string header) }; } - private static readonly Regex ScriptErrorRegex = new Regex( + private static readonly Regex AsmErrorRegex = new Regex( @"\*(?[EW]),(?[^:(]+)(?>\s\((?.+):(?\d+)\))?:\s(?.+)", RegexOptions.Compiled); - private static readonly Regex ScriptErrorLocationInTextRegex = new Regex( - @"(?.+)\s\((?.+):(?\d+)\)", RegexOptions.Compiled); - - private static Message ParseScriptMessage(string header) + private static Message ParseAsmMessage(string header) { - var match = ScriptErrorRegex.Match(header); + var match = AsmErrorRegex.Match(header); if (!match.Success) return null; var code = match.Groups["code"].Value; var textAndMaybeLocation = match.Groups["text"].Value; - var message = new Message { Kind = ParseMessageKind(match.Groups["kind"].Value) }; - - if (!match.Groups["file"].Success) - match = ScriptErrorLocationInTextRegex.Match(textAndMaybeLocation); + var kind = ParseMessageKind(match.Groups["kind"].Value); if (match.Success) { - message.SourceFile = match.Groups["file"].Value; - message.Line = int.Parse(match.Groups["line"].Value); + var source = match.Groups["file"].Success + ? match.Groups["file"].Value.Trim() + : ""; + var line = match.Groups["line"].Success + ? int.Parse(match.Groups["line"].Value) + : 0; + return new Message { + Kind = kind, + SourceFile = source, + Line = line, + Text = code + ": " + match.Groups["text"].Value + }; + } + else + { + return new Message { Kind = kind, Text = code + ": " + textAndMaybeLocation }; } - - message.Text = code + ": " + (match.Success ? match.Groups["text"].Value : textAndMaybeLocation); - - return message; } - private static readonly Regex KeywordErrorRegex = new Regex( + private static readonly Regex ScriptErrorRegex = new Regex( @"(?ERROR|WARNING):\s*(?.+)", RegexOptions.Compiled); - private static Message ParseKeywordMessage(string header) + private static Message ParseScriptMessage(string header) { - var match = KeywordErrorRegex.Match(header); + var match = ScriptErrorRegex.Match(header); if (!match.Success) return null; - var message = new Message + return new Message { Kind = ParseMessageKind(match.Groups["kind"].Value), Text = match.Groups["text"].Value }; - - return message; } private static MessageKind ParseMessageKind(string kind) diff --git a/VSRAD.PackageTests/BuildTools/Errors/ParserTests.cs b/VSRAD.PackageTests/BuildTools/Errors/ParserTests.cs index 7113d69bd..16415fa58 100644 --- a/VSRAD.PackageTests/BuildTools/Errors/ParserTests.cs +++ b/VSRAD.PackageTests/BuildTools/Errors/ParserTests.cs @@ -18,11 +18,9 @@ public class ParserTests printf(""h""); ^ C:\Absolute\Path\host.c:4:2: note: include the header or explicitly provide a declaration for 'printf' - input.s:16:10: fatal error: 'abcde.s' file not found #include ""abcde.s"" - ^~~~~~~~~ -"; + ^~~~~~~~~"; public static readonly Message[] ClangExpectedMessages = new Message[] { @@ -39,7 +37,7 @@ public class ParserTests printf(""h""); ^"}, new Message { Kind = MessageKind.Note, Line = 4, Column = 2, SourceFile = @"C:\Absolute\Path\host.c", Text = - "include the header or explicitly provide a declaration for 'printf'\r\n" }, + "include the header or explicitly provide a declaration for 'printf'" }, new Message { Kind = MessageKind.Error, Line = 16, Column = 10, SourceFile = "input.s", Text = @"'abcde.s' file not found #include ""abcde.s"" @@ -53,43 +51,39 @@ public void ClangErrorTest() Assert.Equal(ClangExpectedMessages, messages); } - public const string ScriptStderr = @" -*E,fatal: undefined reference to 'printf' (:3) -*E,fatal: undefined reference to 'printf' (C:\Absolute\Path\source.c:3) -*W,undefined: 1 undefined references found + public const string AsmStderr = +@"*W,undefined: 1 undefined references found *E,syntax error (:12): at symbol 'printf' parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM did you really mean to use the scope resolution op here? *E,fatal (C:\Absolute\Path\source.c:35): Uncaught error: Undefined variable: user -"; +*W,undefined: undefined reference to 'printf'"; - public static readonly Message[] ScriptExpectedMessages = new Message[] + public static readonly Message[] AsmExpectedMessages = new Message[] { - new Message { Kind = MessageKind.Error, Line = 3, SourceFile = "", Text = "fatal: undefined reference to 'printf'"}, - new Message { Kind = MessageKind.Error, Line = 3, SourceFile = @"C:\Absolute\Path\source.c", Text = "fatal: undefined reference to 'printf'"}, new Message { Kind = MessageKind.Warning, Line = 0, SourceFile = "", Text = "undefined: 1 undefined references found" }, new Message { Kind = MessageKind.Error, Line = 12, SourceFile = "", Text = @"syntax error: at symbol 'printf' parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM did you really mean to use the scope resolution op here?" }, - new Message { Kind = MessageKind.Error, Line = 35, SourceFile = @"C:\Absolute\Path\source.c", Text = "fatal: Uncaught error: Undefined variable: user" } + new Message { Kind = MessageKind.Error, Line = 35, SourceFile = @"C:\Absolute\Path\source.c", Text = "fatal: Uncaught error: Undefined variable: user" }, + new Message { Kind = MessageKind.Warning, Line = 0, SourceFile = "", Text = "undefined: undefined reference to 'printf'" } }; [Fact] - public void ScriptErrorTest() + public void AsmErrorTest() { - var messages = ParseStderr(new string[] { ScriptStderr }).ToArray(); - Assert.Equal(ScriptExpectedMessages, messages); + var messages = ParseStderr(new string[] { AsmStderr }).ToArray(); + Assert.Equal(AsmExpectedMessages, messages); } - public const string KeywordStderr = @" -*E,fatal: undefined reference to 'printf' (:3) + public const string ScriptStderr = +@"*E,fatal (:3): undefined reference to 'printf' ERROR: check if app exists and can be executed 'C:\NEVER\GONNA\GIVE\YOU\UP.exe' WARNING: you are incredibly beautiful! -*E,fatal (auth.c:35): Uncaught error: Undefined variable: user -"; +*E,fatal (auth.c:35): Uncaught error: Undefined variable: user"; - public static readonly Message[] KeywordErrorExpectedMessages = new Message[] + public static readonly Message[] ScriptErrorExpectedMessages = new Message[] { new Message { Kind = MessageKind.Error, Line = 3, SourceFile = "", Text = "fatal: undefined reference to 'printf'" }, new Message { Kind = MessageKind.Error, Line = 0, SourceFile = "", Text = @"check if app exists and can be executed 'C:\NEVER\GONNA\GIVE\YOU\UP.exe'" }, @@ -98,18 +92,18 @@ public void ScriptErrorTest() }; [Fact] - public void KeywordErrorTest() + public void ScriptErrorTest() { - var messages = ParseStderr(new string[] { KeywordStderr }).ToArray(); - Assert.Equal(KeywordErrorExpectedMessages, messages); + var messages = ParseStderr(new string[] { ScriptStderr }).ToArray(); + Assert.Equal(ScriptErrorExpectedMessages, messages); } [Fact] public void MixedErrorFormatsTest() { - var expectedMessages = ClangExpectedMessages.Concat(KeywordErrorExpectedMessages).Concat(ScriptExpectedMessages).ToArray(); + var expectedMessages = ClangExpectedMessages.Concat(ScriptErrorExpectedMessages).Concat(AsmExpectedMessages).ToArray(); - var separateOutputs = new[] { ClangStderr, KeywordStderr, ScriptStderr }; + var separateOutputs = new[] { ClangStderr, ScriptStderr, AsmStderr }; var separateOutputsMessages = ParseStderr(separateOutputs).ToArray(); Assert.Equal(expectedMessages, separateOutputsMessages);