Refactored JSON sequence diagram generator

This commit is contained in:
Bartek Kryza
2023-03-19 19:08:15 +01:00
parent f0497e934d
commit 44cd7b0484
6 changed files with 335 additions and 227 deletions

View File

@@ -111,6 +111,8 @@ std::string to_string(message_t r)
return "end switch"; return "end switch";
case message_t::kConditional: case message_t::kConditional:
return "conditional"; return "conditional";
case message_t::kConditionalElse:
return "conditional else";
case message_t::kConditionalEnd: case message_t::kConditionalEnd:
return "end conditional"; return "end conditional";
default: default:

View File

@@ -61,6 +61,7 @@ enum class message_t {
kCase, kCase,
kSwitchEnd, kSwitchEnd,
kConditional, kConditional,
kConditionalElse,
kConditionalEnd, kConditionalEnd,
kNone kNone
}; };

View File

@@ -97,9 +97,6 @@ void generator::generate_call(const message &m, nlohmann::json &parent) const
.message_name(render_mode); .message_name(render_mode);
} }
} }
//
// const std::string from_alias = generate_alias(from.value());
// const std::string to_alias = generate_alias(to.value());
nlohmann::json msg; nlohmann::json msg;
@@ -149,11 +146,77 @@ void generator::generate_activity(
{ {
// Generate calls from this activity to other activities // Generate calls from this activity to other activities
for (const auto &m : a.messages()) { for (const auto &m : a.messages()) {
if (m.type() == message_t::kCall) { switch (m.type()) {
const auto &to = case message_t::kCall:
m_model.get_participant<model::participant>(m.to()); process_call_message(m, visited);
break;
case message_t::kIf:
process_if_message(m);
break;
case message_t::kElseIf:
case message_t::kElse:
process_else_if_message();
break;
case message_t::kIfEnd:
process_end_if_message();
break;
case message_t::kWhile:
process_while_message(m);
break;
case message_t::kWhileEnd:
process_end_while_message();
break;
case message_t::kFor:
process_for_message(m);
break;
case message_t::kForEnd:
process_end_for_message();
break;
case message_t::kDo:
process_do_message(m);
break;
case message_t::kDoEnd:
process_end_do_message();
break;
case message_t::kTry:
process_try_message(m);
break;
case message_t::kCatch:
process_catch_message();
break;
case message_t::kTryEnd:
process_end_try_message();
break;
case message_t::kSwitch:
process_switch_message(m);
break;
case message_t::kCase:
process_case_message(m);
break;
case message_t::kSwitchEnd:
process_end_switch_message();
break;
case message_t::kConditional:
process_conditional_message(m);
break;
case message_t::kConditionalElse:
process_conditional_else_message();
break;
case message_t::kConditionalEnd:
process_end_conditional_message();
break;
case message_t::kNone:
case message_t::kReturn:; // noop
}
}
}
void generator::process_call_message(const model::message &m,
std::vector<common::model::diagram_element::id_t> &visited) const
{
const auto &to = m_model.get_participant<model::participant>(m.to());
if (!to || to.value().skip()) if (!to || to.value().skip())
continue; return;
visited.push_back(m.from()); visited.push_back(m.from());
@@ -163,8 +226,7 @@ void generator::generate_activity(
if (m_model.sequences().find(m.to()) != m_model.sequences().end()) { if (m_model.sequences().find(m.to()) != m_model.sequences().end()) {
if (std::find(visited.begin(), visited.end(), m.to()) == if (std::find(visited.begin(), visited.end(), m.to()) ==
visited visited.end()) { // break infinite recursion on recursive calls
.end()) { // break infinite recursion on recursive calls
LOG_DBG("Creating activity {} --> {} - missing sequence {}", LOG_DBG("Creating activity {} --> {} - missing sequence {}",
m.from(), m.to(), m.to()); m.from(), m.to(), m.to());
@@ -174,103 +236,75 @@ void generator::generate_activity(
} }
} }
else else
LOG_DBG("Skipping activity {} --> {} - missing sequence {}", LOG_DBG("Skipping activity {} --> {} - missing sequence {}", m.from(),
m.from(), m.to(), m.to()); m.to(), m.to());
} }
else if (m.type() == message_t::kIf) {
nlohmann::json if_block;
if_block["type"] = "alt";
if_block["name"] = "if";
if_block["activity_id"] = std::to_string(m.from());
current_block_statement()["messages"].push_back( void generator::process_while_message(const message &m) const
std::move(if_block)); {
block_statements_stack_.push_back(
std::ref(current_block_statement()["messages"].back()));
nlohmann::json branch;
branch["type"] = "consequent";
current_block_statement()["branches"].push_back(std::move(branch));
block_statements_stack_.push_back(
std::ref(current_block_statement()["branches"].back()));
}
else if (m.type() == message_t::kElseIf ||
m.type() == message_t::kElse) {
// remove previous branch from the stack
block_statements_stack_.pop_back();
nlohmann::json branch;
branch["type"] = "alternative";
current_block_statement()["branches"].push_back(std::move(branch));
block_statements_stack_.push_back(
std::ref(current_block_statement()["branches"].back()));
}
else if (m.type() == message_t::kIfEnd) {
// Remove last if branch from the stack
block_statements_stack_.pop_back();
// Remove the if statement block from the stack
block_statements_stack_.pop_back();
}
else if (m.type() == message_t::kWhile) {
nlohmann::json while_block; nlohmann::json while_block;
while_block["type"] = "loop"; while_block["type"] = "loop";
while_block["name"] = "while"; while_block["name"] = "while";
while_block["activity_id"] = std::to_string(m.from()); while_block["activity_id"] = std::to_string(m.from());
current_block_statement()["messages"].push_back( current_block_statement()["messages"].push_back(std::move(while_block));
std::move(while_block));
block_statements_stack_.push_back( block_statements_stack_.push_back(
std::ref(current_block_statement()["messages"].back())); std::ref(current_block_statement()["messages"].back()));
} }
else if (m.type() == message_t::kWhileEnd) {
void generator::process_end_while_message() const
{
// Remove the while statement block from the stack // Remove the while statement block from the stack
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
} }
else if (m.type() == message_t::kFor) {
void generator::process_for_message(const message &m) const
{
nlohmann::json for_block; nlohmann::json for_block;
for_block["type"] = "loop"; for_block["type"] = "loop";
for_block["name"] = "for"; for_block["name"] = "for";
for_block["activity_id"] = std::to_string(m.from()); for_block["activity_id"] = std::to_string(m.from());
current_block_statement()["messages"].push_back( current_block_statement()["messages"].push_back(std::move(for_block));
std::move(for_block));
block_statements_stack_.push_back( block_statements_stack_.push_back(
std::ref(current_block_statement()["messages"].back())); std::ref(current_block_statement()["messages"].back()));
} }
else if (m.type() == message_t::kForEnd) {
void generator::process_end_for_message() const
{
// Remove the while statement block from the stack // Remove the while statement block from the stack
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
} }
else if (m.type() == message_t::kDo) {
void generator::process_do_message(const message &m) const
{
nlohmann::json do_block; nlohmann::json do_block;
do_block["type"] = "loop"; do_block["type"] = "loop";
do_block["name"] = "do"; do_block["name"] = "do";
do_block["activity_id"] = std::to_string(m.from()); do_block["activity_id"] = std::to_string(m.from());
current_block_statement()["messages"].push_back( current_block_statement()["messages"].push_back(std::move(do_block));
std::move(do_block));
block_statements_stack_.push_back( block_statements_stack_.push_back(
std::ref(current_block_statement()["messages"].back())); std::ref(current_block_statement()["messages"].back()));
} }
else if (m.type() == message_t::kDoEnd) {
void generator::process_end_do_message() const
{
// Remove the do statement block from the stack // Remove the do statement block from the stack
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
} }
else if (m.type() == message_t::kTry) {
void generator::process_try_message(const message &m) const
{
nlohmann::json try_block; nlohmann::json try_block;
try_block["type"] = "break"; try_block["type"] = "break";
try_block["name"] = "try"; try_block["name"] = "try";
try_block["activity_id"] = std::to_string(m.from()); try_block["activity_id"] = std::to_string(m.from());
current_block_statement()["messages"].push_back( current_block_statement()["messages"].push_back(std::move(try_block));
std::move(try_block));
block_statements_stack_.push_back( block_statements_stack_.push_back(
std::ref(current_block_statement()["messages"].back())); std::ref(current_block_statement()["messages"].back()));
@@ -282,7 +316,9 @@ void generator::generate_activity(
block_statements_stack_.push_back( block_statements_stack_.push_back(
std::ref(current_block_statement()["blocks"].back())); std::ref(current_block_statement()["blocks"].back()));
} }
else if (m.type() == message_t::kCatch) {
void generator::process_catch_message() const
{
// remove previous block from the stack // remove previous block from the stack
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
@@ -293,26 +329,31 @@ void generator::generate_activity(
block_statements_stack_.push_back( block_statements_stack_.push_back(
std::ref(current_block_statement()["blocks"].back())); std::ref(current_block_statement()["blocks"].back()));
} }
else if (m.type() == message_t::kTryEnd) {
void generator::process_end_try_message() const
{
// Remove last if block from the stack // Remove last if block from the stack
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
// Remove the try statement block from the stack // Remove the try statement block from the stack
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
} }
else if (m.type() == message_t::kSwitch) {
void generator::process_switch_message(const message &m) const
{
nlohmann::json if_block; nlohmann::json if_block;
if_block["type"] = "alt"; if_block["type"] = "alt";
if_block["name"] = "switch"; if_block["name"] = "switch";
if_block["activity_id"] = std::to_string(m.from()); if_block["activity_id"] = std::to_string(m.from());
current_block_statement()["messages"].push_back( current_block_statement()["messages"].push_back(std::move(if_block));
std::move(if_block));
block_statements_stack_.push_back( block_statements_stack_.push_back(
std::ref(current_block_statement()["messages"].back())); std::ref(current_block_statement()["messages"].back()));
} }
else if (m.type() == message_t::kCase) {
void generator::process_case_message(const message &m) const
{
if (current_block_statement()["type"] == "case") if (current_block_statement()["type"] == "case")
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
@@ -324,21 +365,23 @@ void generator::generate_activity(
block_statements_stack_.push_back( block_statements_stack_.push_back(
std::ref(current_block_statement()["cases"].back())); std::ref(current_block_statement()["cases"].back()));
} }
else if (m.type() == message_t::kSwitchEnd) {
// Remove last case block from the stack void generator::process_end_switch_message() const
{ // Remove last case block from the stack
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
// Remove the switch statement block from the stack // Remove the switch statement block from the stack
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
} }
else if (m.type() == message_t::kConditional) {
void generator::process_conditional_message(const message &m) const
{
nlohmann::json if_block; nlohmann::json if_block;
if_block["type"] = "alt"; if_block["type"] = "alt";
if_block["name"] = "conditional"; if_block["name"] = "conditional";
if_block["activity_id"] = std::to_string(m.from()); if_block["activity_id"] = std::to_string(m.from());
current_block_statement()["messages"].push_back( current_block_statement()["messages"].push_back(std::move(if_block));
std::move(if_block));
block_statements_stack_.push_back( block_statements_stack_.push_back(
std::ref(current_block_statement()["messages"].back())); std::ref(current_block_statement()["messages"].back()));
@@ -350,7 +393,9 @@ void generator::generate_activity(
block_statements_stack_.push_back( block_statements_stack_.push_back(
std::ref(current_block_statement()["branches"].back())); std::ref(current_block_statement()["branches"].back()));
} }
else if (m.type() == message_t::kElse) {
void generator::process_conditional_else_message() const
{
// remove previous branch from the stack // remove previous branch from the stack
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
@@ -361,18 +406,56 @@ void generator::generate_activity(
block_statements_stack_.push_back( block_statements_stack_.push_back(
std::ref(current_block_statement()["branches"].back())); std::ref(current_block_statement()["branches"].back()));
} }
else if (m.type() == message_t::kConditionalEnd) {
void generator::process_end_conditional_message() const
{
// Remove last if branch from the stack // Remove last if branch from the stack
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
// Remove the if statement block from the stack // Remove the if statement block from the stack
block_statements_stack_.pop_back(); block_statements_stack_.pop_back();
} }
else {
// Unhandled message_t case void generator::process_end_if_message() const
assert(false); {
// Remove last if branch from the stack
block_statements_stack_.pop_back();
// Remove the if statement block from the stack
block_statements_stack_.pop_back();
} }
void generator::process_else_if_message() const
{
// remove previous branch from the stack
block_statements_stack_.pop_back();
nlohmann::json branch;
branch["type"] = "alternative";
current_block_statement()["branches"].push_back(std::move(branch));
block_statements_stack_.push_back(
std::ref(current_block_statement()["branches"].back()));
} }
void generator::process_if_message(const message &m) const
{
nlohmann::json if_block;
if_block["type"] = "alt";
if_block["name"] = "if";
if_block["activity_id"] = std::to_string(m.from());
current_block_statement()["messages"].push_back(std::move(if_block));
block_statements_stack_.push_back(
std::ref(current_block_statement()["messages"].back()));
nlohmann::json branch;
branch["type"] = "consequent";
current_block_statement()["branches"].push_back(std::move(branch));
block_statements_stack_.push_back(
std::ref(current_block_statement()["branches"].back()));
} }
void generator::generate_participant( void generator::generate_participant(

View File

@@ -76,6 +76,28 @@ private:
mutable std::vector<std::reference_wrapper<nlohmann::json>> mutable std::vector<std::reference_wrapper<nlohmann::json>>
block_statements_stack_; block_statements_stack_;
void process_call_message(const model::message &m,
std::vector<common::model::diagram_element::id_t> &visited) const;
void process_if_message(const model::message &m) const;
void process_else_if_message() const;
void process_end_if_message() const;
void process_end_conditional_message() const;
void process_conditional_else_message() const;
void process_conditional_message(const model::message &m) const;
void process_end_switch_message() const;
void process_case_message(const model::message &m) const;
void process_switch_message(const model::message &m) const;
void process_end_try_message() const;
void process_catch_message() const;
void process_try_message(const model::message &m) const;
void process_end_do_message() const;
void process_do_message(const model::message &m) const;
void process_end_for_message() const;
void process_for_message(const model::message &m) const;
void process_end_while_message() const;
void process_while_message(const model::message &m) const;
}; };
} // namespace clanguml::sequence_diagram::generators::json } // namespace clanguml::sequence_diagram::generators::json

View File

@@ -233,7 +233,7 @@ void generator::generate_activity(const activity &a, std::ostream &ostr,
print_debug(m, ostr); print_debug(m, ostr);
ostr << "alt\n"; ostr << "alt\n";
} }
else if (m.type() == message_t::kElse) { else if (m.type() == message_t::kConditionalElse) {
print_debug(m, ostr); print_debug(m, ostr);
ostr << "else\n"; ostr << "else\n";
} }

View File

@@ -821,7 +821,7 @@ bool translation_unit_visitor::TraverseConditionalOperator(
stmt->getTrueExpr()); stmt->getTrueExpr());
if (current_caller_id != 0) { if (current_caller_id != 0) {
model::message m{message_t::kElse, current_caller_id}; model::message m{message_t::kConditionalElse, current_caller_id};
set_source_location(*stmt, m); set_source_location(*stmt, m);
diagram().add_message(std::move(m)); diagram().add_message(std::move(m));
} }