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