user
Given a mapping between items, and items they depend on, a topological sort orders items so that no item precedes an item it depends upon.

The compiling of a design in the VHDL language has the constraint that a file must be compiled after any file containing definitions it depends on. A tool exists that extracts file dependencies.

* Assume the file names are single words, given without their file extensions.
* Files mentioned as only dependants, have no dependants of their own, but their order of compiling must be given.
* Any self dependencies should be ignored.

A top level file is defined as a file that:

1. Has dependents.
2. Is not itself the dependent of another file

**Task Description**

Given the following file dependencies as an example:

```
FILE    FILE DEPENDENCIES
====    =================
top1    des1 ip1 ip2
top2    des1 ip2 ip3
ip1     extra1 ip1a ipcommon
ip2     ip2a ip2b ip2c ipcommon
des1    des1a des1b des1c
des1a   des1a1 des1a2
des1c   des1c1 extra1
```

The task is to create a program that given a graph of the dependency:

1. Determines the top levels from the dependencies and show them.
2. Extracts a compile order of files to compile any given (usually top level) file.
3. Give a compile order for file top1.
4. Give a compile order for file top2.

You may show how to compile multiple top levels as a stretch goal

Note: this task differs from task Topological sort in that the order for compiling any file might not include all files; and that checks for dependency cycles are not mandated.

Related task

* Topological sort
assistant
(formerly Perl 6)

```
sub top_topos ( %deps, *@top ) {
    my %ba;
    for %deps.kv -> $after, @befores {
        for @befores -> $before {
            %ba{$after}{$before} = 0 if $before ne $after;
            %ba{$before} //= {};
        }
    }

    if @top {
	my @want = @top;
	my %care;
	%care{@want} = 1 xx *;
	repeat while @want {
	    my @newwant;
	    for @want -> $before {
		if %ba{$before} {
		    for %ba{$before}.keys -> $after {
			if not %ba{$before}{$after} {
			    %ba{$before}{$after}++;
			    push @newwant, $after;
			}
		    }
		}
	    }
	    @want = @newwant;
	    %care{@want} = 1 xx *;
	}

	for %ba.keys -> $before {
	    %ba{$before}:delete unless %care{$before};
	}
    }
 
    my @levels;
    while %ba.grep( not *.value )».key -> @befores {
	push @levels, ~@befores.sort;
        %ba{@befores}:delete;
        for %ba.values { .{@befores}:delete }
    }
    if @top {
	say "For top-level-modules: ", @top;
	say "  $_" for @levels;
    }
    else {
	say "Top levels are: @levels[*-1]";
    }
 
    say "Cycle found! {%ba.keys.sort}" if %ba;
    say ''; 
}

my %deps =
    top1  =>  <des1 ip1 ip2>,
    top2  =>  <des1 ip2 ip3>,
    ip1   =>  <extra1 ip1a ipcommon>,
    ip2   =>  <ip2a ip2b ip2c ipcommon>,
    des1  =>  <des1a des1b des1c>,
    des1a =>  <des1a1 des1a2>,
    des1c =>  <des1c1 extra1>;
     
top_topos(%deps);
top_topos(%deps, 'top1');
top_topos(%deps, 'top2');
top_topos(%deps, 'ip1');
top_topos(%deps, 'top1', 'top2');

```

Output:

```
Top levels are: top1 top2

For top-level-modules: top1
  des1a1 des1a2 des1b des1c1 extra1 ip1a ip2a ip2b ip2c ipcommon
  des1a des1c ip1 ip2
  des1
  top1

For top-level-modules: top2
  des1a1 des1a2 des1b des1c1 extra1 ip2a ip2b ip2c ip3 ipcommon
  des1a des1c ip2
  des1
  top2

For top-level-modules: ip1
  extra1 ip1a ipcommon
  ip1

For top-level-modules: top1 top2
  des1a1 des1a2 des1b des1c1 extra1 ip1a ip2a ip2b ip2c ip3 ipcommon
  des1a des1c ip1 ip2
  des1
  top1 top2

```