forked from joelvaneenwyk/language84
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpackage.84
138 lines (132 loc) · 4.48 KB
/
package.84
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
{
: 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.map binders
Func binder
Match binder {
| 'let.{_ expr} expr
})))
| 'app.{func args} (Fold [func & args])
| '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])
| '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
Let GRAPH Package "graph"
Let LIST Package "list"
Let OS Package "os"
Let SEARCH Package "search"
Let STRING Package "string"