From 3d29c9029349ef2948dd6ae63c08c2ea2f4380dc Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Tue, 20 Jun 2017 12:52:12 -0700 Subject: Check `import` decls before all others. This helps ensure that we pull things into scope at the right time. --- source/slang/check.cpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'source') diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 128afcefe..5a82380d3 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -44,7 +44,7 @@ namespace Slang class SemanticsVisitor : public SyntaxVisitor { - ProgramSyntaxNode * program = nullptr; +// ProgramSyntaxNode * program = nullptr; FunctionSyntaxNode * function = nullptr; CompileRequest* request = nullptr; @@ -1239,37 +1239,40 @@ namespace Slang } } - // + // We need/want to visit any `import` declarations before + // anything else, to make sure that scoping works. + for(auto& importDecl : programNode->getMembersOfType()) + { + EnsureDecl(importDecl); + } - HashSet funcNames; - this->program = programNode; - this->function = nullptr; + // - for (auto & s : program->GetTypeDefs()) + for (auto & s : programNode->GetTypeDefs()) VisitTypeDefDecl(s.Ptr()); - for (auto & s : program->GetStructs()) + for (auto & s : programNode->GetStructs()) { VisitStruct(s.Ptr()); } - for (auto & s : program->GetClasses()) + for (auto & s : programNode->GetClasses()) { VisitClass(s.Ptr()); } // HACK(tfoley): Visiting all generic declarations here, // because otherwise they won't get visited. - for (auto & g : program->getMembersOfType()) + for (auto & g : programNode->getMembersOfType()) { VisitGenericDecl(g.Ptr()); } - for (auto & func : program->GetFunctions()) + for (auto & func : programNode->GetFunctions()) { if (!func->IsChecked(DeclCheckState::Checked)) { VisitFunctionDeclaration(func.Ptr()); } } - for (auto & func : program->GetFunctions()) + for (auto & func : programNode->GetFunctions()) { EnsureDecl(func); } @@ -4935,6 +4938,9 @@ namespace Slang virtual void visitImportDecl(ImportDecl* decl) override { + if(decl->IsChecked(DeclCheckState::Checked)) + return; + // We need to look for a module with the specified name // (whether it has already been loaded, or needs to // be loaded), and then put its declarations into @@ -4961,6 +4967,8 @@ namespace Slang subScope->nextSibling = scope->nextSibling; scope->nextSibling = subScope; + + decl->SetCheckState(DeclCheckState::Checked); } }; -- cgit v1.2.3 From 4313db822ca468e33c765170c924bf031e5e66a5 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Tue, 20 Jun 2017 13:57:20 -0700 Subject: Add a useful source location to `typedef` declarations This was just missing logic in the parser. --- source/slang/parser.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp index 5e06aa877..48954dc04 100644 --- a/source/slang/parser.cpp +++ b/source/slang/parser.cpp @@ -488,6 +488,9 @@ namespace Slang RefPtr ParseTypeDef(Parser* parser) { + RefPtr typeDefDecl = new TypeDefDecl(); + typeDefDecl->Position = parser->tokenReader.PeekLoc(); + // Consume the `typedef` keyword parser->ReadToken("typedef"); @@ -496,7 +499,6 @@ namespace Slang auto nameToken = parser->ReadToken(TokenType::Identifier); - RefPtr typeDefDecl = new TypeDefDecl(); typeDefDecl->Name = nameToken; typeDefDecl->Type = type; -- cgit v1.2.3 From d852ad9fedb71f23b3aa70db0c7b43f6d6fd10e2 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Tue, 20 Jun 2017 13:57:46 -0700 Subject: Only emit each `import`ed module once. If the user imports a module along more than one path, we need to make sure we don't emit the code twice. I handle this by keeping a set of already-emitted modules. Down the line, a more robust code generation strategy for non-"rewriter" use cases would be handling this at the per-declaration level, and this logic wouldn't really be needed. --- source/slang/emit.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'source') diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 21704f6ff..c531a0a77 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -34,6 +34,8 @@ struct EmitContext // instead. Dictionary mapGLSLSourcePathToID; int glslSourceIDCount = 0; + + HashSet modulesAlreadyEmitted; }; // @@ -2662,16 +2664,24 @@ static void EmitDeclImpl(EmitContext* context, RefPtr decl, RefPtrimportedModuleDecl; + auto moduleDecl = importDecl->importedModuleDecl.Ptr(); - // TODO: do we need to modify the code generation environment at - // all when doing this recursive emit? - // - // TODO: what if we import the same module along two different - // paths? Probably need logic to avoid emitting the same - // module more than once. + // We might import the same module along two different paths, + // so we need to be careful to only emit each module once + // per output. + if(!context->modulesAlreadyEmitted.Contains(moduleDecl)) + { + // Add the module to our set before emitting it, just + // in case a circular reference would lead us to + // infinite recursion (but that shouldn't be allowed + // in the first place). + context->modulesAlreadyEmitted.Add(moduleDecl); - EmitDeclsInContainer(context, moduleDecl); + // TODO: do we need to modify the code generation environment at + // all when doing this recursive emit? + + EmitDeclsInContainer(context, moduleDecl); + } return; } -- cgit v1.2.3