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) const {}
95
96void IdPtrn::bind(Scopes& s, bool quiet) const {
97 if (!quiet && type()) type()->bind(s);
98 s.bind(dbg(), this, rebind(), quiet);
99}
100
101void TuplePtrn::bind(Scopes& s, bool quiet) const {
102 for (const auto& ptrn : ptrns()) ptrn->bind(s, quiet);
103 s.bind(dbg(), this, rebind(), quiet);
104}
105
106void GrpPtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind(), quiet); }
107
108/*
109 * Expr
110 */
111
112// clang-format off
113void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); }
114void TypeExpr ::bind(Scopes& s) const { level()->bind(s); }
115void ErrorExpr ::bind(Scopes&) const {}
116void InferExpr ::bind(Scopes&) const {}
118// clang-format on
119
120void LitExpr::bind(Scopes& s) const {
121 if (type()) {
122 type()->bind(s);
123 if (tag() == Tag::L_str || tag() == Tag::L_c || tag() == Tag::L_i)
124 s.ast().error(type()->loc(), "a {} shall not have a type annotation", tag());
125 } else {
126 if (tag() == Tag::L_f) s.ast().error(loc(), "type annotation mandatory for floating point literal");
127 }
128}
129
130void DeclExpr::bind(Scopes& s) const {
131 if (is_where())
132 for (const auto& decl : decls() | std::ranges::views::reverse) decl->bind(s);
133 else
134 for (const auto& decl : decls()) decl->bind(s);
135 expr()->bind(s);
136}
137
138void ArrowExpr::bind(Scopes& s) const {
139 dom()->bind(s);
140 codom()->bind(s);
141}
142
143void PiExpr::Dom::bind(Scopes& s, bool quiet) const {
144 ptrn()->bind(s, quiet);
145 if (ret()) ret()->bind(s, quiet);
146}
147
148void PiExpr::bind(Scopes& s) const {
149 s.push();
150 for (const auto& dom : doms()) dom->bind(s);
151 if (codom()) {
152 if (tag() == Tag::K_Cn) s.ast().error(codom()->loc(), "a continuation shall not have a codomain");
153 codom()->bind(s);
154 }
155 s.pop();
156}
157
158void LamExpr::bind(Scopes& s) const {
159 lam()->bind_decl(s);
160 lam()->bind_body(s);
161}
162
163void AppExpr::bind(Scopes& s) const {
164 callee()->bind(s);
165 arg()->bind(s);
166}
167
168void RetExpr::bind(Scopes& s) const {
169 callee()->bind(s);
170 arg()->bind(s);
171 ptrn()->bind(s);
172 body()->bind(s);
173}
174
175void SigmaExpr::bind(Scopes& s) const {
176 s.push();
177 ptrn()->bind(s);
178 s.pop();
179}
180
181void TupleExpr::bind(Scopes& s) const {
182 for (const auto& elem : elems()) elem->bind(s);
183}
184
185template<bool arr> void ArrOrPackExpr<arr>::bind(Scopes& s) const {
186 s.push();
187 shape()->bind(s);
188 body()->bind(s);
189 s.pop();
190}
191
192template void ArrOrPackExpr<true>::bind(Scopes&) const;
193template void ArrOrPackExpr<false>::bind(Scopes&) const;
194
195void ExtractExpr::bind(Scopes& s) const {
196 tuple()->bind(s);
197 if (auto expr = std::get_if<Ptr<Expr>>(&index()))
198 (*expr)->bind(s);
199 else {
200 auto dbg = std::get<Dbg>(index());
201 decl_ = s.find(dbg, true);
202 }
203}
204
205void InsertExpr::bind(Scopes& s) const {
206 tuple()->bind(s);
207 index()->bind(s);
208 value()->bind(s);
209}
210
211/*
212 * Decl
213 */
214
215void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const {
216 auto sym = s.ast().sym(axiom->dbg().sym().str() + "."s + dbg().sym().str());
217 full_ = Dbg(dbg().loc(), sym);
218 s.bind(full_, this);
219}
220
221void AxiomDecl::bind(Scopes& s) const {
222 type()->bind(s);
223 annex_ = s.ast().name2annex(dbg(), nullptr);
224
225 if (annex_->fresh)
226 annex_->normalizer = normalizer();
227 else if (annex_->normalizer.sym() != normalizer().sym()) {
228 auto l = normalizer().loc() ? normalizer().loc() : loc().anew_finis();
229 s.ast().error(l, "normalizer mismatch for axiom '{}'", dbg());
230 if (auto norm = annex_->normalizer)
231 s.ast().note(norm.loc(), "previous normalizer '{}'", norm);
232 else
233 s.ast().note(l, "initially no normalizer specified");
234 }
235
236 if (num_subs() == 0) {
237 s.bind(dbg(), this);
238 } else {
239 if (auto old = s.find(dbg(), true)) {
240 if (auto old_ax = old->isa<AxiomDecl>()) {
241 if (old_ax->num_subs() == 0) {
242 s.ast().error(dbg().loc(), "redeclared sub-less axiom '{}' with subs", dbg());
243 s.ast().note(old_ax->dbg().loc(), "previous location here");
244 }
245 }
246 }
247 for (const auto& aliases : subs())
248 for (const auto& alias : aliases) alias->bind(s, this);
249 }
250}
251
252void LetDecl::bind(Scopes& s) const {
253 s.push();
254 value()->bind(s);
255 s.pop();
256 ptrn()->bind(s);
257
258 if (auto id = ptrn()->isa<IdPtrn>()) annex_ = s.ast().name2annex(id->dbg(), &sub_);
259}
260
261void RecDecl::bind(Scopes& s) const {
262 for (auto curr = this; curr; curr = curr->next()) curr->bind_decl(s);
263 for (auto curr = this; curr; curr = curr->next()) curr->bind_body(s);
264 annex_ = s.ast().name2annex(dbg(), &sub_);
265}
266
268 if (auto t = type()) t->bind(s);
269 if (!type()->isa<InferExpr>() && body()->isa<LamExpr>())
270 s.ast().warn(type()->loc(), "type of recursive declaration ignored for function expression");
271
272 if (!body()->isa<LamExpr>() && !body()->isa<PiExpr>() && !body()->isa<SigmaExpr>())
273 s.ast().error(body()->loc(), "unsupported expression for a recursive declaration");
274
275 s.bind(dbg(), this);
276}
277
278void RecDecl::bind_body(Scopes& s) const { body()->bind(s); }
279
280void LamDecl::Dom::bind(Scopes& s, bool quiet) const {
281 PiExpr::Dom::bind(s, quiet);
282 if (filter() && !quiet) filter()->bind(s);
283}
284
286 s.push();
287 for (size_t i = 0, e = num_doms(); i != e; ++i) dom(i)->bind(s);
288
289 if (auto filter = doms().back()->filter()) {
290 if (auto pe = filter->isa<PrimaryExpr>()) {
291 if (pe->tag() == Tag::K_tt && (tag() == Tag::K_lam || tag() == Tag::T_lm))
292 s.ast().warn(filter->loc(),
293 "'.tt'-filter superfluous as the last curried function group of a '{}' receives a "
294 "'.tt'-filter by default",
295 tag());
296 if (pe->tag() == Tag::K_ff && (tag() != Tag::K_lam && tag() != Tag::T_lm))
297 s.ast().warn(filter->loc(),
298 "'.ff'-filter superfluous as the last curried function group of a '{}' receives a "
299 "'.ff'-filter by default",
300 tag());
301 }
302 }
303
304 if (codom()) {
305 if (tag() == Tag::K_con || tag() == Tag::K_cn)
306 s.ast().error(codom()->loc(), "a continuation shall not have a codomain");
307 codom()->bind(s);
308 }
309
310 s.pop();
311 s.bind(dbg(), this);
312 annex_ = s.ast().name2annex(dbg(), &sub_);
313}
314
316 s.push();
317 for (const auto& dom : doms()) dom->bind(s, true);
318 body()->bind(s);
319 s.pop();
320}
321
322void CDecl::bind(Scopes& s) const {
323 s.push();
324 dom()->bind(s);
325 s.pop(); // we don't allow codom to depent on dom
326 if (codom()) codom()->bind(s);
327 s.bind(dbg(), this);
328}
329
330} // 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:61
Error & note(Loc loc, const char *fmt, Args &&... args) const
Definition ast.h:85
Error & error()
Definition ast.h:62
void bind(Scopes &) const override
Definition bind.cpp:163
void bind(Scopes &) const override
Definition bind.cpp:185
void bind(Scopes &) const override
Definition bind.cpp:138
void bind(Scopes &, const AxiomDecl *) const
Definition bind.cpp:215
.ax ptrn: type = value;
Definition ast.h:713
void bind(Scopes &) const override
Definition bind.cpp:221
Dbg dbg() const
Definition ast.h:742
void bind(Scopes &) const override
Definition bind.cpp:322
const Expr * expr() const
Definition ast.h:378
const auto & decls() const
Definition ast.h:376
void bind(Scopes &) const override
Definition bind.cpp:130
bool is_where() const
Definition ast.h:377
std::ostream & stream(Tab &, std::ostream &os) const override
Definition bind.cpp:14
void bind(Scopes &, bool quiet=false) const override
Definition bind.cpp:94
virtual void bind(Scopes &) const =0
void bind(Scopes &) const override
Definition bind.cpp:195
void bind(Scopes &, bool quiet=false) const override
Definition bind.cpp:106
void bind(Scopes &, bool quiet=false) const override
Definition bind.cpp:96
const Expr * type() const
Definition ast.h:211
void bind(Scopes &) const
Definition bind.cpp:88
const Module * module() const
Definition ast.h:905
void bind(Scopes &) const override
Definition bind.cpp:205
void bind(Scopes &scopes, bool quiet=false) const override
Definition bind.cpp:280
void bind_body(Scopes &) const override
Definition bind.cpp:315
void bind_decl(Scopes &) const override
Definition bind.cpp:285
void bind(Scopes &) const override
Definition bind.cpp:158
void bind(Scopes &) const override
Definition bind.cpp:252
const Expr * type() const
Definition ast.h:355
Tok::Tag tag() const
Definition ast.h:354
void bind(Scopes &) const override
Definition bind.cpp:120
const auto & decls() const
Definition ast.h:933
const auto & implicit_imports() const
Definition ast.h:931
void bind(AST &) const
Definition bind.cpp:77
const auto & imports() const
Definition ast.h:932
Loc loc() const
Definition ast.h:120
virtual void bind(Scopes &scopes, bool quiet=false) const
Definition bind.cpp:143
const IdPtrn * ret() const
Definition ast.h:448
const Ptrn * ptrn() const
Definition ast.h:447
void bind(Scopes &) const override
Definition bind.cpp:148
void bind(Scopes &) const override
Definition bind.cpp:117
bool rebind() const
Definition ast.h:177
Dbg dbg() const
Definition ast.h:178
virtual void bind(Scopes &, bool quiet=false) const =0
virtual void bind_body(Scopes &) const
Definition bind.cpp:278
virtual void bind_decl(Scopes &) const
Definition bind.cpp:267
void bind(Scopes &) const override
Definition bind.cpp:261
void bind(Scopes &) const override
Definition bind.cpp:168
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:175
void bind(Scopes &) const override
Definition bind.cpp:181
void bind(Scopes &, bool quiet=false) const override
Definition bind.cpp:101
const Ptrn * ptrn(size_t i) const
Definition ast.h:261
const auto & ptrns() const
Definition ast.h:260
Definition ast.h:13
fe::Arena::Ptr< const T > Ptr
Definition ast.h:20
constexpr decltype(auto) get(mim::Span< T, N > span)
Definition span.h:113
Sym sym() const
Definition dbg.h:145