#!/bin/bash usage(){ cat <&2 Usage : hierarchy-diagram [OPTIONS] Description: hierarchy-diagram is a small utility to draw hierarchy diagrams of mathematical structures. This utility uses the coercion paths and the canonical projections between .type types (typically in the MathComp library) to draw the diagram. Indirect edges which can be composed of other edges by transitivity are eliminated automatically for each kind of edges. A diagram appears on the standard output in the DOT format which can be converted to several image formats by Graphviz. Options: -h, -help: Output a usage message and exit. -canonicals (off|on|color): Configure output of edges of canonical projections. The default value is "on". -coercions (off|on|color): Configure output of edges of coercions. The default value is "off". The value given by this option must be different from that by -canonical soption. -R dir coqdir: This option is passed to coqtop: "recursively map physical dir to logical coqdir". -lib library: Specify a Coq library used to draw a diagram. This option can appear repetitively. If not specified, all.all will be used. EOT } raw_coercions=$(tempfile -s .out | sed s/\.out$//) raw_canonicals=$(tempfile -s .out | sed s/\.out$//) parsed_coercions=$(tempfile) parsed_canonicals=$(tempfile) opt_raw_inheritances=off opt_canonicals=on opt_coercions=off opt_libs=() opt_coqtopargs=() while [[ $# -gt 0 ]] do case "$1" in -raw-inheritances) opt_raw_inheritances=on shift; ;; -canonicals) opt_canonicals="$2" shift; shift ;; -coercions) opt_coercions="$2" shift; shift ;; -R) opt_coqtopargs+=("-R" "$2" "$3") shift; shift; shift ;; -lib) opt_libs+=("$2") shift; shift ;; -h|-help) usage; exit ;; *) echo "ERROR: invalid option -- $1" >&2 echo >&2 usage; exit 1 ;; esac done [[ ${#opt_libs[@]} -eq 0 ]] && opt_libs=(all.all) coqtop -w none ${opt_coqtopargs[@]} >/dev/null 2>&1 < $parsed_canonicals cat $raw_coercions.out \ | sed -n 's/^\[\([^]]*\)\] : \([a-zA-Z_\.]*\)\.type >-> \([a-zA-Z_\.]*\)\.type$/\2 \3 \1/p' > $parsed_coercions if [[ $opt_raw_inheritances != "off" ]]; then cat $parsed_canonicals | sed 's/^\([^ ]*\) \([^ ]*\) .*$/\1\n\2/g' | sort | uniq \ | while read -r module; do echo -n "$module " sed -n "s/^\([^ ]*\) $module .*$/\1/p" $parsed_canonicals | sort | xargs done else echo "digraph structures {" if [[ $opt_canonicals != "off" ]]; then cat $parsed_canonicals | while read -r from_module to_module proj_module projection; do grep "^$from_module " $parsed_canonicals | ( while read -r _ middle_module _ _; do if grep -q "^$middle_module $to_module " $parsed_canonicals; then exit 1 fi done ) if [[ "$?" = "0" ]]; then echo -n "\"$to_module\" -> \"$from_module\"" [[ $opt_canonicals == "on" ]] || echo -n "[color=$opt_canonicals]" echo ";" fi done fi if [[ $opt_coercions != "off" ]]; then cat $parsed_coercions | while read -r from_module to_module coercion; do grep "^$from_module " $parsed_coercions | ( while read -r _ middle_module _; do if grep -q "^$middle_module $to_module " $parsed_coercions; then exit 1 fi done ) if [[ "$?" = "0" ]]; then echo -n "\"$to_module\" -> \"$from_module\"" [[ $opt_coercions == "on" ]] || echo -n "[color=$opt_coercions]" echo ";" fi done fi echo "}" fi rm $raw_coercions.out $raw_canonicals.out $parsed_coercions $parsed_canonicals