diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2018-10-16 18:49:11 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-10-16 18:49:11 -0400 |
| commit | 3e74d39f24fdfaa547ce900be177863e2bfe2dea (patch) | |
| tree | 9a5143e6de4caa27b23fc870003011e96129905f /source/slang | |
| parent | 204fb3c75b520a2cbb1c25f995a8c424ec2753f3 (diff) | |
Feature/include refactor (#675)
* Refactor of path handling.
* Added PathInfo
* Changed ISlangFileSystem - such that has separate concepts of reading a file, getting a relative path and getting a canonical path
* Added support for getting a canonical path for windows/linux
* Made maps/testing around canonicalPaths
* User output remains around 'foundPath' - which is the same as before
* Small improvements around PathInfo
* Added a type and make constructors to make clear the different 'path' uses
* Fixed bug in findViewRecursively
* Checking and reporting for ignored #pragma once.
* Removed SLANG_PATH_TYPE_NONE as doesn't serve any useful purpose.
* Improve comments in slang.h aroung ISlangFileSystem
* Remove the need for <windows.h> in slang-io.cpp
* Ran premake5.
* Improvements and fixes around PathInfo.
* Fix typo on linix GetCanonical
* Make the ISlangFileSystem the same as before, and ISlangFileSystem contain the new methods.
Internally it always uses the ISlangFileSystemExt, and will wrap a ISlangFileSystem with WrapFileSystem, if it is determined (via queryInterface) that it doesn't implement the full interface.
Diffstat (limited to 'source/slang')
| -rw-r--r-- | source/slang/compiler.cpp | 5 | ||||
| -rw-r--r-- | source/slang/compiler.h | 12 | ||||
| -rw-r--r-- | source/slang/diagnostic-defs.h | 3 | ||||
| -rw-r--r-- | source/slang/diagnostics.cpp | 2 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 11 | ||||
| -rw-r--r-- | source/slang/include-file-system.cpp | 101 | ||||
| -rw-r--r-- | source/slang/include-file-system.h | 81 | ||||
| -rw-r--r-- | source/slang/preprocessor.cpp | 62 | ||||
| -rw-r--r-- | source/slang/preprocessor.h | 19 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 196 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj | 12 | ||||
| -rw-r--r-- | source/slang/slang.vcxproj.filters | 16 | ||||
| -rw-r--r-- | source/slang/source-loc.cpp | 95 | ||||
| -rw-r--r-- | source/slang/source-loc.h | 58 |
14 files changed, 520 insertions, 153 deletions
diff --git a/source/slang/compiler.cpp b/source/slang/compiler.cpp index 7a5501a23..4b7fcb554 100644 --- a/source/slang/compiler.cpp +++ b/source/slang/compiler.cpp @@ -186,7 +186,10 @@ namespace Slang for(auto sourceFile : translationUnit->sourceFiles) { codeBuilder << "#line 1 \""; - for(auto c : sourceFile->path) + + const String& path = sourceFile->pathInfo.foundPath; + + for(auto c : path) { char buffer[] = { c, 0 }; switch(c) diff --git a/source/slang/compiler.h b/source/slang/compiler.h index a83d8b334..04508837f 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -13,6 +13,7 @@ namespace Slang { + struct PathInfo; struct IncludeHandler; class CompileRequest; class ProgramLayout; @@ -395,6 +396,11 @@ namespace Slang /// ComPtr<ISlangFileSystem> fileSystem; + /// The extended file system implementation. Will be set to a default implementation + /// if fileSystem is nullptr. Otherwise it will either be fileSystem's interface, + /// or a wrapped impl that makes fileSystem operate as fileSystemExt + ComPtr<ISlangFileSystemExt> fileSystemExt; + /// Load a file into memory using the configured file system. /// /// @param path The path to attempt to load from @@ -454,14 +460,14 @@ namespace Slang RefPtr<ModuleDecl> loadModule( Name* name, - String const& path, - ISlangBlob* sourceBlob, + const PathInfo& filePathInfo, + ISlangBlob* fileContentsBlob, SourceLoc const& loc); void loadParsedModule( RefPtr<TranslationUnitRequest> const& translationUnit, Name* name, - String const& path); + PathInfo const& pathInfo); RefPtr<ModuleDecl> findOrImportModule( Name* name, diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h index 1df7e23f5..89db9d0e3 100644 --- a/source/slang/diagnostic-defs.h +++ b/source/slang/diagnostic-defs.h @@ -125,6 +125,8 @@ DIAGNOSTIC(-1, Note, seeOpeningToken, "see opening '$0'") DIAGNOSTIC(15300, Error, includeFailed, "failed to find include file '$0'") DIAGNOSTIC(15301, Error, importFailed, "failed to find imported file '$0'") DIAGNOSTIC(-1, Error, noIncludeHandlerSpecified, "no `#include` handler was specified") +DIAGNOSTIC(15302, Error, noCanonicalPath, "`#include` handler didn't generate a canonical path for '$0'") + // 154xx - macro definition DIAGNOSTIC(15400, Warning, macroRedefinition, "redefinition of macro '$0'") @@ -138,6 +140,7 @@ DIAGNOSTIC(15501, Error, wrongNumberOfArgumentsToMacro, "wrong number of argumen // 156xx - pragmas DIAGNOSTIC(15600, Error, expectedPragmaDirectiveName, "expected a name after '#pragma'") DIAGNOSTIC(15601, Warning, unknownPragmaDirectiveIgnored, "ignoring unknown directive '#pragma $0'") +DIAGNOSTIC(15602, Warning, pragmaOnceIgnored, "pragma once was ignored - this is typically because is not placed in an include") // 159xx - user-defined error/warning DIAGNOSTIC(15900, Error, userDefinedError, "#error: $0") diff --git a/source/slang/diagnostics.cpp b/source/slang/diagnostics.cpp index ff664e81b..c4638f29a 100644 --- a/source/slang/diagnostics.cpp +++ b/source/slang/diagnostics.cpp @@ -171,7 +171,7 @@ static void formatDiagnostic( auto humaneLoc = sourceManager->getHumaneLoc(diagnostic.loc); - sb << humaneLoc.path; + sb << humaneLoc.pathInfo.foundPath; sb << "("; sb << humaneLoc.line; sb << "): "; diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index c306186fb..4961518f1 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -541,7 +541,7 @@ struct EmitVisitor emitRawText(buffer); // Only emit the path part of a `#line` directive if needed - if(sourceLocation.path != context->shared->loc.path) + if(sourceLocation.pathInfo.foundPath != context->shared->loc.pathInfo.foundPath) { emitRawText(" "); @@ -578,7 +578,7 @@ struct EmitVisitor if(shouldUseGLSLStyleLineDirective) { - auto path = sourceLocation.path; + auto path = sourceLocation.pathInfo.foundPath; // GLSL doesn't support the traditional form of a `#line` directive without // an extension. Rather than depend on that extension we will output @@ -609,7 +609,8 @@ struct EmitVisitor // in a module that tracks source files. emitRawText("\""); - for(auto c : sourceLocation.path) + const auto& path = sourceLocation.pathInfo.foundPath; + for(auto c : path) { char charBuffer[] = { c, 0 }; switch(c) @@ -673,7 +674,7 @@ struct EmitVisitor // a differnet file or line, *or* if the source location is // somehow later on the line than what we want to emit, // then we need to emit a new `#line` directive. - if(sourceLocation.path != context->shared->loc.path + if(sourceLocation.pathInfo.foundPath != context->shared->loc.pathInfo.foundPath || sourceLocation.line != context->shared->loc.line || sourceLocation.column < context->shared->loc.column) { @@ -682,7 +683,7 @@ struct EmitVisitor // to get us caught up. enum { kSmallLineCount = 3 }; auto lineDiff = sourceLocation.line - context->shared->loc.line; - if(sourceLocation.path == context->shared->loc.path + if(sourceLocation.pathInfo.foundPath == context->shared->loc.pathInfo.foundPath && sourceLocation.line > context->shared->loc.line && lineDiff <= kSmallLineCount) { diff --git a/source/slang/include-file-system.cpp b/source/slang/include-file-system.cpp new file mode 100644 index 000000000..d2c1670fe --- /dev/null +++ b/source/slang/include-file-system.cpp @@ -0,0 +1,101 @@ +#include "include-file-system.h" + +#include "../../slang-com-ptr.h" +#include "../core/slang-io.h" +#include "compiler.h" + +namespace Slang +{ + +// Allocate static const storage for the various interface IDs that the Slang API needs to expose +static const Guid IID_ISlangUnknown = SLANG_UUID_ISlangUnknown; +static const Guid IID_ISlangFileSystem = SLANG_UUID_ISlangFileSystem; +static const Guid IID_ISlangFileSystemExt = SLANG_UUID_ISlangFileSystemExt; + +/* !!!!!!!!!!!!!!!!!!!!!!!!!! IncludeFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + +/* static */ISlangFileSystemExt* IncludeFileSystem::getDefault() +{ + static IncludeFileSystem s_includeFileSystem; + s_includeFileSystem.ensureRef(); + return &s_includeFileSystem; +} + +ISlangUnknown* IncludeFileSystem::getInterface(const Guid& guid) +{ + return (guid == IID_ISlangUnknown || guid == IID_ISlangFileSystem || guid == IID_ISlangFileSystemExt) ? static_cast<ISlangFileSystemExt*>(this) : nullptr; +} + +SlangResult IncludeFileSystem::getCanoncialPath(const char* path, ISlangBlob** canonicalPathOut) +{ + String canonicalPath; + SLANG_RETURN_ON_FAIL(Path::GetCanonical(path, canonicalPath)); + + *canonicalPathOut = createStringBlob(canonicalPath).detach(); + return SLANG_OK; +} + +SlangResult IncludeFileSystem::calcRelativePath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +{ + String relPath; + switch (fromPathType) + { + case SLANG_PATH_TYPE_FILE: + { + relPath = Path::Combine(Path::GetDirectoryName(fromPath), path); + break; + } + case SLANG_PATH_TYPE_DIRECTORY: + { + relPath = Path::Combine(fromPath, path); + break; + } + } + + *pathOut = createStringBlob(relPath).detach(); + return SLANG_OK; +} + +SlangResult SLANG_MCALL IncludeFileSystem::loadFile(char const* path, ISlangBlob** outBlob) +{ + // Otherwise, fall back to a default implementation that uses the `core` + // libraries facilities for talking to the OS filesystem. + // + // TODO: we might want to conditionally compile these in, so that + // a user could create a build of Slang that doesn't include any OS + // filesystem calls. + // + + if (!File::Exists(path)) + { + return SLANG_E_NOT_FOUND; + } + + try + { + String sourceString = File::ReadAllText(path); + ComPtr<ISlangBlob> sourceBlob = createStringBlob(sourceString); + *outBlob = sourceBlob.detach(); + return SLANG_OK; + } + catch (...) + { + } + return SLANG_E_CANNOT_OPEN; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!! WrapFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + +SlangResult SLANG_MCALL WrapFileSystem::loadFile(char const* path, ISlangBlob** outBlob) +{ + return m_fileSystem->loadFile(path, outBlob); +} + +SlangResult WrapFileSystem::getCanoncialPath(const char* path, ISlangBlob** canonicalPathOut) +{ + String canonicalPath(path); + *canonicalPathOut = createStringBlob(canonicalPath).detach(); + return SLANG_OK; +} + +}
\ No newline at end of file diff --git a/source/slang/include-file-system.h b/source/slang/include-file-system.h new file mode 100644 index 000000000..4b34c2a0f --- /dev/null +++ b/source/slang/include-file-system.h @@ -0,0 +1,81 @@ +#ifndef SLANG_INCLUDE_FILE_SYSTEM_H_INCLUDED +#define SLANG_INCLUDE_FILE_SYSTEM_H_INCLUDED + +#include "../../slang.h" +#include "../../slang-com-helper.h" +#include "../../slang-com-ptr.h" + +namespace Slang +{ + +class IncludeFileSystem : public ISlangFileSystemExt +{ +public: + // ISlangUnknown + SLANG_IUNKNOWN_ALL + + // ISlangFileSystem + virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile( + char const* path, + ISlangBlob** outBlob) SLANG_OVERRIDE; + + // ISlangFileSystemExt + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getCanoncialPath( + const char* path, + ISlangBlob** canonicalPathOut) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcRelativePath( + SlangPathType fromPathType, + const char* fromPath, + const char* path, + ISlangBlob** pathOut) SLANG_OVERRIDE; + + /// Get a default instance + static ISlangFileSystemExt* getDefault(); + +protected: + + /// If no ref, add one to the ref + void ensureRef() { m_refCount += (m_refCount == 0); } + + ISlangUnknown* getInterface(const Guid& guid); + uint32_t m_refCount = 0; +}; + +/* Wraps an ISlangFileSystem, and provides the extra methods required to make a ISlangFileSystemExt +interface, deferring to the contained file system to do reading. + +NOTE! That this behavior is the same as previously in that.... +1) getRelativePath, just returns the path as processed by the Path:: methods +2) getCanonicalPath, just returns the input path as the 'canonical' path. This will be wrong with a file multiply referenced through paths with .. and or . but +doing it this way means it works as before and requires no new functions. +*/ +class WrapFileSystem : public IncludeFileSystem +{ +public: + // So we don't need virtual dtor + SLANG_IUNKNOWN_RELEASE + + // ISlangFileSystem + virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile( + char const* path, + ISlangBlob** outBlob) SLANG_OVERRIDE; + + // ISlangFileSystemExt + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getCanoncialPath( + const char* path, + ISlangBlob** canonicalPathOut) SLANG_OVERRIDE; + + /// Ctor + WrapFileSystem(ISlangFileSystem* fileSystem): + m_fileSystem(fileSystem) + { + } + +protected: + ComPtr<ISlangFileSystem> m_fileSystem; ///< The wrapped file system +}; + +} + +#endif
\ No newline at end of file diff --git a/source/slang/preprocessor.cpp b/source/slang/preprocessor.cpp index 98347bd0c..ca11b24e8 100644 --- a/source/slang/preprocessor.cpp +++ b/source/slang/preprocessor.cpp @@ -838,7 +838,9 @@ top: SourceManager* sourceManager = preprocessor->getCompileRequest()->getSourceManager(); // We create a dummy file to represent the token-paste operation - SourceFile* sourceFile = sourceManager->createSourceFile("token paste", sb.ProduceString()); + PathInfo pathInfo = PathInfo::makeTokenPaste(); + + SourceFile* sourceFile = sourceManager->createSourceFile(pathInfo, sb.ProduceString()); SourceView* sourceView = sourceManager->createSourceView(sourceFile); @@ -1589,10 +1591,8 @@ static void HandleIncludeDirective(PreprocessorDirectiveContext* context) auto directiveLoc = GetDirectiveLoc(context); - String pathIncludedFrom = context->preprocessor->translationUnit->compileRequest->getSourceManager()->getPath(directiveLoc, SourceLocType::Actual); - String foundPath; - ComPtr<ISlangBlob> foundSourceBlob; - + PathInfo includedFromPathInfo = context->preprocessor->translationUnit->compileRequest->getSourceManager()->getPathInfo(directiveLoc, SourceLocType::Actual); + IncludeHandler* includeHandler = context->preprocessor->includeHandler; if (!includeHandler) { @@ -1600,17 +1600,20 @@ static void HandleIncludeDirective(PreprocessorDirectiveContext* context) GetSink(context)->diagnose(pathToken.loc, Diagnostics::noIncludeHandlerSpecified); return; } - auto includeResult = includeHandler->TryToFindIncludeFile(path, pathIncludedFrom, &foundPath, foundSourceBlob.writeRef()); - - switch (includeResult) + + /* Find the path relative to the foundPath */ + PathInfo filePathInfo; + if (SLANG_FAILED(includeHandler->findFile(path, includedFromPathInfo.foundPath, filePathInfo))) { - case IncludeResult::NotFound: - case IncludeResult::Error: GetSink(context)->diagnose(pathToken.loc, Diagnostics::includeFailed, path); return; + } - case IncludeResult::Found: - break; + // We must have a canonical path to be compare + if (!filePathInfo.hasCanonicalPath()) + { + GetSink(context)->diagnose(pathToken.loc, Diagnostics::noCanonicalPath, path); + return; } // Do all checking related to the end of this directive before we push a new stream, @@ -1619,7 +1622,7 @@ static void HandleIncludeDirective(PreprocessorDirectiveContext* context) expectEndOfDirective(context); // Check whether we've previously included this file and seen a `#pragma once` directive - if(context->preprocessor->pragmaOncePaths.Contains(foundPath)) + if(context->preprocessor->pragmaOncePaths.Contains(filePathInfo.canonicalPath)) { return; } @@ -1629,12 +1632,19 @@ static void HandleIncludeDirective(PreprocessorDirectiveContext* context) auto sourceManager = context->preprocessor->getCompileRequest()->getSourceManager(); // See if this an already loaded source file - SourceFile* sourceFile = sourceManager->findSourceFile(foundPath); + SourceFile* sourceFile = sourceManager->findSourceFileRecursively(filePathInfo.canonicalPath); // If not create a new one, and add to the list of known source files if (!sourceFile) { - sourceFile = sourceManager->createSourceFile(foundPath, foundSourceBlob); - sourceManager->addSourceFile(foundPath, sourceFile); + ComPtr<ISlangBlob> foundSourceBlob; + if (SLANG_FAILED(includeHandler->readFile(filePathInfo.canonicalPath, foundSourceBlob.writeRef()))) + { + GetSink(context)->diagnose(pathToken.loc, Diagnostics::includeFailed, path); + return; + } + + sourceFile = sourceManager->createSourceFile(filePathInfo, foundSourceBlob); + sourceManager->addSourceFile(filePathInfo.canonicalPath, sourceFile); } // This is a new parse (even if it's a pre-existing source file), so create a new SourceUnit @@ -1822,7 +1832,7 @@ static void HandleLineDirective(PreprocessorDirectiveContext* context) String file; if (PeekTokenType(context) == TokenType::EndOfDirective) { - file = sourceManager->getPath(directiveLoc); + file = sourceManager->getPathInfo(directiveLoc).foundPath; } else if (PeekTokenType(context) == TokenType::StringLiteral) { @@ -1875,9 +1885,16 @@ SLANG_PRAGMA_DIRECTIVE_CALLBACK(handlePragmaOnceDirective) // trivial cases of the "same" path. // auto directiveLoc = GetDirectiveLoc(context); - auto pathIssuedFrom = context->preprocessor->translationUnit->compileRequest->getSourceManager()->getPath(directiveLoc, SourceLocType::Actual); + auto issuedFromPathInfo = context->preprocessor->translationUnit->compileRequest->getSourceManager()->getPathInfo(directiveLoc, SourceLocType::Actual); + + // Must have a canonical path for a #pragma once to work + if (!issuedFromPathInfo.hasCanonicalPath()) + { + GetSink(context)->diagnose(subDirectiveToken, Diagnostics::pragmaOnceIgnored); + return; + } - context->preprocessor->pragmaOncePaths.Add(pathIssuedFrom); + context->preprocessor->pragmaOncePaths.Add(issuedFromPathInfo.canonicalPath); } // Information about a specific `#pragma` directive @@ -2243,13 +2260,14 @@ static void DefineMacro( String const& key, String const& value) { - String fileName = "command line"; + PathInfo pathInfo = PathInfo::makeCommandLine(); + PreprocessorMacro* macro = CreateMacro(preprocessor); auto sourceManager = preprocessor->translationUnit->compileRequest->getSourceManager(); - SourceFile* keyFile = sourceManager->createSourceFile(fileName, key); - SourceFile* valueFile = sourceManager->createSourceFile(fileName, value); + SourceFile* keyFile = sourceManager->createSourceFile(pathInfo, key); + SourceFile* valueFile = sourceManager->createSourceFile(pathInfo, value); SourceView* keyView = sourceManager->createSourceView(keyFile); SourceView* valueView = sourceManager->createSourceView(valueFile); diff --git a/source/slang/preprocessor.h b/source/slang/preprocessor.h index 0e30038bf..42a3b25f4 100644 --- a/source/slang/preprocessor.h +++ b/source/slang/preprocessor.h @@ -11,22 +11,17 @@ class DiagnosticSink; class ModuleDecl; class TranslationUnitRequest; -enum class IncludeResult -{ - Error, - NotFound, - Found, -}; - // Callback interface for the preprocessor to use when looking // for files in `#include` directives. struct IncludeHandler { - virtual IncludeResult TryToFindIncludeFile( - String const& pathToInclude, - String const& pathIncludedFrom, - String* outFoundPath, - ISlangBlob** outFoundSourceBlob) = 0; + + virtual SlangResult findFile(const String& pathToInclude, + const String& pathIncludedFrom, + PathInfo& pathInfoOut) = 0; + + virtual SlangResult readFile(const String& path, + ISlangBlob** blobOut) = 0; }; // Take a string of source code and preprocess it into a list of tokens. diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index c04aaa044..908bee283 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -9,6 +9,8 @@ #include "syntax-visitors.h" #include "../slang/type-layout.h" +#include "include-file-system.h" + #include "ir-serialize.h" // Used to print exception type names in internal-compiler-error messages @@ -75,39 +77,106 @@ Session::Session() addBuiltinSource(hlslLanguageScope, "hlsl", getHLSLLibraryCode()); } +static String getString(ISlangBlob* blob) +{ + if (blob) + { + size_t size = blob->getBufferSize(); + if (size > 0) + { + const char* contents = (const char*)blob->getBufferPointer(); + // Check it has terminating 0, if not we must construct as if it does + if (contents[size - 1] == 0) + { + size --; + } + return String(contents, contents + size); + } + } + return String(); +} + struct IncludeHandlerImpl : IncludeHandler { CompileRequest* request; - virtual IncludeResult TryToFindIncludeFile( + ISlangFileSystemExt* _getFileSystemExt() + { + return request->fileSystemExt; + } + + SlangResult _findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& pathInfoOut) + { + ISlangFileSystemExt* fileSystemExt = _getFileSystemExt(); + + // Get relative path + ComPtr<ISlangBlob> relPathBlob; + SLANG_RETURN_ON_FAIL(fileSystemExt->calcRelativePath(fromPathType, fromPath.begin(), path.begin(), relPathBlob.writeRef())); + String relPath(getString(relPathBlob)); + if (relPath.Length() <= 0) + { + return SLANG_FAIL; + } + + // Get the canonical path + ComPtr<ISlangBlob> canonicalPathBlob; + SLANG_RETURN_ON_FAIL(fileSystemExt->getCanoncialPath(relPath.begin(), canonicalPathBlob.writeRef())); + + // If the rel path exists -> the canonical path MUST exists too + String canonicalPath(getString(canonicalPathBlob)); + if (canonicalPath.Length() <= 0) + { + // Canonical path can't be empty + return SLANG_FAIL; + } + + pathInfoOut.type = PathInfo::Type::Normal; + pathInfoOut.foundPath = relPath; + pathInfoOut.canonicalPath = canonicalPath; + return SLANG_OK; + } + + virtual SlangResult findFile( String const& pathToInclude, String const& pathIncludedFrom, - String* outFoundPath, - ISlangBlob** outFoundSourceBlob) override + PathInfo& pathInfoOut) override { - String path = Path::Combine(Path::GetDirectoryName(pathIncludedFrom), pathToInclude); + pathInfoOut.type = PathInfo::Type::Unknown; - if(SLANG_SUCCEEDED(request->loadFile(path, outFoundSourceBlob))) + // Try just relative to current path { - *outFoundPath = path; - request->mDependencyFilePaths.Add(path); - return IncludeResult::Found; + SlangResult res = _findFile(SLANG_PATH_TYPE_FILE, pathIncludedFrom, pathToInclude, pathInfoOut); + // It either succeeded or wasn't found, anything else is a failure passed back + if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND) + { + return res; + } } + // Search all the searchDirectories for (auto & dir : request->searchDirectories) { - path = Path::Combine(dir.path, pathToInclude); - - if(SLANG_SUCCEEDED(request->loadFile(path, outFoundSourceBlob))) + SlangResult res = _findFile(SLANG_PATH_TYPE_DIRECTORY, dir.path, pathToInclude, pathInfoOut); + if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND) { - *outFoundPath = path; - request->mDependencyFilePaths.Add(path); - return IncludeResult::Found; + return res; } } - return IncludeResult::NotFound; + return SLANG_E_NOT_FOUND; + } + + virtual SlangResult readFile(const String& path, + ISlangBlob** blobOut) override + { + ISlangFileSystem* fileSystemExt = _getFileSystemExt(); + SLANG_RETURN_ON_FAIL(fileSystemExt->loadFile(path.begin(), blobOut)); + + request->mDependencyFilePaths.Add(path); + + return SLANG_OK; } + }; // @@ -244,6 +313,10 @@ CompileRequest::CompileRequest(Session* session) setSourceManager(&sourceManagerStorage); sourceManager->initialize(session->getBuiltinSourceManager()); + + // Set up the default file system + SLANG_ASSERT(fileSystem == nullptr); + fileSystemExt = IncludeFileSystem::getDefault(); } CompileRequest::~CompileRequest() @@ -376,7 +449,7 @@ RefPtr<Expr> CompileRequest::parseTypeString(TranslationUnitRequest * translatio SourceManager localSourceManager; localSourceManager.initialize(sourceManager); - Slang::RefPtr<Slang::SourceFile> srcFile(localSourceManager.createSourceFile(String("type string"), typeStr)); + Slang::RefPtr<Slang::SourceFile> srcFile(localSourceManager.createSourceFile(PathInfo::makeTypeParse(), typeStr)); // We'll use a temporary diagnostic sink DiagnosticSink sink; @@ -706,7 +779,8 @@ void CompileRequest::addTranslationUnitSourceBlob( String const& path, ISlangBlob* sourceBlob) { - RefPtr<SourceFile> sourceFile = getSourceManager()->createSourceFile(path, sourceBlob); + PathInfo pathInfo = PathInfo::makePath(path); + RefPtr<SourceFile> sourceFile = getSourceManager()->createSourceFile(pathInfo, sourceBlob); addTranslationUnitSourceFile(translationUnitIndex, sourceFile); } @@ -716,7 +790,8 @@ void CompileRequest::addTranslationUnitSourceString( String const& path, String const& source) { - RefPtr<SourceFile> sourceFile = getSourceManager()->createSourceFile(path, source); + PathInfo pathInfo = PathInfo::makePath(path); + RefPtr<SourceFile> sourceFile = getSourceManager()->createSourceFile(pathInfo, source); addTranslationUnitSourceFile(translationUnitIndex, sourceFile); } @@ -789,13 +864,18 @@ UInt CompileRequest::addTarget( void CompileRequest::loadParsedModule( RefPtr<TranslationUnitRequest> const& translationUnit, Name* name, - String const& path) + const PathInfo& pathInfo) { // Note: we add the loaded module to our name->module listing // before doing semantic checking, so that if it tries to // recursively `import` itself, we can detect it. RefPtr<LoadedModule> loadedModule = new LoadedModule(); - mapPathToLoadedModule.Add(path, loadedModule); + + // Get a path + String mostUniquePath = pathInfo.getMostUniquePath(); + SLANG_ASSERT(mostUniquePath.Length() > 0); + + mapPathToLoadedModule.Add(mostUniquePath, loadedModule); mapNameToLoadedModules.Add(name, loadedModule); int errorCountBefore = mSink.GetErrorCount(); @@ -821,8 +901,8 @@ void CompileRequest::loadParsedModule( RefPtr<ModuleDecl> CompileRequest::loadModule( Name* name, - String const& path, - ISlangBlob* sourceBlob, + const PathInfo& filePathInfo, + ISlangBlob* sourceBlob, SourceLoc const& srcLoc) { RefPtr<TranslationUnitRequest> translationUnit = new TranslationUnitRequest(); @@ -835,11 +915,11 @@ RefPtr<ModuleDecl> CompileRequest::loadModule( // TODO: decide which options, if any, should be inherited. translationUnit->compileFlags = 0; - RefPtr<SourceFile> sourceFile = getSourceManager()->createSourceFile(path, sourceBlob); + // Create with the 'friendly' name + RefPtr<SourceFile> sourceFile = getSourceManager()->createSourceFile(filePathInfo, sourceBlob); translationUnit->sourceFiles.Add(sourceFile); - int errorCountBefore = mSink.GetErrorCount(); parseTranslationUnit(translationUnit.Ptr()); int errorCountAfter = mSink.GetErrorCount(); @@ -854,7 +934,7 @@ RefPtr<ModuleDecl> CompileRequest::loadModule( loadParsedModule( translationUnit, name, - path); + filePathInfo); errorCountAfter = mSink.GetErrorCount(); @@ -891,7 +971,7 @@ RefPtr<ModuleDecl> CompileRequest::findOrImportModule( } // Derive a file name for the module, by taking the given - // identifier, replacing all occurences of `_` with `-`, + // identifier, replacing all occurrences of `_` with `-`, // and then appending `.slang`. // // For example, `foo_bar` becomes `foo-bar.slang`. @@ -914,39 +994,37 @@ RefPtr<ModuleDecl> CompileRequest::findOrImportModule( IncludeHandlerImpl includeHandler; includeHandler.request = this; - // Get the original path - String pathIncludedFrom= getSourceManager()->getPath(loc, SourceLocType::Actual); - - String foundPath; - ComPtr<ISlangBlob> foundSourceBlob; - IncludeResult includeResult = includeHandler.TryToFindIncludeFile(fileName, pathIncludedFrom, &foundPath, foundSourceBlob.writeRef()); - switch( includeResult ) - { - case IncludeResult::NotFound: - case IncludeResult::Error: - { - this->mSink.diagnose(loc, Diagnostics::cannotFindFile, fileName); - - mapNameToLoadedModules[name] = nullptr; - return nullptr; - } - break; + // Get the original path info + PathInfo pathIncludedFromInfo = getSourceManager()->getPathInfo(loc, SourceLocType::Actual); + PathInfo filePathInfo; - default: - break; + // There is an argument to passing in the 'canonicalPath' instead of the foundPath, but either should work here + if (SLANG_FAILED(includeHandler.findFile(fileName, pathIncludedFromInfo.foundPath, filePathInfo))) + { + this->mSink.diagnose(loc, Diagnostics::cannotFindFile, fileName); + mapNameToLoadedModules[name] = nullptr; + return nullptr; } // Maybe this was loaded previously at a different relative name? - if (mapPathToLoadedModule.TryGetValue(foundPath, loadedModule)) + if (mapPathToLoadedModule.TryGetValue(filePathInfo.canonicalPath, loadedModule)) return loadedModule->moduleDecl; + // Try to load it + ComPtr<ISlangBlob> fileContents; + if (SLANG_FAILED(includeHandler.readFile(filePathInfo.canonicalPath, fileContents.writeRef()))) + { + this->mSink.diagnose(loc, Diagnostics::cannotOpenFile, fileName); + mapNameToLoadedModules[name] = nullptr; + return nullptr; + } // We've found a file that we can load for the given module, so // go ahead and perform the module-load action return loadModule( name, - foundPath, - foundSourceBlob, + filePathInfo, + fileContents, loc); } @@ -1121,13 +1199,35 @@ SLANG_API void spDestroyCompileRequest( delete req; } +static const Slang::Guid IID_ISlangFileSystemExt = SLANG_UUID_ISlangFileSystemExt; + SLANG_API void spSetFileSystem( SlangCompileRequest* request, ISlangFileSystem* fileSystem) { if(!request) return; auto req = REQ(request); + + // Set the fileSystem req->fileSystem = fileSystem; + + // Set up fileSystemExt appropriately + if (fileSystem == nullptr) + { + req->fileSystemExt = Slang::IncludeFileSystem::getDefault(); + } + else + { + // See if we have the interface + fileSystem->queryInterface(IID_ISlangFileSystemExt, (void**)req->fileSystemExt.writeRef()); + + // If not wrap with WrapFileSytem that keeps the old behavior + if (!req->fileSystemExt) + { + // Construct a wrapper to emulate the extended interface behavior + req->fileSystemExt = new Slang::WrapFileSystem(fileSystem); + } + } } diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj index db745b800..970f4f5fb 100644 --- a/source/slang/slang.vcxproj +++ b/source/slang/slang.vcxproj @@ -181,6 +181,7 @@ <ClInclude Include="expr-defs.h" /> <ClInclude Include="glsl.meta.slang.h" /> <ClInclude Include="hlsl.meta.slang.h" /> + <ClInclude Include="include-file-system.h" /> <ClInclude Include="ir-constexpr.h" /> <ClInclude Include="ir-dominators.h" /> <ClInclude Include="ir-inst-defs.h" /> @@ -230,6 +231,7 @@ <ClCompile Include="diagnostics.cpp" /> <ClCompile Include="dxc-support.cpp" /> <ClCompile Include="emit.cpp" /> + <ClCompile Include="include-file-system.cpp" /> <ClCompile Include="ir-constexpr.cpp" /> <ClCompile Include="ir-dominators.cpp" /> <ClCompile Include="ir-legalize-types.cpp" /> @@ -263,16 +265,13 @@ <ClCompile Include="vm.cpp" /> </ItemGroup> <ItemGroup> - <None Include="slang.natvis" /> - </ItemGroup> - <ItemGroup> <CustomBuild Include="core.meta.slang"> <FileType>Document</FileType> <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"../../bin/windows-x86/debug/slang-generate" %(Identity)</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-generate" %(Identity)</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-generate" %(Identity)</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-generate" %(Identity)</Command> - <Outputs>%(Identity).h</Outputs> + <Outputs>../../core.meta.slang.h</Outputs> <Message>slang-generate %(Identity)</Message> <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-generate.exe</AdditionalInputs> <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../bin/windows-x64/debug/slang-generate.exe</AdditionalInputs> @@ -285,7 +284,7 @@ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-generate" %(Identity)</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-generate" %(Identity)</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-generate" %(Identity)</Command> - <Outputs>%(Identity).h</Outputs> + <Outputs>../../hlsl.meta.slang.h</Outputs> <Message>slang-generate %(Identity)</Message> <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-generate.exe</AdditionalInputs> <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../bin/windows-x64/debug/slang-generate.exe</AdditionalInputs> @@ -294,6 +293,9 @@ </CustomBuild> </ItemGroup> <ItemGroup> + <Natvis Include="slang.natvis" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include="..\core\core.vcxproj"> <Project>{F9BE7957-8399-899E-0C49-E714FDDD4B65}</Project> </ProjectReference> diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters index a17717b2d..e8c86a372 100644 --- a/source/slang/slang.vcxproj.filters +++ b/source/slang/slang.vcxproj.filters @@ -42,6 +42,9 @@ <ClInclude Include="hlsl.meta.slang.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="include-file-system.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="ir-constexpr.h"> <Filter>Header Files</Filter> </ClInclude> @@ -185,6 +188,9 @@ <ClCompile Include="emit.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="include-file-system.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="ir-constexpr.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -280,11 +286,6 @@ </ClCompile> </ItemGroup> <ItemGroup> - <None Include="slang.natvis"> - <Filter>Source Files</Filter> - </None> - </ItemGroup> - <ItemGroup> <CustomBuild Include="core.meta.slang"> <Filter>Source Files</Filter> </CustomBuild> @@ -292,4 +293,9 @@ <Filter>Source Files</Filter> </CustomBuild> </ItemGroup> + <ItemGroup> + <Natvis Include="slang.natvis"> + <Filter>Source Files</Filter> + </Natvis> + </ItemGroup> </Project>
\ No newline at end of file diff --git a/source/slang/source-loc.cpp b/source/slang/source-loc.cpp index d6b75b909..1c3b8c70a 100644 --- a/source/slang/source-loc.cpp +++ b/source/slang/source-loc.cpp @@ -5,7 +5,19 @@ namespace Slang { -/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceUnit !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceView !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +const String PathInfo::getMostUniquePath() const +{ + switch (type) + { + case Type::Normal: return canonicalPath; + case Type::FoundPath: return foundPath; + default: return ""; + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceView !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ int SourceView::findEntryIndex(SourceLoc sourceLoc) const { @@ -136,38 +148,33 @@ HumaneSourceLoc SourceView::getHumaneLoc(SourceLoc loc, SourceLocType type) pathHandle = entry.m_pathHandle; } + humaneLoc.pathInfo = _getPathInfo(pathHandle); + return humaneLoc; +} + +PathInfo SourceView::_getPathInfo(StringSlicePool::Handle pathHandle) const +{ // If there is no override path, then just the source files path if (pathHandle == StringSlicePool::Handle(0)) { - humaneLoc.path = m_sourceFile->path; + return m_sourceFile->pathInfo; } else { - humaneLoc.path = m_sourceManager->getStringSlicePool().getSlice(pathHandle); + // We don't have a full normal path (including 'canonical') so just go with FoundPath + return PathInfo::makePath(m_sourceManager->getStringSlicePool().getSlice(pathHandle)); } - - return humaneLoc; } -String SourceView::getPath(SourceLoc loc, SourceLocType type) +PathInfo SourceView::getPathInfo(SourceLoc loc, SourceLocType type) { if (type == SourceLocType::Actual) { - return m_sourceFile->path; + return m_sourceFile->pathInfo; } const int entryIndex = findEntryIndex(loc); - const StringSlicePool::Handle pathHandle = (entryIndex >= 0) ? m_entries[entryIndex].m_pathHandle : StringSlicePool::Handle(0); - - // If there is no override path, then just the source files path - if (pathHandle == StringSlicePool::Handle(0)) - { - return m_sourceFile->path; - } - else - { - return m_sourceManager->getStringSlicePool().getSlice(pathHandle); - } + return _getPathInfo((entryIndex >= 0) ? m_entries[entryIndex].m_pathHandle : StringSlicePool::Handle(0)); } /* !!!!!!!!!!!!!!!!!!!!!!! SourceFile !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -300,28 +307,24 @@ SourceRange SourceManager::allocateSourceRange(UInt size) return SourceRange(beginLoc, endLoc); } -SourceFile* SourceManager::createSourceFile( - String const& path, - ISlangBlob* contentBlob) +SourceFile* SourceManager::createSourceFile(const PathInfo& pathInfo, ISlangBlob* contentBlob) { char const* contentBegin = (char const*) contentBlob->getBufferPointer(); UInt contentSize = contentBlob->getBufferSize(); char const* contentEnd = contentBegin + contentSize; SourceFile* sourceFile = new SourceFile(); - sourceFile->path = path; + sourceFile->pathInfo = pathInfo; sourceFile->contentBlob = contentBlob; sourceFile->content = UnownedStringSlice(contentBegin, contentEnd); return sourceFile; } - -SourceFile* SourceManager::createSourceFile( - String const& path, - String const& content) + +SourceFile* SourceManager::createSourceFile(const PathInfo& pathInfo, const String& content) { ComPtr<ISlangBlob> contentBlob = createStringBlob(content); - return createSourceFile(path, contentBlob); + return createSourceFile(pathInfo, contentBlob); } SourceView* SourceManager::createSourceView(SourceFile* sourceFile) @@ -394,13 +397,12 @@ SourceView* SourceManager::findSourceViewRecursively(SourceLoc loc) const const SourceManager* manager = this; do { - SourceView* sourceView = findSourceView(loc); + SourceView* sourceView = manager->findSourceView(loc); // If we found a hit we are done if (sourceView) { return sourceView; } - // Try the parent manager = manager->m_parent; } @@ -409,20 +411,31 @@ SourceView* SourceManager::findSourceViewRecursively(SourceLoc loc) const return nullptr; } -SourceFile* SourceManager::findSourceFile(const String& path) +SourceFile* SourceManager::findSourceFile(const String& canonicalPath) const +{ + RefPtr<SourceFile>* filePtr = m_sourceFiles.TryGetValue(canonicalPath); + return (filePtr) ? filePtr->Ptr() : nullptr; +} + +SourceFile* SourceManager::findSourceFileRecursively(const String& canonicalPath) const { - RefPtr<SourceFile>* filePtr = m_sourceFiles.TryGetValue(path); - if (filePtr) + const SourceManager* manager = this; + do { - return filePtr->Ptr(); - } - return m_parent ? m_parent->findSourceFile(path) : nullptr; + SourceFile* sourceFile = manager->findSourceFile(canonicalPath); + if (sourceFile) + { + return sourceFile; + } + manager = manager->m_parent; + } while (manager); + return nullptr; } -void SourceManager::addSourceFile(const String& path, SourceFile* sourceFile) +void SourceManager::addSourceFile(const String& canonicalPath, SourceFile* sourceFile) { - SLANG_ASSERT(!findSourceFile(path)); - m_sourceFiles.Add(path, sourceFile); + SLANG_ASSERT(!findSourceFileRecursively(canonicalPath)); + m_sourceFiles.Add(canonicalPath, sourceFile); } HumaneSourceLoc SourceManager::getHumaneLoc(SourceLoc loc, SourceLocType type) @@ -438,16 +451,16 @@ HumaneSourceLoc SourceManager::getHumaneLoc(SourceLoc loc, SourceLocType type) } } -String SourceManager::getPath(SourceLoc loc, SourceLocType type) +PathInfo SourceManager::getPathInfo(SourceLoc loc, SourceLocType type) { SourceView* sourceView = findSourceViewRecursively(loc); if (sourceView) { - return sourceView->getPath(loc, type); + return sourceView->getPathInfo(loc, type); } else { - return String("unknown"); + return PathInfo::makeUnknown(); } } diff --git a/source/slang/source-loc.h b/source/slang/source-loc.h index 48b7791c7..8f6b8f7cb 100644 --- a/source/slang/source-loc.h +++ b/source/slang/source-loc.h @@ -38,6 +38,40 @@ SourceViews are created, with unique SourceRanges. This is so that it is possibl interpretation for that lex/parse. */ +struct PathInfo +{ + /// To be more rigorous about where a path comes from, the type identifies what a paths origin is + enum class Type + { + Unknown, ///< The path is not known + Normal, ///< Normal has both path and canonical path + FoundPath, ///< Just has a found path (canonical path is unknown, or even 'unknowable') + TokenPaste, ///< No paths, just created to do a macro expansion + TypeParse, ///< No path, just created to do a type parse + CommandLine, ///< A macro constructed from the command line + }; + + /// True if has a canonical path + SLANG_FORCE_INLINE bool hasCanonicalPath() const { return type == Type::Normal && canonicalPath.Length() > 0; } + /// True if has a regular found path + SLANG_FORCE_INLINE bool hasFoundPath() const { return type == Type::Normal || type == Type::FoundPath; } + + /// The canonical path is unique, so return that if we have it. If not the regular path, otherwise the empty string. + const String getMostUniquePath() const; + + // So simplify construction. In normal usage it's safer to use make methods over constructing directly. + static PathInfo makeUnknown() { return PathInfo { Type::Unknown, "unknown" }; } + static PathInfo makeTokenPaste() { return PathInfo{ Type::TokenPaste, "token paste" }; } + static PathInfo makeNormal(const String& foundPathIn, const String& canonicalPathIn) { SLANG_ASSERT(canonicalPathIn.Length() > 0 && foundPathIn.Length() > 0); return PathInfo { Type::Normal, foundPathIn, canonicalPathIn }; } + static PathInfo makePath(const String& pathIn) { SLANG_ASSERT(pathIn.Length() > 0); return PathInfo { Type::FoundPath, pathIn }; } + static PathInfo makeTypeParse() { return PathInfo { Type::TypeParse, "type string" }; } + static PathInfo makeCommandLine() { return PathInfo { Type::CommandLine, "command line" }; } + + Type type; ///< The type of path + String foundPath; ///< The path where the file was found (might contain relative elements) + String canonicalPath; ///< Canonical version of the found path +}; + class SourceLoc { public: @@ -121,7 +155,7 @@ public: /// Calculate the offset for a line int calcColumnIndex(int line, int offset); - String path; ///< The logical file path to report for locations inside this span. + PathInfo pathInfo; ///< The path The logical file path to report for locations inside this span. ComPtr<ISlangBlob> contentBlob; ///< A blob that owns the storage for the file contents UnownedStringSlice content; ///< The actual contents of the file. @@ -141,7 +175,7 @@ enum class SourceLocType // A source location in a format a human might like to see struct HumaneSourceLoc { - String path; + PathInfo pathInfo; Int line = 0; Int column = 0; }; @@ -200,7 +234,7 @@ class SourceView: public RefObject HumaneSourceLoc getHumaneLoc(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); /// Get the path associated with a location - String getPath(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); + PathInfo getPathInfo(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); /// Ctor SourceView(SourceManager* sourceManager, SourceFile* sourceFile, SourceRange range): @@ -211,7 +245,8 @@ class SourceView: public RefObject } protected: - + PathInfo _getPathInfo(StringSlicePool::Handle pathHandle) const; + SourceManager* m_sourceManager; /// Get the manager this belongs to SourceRange m_range; ///< The range that this SourceView applies to RefPtr<SourceFile> m_sourceFile; ///< The source file can hold the line breaks @@ -227,15 +262,15 @@ struct SourceManager SourceRange allocateSourceRange(UInt size); /// Create a SourceFile defined with the specified path, and content held within a blob - SourceFile* createSourceFile(String const& path, ISlangBlob* content); + SourceFile* createSourceFile(const PathInfo& pathInfo, ISlangBlob* content); /// Create a SourceFile with specified path. Create a Blob that contains the content. - SourceFile* createSourceFile(String const& path, String const& content); + SourceFile* createSourceFile(const PathInfo& pathInfo, String const& content); /// Get the humane source location HumaneSourceLoc getHumaneLoc(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); /// Get the path associated with a location - String getPath(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); + PathInfo getPathInfo(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); /// Create a new source view from a file SourceView* createSourceView(SourceFile* sourceFile); @@ -251,10 +286,12 @@ struct SourceManager /// Searches this manager, and then the parent to see if can find a match for path. /// If not found returns nullptr. - SourceFile* findSourceFile(const String& path); + SourceFile* findSourceFileRecursively(const String& canonicalPath) const; + /// Find if the source file is defined on this manager. + SourceFile* findSourceFile(const String& canonicalPath) const; /// Add a source file, path must be unique for this manager AND any parents - void addSourceFile(const String& path, SourceFile* sourceFile); + void addSourceFile(const String& canonicalPath, SourceFile* sourceFile); /// Get the slice pool StringSlicePool& getStringSlicePool() { return m_slicePool; } @@ -283,7 +320,8 @@ struct SourceManager List<RefPtr<SourceView> > m_sourceViews; StringSlicePool m_slicePool; - Dictionary<String, RefPtr<SourceFile> > m_sourceFiles; + // Maps canonical paths to source files + Dictionary<String, RefPtr<SourceFile> > m_sourceFiles; }; } // namespace Slang |
