Thorin 1.9.0
The Higher ORder INtermediate representation
Loading...
Searching...
No Matches
parser.cpp
Go to the documentation of this file.
1#include "thorin/fe/parser.h"
2
3#include <filesystem>
4#include <fstream>
5#include <limits>
6#include <sstream>
7#include <variant>
8
9#include "thorin/check.h"
10#include "thorin/def.h"
11#include "thorin/driver.h"
12#include "thorin/rewrite.h"
13
14#include "thorin/util/sys.h"
15
16using namespace std::string_literals;
17
18namespace thorin {
19
20using Tag = Tok::Tag;
21
22/*
23 * entry points
24 */
25
26void Parser::parse_module() {
27 while (true)
28 if (ahead().tag() == Tag::K_import)
29 parse_import();
30 else if (ahead().tag() == Tag::K_plugin)
31 parse_plugin();
32 else
33 break;
34
35 parse_decls({});
36 expect(Tag::EoF, "module");
37}
38
39void Parser::import(Sym name, std::ostream* md) {
40 world().VLOG("import: {}", name);
41 auto filename = fs::path(name.view());
42
43 if (!filename.has_extension()) filename.replace_extension("thorin"); // TODO error cases
44
45 fs::path rel_path;
46 for (const auto& path : driver().search_paths()) {
47 std::error_code ignore;
48 rel_path = path / filename;
49 if (bool reg_file = fs::is_regular_file(rel_path, ignore); reg_file && !ignore) break;
50 rel_path = path / name.view() / filename;
51 if (bool reg_file = fs::is_regular_file(rel_path, ignore); reg_file && !ignore) break;
52 }
53
54 if (auto path = driver().add_import(std::move(rel_path), name)) {
55 auto ifs = std::ifstream(*path);
56 import(ifs, path, md);
57 }
58}
59
60void Parser::import(std::istream& is, const fs::path* path, std::ostream* md) {
61 world().VLOG("reading: {}", path ? path->string() : "<unknown file>"s);
62 if (!is) error("cannot read file '{}'", *path);
63
64 auto state = std::tuple(prev_, ahead_, lexer_);
65 auto lexer = Lexer(world(), is, path, md);
66 lexer_ = &lexer;
67 init(path);
68 parse_module();
69 std::tie(prev_, ahead_, lexer_) = state;
70}
71
72void Parser::plugin(Sym name) {
73 if (!driver().flags().bootstrap && !driver().is_loaded(name)) driver().load(name);
74 import(name);
75}
76
77/*
78 * misc
79 */
80
81void Parser::parse_import() {
82 eat(Tag::K_import);
83 auto name = expect(Tag::M_id, "import name");
84 expect(Tag::T_semicolon, "end of import");
85 import(name.sym());
86}
87
88void Parser::parse_plugin() {
89 eat(Tag::K_plugin);
90 auto name = expect(Tag::M_id, "thorin/plugin name");
91 expect(Tag::T_semicolon, "end of import");
92 plugin(name.sym());
93}
94
95Dbg Parser::parse_id(std::string_view ctxt) {
96 if (auto id = accept(Tag::M_id)) return id.dbg();
97 syntax_err("identifier", ctxt);
98 return {prev_, world().sym("<error>")};
99}
100
101std::pair<Dbg, bool> Parser::parse_name(std::string_view ctxt) {
102 if (auto tok = accept(Tag::M_anx)) return {tok.dbg(), true};
103 if (auto tok = accept(Tag::M_id)) return {tok.dbg(), false};
104 syntax_err("identifier or annex name", ctxt);
105 return {
106 {prev_, world().sym("<error>")},
107 false
108 };
109}
110
111void Parser::register_annex(Dbg dbg, Ref def) {
112 auto [plugin, tag, sub] = Annex::split(world(), dbg.sym);
113 auto name = world().sym("%"s + plugin.str() + "."s + tag.str());
114 auto&& [annex, is_new] = driver().name2annex(name, plugin, tag, dbg.loc);
116 tag_t t = annex.tag_id;
117 sub_t s = annex.subs.size();
118
119 if (sub) {
120 auto& aliases = annex.subs.emplace_back();
121 aliases.emplace_back(sub);
122 }
123
124 world().register_annex(p | (t << 8) | s, def);
125}
126
127Ref Parser::parse_type_ascr(std::string_view ctxt) {
128 if (accept(Tag::T_colon)) return parse_expr(ctxt, Tok::Prec::Bot);
129 if (ctxt.empty()) return nullptr;
130 syntax_err("':'", ctxt);
131}
132
133/*
134 * exprs
135 */
136
137Ref Parser::parse_expr(std::string_view ctxt, Tok::Prec p) {
138 auto track = tracker();
139 auto lhs = parse_primary_expr(ctxt);
140 return parse_infix_expr(track, lhs, p);
141}
142
143Ref Parser::parse_infix_expr(Tracker track, const Def* lhs, Tok::Prec p) {
144 while (true) {
145 // If operator in ahead has less left precedence: reduce (break).
146 if (ahead().isa(Tag::T_extract)) {
147 if (auto extract = parse_extract_expr(track, lhs, p))
148 lhs = extract;
149 else
150 break;
151 } else if (ahead().isa(Tag::T_arrow)) {
152 auto [l, r] = Tok::prec(Tok::Prec::Arrow);
153 if (l < p) break;
154 lex();
155 auto rhs = parse_expr("right-hand side of an function type", r);
156 lhs = world().pi(lhs, rhs)->set(track.loc());
157 } else {
158 auto [l, r] = Tok::prec(Tok::Prec::App);
159 if (l < p) break;
160 bool is_explicit = (bool)accept(Tag::T_at);
161 if (auto rhs = parse_expr({}, r)) // if we can parse an expression, it's an App
162 lhs = (is_explicit ? world().app(lhs, rhs) : world().iapp(lhs, rhs))->set(track.loc());
163 else
164 return lhs;
165 }
166 }
167
168 return lhs;
169}
170
171Ref Parser::parse_extract_expr(Tracker track, const Def* lhs, Tok::Prec p) {
172 auto [l, r] = Tok::prec(Tok::Prec::Extract);
173 if (l < p) return nullptr;
174 lex();
175
176 if (ahead().isa(Tag::M_id)) {
177 if (auto sigma = lhs->type()->isa_mut<Sigma>()) {
178 auto tok = eat(Tag::M_id);
179 if (tok.sym() == '_') error(tok.loc(), "you cannot use special symbol '_' as field access");
180
181 if (auto i = def2fields_.find(sigma); i != def2fields_.end()) {
182 if (auto& fields = i->second; fields.size() == sigma->num_ops()) {
183 for (size_t i = 0, n = sigma->num_ops(); i != n; ++i)
184 if (fields[i] == tok.sym()) return world().extract(lhs, n, i)->set(track.loc());
185 }
186 }
187 error(tok.loc(), "could not find elemement '{}' to extract from '{}' of type '{}'", tok.sym(), lhs, sigma);
188 }
189 }
190
191 auto rhs = parse_expr("right-hand side of an extract", r);
192 return world().extract(lhs, rhs)->set(track.loc());
193}
194
195Ref Parser::parse_insert_expr() {
196 eat(Tag::K_ins);
197 auto track = tracker();
198
199 expect(Tag::D_paren_l, "opening paren for insert arguments");
200 auto tuple = parse_expr("the tuple to insert into");
201 expect(Tag::T_comma, "comma after tuple to insert into");
202 auto index = parse_expr("insert index");
203 expect(Tag::T_comma, "comma after insert index");
204 auto value = parse_expr("insert value");
205 expect(Tag::D_paren_r, "closing paren for insert arguments");
206
207 return world().insert(tuple, index, value)->set(track.loc());
208}
209
210Ref Parser::parse_primary_expr(std::string_view ctxt) {
211 // clang-format off
212 switch (ahead().tag()) {
213 case Tag::D_quote_l: return parse_arr_expr();
214 case Tag::D_angle_l: return parse_pack_expr();
215 case Tag::D_brace_l: return parse_block_expr();
216 case Tag::D_brckt_l: return parse_sigma_expr();
217 case Tag::D_paren_l: return parse_tuple_expr();
218 case Tag::K_Type: return parse_type_expr();
219 case Tag::K_Univ: lex(); return world().univ();
220 case Tag::K_Idx: lex(); return world().type_idx();
221 case Tag::K_Nat: lex(); return world().type_nat();
222 case Tag::K_ff: lex(); return world().lit_ff();
223 case Tag::K_tt: lex(); return world().lit_tt();
224 case Tag::K_i1: lex(); return world().lit_i1();
225 case Tag::K_i8: lex(); return world().lit_i8();
226 case Tag::K_i16: lex(); return world().lit_i16();
227 case Tag::K_i32: lex(); return world().lit_i32();
228 case Tag::K_i64: lex(); return world().lit_i64();
229 case Tag::K_Bool:
230 case Tag::K_I1: lex(); return world().type_i1();
231 case Tag::K_I8: lex(); return world().type_i8();
232 case Tag::K_I16: lex(); return world().type_i16();
233 case Tag::K_I32: lex(); return world().type_i32();
234 case Tag::K_I64: lex(); return world().type_i64();
235 case Tag::K_Cn:
236 case Tag::K_Fn:
237 case Tag::T_Pi: return parse_pi_expr();
238 case Tag::K_cn:
239 case Tag::K_fn:
240 case Tag::T_lm: return parse_lam();
241 case Tag::T_star: lex(); return world().type();
242 case Tag::T_box: lex(); return world().type<1>();
243 case Tag::T_bot:
244 case Tag::T_top:
245 case Tag::L_s:
246 case Tag::L_u:
247 case Tag::L_f: return parse_lit_expr();
248 case Tag::L_c: return world().lit_i8(lex().lit_c());
249 case Tag::L_i: return lex().lit_i();
250 case Tag::K_ins: return parse_insert_expr();
251 case Tag::K_ret: return parse_ret_expr();
252 case Tag::M_anx:
253 case Tag::M_id: return scopes_.find(lex().dbg());
254 case Tag::M_str: return world().tuple(lex().sym())->set(prev_);
255 default:
256 if (ctxt.empty()) return nullptr;
257 syntax_err("primary expression", ctxt);
258 }
259 // clang-format on
260 return nullptr;
261}
262
263Ref Parser::parse_arr_expr() {
264 auto track = tracker();
265 scopes_.push();
266 eat(Tag::D_quote_l);
267
268 const Def* shape = nullptr;
269 Arr* arr = nullptr;
270 if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon)) {
271 auto id = eat(Tag::M_id);
272 eat(Tag::T_colon);
273
274 auto shape = parse_expr("shape of an array");
275 auto type = world().mut_infer_univ();
276 arr = world().mut_arr(type)->set_shape(shape);
277 scopes_.bind(id.dbg(), arr->var()->set(id.dbg()));
278 } else {
279 shape = parse_expr("shape of an array");
280 }
281
282 expect(Tag::T_semicolon, "array");
283 auto body = parse_expr("body of an array");
284 expect(Tag::D_quote_r, "closing delimiter of an array");
285 scopes_.pop();
286
287 if (arr) return arr->set_body(body);
288 return world().arr(shape, body)->set(track.loc());
289}
290
291Ref Parser::parse_pack_expr() {
292 auto track = tracker();
293 scopes_.push();
294 eat(Tag::D_angle_l);
295
296 if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon)) {
297 auto id = eat(Tag::M_id);
298 eat(Tag::T_colon);
299
300 auto shape = parse_expr("shape of a pack");
301 auto infer = world().mut_infer(world().type_idx(shape))->set(id.sym());
302 scopes_.bind(id.dbg(), infer);
303
304 expect(Tag::T_semicolon, "pack");
305 auto body = parse_expr("body of a pack");
306 expect(Tag::D_angle_r, "closing delimiter of a pack");
307 scopes_.pop();
308
309 auto arr = world().arr(shape, body->type());
310 auto pack = world().mut_pack(arr)->set(body);
311 auto var = pack->var();
312 infer->set(var);
313 return pack->reset(pack->reduce(var)); // get rid of infer
314 }
315
316 auto shape = parse_expr("shape of a pack");
317 expect(Tag::T_semicolon, "pack");
318 auto body = parse_expr("body of a pack");
319 expect(Tag::D_angle_r, "closing delimiter of a pack");
320 scopes_.pop();
321 return world().pack(shape, body)->set(track.loc());
322}
323
324Ref Parser::parse_block_expr() {
325 scopes_.push();
326 eat(Tag::D_brace_l);
327 auto res = parse_decls("block expression");
328 expect(Tag::D_brace_r, "block expression");
329 scopes_.pop();
330 return res;
331}
332
333Ref Parser::parse_sigma_expr() {
334 auto track = tracker();
335 auto ptrn = parse_tuple_ptrn(track, false, anonymous_);
336 return ptrn->type(world(), def2fields_);
337}
338
339Ref Parser::parse_tuple_expr() {
340 auto track = tracker();
341 DefVec ops;
342 parse_list("tuple", Tag::D_paren_l, [&]() { ops.emplace_back(parse_expr("tuple element")); });
343 return world().tuple(ops)->set(track.loc());
344}
345
346Ref Parser::parse_type_expr() {
347 auto track = tracker();
348 eat(Tag::K_Type);
349 auto [l, r] = Tok::prec(Tok::Prec::App);
350 auto level = parse_expr("type level", r);
351 return world().type(level)->set(track.loc());
352}
353
354Pi* Parser::parse_pi_expr(Pi* outer) {
355 auto track = tracker();
356 auto tok = lex();
357
358 std::string entity;
359 switch (tok.tag()) {
360 case Tag::T_Pi: entity = "dependent function type"; break;
361 case Tag::K_Cn: entity = "continuation type"; break;
362 case Tag::K_Fn: entity = "returning continuation type"; break;
363 default: fe::unreachable();
364 }
365
366 Pi* first = nullptr;
367 std::deque<Pi*> pis;
368 scopes_.push();
369 do {
370 auto implicit = (bool)accept(Tag::T_dot);
371 auto prec = tok.isa(Tag::K_Cn) ? Tok::Prec::Bot : Tok::Prec::App;
372 auto dom = parse_ptrn(Tag::D_brckt_l, "domain of a "s + entity, prec);
373 auto dom_t = dom->type(world(), def2fields_);
374 auto pi = (outer ? outer : world().mut_pi(world().type_infer_univ()))->set_dom(dom_t)->set(dom->dbg());
375 auto var = pi->var()->set(dom->sym());
376 first = first ? first : pi;
377
378 if (implicit) pi->make_implicit();
379 dom->bind(scopes_, var);
380 pis.emplace_back(pi);
381 } while (ahead().isa(Tag::T_dot) || ahead().isa(Tag::D_brckt_l) || ahead().isa(Tag::T_backtick)
382 || (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon_colon)));
383
384 Ref codom;
385 switch (tok.tag()) {
386 case Tag::T_Pi:
387 expect(Tag::T_arrow, entity);
388 codom = parse_expr("codomain of a dependent function type", Tok::Prec::Arrow);
389 break;
390 case Tag::K_Cn: codom = world().Bot(); break;
391 case Tag::K_Fn: {
392 expect(Tag::T_arrow, entity);
393 codom = world().Bot();
394 auto ret = parse_expr("domain of return continuation", Tok::Prec::Arrow);
395 auto pi = pis.back();
396 auto last = world().sigma({pi->dom(), world().cn(ret)});
397 pi->unset()->set_dom(last);
398 break;
399 }
400 default: fe::unreachable();
401 }
402
403 for (auto pi : pis | std::ranges::views::reverse) {
404 pi->set_codom(codom);
405 codom = pi;
406 }
407
408 first->set(track.loc());
409 scopes_.pop();
410 return first;
411}
412
413Lam* Parser::parse_lam(bool is_decl) {
414 auto track = tracker();
415 auto tok = lex();
416 auto prec = tok.isa(Tag::K_cn) || tok.isa(Tag::K_con) ? Tok::Prec::Bot : Tok::Prec::Pi;
417 bool external = is_decl && (bool)accept(Tag::K_extern);
418
419 std::string entity;
420 // clang-format off
421 switch (tok.tag()) {
422 case Tag::T_lm: entity = "function expression"; break;
423 case Tag::K_cn: entity = "continuation expression"; break;
424 case Tag::K_fn: entity = "returning continuation expression"; break;
425 case Tag::K_lam: entity = "function declaration"; break;
426 case Tag::K_con: entity = "continuation declaration"; break;
427 case Tag::K_fun: entity = "returning continuation declaration"; break;
428 default: fe::unreachable();
429 }
430 // clang-format on
431
432 auto [dbg, anx] = is_decl ? parse_name(entity) : std::pair(Dbg{prev_, anonymous_}, false);
433 auto outer = scopes_.curr();
434 Lam* decl = nullptr;
435
436 if (auto def = scopes_.query(dbg)) {
437 if (auto lam = def->isa_mut<Lam>())
438 decl = lam;
439 else
440 error(dbg.loc, "'{}' has not been declared as a function", dbg.sym);
441 }
442
443 std::unique_ptr<Ptrn> dom_p;
444 scopes_.push();
445 std::deque<std::tuple<Pi*, Lam*, const Def*>> funs;
446 do {
447 const Def* filter = accept(Tag::T_bang) ? world().lit_tt() : nullptr;
448 bool implicit = (bool)accept(Tag::T_dot);
449 dom_p = parse_ptrn(Tag::D_paren_l, "domain pattern of a "s + entity, prec);
450 auto dom_t = dom_p->type(world(), def2fields_);
451 auto pi = world().mut_pi(world().type_infer_univ(), implicit)->set_dom(dom_t);
452 auto lam = (funs.empty() && decl) ? decl : world().mut_lam(pi);
453 auto var = lam->var()->set<true>(dom_p->loc(), dom_p->sym());
454 dom_p->bind(scopes_, var);
455
456 if (auto tok = accept(Tag::T_at)) {
457 if (filter) error(tok.loc(), "filter already specified via '!'");
458 expect(Tag::D_paren_l, "opening parenthesis of a filter");
459 filter = parse_expr("filter");
460 expect(Tag::D_paren_r, "closing parenthesis of a filter");
461 }
462
463 funs.emplace_back(std::tuple(pi, lam, filter));
464 } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon));
465
466 Ref codom;
467 switch (tok.tag()) {
468 case Tag::T_lm:
469 case Tag::K_lam: {
470 codom = accept(Tag::T_colon) ? parse_expr("return type of a "s + entity) : world().mut_infer_type();
471 break;
472 }
473 case Tag::K_cn:
474 case Tag::K_con: codom = world().Bot(); break;
475 case Tag::K_fn:
476 case Tag::K_fun: {
477 auto& [pi, lam, filter] = funs.back();
478
479 codom = world().Bot();
480 auto track = tracker();
481 auto ret = accept(Tag::T_colon) ? parse_expr("return type of a "s + entity) : world().mut_infer_type();
482 auto ret_loc = dom_p->loc() + track.loc();
483 auto sigma = world().mut_sigma(2)->set(0, pi->dom());
484
485 // Fix wrong dependencies:
486 // Connect old filter to lam and ret to pi. Otherwise, scope will not find it.
487 // 1. ret depends on lam->var() instead of sigma->var(2, 0)
488 pi->set_codom(ret);
489 if (filter) lam->set_filter(filter);
490 auto old_var = lam->var()->as<Var>();
491 auto rw = VarRewriter(old_var, sigma->var(2, 0));
492 sigma->set(1, world().cn({rw.rewrite(ret)}));
493
494 auto new_pi = world().mut_pi(pi->type(), pi->is_implicit())->set(ret_loc)->set_dom(sigma);
495 auto new_lam = world().mut_lam(new_pi);
496 auto new_var = new_lam->var()->set(ret_loc);
497
498 // 2. filter depends on lam->var() instead of new_lam->var(2, 0)
499 if (filter) filter = rewrite(filter, lam, new_lam->var(2, 0)->set(lam->var()->dbg()));
500
501 pi->unset();
502 pi = new_pi;
503 lam->unset();
504 lam = new_lam;
505
506 dom_p->bind(scopes_, new_var->proj(2, 0), true);
507 scopes_.bind({ret_loc, return_}, new_var->proj(2, 1)->set(Dbg{ret_loc, return_}));
508 break;
509 }
510 default: fe::unreachable();
511 }
512
513 auto [_, first, __] = funs.front();
514 first->set(dbg.sym);
515
516 for (auto [pi, lam, _] : funs | std::ranges::views::reverse) {
517 // First, connect old codom to lam. Otherwise, scope will not find it. Then, rewrite.
518 pi->set_codom(codom);
519 auto rw = VarRewriter(lam->var()->as<Var>(), pi->var()->set(lam->var()->dbg()));
520 auto dom = pi->dom();
521 codom = rw.rewrite(codom);
522 pi->reset({dom, codom});
523 codom = pi;
524 }
525
526 if (!decl) {
527 scopes_.bind(outer, dbg, first);
528 if (external) first->make_external();
529 }
530
531 auto body = accept(Tag::T_assign) ? parse_decls("body of a "s + entity) : nullptr;
532 if (!body) {
533 if (!is_decl) error(prev_, "body of a {}", entity);
534 if (auto [_, __, filter] = funs.back(); filter) error(prev_, "cannot specify filter of a {}", entity);
535 }
536
537 // filter defaults to .tt for everything except the actual continuation of con/cn/fun/fn; here we use .ff as default
538 bool last = true;
539 for (auto [_, lam, filter] : funs | std::ranges::views::reverse) {
540 bool is_cn
541 = last
542 && (tok.tag() == Tag::K_con || tok.tag() == Tag::K_cn || tok.tag() == Tag::K_fun || tok.tag() == Tag::K_fn);
543 if (body) lam->set(filter ? filter : is_cn ? world().lit_ff() : world().lit_tt(), body);
544 body = lam;
545 last = false;
546 }
547
548 if (is_decl) expect(Tag::T_semicolon, "end of "s + entity);
549 if (anx) register_annex(dbg, first);
550
551 first->set(track.loc());
552
553 scopes_.pop();
554 return first;
555}
556
557Ref Parser::parse_ret_expr() {
558 eat(Tag::K_ret);
559 auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a ret expression");
560 expect(Tag::T_assign, "let expression");
561
562 auto cn = parse_expr("continuation expression of a ret expression");
563 expect(Tag::T_dollar, "separator of a ret expression");
564 if (auto ret_pi = Pi::ret_pi(cn->type())) {
565 auto arg = parse_expr("argument of ret expression");
566 expect(Tag::T_semicolon, "let expression");
567 auto lam = world().mut_lam(ret_pi);
568 ptrn->bind(scopes_, lam->var());
569 auto body = parse_decls("body of a ret expression");
570 lam->set(false, body);
571 return world().app(cn, {arg, lam});
572 }
573
574 error(prev_, "continuation of the ret expression is not a returning continuation but has type '{}'", cn->type());
575}
576
577Ref Parser::parse_lit_expr() {
578 auto track = tracker();
579 auto tok = lex();
580 auto [_, r] = Tok::prec(Tok::Prec::Lit);
581
582 if (accept(Tag::T_colon)) {
583 auto type = parse_expr("literal", r);
584
585 // clang-format off
586 switch (tok.tag()) {
587 case Tag::L_s:
588 case Tag::L_u:
589 case Tag::L_f: break;
590 case Tag::T_bot: return world().bot(type)->set(track.loc());
591 case Tag::T_top: return world().top(type)->set(track.loc());
592 default: fe::unreachable();
593 }
594 // clang-format on
595 return world().lit(type, tok.lit_u())->set(track.loc());
596 }
597
598 if (tok.tag() == Tag::T_bot) return world().bot(world().type())->set(track.loc());
599 if (tok.tag() == Tag::T_top) return world().top(world().type())->set(track.loc());
600 if (tok.tag() == Tag::L_s) error(prev_, ".Nat literal specified as signed but must be unsigned");
601 if (tok.tag() == Tag::L_f) error(prev_, ".Nat literal specified as floating-point but must be unsigned");
602
603 return world().lit_nat(tok.lit_u())->set(track.loc());
604}
605
606/*
607 * ptrns
608 */
609
610std::unique_ptr<Ptrn> Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec /*= Tok::Prec::Bot*/) {
611 auto track = tracker();
612 auto sym = anonymous_;
613 bool p = delim_l == Tag::D_paren_l;
614 bool b = delim_l == Tag::D_brckt_l;
615 assert((p ^ b) && "left delimiter must either be '(' or '['");
616 // p -> (p, ..., p)
617 // p -> [b, ..., b] b -> [b, ..., b]
618 // p -> s::(p, ..., p)
619 // p -> s::[b, ..., b] b -> s::[b, ..., b]
620 // p -> s: e b -> s: e
621 // p -> s b -> e
622 // p -> 's::(p, ..., p)
623 // p -> 's::[b, ..., b] b -> 's::[b, ..., b]
624 // p -> 's: e b -> 's: e
625 // p -> 's
626
627 if (p && ahead().isa(Tag::D_paren_l)) {
628 // p -> (p, ..., p)
629 return parse_tuple_ptrn(track, false, sym);
630 } else if (ahead().isa(Tag::D_brckt_l)) {
631 // p -> [b, ..., b] b -> [b, ..., b]
632 return parse_tuple_ptrn(track, false, sym);
633 }
634
635 auto backtick = accept(Tag::T_backtick);
636 bool rebind = (bool)backtick;
637
638 if (ahead(0).isa(Tag::M_id)) {
639 // p -> s::(p, ..., p)
640 // p -> s::[b, ..., b] b -> s::[b, ..., b]
641 // p -> s: e b -> s: e
642 // p -> s b -> e where e == id
643 // p -> 's::(p, ..., p)
644 // p -> 's::[b, ..., b] b -> 's::[b, ..., b]
645 // p -> 's: e b -> 's: e
646 // p -> 's
647 if (ahead(1).isa(Tag::T_colon_colon)) {
648 sym = eat(Tag::M_id).sym();
649 eat(Tag::T_colon_colon);
650 if (b && ahead().isa(Tag::D_paren_l))
651 error(ahead().loc(), "switching from []-style patterns to ()-style patterns is not allowed");
652 // b -> s::(p, ..., p)
653 // b -> s::[b, ..., b] b -> s::[b, ..., b]
654 // b -> 's::(p, ..., p)
655 // b -> 's::[b, ..., b] b -> 's::[b, ..., b]
656 if (ahead().isa(Tag::D_paren_l) || ahead().isa(Tag::D_brckt_l))
657 return parse_tuple_ptrn(track, rebind, sym);
658 else
659 syntax_err("tuple pattern after '" + sym.str() + "::'", ctxt);
660 } else if (ahead(1).isa(Tag::T_colon)) {
661 // p -> s: e b -> s: e
662 // p -> 's: e b -> 's: e
663 sym = eat(Tag::M_id).sym();
664 eat(Tag::T_colon);
665 auto type = parse_expr(ctxt, prec);
666 return std::make_unique<IdPtrn>(dbg(track, sym), rebind, type);
667 } else {
668 // p -> s b -> e where e == id
669 // p -> 's
670 if (p) {
671 // p -> s
672 // p -> 's
673 sym = eat(Tag::M_id).sym();
674 return std::make_unique<IdPtrn>(dbg(track, sym), rebind, nullptr);
675 } else {
676 // b -> e where e == id
677 auto type = parse_expr(ctxt, prec);
678 return std::make_unique<IdPtrn>(dbg(track, sym), rebind, type);
679 }
680 }
681 } else if (b) {
682 // b -> e where e != id
683 if (backtick) error(backtick.loc(), "you can only prefix identifiers with backtick for rebinding");
684 auto type = parse_expr(ctxt, prec);
685 return std::make_unique<IdPtrn>(dbg(track, sym), rebind, type);
686 } else if (!ctxt.empty()) {
687 // p -> ↯
688 syntax_err("pattern", ctxt);
689 }
690
691 return nullptr;
692}
693
694std::unique_ptr<TuplePtrn> Parser::parse_tuple_ptrn(Tracker track, bool rebind, Sym sym, Def* decl) {
695 auto delim_l = ahead().tag();
696 bool p = delim_l == Tag::D_paren_l;
697 bool b = delim_l == Tag::D_brckt_l;
698 assert(p ^ b);
699
700 std::deque<std::unique_ptr<Ptrn>> ptrns;
701 std::vector<Infer*> infers;
702 DefVec ops;
703
704 scopes_.push();
705 parse_list("tuple pattern", delim_l, [&]() {
706 parse_decls({});
707 auto track = tracker();
708 if (!ptrns.empty()) ptrns.back()->bind(scopes_, infers.back());
709 std::unique_ptr<Ptrn> ptrn;
710
711 if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::M_id)) {
712 std::vector<Tok> sym_toks;
713 while (auto tok = accept(Tag::M_id)) sym_toks.emplace_back(tok);
714
715 if (accept(Tag::T_colon)) { // identifier group: x y x: T
716 auto type = parse_expr("type of an identifier group within a tuple pattern");
717
718 for (size_t i = 0, e = sym_toks.size(); i != e; ++i) {
719 auto tok = sym_toks[i];
720 infers.emplace_back(world().mut_infer(type)->set(tok.dbg()));
721 ops.emplace_back(type);
722 auto ptrn = std::make_unique<IdPtrn>(tok.dbg(), false, type);
723 if (i != e - 1) ptrn->bind(scopes_, infers.back()); // last element will be bound above
724 ptrns.emplace_back(std::move(ptrn));
725 }
726 return;
727 }
728
729 // "x y z" is a curried app and maybe the prefix of a longer type expression
730 auto lhs = scopes_.find(sym_toks.front().dbg());
731 for (auto sym_tok : sym_toks | std::views::drop(1)) {
732 auto rhs = scopes_.find(sym_tok.dbg());
733 lhs = world().iapp(lhs, rhs)->set(lhs->loc() + sym_tok.loc());
734 }
735 auto [_, r] = Tok::prec(Tok::Prec::App);
736 auto expr = parse_infix_expr(track, lhs, r);
737 ptrn = std::make_unique<IdPtrn>(dbg(track, anonymous_), false, expr);
738 } else {
739 ptrn = parse_ptrn(delim_l, "element of a tuple pattern");
740 auto type = ptrn->type(world(), def2fields_);
741
742 if (b) { // If we are able to parse more stuff, we got an expression instead of just a binder.
743 if (auto expr = parse_infix_expr(track, type); expr != type)
744 ptrn = std::make_unique<IdPtrn>(dbg(track, anonymous_), false, expr);
745 }
746 }
747
748 auto type = ptrn->type(world(), def2fields_);
749 infers.emplace_back(world().mut_infer(type)->set(ptrn->sym()));
750 ops.emplace_back(type);
751 ptrns.emplace_back(std::move(ptrn));
752 });
753 scopes_.pop();
754
755 // TODO parse type
756 return std::make_unique<TuplePtrn>(dbg(track, sym), rebind, std::move(ptrns), nullptr, std::move(infers), decl);
757}
758
759/*
760 * decls
761 */
762
763Ref Parser::parse_decls(std::string_view ctxt) {
764 while (true) {
765 // clang-format off
766 switch (ahead().tag()) {
767 case Tag::T_semicolon: lex(); break; // eat up stray semicolons
768 case Tag::K_ax: parse_ax_decl(); break;
769 case Tag::K_let: parse_let_decl(); break;
770 case Tag::K_Sigma: parse_sigma_decl(); break;
771 case Tag::K_Pi: parse_pi_decl(); break;
772 case Tag::K_con:
773 case Tag::K_fun:
774 case Tag::K_lam: parse_lam(true); break;
775 default: return ctxt.empty() ? nullptr : parse_expr(ctxt);
776 }
777 // clang-format on
778 }
779}
780
781void Parser::parse_ax_decl() {
782 auto track = tracker();
783 eat(Tag::K_ax);
784 auto dbg = expect(Tag::M_anx, "annex name of an axiom").dbg();
785 auto [plugin, tag, sub] = Annex::split(world(), dbg.sym);
786 auto&& [annex, is_new] = driver().name2annex(dbg.sym, plugin, tag, dbg.loc);
787
788 if (!plugin) error(dbg.loc, "invalid axiom name '{}'", dbg.sym);
789 if (sub) error(dbg.loc, "axiom '{}' must not have a subtag", dbg.sym);
790
791 std::deque<std::deque<Sym>> new_subs;
792 if (ahead().isa(Tag::D_paren_l)) {
793 parse_list("tag list of an axiom", Tag::D_paren_l, [&]() {
794 auto& aliases = new_subs.emplace_back();
795 auto [_, tag] = parse_id("tag of an axiom");
796 aliases.emplace_back(tag);
797 while (accept(Tag::T_assign)) {
798 auto [_, alias] = parse_id("alias of an axiom tag");
799 aliases.emplace_back(alias);
800 }
801 });
802 }
803
804 if (!is_new && new_subs.empty() && !annex.subs.empty())
805 error(dbg.loc, "redeclaration of axiom '{}' without specifying new subs", dbg.sym);
806 else if (!is_new && !new_subs.empty() && annex.subs.empty())
807 error(dbg.loc, "cannot extend subs of axiom '{}' because it was declared as a subless axiom", dbg.sym);
808
809 auto type = parse_type_ascr("type ascription of an axiom");
810 if (!is_new && annex.pi != (type->isa<Pi>() != nullptr))
811 error(dbg.loc, "all declarations of annex '{}' have to be function types if any is", dbg.sym);
812 annex.pi = type->isa<Pi>() != nullptr;
813
814 Sym normalizer;
815 if (ahead().isa(Tag::T_comma) && ahead(1).isa(Tag::M_id)) {
816 lex();
817 normalizer = parse_id("normalizer of an axiom").sym;
818 }
819
820 if (!is_new && (annex.normalizer && normalizer) && annex.normalizer != normalizer)
821 error(dbg.loc, "all declarations of axiom '{}' must use the same normalizer name", dbg.sym);
822 annex.normalizer = normalizer;
823
824 auto [curry, trip] = Axiom::infer_curry_and_trip(type);
825
826 if (accept(Tag::T_comma)) {
827 auto c = expect(Tag::L_u, "curry counter for axiom");
828 if (c.lit_u() > curry) error(c.loc(), "curry counter cannot be greater than {}", curry);
829 curry = c.lit_u();
830 }
831
832 if (accept(Tag::T_comma)) trip = expect(Tag::L_u, "trip count for axiom").lit_u();
833
835 tag_t t = annex.tag_id;
836 sub_t s = annex.subs.size();
837 if (new_subs.empty()) {
838 auto norm = driver().normalizer(p, t, 0);
839 auto axiom = world().axiom(norm, curry, trip, type, p, t, 0)->set(dbg);
840 world().register_annex(p | (flags_t(t) << 8_u64), axiom);
841 scopes_.bind(dbg, axiom);
842 } else {
843 for (const auto& sub : new_subs) {
844 auto name = world().sym(dbg.sym.str() + "."s + sub.front().str());
845 auto norm = driver().normalizer(p, t, s);
846 auto axiom = world().axiom(norm, curry, trip, type, p, t, s)->set(track.loc(), name);
847 world().register_annex(p | (flags_t(t) << 8_u64) | flags_t(s), axiom);
848 for (auto& alias : sub) {
849 auto sym = world().sym(dbg.sym.str() + "."s + alias.str());
850 scopes_.bind({prev_, sym}, axiom);
851 }
852 ++s;
853 }
854 annex.subs.insert(annex.subs.end(), new_subs.begin(), new_subs.end());
855 }
856 expect(Tag::T_semicolon, "end of an axiom");
857}
858
859void Parser::parse_let_decl() {
860 auto track = tracker();
861 eat(Tag::K_let);
862
863 std::variant<std::unique_ptr<Ptrn>, Dbg> name;
864 Ref type;
865 if (auto tok = accept(Tag::M_anx)) {
866 name = tok.dbg();
867 type = parse_type_ascr();
868 } else {
869 auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a let declaration");
870 type = ptrn->type(world(), def2fields_);
871 name = std::move(ptrn);
872 }
873
874 expect(Tag::T_assign, "let");
875 auto value = parse_expr("value of a let declaration");
876
877 if (type && !Check::assignable(type, value))
878 error(track.loc(), "cannot assign value `{}` of type `{}` to its declared type `{}` in a let declaration",
879 value, value->type(), type);
880
881 if (auto dbg = std::get_if<Dbg>(&name)) {
882 scopes_.bind(*dbg, value);
883 register_annex(*dbg, value);
884 } else {
885 std::get<std::unique_ptr<Ptrn>>(name)->bind(scopes_, value);
886 }
887
888 expect(Tag::T_semicolon, "let declaration");
889}
890
891void Parser::parse_sigma_decl() {
892 auto track = tracker();
893 eat(Tag::K_Sigma);
894 auto [dbg, anx] = parse_name("sigma declaration");
895 auto type = accept(Tag::T_colon) ? parse_expr("type of a sigma declaration") : world().type();
896 auto arity = std::optional<nat_t>{};
897 if (accept(Tag::T_comma)) arity = expect(Tag::L_u, "arity of a sigma").lit_u();
898
899 if (accept(Tag::T_assign)) {
900 Def* decl;
901 if (auto def = scopes_.query(dbg)) {
902 if ((!def->isa_mut<Sigma>() && !def->isa<Infer>()) || !def->isa_lit_arity())
903 error(dbg.loc, "'{}' has not been declared as a sigma", dbg.sym);
904 if (!Check::alpha(def->type(), type))
905 error(dbg.loc, "'{}' of type '{}' has been redeclared with a different type '{}'; here: {}", dbg.sym,
906 def->type(), type, def->loc());
907 if (arity && *arity != def->as_lit_arity())
908 error(dbg.loc, "sigma '{}' redeclared with a different arity '{}'; previous arity was '{}' here: {}",
909 dbg.sym, *arity, def->arity(), def->loc());
910 decl = def->as_mut();
911 if (decl->is_set())
912 error(dbg.loc, "redefinition of '{}'; previous definition here: '{}'", dbg.sym, decl->loc());
913 } else {
914 decl = (arity ? (Def*)world().mut_sigma(type, *arity) : (Def*)world().mut_infer(type))->set(dbg);
915 scopes_.bind(dbg, decl);
916 }
917
918 if (!ahead().isa(Tag::D_brckt_l)) syntax_err("sigma expression", "definition of a sigma declaration");
919
920 auto ptrn = parse_tuple_ptrn(track, false, dbg.sym, decl);
921 auto t = ptrn->type(world(), def2fields_);
922
923 assert(t->isa_mut<Sigma>());
924 t->set<true>(track.loc());
925 if (anx) register_annex(dbg, t);
926
927 if (auto infer = decl->isa<Infer>()) {
928 assert(infer->op() == t);
929 infer->set<true>(track.loc());
930 scopes_.bind(dbg, t, true); // rebind dbg to point to sigma instead of infer
931 } else {
932 assert(t == decl);
933 }
934 } else {
935 auto decl = (arity ? (Def*)world().mut_sigma(type, *arity) : (Def*)world().mut_infer(type))->set(dbg);
936 scopes_.bind(dbg, decl);
937 }
938
939 expect(Tag::T_semicolon, "end of a sigma declaration");
940}
941
942void Parser::parse_pi_decl() {
943 auto track = tracker();
944 eat(Tag::K_Pi);
945 auto [dbg, anx] = parse_name("pi declaration");
946 auto type = accept(Tag::T_colon) ? parse_expr("type of a pi declaration") : world().type();
947
948 if (accept(Tag::T_assign)) {
949 Pi* pi;
950 if (auto def = scopes_.query(dbg)) {
951 if (auto mut = def->isa_mut<Pi>()) {
952 if (!Check::alpha(mut->type(), type))
953 error(dbg.loc, "'{}' of type '{}' has been redeclared with a different type '{}'; here: {}",
954 dbg.sym, mut->type(), type, mut->loc());
955 if (mut->is_set())
956 error(dbg.loc, "redefinition of '{}'; previous definition here: '{}'", dbg.sym, mut->loc());
957 pi = mut;
958 } else {
959 error(dbg.loc, "'{}' has not been declared as a pi", dbg.sym);
960 }
961 } else {
962 pi = world().mut_pi(type)->set(dbg);
963 scopes_.bind(dbg, pi);
964 }
965 if (anx) register_annex(dbg, pi);
966
967 if (!ahead().isa(Tag::T_Pi) && !ahead().isa(Tag::K_Cn) && !ahead().isa(Tag::K_Fn))
968 syntax_err("pi expression", "definition of a pi declaration");
969
970 auto other = parse_pi_expr(pi);
971 assert_unused(other == pi);
972 pi->set<true>(track.loc());
973 } else {
974 auto pi = world().mut_pi(type)->set(dbg);
975 scopes_.bind(dbg, pi);
976 }
977
978 expect(Tag::T_semicolon, "end of a pi declaration");
979}
980
981} // namespace thorin
Arr * set_shape(const Def *shape)
Definition tuple.h:67
static std::pair< u8, u8 > infer_curry_and_trip(const Def *type)
Definition axiom.cpp:14
static bool alpha(Ref d1, Ref d2)
Are d1 and d2 α-equivalent?
Definition check.h:59
static bool assignable(Ref type, Ref value)
Can value be assigned to sth of type?
Definition check.h:63
Def * reset(size_t i, const Def *def)
Successively reset from left to right.
Definition def.h:291
Ref var(nat_t a, nat_t i)
Definition def.h:403
Def * unset()
Unsets all Def::ops; works even, if not set at all or partially.
Definition def.cpp:272
Def * set(size_t i, const Def *def)
Successively set from left to right.
Definition def.cpp:254
std::pair< Annex &, bool > name2annex(Sym sym, Sym plugin, Sym tag, Loc loc)
Definition driver.cpp:96
void load(Sym name)
Definition driver.cpp:53
const auto & search_paths() const
Definition driver.h:36
const fs::path * add_import(fs::path, Sym)
Yields a fs::path* if not already added that you can use in Location; returns nullptr otherwise.
Definition driver.cpp:45
auto normalizer(flags_t flags) const
Definition driver.h:74
Infer * set(const Def *op)
Definition check.h:21
Pack * set(const Def *body)
Definition tuple.h:104
void plugin(Sym)
Definition parser.cpp:72
Driver & driver()
Definition parser.h:41
World & world()
Definition parser.h:40
void import(std::string_view sv)
Definition parser.h:42
Pi * set_dom(Ref dom)
Definition lam.h:74
Pi * set(Ref dom, Ref codom)
Definition lam.h:73
const Pi * ret_pi() const
Yields the last Pi::dom, if it Pi::isa_basicblock.
Definition lam.cpp:13
const Def * query(Dbg) const
Definition scopes.cpp:12
void pop()
Definition scopes.cpp:7
void bind(Scope *, Dbg, const Def *, bool rebind=false)
Definition scopes.cpp:27
void push()
Definition scopes.h:18
Scope * curr()
Definition scopes.h:20
const Def * find(Dbg) const
Same as Scopes::query but potentially raises an error.
Definition scopes.cpp:21
Sigma * set(size_t i, const Def *def)
Definition tuple.h:20
static constexpr std::array< Prec, 2 > prec(Prec p)
Definition tok.h:125
Infer * mut_infer_univ()
Definition world.h:202
Ref type_i64()
Definition world.h:464
const Lit * lit_i1()
Definition world.h:373
Ref insert(Ref d, Ref i, Ref val)
Definition world.cpp:340
Pi * mut_pi(Ref type, bool implicit=false)
Definition world.h:238
Arr * mut_arr(Ref type)
Definition world.h:310
const Lit * lit_i8()
Definition world.h:374
Ref type_i1()
Definition world.h:458
Ref iapp(Ref callee, Ref arg)
Places Infer arguments as demanded by Pi::implicit and then apps arg.
Definition world.cpp:162
const Lit * lit(Ref type, u64 val)
Definition world.cpp:435
Ref type_i32()
Definition world.h:463
Pack * mut_pack(Ref type)
Definition world.h:332
const Lit * lit_i16()
Definition world.h:375
const Lit * lit_i64()
Definition world.h:377
Ref Bot()
Definition world.h:416
Sym sym(std::string_view)
Definition world.cpp:77
Ref var(Ref type, Def *mut)
Definition world.cpp:153
Ref type_i16()
Definition world.h:462
Ref pack(Ref arity, Ref body)
Definition world.cpp:405
Sigma * mut_sigma(Ref type, size_t size)
Definition world.h:301
const Nat * type_nat()
Definition world.h:446
const Axiom * axiom(NormalizeFn n, u8 curry, u8 trip, Ref type, plugin_t p, tag_t t, sub_t s)
Definition world.h:216
const Pi * pi(Ref dom, Ref codom, bool implicit=false)
Definition world.h:234
const Lit * lit_i32()
Definition world.h:376
Ref extract(Ref d, Ref i)
Definition world.cpp:278
const Idx * type_idx()
Definition world.h:447
Ref sigma(Defs ops)
Definition world.cpp:218
Ref top(Ref type)
Definition world.h:415
const Lit * lit_tt()
Definition world.h:406
const Lit * lit_nat(nat_t a)
Definition world.h:367
Ref arr(Ref shape, Ref body)
Definition world.cpp:378
Ref bot(Ref type)
Definition world.h:414
const Def * register_annex(flags_t f, const Def *)
Definition world.cpp:80
Ref app(Ref callee, Ref arg)
Definition world.cpp:183
Ref tuple(Defs ops)
Definition world.cpp:226
const Lit * lit_ff()
Definition world.h:405
Ref type_i8()
Definition world.h:461
Infer * mut_infer(Ref type)
Definition world.h:201
Lam * mut_lam(const Pi *pi)
Definition world.h:263
const Univ * univ()
Definition world.h:183
const Type * type(Ref level)
Definition world.cpp:92
Definition span.h:103
Definition cfg.h:11
DefVec rewrite(Def *mut, Ref arg)
Definition rewrite.cpp:45
u8 sub_t
Definition types.h:49
void error(const Def *def, const char *fmt, Args &&... args)
Definition def.h:622
void bootstrap(Driver &, Sym, std::ostream &)
Definition bootstrap.cpp:11
Tok::Tag Tag
Definition lexer.cpp:10
u8 tag_t
Definition types.h:48
u64 plugin_t
Definition types.h:47
Sym sym
Definition dbg.h:33
Vector< const Def * > DefVec
Definition def.h:63
u64 flags_t
Definition types.h:46
static std::optional< plugin_t > mangle(Sym s)
Mangles s into a dense 48-bit representation.
Definition plugin.cpp:9
static std::array< Sym, 3 > split(World &, Sym)
Definition plugin.cpp:58