#include "klammer.h" #include "klammer_registry.h" #include "show.h" #include "util.h" #include "log.h" #include "error.h" /* bool Klammer_registry::has(std::string name, std::string target) { return m_klammers.count(name) > 0; } */ void Klammer_registry::add( const Argtype_registry& argtypes, const Target_registry& targets, Option_set_registry& option_sets, katom_iter begin, katom_iter end, katom_list& katoms) { (void)K::log(3, *begin, *(end - 1)); restore_initial_type(begin, end); auto [klammer_name, target_names, general_declared] = parse_name(targets, *begin); if (is_in(Target_registry::optionset_name, target_names)) { // The Machine routes an ".o" definition to the option set registry; // reaching here means it did not. parse_name has already rejected // ".o" as a member of a list, so this is the bare ".o" form. throw Internal_error( "The option set declaration \"" + klammer_name + ".o\" reached the klammer registry", begin->m_loc); } // Find the incoming definition mode katom_t incoming_deftype = katom_t::klammer_definition; for (auto it = begin + 1; it != end - 1; ++it) { if (is_deftype(it->m_type)) { incoming_deftype = it->m_type; break; } } defmode_t incoming_mode = defmode_from_katom(incoming_deftype); if (m_klammers.count(klammer_name) == 0) { m_klammers[klammer_name] = Klammer(klammer_name); } // Sticky: once a definition has written ".*", the klammer carries the // claim. A klammer with both a ".*" body and a target-specific one still // asserts that the general body serves everything else. if (general_declared) { m_klammers[klammer_name].m_general_declared = true; } // One definition per target named. A comma-separated list is surface // syntax: each target goes through the same registration, including the // redefinition transition table, so a list that collides with an existing // definition is decided per target -- one member may be silently ignored // or rejected while the others are created. for (const auto& target_name : target_names) { if (m_klammers[klammer_name].m_defloc.count(target_name) > 0) { defmode_t existing_mode = m_klammers[klammer_name].m_defmode[target_name]; const auto& result = defmode_transition(existing_mode, incoming_mode); std::string name_target = klammer_name + "." + target_name; std::string at_desc = m_klammers[klammer_name].m_defloc[target_name].desc(); if (!result.replace) { if (result.message.empty()) { // Silent ignore (e.g., create + default) continue; } std::string msg = result.message; msg = string_replace(msg, "NAME", q_(name_target)); msg = string_replace(msg, "AT", at_desc); throw Definition_error(msg, begin->m_loc); } if (result.warn) { std::string msg = result.message; msg = string_replace(msg, "NAME", q_(name_target)); msg = string_replace(msg, "AT", at_desc); warning(msg, begin->m_loc); } m_klammers[klammer_name].remove_target_definition(target_name); } m_klammers[klammer_name].add_target_definition( target_name, argtypes, option_sets, begin + 1, end - 1); // This add's target: Target target = targets.get(target_name, begin->m_loc); for (const auto& provide_name : target.m_provides) { if (m_klammers[klammer_name].m_defloc.count(provide_name) > 0) { m_klammers[klammer_name].remove_target_definition(provide_name); } m_klammers[klammer_name].add_target_definition( provide_name, argtypes, option_sets, begin + 1, end - 1); } } modify_type(katom_t::replaced, begin, end); auto next_iter = end; if (next_iter < katoms.end()) { // std::cout << "next_iter: " << kindex << *next_iter << "\n"; } else { // std::cout << "next_iter past end. katoms length: " << katoms.size() << "\n"; } ignore_whitespace(next_iter, katoms); } void Klammer_registry::rationalize(const Target_registry& targets) { (void)K::log(3); for (auto& [name, klammer] : m_klammers) { klammer.rationalize(targets); } } /* bool Klammer_registry::has(std::string name, std::string target) { return m_klammers.count(name) > 0; } */ void Klammer_registry::check_klammer(const std::string& name, const std::string& target, const Locator& loc) const { if (m_klammers.count(name) == 0) { throw Definition_error("The klammer " + q_(name) + " is not defined for an unspecified target", loc); } const Klammer& k = m_klammers.at(name); if (k.m_defloc.count(target) == 0) { std::string desc; if (target == Target_registry::general_name) { desc = "an unspecified target"; } else { desc = "target " + q_(target); } throw Definition_error("The " + q_(name) + " klammer is not defined for " + desc, loc); } } const std::vector* Klammer_registry::constant_body(const std::string& name) const { auto it = m_klammers.find(name); if (it == m_klammers.end()) return nullptr; const Klammer& k = it->second; // A constant klammer has no parameters at all — neither in the general // definition nor inherited from a .k declaration. A "::" instance has // empty d.parameters (it inherits), so we must also check that no other // definition (especially .k) declares parameters for this klammer. for (const auto& d : k.m_defs) { if (!d.parameters.empty()) return nullptr; } for (const auto& d : k.m_defs) { if (d.target == Target_registry::general_name && d.parameters.empty()) { return &d.body; } } return nullptr; } int max_length(const std::map& ss) { size_t result = 0; for_each(ss.begin(), ss.end(), [&result](const auto& s) { result = std::max(result, s.first.size()); }); return result; } std::string Klammer_registry::instance_list(int margin) const { std::stringstream ss {}; std::string tab(margin, ' '); auto name_width = max_length(m_klammers); for (const auto& [name, k] : m_klammers) { ss << tab << std::setfill(' ') << std::setw(name_width) << name << sp_arrow << k << "\n"; } return ss.str(); } std::string Klammer_registry::describe(int margin, const std::string& search) const { /* strings_t names {}; std::vector targets {}; strings_t locations {}; */ std::string result; std::string query = collapse_whitespace(search); for (const auto& [name, k] : m_klammers) { if (!query.empty() && !contains_fold(name, query) && !contains_fold(collapse_whitespace(k.description_text()), query)) { continue; } result += k.describe(margin) + "\n"; /* names.push_back(name); targets.push_back(k.get_target_names()); std::cout << name << " " << k.get_target_names() << "\n"; locator_summary(k.get_locations()); //locations.push_back( */ } return result; }