diff -uNr a/vtools/manifest b/vtools/manifest --- a/vtools/manifest b2e3eb274b80a94c295a07f158fffdc7d757ca22d729d9171b6e6141d3652f643bb7a9868c01516aff282ed0106bd27c24ac87139154995e1122424daf38ee96 +++ b/vtools/manifest e3f059374c1d6e57a7897b0e834261ee3db264d486cbb8efecb18d3acb22b0bf9cf40014d742454e54a6ac398378106e2ae6b5605db053637427843ed9baa94e @@ -18,3 +18,4 @@ 619714 bvt vtools_vsh_shellcheck A round of shellcheck on the v.sh source. 620790 bvt vtools_ascii_visualization Add "vtree" command, work towards pipeable output. 621251 bvt vtools_vsh_ascii_fix2 vflow: remove early exit, DFS-based toposorting; v.sh: correct error checking and reporting in v.sh, fix vtree indentation, better error reporting in case of conflicts; makefile: remove. +621530 bvt vtools_vsh_orphans Handle vpatches without antecedents without crashing. diff -uNr a/vtools/src/vflow.adb b/vtools/src/vflow.adb --- a/vtools/src/vflow.adb 5ee6bcb685f193971ff5990bf189e36b52cd113e289cf46248fcd29da401a00114e4e22235f2f4d492a202546c6622a73976ed524ba9cd1f0f9dce8a6fcf3a11 +++ b/vtools/src/vflow.adb 48b4309512d0881e132e7e19127d6105143fdea928be46f0e04d2c88fed8b7184d6e804b1631cb7ccb475c87b4c45761a2ae07348e230671838faf652f42982b @@ -34,6 +34,7 @@ Vpatch_Dependencies: Vpatch_Relationship := (others => (others => False)); Vpatch_Conflicts : Vpatch_Relationship := (others => (others => False)); Vpatch_Order : Vpatch_List := (others => 0); + Vpatch_Orphans : Vpatch_Set := (others => False); function Get_Hunk return Hunk is H: Hunk; @@ -210,7 +211,8 @@ -- Looped through all vpatches, there are hunks without matched inputs: if not Finished then - raise Constraint_Error with "Unsatisfied hunks."; + Put_Line("O " & Integer'Image(I)); + Vpatch_Orphans(I) := True; end if; end; end loop; @@ -292,7 +294,7 @@ -- Check if there are still free vpatches (there is a loop): for I in Free_Vpatches'Range loop - if Free_Vpatches(I) then + if Free_Vpatches(I) and not Vpatch_Orphans(I) then Put_Line("L " & Integer'Image(I)); Has_Loops := True; end if; @@ -305,7 +307,7 @@ for I in R'Range(1) loop for J in R'Range(2) loop if R(I,J) then - Put_Line(C & " " & Integer'Image(I) & " " & Integer'Image(J)); + Put_Line(C & " " & Integer'Image(I) & " " & Integer'Image(J)); end if; end loop; end loop; @@ -369,24 +371,51 @@ end Read_Selection; procedure Add_Dependencies is - Finish : Boolean := False; begin - while not Finish loop - Finish := True; - for I in Selected_Vpatches'Range loop - if Selected_Vpatches(I) then - for J in Vpatch_Dependencies'Range(2) loop - if Vpatch_Dependencies(I,J) and not Selected_Vpatches(J) then - Finish := False; - Selected_Vpatches(J) := True; - end if; - end loop; - end if; - end loop; + -- loop forward propagating orphans + for I in Vpatch_Order'Range loop + declare + V : Vpatch_Index := Vpatch_Order(I); + begin + for J in Vpatch_Dependencies'Range(2) loop + if Vpatch_Dependencies(V,J) and Vpatch_Orphans(J) then + Vpatch_Orphans(V) := True; + end if; + end loop; + end; + end loop; + + for I in reverse Vpatch_Order'Range loop + declare + V : Vpatch_Index := Vpatch_Order(I); + begin + for J in Vpatch_Dependencies'Range(1) loop + if Vpatch_Dependencies(J,V) and Selected_Vpatches(J) then + Selected_Vpatches(V) := True; + end if; + end loop; + end; end loop; end Add_Dependencies; - procedure Print_Flow_Or_Conflicts is + procedure Print_Heads is + begin + for I in Vpatch_Dependencies'Range(2) loop + declare + Is_Head : Boolean := not Vpatch_Orphans(I); + begin + for J in Vpatch_Dependencies'Range(1) loop + Is_Head := Is_Head and + (not Vpatch_Dependencies(J,I) or Vpatch_Orphans(J)); + end loop; + if Is_Head then + Put_Line("H " & Integer'Image(I)); + end if; + end; + end loop; + end Print_Heads; + + procedure Print_Flow_And_Conflicts is begin for I in Vpatch_Conflicts'Range(1) loop for J in Vpatch_Conflicts'Range(2) loop @@ -399,18 +428,27 @@ end loop; for I in Vpatch_Order'Range loop - if Selected_Vpatches(Vpatch_Order(I)) then - Put_Line("P " & Integer'Image(Vpatch_Order(I))); - else - Put_Line("p " & Integer'Image(Vpatch_Order(I))); - end if; + declare + V : Vpatch_Index := Vpatch_Order(I); + begin + if Selected_Vpatches(V) and not Vpatch_Orphans(V) then + Put_Line("P " & Integer'Image(V)); + elsif Selected_Vpatches(V) and Vpatch_Orphans(V) then + Put_Line("E " & Integer'Image(V)); + elsif not Selected_Vpatches(V) and not Vpatch_Orphans(V) then + Put_Line("p " & Integer'Image(V)); + else + Put_Line("e " & Integer'Image(V)); + end if; + end; end loop; - end Print_Flow_Or_Conflicts; + end Print_Flow_And_Conflicts; begin Read_Selection; Add_Dependencies; - Print_Flow_Or_Conflicts; + Print_Heads; + Print_Flow_And_Conflicts; end Print_Selected; begin diff -uNr a/vtools/v.sh b/vtools/v.sh --- a/vtools/v.sh e64bb2725e055aaa4e7ce33a909209d55686fb42e4105fb0d383cf5d80145104333673486cf1dfbb2a42e6e2743cf9466d17fe7f799b40aaa708b5421afd854e +++ b/vtools/v.sh 91559c9818cadf7a6409f1c873759f1ef370edd0f9d9627e534105f1a3e6c4119f552142121143bfa808516cf2abb58d7df9ef07b883322e01b78dbaf1fc0ad2 @@ -2,6 +2,8 @@ set -e +[ -n "$VERBOSE" ] && set -x + allkeyword="all" vgpgdir="" @@ -139,28 +141,35 @@ vflow $(wc -l <"$filtered") $(wc -l <"$vpatches") >"$topo" } +report_vpatches() { + >&2 printf "$1" + awk -v L="$2" '$1 == L {print $2}' < "$topo" | vpatchnames >&2 +} + vpatchflowerr() { set +e awk 'BEGIN {err=0; ok=0;} err == 0 && $1 == "C" {err=1; ech=$1;} err == 0 && $1 == "L" {err=2; ech=$1;} +err == 0 && $1 == "E" {err=3; ech=$1;} err == 0 && $1 == "P" {ok=1;} -END {if (err != 0) exit err; if (ok != 1) exit 3; exit 0;}' <"$topo" +END {if (err != 0) exit err; if (ok != 1) exit 4; exit 0;}' <"$topo" exitcode="$?" set -e if [ "$exitcode" -eq "1" ]; then >&2 printf "Conflicting leaves selected:\n" awk '$1 == "C" {print $2}' < "$topo" | vpatchnames | sort | uniq >&2 - >&2 printf "Available heads:\n" - awk ' -($1 == "I" || $1 == "d" ) {non_terminals[$3]=1;} -($1 == "P") {if (!($2 in non_terminals)) {print $2;}}' < "$topo" | vpatchnames >&2 + report_vpatches "Orphans:\n" "O" + report_vpatches "Available heads:\n" "H" fail elif [ "$exitcode" -eq "2" ]; then - >&2 printf "Loop among vpatches:\n" - awk '{print $2}' < "$topo" | vpatchnames >&2 + report_vpatches "Loop among vpatches:\n" "L" fail elif [ "$exitcode" -eq "3" ]; then + report_vpatches "Orphan vpatches selected:\n" "E" + report_vpatches "Available heads:\n" "H" + fail + elif [ "$exitcode" -eq "4" ]; then >&2 echo "Unknown error. Investigate in $vgpgdir:" >&2 cat "$topo" exit 1 # no cleanup @@ -194,9 +203,11 @@ cat >"$dotfile" < \""a[$2]"\""} FILENAME=="-" && $1 == "d" {print "\""a[$3]"\" -> \""a[$2]"\""} ' "$vpatches" - <"$topo" >>"$dotfile" echo "}" >> "$dotfile" @@ -285,9 +296,10 @@ function max(a,b) { return (a > b) ? a : b;} function repeat(s,n) {i=0; while (i++ < n) {printf("%s",s);}} FILENAME==VF {names[$2]=$1} -FILENAME=="-" && ($1 == "I" || $1 == "d" ) {non_terminals[$3]=1;} +FILENAME=="-" && ($1 == "O") {print "Orphan:", names[$2]; orphans[$2]=1;} +FILENAME=="-" && ($1 == "H" ) {heads[$2]=1;} FILENAME=="-" && ($1 == "d") {if (!($2 in n_ante)) n_ante[$2] = 0; dir_ante[$2][n_ante[$2]] = $3; n_ante[$2]++;} -FILENAME=="-" && ($1 == "P" || $1 == "p") { +FILENAME=="-" && ($1 == "P" || $1 == "p" || $1 == "E" || $1 == "e") { level[$2] = 0; if ($2 in n_ante) { for (i = 0; i < n_ante[$2]; i++) { @@ -295,7 +307,8 @@ } } repeat(" ", level[$2]); - printf("%s%s%s\n",names[$2], ($2 in non_terminals) ? "" : " (*)", ($1 == "P") ? " +" : "" ); + if ($1 =="E" || $1 == "e") printf("O: "); + printf("%s%s%s\n",names[$2], ($2 in heads) ? " (*)" : "", ($1 == "P") ? " +" : "" ); }' "$vpatches" - <"$topo" exit_success fi