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