diff --git a/src/parser/cxx/name_lookup.cc b/src/parser/cxx/name_lookup.cc index 54bad1ed..05b062af 100644 --- a/src/parser/cxx/name_lookup.cc +++ b/src/parser/cxx/name_lookup.cc @@ -31,152 +31,9 @@ namespace cxx { Lookup::Lookup(ScopeSymbol* scope) : scope_(scope) {} -auto Lookup::operator()(const Name* name, - const std::function& accept) const - -> Symbol* { - return lookup(nullptr, name, accept); -} - -auto Lookup::operator()(NestedNameSpecifierAST* nestedNameSpecifier, - const Name* name, - const std::function& accept) const - -> Symbol* { - return lookup(nestedNameSpecifier, name, accept); -} - -auto Lookup::unqualifiedLookup(const Name* name, - const std::function& accept) const - -> Symbol* { - std::unordered_set cache; - for (auto current = scope_; current; current = current->parent()) { - if (auto symbol = lookupHelper(current, name, cache, accept)) { - return symbol; - } - } - return nullptr; -} - -auto Lookup::qualifiedLookup(ScopeSymbol* scope, const Name* name, - const std::function& accept) const - -> Symbol* { - std::unordered_set cache; - return lookupHelper(scope, name, cache, accept); -} - -auto Lookup::qualifiedLookup(Symbol* scopeSymbol, const Name* name, - const std::function& accept) const - -> Symbol* { - if (!scopeSymbol) return nullptr; - switch (scopeSymbol->kind()) { - case SymbolKind::kNamespace: - return qualifiedLookup(symbol_cast(scopeSymbol), name, - accept); - - case SymbolKind::kClass: - return qualifiedLookup(symbol_cast(scopeSymbol), name, - accept); - - case SymbolKind::kEnum: - return qualifiedLookup(symbol_cast(scopeSymbol), name, - accept); - - case SymbolKind::kScopedEnum: - return qualifiedLookup(symbol_cast(scopeSymbol), name, - accept); - - case SymbolKind::kTypeAlias: { - auto alias = symbol_cast(scopeSymbol); - - if (auto classType = type_cast(alias->type())) { - auto classSymbol = classType->symbol(); - return qualifiedLookup(classSymbol, name, accept); - } - - if (auto enumType = type_cast(alias->type())) { - auto enumSymbol = enumType->symbol(); - return qualifiedLookup(enumSymbol, name, accept); - } - - if (auto scopedEnumType = type_cast(alias->type())) { - auto scopedEnumSymbol = scopedEnumType->symbol(); - return qualifiedLookup(scopedEnumSymbol, name, accept); - } - - return nullptr; - } - - default: - return nullptr; - } // switch -} - -auto Lookup::lookup(NestedNameSpecifierAST* nestedNameSpecifier, - const Name* name, - const std::function& accept) const - -> Symbol* { - if (!name) return nullptr; - if (!nestedNameSpecifier) return unqualifiedLookup(name, accept); - if (!nestedNameSpecifier->symbol) return nullptr; - return qualifiedLookup(nestedNameSpecifier->symbol, name, accept); -} - -auto Lookup::lookupHelper(ScopeSymbol* scope, const Name* name, - std::unordered_set& cache, - const std::function& accept) const - -> Symbol* { - if (cache.contains(scope)) { - return nullptr; - } - - cache.insert(scope); - - for (auto symbol : scope->find(name)) { - if (auto u = symbol_cast(symbol); - u && u->target()) { - if (!accept || accept(u->target())) { - return u->target(); - } - } - - if (!accept || accept(symbol)) { - return symbol; - } - } - - if (auto classSymbol = symbol_cast(scope)) { - // iterate over the annonymous symbols - for (auto member : classSymbol->find(/*unnamed=*/nullptr)) { - auto nestedClass = symbol_cast(member); - if (!nestedClass) continue; - - auto symbol = lookupHelper(nestedClass, name, cache, accept); - if (symbol) { - // found a match in an anonymous nested class - return symbol; - } - } - - for (const auto& base : classSymbol->baseClasses()) { - auto baseClass = symbol_cast(base->symbol()); - if (!baseClass) continue; - if (auto symbol = lookupHelper(baseClass, name, cache, accept)) { - return symbol; - } - } - } - - for (auto u : scope->usingDirectives()) { - if (auto symbol = lookupHelper(u, name, cache, accept)) { - return symbol; - } - } - - return nullptr; -} - auto Lookup::lookupNamespace(NestedNameSpecifierAST* nestedNameSpecifier, const Identifier* id) const -> NamespaceSymbol* { - std::unordered_set set; + std::vector set; if (!nestedNameSpecifier) { // unqualified lookup, start with the current scope and go up. @@ -197,12 +54,14 @@ auto Lookup::lookupNamespace(NestedNameSpecifierAST* nestedNameSpecifier, } auto Lookup::lookupNamespaceHelper(ScopeSymbol* scope, const Identifier* id, - std::unordered_set& set) const + std::vector& set) const -> NamespaceSymbol* { - if (!set.insert(scope).second) { + if (std::ranges::contains(set, scope)) { return nullptr; } + set.push_back(scope); + for (auto candidate : scope->find(id) | views::namespaces) { return candidate; } @@ -218,7 +77,7 @@ auto Lookup::lookupNamespaceHelper(ScopeSymbol* scope, const Identifier* id, auto Lookup::lookupType(NestedNameSpecifierAST* nestedNameSpecifier, const Identifier* id) const -> Symbol* { - std::unordered_set set; + std::vector set; if (!nestedNameSpecifier) { // unqualified lookup, start with the current scope and go up. @@ -282,12 +141,13 @@ auto Lookup::lookupType(NestedNameSpecifierAST* nestedNameSpecifier, } auto Lookup::lookupTypeHelper(ScopeSymbol* scope, const Identifier* id, - std::unordered_set& set) const - -> Symbol* { - if (!set.insert(scope).second) { + std::vector& set) const -> Symbol* { + if (std::ranges::contains(set, scope)) { return nullptr; } + set.push_back(scope); + for (auto candidate : scope->find(id)) { if (auto u = symbol_cast(candidate); u && u->target()) { diff --git a/src/parser/cxx/name_lookup.h b/src/parser/cxx/name_lookup.h index 10b90117..b1f0bac8 100644 --- a/src/parser/cxx/name_lookup.h +++ b/src/parser/cxx/name_lookup.h @@ -20,12 +20,18 @@ #pragma once +#include #include #include +#include #include +#include +#include +#include #include -#include +#include +#include namespace cxx { @@ -33,21 +39,58 @@ class Lookup { public: explicit Lookup(ScopeSymbol* scope); - [[nodiscard]] auto operator()( - const Name* name, const std::function& accept = {}) const - -> Symbol*; - - [[nodiscard]] auto operator()( - NestedNameSpecifierAST* nestedNameSpecifier, const Name* name, - const std::function& accept = {}) const -> Symbol*; - - [[nodiscard]] auto lookup( - NestedNameSpecifierAST* nestedNameSpecifier, const Name* name, - const std::function& accept = {}) const -> Symbol*; - - [[nodiscard]] auto qualifiedLookup( - ScopeSymbol* scope, const Name* name, - const std::function& accept = {}) const -> Symbol*; + template + requires std::predicate + [[nodiscard]] auto operator()(const Name* name, Predicate accept) const + -> Symbol* { + return lookup(nullptr, name, accept); + } + + [[nodiscard]] auto operator()(const Name* name) const -> Symbol* { + return operator()(name, [](Symbol*) { return true; }); + } + + template + requires std::predicate + [[nodiscard]] auto operator()(NestedNameSpecifierAST* nestedNameSpecifier, + const Name* name, Predicate accept) const + -> Symbol* { + return lookup(nestedNameSpecifier, name, accept); + } + + [[nodiscard]] auto operator()(NestedNameSpecifierAST* nestedNameSpecifier, + const Name* name) const -> Symbol* { + return operator()(nestedNameSpecifier, name, [](Symbol*) { return true; }); + } + + template + requires std::predicate + [[nodiscard]] auto lookup(NestedNameSpecifierAST* nestedNameSpecifier, + const Name* name, Predicate accept) const + -> Symbol* { + if (!name) return nullptr; + if (!nestedNameSpecifier) return unqualifiedLookup(name, accept); + if (!nestedNameSpecifier->symbol) return nullptr; + return qualifiedLookup(nestedNameSpecifier->symbol, name, accept); + } + + [[nodiscard]] auto lookup(NestedNameSpecifierAST* nestedNameSpecifier, + const Name* name) const -> Symbol* { + return lookup(nestedNameSpecifier, name, [](Symbol*) { return true; }); + } + + template + requires std::predicate + [[nodiscard]] auto qualifiedLookup(ScopeSymbol* scope, const Name* name, + Predicate accept) const -> Symbol* { + std::vector cache; + return lookupHelper(scope, name, cache, accept); + } + + [[nodiscard]] auto qualifiedLookup(ScopeSymbol* scope, const Name* name) const + -> Symbol* { + return qualifiedLookup(scope, name, [](Symbol*) { return true; }); + } [[nodiscard]] auto lookupNamespace( NestedNameSpecifierAST* nestedNameSpecifier, const Identifier* id) const @@ -57,26 +100,108 @@ class Lookup { const Identifier* id) const -> Symbol*; private: - [[nodiscard]] auto unqualifiedLookup( - const Name* name, const std::function& accept) const - -> Symbol*; - - [[nodiscard]] auto qualifiedLookup( - Symbol* scopeSymbol, const Name* name, - const std::function& accept) const -> Symbol*; - - [[nodiscard]] auto lookupHelper( - ScopeSymbol* scope, const Name* name, - std::unordered_set& cache, - const std::function& accept) const -> Symbol*; - - [[nodiscard]] auto lookupNamespaceHelper( - ScopeSymbol* scope, const Identifier* id, - std::unordered_set& set) const -> NamespaceSymbol*; + template + [[nodiscard]] auto unqualifiedLookup(const Name* name, Predicate accept) const + -> Symbol* { + std::vector cache; + for (auto current = scope_; current; current = current->parent()) { + if (auto symbol = lookupHelper(current, name, cache, accept)) { + return symbol; + } + } + return nullptr; + } + + template + [[nodiscard]] auto qualifiedLookup(Symbol* scopeSymbol, const Name* name, + Predicate accept) const -> Symbol* { + if (!scopeSymbol) return nullptr; + + if (auto alias = symbol_cast(scopeSymbol)) { + if (auto classType = type_cast(alias->type())) { + return qualifiedLookup(classType->symbol(), name, accept); + } + if (auto enumType = type_cast(alias->type())) { + return qualifiedLookup(enumType->symbol(), name, accept); + } + if (auto scopedEnumType = type_cast(alias->type())) { + return qualifiedLookup(scopedEnumType->symbol(), name, accept); + } + } + + switch (scopeSymbol->kind()) { + case SymbolKind::kNamespace: + case SymbolKind::kClass: + case SymbolKind::kEnum: + case SymbolKind::kScopedEnum: + return qualifiedLookup(scopeSymbol->asScopeSymbol(), name, accept); + default: + return nullptr; + } // switch + } + + template + [[nodiscard]] auto lookupHelper(ScopeSymbol* scope, const Name* name, + std::vector& cache, + Predicate accept) const -> Symbol* { + if (std::ranges::contains(cache, scope)) { + return nullptr; + } + + cache.push_back(scope); + + for (auto symbol : scope->find(name)) { + if (auto u = symbol_cast(symbol); + u && u->target()) { + if (std::invoke(accept, u->target())) { + return u->target(); + } + } + + if (std::invoke(accept, symbol)) { + return symbol; + } + } + + if (auto classSymbol = symbol_cast(scope)) { + // iterate over the anonymous symbols + for (auto member : classSymbol->find(/*unnamed=*/nullptr)) { + auto nestedClass = symbol_cast(member); + if (!nestedClass) continue; + + auto symbol = lookupHelper(nestedClass, name, cache, accept); + if (symbol) { + // found a match in an anonymous nested class + return symbol; + } + } + + for (const auto& base : classSymbol->baseClasses()) { + auto baseClass = symbol_cast(base->symbol()); + if (!baseClass) continue; + if (auto symbol = lookupHelper(baseClass, name, cache, accept)) { + return symbol; + } + } + } + + for (auto u : scope->usingDirectives()) { + if (auto symbol = lookupHelper(u, name, cache, accept)) { + return symbol; + } + } + + return nullptr; + } + + [[nodiscard]] auto lookupNamespaceHelper(ScopeSymbol* scope, + const Identifier* id, + std::vector& set) const + -> NamespaceSymbol*; - [[nodiscard]] auto lookupTypeHelper( - ScopeSymbol* scope, const Identifier* id, - std::unordered_set& set) const -> Symbol*; + [[nodiscard]] auto lookupTypeHelper(ScopeSymbol* scope, const Identifier* id, + std::vector& set) const + -> Symbol*; private: ScopeSymbol* scope_ = nullptr; diff --git a/src/parser/cxx/preprocessor.cc b/src/parser/cxx/preprocessor.cc index f85f5129..c661bcee 100644 --- a/src/parser/cxx/preprocessor.cc +++ b/src/parser/cxx/preprocessor.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -200,14 +201,15 @@ class Hideset { Hideset() = default; - explicit Hideset(std::set names) + explicit Hideset(std::vector names) : names_(std::move(names)) {} - [[nodiscard]] auto contains(const std::string_view& name) const -> bool { - return names_.contains(name); + [[nodiscard]] auto contains(const cxx::Identifier* name) const -> bool { + return std::binary_search(names_.begin(), names_.end(), name); } - [[nodiscard]] auto names() const -> const std::set& { + [[nodiscard]] auto names() const + -> const std::vector& { return names_; }; @@ -216,7 +218,7 @@ class Hideset { } private: - std::set names_; + std::vector names_; }; inline auto getHeaderName(const cxx::Include& include) -> std::string { @@ -235,26 +237,15 @@ struct std::less { } auto operator()(const Hideset& hideset, - const std::set& names) const -> bool { + const std::vector& names) const + -> bool { return hideset.names() < names; } - auto operator()(const std::set& names, + auto operator()(const std::vector& names, const Hideset& hideset) const -> bool { return names < hideset.names(); } - - auto operator()(const Hideset& hideset, const std::string_view& name) const - -> bool { - return std::lexicographical_compare(begin(hideset.names()), - end(hideset.names()), &name, &name + 1); - } - - auto operator()(const std::string_view& name, const Hideset& hideset) const - -> bool { - return std::lexicographical_compare( - &name, &name + 1, begin(hideset.names()), end(hideset.names())); - } }; template <> @@ -265,18 +256,12 @@ struct std::hash { return operator()(hideset.names()); } - auto operator()(const std::set& names) const + auto operator()(const std::vector& names) const -> std::size_t { std::size_t seed = 0; for (const auto& name : names) cxx::hash_combine(seed, name); return seed; } - - auto operator()(const std::string_view& name) const -> std::size_t { - std::size_t seed = 0; - cxx::hash_combine(seed, name); - return seed; - } }; template <> @@ -288,24 +273,15 @@ struct std::equal_to { } auto operator()(const Hideset& hideset, - const std::set& names) const -> bool { + const std::vector& names) const + -> bool { return hideset.names() == names; } - auto operator()(const std::set& names, + auto operator()(const std::vector& names, const Hideset& hideset) const -> bool { return hideset.names() == names; } - - auto operator()(const Hideset& hideset, const std::string_view& name) const - -> bool { - return hideset.names().size() == 1 && *hideset.names().begin() == name; - } - - auto operator()(const std::string_view& name, const Hideset& hideset) const - -> bool { - return hideset.names().size() == 1 && *hideset.names().begin() == name; - } }; namespace cxx { @@ -704,7 +680,7 @@ struct Preprocessor::Private { std::vector systemIncludePaths_; std::vector quoteIncludePaths_; std::unordered_map macros_; - std::set hidesets; + std::unordered_set hidesets; std::forward_list scratchBuffer_; std::unordered_map ifndefProtectedFiles_; std::vector> sourceFiles_; @@ -923,10 +899,12 @@ struct Preprocessor::Private { [[nodiscard]] auto makeUnion(const Hideset* hs, const std::string_view& name) -> const Hideset* { - if (!hs) return get(name); - if (hs->names().contains(name)) return hs; + auto id = control_->getIdentifier(name); + if (!hs) return get(id); + if (hs->contains(id)) return hs; auto names = hs->names(); - names.insert(name); + auto it = std::upper_bound(names.begin(), names.end(), id); + names.insert(it, id); return get(std::move(names)); } @@ -935,24 +913,27 @@ struct Preprocessor::Private { if (!other || !hs) return nullptr; if (other == hs) return hs; - std::set names; + std::vector names; std::set_intersection(begin(hs->names()), end(hs->names()), begin(other->names()), end(other->names()), - std::inserter(names, names.begin())); + std::back_inserter(names)); return get(std::move(names)); } - [[nodiscard]] auto get(std::set names) -> const Hideset* { + [[nodiscard]] auto get(std::vector names) + -> const Hideset* { if (names.empty()) return nullptr; if (auto it = hidesets.find(names); it != hidesets.end()) return &*it; return &*hidesets.emplace(std::move(names)).first; } - [[nodiscard]] auto get(const std::string_view& name) -> const Hideset* { - if (auto it = hidesets.find(name); it != hidesets.end()) return &*it; - return &*hidesets.emplace(std::set{name}).first; + [[nodiscard]] auto get(const cxx::Identifier* name) -> const Hideset* { + std::vector names; + names.push_back(name); + if (auto it = hidesets.find(names); it != hidesets.end()) return &*it; + return &*hidesets.emplace(std::move(names)).first; } [[nodiscard]] auto isStringLiteral(TokenKind kind) const -> bool { @@ -1140,20 +1121,21 @@ struct Preprocessor::Private { [[nodiscard]] auto parseMacroDefinition(TokList* ts) -> Macro; - [[nodiscard]] auto expand(const std::function& emitToken) - -> PreprocessingState; + using EmitToken = std::function; + + [[nodiscard]] auto expand(const EmitToken& emitToken) -> PreprocessingState; [[nodiscard]] auto expandTokens(TokIterator it, TokIterator last, bool inConditionalExpression) -> TokIterator; - [[nodiscard]] auto expandOne(TokIterator first, TokIterator last, + [[nodiscard]] auto expandOne(TokIterator it, TokIterator last, bool inConditionalExpression, - const std::function& emitToken) - -> TokIterator; + const EmitToken& emitToken) -> TokIterator; - [[nodiscard]] auto replaceIsDefinedMacro( - TokList* ts, bool inConditionalExpression, - const std::function& emitToken) -> TokList*; + [[nodiscard]] auto replaceIsDefinedMacro(TokList* ts, + bool inConditionalExpression, + const EmitToken& emitToken) + -> TokList*; [[nodiscard]] auto expandMacro(TokList* ts) -> TokList*; @@ -1747,27 +1729,8 @@ auto Preprocessor::Private::tokenize(const std::string_view& source, return ts; } -auto Preprocessor::Private::expandTokens(TokIterator it, TokIterator last, - bool inConditionalExpression) - -> TokIterator { - TokList* tokens = nullptr; - auto out = &tokens; - - while (it != last) { - if (it->is(TokenKind::T_EOF_SYMBOL)) { - break; - } - it = expandOne(it, last, inConditionalExpression, [&](auto tok) { - *out = cons(tok); - out = (&(*out)->next); - }); - } - - return TokIterator{tokens}; -} - -auto Preprocessor::Private::expand( - const std::function& emitToken) -> PreprocessingState { +auto Preprocessor::Private::expand(const EmitToken& emitToken) + -> PreprocessingState { if (buffers_.empty()) return ProcessingComplete{}; auto buffer = buffers_.back(); @@ -1861,6 +1824,81 @@ auto Preprocessor::Private::expand( return CanContinuePreprocessing{}; } +auto Preprocessor::Private::expandTokens(TokIterator it, TokIterator last, + bool inConditionalExpression) + -> TokIterator { + TokList* tokens = nullptr; + auto out = &tokens; + + while (it != last) { + if (it->is(TokenKind::T_EOF_SYMBOL)) { + break; + } + it = expandOne(it, last, inConditionalExpression, [&](auto tok) { + *out = cons(tok); + out = (&(*out)->next); + }); + } + + return TokIterator{tokens}; +} + +auto Preprocessor::Private::expandOne(TokIterator it, TokIterator last, + bool inConditionalExpression, + const EmitToken& emitToken) + -> TokIterator { + if (it == last) return last; + + if (auto continuation = replaceIsDefinedMacro( + it.toTokList(), inConditionalExpression, emitToken)) { + return TokIterator{continuation}; + } + + if (auto continuation = expandMacro(it.toTokList())) { + return TokIterator{continuation}; + } + + emitToken(&*it); + + ++it; + + return it; +} + +auto Preprocessor::Private::replaceIsDefinedMacro(TokList* ts, + bool inConditionalExpression, + const EmitToken& emitToken) + -> TokList* { + if (!inConditionalExpression) { + return nullptr; + } + + auto start = ts->tok; + + if (!matchId(ts, "defined")) { + return nullptr; + } + + bool value = false; + + if (match(ts, TokenKind::T_LPAREN)) { + value = isDefined(ts->tok); + ts = ts->next; + expect(ts, TokenKind::T_RPAREN); + } else { + value = isDefined(ts->tok); + ts = ts->next; + } + + auto tk = gen(TokenKind::T_INTEGER_LITERAL, value ? "1" : "0"); + tk->sourceFile = start->sourceFile; + tk->space = start->space; + tk->bol = start->bol; + emitToken(tk); + + return ts; +} + auto Preprocessor::Private::parseDirective(SourceFile* source, TokList* start) -> ParsedDirective { auto directive = start->next; @@ -2136,60 +2174,6 @@ auto Preprocessor::Private::parseHeaderName(TokList* ts) return {ts, std::nullopt}; } -auto Preprocessor::Private::expandOne( - TokIterator it, TokIterator last, bool inConditionalExpression, - const std::function& emitToken) -> TokIterator { - if (it == last) return last; - - if (auto continuation = replaceIsDefinedMacro( - it.toTokList(), inConditionalExpression, emitToken)) { - return TokIterator{continuation}; - } - - if (auto continuation = expandMacro(it.toTokList())) { - return TokIterator{continuation}; - } - - emitToken(&*it); - - ++it; - - return it; -} - -auto Preprocessor::Private::replaceIsDefinedMacro( - TokList* ts, bool inConditionalExpression, - const std::function& emitToken) -> TokList* { - if (!inConditionalExpression) { - return nullptr; - } - - auto start = ts->tok; - - if (!matchId(ts, "defined")) { - return nullptr; - } - - bool value = false; - - if (match(ts, TokenKind::T_LPAREN)) { - value = isDefined(ts->tok); - ts = ts->next; - expect(ts, TokenKind::T_RPAREN); - } else { - value = isDefined(ts->tok); - ts = ts->next; - } - - auto tk = gen(TokenKind::T_INTEGER_LITERAL, value ? "1" : "0"); - tk->sourceFile = start->sourceFile; - tk->space = start->space; - tk->bol = start->bol; - emitToken(tk); - - return ts; -} - auto Preprocessor::Private::expandMacro(TokList* ts) -> TokList* { struct ExpandMacro { Private& self; @@ -2864,7 +2848,8 @@ auto Preprocessor::Private::lookupMacro(const Tok* tk) const -> const Macro* { } if (auto it = macros_.find(tk->text); it != macros_.end()) { - const auto disabled = tk->hideset && tk->hideset->contains(tk->text); + const auto disabled = + tk->hideset && tk->hideset->contains(control_->getIdentifier(tk->text)); if (!disabled) { return &it->second; }