{ :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"