MimIR 0.1
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
parser.cpp
Go to the documentation of this file.
1#include "mim/ast/parser.h"
2
3#include <filesystem>
4#include <fstream>
5
6#include "mim/driver.h"
7
8// clang-format off
9#define C_PRIMARY \
10 K_Univ: \
11 case Tag::K_Nat: \
12 case Tag::K_Idx: \
13 case Tag::K_Bool: \
14 case Tag::K_ff: \
15 case Tag::K_tt: \
16 case Tag::K_i1: \
17 case Tag::K_i8: \
18 case Tag::K_i16: \
19 case Tag::K_i32: \
20 case Tag::K_i64: \
21 case Tag::K_I1: \
22 case Tag::K_I8: \
23 case Tag::K_I16: \
24 case Tag::K_I32: \
25 case Tag::K_I64: \
26 case Tag::T_star: \
27 case Tag::T_box
28
29#define C_ID \
30 M_anx: \
31 case Tag::M_id
32
33#define C_LIT \
34 T_bot: \
35 case Tag::T_top: \
36 case Tag::L_str: \
37 case Tag::L_c: \
38 case Tag::L_s: \
39 case Tag::L_u: \
40 case Tag::L_f: \
41 case Tag::L_i
42
43#define C_LAM \
44 K_lam: \
45 case Tag::K_con: \
46 case Tag::K_fun
47
48#define C_DECL \
49 K_ax: \
50 case Tag::K_let: \
51 case Tag::K_rec: \
52 case Tag::K_ccon: \
53 case Tag::K_cfun: \
54 case Tag::C_LAM
55
56#define C_PI \
57 T_Pi: \
58 case Tag::K_Cn: \
59 case Tag::K_Fn
60
61#define C_LM \
62 T_lm: \
63 case Tag::K_cn: \
64 case Tag::K_fn
65
66#define C_EXPR \
67 C_PRIMARY: \
68 case Tag::C_ID: \
69 case Tag::C_LIT: \
70 case Tag::C_DECL: \
71 case Tag::C_PI: \
72 case Tag::C_LM: \
73 case Tag::K_Type: /*TypeExpr*/ \
74 case Tag::K_ins: /*InsertExpr*/ \
75 case Tag::K_ret: /*RetExpr*/ \
76 case Tag::D_angle_l: /*PackExpr*/ \
77 case Tag::D_brckt_l: /*SigmaExpr*/ \
78 case Tag::D_paren_l: /*TupleExpr*/ \
79 case Tag::D_quote_l /*ArrExpr*/
80
81#define C_PTRN \
82 M_id: \
83 case Tag::T_backtick: \
84 case Tag::D_brckt_l: \
85 case Tag::D_paren_l
86// clang-format on
87
88using namespace std::string_literals;
89
90namespace mim::ast {
91
92using Tag = Tok::Tag;
93
94/*
95 * entry points
96 */
97
98Ptr<Module> Parser::parse_module() {
99 auto track = tracker();
100 Ptrs<Import> imports;
101 while (true) {
102 if (ahead().isa(Tag::K_import) || ahead().isa(Tag::K_plugin)) {
103 if (auto import = parse_import_or_plugin()) imports.emplace_back(std::move(import));
104 } else {
105 break;
106 }
107 }
108 auto decls = parse_decls();
109 bool where = ahead().isa(Tag::K_where);
110 expect(Tag::EoF, "module");
111 auto mod = ptr<Module>(track, std::move(imports), std::move(decls));
112 if (where) ast().note(mod->loc().anew_finis(), "did you accidentally end your declaration expression with a ';'?");
113 return mod;
114}
115
116Ptr<Module> Parser::import(Dbg dbg, std::ostream* md) {
117 auto name = dbg.sym();
118 auto filename = fs::path(name.view());
119 driver().VLOG("import: {}", name);
120
121 if (!filename.has_extension()) filename.replace_extension("mim"); // TODO error cases
122
123 fs::path rel_path;
124 for (const auto& path : driver().search_paths()) {
125 std::error_code ignore;
126 rel_path = path / filename;
127 if (bool reg_file = fs::is_regular_file(rel_path, ignore); reg_file && !ignore) break;
128 rel_path = path / name.view() / filename;
129 if (bool reg_file = fs::is_regular_file(rel_path, ignore); reg_file && !ignore) break;
130 }
131
132 if (auto path = driver().add_import(std::move(rel_path), name)) {
133 auto ifs = std::ifstream(*path);
134 return import(ifs, dbg.loc(), path, md);
135 }
136 return {};
137}
138
139Ptr<Module> Parser::import(std::istream& is, Loc loc, const fs::path* path, std::ostream* md) {
140 driver().VLOG("reading: {}", path ? path->string() : "<unknown file>"s);
141 if (!is) {
142 ast().error(loc, "cannot read file {}", *path);
143 return {};
144 }
145
146 auto state = std::tuple(prev_, ahead_, lexer_);
147 auto lexer = Lexer(ast(), is, path, md);
148 lexer_ = &lexer;
149 init(path);
150 auto mod = parse_module();
151 std::tie(prev_, ahead_, lexer_) = state;
152 return mod;
153}
154
156 if (!driver().flags().bootstrap && !driver().is_loaded(dbg.sym())) driver().load(dbg.sym());
157 return import(dbg);
158}
159
160/*
161 * misc
162 */
163
164Ptr<Import> Parser::parse_import_or_plugin() {
165 auto track = tracker();
166 auto tag = lex().tag();
167 auto name = expect(Tag::M_id, "{} name", tag == Tag::K_import ? "import" : "plugin");
168 auto dbg = name.dbg();
169 expect(Tag::T_semicolon, "end of {}", tag == Tag::K_import ? "import" : "plugin");
170 if (auto module = tag == Tag::K_import ? import(dbg) : plugin(dbg))
171 return ptr<Import>(track, tag, name.dbg(), std::move(module));
172 return {};
173}
174
175Dbg Parser::parse_id(std::string_view ctxt) {
176 if (auto id = accept(Tag::M_id)) return id.dbg();
177 syntax_err("identifier", ctxt);
178 return {prev_, driver().sym("<error>")};
179}
180
181Dbg Parser::parse_name(std::string_view ctxt) {
182 if (auto tok = accept(Tag::M_anx)) return tok.dbg();
183 if (auto tok = accept(Tag::M_id)) return tok.dbg();
184 syntax_err("identifier or annex name", ctxt);
185 return Dbg(prev_, ast().sym("<error>"));
186}
187
188Ptr<Expr> Parser::parse_type_ascr(std::string_view ctxt) {
189 if (accept(Tag::T_colon)) return parse_expr(ctxt);
190 if (ctxt.empty()) return nullptr;
191 syntax_err("':'", ctxt);
192 return ptr<ErrorExpr>(prev_);
193}
194
195/*
196 * exprs
197 */
198
199Ptr<Expr> Parser::parse_expr(std::string_view ctxt, Prec curr_prec) {
200 auto track = tracker();
201 auto lhs = parse_primary_expr(ctxt);
202 return parse_infix_expr(track, std::move(lhs), curr_prec);
203}
204
205Ptr<Expr> Parser::parse_infix_expr(Tracker track, Ptr<Expr>&& lhs, Prec curr_prec) {
206 while (true) {
207 // If operator in ahead has less left precedence: reduce (break).
208 switch (ahead().tag()) {
209 case Tag::T_extract: {
210 if (curr_prec >= Prec::Extract) return lhs;
211 lex();
212 if (auto tok = accept(Tag::M_id))
213 lhs = ptr<ExtractExpr>(track.loc(), std::move(lhs), tok.dbg());
214 else {
215 auto rhs = parse_expr("right-hand side of an extract", Prec::Extract);
216 lhs = ptr<ExtractExpr>(track.loc(), std::move(lhs), std::move(rhs));
217 }
218 continue;
219 }
220 case Tag::T_arrow: {
221 if (curr_prec > Prec::Arrow) return lhs; // ">" - Arrow is rassoc
222 lex();
223 auto rhs = parse_expr("right-hand side of a function type", Prec::Arrow);
224 lhs = ptr<ArrowExpr>(track.loc(), std::move(lhs), std::move(rhs));
225 continue;
226 }
227 case Tag::T_at: {
228 if (curr_prec >= Prec::App) return lhs;
229 lex();
230 auto rhs = parse_expr("explicit argument to an application", Prec::App);
231 lhs = ptr<AppExpr>(track.loc(), true, std::move(lhs), std::move(rhs));
232 continue;
233 }
234 case Tag::C_EXPR: {
235 if (curr_prec >= Prec::App) return lhs;
236 switch (ahead().tag()) {
237 case Tag::C_DECL:
238 ast().warn(ahead().loc(), "you are passing a declaration expression as argument");
239 ast().note(lhs->loc(), "to this expression");
240 ast().note(ahead().loc(),
241 "if this was your intention, consider to parenthesize the declaration expression");
242 ast().note(lhs->loc().anew_finis(), "otherwise, you are probably missing a ';'");
243 default: break;
244 }
245 auto rhs = parse_expr("argument to an application", Prec::App);
246 lhs = ptr<AppExpr>(track.loc(), false, std::move(lhs), std::move(rhs));
247 continue;
248 }
249 case Tag::K_where: {
250 if (curr_prec >= Prec::Where) return lhs;
251 lex();
252 auto decls = parse_decls();
253 lhs = ptr<DeclExpr>(track, std::move(decls), std::move(lhs), true);
254
255 bool where = ahead().tag() == Tag::K_where;
256 expect(Tag::K_end, "end of a .where declaration block");
257 if (where)
258 ast().note(lhs->loc().anew_finis(),
259 "did you accidentally end your declaration expression with a ';'?");
260 return lhs;
261 }
262 default: return lhs;
263 }
264 }
265}
266
267Ptr<Expr> Parser::parse_insert_expr() {
268 eat(Tag::K_ins);
269 auto track = tracker();
270 expect(Tag::D_paren_l, "opening paren for insert arguments");
271 auto tuple = parse_expr("the tuple to insert into");
272 expect(Tag::T_comma, "comma after tuple to insert into");
273 auto index = parse_expr("insert index");
274 expect(Tag::T_comma, "comma after insert index");
275 auto value = parse_expr("insert value");
276 expect(Tag::D_paren_r, "closing paren for insert arguments");
277 return ptr<InsertExpr>(track.loc(), std::move(tuple), std::move(index), std::move(value));
278}
279
280Ptr<Expr> Parser::parse_primary_expr(std::string_view ctxt) {
281 // clang-format off
282 switch (ahead().tag()) {
283 case Tag::C_PRIMARY: return ptr<PrimaryExpr>(lex());
284 case Tag::C_ID: return ptr<IdExpr>(lex().dbg());
285 case Tag::C_LIT: return parse_lit_expr();
286 case Tag::C_DECL: return parse_decl_expr();
287 case Tag::C_PI: return parse_pi_expr();
288 case Tag::C_LM: return parse_lam_expr();
289 case Tag::K_ins: return parse_insert_expr();
290 case Tag::K_ret: return parse_ret_expr();
291 case Tag::D_quote_l: return parse_arr_or_pack_expr<true>();
292 case Tag::D_angle_l: return parse_arr_or_pack_expr<false>();
293 case Tag::D_brckt_l: return parse_sigma_expr();
294 case Tag::D_paren_l: return parse_tuple_expr();
295 case Tag::K_Type: return parse_type_expr();
296 default:
297 if (ctxt.empty()) return nullptr;
298 syntax_err("primary expression", ctxt);
299 }
300 // clang-format on
301 return ptr<ErrorExpr>(prev_);
302}
303
304template<bool arr> Ptr<Expr> Parser::parse_arr_or_pack_expr() {
305 auto track = tracker();
306 eat(arr ? Tag::D_quote_l : Tag::D_angle_l);
307
308 Dbg dbg;
309 if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon)) {
310 dbg = eat(Tag::M_id).dbg();
311 eat(Tag::T_colon);
312 }
313
314 auto shape = parse_expr(arr ? "shape of an array" : "shape of a pack");
315 auto ptrn = IdPtrn::mk_id(ast(), dbg, std::move(shape));
316 expect(Tag::T_semicolon, arr ? "array" : "pack");
317 auto body = parse_expr(arr ? "body of an array" : "body of a pack");
318 expect(arr ? Tag::D_quote_r : Tag::D_angle_r,
319 arr ? "closing delimiter of an array" : "closing delimiter of a pack");
320
321 return ptr<ArrOrPackExpr<arr>>(track, std::move(ptrn), std::move(body));
322}
323
324Ptr<Expr> Parser::parse_decl_expr() {
325 auto track = tracker();
326 auto decls = parse_decls();
327 auto expr = parse_expr("final expression of a declaration expression");
328 return ptr<DeclExpr>(track, std::move(decls), std::move(expr), false);
329}
330
331Ptr<Expr> Parser::parse_lit_expr() {
332 auto track = tracker();
333 auto tok = lex();
334 auto type = accept(Tag::T_colon) ? parse_expr("literal", Prec::Lit) : nullptr;
335 return ptr<LitExpr>(track, tok, std::move(type));
336}
337
338Ptr<Expr> Parser::parse_sigma_expr() { return ptr<SigmaExpr>(parse_tuple_ptrn()); }
339
340Ptr<Expr> Parser::parse_tuple_expr() {
341 auto track = tracker();
342 Ptrs<Expr> elems;
343 parse_list("tuple", Tag::D_paren_l, [&]() { elems.emplace_back(parse_expr("tuple element")); });
344 return ptr<TupleExpr>(track, std::move(elems));
345}
346
347Ptr<Expr> Parser::parse_type_expr() {
348 auto track = tracker();
349 eat(Tag::K_Type);
350 auto level = parse_expr("type level", Prec::App);
351 return ptr<TypeExpr>(track, std::move(level));
352}
353
354Ptr<Expr> Parser::parse_pi_expr() {
355 auto track = tracker();
356 auto tag = lex().tag();
357
358 std::string entity;
359 switch (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
367 while (true) {
368 auto track = tracker();
369 auto implicit = (bool)accept(Tag::T_dot);
370 auto prec = tag == Tag::K_Cn ? Prec::Bot : Prec::Pi;
371 auto ptrn = parse_ptrn(Tag::D_brckt_l, "domain of a "s + entity, prec);
372 doms.emplace_back(ptr<PiExpr::Dom>(track, implicit, std::move(ptrn)));
373
374 switch (ahead().tag()) {
375 case Tag::C_PTRN: continue;
376 default: break;
377 }
378 break;
379 }
380
381 auto codom = tag != Tag::K_Cn ? (expect(Tag::T_arrow, entity), parse_expr("codomain of a "s + entity, Prec::Arrow))
382 : nullptr;
383
384 if (tag == Tag::K_Fn) doms.back()->add_ret(ast(), codom ? std::move(codom) : ptr<InferExpr>(prev_));
385
386 return ptr<PiExpr>(track.loc(), tag, std::move(doms), std::move(codom));
387}
388
389Ptr<Expr> Parser::parse_lam_expr() { return ptr<LamExpr>(parse_lam_decl()); }
390
391Ptr<Expr> Parser::parse_ret_expr() {
392 auto track = tracker();
393 eat(Tag::K_ret);
394 auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a ret expression");
395 expect(Tag::T_assign, "ret expression");
396 auto callee = parse_expr("continuation expression of a ret expression");
397 expect(Tag::T_dollar, "separator of a ret expression");
398 auto arg = parse_expr("argument of ret expression");
399 expect(Tag::T_semicolon, "ret expression");
400 auto body = parse_expr("body of a ret expression");
401 return ptr<RetExpr>(track, std::move(ptrn), std::move(callee), std::move(arg), std::move(body));
402}
403
404/*
405 * ptrns
406 */
407
408Ptr<Ptrn> Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Prec prec, bool allow_annex) {
409 auto track = tracker();
410 bool p = delim_l == Tag::D_paren_l;
411 bool b = delim_l == Tag::D_brckt_l;
412 assert((p ^ b) && "left delimiter must either be '(' or '['");
413
414 // p -> anx
415 // p -> anx: e
416 if (allow_annex) {
417 assert(p);
418 if (auto anx = accept(Tok::Tag::M_anx)) {
419 auto type = parse_type_ascr();
420 return ptr<IdPtrn>(track, false, anx.dbg(), std::move(type));
421 }
422 }
423
424 // p -> `s: e b -> `s: e
425 if (accept(Tok::Tag::T_backtick)) {
426 auto dbg = expect(Tok::Tag::M_id, "identifier pattern").dbg();
427 auto type = accept(Tok::Tag::T_colon) ? parse_expr("identifier pattern", prec) : nullptr;
428 return ptr<IdPtrn>(track, true, dbg, std::move(type));
429 }
430
431 // p -> (p, ..., p)
432 // p -> [b, ..., b] b -> [b, ..., b]
433 if ((p && ahead().isa(Tag::D_paren_l)) || ahead().isa(Tag::D_brckt_l)) return parse_tuple_ptrn();
434
435 if (ahead(0).isa(Tag::M_id)) {
436 if (ahead(1).isa(Tag::T_colon)) {
437 // p -> s: e b -> s: e
438 auto dbg = eat(Tag::M_id).dbg();
439 eat(Tag::T_colon);
440 auto type = parse_expr(ctxt, prec);
441 return ptr<IdPtrn>(track, false, dbg, std::move(type));
442 } else if (p) {
443 // p -> s
444 // p -> `s
445 auto dbg = eat(Tag::M_id).dbg();
446 return ptr<IdPtrn>(track, false, dbg, nullptr);
447 } else {
448 // b -> e where e == id
449 auto type = parse_expr(ctxt, prec);
450 return ptr<IdPtrn>(track, false, type->loc().anew_begin(), std::move(type));
451 }
452 } else if (b) {
453 // b -> e where e != id
454 auto type = parse_expr(ctxt, prec);
455 auto loc = type->loc().anew_begin();
456 return ptr<IdPtrn>(track, false, Dbg(loc), std::move(type));
457 } else if (!ctxt.empty()) {
458 // p -> ↯
459 syntax_err("pattern", ctxt);
460 return ptr<ErrorPtrn>(prev_);
461 }
462
463 return nullptr;
464}
465
466Ptr<TuplePtrn> Parser::parse_tuple_ptrn() {
467 auto track = tracker();
468 auto delim_l = ahead().tag();
469
470 Ptrs<Ptrn> ptrns;
471 parse_list("tuple pattern", delim_l, [&]() {
472 auto track = tracker();
473 Ptr<Ptrn> ptrn;
474
475 if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::M_id)) {
476 Dbgs dbgs;
477 while (auto tok = accept(Tag::M_id)) dbgs.emplace_back(tok.dbg());
478
479 if (accept(Tag::T_colon)) { // identifier group: x y x: T
480 auto dbg = dbgs.back();
481 auto type = parse_expr("type of an identifier group within a tuple pattern");
482 auto id = ptr<IdPtrn>(dbg.loc() + type->loc().finis, false, dbg, std::move(type));
483
484 for (auto dbg : dbgs | std::views::take(dbgs.size() - 1))
485 ptrns.emplace_back(ptr<GrpPtrn>(dbg, id.get()));
486 ptrns.emplace_back(std::move(id));
487 return;
488 }
489
490 // "x y z" is a curried app and maybe the prefix of a longer type expression
491 Ptr<Expr> lhs = ptr<IdExpr>(dbgs.front());
492 for (auto dbg : dbgs | std::views::drop(1)) {
493 auto rhs = ptr<IdExpr>(dbg);
494 lhs = ptr<AppExpr>(track, false, std::move(lhs), std::move(rhs));
495 }
496 auto expr = parse_infix_expr(track, std::move(lhs), Prec::App);
497 ptrn = IdPtrn::mk_type(ast(), std::move(expr));
498 } else {
499 auto dl = delim_l == Tag::D_brckt_l ? delim_l : Tag::D_paren_l;
500 ptrn = parse_ptrn(dl, "element of a tuple pattern");
501
502 if (delim_l == Tag::D_brckt_l) {
503 // If we are able to parse more stuff, we got an expr instead of a binder:
504 // [..., [.Nat, .Nat] -> .Nat, ...] ==> [..., _: [.Nat, .Nat] -> .Nat, ...]
505 if (auto expr = Ptrn::to_expr(ast(), std::move(ptrn))) {
506 auto addr = expr.get();
507 expr = parse_infix_expr(track, std::move(expr));
508 if (expr.get() != addr) {
509 auto loc = expr->loc();
510 ptrn = ptr<IdPtrn>(loc, false, Dbg(loc.anew_begin(), Sym()), std::move(expr));
511 } else {
512 if (!ptrn) ptrn = Ptrn::to_ptrn(std::move(expr));
513 }
514 }
515 }
516 }
517
518 ptrns.emplace_back(std::move(ptrn));
519 });
520
521 Dbg dbg;
522 bool rebind = false;
523 if (accept(Tag::T_colon_colon)) {
524 rebind = (bool)accept(Tag::T_backtick);
525 dbg = eat(Tag::M_id).dbg();
526 }
527 return ptr<TuplePtrn>(track, delim_l, std::move(ptrns), rebind, dbg);
528}
529
530/*
531 * decls
532 */
533
534Ptrs<ValDecl> Parser::parse_decls() {
535 Ptrs<ValDecl> decls;
536 while (true) {
537 // clang-format off
538 switch (ahead().tag()) {
539 case Tag::T_semicolon: lex(); break; // eat up stray semicolons
540 case Tag::K_ax: decls.emplace_back(parse_axiom_decl()); break;
541 case Tag::K_ccon:
542 case Tag::K_cfun: decls.emplace_back(parse_c_decl()); break;
543 case Tag::K_let: decls.emplace_back(parse_let_decl()); break;
544 case Tag::K_rec: decls.emplace_back(parse_rec_decl(true)); break;
545 case Tag::K_con:
546 case Tag::K_fun:
547 case Tag::K_lam: decls.emplace_back(parse_lam_decl()); break;
548 default: return decls;
549 }
550 // clang-format on
551 }
552}
553
554Ptr<ValDecl> Parser::parse_axiom_decl() {
555 auto track = tracker();
556 eat(Tag::K_ax);
557 Dbg dbg, normalizer;
558 Tok curry, trip;
559 if (auto name = expect(Tag::M_anx, "annex name of an axiom"))
560 dbg = name.dbg();
561 else
562 dbg = Dbg(prev_, ast().sym("<error annex name>"));
563
564 std::deque<Ptrs<AxiomDecl::Alias>> subs;
565 if (ahead().isa(Tag::D_paren_l)) {
566 parse_list("tag list of an axiom", Tag::D_paren_l, [&]() {
567 auto& aliases = subs.emplace_back();
568 aliases.emplace_back(ptr<AxiomDecl::Alias>(parse_id("tag of an axiom")));
569 while (accept(Tag::T_assign))
570 aliases.emplace_back(ptr<AxiomDecl::Alias>(parse_id("alias of an axiom tag")));
571 });
572 }
573
574 auto type = parse_type_ascr("type ascription of an axiom");
575
576 if (ahead(0).isa(Tag::T_comma) && ahead(1).isa(Tag::M_id)) {
577 lex();
578 normalizer = lex().dbg();
579 }
580 if (accept(Tag::T_comma)) {
581 if (auto c = expect(Tag::L_u, "curry counter for axiom")) curry = c;
582 if (accept(Tag::T_comma)) {
583 if (auto t = expect(Tag::L_u, "trip count for axiom")) trip = t;
584 }
585 }
586
587 return ptr<AxiomDecl>(track, dbg, std::move(subs), std::move(type), normalizer, curry, trip);
588}
589
590Ptr<ValDecl> Parser::parse_let_decl() {
591 auto track = tracker();
592 eat(Tag::K_let);
593 auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a let declaration", Prec::Bot, true);
594 expect(Tag::T_assign, "let");
595 auto type = parse_type_ascr();
596 auto value = parse_expr("value of a let declaration");
597 return ptr<LetDecl>(track, std::move(ptrn), std::move(value));
598}
599
600Ptr<ValDecl> Parser::parse_c_decl() {
601 auto track = tracker();
602 auto tag = lex().tag();
603 auto id = expect(Tag::M_id, "C function declaration");
604 auto dom = parse_ptrn(Tag::D_brckt_l, "domain of a C function"s, Prec::App);
605 Ptr<Expr> codom;
606 if (tag == Tag::K_cfun) {
607 expect(Tag::T_colon, "codomain of a C function");
608 codom = parse_expr("codomain of a C function");
609 }
610 return ptr<CDecl>(track, tag, id.dbg(), std::move(dom), std::move(codom));
611}
612
613Ptr<RecDecl> Parser::parse_rec_decl(bool first) {
614 auto track = tracker();
615 eat(first ? Tag::K_rec : Tag::K_and);
616 auto dbg = parse_name("recursive declaration");
617 auto type = accept(Tag::T_colon) ? parse_expr("type of a recursive declaration") : ptr<InferExpr>(prev_);
618 expect(Tag::T_assign, "recursive declaration");
619 auto body = parse_expr("body of a recursive declaration");
620 auto next = ahead().isa(Tag::K_and) ? parse_and_decl() : nullptr;
621 return ptr<RecDecl>(track, dbg, std::move(type), std::move(body), std::move(next));
622}
623
624Ptr<LamDecl> Parser::parse_lam_decl() {
625 auto track = tracker();
626 auto tag = lex().tag();
627 auto prec = tag == Tag::K_cn || tag == Tag::K_con ? Prec::Bot : Prec::Pi;
628 bool external = (bool)accept(Tag::K_extern);
629
630 bool decl;
631 std::string entity;
632 // clang-format off
633 switch (tag) {
634 case Tag::T_lm: decl = false; entity = "function expression"; break;
635 case Tag::K_cn: decl = false; entity = "continuation expression"; break;
636 case Tag::K_fn: decl = false; entity = "returning continuation expression"; break;
637 case Tag::K_lam: decl = true ; entity = "function declaration"; break;
638 case Tag::K_con: decl = true ; entity = "continuation declaration"; break;
639 case Tag::K_fun: decl = true ; entity = "returning continuation declaration"; break;
640 default: fe::unreachable();
641 }
642 // clang-format on
643
644 auto dbg = decl ? parse_name(entity) : Dbg();
646 while (true) {
647 auto track = tracker();
648 bool implicit = (bool)accept(Tag::T_dot);
649 auto ptrn = parse_ptrn(Tag::D_paren_l, "domain pattern of a "s + entity, prec);
650 auto filter = accept(Tag::T_at) ? parse_expr("filter") : nullptr;
651
652 doms.emplace_back(ptr<LamDecl::Dom>(track, implicit, std::move(ptrn), std::move(filter)));
653 switch (ahead().tag()) {
654 case Tag::C_PTRN: continue;
655 default: break;
656 }
657 break;
658 }
659
660 auto codom = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Prec::Arrow) : nullptr;
661 if (tag == Tag::K_fn || tag == Tag::K_fun)
662 doms.back()->add_ret(ast(), codom ? std::move(codom) : ptr<InferExpr>(prev_));
663
664 expect(Tag::T_assign, "body of a "s + entity);
665 auto body = parse_expr("body of a "s + entity);
666 auto next = ahead().isa(Tag::K_and) ? parse_and_decl() : nullptr;
667
668 return ptr<LamDecl>(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body), std::move(next));
669}
670
671Ptr<RecDecl> Parser::parse_and_decl() {
672 switch (ahead(1).tag()) {
673 case Tag::C_LAM: return lex(), parse_lam_decl();
674 default: return parse_rec_decl(false);
675 }
676}
677
678} // namespace mim::ast
void load(Sym name)
Definition driver.cpp:53
Error & note(Loc loc, const char *fmt, Args &&... args) const
Definition ast.h:85
Error & error()
Definition ast.h:62
Error & warn(Loc loc, const char *fmt, Args &&... args) const
Definition ast.h:84
static Ptr< IdPtrn > mk_id(AST &ast, Dbg dbg, Ptr< Expr > &&type)
Definition ast.h:217
static Ptr< IdPtrn > mk_type(AST &ast, Ptr< Expr > &&type)
Definition ast.h:213
Ptr< Module > import(std::string_view sv)
Definition parser.h:39
AST & ast()
Definition parser.h:37
Driver & driver()
Definition parser.h:38
Ptr< Module > plugin(Dbg)
Definition parser.cpp:155
static Ptr< Ptrn > to_ptrn(Ptr< Expr > &&)
Definition ast.cpp:171
static Ptr< Expr > to_expr(AST &, Ptr< Ptrn > &&)
Definition ast.cpp:161
Dbg dbg() const
Definition tok.h:171
Definition ast.h:13
std::deque< Dbg > Dbgs
Definition ast.h:22
fe::Arena::Ptr< const T > Ptr
Definition ast.h:20
std::deque< Ptr< T > > Ptrs
Definition ast.h:21
void * get(void *handle, const char *symbol_name)
Definition dl.cpp:36