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 override { 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 InferExpr ::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 PiExpr::Dom::bind(Scopes& s, bool quiet) const {
147 ptrn()->bind(s, false, quiet);
148 if (ret()) ret()->bind(s, false, quiet);
149}
150
151void PiExpr::bind(Scopes& s) const {
152 s.push();
153 for (const auto& dom : doms()) dom->bind(s);
154 if (codom()) {
155 if (tag() == Tag::K_Cn) s.ast().error(codom()->loc(), "a continuation shall not have a codomain");
156 codom()->bind(s);
157 }
158 s.pop();
159}
160
161void LamExpr::bind(Scopes& s) const {
162 lam()->bind_decl(s);
163 lam()->bind_body(s);
164}
165
166void AppExpr::bind(Scopes& s) const {
167 callee()->bind(s);
168 arg()->bind(s);
169}
170
171void RetExpr::bind(Scopes& s) const {
172 callee()->bind(s);
173 arg()->bind(s);
174 ptrn()->bind(s, true, false);
175 body()->bind(s);
176}
177
178void SigmaExpr::bind(Scopes& s) const {
179 s.push();
180 ptrn()->bind(s, false, false);
181 s.pop();
182}
183
184void TupleExpr::bind(Scopes& s) const {
185 for (const auto& elem : elems()) elem->bind(s);
186}
187
188template<bool arr> void ArrOrPackExpr<arr>::bind(Scopes& s) const {
189 s.push();
190 shape()->bind(s, false, false);
191 body()->bind(s);
192 s.pop();
193}
194
195template void ArrOrPackExpr<true>::bind(Scopes&) const;
196template void ArrOrPackExpr<false>::bind(Scopes&) const;
197
198void ExtractExpr::bind(Scopes& s) const {
199 tuple()->bind(s);
200 if (auto expr = std::get_if<Ptr<Expr>>(&index()))
201 (*expr)->bind(s);
202 else {
203 auto dbg = std::get<Dbg>(index());
204 decl_ = s.find(dbg, true);
205 }
206}
207
208void InsertExpr::bind(Scopes& s) const {
209 tuple()->bind(s);
210 index()->bind(s);
211 value()->bind(s);
212}
213
214/*
215 * Decl
216 */
217
218void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const {
219 auto sym = s.ast().sym(axiom->dbg().sym().str() + "."s + dbg().sym().str());
220 full_ = Dbg(dbg().loc(), sym);
221 s.bind(full_, this);
222}
223
224void AxiomDecl::bind(Scopes& s) const {
225 type()->bind(s);
226 annex_ = s.ast().name2annex(dbg(), nullptr);
227
228 if (annex_->fresh)
229 annex_->normalizer = normalizer();
230 else if (annex_->normalizer.sym() != normalizer().sym()) {
231 auto l = normalizer().loc() ? normalizer().loc() : loc().anew_finis();
232 s.ast().error(l, "normalizer mismatch for axiom '{}'", dbg());
233 if (auto norm = annex_->normalizer)
234 s.ast().note(norm.loc(), "previous normalizer '{}'", norm);
235 else
236 s.ast().note(l, "initially no normalizer specified");
237 }
238
239 if (num_subs() == 0) {
240 s.bind(dbg(), this);
241 } else {
242 if (auto old = s.find(dbg(), true)) {
243 if (auto old_ax = old->isa<AxiomDecl>()) {
244 if (old_ax->num_subs() == 0) {
245 s.ast().error(dbg().loc(), "redeclared sub-less axiom '{}' with subs", dbg());
246 s.ast().note(old_ax->dbg().loc(), "previous location here");
247 }
248 }
249 }
250 for (const auto& aliases : subs())
251 for (const auto& alias : aliases) alias->bind(s, this);
252 }
253}
254
255void LetDecl::bind(Scopes& s) const {
256 s.push();
257 value()->bind(s);
258 s.pop();
259 ptrn()->bind(s, true, false);
260
261 if (auto id = ptrn()->isa<IdPtrn>()) annex_ = s.ast().name2annex(id->dbg(), &sub_);
262}
263
264void RecDecl::bind(Scopes& s) const {
265 for (auto curr = this; curr; curr = curr->next()) curr->bind_decl(s);
266 for (auto curr = this; curr; curr = curr->next()) curr->bind_body(s);
267 annex_ = s.ast().name2annex(dbg(), &sub_);
268}
269
271 if (auto t = type()) t->bind(s);
272 if (!type()->isa<InferExpr>() && body()->isa<LamExpr>())
273 s.ast().warn(type()->loc(), "type of recursive declaration ignored for function expression");
274
275 if (!body()->isa<LamExpr>() && !body()->isa<PiExpr>() && !body()->isa<ArrowExpr>() && !body()->isa<SigmaExpr>())
276 s.ast().error(body()->loc(), "unsupported expression for a recursive declaration");
277
278 s.bind(dbg(), this);
279}
280
281void RecDecl::bind_body(Scopes& s) const { body()->bind(s); }
282
283void LamDecl::Dom::bind(Scopes& s, bool quiet) const {
284 PiExpr::Dom::bind(s, quiet);
285 if (filter() && !quiet) filter()->bind(s);
286}
287
289 s.push();
290 for (size_t i = 0, e = num_doms(); i != e; ++i) dom(i)->bind(s);
291
292 if (auto filter = doms().back()->filter()) {
293 if (auto pe = filter->isa<PrimaryExpr>()) {
294 if (pe->tag() == Tag::K_tt && (tag() == Tag::K_lam || tag() == Tag::T_lm))
295 s.ast().warn(filter->loc(),
296 "'tt'-filter superfluous as the last curried function group of a '{}' receives a "
297 "'tt'-filter by default",
298 tag());
299 if (pe->tag() == Tag::K_ff && (tag() != Tag::K_lam && tag() != Tag::T_lm))
300 s.ast().warn(filter->loc(),
301 "'ff'-filter superfluous as the last curried function group of a '{}' receives a "
302 "'ff'-filter by default",
303 tag());
304 }
305 }
306
307 if (codom()) {
308 if (tag() == Tag::K_con || tag() == Tag::K_cn)
309 s.ast().error(codom()->loc(), "a continuation shall not have a codomain");
310 codom()->bind(s);
311 }
312
313 s.pop();
314 s.bind(dbg(), this);
315 annex_ = s.ast().name2annex(dbg(), &sub_);
316}
317
319 s.push();
320 for (const auto& dom : doms()) dom->bind(s, true);
321 body()->bind(s);
322 s.pop();
323}
324
325void CDecl::bind(Scopes& s) const {
326 s.push();
327 dom()->bind(s, false, false);
328 s.pop(); // we don't allow codom to depent on dom
329 if (codom()) codom()->bind(s);
330 s.bind(dbg(), this);
331}
332
333} // namespace mim::ast
Some "global" variables needed all over the place.
Definition driver.h:17
Keeps track of indentation level.
Definition print.h:195
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:273
const Ptrn * ptrn() const
Definition ast.h:272
void bind(Scopes &, bool rebind, bool quiet) const override
Definition bind.cpp:102
void bind(Scopes &) const override
Definition bind.cpp:166
void bind(Scopes &) const override
Definition bind.cpp:188
void bind(Scopes &) const override
Definition bind.cpp:141
void bind(Scopes &, const AxiomDecl *) const
Definition bind.cpp:218
axm ptrn: type = value;
Definition ast.h:753
void bind(Scopes &) const override
Definition bind.cpp:224
Dbg dbg() const
Definition ast.h:782
void bind(Scopes &) const override
Definition bind.cpp:325
const Expr * expr() const
Definition ast.h:417
const auto & decls() const
Definition ast.h:415
void bind(Scopes &) const override
Definition bind.cpp:133
bool is_where() const
Definition ast.h:416
std::ostream & stream(Tab &, std::ostream &os) const override
Definition bind.cpp:14
void bind(Scopes &, bool rebind, bool quiet) const override
Definition bind.cpp:94
virtual void bind(Scopes &) const =0
void bind(Scopes &) const override
Definition bind.cpp:198
void bind(Scopes &, bool rebind, bool quiet) const override
Definition bind.cpp:95
Dbg dbg() const
Definition ast.h:251
void bind(Scopes &, bool rebind, bool quiet) const override
Definition bind.cpp:97
Dbg dbg() const
Definition ast.h:221
const Expr * type() const
Definition ast.h:222
void bind(Scopes &) const
Definition bind.cpp:88
const Module * module() const
Definition ast.h:946
void bind(Scopes &) const override
Definition bind.cpp:208
void bind(Scopes &scopes, bool quiet=false) const override
Definition bind.cpp:283
void bind_body(Scopes &) const override
Definition bind.cpp:318
void bind_decl(Scopes &) const override
Definition bind.cpp:288
void bind(Scopes &) const override
Definition bind.cpp:161
void bind(Scopes &) const override
Definition bind.cpp:255
const Expr * type() const
Definition ast.h:394
Tok::Tag tag() const
Definition ast.h:393
void bind(Scopes &) const override
Definition bind.cpp:123
const auto & decls() const
Definition ast.h:974
const auto & implicit_imports() const
Definition ast.h:972
void bind(AST &) const
Definition bind.cpp:77
const auto & imports() const
Definition ast.h:973
Loc loc() const
Definition ast.h:121
virtual void bind(Scopes &scopes, bool quiet=false) const
Definition bind.cpp:146
const IdPtrn * ret() const
Definition ast.h:489
const Ptrn * ptrn() const
Definition ast.h:488
void bind(Scopes &) const override
Definition bind.cpp:151
void bind(Scopes &) const override
Definition bind.cpp:120
virtual void bind(Scopes &, bool rebind, bool quiet) const =0
virtual void bind_body(Scopes &) const
Definition bind.cpp:281
virtual void bind_decl(Scopes &) const
Definition bind.cpp:270
void bind(Scopes &) const override
Definition bind.cpp:264
void bind(Scopes &) const override
Definition bind.cpp:171
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
void bind(Scopes &) const override
Definition bind.cpp:178
void bind(Scopes &) const override
Definition bind.cpp:184
void bind(Scopes &, bool rebind, bool quiet) const override
Definition bind.cpp:107
const Ptrn * ptrn(size_t i) const
Definition ast.h:301
const auto & ptrns() const
Definition ast.h:300
Definition ast.h:14
fe::Arena::Ptr< const T > Ptr
Definition ast.h:21
constexpr decltype(auto) get(mim::Span< T, N > span)
Definition span.h:113
Sym sym() const
Definition dbg.h:145