diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2021-02-03 16:31:58 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-03 16:31:58 -0500 |
| commit | 4c66c17b2e5572c95da260ea4761f5804eb52853 (patch) | |
| tree | 198a2f7aeffb17d3a87fbe6223e1d8df32287562 /tools/slang-test/parse-diagnostic-util.cpp | |
| parent | a1d543d9b1bf3b2bcd813a498d2d3e24de67106d (diff) | |
Diagnostic comparison using parsing (#1683)
* #include an absolute path didn't work - because paths were taken to always be relative.
* WIP diagnostics for line number output.
* Small param naming change
* Use x macro for pass through compile human name lookup/getting.
* WIP on parsing downstream compiler output.
* Split out parsing into ParseDiagnosticUtil.
Added test result of single line.
* Dump out the std output on fail to parse diagnostics.
* Change test type for syntax-error-intrinsic.slang be TEST not TEST_DIAGNOSTIC
* Use Index for StringUtil.
* WIP: First pass support for parsing Slang diagnostics.
* WIP Testing comparing with ParseDiagnosticUtil with previous ad-hoc mechanism.
* Use the new parsing mechanism for diagnostic comparisons.
* Improvements to diagnostics parsing.
Better error handling, and fallback handling.
Added ability to parse downstream compilers without a prefix.
Added ability to parse Slang with a prefix.
Diffstat (limited to 'tools/slang-test/parse-diagnostic-util.cpp')
| -rw-r--r-- | tools/slang-test/parse-diagnostic-util.cpp | 529 |
1 files changed, 406 insertions, 123 deletions
diff --git a/tools/slang-test/parse-diagnostic-util.cpp b/tools/slang-test/parse-diagnostic-util.cpp index af2ef2a05..6d5a64cce 100644 --- a/tools/slang-test/parse-diagnostic-util.cpp +++ b/tools/slang-test/parse-diagnostic-util.cpp @@ -26,22 +26,21 @@ using namespace Slang; 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; + UnownedStringSlice slices[2]; + const Index numSlices = StringUtil::split(locationSlice, ',', 2, slices); + Int locationIndex[2] = { 0, 0 }; - SLANG_RETURN_ON_FAIL(StringUtil::parseInt(locationSlices[0], locationLine)); - if (locationSlices.getCount() > 1) + for (Index i = 0; i < numSlices; ++i) { - SLANG_RETURN_ON_FAIL(StringUtil::parseInt(locationSlices[1], locationCol)); + SLANG_RETURN_ON_FAIL(StringUtil::parseInt(slices[i], locationIndex[i])); } - outDiagnostic.fileLine = locationLine; + // Store the line + outDiagnostic.fileLine = locationIndex[0]; } } else @@ -53,139 +52,235 @@ using namespace Slang; /* static */SlangResult ParseDiagnosticUtil::parseFXCLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic) { - SLANG_RETURN_ON_FAIL(splitPathLocation(lineSlices[1], outDiagnostic)); - - if (lineSlices.getCount() > 2) + /* tests/diagnostics/syntax-error-intrinsic.slang(14,2): error X3000: syntax error: unexpected token '@' */ + if (lineSlices.getCount() < 3) { - UnownedStringSlice errorSlice = lineSlices[2].trim(); - Index spaceIndex = errorSlice.indexOf(' '); - if (spaceIndex >= 0) - { - UnownedStringSlice diagnosticType = errorSlice.head(spaceIndex); - UnownedStringSlice code = errorSlice.tail(spaceIndex + 1).trim(); + return SLANG_FAIL; + } - if (diagnosticType == "warning") - { - outDiagnostic.type = DownstreamDiagnostic::Type::Warning; - } + SLANG_RETURN_ON_FAIL(splitPathLocation(lineSlices[0], outDiagnostic)); - outDiagnostic.code = code; - } - else - { - outDiagnostic.code = errorSlice; - } + { + const UnownedStringSlice errorSlice = lineSlices[1].trim(); + + const UnownedStringSlice errorTypeName = StringUtil::getAtInSplit(errorSlice, ' ', 0); + outDiagnostic.code = StringUtil::getAtInSplit(errorSlice, ' ', 1); - if (lineSlices.getCount() > 3) + outDiagnostic.type = DownstreamDiagnostic::Type::Error; + if (errorTypeName == "warning") { - outDiagnostic.text = UnownedStringSlice(lineSlices[3].begin(), line.end()); + outDiagnostic.type = DownstreamDiagnostic::Type::Warning; } } + outDiagnostic.text = UnownedStringSlice(lineSlices[2].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 */ + /* tests/diagnostics/syntax-error-intrinsic.slang:14:2: error: expected expression */ + if (lineSlices.getCount() < 5) + { + return SLANG_FAIL; + } - outDiagnostic.filePath = lineSlices[1]; + outDiagnostic.filePath = lineSlices[0]; - SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[2], outDiagnostic.fileLine)); + SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[1], outDiagnostic.fileLine)); Int lineCol; - SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[3], lineCol)); + SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[2], lineCol)); - UnownedStringSlice typeSlice = lineSlices[4].trim(); + UnownedStringSlice typeSlice = lineSlices[3].trim(); + outDiagnostic.type = DownstreamDiagnostic::Type::Error; if (typeSlice == UnownedStringSlice::fromLiteral("warning")) { outDiagnostic.type = DownstreamDiagnostic::Type::Warning; } // The rest of the line - outDiagnostic.text = UnownedStringSlice(lineSlices[5].begin(), line.end()); + outDiagnostic.text = UnownedStringSlice(lineSlices[4].begin(), line.end()); return SLANG_OK; } /* static */ SlangResult ParseDiagnosticUtil::parseGlslangLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic) { - if (lineSlices.getCount() < 5) + /* ERROR: tests/diagnostics/syntax-error-intrinsic.slang:13: '@' : unexpected token */ + + if (lineSlices.getCount() < 4) { return SLANG_FAIL; } + { + const UnownedStringSlice typeSlice = lineSlices[0].trim(); - /* glslang: ERROR: tests/diagnostics/syntax-error-intrinsic.slang:13: '@' : unexpected token - */ + outDiagnostic.type = DownstreamDiagnostic::Type::Error; + if (typeSlice.caseInsensitiveEquals(UnownedStringSlice::fromLiteral("warning"))) + { + outDiagnostic.type = DownstreamDiagnostic::Type::Warning; + } + } + + outDiagnostic.filePath = lineSlices[1]; - UnownedStringSlice typeSlice = lineSlices[1].trim(); - if (typeSlice.caseInsensitiveEquals(UnownedStringSlice::fromLiteral("warning"))) + SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[2], outDiagnostic.fileLine)); + outDiagnostic.text = UnownedStringSlice(lineSlices[3].begin(), line.end()); + return SLANG_OK; +} + +/* static */SlangResult ParseDiagnosticUtil::parseGenericLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic) +{ + /* e:\git\somewhere\tests\diagnostics\syntax-error-intrinsic.slang(13): error C2018: unknown character '0x40' */ + if (lineSlices.getCount() < 3) { - outDiagnostic.type = DownstreamDiagnostic::Type::Warning; + return SLANG_FAIL; + } + + { + const UnownedStringSlice errorSlice = lineSlices[1].trim(); + // Get the code + outDiagnostic.code = StringUtil::getAtInSplit(errorSlice, ' ', 1).trim(); + + const UnownedStringSlice typeSlice = StringUtil::getAtInSplit(errorSlice, ' ', 0); + + outDiagnostic.type = DownstreamDiagnostic::Type::Error; + if (typeSlice == UnownedStringSlice::fromLiteral("warning")) + { + outDiagnostic.type = DownstreamDiagnostic::Type::Warning; + } + else if (typeSlice == UnownedStringSlice::fromLiteral("info")) + { + outDiagnostic.type = DownstreamDiagnostic::Type::Info; + } } - outDiagnostic.filePath = lineSlices[2]; + // Get the location info + SLANG_RETURN_ON_FAIL(splitPathLocation(lineSlices[0], outDiagnostic)); - SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[3], outDiagnostic.fileLine)); - outDiagnostic.text = UnownedStringSlice(lineSlices[4].begin(), line.end()); + outDiagnostic.text = UnownedStringSlice(lineSlices[2].begin(), line.end()); return SLANG_OK; } -/* static */SlangResult ParseDiagnosticUtil::parseGenericLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic) +static SlangResult _getSlangDiagnosticType(const UnownedStringSlice& inText, DownstreamDiagnostic::Type& outType, Int& outCode) { - /* Visual Studio 14.0: e:\git\somewhere\tests\diagnostics\syntax-error-intrinsic.slang(13): error C2018: unknown character '0x40' */ + UnownedStringSlice text(inText.trim()); - UnownedStringSlice errorSlice = lineSlices[2].trim(); - UnownedStringSlice typeSlice = StringUtil::getAtInSplit(errorSlice, ' ', 0); - if (typeSlice == UnownedStringSlice::fromLiteral("warning")) + static const UnownedStringSlice prefixes[] = { - outDiagnostic.type = DownstreamDiagnostic::Type::Warning; + UnownedStringSlice::fromLiteral("note"), + UnownedStringSlice::fromLiteral("warning"), + UnownedStringSlice::fromLiteral("error"), + UnownedStringSlice::fromLiteral("fatal error"), + UnownedStringSlice::fromLiteral("internal error"), + UnownedStringSlice::fromLiteral("unknown error") + }; + + Int index = -1; + + for (Index i = 0; i < SLANG_COUNT_OF(prefixes); ++i) + { + const auto& prefix = prefixes[i]; + if (text.startsWith(prefix)) + { + index = i; + break; + } } - else if (typeSlice == UnownedStringSlice::fromLiteral("info")) + + switch (index) { - outDiagnostic.type = DownstreamDiagnostic::Type::Info; + case -1: return SLANG_FAIL; + case 0: outType = DownstreamDiagnostic::Type::Info; break; + case 1: outType = DownstreamDiagnostic::Type::Warning; break; + default: outType = DownstreamDiagnostic::Type::Error; break; } - // Get the code - outDiagnostic.code = StringUtil::getAtInSplit(errorSlice, ' ', 1); + outCode = 0; - // Get the location info - SLANG_RETURN_ON_FAIL(splitPathLocation(lineSlices[1], outDiagnostic)); + UnownedStringSlice tail = text.tail(prefixes[index].getLength()).trim(); + if (tail.getLength() > 0) + { + SLANG_RETURN_ON_FAIL(StringUtil::parseInt(tail, outCode)); + } - outDiagnostic.text = UnownedStringSlice(lineSlices[3].begin(), line.end()); + return SLANG_OK; +} + +static bool _isSlangDiagnostic(const UnownedStringSlice& line) +{ + /* + tests/diagnostics/accessors.slang(11): error 31101: accessors other than 'set' must not have parameters + */ + + UnownedStringSlice initial = StringUtil::getAtInSplit(line, ':', 0); + + // Handle if path has : + const Index typeIndex = (initial.getLength() == 1 && CharUtil::isAlpha(initial[0])) ? 2 : 1; + // Extract the type/code slice + UnownedStringSlice typeSlice = StringUtil::getAtInSplit(line, ':', typeIndex); + + DownstreamDiagnostic::Type type; + Int code; + return SLANG_SUCCEEDED(_getSlangDiagnosticType(typeSlice, type, code)); +} + +/* static */SlangResult ParseDiagnosticUtil::parseSlangLine(const UnownedStringSlice& line, List<UnownedStringSlice>& lineSlices, DownstreamDiagnostic& outDiagnostic) +{ + /* + tests/diagnostics/accessors.slang(11): error 31101: accessors other than 'set' must not have parameters + */ + + // Can be larger than 3, because might be : in the actual error text + if (lineSlices.getCount() < 3) + { + return SLANG_FAIL; + } + SLANG_RETURN_ON_FAIL(splitPathLocation(lineSlices[0], outDiagnostic)); + Int code; + SLANG_RETURN_ON_FAIL(_getSlangDiagnosticType(lineSlices[1], outDiagnostic.type, code)); + + if (code != 0) + { + StringBuilder buf; + buf << code; + outDiagnostic.code = buf.ProduceString(); + } + + outDiagnostic.text = UnownedStringSlice(lineSlices[2].begin(), line.end()); return SLANG_OK; } -/* static */ SlangResult ParseDiagnosticUtil::splitCompilerDiagnosticLine(SlangPassThrough downstreamCompiler, const UnownedStringSlice& line, UnownedStringSlice& linePrefix, List<UnownedStringSlice>& outSlices) +/* static */ SlangResult ParseDiagnosticUtil::splitDiagnosticLine(const CompilerIdentity& compilerIdentity, const UnownedStringSlice& line, const UnownedStringSlice& linePrefix, List<UnownedStringSlice>& outSlices) { + StringUtil::split(line, ':', outSlices); + + // If we have a prefix (typically identifying the compiler), remove so same code can be used for output with prefixes and without + if (linePrefix.getLength()) + { + SLANG_ASSERT(outSlices[0].startsWith(linePrefix)); + outSlices.removeAt(0); + } + /* 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 + tests/diagnostics/accessors.slang(11): error 31101: accessors other than 'set' must not have parameters */ - 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; - } + // Need to determine where the path is located, and that depends on the compiler + const Int pathIndex = (compilerIdentity == CompilerIdentity::make(SLANG_PASS_THROUGH_GLSLANG)) ? 1 : 0; - // Make sure this seems plausible + // Now we want to fix up a path as might have drive letter, and therefore : + // If this is the situation then we need to have a slice after the one at the index if (outSlices.getCount() > pathIndex + 1) { - UnownedStringSlice pathStart = outSlices[pathIndex].trim(); - + const UnownedStringSlice pathStart = outSlices[pathIndex].trim(); if (pathStart.getLength() == 1 && CharUtil::isAlpha(pathStart[0])) { // Splice back together @@ -205,6 +300,13 @@ static void _addDiagnosticNote(const UnownedStringSlice& in, List<DownstreamDiag return; } + // If there's nothing previous, we'll ignore too, as note should be in addition to + // a pre-existing error/warning + if (outDiagnostics.getCount() == 0) + { + return; + } + // Make it a note on the output DownstreamDiagnostic diagnostic; diagnostic.reset(); @@ -229,50 +331,113 @@ static SlangResult _findDownstreamCompiler(const UnownedStringSlice& slice, Slan return SLANG_FAIL; } +/* static */SlangResult ParseDiagnosticUtil::identifyCompiler(const UnownedStringSlice& inText, CompilerIdentity& outIdentity) +{ + outIdentity = CompilerIdentity(); + + // This might be overkill - we should be able to identify the compiler from the first line, of the diagnostics. + // Here, we go through each line trying to identify the compiler. + // For downstream compilers, the only way to identify unambiguously is via the compiler name prefix. + // For Slang we *assume* if there isn't such a prefix, and it 'looks like' a Slang diagnostic that it is + + UnownedStringSlice text(inText), line; + while (StringUtil::extractLine(text, line)) + { + UnownedStringSlice initial = StringUtil::getAtInSplit(line, ':', 0); + + if (_isSlangDiagnostic(line)) + { + outIdentity = CompilerIdentity::makeSlang(); + return SLANG_OK; + } + else + { + SlangPassThrough downstreamCompiler; + // First entry that begins with a numeral indicates the version number + if (SLANG_SUCCEEDED(_findDownstreamCompiler(initial, downstreamCompiler))) + { + outIdentity = CompilerIdentity::make(downstreamCompiler); + return SLANG_OK; + } + } + } + + return SLANG_FAIL; +} + +/* static */ParseDiagnosticUtil::LineParser ParseDiagnosticUtil::getLineParser(const CompilerIdentity& compilerIdentity) +{ + if (compilerIdentity.m_type == CompilerIdentity::Slang) + { + return &parseSlangLine; + } + else if (compilerIdentity.m_type == CompilerIdentity::DownstreamCompiler) + { + switch (compilerIdentity.m_downstreamCompiler) + { + case SLANG_PASS_THROUGH_FXC: return &parseFXCLine; + case SLANG_PASS_THROUGH_DXC: return &parseDXCLine; + case SLANG_PASS_THROUGH_GLSLANG: return &parseGlslangLine; + default: return &parseGenericLine; + } + } + return nullptr; +} + /* 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 + // As it stands output of downstream compilers isn't standardized. This can be improved upon - and if so // 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 + CompilerIdentity compilerIdentity; + SLANG_RETURN_ON_FAIL(ParseDiagnosticUtil::identifyCompiler(inText, compilerIdentity)); - SlangPassThrough downstreamCompiler = SLANG_PASS_THROUGH_NONE; UnownedStringSlice linePrefix; + if (compilerIdentity.m_type == CompilerIdentity::Type::DownstreamCompiler) + { + linePrefix = TypeTextUtil::getPassThroughAsHumanText(compilerIdentity.m_downstreamCompiler); + } + else + { + // For Slang there isn't *currently* a prefix ever used, but that might change in the future + // For now we assume no prefix. + } + + return parseDiagnostics(inText, compilerIdentity, linePrefix, outDiagnostics); +} + +/* static */SlangResult ParseDiagnosticUtil::parseDiagnostics(const UnownedStringSlice& inText, const CompilerIdentity& compilerIdentity, const UnownedStringSlice& linePrefix, List<DownstreamDiagnostic>& outDiagnostics) +{ + auto lineParser = getLineParser(compilerIdentity); + if (!lineParser) + { + return SLANG_FAIL; + } + List<UnownedStringSlice> splitLine; UnownedStringSlice text(inText), line; while (StringUtil::extractLine(text, line)) { - UnownedStringSlice initial = StringUtil::getAtInSplit(line, ':', 0); - - if (downstreamCompiler == SLANG_PASS_THROUGH_NONE) + bool isValidSplit = false; + // And the first entry must contain the prefix, else assume it's a note + if (linePrefix.getLength() > 0 && line.startsWith(linePrefix)) { - // First entry that begins with a numeral indicates the version number - if (SLANG_FAILED(_findDownstreamCompiler(initial, downstreamCompiler))) - { - continue; - } - - linePrefix = TypeTextUtil::getPassThroughAsHumanText(downstreamCompiler); + // Try with the line prefix + isValidSplit = SLANG_SUCCEEDED(splitDiagnosticLine(compilerIdentity, line, linePrefix, splitLine)); } - if (line.indexOf(':') < 0 ) + if (!isValidSplit) { - _addDiagnosticNote(line, outDiagnostics); - continue; - } - - if (SLANG_FAILED(splitCompilerDiagnosticLine(downstreamCompiler, line, linePrefix, splitLine))) - { - _addDiagnosticNote(line, outDiagnostics); - continue; + // Try without the prefix, as some output output's only some lines with the prefix (GLSL for example) + isValidSplit = SLANG_SUCCEEDED(splitDiagnosticLine(compilerIdentity, line, UnownedStringSlice(), splitLine)); } - // If doesn't have prefix, just add as note - if (!splitLine[0].trim().startsWith(linePrefix)) + // If we don't have a valid split then just assume it's a note + if (!isValidSplit) { _addDiagnosticNote(line, outDiagnostics); continue; @@ -283,42 +448,160 @@ static SlangResult _findDownstreamCompiler(const UnownedStringSlice& slice, Slan diagnostic.stage = DownstreamDiagnostic::Stage::Compile; diagnostic.fileLine = 0; - SlangResult parseRes; + if (SLANG_SUCCEEDED(lineParser(line, splitLine, diagnostic))) + { + outDiagnostics.add(diagnostic); + } + else + { + // If couldn't parse, just add as a note + _addDiagnosticNote(line, outDiagnostics); + } + } + + return SLANG_OK; +} + +static UnownedStringSlice _getEquals(const UnownedStringSlice& in) +{ + Index equalsIndex = in.indexOf('='); + if (equalsIndex < 0) + { + return UnownedStringSlice(); + } + return in.tail(equalsIndex + 1).trim(); +} + +/* static */SlangResult ParseDiagnosticUtil::parseOutputInfo(const UnownedStringSlice& inText, OutputInfo& out) +{ + enum State + { + Normal, + InStdError, + InStdOut, + }; + + UnownedStringSlice resultCodePrefix = UnownedStringSlice::fromLiteral("result code"); + UnownedStringSlice stdErrorPrefix = UnownedStringSlice::fromLiteral("standard error"); + UnownedStringSlice stdOutputPrefix = UnownedStringSlice::fromLiteral("standard output"); + + + List<UnownedStringSlice> lines; - switch (downstreamCompiler) + State state = State::Normal; + + UnownedStringSlice text(inText), line; + while (StringUtil::extractLine(text, line)) + { + switch (state) { - case SLANG_PASS_THROUGH_FXC: + case State::Normal: { - parseRes = parseFXCLine(line, splitLine, diagnostic); + if (line.startsWith(resultCodePrefix)) + { + // Split past the equal + const UnownedStringSlice valueSlice = _getEquals(line.tail(resultCodePrefix.getLength())); + Int value; + SLANG_RETURN_ON_FAIL(StringUtil::parseInt(valueSlice, value)); + out.resultCode = int(value); + } + else + { + UnownedStringSlice* startsWith = nullptr; + if (line.startsWith(stdErrorPrefix)) + { + startsWith = &stdErrorPrefix; + } + else if (line.startsWith(stdOutputPrefix)) + { + startsWith = &stdOutputPrefix; + } + + if (startsWith) + { + // Clear the lines buffer + lines.clear(); + + UnownedStringSlice valueSlice = _getEquals(line.tail(startsWith->getLength())); + if (!valueSlice.isChar('{')) + { + return SLANG_FAIL; + } + // Okay we now inside std out or std error, so update the state + state = (startsWith == &stdErrorPrefix) ? State::InStdError : State::InStdOut; + } + } break; } - case SLANG_PASS_THROUGH_DXC: + case State::InStdError: + case State::InStdOut: { - parseRes = parseDXCLine(line, splitLine, diagnostic); - break; + if (line == "}") + { + String& dst = state == State::InStdError ? out.stdError : out.stdOut; + if (lines.getCount() > 0) + { + dst = UnownedStringSlice(lines[0].begin(), lines.getLast().end()); + } + state = State::Normal; + } + else + { + lines.add(line); + } } - case SLANG_PASS_THROUGH_GLSLANG: + } + } + + return (state == State::Normal) ? SLANG_OK : SLANG_FAIL; +} + + +/* static */bool ParseDiagnosticUtil::areEqual(const UnownedStringSlice& a, const UnownedStringSlice& b, EqualityFlags flags) +{ + List<DownstreamDiagnostic> diagsA, diagsB; + SlangResult resA = ParseDiagnosticUtil::parseDiagnostics(a, diagsA); + SlangResult resB = ParseDiagnosticUtil::parseDiagnostics(b, diagsB); + + /* + TODO(JS): In the past we needed special handling of the stdlib, when + in some builds the path contains the stdlib. + + For now we don't seem to need this, this is for future reference, if there + is an issue with needing to specially handle this. + + static const UnownedStringSlice stdLibNames[] = + { + UnownedStringSlice::fromLiteral("core.meta.slang"), + UnownedStringSlice::fromLiteral("hlsl.meta.slang"), + UnownedStringSlice::fromLiteral("slang-stdlib.cpp"), + }; + */ + + // Must have both succeeded, and have the same amount of lines + if (SLANG_SUCCEEDED(resA) && SLANG_SUCCEEDED(resB) && + diagsA.getCount() == diagsB.getCount()) + { + for (Index i = 0; i < diagsA.getCount(); ++i) + { + DownstreamDiagnostic diagA = diagsA[i]; + DownstreamDiagnostic diagB = diagsB[i]; + + // Check if we need to ignore line numbers + if (flags & EqualityFlag::IgnoreLineNos) { - parseRes = parseGlslangLine(line, splitLine, diagnostic); - break; + diagA.fileLine = 0; + diagB.fileLine = 0; } - default: + + if (diagA != diagB) { - parseRes = parseGenericLine(line, splitLine, diagnostic); - break; + return false; } } - // If couldn't parse, just add as a note - if (SLANG_FAILED(parseRes)) - { - _addDiagnosticNote(line, outDiagnostics); - } - else - { - outDiagnostics.add(diagnostic); - } + return true; } - - return SLANG_OK; + + return false; } |
