/** ** \file ast/dumper-dot.hxx ** \brief Implementation of ast::DumperDot. */ #pragma once #include #include #include namespace ast { template requires misc::ConstIterable inline void DumperDot::dump_list(const std::string& field, const Container& l) { const std::string* old_parent_field = parent_field; auto it = l.begin(); unsigned n = 0; while (it != l.end()) { std::ostringstream o; o << field; if (std::next(it) != l.end() || n > 0) o << n++; const std::string field_name = o.str(); parent_field = &field_name; (*it++)->accept(*this); } parent_field = old_parent_field; } template inline void DumperDot::dump_def(const T& e) const { const ast::Ast* d = nullptr; // FIXME: Some code was deleted here (set d using definition of e). (void)e; if (!d) return; ostr_ << parent_id << ":def:s -> " << reinterpret_cast(d) << ":nodename [constraint=false, style=dashed, color=\"dimgray\"]" << misc::iendl; } inline void DumperDot::display_link(unsigned long old_parent_id) const { if (parent_field) ostr_ << old_parent_id << ":" << *parent_field << ":s" << " -> " << parent_id << ":nodename:n" << misc::iendl; } inline void DumperDot::footer_and_link(unsigned long old_parent_id) const { node_html_footer(); display_link(old_parent_id); } template inline void DumperDot::dump_chunk(const E& e, const std::string& name) { unsigned long old_parent_id = parent_id; parent_id = reinterpret_cast(&e); ostr_ << parent_id << " [label=<" << misc::incendl << "" << misc::incendl << "" << misc::incendl; inner_fields = 0; node_html_port_list(name, e, true); ostr_ << misc::decendl << "" << misc::decendl << "
" << misc::decendl << ">]" << misc::iendl; display_link(old_parent_id); dump_list("nodename", e); parent_id = old_parent_id; } namespace { inline void node_html_begin_inner(std::ostream& ostr, bool list = false) { ostr << "" << misc::incendl << "" << misc::incendl << "" << misc::incendl; } inline void node_html_end_inner(std::ostream& ostr) { ostr << misc::decendl << "" << misc::decendl << "
" << misc::decendl << ""; } inline void node_html_separator(std::ostream& ostr) { node_html_end_inner(ostr); ostr << misc::decendl << "" << misc::iendl << "" << misc::incendl; node_html_begin_inner(ostr); } inline void node_html_tr(std::ostream& ostr, const std::string& port, const std::string content) { ostr << "" << content << ""; } inline bool ends_with(const std::string& value, const std::string& ending) { if (ending.size() > value.size()) return false; return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); } inline std::string node_html_color(const std::string& type) { if (ends_with(type, "Dec")) return "red1"; else if (ends_with(type, "Var")) return "orange1"; else if (ends_with(type, "Ty")) return "green3"; else if (ends_with(type, "Exp")) return "blue2"; return "black"; } template std::string html_escape(const T& input) { std::ostringstream i; i << input; const std::string& str = i.str(); std::ostringstream o; const std::string& specials = "&<>"; for (const auto& p : str) if (p == '\\') o << '\\' << '\\'; else if (specials.find(p) != std::string::npos) o << "&#" << static_cast(static_cast(p)) << ";"; else o << p; return o.str(); } } // namespace template inline unsigned long DumperDot::node_html_header(const T& e, const std::string& type) { unsigned long old_parent_id = parent_id; parent_id = reinterpret_cast(&e); ostr_ << parent_id << " [label=<" << misc::incendl << "" << misc::incendl << "" << misc::incendl; node_html_begin_inner(ostr_); node_html_tr(ostr_, "nodename", type); node_html_separator(ostr_); inner_fields = 0; return old_parent_id; } template inline void DumperDot::node_html_field(const std::string& name, const T& content, const std::string& sep) { std::ostringstream o; o << name << ": " << sep << html_escape(content) << sep; if (inner_fields++) ostr_ << misc::iendl; node_html_tr(ostr_, name, o.str()); } inline void DumperDot::node_html_one_port(const std::string& p) { if (inner_fields++) ostr_ << misc::iendl; node_html_tr(ostr_, p, p); } inline void DumperDot::node_html_ports(const std::vector& ports) { if (inner_fields) node_html_separator(ostr_); inner_fields = 0; for (auto p : ports) node_html_one_port(p); } template inline void DumperDot::node_html_port_list(const std::string& name, const T& list, bool chunk) { if (inner_fields++) ostr_ << misc::iendl; const std::string ref = chunk ? "nodename" : name; node_html_begin_inner(ostr_, true); long int size = std::distance(list.begin(), list.end()); ostr_ << ""; if (size > 1) { ostr_ << misc::decendl << "" << misc::iendl << "" << misc::incindent; for (long int n = 0; n < size; n++) ostr_ << misc::iendl << ""; } node_html_end_inner(ostr_); } inline void DumperDot::node_html_footer() const { if (!inner_fields) ostr_ << ""; node_html_end_inner(ostr_); ostr_ << misc::decendl << "" << misc::decendl << "
" << name << "
" << n << "
" << misc::decendl << ">]" << misc::iendl; } } // namespace ast