diff options
Diffstat (limited to 'source/compiler-core')
| -rw-r--r-- | source/compiler-core/slang-artifact-container-util.cpp | 48 | ||||
| -rw-r--r-- | source/compiler-core/slang-artifact-container-util.h | 3 | ||||
| -rw-r--r-- | source/compiler-core/slang-artifact-desc-util.cpp | 10 | ||||
| -rw-r--r-- | source/compiler-core/slang-json-source-map-util.cpp | 90 | ||||
| -rw-r--r-- | source/compiler-core/slang-json-source-map-util.h | 4 | ||||
| -rw-r--r-- | source/compiler-core/slang-source-loc.cpp | 177 | ||||
| -rw-r--r-- | source/compiler-core/slang-source-loc.h | 34 |
7 files changed, 301 insertions, 65 deletions
diff --git a/source/compiler-core/slang-artifact-container-util.cpp b/source/compiler-core/slang-artifact-container-util.cpp index 29e2e736e..6121df964 100644 --- a/source/compiler-core/slang-artifact-container-util.cpp +++ b/source/compiler-core/slang-artifact-container-util.cpp @@ -626,7 +626,6 @@ SlangResult ArtifactContainerReader::read(ISlangFileSystemExt* fileSystem, ComPt return _readArtifactDirectory(0, outArtifact); } - SlangResult ArtifactContainerReader::_readFile(Index fileIndex, ComPtr<IArtifact>& outArtifact) { outArtifact.setNull(); @@ -655,6 +654,19 @@ SlangResult ArtifactContainerReader::_readFile(Index fileIndex, ComPtr<IArtifact return SLANG_OK; } + // We don't have manifest, so for now well assume if the name ends in "-obfuscated" and it's a source map + // it's an obfuscated one + if (desc.kind == ArtifactKind::Json && + desc.payload == ArtifactPayload::SourceMap) + { + auto name = Path::getFileNameWithoutExt(entry.name); + + if (name.endsWith(toSlice("-obfuscated"))) + { + desc.style = ArtifactStyle::Obfuscated; + } + } + // I guess I can just make an artifact for this auto artifact = ArtifactUtil::createArtifact(desc); @@ -781,6 +793,40 @@ SlangResult ArtifactContainerReader::_readArtifactDirectory(Index directoryIndex return SLANG_OK; } +SlangResult ArtifactContainerUtil::readContainer(IArtifact* artifact, ComPtr<IArtifact>& outArtifact) +{ + auto desc = artifact->getDesc(); + + ComPtr<ISlangMutableFileSystem> fileSystem; + + switch (desc.kind) + { + case ArtifactKind::Zip: + { + SLANG_RETURN_ON_FAIL(ZipFileSystem::create(fileSystem)); + + ComPtr<ISlangBlob> blob; + SLANG_RETURN_ON_FAIL(artifact->loadBlob(ArtifactKeep::No, blob.writeRef())); + + // Load into the zip + + // Now write out to the output file + IArchiveFileSystem* archiveFileSystem = as<IArchiveFileSystem>(fileSystem); + SLANG_ASSERT(archiveFileSystem); + + SLANG_RETURN_ON_FAIL(archiveFileSystem->loadArchive(blob->getBufferPointer(), blob->getBufferSize())); + break; + } + default: + { + return SLANG_FAIL; + } + } + + SLANG_RETURN_ON_FAIL(readContainer(fileSystem, outArtifact)); + return SLANG_OK; +} + /* static */SlangResult ArtifactContainerUtil::readContainer(ISlangFileSystemExt* fileSystem, ComPtr<IArtifact>& outArtifact) { SLANG_UNUSED(outArtifact); diff --git a/source/compiler-core/slang-artifact-container-util.h b/source/compiler-core/slang-artifact-container-util.h index b3e591797..c6e836245 100644 --- a/source/compiler-core/slang-artifact-container-util.h +++ b/source/compiler-core/slang-artifact-container-util.h @@ -33,6 +33,9 @@ struct ArtifactContainerUtil static SlangResult writeContainer(IArtifact* artifact, const String& defaultFileName, ISlangMutableFileSystem* fileSystem); static SlangResult readContainer(ISlangFileSystemExt* fileSystem, ComPtr<IArtifact>& outArtifact); + + /// Read an artifact that represents a container as an artifact hierarchy + static SlangResult readContainer(IArtifact* artifact, ComPtr<IArtifact>& outArtifact); }; } // namespace Slang diff --git a/source/compiler-core/slang-artifact-desc-util.cpp b/source/compiler-core/slang-artifact-desc-util.cpp index fb1c2dbd2..67501782a 100644 --- a/source/compiler-core/slang-artifact-desc-util.cpp +++ b/source/compiler-core/slang-artifact-desc-util.cpp @@ -460,7 +460,15 @@ static const KindExtension g_cpuKindExts[] = /* static */bool ArtifactDescUtil::isLinkable(const ArtifactDesc& desc) { - if (isDerivedFrom(desc.kind, ArtifactKind::CompileBinary)) + // If is a container with compile results *assume* that result is linkable + if (isDerivedFrom(desc.kind, ArtifactKind::Container) && + isDerivedFrom(desc.payload, ArtifactPayload::CompileResults)) + { + return true; + } + + // if it's a compile binary or a container + if (isDerivedFrom(desc.kind, ArtifactKind::CompileBinary)) { if (isDerivedFrom(desc.payload, ArtifactPayload::KernelLike)) { diff --git a/source/compiler-core/slang-json-source-map-util.cpp b/source/compiler-core/slang-json-source-map-util.cpp index a5a454bd5..3929a3387 100644 --- a/source/compiler-core/slang-json-source-map-util.cpp +++ b/source/compiler-core/slang-json-source-map-util.cpp @@ -105,34 +105,31 @@ static SlangResult _decode(UnownedStringSlice& ioEncoded, Index& out) { Index v = 0; - Index shift = 0; const char* cur = ioEncoded.begin(); const char* end = ioEncoded.end(); - // Must have some chars - if (cur >= end) { - return SLANG_FAIL; - } - - for (; cur < end; ++cur) - { - const Index value = g_vlqDecodeTable[*cur]; - if (value < 0) + Index shift = 0; + Index decodeValue = 0; + do { - return SLANG_FAIL; - } + // Must have a char to decode + if (cur >= end) + { + return SLANG_FAIL; + } + + decodeValue = g_vlqDecodeTable[*cur++]; + if (decodeValue < 0) + { + return SLANG_FAIL; + } - v += (value & 0x1f) << shift; + v += (decodeValue & 0x1f) << shift; - // If the continuation bit is not set we are done - if (( value & 0x20) == 0) - { - ++cur; - break; + shift += 5; } - - shift += 5; + while (decodeValue & 0x20); } // Save out the remaining part @@ -158,20 +155,16 @@ void _encode(Index v, StringBuilder& out) do { - // Encode it - const auto nextV = v >> 5; - - // Encode 5 bits - char c = g_vlqEncodeTable[(v & 0x1f)]; - - // See what bits are remaining - v = (v >> 5); - - // Set the continuation bit's if there is more to encode - c |= v ? 0x20 : 0; + const Index nextV = v >> 5; + const Index encodeValue = (v & 0x1f) + (nextV ? 0x20 : 0); + // Encode 5 bits, plus continuation bit + char c = g_vlqEncodeTable[encodeValue]; + // Save the char *cur++ = c; + + v = nextV; } while (v); @@ -461,4 +454,39 @@ SlangResult JSONSourceMapUtil::encode(SourceMap* sourceMap, JSONContainer* conta return SLANG_OK; } +SlangResult JSONSourceMapUtil::read(ISlangBlob* blob, DiagnosticSink* parentSink, RefPtr<SourceMap>& outSourceMap) +{ + SourceManager sourceManager; + sourceManager.initialize(nullptr, nullptr); + DiagnosticSink sink(&sourceManager, nullptr); + + sink.setParentSink(parentSink); + + RefPtr<JSONContainer> container = new JSONContainer(&sourceManager); + + JSONValue rootValue; + { + // Now need to parse as JSON + SourceFile* sourceFile = sourceManager.createSourceFileWithBlob(PathInfo::makeUnknown(), blob); + SourceView* sourceView = sourceManager.createSourceView(sourceFile, nullptr, SourceLoc()); + + JSONLexer lexer; + lexer.init(sourceView, &sink); + + JSONBuilder builder(container); + + JSONParser parser; + SLANG_RETURN_ON_FAIL(parser.parse(&lexer, sourceView, &builder, &sink)); + + rootValue = builder.getRootValue(); + } + + RefPtr<SourceMap> sourceMap; + + SLANG_RETURN_ON_FAIL(decode(container, rootValue, &sink, sourceMap)); + + outSourceMap = sourceMap; + return SLANG_OK; +} + } // namespace Slang diff --git a/source/compiler-core/slang-json-source-map-util.h b/source/compiler-core/slang-json-source-map-util.h index 51b11b6cd..ba417dd7c 100644 --- a/source/compiler-core/slang-json-source-map-util.h +++ b/source/compiler-core/slang-json-source-map-util.h @@ -14,6 +14,10 @@ struct JSONSourceMapUtil /// Converts the source map contents into JSON static SlangResult encode(SourceMap* sourceMap, JSONContainer* container, DiagnosticSink* sink, JSONValue& outValue); + + /// Read the blob (encoded as JSON) as a source map. + /// Sink is optional, and can be passed as nullptr + static SlangResult read(ISlangBlob* blob, DiagnosticSink* sink, RefPtr<SourceMap>& outSourceMap); }; } // namespace Slang diff --git a/source/compiler-core/slang-source-loc.cpp b/source/compiler-core/slang-source-loc.cpp index 951f7feec..23cbdf839 100644 --- a/source/compiler-core/slang-source-loc.cpp +++ b/source/compiler-core/slang-source-loc.cpp @@ -3,6 +3,7 @@ #include "../core/slang-string-util.h" #include "../core/slang-string-escape-util.h" +#include "../core/slang-char-encode.h" #include "slang-artifact-representation-impl.h" #include "slang-artifact-impl.h" @@ -189,44 +190,118 @@ void SourceView::addDefaultLineDirective(SourceLoc directiveLoc) m_entries.add(entry); } -HandleSourceLoc SourceView::getHandleLoc(SourceLoc loc, SourceLocType type) +SlangResult _findLocWithSourceMap(SourceManager* lookupSourceManager, SourceView* sourceView, SourceLoc loc, HandleSourceLoc& outLoc) { - auto obfuscatedSourceMap = getSourceFile()->getObfuscatedSourceMap(); - if (obfuscatedSourceMap) + auto sourceFile = sourceView->getSourceFile(); + + // Hold a list of sourceFiles visited so we can't end up in a loop of lookups + List<SourceFile*> sourceFiles; + sourceFiles.add(sourceFile); + + Index entryIndex = -1; + + // Do the initial lookup using the loc + { + const auto offset = sourceView->getRange().getOffset(loc); + + const auto lineIndex = sourceFile->calcLineIndexFromOffset(offset); + const auto colIndex = sourceFile->calcColumnIndex(lineIndex, offset); + + // If we are in this function the sourceFile should have a map + auto sourceMap = sourceFile->getSourceMap(); + SLANG_ASSERT(sourceMap); + + entryIndex = sourceMap->findEntry(lineIndex, colIndex); + } + + if (entryIndex < 0) { - const Index col = getRange().getOffset(loc); + return SLANG_FAIL; + } + + // Keep searching through source maps + do + { + auto sourceMap = sourceFile->getSourceMap(); - const Index entryIndex = obfuscatedSourceMap->findEntry(0, col); - if (entryIndex >= 0) + // Find the entry + const auto& entry = sourceMap->getEntryByIndex(entryIndex); + const auto sourceFileName = sourceMap->getSourceFileName(entry.sourceFileIndex); + + // If we have a source name, see if it already exists in source manager + if (sourceFileName.getLength()) { - const auto& entry = obfuscatedSourceMap->getEntryByIndex(entryIndex); + if (auto foundSourceFile = lookupSourceManager->findSourceFileByPathRecursively(sourceFileName)) + { + // We only follow if the source file hasn't already been visisted + if (sourceFiles.indexOf(foundSourceFile) < 0) + { + // Add so we don't reprocess + sourceFiles.add(foundSourceFile); + + // If it has a source map, we try and look up the current location in it's source map + if (auto foundSourceMap = foundSourceFile->getSourceMap()) + { + const auto foundEntryIndex = foundSourceMap->findEntry(entry.sourceLine, entry.sourceColumn); + + // If we found the entry repeat the lookup + if (foundEntryIndex >= 0) + { + sourceFile = foundSourceFile; + entryIndex = foundEntryIndex; + continue; + } + } + } + } + } + } while (false); - // Generate the HandleSourceLoc + // Generate the HandleSourceLoc + auto sourceMap = sourceFile->getSourceMap(); + const auto& entry = sourceMap->getEntryByIndex(entryIndex); - HandleSourceLoc handleLoc; - handleLoc.line = entry.sourceLine + 1; - handleLoc.column = entry.sourceColumn + 1; + // We need to add the pool of the originating source view/file + const auto originatingSourceManager = sourceView->getSourceManager(); - auto& managerPool = getSourceManager()->getStringSlicePool(); + auto& managerPool = originatingSourceManager->getStringSlicePool(); - handleLoc.pathHandle = managerPool.add(obfuscatedSourceMap->getSourceFileName(entry.sourceFileIndex)); + outLoc.line = entry.sourceLine + 1; + outLoc.column = entry.sourceColumn + 1; + outLoc.pathHandle = managerPool.add(sourceMap->getSourceFileName(entry.sourceFileIndex)); + + return SLANG_OK; +} + +HandleSourceLoc SourceView::getHandleLoc(SourceLoc loc, SourceLocType type) +{ + // If it's nominal + if (type == SourceLocType::Nominal && m_sourceFile->getSourceMap()) + { + // TODO(JS): + // Ideally we'd do the lookup on the "current" source manager rather than the source manager on this + // view, which may be a parent to the current one. + auto lookupSourceManager = m_sourceFile->getSourceManager(); + + HandleSourceLoc handleLoc; + if (SLANG_SUCCEEDED(_findLocWithSourceMap(lookupSourceManager, this, loc, handleLoc))) + { return handleLoc; } } + // Get the offset in bytes for this loc const int offset = m_range.getOffset(loc); // We need the line index from the original source file const int lineIndex = m_sourceFile->calcLineIndexFromOffset(offset); - // TODO: we should really translate the byte index in the line - // to deal with: - // - // - Non-ASCII characters, while might consume multiple bytes - // + // TODO: // - Tab characters, which should really adjust how we report // columns (although how are we supposed to know the setting - // that an IDE expects us to use when reporting locations?) + // that an IDE expects us to use when reporting locations?) + // + // For now we just count tabs as single chars const int columnIndex = m_sourceFile->calcColumnIndex(lineIndex, offset); HandleSourceLoc handleLoc; @@ -409,12 +484,43 @@ int SourceFile::calcLineIndexFromOffset(int offset) return int(lo); } -int SourceFile::calcColumnIndex(int lineIndex, int offset) +int SourceFile::calcColumnOffset(int lineIndex, int offset) { const auto& lineBreakOffsets = getLineBreakOffsets(); return offset - lineBreakOffsets[lineIndex]; } +int SourceFile::calcColumnIndex(int lineIndex, int offset, int tabSize) +{ + const int colOffset = calcColumnOffset(lineIndex, offset); + + // If we don't have the content of the file, the best we can do is to assume there is a char per column + if (!hasContent()) + { + return colOffset; + } + + const auto line = getLineAtIndex(lineIndex); + + const auto head = line.head(colOffset); + + auto colCount = UTF8Util::calcCodePointCount(head); + + if (tabSize >= 0) + { + Count tabCount = 0; + for (auto c : head) + { + tabCount += Count(c == '\t'); + } + + // We substract one from tabSize, because colCount will already holds a +1 for each tab. + colCount += tabCount * (tabSize - 1); + } + + return int(colCount); +} + /* !!!!!!!!!!!!!!!!!!!!!!!!! SourceFile !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ void SourceFile::setContents(ISlangBlob* blob) @@ -677,6 +783,37 @@ SourceView* SourceManager::findSourceViewRecursively(SourceLoc loc) const return nullptr; } +SourceFile* SourceManager::findSourceFileByPathRecursively(const String& name) const +{ + // Start with this manager + const SourceManager* manager = this; + do + { + SourceFile* sourceFile = manager->findSourceFileByPath(name); + // If we found a hit we are done + if (sourceFile) + { + return sourceFile; + } + // Try the parent + manager = manager->m_parent; + } while (manager); + // Didn't find it + return nullptr; +} + +SourceFile* SourceManager::findSourceFileByPath(const String& name) const +{ + for(auto sourceFile : m_sourceFiles) + { + if (sourceFile->getPathInfo().foundPath == name) + { + return sourceFile; + } + } + return nullptr; +} + SourceFile* SourceManager::findSourceFile(const String& uniqueIdentity) const { SourceFile*const* filePtr = m_sourceFileMap.TryGetValue(uniqueIdentity); diff --git a/source/compiler-core/slang-source-loc.h b/source/compiler-core/slang-source-loc.h index 4103c9d6d..98b1bdbbd 100644 --- a/source/compiler-core/slang-source-loc.h +++ b/source/compiler-core/slang-source-loc.h @@ -218,8 +218,13 @@ public: /// Calculate the line based on the offset int calcLineIndexFromOffset(int offset); - /// Calculate the offset for a line - int calcColumnIndex(int line, int offset); + /// Calculate the offset (in bytes) for a line + int calcColumnOffset(int line, int offset); + + /// Given a line and offset (in bytes for the whole file), return the column index, taking into account tabs + /// and utf8 encoding. + /// Passing tabSize uses the default tab size (currently tab set to 1) + int calcColumnIndex(int line, int offset, int tabSize = -1); /// Get the content holding blob ISlangBlob* getContentBlob() const { return m_contentBlob; } @@ -247,11 +252,11 @@ public: /// Get the source manager this was created on SourceManager* getSourceManager() const { return m_sourceManager; } - /// If set this "file" only exists as a way to obfuscate locations - /// The mapping between the two is specified in the specified source map - SourceMap* getObfuscatedSourceMap() const { return m_obfuscatedSourceMap; } - /// Set the obfuscated source map - void setObfuscatedSourceMap(SourceMap* sourceMap) { m_obfuscatedSourceMap = sourceMap; } + /// Get the source map associated with this file. If it's set when doing + /// lookup for source locations, the source map will be used + SourceMap* getSourceMap() const { return m_sourceMap; } + /// Set a source map + void setSourceMap(SourceMap* sourceMap) { m_sourceMap = sourceMap; } /// Ctor SourceFile(SourceManager* sourceManager, const PathInfo& pathInfo, size_t contentSize); @@ -272,15 +277,15 @@ public: // the input file: List<uint32_t> m_lineBreakOffsets; - // If set then this file isn't a regular source file, but provides obfuscation. - // The mapping of that obfuscation can be found via the obfuscated source map - RefPtr<SourceMap> m_obfuscatedSourceMap; + // If set then the locations in this file are really from locations from elsewhere, + // where the SourceMap specifies that mapping + RefPtr<SourceMap> m_sourceMap; }; enum class SourceLocType { - Nominal, ///< The normal interpretation which takes into account #line directives - Actual, ///< Ignores #line directives - and is the location as seen in the actual file + Nominal, ///< The normal interpretation which takes into account #line directives and source maps + Actual, ///< Ignores #line directives/source maps - and is the location as seen in the actual file }; // A source location in a format a human might like to see @@ -441,6 +446,11 @@ struct SourceManager /// Find if the source file is defined on this manager. SourceFile* findSourceFile(const String& uniqueIdentity) const; + /// Find a source file by path. + SourceFile* findSourceFileByPath(const String& name) const; + /// Find a source file by path recursively. + SourceFile* findSourceFileByPathRecursively(const String& name) const; + /// Searches this manager, and then the parent to see if can find a match SourceFile* findSourceFileByContentRecursively(const char* text); /// Find the source file that contains *the memory* text points to. |
