summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/visual-studio/slang-test/slang-test.vcxproj2
-rw-r--r--build/visual-studio/slang-test/slang-test.vcxproj.filters6
-rw-r--r--source/core/slang-string-util.cpp6
-rw-r--r--source/core/slang-type-text-util.cpp30
-rw-r--r--source/core/slang-type-text-util.h2
-rw-r--r--source/slang/core.meta.slang11
-rw-r--r--tests/diagnostics/syntax-error-intrinsic.slang20
-rw-r--r--tests/diagnostics/syntax-error-intrinsic.slang.1.expected1
-rw-r--r--tests/diagnostics/syntax-error-intrinsic.slang.2.expected1
-rw-r--r--tests/diagnostics/syntax-error-intrinsic.slang.3.expected1
-rw-r--r--tests/diagnostics/syntax-error-intrinsic.slang.4.expected1
-rw-r--r--tests/diagnostics/syntax-error-intrinsic.slang.expected1
-rw-r--r--tools/slang-test/parse-diagnostic-util.cpp324
-rw-r--r--tools/slang-test/parse-diagnostic-util.h30
-rw-r--r--tools/slang-test/slang-test-main.cpp83
15 files changed, 505 insertions, 14 deletions
diff --git a/build/visual-studio/slang-test/slang-test.vcxproj b/build/visual-studio/slang-test/slang-test.vcxproj
index 1626b6cca..27c64c7cb 100644
--- a/build/visual-studio/slang-test/slang-test.vcxproj
+++ b/build/visual-studio/slang-test/slang-test.vcxproj
@@ -164,6 +164,7 @@
<ItemGroup>
<ClInclude Include="..\..\..\tools\slang-test\directory-util.h" />
<ClInclude Include="..\..\..\tools\slang-test\options.h" />
+ <ClInclude Include="..\..\..\tools\slang-test\parse-diagnostic-util.h" />
<ClInclude Include="..\..\..\tools\slang-test\slangc-tool.h" />
<ClInclude Include="..\..\..\tools\slang-test\test-context.h" />
<ClInclude Include="..\..\..\tools\slang-test\test-reporter.h" />
@@ -171,6 +172,7 @@
<ItemGroup>
<ClCompile Include="..\..\..\tools\slang-test\directory-util.cpp" />
<ClCompile Include="..\..\..\tools\slang-test\options.cpp" />
+ <ClCompile Include="..\..\..\tools\slang-test\parse-diagnostic-util.cpp" />
<ClCompile Include="..\..\..\tools\slang-test\slang-test-main.cpp" />
<ClCompile Include="..\..\..\tools\slang-test\slangc-tool.cpp" />
<ClCompile Include="..\..\..\tools\slang-test\test-context.cpp" />
diff --git a/build/visual-studio/slang-test/slang-test.vcxproj.filters b/build/visual-studio/slang-test/slang-test.vcxproj.filters
index 8718a4d86..41a6237ba 100644
--- a/build/visual-studio/slang-test/slang-test.vcxproj.filters
+++ b/build/visual-studio/slang-test/slang-test.vcxproj.filters
@@ -15,6 +15,9 @@
<ClInclude Include="..\..\..\tools\slang-test\options.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\..\..\tools\slang-test\parse-diagnostic-util.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="..\..\..\tools\slang-test\slangc-tool.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -32,6 +35,9 @@
<ClCompile Include="..\..\..\tools\slang-test\options.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\..\..\tools\slang-test\parse-diagnostic-util.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\..\..\tools\slang-test\slang-test-main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/source/core/slang-string-util.cpp b/source/core/slang-string-util.cpp
index 326bc3191..a859c6945 100644
--- a/source/core/slang-string-util.cpp
+++ b/source/core/slang-string-util.cpp
@@ -32,9 +32,9 @@ namespace Slang {
return areAllEqual(slicesA, slicesB, equalFn);
}
-/* static */void StringUtil::split(const UnownedStringSlice& in, char splitChar, List<UnownedStringSlice>& slicesOut)
+/* static */void StringUtil::split(const UnownedStringSlice& in, char splitChar, List<UnownedStringSlice>& outSlices)
{
- slicesOut.clear();
+ outSlices.clear();
const char* start = in.begin();
const char* end = in.end();
@@ -49,7 +49,7 @@ namespace Slang {
}
// Add to output
- slicesOut.add(UnownedStringSlice(start, cur));
+ outSlices.add(UnownedStringSlice(start, cur));
// Skip the split character, if at end we are okay anyway
start = cur + 1;
diff --git a/source/core/slang-type-text-util.cpp b/source/core/slang-type-text-util.cpp
index 80ef0027f..89cd4504b 100644
--- a/source/core/slang-type-text-util.cpp
+++ b/source/core/slang-type-text-util.cpp
@@ -128,22 +128,34 @@ static const ArchiveTypeInfo s_archiveTypeInfos[] =
return slang::TypeReflection::ScalarType::None;
}
+#define SLANG_PASS_THROUGH_HUMAN_TEXT(x) \
+ x(NONE, "Unknown") \
+ x(VISUAL_STUDIO, "Visual Studio") \
+ x(GCC, "GCC") \
+ x(CLANG, "Clang") \
+ x(NVRTC, "NVRTC") \
+ x(FXC, "fxc") \
+ x(DXC, "dxc") \
+ x(GLSLANG, "glslang")
+
/* static */UnownedStringSlice TypeTextUtil::getPassThroughAsHumanText(SlangPassThrough type)
{
+#define SLANG_PASS_THROUGH_HUMAN_CASE(value, text) case SLANG_PASS_THROUGH_##value: return UnownedStringSlice::fromLiteral(text);
+
switch (type)
{
- default:
- case SLANG_PASS_THROUGH_NONE: return UnownedStringSlice::fromLiteral("Unknown");
- case SLANG_PASS_THROUGH_VISUAL_STUDIO: return UnownedStringSlice::fromLiteral("Visual Studio");
- case SLANG_PASS_THROUGH_GCC: return UnownedStringSlice::fromLiteral("GCC");
- case SLANG_PASS_THROUGH_CLANG: return UnownedStringSlice::fromLiteral("Clang");
- case SLANG_PASS_THROUGH_NVRTC: return UnownedStringSlice::fromLiteral("NVRTC");
- case SLANG_PASS_THROUGH_FXC: return UnownedStringSlice::fromLiteral("fxc");
- case SLANG_PASS_THROUGH_DXC: return UnownedStringSlice::fromLiteral("dxc");
- case SLANG_PASS_THROUGH_GLSLANG: return UnownedStringSlice::fromLiteral("glslang");
+ default: /* fall-through to none */
+ SLANG_PASS_THROUGH_HUMAN_TEXT(SLANG_PASS_THROUGH_HUMAN_CASE)
}
}
+/* static */SlangResult TypeTextUtil::findPassThroughFromHumanText(const UnownedStringSlice& inText, SlangPassThrough& outPassThrough)
+{
+ #define SLANG_PASS_THROUGH_HUMAN_IF(value, text) if (inText == UnownedStringSlice::fromLiteral(text)) { outPassThrough = SLANG_PASS_THROUGH_##value; return SLANG_OK; } else
+ SLANG_PASS_THROUGH_HUMAN_TEXT(SLANG_PASS_THROUGH_HUMAN_IF)
+ return SLANG_FAIL;
+}
+
/* static */SlangSourceLanguage TypeTextUtil::findSourceLanguage(const UnownedStringSlice& text)
{
if (text == "c" || text == "C")
diff --git a/source/core/slang-type-text-util.h b/source/core/slang-type-text-util.h
index 07426246e..f5534ec72 100644
--- a/source/core/slang-type-text-util.h
+++ b/source/core/slang-type-text-util.h
@@ -20,6 +20,8 @@ struct TypeTextUtil
/// As human readable text
static UnownedStringSlice getPassThroughAsHumanText(SlangPassThrough type);
+ /// Gets pass through from human text (as from getPassThroughAsHumanText)
+ static SlangResult findPassThroughFromHumanText(const UnownedStringSlice& text, SlangPassThrough& outPassThrough);
/// Given a source language name returns a source language. Name here is distinct from extension
static SlangSourceLanguage findSourceLanguage(const UnownedStringSlice& text);
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index 9fecc7661..a60da422c 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -1914,12 +1914,19 @@ ${{{{
}}}}
-
// Specialized function
__intrinsic_op
int getStringHash(String string);
+// Use will produce a syntax error in downstream compiler
+// Useful for testing diagnostics around compilation errors of downstream compiler
+__target_intrinsic(hlsl, " @ ")
+__target_intrinsic(glsl, " @ ")
+__target_intrinsic(cuda, " @ ")
+__target_intrinsic(cpp, " @ ")
+void __SyntaxError();
+
// Operators to apply to `enum` types
__generic<E : __EnumType>
@@ -2084,4 +2091,4 @@ __attributeTarget(DeclBase)
attribute_syntax [__requiresNVAPI] : RequiresNVAPIAttribute;
__attributeTarget(FunctionDeclBase)
-attribute_syntax [noinline] : NoInlineAttribute; \ No newline at end of file
+attribute_syntax [noinline] : NoInlineAttribute;
diff --git a/tests/diagnostics/syntax-error-intrinsic.slang b/tests/diagnostics/syntax-error-intrinsic.slang
new file mode 100644
index 000000000..dde54b2ad
--- /dev/null
+++ b/tests/diagnostics/syntax-error-intrinsic.slang
@@ -0,0 +1,20 @@
+// syntax-error-intrinsic.slang
+
+// NOTE! That although this is a 'diagnostic' like test, it tests using downstream compiler
+// the downstream compiler being present is a requirement, so we mark as a 'TEST' so that
+// those tests are made.
+
+//TEST:SIMPLE_LINE:-entry computeMain -target spirv
+//TEST:SIMPLE_LINE:-entry computeMain -target dxil -profile cs_6_0
+//TEST:SIMPLE_LINE:-entry computeMain -target dxbc
+//TEST:SIMPLE_LINE:-entry computeMain -target dll
+//TEST:SIMPLE_LINE:-entry computeMain -target ptx
+
+[shader("compute")]
+[numthreads(4, 1, 1)]
+void computeMain()
+{
+ // Will output what downstream compilers will output as a syntax
+ // error.
+ __SyntaxError();
+} \ No newline at end of file
diff --git a/tests/diagnostics/syntax-error-intrinsic.slang.1.expected b/tests/diagnostics/syntax-error-intrinsic.slang.1.expected
new file mode 100644
index 000000000..3c032078a
--- /dev/null
+++ b/tests/diagnostics/syntax-error-intrinsic.slang.1.expected
@@ -0,0 +1 @@
+18
diff --git a/tests/diagnostics/syntax-error-intrinsic.slang.2.expected b/tests/diagnostics/syntax-error-intrinsic.slang.2.expected
new file mode 100644
index 000000000..3c032078a
--- /dev/null
+++ b/tests/diagnostics/syntax-error-intrinsic.slang.2.expected
@@ -0,0 +1 @@
+18
diff --git a/tests/diagnostics/syntax-error-intrinsic.slang.3.expected b/tests/diagnostics/syntax-error-intrinsic.slang.3.expected
new file mode 100644
index 000000000..98d9bcb75
--- /dev/null
+++ b/tests/diagnostics/syntax-error-intrinsic.slang.3.expected
@@ -0,0 +1 @@
+17
diff --git a/tests/diagnostics/syntax-error-intrinsic.slang.4.expected b/tests/diagnostics/syntax-error-intrinsic.slang.4.expected
new file mode 100644
index 000000000..98d9bcb75
--- /dev/null
+++ b/tests/diagnostics/syntax-error-intrinsic.slang.4.expected
@@ -0,0 +1 @@
+17
diff --git a/tests/diagnostics/syntax-error-intrinsic.slang.expected b/tests/diagnostics/syntax-error-intrinsic.slang.expected
new file mode 100644
index 000000000..98d9bcb75
--- /dev/null
+++ b/tests/diagnostics/syntax-error-intrinsic.slang.expected
@@ -0,0 +1 @@
+17
diff --git a/tools/slang-test/parse-diagnostic-util.cpp b/tools/slang-test/parse-diagnostic-util.cpp
new file mode 100644
index 000000000..af2ef2a05
--- /dev/null
+++ b/tools/slang-test/parse-diagnostic-util.cpp
@@ -0,0 +1,324 @@
+// parse-diagnostic-util.cpp
+
+#include "parse-diagnostic-util.h"
+
+#include "../../source/core/slang-hex-dump-util.h"
+#include "../../source/core/slang-type-text-util.h"
+
+#include "../../slang-com-helper.h"
+
+#include "../../source/core/slang-string-util.h"
+#include "../../source/core/slang-byte-encode-util.h"
+#include "../../source/core/slang-char-util.h"
+
+#include "../../source/core/slang-downstream-compiler.h"
+
+using namespace Slang;
+
+/* static */SlangResult ParseDiagnosticUtil::splitPathLocation(const UnownedStringSlice& pathLocation, DownstreamDiagnostic& outDiagnostic)
+{
+ const Index lineStartIndex = pathLocation.lastIndexOf('(');
+ if (lineStartIndex >= 0)
+ {
+ outDiagnostic.filePath = UnownedStringSlice(pathLocation.head(lineStartIndex).trim());
+
+ const UnownedStringSlice tail = pathLocation.tail(lineStartIndex + 1);
+ const Index lineEndIndex = tail.indexOf(')');
+
+ if (lineEndIndex >= 0)
+ {
+ // Extract the location info
+ UnownedStringSlice locationSlice(tail.begin(), tail.begin() + lineEndIndex);
+ List<UnownedStringSlice> locationSlices;
+ StringUtil::split(locationSlice, ',', locationSlices);
+
+ Int locationLine = 0;
+ Int locationCol = 0;
+
+ SLANG_RETURN_ON_FAIL(StringUtil::parseInt(locationSlices[0], locationLine));
+ if (locationSlices.getCount() > 1)
+ {
+ SLANG_RETURN_ON_FAIL(StringUtil::parseInt(locationSlices[1], locationCol));
+ }
+
+ outDiagnostic.fileLine = locationLine;
+ }
+ }
+ else
+ {
+ outDiagnostic.filePath = pathLocation;
+ }
+ return SLANG_OK;
+}
+
+/* static */SlangResult ParseDiagnosticUtil::parseFXCLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic)
+{
+ SLANG_RETURN_ON_FAIL(splitPathLocation(lineSlices[1], outDiagnostic));
+
+ if (lineSlices.getCount() > 2)
+ {
+ UnownedStringSlice errorSlice = lineSlices[2].trim();
+ Index spaceIndex = errorSlice.indexOf(' ');
+ if (spaceIndex >= 0)
+ {
+ UnownedStringSlice diagnosticType = errorSlice.head(spaceIndex);
+ UnownedStringSlice code = errorSlice.tail(spaceIndex + 1).trim();
+
+ if (diagnosticType == "warning")
+ {
+ outDiagnostic.type = DownstreamDiagnostic::Type::Warning;
+ }
+
+ outDiagnostic.code = code;
+ }
+ else
+ {
+ outDiagnostic.code = errorSlice;
+ }
+
+ if (lineSlices.getCount() > 3)
+ {
+ outDiagnostic.text = UnownedStringSlice(lineSlices[3].begin(), line.end());
+ }
+ }
+
+ return SLANG_OK;
+}
+
+/* static */SlangResult ParseDiagnosticUtil::parseDXCLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic)
+{
+ /* dxc: tests/diagnostics/syntax-error-intrinsic.slang:14:2: error: expected expression */
+
+ outDiagnostic.filePath = lineSlices[1];
+
+ SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[2], outDiagnostic.fileLine));
+
+ Int lineCol;
+ SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[3], lineCol));
+
+ UnownedStringSlice typeSlice = lineSlices[4].trim();
+
+ if (typeSlice == UnownedStringSlice::fromLiteral("warning"))
+ {
+ outDiagnostic.type = DownstreamDiagnostic::Type::Warning;
+ }
+
+ // The rest of the line
+ outDiagnostic.text = UnownedStringSlice(lineSlices[5].begin(), line.end());
+ return SLANG_OK;
+}
+
+/* static */ SlangResult ParseDiagnosticUtil::parseGlslangLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic)
+{
+ if (lineSlices.getCount() < 5)
+ {
+ return SLANG_FAIL;
+ }
+
+ /* glslang: ERROR: tests/diagnostics/syntax-error-intrinsic.slang:13: '@' : unexpected token
+ */
+
+ UnownedStringSlice typeSlice = lineSlices[1].trim();
+ if (typeSlice.caseInsensitiveEquals(UnownedStringSlice::fromLiteral("warning")))
+ {
+ outDiagnostic.type = DownstreamDiagnostic::Type::Warning;
+ }
+
+ outDiagnostic.filePath = lineSlices[2];
+
+ SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[3], outDiagnostic.fileLine));
+ outDiagnostic.text = UnownedStringSlice(lineSlices[4].begin(), line.end());
+ return SLANG_OK;
+}
+
+/* static */SlangResult ParseDiagnosticUtil::parseGenericLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic)
+{
+ /* Visual Studio 14.0: e:\git\somewhere\tests\diagnostics\syntax-error-intrinsic.slang(13): error C2018: unknown character '0x40' */
+
+ UnownedStringSlice errorSlice = lineSlices[2].trim();
+ UnownedStringSlice typeSlice = StringUtil::getAtInSplit(errorSlice, ' ', 0);
+ if (typeSlice == UnownedStringSlice::fromLiteral("warning"))
+ {
+ outDiagnostic.type = DownstreamDiagnostic::Type::Warning;
+ }
+ else if (typeSlice == UnownedStringSlice::fromLiteral("info"))
+ {
+ outDiagnostic.type = DownstreamDiagnostic::Type::Info;
+ }
+
+ // Get the code
+ outDiagnostic.code = StringUtil::getAtInSplit(errorSlice, ' ', 1);
+
+ // Get the location info
+ SLANG_RETURN_ON_FAIL(splitPathLocation(lineSlices[1], outDiagnostic));
+
+ outDiagnostic.text = UnownedStringSlice(lineSlices[3].begin(), line.end());
+
+ return SLANG_OK;
+}
+
+/* static */ SlangResult ParseDiagnosticUtil::splitCompilerDiagnosticLine(SlangPassThrough downstreamCompiler, const UnownedStringSlice& line, UnownedStringSlice& linePrefix, List<UnownedStringSlice>& outSlices)
+{
+ /*
+ glslang: ERROR: tests/diagnostics/syntax-error-intrinsic.slang:13: '@' : unexpected token
+ dxc: tests/diagnostics/syntax-error-intrinsic.slang:14:2: error: expected expression
+ fxc: tests/diagnostics/syntax-error-intrinsic.slang(14,2): error X3000: syntax error: unexpected token '@'
+ Visual Studio 14.0: e:\git\somewhere\tests\diagnostics\syntax-error-intrinsic.slang(13): error C2018: unknown character '0x40'
+ NVRTC 11.0: tests/diagnostics/syntax-error-intrinsic.slang(13): error : unrecognized token
+ */
+
+ Int pathIndex = 1;
+
+ StringUtil::split(line, ':', outSlices);
+
+ if (downstreamCompiler == SLANG_PASS_THROUGH_GLSLANG)
+ {
+ // If we don't have the prefix then add it
+ if (!outSlices[0].trim().startsWith(linePrefix))
+ {
+ outSlices.insert(0, linePrefix);
+ }
+ pathIndex = 2;
+ }
+
+ // Make sure this seems plausible
+ if (outSlices.getCount() > pathIndex + 1)
+ {
+ UnownedStringSlice pathStart = outSlices[pathIndex].trim();
+
+ if (pathStart.getLength() == 1 && CharUtil::isAlpha(pathStart[0]))
+ {
+ // Splice back together
+ outSlices[pathIndex] = UnownedStringSlice(outSlices[pathIndex].begin(), outSlices[pathIndex + 1].end());
+ outSlices.removeAt(pathIndex + 1);
+ }
+ }
+
+ return SLANG_OK;
+}
+
+static void _addDiagnosticNote(const UnownedStringSlice& in, List<DownstreamDiagnostic>& outDiagnostics)
+{
+ // Don't bother adding an empty line
+ if (in.trim().getLength() == 0)
+ {
+ return;
+ }
+
+ // Make it a note on the output
+ DownstreamDiagnostic diagnostic;
+ diagnostic.reset();
+ diagnostic.type = DownstreamDiagnostic::Type::Info;
+ diagnostic.text = in;
+ outDiagnostics.add(diagnostic);
+}
+
+static SlangResult _findDownstreamCompiler(const UnownedStringSlice& slice, SlangPassThrough& outDownstreamCompiler)
+{
+ for (Index i = SLANG_PASS_THROUGH_NONE + 1; i < SLANG_PASS_THROUGH_COUNT_OF; ++i)
+ {
+ const SlangPassThrough downstreamCompiler = SlangPassThrough(i);
+ UnownedStringSlice name = TypeTextUtil::getPassThroughAsHumanText(downstreamCompiler);
+
+ if (slice.startsWith(name))
+ {
+ outDownstreamCompiler = downstreamCompiler;
+ return SLANG_OK;
+ }
+ }
+ return SLANG_FAIL;
+}
+
+/* static */SlangResult ParseDiagnosticUtil::parseDiagnostics(const UnownedStringSlice& inText, List<DownstreamDiagnostic>& outDiagnostics)
+{
+ // TODO(JS):
+ // As it stands output of downstream compilers isn't standardized. This should be improved upon, and perhaps
+ // we should have a function that will parse the standardized output
+ // Currently dxc/fxc/glslang, use a different downstream path
+
+ // We look for the first l
+
+ SlangPassThrough downstreamCompiler = SLANG_PASS_THROUGH_NONE;
+ UnownedStringSlice linePrefix;
+
+ List<UnownedStringSlice> splitLine;
+
+ UnownedStringSlice text(inText), line;
+ while (StringUtil::extractLine(text, line))
+ {
+ UnownedStringSlice initial = StringUtil::getAtInSplit(line, ':', 0);
+
+ if (downstreamCompiler == SLANG_PASS_THROUGH_NONE)
+ {
+ // First entry that begins with a numeral indicates the version number
+ if (SLANG_FAILED(_findDownstreamCompiler(initial, downstreamCompiler)))
+ {
+ continue;
+ }
+
+ linePrefix = TypeTextUtil::getPassThroughAsHumanText(downstreamCompiler);
+ }
+
+ if (line.indexOf(':') < 0 )
+ {
+ _addDiagnosticNote(line, outDiagnostics);
+ continue;
+ }
+
+ if (SLANG_FAILED(splitCompilerDiagnosticLine(downstreamCompiler, line, linePrefix, splitLine)))
+ {
+ _addDiagnosticNote(line, outDiagnostics);
+ continue;
+ }
+
+ // If doesn't have prefix, just add as note
+ if (!splitLine[0].trim().startsWith(linePrefix))
+ {
+ _addDiagnosticNote(line, outDiagnostics);
+ continue;
+ }
+
+ DownstreamDiagnostic diagnostic;
+ diagnostic.type = DownstreamDiagnostic::Type::Error;
+ diagnostic.stage = DownstreamDiagnostic::Stage::Compile;
+ diagnostic.fileLine = 0;
+
+ SlangResult parseRes;
+
+ switch (downstreamCompiler)
+ {
+ case SLANG_PASS_THROUGH_FXC:
+ {
+ parseRes = parseFXCLine(line, splitLine, diagnostic);
+ break;
+ }
+ case SLANG_PASS_THROUGH_DXC:
+ {
+ parseRes = parseDXCLine(line, splitLine, diagnostic);
+ break;
+ }
+ case SLANG_PASS_THROUGH_GLSLANG:
+ {
+ parseRes = parseGlslangLine(line, splitLine, diagnostic);
+ break;
+ }
+ default:
+ {
+ parseRes = parseGenericLine(line, splitLine, diagnostic);
+ break;
+ }
+ }
+
+ // If couldn't parse, just add as a note
+ if (SLANG_FAILED(parseRes))
+ {
+ _addDiagnosticNote(line, outDiagnostics);
+ }
+ else
+ {
+ outDiagnostics.add(diagnostic);
+ }
+ }
+
+ return SLANG_OK;
+}
diff --git a/tools/slang-test/parse-diagnostic-util.h b/tools/slang-test/parse-diagnostic-util.h
new file mode 100644
index 000000000..26349b779
--- /dev/null
+++ b/tools/slang-test/parse-diagnostic-util.h
@@ -0,0 +1,30 @@
+// parse-diagnostic-util.h
+
+#ifndef PARSE_DIAGNOSTIC_UTIL_H
+#define PARSE_DIAGNOSTIC_UTIL_H
+
+#include "../../source/core/slang-string-util.h"
+#include "../../source/core/slang-downstream-compiler.h"
+#include "../../source/core/slang-string.h"
+
+#include "../../slang-com-ptr.h"
+
+struct ParseDiagnosticUtil
+{
+ static SlangResult splitPathLocation(const Slang::UnownedStringSlice& pathLocation, Slang::DownstreamDiagnostic& outDiagnostic);
+
+ static SlangResult parseFXCLine(const Slang::UnownedStringSlice& line, Slang::List<Slang::UnownedStringSlice>& lineSlices, Slang::DownstreamDiagnostic& outDiagnostic);
+
+ static SlangResult parseDXCLine(const Slang::UnownedStringSlice& line, Slang::List<Slang::UnownedStringSlice>& lineSlices, Slang::DownstreamDiagnostic& outDiagnostic);
+
+ static SlangResult parseGlslangLine(const Slang::UnownedStringSlice& line, Slang::List<Slang::UnownedStringSlice>& lineSlices, Slang::DownstreamDiagnostic& outDiagnostic);
+
+ static SlangResult parseGenericLine(const Slang::UnownedStringSlice& line, Slang::List<Slang::UnownedStringSlice>& lineSlices, Slang::DownstreamDiagnostic& outDiagnostic);
+
+ static SlangResult splitCompilerDiagnosticLine(SlangPassThrough downstreamCompiler, const Slang::UnownedStringSlice& line, Slang::UnownedStringSlice& linePrefix, Slang::List<Slang::UnownedStringSlice>& outSlices);
+
+ static SlangResult parseDiagnostics(const Slang::UnownedStringSlice& inText, Slang::List<Slang::DownstreamDiagnostic>& outDiagnostics);
+
+};
+
+#endif // PARSE_DIAGNOSTIC_UTIL_H
diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp
index 3a15c6e61..fcb609c34 100644
--- a/tools/slang-test/slang-test-main.cpp
+++ b/tools/slang-test/slang-test-main.cpp
@@ -10,6 +10,7 @@
#include "../../source/core/slang-string-util.h"
#include "../../source/core/slang-byte-encode-util.h"
+#include "../../source/core/slang-char-util.h"
using namespace Slang;
@@ -19,6 +20,7 @@ using namespace Slang;
#include "test-reporter.h"
#include "options.h"
#include "slangc-tool.h"
+#include "parse-diagnostic-util.h"
#include "../../source/core/slang-downstream-compiler.h"
@@ -1244,6 +1246,86 @@ TestResult runSimpleTest(TestContext* context, TestInput& input)
return result;
}
+TestResult runSimpleLineTest(TestContext* context, TestInput& input)
+{
+ // need to execute the stand-alone Slang compiler on the file, and compare its output to what we expect
+ auto outputStem = input.outputStem;
+
+ CommandLine cmdLine;
+ _initSlangCompiler(context, cmdLine);
+
+ cmdLine.addArg(input.filePath);
+
+ for (auto arg : input.testOptions->args)
+ {
+ cmdLine.addArg(arg);
+ }
+
+ ExecuteResult exeRes;
+ TEST_RETURN_ON_DONE(spawnAndWait(context, outputStem, input.spawnType, cmdLine, exeRes));
+
+ if (context->isCollectingRequirements())
+ {
+ return TestResult::Pass;
+ }
+
+ // Parse all the diagnostics so we can extract line numbers
+ List<DownstreamDiagnostic> diagnostics;
+ if (SLANG_FAILED(ParseDiagnosticUtil::parseDiagnostics(exeRes.standardError.getUnownedSlice(), diagnostics)) || diagnostics.getCount() <= 0)
+ {
+ // Write out the diagnostics which couldn't be parsed.
+
+ String actualOutputPath = outputStem + ".actual";
+ Slang::File::writeAllText(actualOutputPath, exeRes.standardError);
+
+ return TestResult::Fail;
+ }
+
+ StringBuilder actualOutput;
+
+ if (diagnostics.getCount() > 0)
+ {
+ actualOutput << diagnostics[0].fileLine << "\n";
+ }
+ else
+ {
+ actualOutput << "No output diagnostics\n";
+ }
+
+
+ String expectedOutputPath = outputStem + ".expected";
+ String expectedOutput;
+ try
+ {
+ expectedOutput = Slang::File::readAllText(expectedOutputPath);
+ }
+ catch (const Slang::IOException&)
+ {
+ }
+
+ TestResult result = TestResult::Pass;
+
+ // Otherwise we compare to the expected output
+ if (!_areResultsEqual(input.testOptions->type, expectedOutput, actualOutput))
+ {
+ context->reporter->dumpOutputDifference(expectedOutput, actualOutput);
+ result = TestResult::Fail;
+ }
+
+ // If the test failed, then we write the actual output to a file
+ // so that we can easily diff it from the command line and
+ // diagnose the problem.
+ if (result == TestResult::Fail)
+ {
+ String actualOutputPath = outputStem + ".actual";
+ Slang::File::writeAllText(actualOutputPath, actualOutput);
+
+ context->reporter->dumpOutputDifference(expectedOutput, actualOutput);
+ }
+
+ return result;
+}
+
TestResult runCompile(TestContext* context, TestInput& input)
{
auto outputStem = input.outputStem;
@@ -2688,6 +2770,7 @@ static const TestCommandInfo s_testCommandInfos[] =
{
{ "SIMPLE", &runSimpleTest, 0 },
{ "SIMPLE_EX", &runSimpleTest, 0 },
+ { "SIMPLE_LINE", &runSimpleLineTest, 0 },
{ "REFLECTION", &runReflectionTest, 0 },
{ "CPU_REFLECTION", &runReflectionTest, 0 },
{ "COMMAND_LINE_SIMPLE", &runSimpleCompareCommandLineTest, 0 },