2023-03-10 10:30:54 -05:00
|
|
|
# Generate ontology visualization for the ASG
|
|
|
|
#
|
|
|
|
# Copyright (C) 2014-2023 Ryan Specialty, LLC.
|
|
|
|
#
|
|
|
|
# This file is part of TAME.
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
# Use the sibling `asg-ontvis` script to invoke this for you with the
|
|
|
|
# necessary files.
|
|
|
|
#
|
|
|
|
# The relationships between objects on the ASG are defined declaratively
|
|
|
|
# using the `object_rel!` macro.
|
|
|
|
# They follow this syntax:
|
|
|
|
#
|
|
|
|
# object_rel! {
|
|
|
|
# Source -> {
|
|
|
|
# tree TargetA,
|
|
|
|
# tree TargetB,
|
|
|
|
# cross TargetC,
|
|
|
|
# }
|
|
|
|
# }
|
|
|
|
#
|
|
|
|
# This script expects to receive a list of files containing such
|
|
|
|
# definitions.
|
|
|
|
# It will output,
|
|
|
|
# to stdout,
|
|
|
|
# a DOT definition representing the ASG's ontology,
|
|
|
|
# which can be used to render a visualization.
|
|
|
|
#
|
|
|
|
# To render the output of this script,
|
|
|
|
# pipe it to e.g. `dot -Tsvg > out.svg`.
|
|
|
|
#
|
|
|
|
# This tool is supposed to generate human-readable DOT output;
|
|
|
|
# please retain that quality in any changes you make.
|
|
|
|
# This is helpful not only to help the user figure out what output they're
|
|
|
|
# seeing,
|
|
|
|
# but is also useful because the DOT output is quite understandable by
|
|
|
|
# itself without the need to generate a graphical representation,
|
|
|
|
# depending on the information the user is looking for.
|
|
|
|
|
|
|
|
BEGIN {
|
|
|
|
print "# Representation of the TAMER ASG ontology generated by asg-ontviz."
|
|
|
|
print "# Generate visualization using e.g. `dot -Tsvg > out.svg`."
|
|
|
|
|
|
|
|
print "digraph {"
|
|
|
|
|
|
|
|
# Whether we're parsing a `object_rel!` block.
|
|
|
|
in_block = 0
|
|
|
|
|
|
|
|
# The current source relation, if `in_block_subexpr`.
|
|
|
|
block_src = ""
|
|
|
|
|
|
|
|
# The final exit status (0 = success)
|
|
|
|
exit_code = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
BEGINFILE {
|
|
|
|
# Whether any object relationships were found in the file.
|
|
|
|
# This is used in `ENDFILE` to notify the user that something may be
|
|
|
|
# wrong.
|
|
|
|
found_rels = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
# Skip comments.
|
|
|
|
/^ *\/+/ { next }
|
|
|
|
|
|
|
|
# Predicates will be reset for each line,
|
|
|
|
# allowing the remainder of the script to be read more declaratively.
|
|
|
|
{ in_block = in_block_subexpr = 0 }
|
|
|
|
|
|
|
|
# Block predicates for each line of text.
|
|
|
|
/^object_rel! {$/, /^}$/ { in_block = 1 }
|
|
|
|
|
|
|
|
# `Foo -> {` line declares the source of the relation.
|
|
|
|
in_block && /->/ {
|
|
|
|
block_src = $1
|
|
|
|
|
|
|
|
printf " # `%s` from `%s:%d`\n", block_src, FILENAME, FNR
|
|
|
|
|
|
|
|
next
|
|
|
|
}
|
|
|
|
|
|
|
|
# A closing curly brace always means that we've finished with the current
|
|
|
|
# source relation,
|
|
|
|
# since we're at the innermost level of nesting.
|
|
|
|
block_src && /}/ {
|
|
|
|
block_src = ""
|
|
|
|
print ""
|
|
|
|
}
|
|
|
|
|
|
|
|
# For each target object,
|
|
|
|
# output a relation.
|
|
|
|
#
|
|
|
|
# The DOT format is pretty rigid;
|
|
|
|
# because we are styling,
|
|
|
|
# we cannot use curly braces similar to how the relation is defined in
|
|
|
|
# Rust using the `object_rel!` macro;
|
|
|
|
# we must independently define each one.
|
|
|
|
# But that's okay;
|
|
|
|
# the output is quite legible.
|
|
|
|
block_src && $NF ~ /\w+,$/ {
|
|
|
|
# Edge type (cross, tree)
|
|
|
|
ty = $(NF-1)
|
|
|
|
|
2023-03-17 12:53:53 -04:00
|
|
|
# Dashed is visually in-between solid and dotted,
|
|
|
|
# and `dyn` is either `tree` or `cross`,
|
|
|
|
# determined at runtime.
|
|
|
|
# But we may need some other representation if `dotted` is too visually
|
|
|
|
# sparse and difficult/annoying to see;
|
|
|
|
# let's see where the ASG visualization ends up first.
|
2023-03-10 10:30:54 -05:00
|
|
|
attrs = ""
|
2023-03-17 12:53:53 -04:00
|
|
|
switch (ty) {
|
|
|
|
case "tree":
|
|
|
|
attrs="[style=solid]";
|
|
|
|
break;
|
|
|
|
case "cross":
|
|
|
|
attrs="[style=dotted]";
|
|
|
|
break;
|
|
|
|
case "dyn":
|
|
|
|
attrs="[style=dashed]";
|
|
|
|
break;
|
2023-03-10 10:30:54 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
gsub(/,$/, "")
|
|
|
|
|
|
|
|
# This may need updating over time as object names in Rust sources
|
|
|
|
# exceed the fixed-width definition here.
|
|
|
|
# This output is intended to form a table that is easy to read and
|
|
|
|
# visually scan.
|
|
|
|
# For this reason,
|
|
|
|
# the source object is right-aligned and target is left-aligned,
|
|
|
|
# so that `Src -> Target` can be easily read regardless of the width
|
|
|
|
# of the objects involved.
|
|
|
|
printf " %5s -> %-5s %14s; # %s edge\n", block_src, $NF, attrs, ty
|
|
|
|
|
|
|
|
found_rels++
|
|
|
|
}
|
|
|
|
|
|
|
|
ENDFILE {
|
|
|
|
if (found_rels == 0) {
|
|
|
|
# Note that this can happen if the macro is changed or the calling
|
|
|
|
# `asg-ontvis` shell script is not providing the correct
|
|
|
|
# filenames.
|
|
|
|
printf "error: no relations found in `%s`\n", FILENAME >"/dev/stderr"
|
|
|
|
exit_code = 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
END {
|
|
|
|
print "}"
|
|
|
|
exit exit_code
|
|
|
|
}
|