/* Copyright (c) 2015 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Leonardo de Moura */ #include #include #include #include "util/priority_queue.h" #include "util/sstream.h" #include "library/attribute_manager.h" #include "library/scoped_ext.h" namespace lean { struct attribute_decl { std::string m_id; std::string m_descr; std::string m_token; set_attribute_proc m_on_set; }; static std::vector * g_attr_decls; static std::vector> * g_incomp = nullptr; static std::string * g_key = nullptr; struct attr_record { name m_decl; list m_params; attr_record() {} attr_record(name decl, list params): m_decl(decl), m_params(params) {} unsigned hash() const { unsigned h = m_decl.hash(); for (unsigned p : m_params) h = ::lean::hash(h, p); return h; } }; struct attr_record_cmp { int operator()(attr_record const & r1, attr_record const & r2) const { // Adding a new record with different arguments should override the old one return quick_cmp(r1.m_decl, r2.m_decl); } }; struct attr_entry { name m_attr; unsigned m_prio; attr_record m_record; attr_entry() {} attr_entry(name attr, unsigned prio, attr_record record): m_attr(attr), m_prio(prio), m_record(record) {} }; typedef priority_queue attr_records; typedef name_map attr_state; struct attr_config { typedef attr_state state; typedef attr_entry entry; static void add_entry(environment const &, io_state const &, state & s, entry const & e) { attr_records m; if (auto q = s.find(e.m_attr)) m = *q; m.insert(e.m_record, e.m_prio); s.insert(e.m_attr, m); } static std::string const & get_serialization_key() { return *g_key; } static void write_entry(serializer & s, entry const & e) { s << e.m_attr << e.m_prio << e.m_record.m_decl; write_list(s, e.m_record.m_params); } static entry read_entry(deserializer & d) { entry e; d >> e.m_attr >> e.m_prio >> e.m_record.m_decl; e.m_record.m_params = read_list(d); return e; } static optional get_fingerprint(entry const & e) { return optional(hash(hash(e.m_attr.hash(), e.m_record.hash()), e.m_prio)); } }; template class scoped_ext; typedef scoped_ext attribute_ext; bool is_attribute(char const * attr) { for (auto const & d : *g_attr_decls) { if (d.m_id == attr) return true; } return false; } void register_attribute(char const * attr, char const * descr, set_attribute_proc const & on_set) { lean_assert(!is_attribute(attr)); g_attr_decls->push_back(attribute_decl {attr, descr, std::string("[") + attr, on_set}); } void register_no_params_attribute(char const * attr, char const * descr, set_no_params_attribute_proc const & on_set) { register_attribute(attr, descr, [=](environment const & env, io_state const & ios, name const & d, unsigned prio, list const & idxs, bool persistent) { if (prio != LEAN_DEFAULT_PRIORITY) throw exception(sstream() << "invalid [" << attr << "] declaration, unexpected priority declaration"); if (idxs) throw exception(sstream() << "invalid [" << attr << "] declaration, unexpected parameter"); return on_set(env, ios, d, persistent); }); } void register_no_params_attribute(char const * attr, char const * descr) { register_no_params_attribute(attr, descr, [](environment const & env, io_state const &, name const &, bool) { return env; }); } void register_prio_attribute(char const * attr, char const * descr, set_prio_attribute_proc const & on_set) { register_attribute(attr, descr, [=](environment const & env, io_state const & ios, name const & d, unsigned prio, list const & idxs, bool persistent) { if (idxs) throw exception(sstream() << "invalid [" << attr << "] declaration, unexpected parameter"); return on_set(env, ios, d, prio, persistent); }); } void register_prio_attribute(char const * attr, char const * descr) { register_prio_attribute(attr, descr, [=](environment const & env, io_state const &, name const &, unsigned, bool) { return env; }); } void register_opt_param_attribute(char const * attr, char const * descr, set_opt_param_attribute_proc const & on_set) { register_attribute(attr, descr, [=](environment const & env, io_state const & ios, name const & d, unsigned prio, list const & idxs, bool persistent) { if (prio != LEAN_DEFAULT_PRIORITY) throw exception(sstream() << "invalid [" << attr << "] declaration, unexpected priority declaration"); if (idxs && tail(idxs)) throw exception(sstream() << "invalid [" << attr << "] declaration, expected at most one parameter"); return on_set(env, ios, d, head_opt(idxs), persistent); }); } void register_params_attribute(char const * attr, char const * descr, set_params_attribute_proc const & on_set) { register_attribute(attr, descr, [=](environment const & env, io_state const & ios, name const & d, unsigned prio, list const & idxs, bool persistent) { if (prio != LEAN_DEFAULT_PRIORITY) throw exception(sstream() << "invalid [" << attr << "] declaration, unexpected priority declaration"); return on_set(env, ios, d, idxs, persistent); }); } void register_params_attribute(char const * attr, char const * descr) { register_params_attribute(attr, descr, [=](environment const & env, io_state const &, name const &, list const &, bool) { return env; }); } void register_incompatible(char const * attr1, char const * attr2) { lean_assert(is_attribute(attr1)); lean_assert(is_attribute(attr2)); std::string s1(attr1); std::string s2(attr2); if (s1 > s2) std::swap(s1, s2); g_incomp->emplace_back(s1, s2); } void get_attributes(buffer & r) { for (auto const & d : *g_attr_decls) r.push_back(d.m_id.c_str()); } void get_attribute_tokens(buffer & r) { for (auto const & d : *g_attr_decls) r.push_back(d.m_token.c_str()); } char const * get_attribute_from_token(char const * tk) { for (auto const & d : *g_attr_decls) { if (d.m_token == tk) return d.m_id.c_str(); } return nullptr; } char const * get_attribute_token(char const * attr) { for (auto const & d : *g_attr_decls) { if (d.m_id == attr) return d.m_token.c_str(); } return nullptr; } bool has_attribute(environment const & env, char const * attr, name const & d) { if (auto it = attribute_ext::get_state(env).find(attr)) return it->contains(attr_record(d, list())); return false; } void get_attribute_instances(environment const & env, name const & attr, buffer & r) { attribute_ext::get_state(env).find(attr)->for_each([&](attr_record const & rec) { r.push_back(rec.m_decl); }); } priority_queue get_attribute_instances_by_prio(environment const & env, name const & attr) { priority_queue q; auto recs = attribute_ext::get_state(env).find(attr); recs->for_each([&](attr_record const & rec) { q.insert(rec.m_decl, recs->get_prio(rec).value()); }); return q; } [[ noreturn ]] void throw_unknown_attribute(name const & attr) { throw exception(sstream() << "unknown attribute '" << attr << "'"); } environment set_attribute(environment const & env, io_state const & ios, char const * attr, name const & d, unsigned prio, list const & params, bool persistent) { for (auto const & decl : *g_attr_decls) { if (decl.m_id == attr) { auto env2 = attribute_ext::add_entry(env, ios, attr_entry(attr, prio, attr_record(d, params)), persistent); return decl.m_on_set(env2, ios, d, prio, params, persistent); } } throw_unknown_attribute(attr); } environment set_attribute(environment const & env, io_state const & ios, char const * attr, name const & d, bool persistent) { return set_attribute(env, ios, attr, d, LEAN_DEFAULT_PRIORITY, list(), persistent); } unsigned get_attribute_prio(environment const & env, name const & attr, name const & d) { if (auto it = attribute_ext::get_state(env).find(attr)) { optional prio = it->get_prio({d, list()}); return prio ? *prio : LEAN_DEFAULT_PRIORITY; } throw_unknown_attribute(attr); } list get_attribute_params(environment const & env, name const & attr, name const & d) { if (auto it = attribute_ext::get_state(env).find(attr)) { if (auto record = it->get_key(attr_record {d, list()})) return record->m_params; } throw_unknown_attribute(attr); } bool are_incompatible(char const * attr1, char const * attr2) { std::string s1(attr1); std::string s2(attr2); if (s1 > s2) std::swap(s1, s2); return std::find(g_incomp->begin(), g_incomp->end(), mk_pair(s1, s2)) != g_incomp->end(); } void initialize_attribute_manager() { g_attr_decls = new std::vector(); g_incomp = new std::vector>(); g_key = new std::string("ATTR"); attribute_ext::initialize(); } void finalize_attribute_manager() { attribute_ext::finalize(); delete g_key; delete g_incomp; delete g_attr_decls; } }