summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-emit-source-writer.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2023-03-17 11:05:15 -0400
committerGitHub <noreply@github.com>2023-03-17 11:05:15 -0400
commit8a61b9dd0ca729df894dad4c89c6ce3bf39ef0be (patch)
treeb7f3da5d30772ba1497f14cdeb39935225183bbb /source/slang/slang-emit-source-writer.cpp
parent9476d4543f4336a66308e55f722b0b0b2bd69dd2 (diff)
Support for producing SourceMap on emit (#2707)
* #include an absolute path didn't work - because paths were taken to always be relative. * WIP source map. * Split out handling of RttiTypeFuncs to a map type. * Make RttiTypeFuncsMap hold default impls. * Slightly more sophisticated RttiTypeFuncsMap * Source map decoding. * Fix tabs. * Fix asserts due to negative values. * Use less obscure mechanisms in SourceMap. * Source map decoding. Simplifying SourceMap usage. * First attempt at ouputting a source map as part of emit. * Added support for -source-map option. SourceMap is added to the artifact.
Diffstat (limited to 'source/slang/slang-emit-source-writer.cpp')
-rw-r--r--source/slang/slang-emit-source-writer.cpp101
1 files changed, 98 insertions, 3 deletions
diff --git a/source/slang/slang-emit-source-writer.cpp b/source/slang/slang-emit-source-writer.cpp
index 7692bd0ec..b27e0f8b4 100644
--- a/source/slang/slang-emit-source-writer.cpp
+++ b/source/slang/slang-emit-source-writer.cpp
@@ -16,10 +16,11 @@
namespace Slang {
-SourceWriter::SourceWriter(SourceManager* sourceManager, LineDirectiveMode lineDirectiveMode)
+SourceWriter::SourceWriter(SourceManager* sourceManager, LineDirectiveMode lineDirectiveMode, SourceMap* sourceMap)
{
+ m_sourceMap = sourceMap;
m_lineDirectiveMode = lineDirectiveMode;
- this->m_sourceManager = sourceManager;
+ m_sourceManager = sourceManager;
}
String SourceWriter::getContentAndClear()
@@ -274,7 +275,10 @@ void SourceWriter::advanceToSourceLocationIfValid(const SourceLoc& sourceLocatio
void SourceWriter::advanceToSourceLocation(const SourceLoc& sourceLocation)
{
- if (getLineDirectiveMode() == LineDirectiveMode::None)
+ // If we don't have any line directives *and* we don't want to output
+ // source map, we can just ignore
+ if (getLineDirectiveMode() == LineDirectiveMode::None &&
+ m_sourceMap == nullptr)
{
// Ignore if we aren't outputting directives
return;
@@ -328,7 +332,14 @@ void SourceWriter::_flushSourceLocationChange()
// advances the location, and outputting text is what
// triggers this flush operation.
m_needToUpdateSourceLocation = false;
+
_emitLineDirectiveIfNeeded(m_nextHumaneSourceLocation);
+
+ // If we have a source map update state
+ if (m_sourceMap)
+ {
+ _updateSourceMap(m_nextHumaneSourceLocation);
+ }
}
void SourceWriter::_emitLineDirectiveAndUpdateSourceLocation(const HumaneSourceLoc& sourceLocation)
@@ -341,6 +352,31 @@ void SourceWriter::_emitLineDirectiveAndUpdateSourceLocation(const HumaneSourceL
m_loc = newLoc;
}
+void SourceWriter::_updateSourceMap(const HumaneSourceLoc& sourceLocation)
+{
+ // Ignore invalid source locations
+ if (sourceLocation.line <= 0)
+ return;
+
+ // We need to work out the current column in the generated (ie being written) output
+ Index generatedLineIndex, generatedColumnIndex;
+ _calcLocation(generatedLineIndex, generatedColumnIndex);
+
+ // Advance to the current output line
+ m_sourceMap->advanceToLine(generatedLineIndex);
+
+ // Add the entry into the map, mapping back to the original source
+ SourceMap::Entry entry;
+ entry.init();
+
+ entry.sourceFileIndex = m_sourceMap->getSourceFileIndex(sourceLocation.pathInfo.getName().getUnownedSlice());
+ entry.sourceLine = sourceLocation.line - 1;
+ entry.sourceColumn = sourceLocation.column - 1;
+ entry.generatedColumn = generatedColumnIndex;
+
+ m_sourceMap->addEntry(entry);
+}
+
void SourceWriter::_emitLineDirectiveIfNeeded(const HumaneSourceLoc& sourceLocation)
{
if (m_supressLineDirective)
@@ -478,4 +514,63 @@ void SourceWriter::_emitLineDirective(const HumaneSourceLoc& sourceLocation)
emitRawText("\n");
}
+void SourceWriter::_calcLocation(Index& outLineIndex, Index& outColumnIndex)
+{
+ // If we are at the end, then we are done.
+ if (m_currentOutputOffset == m_builder.getLength())
+ {
+ outLineIndex = m_currentLineIndex;
+ outColumnIndex = m_currentColumnIndex;
+ return;
+ }
+
+ const char* cur = m_builder.getBuffer() + m_currentOutputOffset;
+ const char* end = m_builder.end();
+
+ const char* start = cur;
+
+ while (cur < end)
+ {
+ // Reset start
+ start = cur;
+
+ // Look for the end of the line
+ while (*cur != '\n' && *cur != '\r' && cur < end)
+ {
+ cur++;
+ }
+
+ // If we are not at the total end then we must have hit a \n or \r
+ if (cur < end)
+ {
+ const auto c = *cur++;
+
+ ++m_currentLineIndex;
+ // Reset the column
+ m_currentColumnIndex = 0;
+
+ // Check the next char to see if it's part of a CR/LF combination
+ if (cur < end)
+ {
+ const auto d = *cur;
+ // If it is combination skip the next byte
+ cur += ((c ^ d) == ('\r' ^ '\n'));
+ }
+ }
+ }
+
+ // Fix up the current index.
+ // TODO(JS):
+ // NOTE! This isn't strictly correct because it assumes one byte is a *column* which isn't actually the case with utf8
+ // encoding...
+ m_currentColumnIndex += Index(cur - start);
+
+ // Set the current offset is the end
+ m_currentOutputOffset = m_builder.getLength();
+
+ // Output the values
+ outLineIndex = m_currentLineIndex;
+ outColumnIndex = m_currentColumnIndex;
+}
+
} // namespace Slang