From d81c347e0edcbbf181885baf2b13978c28dfc9a8 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Mon, 12 Jun 2017 12:26:12 -0700 Subject: First pass at support for cross-compilation This is a large change that contains many pieces: - Update the `cross-compile0` test to actually make use of cross compilation. Now the `cross-compile0.hlsl` file contains both HLSL and GLSL source code, and then imports code from `cross-compile0.slang`, which provides a "library" (one function) that can be shared between both the HLSL and GLSL version of things. - Fixed a bug in the support for backslash-escaped newlines. - Added a new `__import` declaration type (replaces the `using` directive that was still around in a vestigial form) An `__import` causes the compiler to look for a Slang source file (currently using the ordinary `#include` lookup logic), and then parse/check the found file as an additional module ("translation unit"), before making its declarations visible in the current scope. - Refactored the main compilation flow to be simpler. There were the `ShaderCompiler` and `ShaderCompilerImpl` classes that weren't relaly doing anything, but added complexity to the whole workflow. - The `render-test` application has been heavily modified to better support testing cross-compilation workflows. At the most basic level we are starting to distinguish pass-through vs. rewriter workflows, and are passing various `#define`s down to the compiler(s) to let the source code be customized as needed for each case. Several annoying corner cases are caused here by having to support the GLSL compilation model, which really wants each entry point in its own specific translation unit, whereas we really want to keep things nicely contained in single files. - Added support for `__intrinsic` operations to have target-specific behavior. This allows a function to be given a different name for some specific target (so a call gets emitted as a call to that other operation). More generally, the library writer can put together an arbitrary format string that will be used in place of expressions that call the given function, e.g.: __intrinsic(hlsl, "$1 - $0") __intrinsic int foo(int a, int b); Given this declaration, a call like `foo(x,y)` will code generate as `x - y` for HLSL, and as `foo(x,y)` for all other targets. Annoying things still to be dealt with: - The way that I'm filtering the user-provided options when passing things down to the compilation of dynamically loaded modules is a bit ad hoc. It would be good to have a systematic notion of which options will be inherited and which won't. There is also more code duplication than I'd like, so we risk having the compiler behave differently when compiling a file at the top level, vs. because of `__import`. - Adding target-specific behavior to intrinsics is all well and good, but the current approach means we can only add this to the original declaration, which limits the ability to easily extend the set of targets. A better approach long-term would be to add a more robust notion of target-based overload resolution (which would happen after semantic checking). Then one mechanism would be used to find the right target-specific overload to use for an operation, and then each (target-specific) definition could use a simpler attribute to intercept code-generation behavior. Note that we might eventually need a similar notion to deal with stage- or profile-specific functions and the overloading behavior around them, so using this for intrinsics doesn't seem like a bad idea. --- source/slang/slang.cpp | 792 ++++++++++++++++++++++++++++++------------------- 1 file changed, 485 insertions(+), 307 deletions(-) (limited to 'source/slang/slang.cpp') diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 2f37981c5..1de94bb14 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -2,9 +2,11 @@ #include "../core/slang-io.h" #include "../slang/slang-stdlib.h" +#include "parameter-binding.h" #include "../slang/parser.h" #include "../slang/preprocessor.h" #include "../slang/reflection.h" +#include "syntax-visitors.h" #include "../slang/type-layout.h" #ifdef _WIN32 @@ -19,128 +21,142 @@ using namespace CoreLib::Basic; using namespace CoreLib::IO; using namespace Slang::Compiler; -namespace SlangLib +namespace Slang { +namespace Compiler { + +static void stdlibDiagnosticCallback( + char const* message, + void* userData) { - static void stdlibDiagnosticCallback( - char const* message, - void* userData) - { - fputs(message, stderr); - fflush(stderr); + fputs(message, stderr); + fflush(stderr); #ifdef WIN32 - OutputDebugStringA(message); + OutputDebugStringA(message); #endif - } +} - class Session - { - public: - bool useCache = false; - CoreLib::String cacheDir; +class Session +{ +public: + bool useCache = false; + CoreLib::String cacheDir; - RefPtr compiler; + RefPtr slangLanguageScope; + RefPtr hlslLanguageScope; + RefPtr glslLanguageScope; - RefPtr slangLanguageScope; - RefPtr hlslLanguageScope; - RefPtr glslLanguageScope; + List> loadedModuleCode; - List> loadedModuleCode; + Session(bool /*pUseCache*/, CoreLib::String /*pCacheDir*/) + { + // Initialize global state + // TODO: move this into the session instead + BasicExpressionType::Init(); - Session(bool /*pUseCache*/, CoreLib::String /*pCacheDir*/) - { - compiler = CreateShaderCompiler(); + // Create scopes for various language builtins. + // + // TODO: load these on-demand to avoid parsing + // stdlib code for languages the user won't use. - // Create scopes for various language builtins. - // - // TODO: load these on-demand to avoid parsing - // stdlib code for languages the user won't use. + slangLanguageScope = new Scope(); - slangLanguageScope = new Scope(); + hlslLanguageScope = new Scope(); + hlslLanguageScope->parent = slangLanguageScope; - hlslLanguageScope = new Scope(); - hlslLanguageScope->parent = slangLanguageScope; + glslLanguageScope = new Scope(); + glslLanguageScope->parent = slangLanguageScope; - glslLanguageScope = new Scope(); - glslLanguageScope->parent = slangLanguageScope; + addBuiltinSource(slangLanguageScope, "stdlib", SlangStdLib::GetCode()); + addBuiltinSource(glslLanguageScope, "glsl", getGLSLLibraryCode()); + } - addBuiltinSource(slangLanguageScope, "stdlib", SlangStdLib::GetCode()); - addBuiltinSource(glslLanguageScope, "glsl", getGLSLLibraryCode()); - } + ~Session() + { + // We need to clean up the strings for the standard library + // code that we might have allocated and loaded into static + // variables (TODO: don't use `static` variables for this stuff) - ~Session() - { - // We need to clean up the strings for the standard library - // code that we might have allocated and loaded into static - // variables (TODO: don't use `static` variables for this stuff) + SlangStdLib::Finalize(); - SlangStdLib::Finalize(); + // Ditto for our type represnetation stuff - // Ditto for our type represnetation stuff + ExpressionType::Finalize(); + } - ExpressionType::Finalize(); - } + CompileUnit createPredefUnit() + { + CompileUnit translationUnit; - CompileUnit createPredefUnit() - { - CompileUnit translationUnit; + RefPtr translationUnitSyntax = new ProgramSyntaxNode(); - RefPtr translationUnitSyntax = new ProgramSyntaxNode(); + TranslationUnitOptions translationUnitOptions; + translationUnit.options = translationUnitOptions; + translationUnit.SyntaxNode = translationUnitSyntax; - TranslationUnitOptions translationUnitOptions; - translationUnit.options = translationUnitOptions; - translationUnit.SyntaxNode = translationUnitSyntax; + return translationUnit; + } - return translationUnit; - } + void addBuiltinSource( + RefPtr const& scope, + String const& path, + String const& source); +}; - void addBuiltinSource( - RefPtr const& scope, - String const& path, - String const& source); - }; +struct CompileRequest +{ + // Pointer to parent session + Session* mSession; - struct CompileRequest - { - // Pointer to parent session - Session* mSession; + // Input options + CompileOptions Options; + + // Output stuff + DiagnosticSink mSink; + String mDiagnosticOutput; - // Input options - CompileOptions Options; + RefPtr mCollectionOfTranslationUnits; - // Output stuff - DiagnosticSink mSink; - String mDiagnosticOutput; + RefPtr mReflectionData; - RefPtr mCollectionOfTranslationUnits; + CompileResult mResult; - RefPtr mReflectionData; + List mDependencyFilePaths; - CompileResult mResult; + CompileRequest(Session* session) + : mSession(session) + {} - List mDependencyFilePaths; + ~CompileRequest() + {} - CompileRequest(Session* session) - : mSession(session) - {} + struct IncludeHandlerImpl : IncludeHandler + { + CompileRequest* request; - ~CompileRequest() - {} + List searchDirs; - struct IncludeHandlerImpl : IncludeHandler + virtual bool TryToFindIncludeFile( + CoreLib::String const& pathToInclude, + CoreLib::String const& pathIncludedFrom, + CoreLib::String* outFoundPath, + CoreLib::String* outFoundSource) override { - CompileRequest* request; + String path = Path::Combine(Path::GetDirectoryName(pathIncludedFrom), pathToInclude); + if (File::Exists(path)) + { + *outFoundPath = path; + *outFoundSource = File::ReadAllText(path); + + request->mDependencyFilePaths.Add(path); - List searchDirs; + return true; + } - virtual bool TryToFindIncludeFile( - CoreLib::String const& pathToInclude, - CoreLib::String const& pathIncludedFrom, - CoreLib::String* outFoundPath, - CoreLib::String* outFoundSource) override + for (auto & dir : searchDirs) { - String path = Path::Combine(Path::GetDirectoryName(pathIncludedFrom), pathToInclude); + path = Path::Combine(dir, pathToInclude); if (File::Exists(path)) { *outFoundPath = path; @@ -150,303 +166,453 @@ namespace SlangLib return true; } + } + return false; + } + }; - for (auto & dir : searchDirs) - { - path = Path::Combine(dir, pathToInclude); - if (File::Exists(path)) - { - *outFoundPath = path; - *outFoundSource = File::ReadAllText(path); - request->mDependencyFilePaths.Add(path); + CompileUnit parseTranslationUnit( + TranslationUnitOptions const& translationUnitOptions, + CompileOptions& options) + { + IncludeHandlerImpl includeHandler; + includeHandler.request = this; - return true; - } - } - return false; - } - }; + CompileUnit translationUnit; + + RefPtr languageScope; + switch (translationUnitOptions.sourceLanguage) + { + case SourceLanguage::HLSL: + languageScope = mSession->hlslLanguageScope; + break; + + case SourceLanguage::GLSL: + languageScope = mSession->glslLanguageScope; + break; + + case SourceLanguage::Slang: + default: + languageScope = mSession->slangLanguageScope; + break; + } + Dictionary preprocessorDefinitions; + for(auto& def : options.preprocessorDefinitions) + preprocessorDefinitions.Add(def.Key, def.Value); + for(auto& def : translationUnitOptions.preprocessorDefinitions) + preprocessorDefinitions.Add(def.Key, def.Value); - CompileUnit parseTranslationUnit( - TranslationUnitOptions const& translationUnitOptions) + RefPtr translationUnitSyntax = new ProgramSyntaxNode(); + + for (auto sourceFile : translationUnitOptions.sourceFiles) { - auto& options = Options; + auto sourceFilePath = sourceFile->path; + + auto searchDirs = options.SearchDirectories; + searchDirs.Reverse(); + searchDirs.Add(Path::GetDirectoryName(sourceFilePath)); + searchDirs.Reverse(); + includeHandler.searchDirs = searchDirs; + + String source = sourceFile->content; + + auto tokens = preprocessSource( + source, + sourceFilePath, + mResult.GetErrorWriter(), + &includeHandler, + preprocessorDefinitions, + translationUnitSyntax.Ptr()); + + parseSourceFile( + translationUnitSyntax.Ptr(), + options, + tokens, + mResult.GetErrorWriter(), + sourceFilePath, + languageScope); + } - IncludeHandlerImpl includeHandler; - includeHandler.request = this; + translationUnit.options = translationUnitOptions; + translationUnit.SyntaxNode = translationUnitSyntax; - CompileUnit translationUnit; + return translationUnit; + } - RefPtr languageScope; - switch( translationUnitOptions.sourceLanguage ) - { - case SourceLanguage::HLSL: - languageScope = mSession->hlslLanguageScope; - break; - - case SourceLanguage::GLSL: - languageScope = mSession->glslLanguageScope; - break; - - case SourceLanguage::Slang: - default: - languageScope = mSession->slangLanguageScope; - break; - } + CompileUnit parseTranslationUnit( + TranslationUnitOptions const& translationUnitOptions) + { + return parseTranslationUnit(translationUnitOptions, Options); + } + void checkTranslationUnit( + CompileUnit& translationUnit, + RefPtr visitor) + { + visitor->setSourceLanguage(translationUnit.options.sourceLanguage); + translationUnit.SyntaxNode->Accept(visitor.Ptr()); + } - auto& preprocesorDefinitions = options.PreprocessorDefinitions; + void checkTranslationUnit( + CompileUnit& translationUnit, + CompileOptions& options) + { + RefPtr visitor = CreateSemanticsVisitor( + mResult.GetErrorWriter(), + options, + this); - RefPtr translationUnitSyntax = new ProgramSyntaxNode(); + checkTranslationUnit(translationUnit, visitor); + } - for( auto sourceFile : translationUnitOptions.sourceFiles ) - { - auto sourceFilePath = sourceFile->path; + void checkCollectionOfTranslationUnits( + RefPtr collectionOfTranslationUnits) + { + RefPtr visitor = CreateSemanticsVisitor( + mResult.GetErrorWriter(), + Options, + this); + + for( auto& translationUnit : collectionOfTranslationUnits->translationUnits ) + { + checkTranslationUnit(translationUnit, visitor); + } + } - auto searchDirs = options.SearchDirectories; - searchDirs.Reverse(); - searchDirs.Add(Path::GetDirectoryName(sourceFilePath)); - searchDirs.Reverse(); - includeHandler.searchDirs = searchDirs; + void generateOutputForCollectionOfTranslationUnits( + RefPtr collectionOfTranslationUnits) + { + // Do binding generation, and then reflection (globally) + // before we move on to any code-generation activites. + GenerateParameterBindings(collectionOfTranslationUnits.Ptr()); - String source = sourceFile->content; - auto tokens = preprocessSource( - source, - sourceFilePath, - mResult.GetErrorWriter(), - &includeHandler, - preprocesorDefinitions, - translationUnitSyntax.Ptr()); - - parseSourceFile( - translationUnitSyntax.Ptr(), - options, - tokens, - mResult.GetErrorWriter(), - sourceFilePath, - languageScope); - } + // HACK(tfoley): for right now I just want to pretty-print an AST + // into another language, so the whole compiler back-end is just + // getting in the way. + // + // I'm going to bypass it for now and see what I can do: - translationUnit.options = translationUnitOptions; - translationUnit.SyntaxNode = translationUnitSyntax; + ExtraContext extra; + extra.options = &Options; + extra.programLayout = collectionOfTranslationUnits->layout.Ptr(); + extra.compileResult = &mResult; - return translationUnit; - } + generateOutput(extra, collectionOfTranslationUnits.Ptr()); + } - int executeCompilerDriverActions() + int executeCompilerDriverActions() + { + // If we are being asked to do pass-through, then we need to do that here... + if (Options.passThrough != PassThroughMode::None) { - // If we are being asked to do pass-through, then we need to do that here... - if (Options.passThrough != PassThroughMode::None) + for (auto& translationUnitOptions : Options.translationUnits) { - for( auto& translationUnitOptions : Options.translationUnits ) + switch (translationUnitOptions.sourceLanguage) { - switch( translationUnitOptions.sourceLanguage ) - { // We can pass-through code written in a native shading language - case SourceLanguage::GLSL: - case SourceLanguage::HLSL: - break; + case SourceLanguage::GLSL: + case SourceLanguage::HLSL: + break; // All other translation units need to be skipped - default: - continue; - } - - auto sourceFile = translationUnitOptions.sourceFiles[0]; - auto sourceFilePath = sourceFile->path; - String source = sourceFile->content; - - mSession->compiler->PassThrough( - source, - sourceFilePath, - Options, - translationUnitOptions); + default: + continue; } - return 0; - } - // TODO: load the stdlib + auto sourceFile = translationUnitOptions.sourceFiles[0]; + auto sourceFilePath = sourceFile->path; + String source = sourceFile->content; - mCollectionOfTranslationUnits = new CollectionOfTranslationUnits(); + auto translationUnitResult = passThrough( + source, + sourceFilePath, + Options, + translationUnitOptions); - // Parse everything from the input files requested - // - // TODO: this may trigger the loading and/or compilation of additional modules. - for( auto& translationUnitOptions : Options.translationUnits ) - { - auto translationUnit = parseTranslationUnit(translationUnitOptions); - mCollectionOfTranslationUnits->translationUnits.Add(translationUnit); + mResult.translationUnits.Add(translationUnitResult); } - if( mResult.GetErrorCount() != 0 ) - return 1; - - // Now perform semantic checks, emit output, etc. - mSession->compiler->Compile( - mResult, mCollectionOfTranslationUnits.Ptr(), Options); - if(mResult.GetErrorCount() != 0) - return 1; - - mReflectionData = mCollectionOfTranslationUnits->layout; - return 0; } - // Act as expected of the API-based compiler - int executeAPIActions() - { - mResult.mSink = &mSink; - - int err = executeCompilerDriverActions(); + // TODO: load the stdlib - mDiagnosticOutput = mSink.outputBuffer.ProduceString(); + mCollectionOfTranslationUnits = new CollectionOfTranslationUnits(); - if(mSink.GetErrorCount() != 0) - return mSink.GetErrorCount(); - - return err; + // Parse everything from the input files requested + // + // TODO: this may trigger the loading and/or compilation of additional modules. + for (auto& translationUnitOptions : Options.translationUnits) + { + auto translationUnit = parseTranslationUnit(translationUnitOptions); + mCollectionOfTranslationUnits->translationUnits.Add(translationUnit); } + if (mResult.GetErrorCount() != 0) + return 1; - int addTranslationUnit(SourceLanguage language, String const& name) - { - int result = Options.translationUnits.Count(); + // Perform semantic checking on the whole collection + checkCollectionOfTranslationUnits(mCollectionOfTranslationUnits); + if (mResult.GetErrorCount() != 0) + return 1; - TranslationUnitOptions translationUnit; - translationUnit.sourceLanguage = SourceLanguage(language); + // Generate output code, in whatever format was requested + generateOutputForCollectionOfTranslationUnits(mCollectionOfTranslationUnits); + if (mResult.GetErrorCount() != 0) + return 1; - Options.translationUnits.Add(translationUnit); + // Extract the reflection layout information so that users + // can easily query it. + mReflectionData = mCollectionOfTranslationUnits->layout; - return result; - } + return 0; + } - void addTranslationUnitSourceString( - int translationUnitIndex, - String const& path, - String const& source) - { - RefPtr sourceFile = new SourceFile(); - sourceFile->path = path; - sourceFile->content = source; + // Act as expected of the API-based compiler + int executeAPIActions() + { + mResult.mSink = &mSink; - Options.translationUnits[translationUnitIndex].sourceFiles.Add(sourceFile); - } + int err = executeCompilerDriverActions(); - void addTranslationUnitSourceFile( - int translationUnitIndex, - String const& path) - { - String source; - try - { - source = File::ReadAllText(path); - } - catch( ... ) - { - // Emit a diagnostic! - mSink.diagnose( - CodePosition(0,0,0,path), - Diagnostics::cannotOpenFile, - path); - return; - } + mDiagnosticOutput = mSink.outputBuffer.ProduceString(); - addTranslationUnitSourceString( - translationUnitIndex, - path, - source); + if (mSink.GetErrorCount() != 0) + return mSink.GetErrorCount(); - mDependencyFilePaths.Add(path); - } + return err; + } - int addTranslationUnitEntryPoint( - int translationUnitIndex, - String const& name, - Profile profile) - { - EntryPointOption entryPoint; - entryPoint.name = name; - entryPoint.profile = profile; + int addTranslationUnit(SourceLanguage language, String const& name) + { + int result = Options.translationUnits.Count(); - // TODO: realistically want this to be global across all TUs... - int result = Options.translationUnits[translationUnitIndex].entryPoints.Count(); + TranslationUnitOptions translationUnit; + translationUnit.sourceLanguage = SourceLanguage(language); - Options.translationUnits[translationUnitIndex].entryPoints.Add(entryPoint); - return result; - } - }; + Options.translationUnits.Add(translationUnit); - void Session::addBuiltinSource( - RefPtr const& scope, - String const& path, - String const& source) + return result; + } + + void addTranslationUnitSourceString( + int translationUnitIndex, + String const& path, + String const& source) { - CompileRequest compileRequest(this); + RefPtr sourceFile = new SourceFile(); + sourceFile->path = path; + sourceFile->content = source; - auto translationUnitIndex = compileRequest.addTranslationUnit(SourceLanguage::Slang, path); + Options.translationUnits[translationUnitIndex].sourceFiles.Add(sourceFile); + } - compileRequest.addTranslationUnitSourceString( + void addTranslationUnitSourceFile( + int translationUnitIndex, + String const& path) + { + String source; + try + { + source = File::ReadAllText(path); + } + catch (...) + { + // Emit a diagnostic! + mSink.diagnose( + CodePosition(0, 0, 0, path), + Diagnostics::cannotOpenFile, + path); + return; + } + + addTranslationUnitSourceString( translationUnitIndex, path, source); - int err = compileRequest.executeAPIActions(); - if(err) - { - fprintf(stderr, "%s", compileRequest.mDiagnosticOutput.Buffer()); + mDependencyFilePaths.Add(path); + } -#ifdef _WIN32 - OutputDebugStringA(compileRequest.mDiagnosticOutput.Buffer()); -#endif + int addTranslationUnitEntryPoint( + int translationUnitIndex, + String const& name, + Profile profile) + { + EntryPointOption entryPoint; + entryPoint.name = name; + entryPoint.profile = profile; - assert(!"error in stdlib"); - } + // TODO: realistically want this to be global across all TUs... + int result = Options.translationUnits[translationUnitIndex].entryPoints.Count(); + + Options.translationUnits[translationUnitIndex].entryPoints.Add(entryPoint); + return result; + } - // Extract the AST for the code we just parsed - auto syntax = compileRequest.mCollectionOfTranslationUnits->translationUnits[translationUnitIndex].SyntaxNode; + Dictionary> loadedModules; - // HACK(tfoley): mark all declarations in the "stdlib" so - // that we can detect them later (e.g., so we don't emit them) - for (auto m : syntax->Members) + RefPtr findOrImportModule( + String const& name, + CodePosition const& loc) + { + // Have we already loaded a module matching this name? + // If so, return it. + RefPtr moduleDecl; + if (loadedModules.TryGetValue(name, moduleDecl)) + return moduleDecl; + + // Derive a file name for the module, by taking the given + // identifier, replacing all occurences of `_` with `-`, + // and then appending `.slang`. + // + // For example, `foo_bar` becomes `foo-bar.slang`. + + StringBuilder sb; + for (auto c : name) { - auto fromStdLibModifier = new FromStdLibModifier(); + if (c == '_') + c = '-'; - fromStdLibModifier->next = m->modifiers.first; - m->modifiers.first = fromStdLibModifier; + sb.Append(c); } + sb.Append(".slang"); - // Add the resulting code to the appropriate scope - if( !scope->containerDecl ) - { - // We are the first chunk of code to be loaded for this scope - scope->containerDecl = syntax.Ptr(); - } - else + String fileName = sb.ProduceString(); + + // Next, try to find the file of the given name, + // using our ordinary include-handling logic. + + IncludeHandlerImpl includeHandler; + includeHandler.request = this; + + String pathIncludedFrom = loc.FileName; + + String foundPath; + String foundSource; + bool found = includeHandler.TryToFindIncludeFile(fileName, pathIncludedFrom, &foundPath, &foundSource); + if (!found) { - // We need to create a new scope to link into the whole thing - auto subScope = new Scope(); - subScope->containerDecl = syntax.Ptr(); - subScope->nextSibling = scope->nextSibling; - scope->nextSibling = subScope; + this->mSink.diagnose(loc, Diagnostics::cannotFindFile, fileName); + + loadedModules[name] = nullptr; + return nullptr; } - // We need to retain this AST so that we can use it in other code - // (Note that the `Scope` type does not retain the AST it points to) - loadedModuleCode.Add(syntax); + // 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; } + +}; + +RefPtr findOrImportModule( + CompileRequest* request, + String const& name, + CodePosition const& loc) +{ + return request->findOrImportModule(name, loc); } -using namespace SlangLib; +void Session::addBuiltinSource( + RefPtr const& scope, + String const& path, + String const& source) +{ + CompileRequest compileRequest(this); + + auto translationUnitIndex = compileRequest.addTranslationUnit(SourceLanguage::Slang, path); + + compileRequest.addTranslationUnitSourceString( + translationUnitIndex, + path, + source); + + int err = compileRequest.executeAPIActions(); + if (err) + { + fprintf(stderr, "%s", compileRequest.mDiagnosticOutput.Buffer()); + +#ifdef _WIN32 + OutputDebugStringA(compileRequest.mDiagnosticOutput.Buffer()); +#endif + + assert(!"error in stdlib"); + } + + // Extract the AST for the code we just parsed + auto syntax = compileRequest.mCollectionOfTranslationUnits->translationUnits[translationUnitIndex].SyntaxNode; + + // HACK(tfoley): mark all declarations in the "stdlib" so + // that we can detect them later (e.g., so we don't emit them) + for (auto m : syntax->Members) + { + auto fromStdLibModifier = new FromStdLibModifier(); + + fromStdLibModifier->next = m->modifiers.first; + m->modifiers.first = fromStdLibModifier; + } + + // Add the resulting code to the appropriate scope + if (!scope->containerDecl) + { + // We are the first chunk of code to be loaded for this scope + scope->containerDecl = syntax.Ptr(); + } + else + { + // We need to create a new scope to link into the whole thing + auto subScope = new Scope(); + subScope->containerDecl = syntax.Ptr(); + subScope->nextSibling = scope->nextSibling; + scope->nextSibling = subScope; + } + + // We need to retain this AST so that we can use it in other code + // (Note that the `Scope` type does not retain the AST it points to) + loadedModuleCode.Add(syntax); +} + +}} // implementation of C interface -#define SESSION(x) reinterpret_cast(x) -#define REQ(x) reinterpret_cast(x) +#define SESSION(x) reinterpret_cast(x) +#define REQ(x) reinterpret_cast(x) SLANG_API SlangSession* spCreateSession(const char * cacheDir) { - return reinterpret_cast(new SlangLib::Session((cacheDir ? true : false), cacheDir)); + return reinterpret_cast(new Slang::Compiler::Session((cacheDir ? true : false), cacheDir)); } SLANG_API void spDestroySession( @@ -476,7 +642,7 @@ SLANG_API SlangCompileRequest* spCreateCompileRequest( SlangSession* session) { auto s = SESSION(session); - auto req = new SlangLib::CompileRequest(s); + auto req = new Slang::Compiler::CompileRequest(s); return reinterpret_cast(req); } @@ -536,7 +702,7 @@ SLANG_API void spAddPreprocessorDefine( const char* key, const char* value) { - REQ(request)->Options.PreprocessorDefinitions[key] = value; + REQ(request)->Options.preprocessorDefinitions[key] = value; } SLANG_API char const* spGetDiagnosticOutput( @@ -561,6 +727,18 @@ SLANG_API int spAddTranslationUnit( name ? name : ""); } +SLANG_API void spTranslationUnit_addPreprocessorDefine( + SlangCompileRequest* request, + int translationUnitIndex, + const char* key, + const char* value) +{ + auto req = REQ(request); + + req->Options.translationUnits[translationUnitIndex].preprocessorDefinitions[key] = value; + +} + SLANG_API void spAddTranslationUnitSourceFile( SlangCompileRequest* request, int translationUnitIndex, -- cgit v1.2.3