1 import Base
2 import ./lists.bend as Lists
3
4 # A value, with the name it is written as.
5 type Named<-A: Data> is Data:
6 Named{name: String, value: A}
7
8 def lookup.go(
9 -A: Data,
10 +key: String,
11 table: List<&2, Named>,
12 found: Maybe<&2, A>
13 ) -> Maybe<&2, A>:
14 match table found:
15 case _ Some{v}:
16 Some{v}
17 case Nil{} None{}:
18 None{}
19 case Con{Named{k, v}, rest} None{}:
20 lookup.go(A, key, rest, Lists.when(A, String.eq(k, key), v))
21
22 # Each of `xs` with the name `show` gives it: a table for `lookup`, so that each name is written once, in `show`.
23 def table(~A: Data, ~show: A -> String, xs: List<&2, A>) -> List<&2, Named>:
24 match xs:
25 case Nil{}:
26 []
27 case Con{+x, rest}:
28 Named{show(x), x} <> table(~A, ~show, rest)
29
30 # The value `key` names in `table`: the first, read no further.
31 def lookup(-A: Data, key: String, table: List<&2, Named>) -> Maybe<&2, A>:
32 lookup.go(A, key, table, None{})
33
34 # The value `key` names in `table`, a map by name (as `Lint.definitions` makes): one pass over the name, however many
35 # names there are.
36 def find(-A: Data, table: Map<&2, Maybe<&2, A>>, key: String) -> Maybe<&2, A>:
37 Pair.snd(Map<&2, Maybe<&2, A>>, Maybe<&2, A>, Map.get(Maybe<&2, A>, None{}, table, key))
38
39 # Groups
40 # ======
41 # Values by name, in a map: each name's values, last first.
42 def Group.add.of(
43 -A: Data,
44 got: Map<&2, List<&2, A>> & List<&2, A>,
45 key: String,
46 x: A
47 ) -> Map<&2, List<&2, A>>:
48 match got:
49 case Tuple{groups, old}:
50 Map.set(&2, List<&2, A>, groups, key, x <> old)
51
52 # `groups` with `x` added under `key`. A key's list is last first; `Group.get` gives it in order.
53 def Group.add(-A: Data, groups: Map<&2, List<&2, A>>, +key: String, x: A) -> Map<&2, List<&2, A>>:
54 Group.add.of(A, Map.get(List<&2, A>, [], groups, key), key, x)
55
56 # What is added under `key`, in the order added.
57 def Group.get(-A: Data, groups: Map<&2, List<&2, A>>, key: String) -> List<&2, A>:
58 List.reverse(
59 &2,
60 A,
61 Pair.snd(Map<&2, List<&2, A>>, List<&2, A>, Map.get(List<&2, A>, [], groups, key))
62 )
63
64 def Group.of(
65 ~A: Data,
66 ~key: A -> String,
67 xs: List<&2, A>,
68 groups: Map<&2, List<&2, A>>
69 ) -> Map<&2, List<&2, A>>:
70 match xs:
71 case Nil{}:
72 groups
73 case Con{+x, rest}:
74 Group.of(~A, ~key, rest, Group.add(A, groups, key(x), x))