MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
bind.cpp
Go to the documentation of this file.
1#include "mim/ast/ast.h"
2
3using namespace std::literals;
4
5namespace mim::ast {
6
7using Tag = Tok::Tag;
8
9class DummyDecl : public Decl {
10public:
12 : Decl(Loc()) {}
13
14 std::ostream& stream(Tab&, std::ostream& os) const final { return os << "<dummy>"; }
15};
16
17class Scopes {
18public:
19 using Scope = fe::SymMap<std::pair<Loc, const Decl*>>;
20
22 : ast_(ast)
23 , dummy_(ast.ptr<DummyDecl>()) {
24 push(); // root scope
25 }
26
27 AST& ast() const { return ast_; }
28 Driver& driver() const { return ast().driver(); }
29 Scope& top() { return scopes_.back(); }
30 const Decl* dummy() const { return dummy_.get(); }
31
32 void push() { scopes_.emplace_back(); }
33
34 void pop() {
35 assert(!scopes_.empty());
36 scopes_.pop_back();
37 }
38
39 const Decl* find(Dbg dbg, bool quiet = false) {
40 if (dbg.is_anon()) return nullptr;
41
42 for (auto& scope : scopes_ | std::ranges::views::reverse)
43 if (auto i = scope.find(dbg.sym()); i != scope.end()) return i->second.second;
44
45 if (!quiet) {
46 ast().error(dbg.loc(), "'{}' not found", dbg.sym());
47 bind(dbg, dummy()); // put into scope to prevent further errors
48 }
49 return nullptr;
50 }
51
52 void bind(Dbg dbg, const Decl* decl, bool rebind = false, bool quiet = false) {
53 if (dbg.is_anon()) return;
54
55 if (rebind) {
56 top()[dbg.sym()] = std::pair(dbg.loc(), decl);
57 } else if (auto [i, ins] = top().emplace(dbg.sym(), std::pair(dbg.loc(), decl)); !ins) {
58 auto [prev_loc, prev_decl] = i->second;
59 if (!quiet && !prev_decl->isa<DummyDecl>()) { // if prev_decl stems from an error - don't complain
60 ast().error(dbg.loc(), "redeclaration of '{}'", dbg);
61 ast().note(prev_loc, "previous declaration here");
62 }
63 }
64 }
65
66private:
67 AST& ast_;
68 Ptr<DummyDecl> dummy_;
69 std::deque<Scope> scopes_;
70 absl::flat_hash_map<plugin_t, tag_t> plugin2tag_;
71};
72
73/*
74 * Module
75 */
76
77void Module::bind(AST& ast) const {
78 auto scopes = Scopes(ast);
79 bind(scopes);
80}
81
82void Module::bind(Scopes& s) const {
83 for (const auto& import : implicit_imports()) import->bind(s);
84 for (const auto& import : imports()) import->bind(s);
85 for (const auto& decl : decls()) decl->bind(s);
86}
87
88void Import::bind(Scopes& s) const { module()->bind(s); }
89
90/*
91 * Ptrn
92 */
93
94void ErrorPtrn::bind(Scopes&, bool, bool) const {}
95void GrpPtrn::bind(Scopes& s, bool rebind, bool quiet) const { s.bind(dbg(), this, rebind, quiet); }
96
97void IdPtrn::bind(Scopes& s, bool rebind, bool quiet) const {
98 if (!quiet && type()) type()->bind(s);
99 s.bind(dbg(), this, rebind, quiet);
100}
101
102void AliasPtrn::bind(Scopes& s, bool rebind, bool quiet) const {
103 ptrn()->bind(s, rebind, quiet);
104 s.bind(dbg(), this, rebind, quiet);
105}
106
107void TuplePtrn::bind(Scopes& s, bool rebind, bool quiet) const {
108 for (const auto& ptrn : ptrns()) ptrn->bind(s, rebind, quiet);
109}
110
111/*
112 * Expr
113 */
114
115// clang-format off
116void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); }
117void TypeExpr ::bind(Scopes& s) const { level()->bind(s); }
118void ErrorExpr ::bind(Scopes&) const {}
119void HoleExpr ::bind(Scopes&) const {}
121// clang-format on
122
123void LitExpr::bind(Scopes& s) const {
124 if (type()) {
125 type()->bind(s);
126 if (tag() == Tag::L_str || tag() == Tag::L_c || tag() == Tag::L_i)
127 s.ast().error(type()->loc(), "a {} shall not have a type annotation", tag());
128 } else {
129 if (tag() == Tag::L_f) s.ast().error(loc(), "type annotation mandatory for floating point literal");
130 }
131}
132
133void DeclExpr::bind(Scopes& s) const {
134 if (is_where())
135 for (const auto& decl : decls() | std::ranges::views::reverse) decl->bind(s);
136 else
137 for (const auto& decl : decls()) decl->bind(s);
138 expr()->bind(s);
139}
140
141void ArrowExpr::bind(Scopes& s) const {
142 dom()->bind(s);
143 codom()->bind(s);
144}
145
146void UnionExpr::bind(Scopes& s) const {
147 for (auto& type : types()) type->bind(s);
148}
149
150void InjExpr::bind(Scopes& s) const {
151 value()->bind(s);
152 type()->bind(s);
153}
154
156 s.push();
157 ptrn()->bind(s, false, false);
158 body()->bind(s);
159 s.pop();
160}
161
162void MatchExpr::bind(Scopes& s) const {
163 scrutinee()->bind(s);
164 for (const auto& arm : arms()) arm->bind(s);
165}
166
167void PiExpr::Dom::bind(Scopes& s, bool quiet) const {
168 ptrn()->bind(s, false, quiet);
169 if (ret()) ret()->bind(s, false, quiet);
170}
171
172void PiExpr::bind(Scopes& s) const {
173 s.push();
174 dom()->bind(s);
175 if (codom()) {
176 if (tag() == Tag::K_Cn) s.ast().error(codom()->loc(), "a continuation shall not have a codomain");
177 codom()->bind(s);
178 }
179 s.pop();
180}
181
182void LamExpr::bind(Scopes& s) const {
183 lam()->bind_decl(s);
184 lam()->bind_body(s);
185}
186
187void AppExpr::bind(Scopes& s) const {
188 callee()->bind(s);
189 arg()->bind(s);
190}
191
192void RetExpr::bind(Scopes& s) const {
193 callee()->bind(s);
194 arg()->bind(s);
195 ptrn()->bind(s, true, false);
196 body()->bind(s);
197}
198
199void SigmaExpr::bind(Scopes& s) const {
200 s.push();
201 ptrn()->bind(s, false, false);
202 s.pop();
203}
204
205void TupleExpr::bind(Scopes& s) const {
206 for (const auto& elem : elems()) elem->bind(s);
207}
208
209void SeqExpr::bind(Scopes& s) const {
210 s.push();
211 shape()->bind(s, false, false);
212 body()->bind(s);
213 s.pop();
214}
215
216void ExtractExpr::bind(Scopes& s) const {
217 tuple()->bind(s);
218 if (auto expr = std::get_if<Ptr<Expr>>(&index()))
219 (*expr)->bind(s);
220 else {
221 auto dbg = std::get<Dbg>(index());
222 decl_ = s.find(dbg, true);
223 }
224}
225
226void InsertExpr::bind(Scopes& s) const {
227 tuple()->bind(s);
228 index()->bind(s);
229 value()->bind(s);
230}
231
232void UniqExpr::bind(Scopes& s) const { inhabitant()->bind(s); }
233
234/*
235 * Decl
236 */
237
238void AxmDecl::Alias::bind(Scopes& s, const AxmDecl* axm) const {
239 auto sym = s.ast().sym(axm->dbg().sym().str() + "."s + dbg().sym().str());
240 full_ = Dbg(dbg().loc(), sym);
241 s.bind(full_, this);
242}
243
244void AxmDecl::bind(Scopes& s) const {
245 type()->bind(s);
246 annex_ = s.ast().name2annex(dbg(), nullptr);
247
248 if (annex_->fresh)
249 annex_->normalizer = normalizer();
250 else if (annex_->normalizer.sym() != normalizer().sym()) {
251 auto l = normalizer().loc() ? normalizer().loc() : loc().anew_finis();
252 s.ast().error(l, "normalizer mismatch for axm '{}'", dbg());
253 if (auto norm = annex_->normalizer)
254 s.ast().note(norm.loc(), "previous normalizer '{}'", norm);
255 else
256 s.ast().note(l, "initially no normalizer specified");
257 }
258
259 if (num_subs() == 0) {
260 s.bind(dbg(), this);
261 } else {
262 if (auto old = s.find(dbg(), true)) {
263 if (auto old_ax = old->isa<AxmDecl>()) {
264 if (old_ax->num_subs() == 0) {
265 s.ast().error(dbg().loc(), "redeclared sub-less axm '{}' with subs", dbg());
266 s.ast().note(old_ax->dbg().loc(), "previous location here");
267 }
268 }
269 }
270 for (const auto& aliases : subs())
271 for (const auto& alias : aliases) alias->bind(s, this);
272 }
273}
274
275void LetDecl::bind(Scopes& s) const {
276 s.push();
277 value()->bind(s);
278 s.pop();
279 ptrn()->bind(s, true, false);
280
281 if (auto id = ptrn()->isa<IdPtrn>()) annex_ = s.ast().name2annex(id->dbg(), &sub_);
282}
283
284void RecDecl::bind(Scopes& s) const {
285 for (auto curr = this; curr; curr = curr->next()) curr->bind_decl(s);
286 for (auto curr = this; curr; curr = curr->next()) curr->bind_body(s);
287 annex_ = s.ast().name2annex(dbg(), &sub_);
288}
289
291 if (auto t = type()) t->bind(s);
292 if (!type()->isa<HoleExpr>() && body()->isa<LamExpr>())
293 s.ast().warn(type()->loc(), "type of recursive declaration ignored for function expression");
294
295 if (!body()->isa<LamExpr>() && !body()->isa<PiExpr>() && !body()->isa<ArrowExpr>() && !body()->isa<SigmaExpr>())
296 s.ast().error(body()->loc(), "unsupported expression for a recursive declaration");
297
298 s.bind(dbg(), this);
299}
300
301void RecDecl::bind_body(Scopes& s) const { body()->bind(s); }
302
303void LamDecl::Dom::bind(Scopes& s, bool quiet) const {
304 PiExpr::Dom::bind(s, quiet);
305 if (filter() && !quiet) filter()->bind(s);
306}
307
309 s.push();
310 for (size_t i = 0, e = num_doms(); i != e; ++i) dom(i)->bind(s);
311
312 if (auto filter = doms().back()->filter()) {
313 if (auto pe = filter->isa<PrimaryExpr>()) {
314 if (pe->tag() == Tag::K_tt && (tag() == Tag::K_lam || tag() == Tag::T_lm))
315 s.ast().warn(filter->loc(),
316 "'tt'-filter superfluous as the last curried function group of a '{}' receives a "
317 "'tt'-filter by default",
318 tag());
319 if (pe->tag() == Tag::K_ff && (tag() != Tag::K_lam && tag() != Tag::T_lm))
320 s.ast().warn(filter->loc(),
321 "'ff'-filter superfluous as the last curried function group of a '{}' receives a "
322 "'ff'-filter by default",
323 tag());
324 }
325 }
326
327 if (codom()) {
328 if (tag() == Tag::K_con || tag() == Tag::K_cn)
329 s.ast().error(codom()->loc(), "a continuation shall not have a codomain");
330 codom()->bind(s);
331 }
332
333 s.pop();
334 s.bind(dbg(), this);
335 annex_ = s.ast().name2annex(dbg(), &sub_);
336}
337
339 s.push();
340 for (const auto& dom : doms()) dom->bind(s, true);
341 body()->bind(s);
342 s.pop();
343}
344
345void CDecl::bind(Scopes& s) const {
346 s.push();
347 dom()->bind(s, false, false);
348 s.pop(); // we don't allow codom to depent on dom
349 if (codom()) codom()->bind(s);
350 s.bind(dbg(), this);
351}
352
353} // namespace mim::ast
Some "global" variables needed all over the place.
Definition driver.h:17
Keeps track of indentation level.
Definition print.h:196
Driver & driver()
Definition ast.h:62
Error & note(Loc loc, const char *fmt, Args &&... args) const
Definition ast.h:86
Error & error()
Definition ast.h:63
Dbg dbg() const
Definition ast.h:275
const Ptrn * ptrn() const
Definition ast.h:274
void bind(Scopes &, bool rebind, bool quiet) const override
Definition bind.cpp:102
void bind(Scopes &) const override
Definition bind.cpp:187
const Expr * arg() const
Definition ast.h:659
const Expr * callee() const
Definition ast.h:658
void bind(Scopes &) const override
Definition bind.cpp:141
void bind(Scopes &, const AxmDecl *) const
Definition bind.cpp:238
Dbg dbg() const
Definition ast.h:870
friend class AxmDecl
Definition ast.h:879
const auto & subs() const
Definition ast.h:892
const Expr * type() const
Definition ast.h:895
size_t num_subs() const
Definition ast.h:893
AxmDecl(Loc loc, Dbg dbg, std::deque< Ptrs< Alias > > &&subs, Ptr< Expr > &&type, Dbg normalizer, Tok curry, Tok trip)
Definition ast.h:882
void bind(Scopes &) const override
Definition bind.cpp:244
Dbg normalizer() const
Definition ast.h:896
Dbg dbg() const
Definition ast.h:891
const Ptrn * dom() const
Definition ast.h:1027
const Expr * codom() const
Definition ast.h:1028
Dbg dbg() const
Definition ast.h:1025
void bind(Scopes &) const override
Definition bind.cpp:345
const Expr * expr() const
Definition ast.h:419
const auto & decls() const
Definition ast.h:417
void bind(Scopes &) const override
Definition bind.cpp:133
bool is_where() const
Definition ast.h:418
Decl(Loc loc)
Definition ast.h:165
std::ostream & stream(Tab &, std::ostream &os) const final
Definition bind.cpp:14
void bind(Scopes &, bool rebind, bool quiet) const override
Definition bind.cpp:94
virtual void bind(Scopes &) const =0
const auto & index() const
Definition ast.h:779
const Expr * tuple() const
Definition ast.h:778
void bind(Scopes &) const override
Definition bind.cpp:216
void bind(Scopes &, bool rebind, bool quiet) const override
Definition bind.cpp:95
Dbg dbg() const
Definition ast.h:253
Dbg dbg() const
Definition ast.h:353
void bind(Scopes &, bool rebind, bool quiet) const override
Definition bind.cpp:97
Dbg dbg() const
Definition ast.h:223
const Expr * type() const
Definition ast.h:224
void bind(Scopes &) const
Definition bind.cpp:88
const Module * module() const
Definition ast.h:1055
const Expr * type() const
Definition ast.h:481
void bind(Scopes &) const override
Definition bind.cpp:150
const Expr * value() const
Definition ast.h:480
const Expr * index() const
Definition ast.h:803
void bind(Scopes &) const override
Definition bind.cpp:226
const Expr * tuple() const
Definition ast.h:802
const Expr * value() const
Definition ast.h:804
const Expr * filter() const
Definition ast.h:964
void bind(Scopes &, bool quiet=false) const override
Definition bind.cpp:303
Tok::Tag tag() const
Definition ast.h:993
void bind_body(Scopes &) const override
Definition bind.cpp:338
const Ptrs< Dom > & doms() const
Definition ast.h:995
const Expr * codom() const
Definition ast.h:998
size_t num_doms() const
Definition ast.h:997
void bind_decl(Scopes &) const override
Definition bind.cpp:308
const Dom * dom(size_t i) const
Definition ast.h:996
void bind(Scopes &) const override
Definition bind.cpp:182
const LamDecl * lam() const
Definition ast.h:635
void bind(Scopes &) const override
Definition bind.cpp:275
const Expr * value() const
Definition ast.h:848
const Ptrn * ptrn() const
Definition ast.h:847
const Expr * type() const
Definition ast.h:396
Tok::Tag tag() const
Definition ast.h:395
void bind(Scopes &) const override
Definition bind.cpp:123
const Expr * body() const
Definition ast.h:506
virtual void bind(Scopes &) const
Definition bind.cpp:155
const Ptrn * ptrn() const
Definition ast.h:505
void bind(Scopes &) const override
Definition bind.cpp:162
const Expr * scrutinee() const
Definition ast.h:522
const Arm * arm(size_t i) const
Definition ast.h:524
const auto & arms() const
Definition ast.h:523
const auto & decls() const
Definition ast.h:1083
const auto & implicit_imports() const
Definition ast.h:1081
void bind(AST &) const
Definition bind.cpp:77
const auto & imports() const
Definition ast.h:1082
Loc loc() const
Definition ast.h:121
virtual void bind(Scopes &, bool quiet=false) const
Definition bind.cpp:167
const IdPtrn * ret() const
Definition ast.h:578
const Ptrn * ptrn() const
Definition ast.h:577
void bind(Scopes &) const override
Definition bind.cpp:172
void bind(Scopes &) const override
Definition bind.cpp:120
virtual void bind(Scopes &, bool rebind, bool quiet) const =0
Dbg dbg() const
Definition ast.h:924
virtual void bind_body(Scopes &) const
Definition bind.cpp:301
virtual void bind_decl(Scopes &) const
Definition bind.cpp:290
const Expr * body() const
Definition ast.h:926
const Expr * type() const
Definition ast.h:925
void bind(Scopes &) const override
Definition bind.cpp:284
const Ptrn * ptrn() const
Definition ast.h:682
const Expr * arg() const
Definition ast.h:684
void bind(Scopes &) const override
Definition bind.cpp:192
const Expr * body() const
Definition ast.h:685
const Expr * callee() const
Definition ast.h:683
Scopes(AST &ast)
Definition bind.cpp:21
Scope & top()
Definition bind.cpp:29
AST & ast() const
Definition bind.cpp:27
const Decl * dummy() const
Definition bind.cpp:30
const Decl * find(Dbg dbg, bool quiet=false)
Definition bind.cpp:39
void push()
Definition bind.cpp:32
void bind(Dbg dbg, const Decl *decl, bool rebind=false, bool quiet=false)
Definition bind.cpp:52
Driver & driver() const
Definition bind.cpp:28
fe::SymMap< std::pair< Loc, const Decl * > > Scope
Definition bind.cpp:19
const Expr * body() const
Definition ast.h:753
void bind(Scopes &) const override
Definition bind.cpp:209
const IdPtrn * shape() const
Definition ast.h:752
const TuplePtrn * ptrn() const
Definition ast.h:707
void bind(Scopes &) const override
Definition bind.cpp:199
const Expr * elem(size_t i) const
Definition ast.h:730
void bind(Scopes &) const override
Definition bind.cpp:205
const auto & elems() const
Definition ast.h:729
void bind(Scopes &, bool rebind, bool quiet) const override
Definition bind.cpp:107
const Ptrn * ptrn(size_t i) const
Definition ast.h:303
const auto & ptrns() const
Definition ast.h:302
const Expr * level() const
Definition ast.h:439
void bind(Scopes &) const override
Definition bind.cpp:146
const auto & types() const
Definition ast.h:459
const Expr * inhabitant() const
Definition ast.h:824
void bind(Scopes &) const override
Definition bind.cpp:232
Definition ast.h:14
fe::Arena::Ptr< const T > Ptr
Definition ast.h:21
Tok::Tag Tag
Definition bind.cpp:7
Sym sym() const
Definition dbg.h:145