summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2018-10-16 18:49:11 -0400
committerGitHub <noreply@github.com>2018-10-16 18:49:11 -0400
commit3e74d39f24fdfaa547ce900be177863e2bfe2dea (patch)
tree9a5143e6de4caa27b23fc870003011e96129905f /source/slang
parent204fb3c75b520a2cbb1c25f995a8c424ec2753f3 (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.cpp5
-rw-r--r--source/slang/compiler.h12
-rw-r--r--source/slang/diagnostic-defs.h3
-rw-r--r--source/slang/diagnostics.cpp2
-rw-r--r--source/slang/emit.cpp11
-rw-r--r--source/slang/include-file-system.cpp101
-rw-r--r--source/slang/include-file-system.h81
-rw-r--r--source/slang/preprocessor.cpp62
-rw-r--r--source/slang/preprocessor.h19
-rw-r--r--source/slang/slang.cpp196
-rw-r--r--source/slang/slang.vcxproj12
-rw-r--r--source/slang/slang.vcxproj.filters16
-rw-r--r--source/slang/source-loc.cpp95
-rw-r--r--source/slang/source-loc.h58
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