src/lint/world.bend

bolt@1.22.0.0 · 124 lines · 0 definitions

1# src/lint/world: everything `bolt` reads, as one value. The planner
2# (src/lint/plan.bend) is a pure function of a World; the interpreter
3# (src/lint.bend) gathers one, answering each question the planner asks by
4# IO, and prints the plan the planner returns. The design is
5# docs/rfc/bolt-lint-planner.md.
6#
7# The World holds only what the lint reads: the paths named on the command
8# line, the working directory they are named from, and every answer the
9# interpreter gave. A question with no answer yet reads as a directory with no
10# entries or a file that cannot be read.
11import Base
12import bolt@1.22.0.0/src/lazy/lazy.bend as Lazy
13
14# a question the planner asks. Each is answered by one IO action: a
15# directory listed (src/walk/), or a file read (src/lsp/files/).
16type Ask is Data:
17  Entries{dir: String}
18  Contents{path: String}
19
20# the answer to one question. A directory that cannot be opened lists as
21# empty, as src/walk/dir.c answers. A text asked of a path that is a
22# directory is `Directory`, not a read: it has no text.
23type Answer is Data:
24  Listed{names: List<&2, String>}
25  Read{text: String}
26  Unread{}
27  Directory{}
28
29# one question, answered
30type Reply is Data:
31  Reply{ask: Ask, answer: Answer}
32
33# everything `bolt` reads: the paths named on the command line, the working
34# directory (absolute) that relative paths are named from, and every answer
35# the interpreter gave, in the order it gave them
36type World is Data:
37  World{paths: List<&2, String>, cwd: String, replies: List<&2, Reply>}
38
39# the paths named on the command line
40def paths.of(world: World) -> List<&2, String>:
41  World{paths, _cwd, _replies} = world
42  paths
43
44# the working directory the run was started in
45def cwd.of(world: World) -> String:
46  World{_paths, cwd, _replies} = world
47  cwd
48
49# whether two questions are the same question
50def ask.eq(aa: Ask, bb: Ask) -> Bool:
51  match aa bb:
52    case Entries{x1} Entries{y1}:
53      String.eq(x1, y1)
54    case Contents{x2} Contents{y2}:
55      String.eq(x2, y2)
56    case Entries{_x3} Contents{_y3}:
57      False{}
58    case Contents{_x4} Entries{_y4}:
59      False{}
60
61# the first answer given to a question
62def answer.in(rs: List<&2, Reply>, +ask: Ask) -> Maybe<&2, Answer>:
63  match rs:
64    case Nil{}:
65      None{}
66    case Con{Reply{q, a}, rest}:
67      Lazy.stop(Maybe<&2, Answer>, ask.eq(q, ask), Some{a}, _u => answer.in(rest, ask))
68
69# the answer a World holds for a question, None while there is none
70def answer(world: World, +ask: Ask) -> Maybe<&2, Answer>:
71  World{_paths, _cwd, rs} = world
72  answer.in(rs, ask)
73
74# whether a World answers a question
75def answered(world: World, +ask: Ask) -> Bool:
76  Maybe.is_some(&2, Answer, answer(world, ask))
77
78# a listing's names; anything else lists nothing
79def listing.answer(aa: Answer) -> List<&2, String>:
80  match aa:
81    case Listed{names}:
82      names
83    case Read{_text}:
84      []
85    case Unread{}:
86      []
87    case Directory{}:
88      []
89
90def listing.got(mm: Maybe<&2, Answer>) -> List<&2, String>:
91  match mm:
92    case None{}:
93      []
94    case Some{aa}:
95      listing.answer(aa)
96
97# a directory's entries, a sub-directory's name ending in "/"; none while
98# the directory is not listed yet
99def listing(world: World, dir: String) -> List<&2, String>:
100  listing.got(answer(world, Entries{dir}))
101
102# a read's text; anything else is no text
103def text.answer(aa: Answer) -> Maybe<&2, String>:
104  match aa:
105    case Listed{_names}:
106      None{}
107    case Read{tt}:
108      Some{tt}
109    case Unread{}:
110      None{}
111    case Directory{}:
112      None{}
113
114def text.got(mm: Maybe<&2, Answer>) -> Maybe<&2, String>:
115  match mm:
116    case None{}:
117      None{}
118    case Some{aa}:
119      text.answer(aa)
120
121# a file's text, or None when it could not be read, is a directory, or is
122# not read yet
123def text(world: World, path: String) -> Maybe<&2, String>:
124  text.got(answer(world, Contents{path}))