|
4 | 4 | using System.Runtime.CompilerServices;
|
5 | 5 | using System.Runtime.InteropServices;
|
6 | 6 | using System.Text;
|
7 |
| -using System.Text.RegularExpressions; |
8 | 7 | using ComputeSharp.D2D1.Exceptions;
|
9 | 8 | using ComputeSharp.D2D1.Extensions;
|
10 | 9 | using TerraFX.Interop.DirectX;
|
@@ -191,16 +190,46 @@ private static void ThrowHslsCompilationException(ID3DBlob* d3DOperationResult)
|
191 | 190 | // The error message will be in a format like this:
|
192 | 191 | // "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\Roslyn\Shader@0x0000019AD1B4BA70(22,32-35): error X3004: undeclared identifier 'this'"
|
193 | 192 | // This regex tries to match the unnecessary header and remove it, if present. This doesn't need to be bulletproof, and this regex should match all cases anyway.
|
194 |
| - message = Regex.Replace(message, @"^[A-Z]:\\[^:]+: (\w+ \w+:)", static m => m.Groups[1].Value, RegexOptions.Multiline).Trim(); |
| 193 | + // |
| 194 | + // We cannot use Regex (this method was originally using Regex.Replace(message, @"^[A-Z]:\\[^:]+: (\w+ \w+:)", ...)), because that |
| 195 | + // causes significant binary size increase, as it's the only thing rooting all the Regex stack across the whole library. So this |
| 196 | + // code reimplements equivalent logic in a simple way. Because this is a throw helper, allocating a little bit of garbage is fine. |
| 197 | + string[] lines = message.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); |
| 198 | + |
| 199 | + // Go over each (non empty) line and look for the leading file path to trim away |
| 200 | + foreach (ref string line in lines.AsSpan()) |
| 201 | + { |
| 202 | + ReadOnlySpan<char> span = line.AsSpan().Trim(); |
| 203 | + |
| 204 | + // Check whether the trimmed line starts with a drive letter path (eg. 'C:\') and get the rest |
| 205 | + if (span is [>= 'A' and <= 'Z', ':', '\\', .. { Length: > 0 } tail]) |
| 206 | + { |
| 207 | + int indexOfColon = tail.IndexOf(':'); |
| 208 | + |
| 209 | + // We're looking for the color at the end of the file path. If we find it, and the line |
| 210 | + // has at least another character (ie. there's content after that, which should always |
| 211 | + // be the case), then we take that slice, trim its start to skip the leading whitespace, |
| 212 | + // and finally allocate a string to replace the current line. |
| 213 | + if (indexOfColon != -1 && |
| 214 | + tail.Length > indexOfColon) |
| 215 | + { |
| 216 | + ReadOnlySpan<char> trimmedLine = tail.Slice(indexOfColon + 1).TrimStart(); |
| 217 | + |
| 218 | + line = trimmedLine.ToString(); |
| 219 | + } |
| 220 | + } |
| 221 | + } |
| 222 | + |
| 223 | + // Merge the message again with normalized newlines |
| 224 | + string updatedMessage = string.Join("\r\n", lines); |
195 | 225 |
|
196 | 226 | // Add a trailing '.' if not present
|
197 |
| - if (message is { Length: > 0 } && |
198 |
| - message[message.Length - 1] != '.') |
| 227 | + if (updatedMessage is not [.., '.']) |
199 | 228 | {
|
200 |
| - message += '.'; |
| 229 | + updatedMessage += '.'; |
201 | 230 | }
|
202 | 231 |
|
203 |
| - throw new FxcCompilationException(message); |
| 232 | + throw new FxcCompilationException(updatedMessage); |
204 | 233 | }
|
205 | 234 |
|
206 | 235 | /// <summary>
|
|
0 commit comments