{
:sort
:gather_imports
:QUEUE
}
Where
Let QUEUE
Let STRING_SET (SEARCH.SET STRING.compare)
In
Define (new root_path)
Let stack [root_path & 'nil]
In
{stack (STRING_SET.new stack)}
Define (push_all queue paths)
(LIST.reduce paths queue
Func {queue path}
Let {stack filter} queue
In
Match (STRING_SET.search filter path) {
| 'nothing {[path & stack] (STRING_SET.insert filter path)}
| 'just._ queue
})
Define (pop {stack filter})
Match stack {
| 'nil 'nothing
| 'cons.{path stack} 'just.{path {stack filter}}
}
In
{
:new
:push_all
:pop
}
Define (sort packages)
Let components
Let MAP (SEARCH.MAP STRING.compare [Func {path _} path])
Let SET (SEARCH.SET STRING.compare)
In
Let G (GRAPH MAP SET)
Let g (MAP.new (LIST.map packages [Func p {p.path p.imports}]))
In
(G.strongly_connected_components g)
Define (is_self_referential package)
(LIST.reduce package.imports False
Func {b path}
(Or b (STRING.equal path package.path)))
In
(LIST.fold components 'succeed.'nil
Func {component result}
Match result {
| 'fail._ result
| 'succeed.ordered_packages
Match component {
| 'cons.{path paths}
Match paths {
| 'cons._ 'fail.component
| 'nil
Define (has_matching_path package)
(STRING.equal path package.path)
In
Match (LIST.filter packages has_matching_path) {
| 'cons.{package _}
If (is_self_referential package)
'fail.[package & 'nil]
'succeed.[package & ordered_packages]
}
}
}
})
Define (gather_imports expr)
Let SET (SEARCH.SET STRING.compare)
In
Let f
Let empty Func set set
In
Unfold exprs From [expr & 'nil]
Match exprs {
| 'nil empty
| 'cons.{expr exprs}
Let g (Fold exprs)
Let f
Match expr {
| 'true empty
| 'false empty
| 'num._ empty
| 'str._ empty
| 'package.path [Func set (SET.insert set path)]
| 'prim._ empty
| 'var._ empty
| 'chain.{expr _} (Fold [expr & 'nil])
| 'tuple.exprs (Fold exprs)
| 'record.{_ inits} (Fold inits)
| 'block.{binders expr}
(Fold
(LIST.cons expr
(LIST.reduce binders 'nil
Func {exprs binder}
Match binder {
| 'let.{_ expr} [expr & exprs]
| 'open.{expr _} [expr & exprs]
})))
| 'app.{func args} (Fold [func & args])
| 'app_infix.{_ left rights} (Fold [left & rights])
| 'func.{_ expr} (Fold [expr & 'nil])
| 'iterate.{_ inits expr} (Fold [expr & inits])
| 'continue.exprs (Fold exprs)
| 'unfold.{_ inits expr} (Fold [expr & inits])
| 'fold.exprs (Fold exprs)
| 'cond.clauses
(Fold
(LIST.concat_map clauses
Func {test body}
[test & body & 'nil]))
| 'if.{test then else}
(Fold [test & then & else & 'nil])
| 'and.{test then}
(Fold [test & then & 'nil])
| 'or.{test else}
(Fold [test & else & 'nil])
| 'pattern_matches.{_ expr} (Fold [expr & 'nil])
| 'labeled.{_ expr} (Fold [expr & 'nil])
| 'match.{expr clauses}
(Fold [expr & (LIST.map clauses [Func {_ body} body])])
}
In
[f >> g]
}
In
(SET.list (f SET.empty))
Where
Open LIST {:Infix &}
Open FUNC {:Infix >>}
Where
Let FUNC Package "func"
Let GRAPH Package "graph"
Let LIST Package "list"
Let OS Package "os"
Let SEARCH Package "search"
Let STRING Package "string"