From 634522da69b14b38c15b14d6b717b1289812e9bb Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Mon, 19 Jun 2017 08:47:23 -0700 Subject: Allow for automatic importing of Slang code The basic idea of this change is that user code can just write: #include "foo.h" and then if `foo.h` gets found in a list of registered directories for "auto-import," then it actually gets interpreted as if the user had writte, more or less: __import foo; That is, the code in `foo.h` will be treated as Slang, and will be fully parsed and checked (no matter what the source language had been), and the scoping rules will be those of `__import` instead of `#include`. This is a really big hammer, and I could imagine it smashing fingers if used poorly. I'm not sure this feature will pan out, but we need to try things to know. One big piece of that that I'll likely keep in either case is an overhaul of command-line options parsing for `slangc`. In particular, this logic has been moved into the core `slang` library (so that users can just pass options in via the API), and it is all done on UTF-8 strings rather than wide strings (which was always going to be Windows-specific). --- source/slang/slang.cpp | 172 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 125 insertions(+), 47 deletions(-) (limited to 'source/slang/slang.cpp') diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index ce48f9032..5ec530592 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -130,9 +130,9 @@ struct CompileRequest { CompileRequest* request; - List searchDirs; + List searchDirs; - virtual bool TryToFindIncludeFile( + virtual IncludeResult TryToFindIncludeFile( String const& pathToInclude, String const& pathIncludedFrom, String* outFoundPath, @@ -146,12 +146,26 @@ struct CompileRequest request->mDependencyFilePaths.Add(path); - return true; + // HACK(tfoley): We might have found the file in the same directory, + // but what if this is also inside an auto-import path? + for (auto & dir : searchDirs) + { + // Only consider auto-import paths + if(dir.kind != SearchDirectory::Kind::AutoImport) + continue; + + String otherPath = Path::Combine(dir.path, pathToInclude); + + if(otherPath == path) + return IncludeResult::FoundAutoImportFile; + } + + return IncludeResult::FoundIncludeFile; } for (auto & dir : searchDirs) { - path = Path::Combine(dir, pathToInclude); + path = Path::Combine(dir.path, pathToInclude); if (File::Exists(path)) { *outFoundPath = path; @@ -159,10 +173,17 @@ struct CompileRequest request->mDependencyFilePaths.Add(path); - return true; + switch( dir.kind ) + { + case SearchDirectory::Kind::Default: + return IncludeResult::FoundIncludeFile; + + case SearchDirectory::Kind::AutoImport: + return IncludeResult::FoundAutoImportFile; + } } } - return false; + return IncludeResult::NotFound; } }; @@ -205,9 +226,9 @@ struct CompileRequest { auto sourceFilePath = sourceFile->path; - auto searchDirs = options.SearchDirectories; + auto searchDirs = options.searchDirectories; searchDirs.Reverse(); - searchDirs.Add(Path::GetDirectoryName(sourceFilePath)); + searchDirs.Add(SearchDirectory(Path::GetDirectoryName(sourceFilePath), SearchDirectory::Kind::Default)); searchDirs.Reverse(); includeHandler.searchDirs = searchDirs; @@ -219,7 +240,8 @@ struct CompileRequest mResult.GetErrorWriter(), &includeHandler, preprocessorDefinitions, - translationUnitSyntax.Ptr()); + translationUnitSyntax.Ptr(), + this); parseSourceFile( translationUnitSyntax.Ptr(), @@ -448,6 +470,63 @@ struct CompileRequest Dictionary> loadedModules; + RefPtr loadModule( + String const& name, + String const& path, + String const& source, + CodePosition const& loc) + { + // now we need to try compiling it, etc. + + // We don't want to use the same options that the user specified + // for loading modules on-demand. In particular, we always want + // semantic checking to be enabled. + CompileOptions moduleOptions; + moduleOptions.searchDirectories = Options.searchDirectories; + moduleOptions.profile = Options.profile; + + RefPtr sourceFile = new SourceFile(); + sourceFile->path = path; + sourceFile->content = source; + + TranslationUnitOptions translationUnitOptions; + translationUnitOptions.sourceFiles.Add(sourceFile); + + CompileUnit translationUnit = parseTranslationUnit(translationUnitOptions, moduleOptions); + + // TODO: handle errors + + checkTranslationUnit(translationUnit, moduleOptions); + + // Skip code generation + + // + + RefPtr moduleDecl = translationUnit.SyntaxNode; + + loadedModules.Add(name, moduleDecl); + + return moduleDecl; + + } + + String autoImportModule( + String const& path, + String const& source, + CodePosition const& loc) + { + // TODO: may want to have some kind of canonicalization step here + String name = path; + + // Have we already loaded a module matching this name? + if (loadedModules.TryGetValue(name)) + return name; + + loadModule(name, path, source, loc); + + return name; + } + RefPtr findOrImportModule( String const& name, CodePosition const& loc) @@ -486,47 +565,30 @@ struct CompileRequest String foundPath; String foundSource; - bool found = includeHandler.TryToFindIncludeFile(fileName, pathIncludedFrom, &foundPath, &foundSource); - if (!found) + IncludeResult includeResult = includeHandler.TryToFindIncludeFile(fileName, pathIncludedFrom, &foundPath, &foundSource); + switch( includeResult ) { - this->mSink.diagnose(loc, Diagnostics::cannotFindFile, fileName); + case IncludeResult::NotFound: + case IncludeResult::Error: + { + this->mSink.diagnose(loc, Diagnostics::cannotFindFile, fileName); + + loadedModules[name] = nullptr; + return nullptr; + } + break; - loadedModules[name] = nullptr; - return nullptr; + default: + break; } // We've found a file that we can load for the given module, so - // now we need to try compiling it, etc. - - // We don't want to use the same options that the user specified - // for loading modules on-demand. In particular, we always want - // semantic checking to be enabled. - CompileOptions moduleOptions; - moduleOptions.SearchDirectories = Options.SearchDirectories; - moduleOptions.profile = Options.profile; - - RefPtr sourceFile = new SourceFile(); - sourceFile->path = foundPath; - sourceFile->content = foundSource; - - TranslationUnitOptions translationUnitOptions; - translationUnitOptions.sourceFiles.Add(sourceFile); - - CompileUnit translationUnit = parseTranslationUnit(translationUnitOptions, moduleOptions); - - // TODO: handle errors - - checkTranslationUnit(translationUnit, moduleOptions); - - // Skip code generation - - // - - moduleDecl = translationUnit.SyntaxNode; - - loadedModules.Add(name, moduleDecl); - - return moduleDecl; + // go ahead and perform the module-load action + return loadModule( + name, + foundPath, + foundSource, + loc); } }; @@ -539,6 +601,15 @@ RefPtr findOrImportModule( return request->findOrImportModule(name, loc); } +String autoImportModule( + CompileRequest* request, + String const& path, + String const& source, + CodePosition const& loc) +{ + return request->autoImportModule(path, source, loc); +} + void Session::addBuiltinSource( RefPtr const& scope, String const& path, @@ -687,9 +758,16 @@ SLANG_API void spSetDiagnosticCallback( SLANG_API void spAddSearchPath( SlangCompileRequest* request, - const char* searchDir) + const char* path) +{ + REQ(request)->Options.searchDirectories.Add(Slang::SearchDirectory(path, Slang::SearchDirectory::Kind::Default)); +} + +SLANG_API void spAddAutoImportPath( + SlangCompileRequest* request, + const char* path) { - REQ(request)->Options.SearchDirectories.Add(searchDir); + REQ(request)->Options.searchDirectories.Add(Slang::SearchDirectory(path, Slang::SearchDirectory::Kind::AutoImport)); } SLANG_API void spAddPreprocessorDefine( -- cgit v1.2.3