From 11748a75e66c2bd3fa7ef7635fd35363465f599c Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Thu, 20 Aug 2020 08:23:51 -0700 Subject: Initial support for a using construct (#1506) The basic idea is that if you have a namespace: namespace MyCoolNamespace { void f() { ... } ... } then you can bring the declarations from that namespace into scope with: using MyCoolNamespace; f(); The `using` construct is allowed in any scope where declarations are allowed. As an additional feature, the construct allows and then ignores the keyword `namespace` if it occurs right after `using`: using namespace MyCoolNamespace; Note that unlike in C++, `using` a namespace inside another namespace doesn't implicitly make the symbols available to clients of that namespace: namespace hidden { void secret() {...} ... } namespace api { using hidden; ... } api.secret(); // ERROR: `secret()` isn't a member of `api` The implementation of this feature was relatively simple, although it does leave out more advanced features that might be desirable in the future: * No support for `using MCN = MyCoolNamespace` sorts of tricks to define a short name * No support for `using` anything that isn't a namespace (e.g., to make the members of a type available without qualification) * No support for cases where multiple visible modules have a namespace of the same name (or dealing with overloaded namespaces in general) --- source/slang/slang-parser.cpp | 50 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) (limited to 'source/slang/slang-parser.cpp') diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index f2bc2eb9a..e02ccf245 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -933,12 +933,16 @@ namespace Slang return parser->getNamePool()->getName(text); } + static bool expect(Parser* parser, TokenType tokenType) + { + return parser->ReadToken(tokenType).type == tokenType; + } + static NameLoc expectIdentifier(Parser* parser) { return NameLoc(parser->ReadToken(TokenType::Identifier)); } - static NodeBase* parseImportDecl( Parser* parser, void* /*userData*/) { @@ -2629,6 +2633,44 @@ namespace Slang return result; } + static NodeBase* parseUsingDecl(Parser* parser, void* /*userData*/) + { + UsingDecl* decl = parser->astBuilder->create(); + parser->FillPosition(decl); + + // A `using` declaration will need to know about the current + // scope at the point where it appears, so that it can know + // the scope it is attempting to extend. + // + decl->scope = parser->currentScope; + + // TODO: We may eventually want to support declarations + // of the form `using = ;` which introduce + // a shorthand alias for a namespace/type/whatever. + // + // For now we are just sticking to the most basic form. + + // As a compatibility feature for programmers used to C++, + // we allow the `namespace` keyword to come after `using`, + // where it has no effect. + // + if(parser->LookAheadToken("namespace")) + { + advanceToken(parser); + } + + // The entity that is going to be used is identified + // using an arbitrary expression (although we expect + // that valid code will not typically use the full + // freedom of what the expression grammar supports. + // + decl->arg = parser->ParseExpression(); + + expect(parser, TokenType::Semicolon); + + return decl; + } + static NodeBase* parseConstructorDecl(Parser* parser, void* /*userData*/) { ConstructorDecl* decl = parser->astBuilder->create(); @@ -2750,11 +2792,6 @@ namespace Slang return decl; } - static bool expect(Parser* parser, TokenType tokenType) - { - return parser->ReadToken(tokenType).type == tokenType; - } - /// Peek in the token stream and return `true` if it looks like a modern-style variable declaration is coming up. static bool _peekModernStyleVarDecl(Parser* parser) { @@ -5659,6 +5696,7 @@ namespace Slang DECL(typealias, parseTypeAliasDecl); DECL(__generic_value_param, parseGlobalGenericValueParamDecl); DECL(namespace, parseNamespaceDecl); + DECL(using, parseUsingDecl); #undef DECL -- cgit v1.2.3