// Copyright (c) 2020-now by the Zeek Project. See LICENSE for details. #pragma once #include #include #include #include #include #include #include namespace hilti { class Meta; } template<> struct std::hash { size_t operator()(const hilti::Meta& meta) const; }; namespace hilti { /** * Meta information associated with AST nodes. The meta data can include a * source code location, source code comments, and an error message. */ class Meta { public: /** List of comments. */ using Comments = std::vector; Meta(Location location, Comments comments = {}) : _comments(std::move(comments)) { setLocation(std::move(location)); } /** Constructor that leaves location unset. */ Meta(Comments comments = {}) : _comments(std::move(comments)) {} Meta(const Meta&) = default; Meta(Meta&&) = default; const Comments& comments() const { return _comments; } const Location& location() const { static Location null; return _location ? *_location : null; } void setLocation(Location l) { _location = std::move(l); } void setComments(Comments c) { _comments = std::move(c); } Meta mergeLocation(const Location& l) const { return Meta(location().merge(l), _comments); } /** * Returns true if the location does not equal a default constructed * instance. */ explicit operator bool() const { return _location || _comments.size(); } Meta& operator=(const Meta&) = default; Meta& operator=(Meta&&) = default; friend bool operator==(const Meta& a, const Meta& b) { return a._location == b._location && a._comments == b._comments; } friend bool operator!=(const Meta& a, const Meta& b) { return ! (a == b); } /** * Returns pointer to a globally shared/cached version of a meta instance. * The returned pointer can be used instead of the Meta instance passed in, * and it guaranteed to remain valid for the entire lifetime of the * program. */ static const Meta* get(Meta m) { return &*_cache.emplace(std::move(m)).first; } private: std::optional _location; Comments _comments; static std::unordered_set _cache; // global cache of meta instances }; } // namespace hilti inline size_t std::hash::operator()(const hilti::Meta& meta) const { size_t h = 0; for ( const auto& c : meta.comments() ) h = hilti::rt::hashCombine(h, std::hash()(c)); return hilti::rt::hashCombine(h, std::hash>()(meta.location())); }