MimIR
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_Rule: /*RuleExpr*/ \
76 case Tag::K_ins: /*InsertExpr*/ \
77 case Tag::K_ret: /*RetExpr*/ \
78 case Tag::D_angle_l: /*PackExpr*/ \
79 case Tag::D_brckt_l: /*SigmaExpr*/ \
80 case Tag::D_curly_l: /*UniqExpr*/ \
81 case Tag::D_paren_l: /*TupleExpr*/ \
82 case Tag::D_quote_l /*ArrExpr*/
83
84#define C_CURRIED_B \
85 D_brace_l: \
86 case Tag::D_brckt_l: \
87 case Tag::D_quote_l
88
89#define C_CURRIED_P \
90 D_brace_l: \
91 case Tag::D_brckt_l: \
92 case Tag::D_paren_l
93// clang-format on
94
95using namespace std::string_literals;
96
97namespace mim::ast {
98
99using Tag = Tok::Tag;
100
101/*
102 * entry points
103 */
104
105Ptr<Module> Parser::parse_module() {
106 auto track = tracker();
107 Ptrs<Import> imports;
108 while (true) {
109 if (ahead().isa(Tag::K_import) || ahead().isa(Tag::K_plugin)) {
110 if (auto import = parse_import_or_plugin()) imports.emplace_back(std::move(import));
111 } else {
112 break;
113 }
114 }
115 auto decls = parse_decls();
116 bool where = ahead().isa(Tag::K_where);
117 expect(Tag::EoF, "module");
118 auto mod = ptr<Module>(track, std::move(imports), std::move(decls));
119 if (where) ast().note(mod->loc().anew_finis(), "did you accidentally end your declaration expression with a ';'?");
120 return mod;
121}
122
123Ptr<Module> Parser::import(Dbg dbg, std::ostream* md, Tok::Tag tag) {
124 auto name = dbg.sym();
125 if (tag == Tag::K_plugin && !driver().is_loaded(name) && !driver().flags().bootstrap) driver().load(name);
126
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, fresh] = driver().imports().add(std::move(rel_path), name, tag); fresh) {
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->string());
152 return {};
153 }
154
155 auto state = std::tuple(curr_, ahead_, lexer_);
156 auto lexer = Lexer(ast(), is, path, md);
157 lexer_ = &lexer;
158 init(path);
159 auto mod = parse_module();
160 std::tie(curr_, ahead_, lexer_) = state;
161 return mod;
162}
163
164Ptr<Module> Parser::import_main(std::string_view input, View<std::string> plugins, std::ostream* md) {
165 Ptrs<Import> imports;
166 for (const auto& name : plugins) {
167 auto dbg = Dbg(Loc(), driver().sym(name));
168 if (auto mod = import(dbg, nullptr, Tag::K_plugin))
169 imports.emplace_back(ast().ptr<Import>(Loc(), Tag::K_plugin, dbg, std::move(mod)));
170 }
171 auto mod = import({Loc(), driver().sym(input)}, md);
172 if (mod) mod->add_implicit_imports(std::move(imports));
173 return mod;
174}
175
176/*
177 * misc
178 */
179
180Ptr<Import> Parser::parse_import_or_plugin() {
181 auto track = tracker();
182 auto tag = lex().tag();
183 auto name = expect(Tag::M_id, "{} name", tag == Tag::K_import ? "import" : "plugin");
184 auto dbg = name.dbg();
185 expect(Tag::T_semicolon, "end of {}", tag == Tag::K_import ? "import" : "plugin");
186 if (auto module = import(dbg, nullptr, tag)) return ptr<Import>(track, tag, name.dbg(), std::move(module));
187 return {};
188}
189
190Dbg Parser::parse_id(std::string_view ctxt) {
191 if (auto id = accept(Tag::M_id)) return id.dbg();
192 syntax_err("identifier", ctxt);
193 return {curr_, driver().sym("<error>")};
194}
195
196Dbg Parser::parse_name(std::string_view ctxt) {
197 if (auto tok = accept(Tag::M_anx)) return tok.dbg();
198 if (auto tok = accept(Tag::M_id)) return tok.dbg();
199 syntax_err("identifier or annex name", ctxt);
200 return Dbg(curr_, ast().sym("<error>"));
201}
202
203Ptr<Expr> Parser::parse_type_ascr(std::string_view ctxt) {
204 if (accept(Tag::T_colon)) return parse_expr(ctxt);
205 if (ctxt.empty()) return nullptr;
206 syntax_err("':'", ctxt);
207 return ptr<ErrorExpr>(curr_);
208}
209
210/*
211 * exprs
212 */
213
214Ptr<Expr> Parser::parse_expr(std::string_view ctxt, Prec curr_prec) {
215 auto track = tracker();
216 auto lhs = parse_primary_expr(ctxt);
217 return parse_infix_expr(track, std::move(lhs), curr_prec);
218}
219
220Ptr<Expr> Parser::parse_infix_expr(Tracker track, Ptr<Expr>&& lhs, Prec curr_prec) {
221 while (true) {
222 // If operator in ahead has less left precedence: reduce (break).
223 switch (ahead().tag()) {
224 case Tag::T_extract: {
225 if (should_reduce(curr_prec, Prec::Extract)) return lhs;
226 lex();
227 if (auto tok = accept(Tag::M_id))
228 lhs = ptr<ExtractExpr>(track, std::move(lhs), tok.dbg());
229 else {
230 auto rhs = parse_expr("right-hand side of an extract", Prec::Extract);
231 lhs = ptr<ExtractExpr>(track, std::move(lhs), std::move(rhs));
232 }
233 continue;
234 }
235 case Tag::T_arrow: {
236 if (should_reduce(curr_prec, Prec::Arrow)) return lhs;
237 lex();
238 auto rhs = parse_expr("right-hand side of a function type", Prec::Arrow);
239 lhs = ptr<ArrowExpr>(track, std::move(lhs), std::move(rhs));
240 continue;
241 }
242 case Tag::T_union: {
243 if (should_reduce(curr_prec, Prec::Union)) return lhs;
244 lex();
245 Ptrs<Expr> types;
246 types.emplace_back(std::move(lhs));
247 do {
248 auto t = parse_expr("right-hand side of a union type", Prec::Union);
249 types.emplace_back(std::move(t));
250 } while (accept(Tag::T_union));
251 lhs = ptr<UnionExpr>(track, std::move(types));
252 continue;
253 }
254 case Tag::K_inj: {
255 if (should_reduce(curr_prec, Prec::Inj)) return lhs;
256 lex();
257 auto rhs = parse_expr("type a value is injected in", Prec::Inj);
258 lhs = ptr<InjExpr>(track, std::move(lhs), std::move(rhs));
259 continue;
260 }
261 case Tag::T_at: {
262 if (should_reduce(curr_prec, Prec::App)) return lhs;
263 lex();
264 auto rhs = parse_expr("explicit argument to an application", Prec::App);
265 lhs = ptr<AppExpr>(track, true, std::move(lhs), std::move(rhs));
266 continue;
267 }
268 case Tag::C_EXPR: {
269 if (should_reduce(curr_prec, Prec::App)) return lhs;
270 switch (ahead().tag()) {
271 case Tag::C_DECL:
272 ast().warn(ahead().loc(), "you are passing a declaration expression as argument");
273 ast().note(lhs->loc(), "to this expression");
274 ast().note(ahead().loc(),
275 "if this was your intention, consider to parenthesize the declaration expression");
276 ast().note(lhs->loc().anew_finis(), "otherwise, you are probably missing a ';'");
277 default: break;
278 }
279 auto rhs = parse_expr("argument to an application", Prec::App);
280 lhs = ptr<AppExpr>(track, false, std::move(lhs), std::move(rhs));
281 continue;
282 }
283 case Tag::K_where: {
284 if (should_reduce(curr_prec, Prec::Where)) return lhs;
285 lex();
286 auto decls = parse_decls();
287 lhs = ptr<DeclExpr>(track, std::move(decls), std::move(lhs), true);
288
289 bool where = ahead().tag() == Tag::K_where;
290 expect(Tag::K_end, "end of a where declaration block");
291 if (where)
292 ast().note(lhs->loc().anew_finis(),
293 "did you accidentally end your declaration expression with a ';'?");
294 return lhs;
295 }
296 default: return lhs;
297 }
298 }
299}
300
301Ptr<Expr> Parser::parse_insert_expr() {
302 eat(Tag::K_ins);
303 auto track = tracker();
304 expect(Tag::D_paren_l, "opening paren for insert arguments");
305 auto tuple = parse_expr("the tuple to insert into");
306 expect(Tag::T_comma, "comma after tuple to insert into");
307 auto index = parse_expr("insert index");
308 expect(Tag::T_comma, "comma after insert index");
309 auto value = parse_expr("insert value");
310 expect(Tag::D_paren_r, "closing paren for insert arguments");
311 return ptr<InsertExpr>(track, std::move(tuple), std::move(index), std::move(value));
312}
313
314Ptr<Expr> Parser::parse_uniq_expr() {
315 auto track = tracker();
316 expect(Tag::D_curly_l, "opening curly bracket for singleton type");
317 auto inhabitant = parse_expr("singleton type");
318 expect(Tag::D_curly_r, "closing curly bracket for singleton type");
319 return ptr<UniqExpr>(track, std::move(inhabitant));
320}
321
322Ptr<Expr> Parser::parse_match_expr() {
323 auto track = tracker();
324 expect(Tag::K_match, "opening match for union destruction");
325 auto scrutinee = parse_expr("destroyed union element");
326 expect(Tag::K_with, "match");
328 accept(Tag::T_pipe);
329 do {
330 auto track = tracker();
331 auto ptrn = parse_ptrn(Paren_Style, "right-hand side of a match-arm", Prec::Bot);
332 expect(Tag::T_fat_arrow, "arm of a match-expression");
333 auto body = parse_expr("arm of a match-expression");
334 arms.emplace_back(ptr<MatchExpr::Arm>(track, std::move(ptrn), std::move(body)));
335 } while (accept(Tag::T_pipe));
336
337 return ptr<MatchExpr>(track, std::move(scrutinee), std::move(arms));
338}
339
340Ptr<Expr> Parser::parse_primary_expr(std::string_view ctxt) {
341 // clang-format off
342 switch (ahead().tag()) {
343 case Tag::C_PRIMARY: return ptr<PrimaryExpr>(lex());
344 case Tag::C_ID: return ptr<IdExpr>(lex().dbg());
345 case Tag::C_LIT: return parse_lit_expr();
346 case Tag::C_DECL: return parse_decl_expr();
347 case Tag::C_PI: return parse_pi_expr();
348 case Tag::C_LM: return parse_lam_expr();
349 case Tag::K_ins: return parse_insert_expr();
350 case Tag::K_ret: return parse_ret_expr();
351 case Tag::D_curly_l: return parse_uniq_expr();
352 case Tag::D_quote_l:
353 case Tag::D_angle_l: return parse_seq_expr();
354 case Tag::D_brckt_l: return parse_sigma_expr();
355 case Tag::D_paren_l: return parse_tuple_expr();
356 case Tag::K_Type: return parse_type_expr();
357 case Tag::K_Rule: return parse_rule_expr();
358 case Tag::K_match: return parse_match_expr();
359 default:
360 if (ctxt.empty()) return nullptr;
361 syntax_err("primary expression", ctxt);
362 }
363 // clang-format on
364 return ptr<ErrorExpr>(curr_);
365}
366
367Ptr<Expr> Parser::parse_seq_expr() {
368 auto track = tracker();
369 bool is_pack = accept(Tag::D_angle_l) ? true : (eat(Tag::D_quote_l), false);
370
371 std::deque<std::pair<Ptr<IdPtrn>, Ptr<Expr>>> arities;
372
373 do {
374 Dbg dbg;
375 if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon)) {
376 dbg = eat(Tag::M_id).dbg();
377 eat(Tag::T_colon);
378 }
379
380 auto expr = parse_expr(is_pack ? "shape of pack" : "shape of a array");
381 auto ptrn = IdPtrn::make_id(ast(), dbg, std::move(expr));
382 arities.emplace_back(std::move(ptrn), std::move(expr));
383 } while (accept(Tag::T_comma));
384
385 expect(Tag::T_semicolon, is_pack ? "pack" : "array");
386 auto body = parse_expr(is_pack ? "body of a pack" : "body of an array");
387 expect(is_pack ? Tag::D_angle_r : Tag::D_quote_r,
388 is_pack ? "closing delimiter of a pack" : "closing delimiter of an array");
389
390 for (auto& [ptrn, expr] : arities | std::views::reverse)
391 body = ptr<SeqExpr>(track, is_pack, std::move(ptrn), std::move(body));
392
393 return body;
394}
395
396Ptr<Expr> Parser::parse_decl_expr() {
397 auto track = tracker();
398 auto decls = parse_decls();
399 auto expr = parse_expr("final expression of a declaration expression");
400 return ptr<DeclExpr>(track, std::move(decls), std::move(expr), false);
401}
402
403Ptr<Expr> Parser::parse_lit_expr() {
404 auto track = tracker();
405 auto tok = lex();
406 auto type = accept(Tag::T_colon) ? parse_expr("literal", Prec::Lit) : nullptr;
407 return ptr<LitExpr>(track, tok, std::move(type));
408}
409
410Ptr<Expr> Parser::parse_sigma_expr() {
411 auto track = tracker();
412 auto ptrn = parse_tuple_ptrn(Brckt_Style);
413 switch (ahead().tag()) {
414 case Tag::K_as: {
415 lex();
416 auto alias = ptr<AliasPtrn>(track, std::move(ptrn), parse_name("alias pattern"));
417 return parse_pi_expr(std::move(alias));
418 }
419 case Tag::C_CURRIED_B:
420 case Tag::T_arrow: return parse_pi_expr(std::move(ptrn)); // TODO precedences for patterns
421 default: return ptr<SigmaExpr>(std::move(ptrn));
422 }
423}
424
425Ptr<Expr> Parser::parse_tuple_expr() {
426 auto track = tracker();
427 Ptrs<Expr> elems;
428 parse_list("tuple", Tag::D_paren_l, [&]() { elems.emplace_back(parse_expr("tuple element")); });
429 return ptr<TupleExpr>(track, std::move(elems));
430}
431
432Ptr<Expr> Parser::parse_type_expr() {
433 auto track = tracker();
434 eat(Tag::K_Type);
435 auto level = parse_expr("type level", Prec::App);
436 return ptr<TypeExpr>(track, std::move(level));
437}
438
439Ptr<Expr> Parser::parse_rule_expr() {
440 auto track = tracker();
441 eat(Tag::K_Rule);
442 return ptr<RuleExpr>(track, parse_expr("domain of rule", Prec::App));
443}
444
445Ptr<Expr> Parser::parse_pi_expr() {
446 auto track = tracker();
447 auto tag = ahead().tag();
448 auto entity = "dependent function type"s;
449
450 if (accept(Tag::K_Cn))
451 entity = "continuation type";
452 else if (accept(Tag::K_Fn))
453 entity = "returning continuation type";
454
455 auto domt = tracker();
456 auto prec = tag == Tag::K_Cn ? Prec::Bot : Prec::Pi;
457 auto ptrn = parse_ptrn(Brckt_Style | Implicit, "domain of a "s + entity, prec);
458 auto dom = ptr<PiExpr::Dom>(domt, std::move(ptrn));
459
460 auto codom = tag != Tag::K_Cn ? (expect(Tag::T_arrow, entity), parse_expr("codomain of a "s + entity, Prec::Arrow))
461 : nullptr;
462
463 if (tag == Tag::K_Fn) dom->add_ret(ast(), codom ? std::move(codom) : ptr<HoleExpr>(curr_));
464 return ptr<PiExpr>(track, tag, std::move(dom), std::move(codom));
465}
466
467Ptr<Expr> Parser::parse_pi_expr(Ptr<Ptrn>&& ptrn) {
468 auto track = tracker(ptrn->loc());
469 auto entity = "dependent function type"s;
470 auto dom = ptr<PiExpr::Dom>(ptrn->loc(), std::move(ptrn));
471 expect(Tag::T_arrow, entity);
472 auto codom = parse_expr("codomain of a "s + entity, Prec::Arrow);
473 return ptr<PiExpr>(track, Tag::Nil, std::move(dom), std::move(codom));
474}
475
476Ptr<Expr> Parser::parse_lam_expr() { return ptr<LamExpr>(parse_lam_decl()); }
477
478Ptr<Expr> Parser::parse_ret_expr() {
479 auto track = tracker();
480 eat(Tag::K_ret);
481 auto ptrn = parse_ptrn(Paren_Style, "binding pattern of a ret expression");
482 expect(Tag::T_assign, "ret expression");
483 auto callee = parse_expr("continuation expression of a ret expression");
484 expect(Tag::T_dollar, "separator of a ret expression");
485 auto arg = parse_expr("argument of ret expression");
486 expect(Tag::T_semicolon, "ret expression");
487 auto body = parse_expr("body of a ret expression");
488 return ptr<RetExpr>(track, std::move(ptrn), std::move(callee), std::move(arg), std::move(body));
489}
490
491/*
492 * ptrns
493 */
494
495Ptr<Ptrn> Parser::parse_ptrn(int style, std::string_view ctxt, Prec prec) {
496 auto track = tracker();
497 auto ptrn = parse_ptrn_(style, ctxt, prec);
498 if (accept(Tag::K_as)) return ptr<AliasPtrn>(track, std::move(ptrn), parse_name("alias pattern"));
499 return ptrn;
500}
501
502Ptr<Ptrn> Parser::parse_ptrn_(int style, std::string_view ctxt, Prec prec) {
503 auto track = tracker();
504
505 // p -> (p, ..., p)
506 // p -> {b, ..., b} b -> {b, ..., b}
507 // p -> [b, ..., b] b -> [b, ..., b]
508 if (is_paren_style(style) && ahead().isa(Tag::D_paren_l)) return parse_tuple_ptrn(style);
509 if (is_implicit(style) && ahead().isa(Tag::D_brace_l)) return parse_tuple_ptrn(style);
510 if (ahead().isa(Tag::D_brckt_l)) return parse_tuple_ptrn(Brckt_Style);
511
512 if (ahead(0).isa(Tag::M_id)) {
513 if (ahead(1).isa(Tag::T_colon)) {
514 // p -> s: e b -> s: e
515 auto dbg = eat(Tag::M_id).dbg();
516 eat(Tag::T_colon);
517 auto type = parse_expr(ctxt, prec);
518 return ptr<IdPtrn>(track, dbg, std::move(type));
519 } else if (is_paren_style(style)) {
520 // p -> s
521 auto dbg = eat(Tag::M_id).dbg();
522 return ptr<IdPtrn>(track, dbg, nullptr);
523 } else {
524 // b -> e where e == id
525 auto type = parse_expr(ctxt, prec);
526 return ptr<IdPtrn>(track, type->loc().anew_begin(), std::move(type));
527 }
528 } else if (is_brket_style(style)) {
529 // b -> e where e != id
530 auto type = parse_expr(ctxt, prec);
531 auto loc = type->loc().anew_begin();
532 return ptr<IdPtrn>(track, Dbg(loc), std::move(type));
533 } else if (!ctxt.empty()) {
534 // p -> ↯
535 syntax_err("pattern", ctxt);
536 return ptr<ErrorPtrn>(curr_);
537 }
538
539 return nullptr;
540}
541
542Ptr<TuplePtrn> Parser::parse_tuple_ptrn(int style) {
543 auto track = tracker();
544 auto delim_l = ahead().tag();
545
546 Ptrs<Ptrn> ptrns;
547 parse_list("tuple pattern", delim_l, [&]() {
548 auto track = tracker();
549 Ptr<Ptrn> ptrn;
550
551 if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::M_id)) {
552 Dbgs dbgs;
553 while (auto tok = accept(Tag::M_id))
554 dbgs.emplace_back(tok.dbg());
555
556 if (accept(Tag::T_colon)) { // identifier group: x y x: T
557 auto dbg = dbgs.back();
558 auto type = parse_expr("type of an identifier group within a tuple pattern");
559 auto id = ptr<IdPtrn>(dbg.loc() + type->loc().finis, dbg, std::move(type));
560
561 for (auto dbg : dbgs | std::views::take(dbgs.size() - 1))
562 ptrns.emplace_back(ptr<GrpPtrn>(dbg, id.get()));
563 ptrns.emplace_back(std::move(id));
564 return;
565 }
566
567 // "x y z" is a curried app and maybe the prefix of a longer type expression
568 Ptr<Expr> lhs = ptr<IdExpr>(dbgs.front());
569 for (auto dbg : dbgs | std::views::drop(1)) {
570 auto rhs = ptr<IdExpr>(dbg);
571 lhs = ptr<AppExpr>(track, false, std::move(lhs), std::move(rhs));
572 }
573 auto expr = parse_infix_expr(track, std::move(lhs));
574 ptrn = IdPtrn::make_type(ast(), std::move(expr));
575 } else {
576 ptrn = parse_ptrn(style & Style_Bit, "element of a tuple pattern");
577
578 if (is_brket_style(style)) {
579 // [..., [Nat, Nat] -> Nat, ...] ==> [..., _: [Nat, Nat] -> Nat, ...]
580 if (ahead().isa(Tag::T_arrow)) {
581 auto loc = ptrn->loc();
582 auto expr = parse_pi_expr(std::move(ptrn));
583 ptrn = ptr<IdPtrn>(loc, Dbg(loc.anew_begin(), Sym()), std::move(expr));
584 } else if (auto expr = Ptrn::to_expr(ast(), std::move(ptrn))) {
585 // If we are able to parse more stuff, we got an expr instead of a binder
586 auto addr = expr.get();
587 expr = parse_infix_expr(track, std::move(expr));
588 if (expr.get() != addr) {
589 auto loc = expr->loc();
590 ptrn = ptr<IdPtrn>(loc, Dbg(loc.anew_begin(), Sym()), std::move(expr));
591 } else {
592 if (!ptrn) ptrn = Ptrn::to_ptrn(std::move(expr));
593 }
594 }
595 }
596 }
597
598 ptrns.emplace_back(std::move(ptrn));
599 });
600
601 return ptr<TuplePtrn>(track, delim_l, std::move(ptrns));
602}
603
604/*
605 * decls
606 */
607
608Ptrs<ValDecl> Parser::parse_decls() {
609 Ptrs<ValDecl> decls;
610 while (true) {
611 // clang-format off
612 switch (ahead().tag()) {
613 case Tag::T_semicolon: lex(); break; // eat up stray semicolons
614 case Tag::K_axm: decls.emplace_back(parse_axm_decl()); break;
615 case Tag::K_ccon:
616 case Tag::K_cfun: decls.emplace_back(parse_c_decl()); break;
617 case Tag::K_let: decls.emplace_back(parse_let_decl()); break;
618 case Tag::K_rec: decls.emplace_back(parse_rec_decl(true)); break;
619 case Tag::K_con:
620 case Tag::K_fun:
621 case Tag::K_lam: decls.emplace_back(parse_lam_decl()); break;
622 case Tag::K_norm:
623 case Tag::K_rule: decls.emplace_back(parse_rule_decl()); break;
624 default: return decls;
625 }
626 // clang-format on
627 }
628}
629
630Ptr<ValDecl> Parser::parse_axm_decl() {
631 auto track = tracker();
632 eat(Tag::K_axm);
633 Dbg dbg, normalizer;
634 Tok curry, trip;
635 // TODO if we check this later, we also have to report this error later
636 if (auto name = expect(Tag::M_anx, "annex name of an axm"))
637 dbg = name.dbg();
638 else {
639 accept(Tag::M_id);
640 dbg = Dbg(curr_, ast().sym("<error annex name>"));
641 }
642
643 std::deque<Ptrs<AxmDecl::Alias>> subs;
644 if (ahead().isa(Tag::D_paren_l)) {
645 parse_list("tag list of an axm", Tag::D_paren_l, [&]() {
646 auto& aliases = subs.emplace_back();
647 aliases.emplace_back(ptr<AxmDecl::Alias>(parse_id("tag of an axm")));
648 while (accept(Tag::T_assign))
649 aliases.emplace_back(ptr<AxmDecl::Alias>(parse_id("alias of an axm tag")));
650 });
651 }
652
653 auto type = parse_type_ascr("type ascription of an axm");
654
655 if (ahead(0).isa(Tag::T_comma) && ahead(1).isa(Tag::M_id)) {
656 lex();
657 normalizer = lex().dbg();
658 }
659 if (accept(Tag::T_comma)) {
660 if (auto c = expect(Tag::L_u, "curry counter for axm")) curry = c;
661 if (accept(Tag::T_comma)) {
662 if (auto t = expect(Tag::L_u, "trip count for axm")) trip = t;
663 }
664 }
665
666 return ptr<AxmDecl>(track, dbg, std::move(subs), std::move(type), normalizer, curry, trip);
667}
668
669Ptr<ValDecl> Parser::parse_let_decl() {
670 auto track = tracker();
671 eat(Tag::K_let);
672
673 Ptr<Ptrn> ptrn;
674 if (auto anx = accept(Tok::Tag::M_anx)) {
675 auto type = parse_type_ascr();
676 ptrn = ptr<IdPtrn>(track, anx.dbg(), std::move(type));
677 } else {
678 ptrn = parse_ptrn(Paren_Style, "binding pattern of a let declaration", Prec::Bot);
679 }
680
681 expect(Tag::T_assign, "let");
682 auto type = parse_type_ascr();
683 auto value = parse_expr("value of a let declaration");
684 return ptr<LetDecl>(track, std::move(ptrn), std::move(value));
685}
686
687Ptr<ValDecl> Parser::parse_c_decl() {
688 auto track = tracker();
689 auto tag = lex().tag();
690 auto id = expect(Tag::M_id, "C function declaration");
691 auto dom = parse_ptrn(Brckt_Style, "domain of a C function"s, Prec::App);
692 Ptr<Expr> codom;
693 if (tag == Tag::K_cfun) {
694 expect(Tag::T_colon, "codomain of a C function");
695 codom = parse_expr("codomain of a C function");
696 }
697 return ptr<CDecl>(track, tag, id.dbg(), std::move(dom), std::move(codom));
698}
699
700Ptr<RecDecl> Parser::parse_rec_decl(bool first) {
701 auto track = tracker();
702 eat(first ? Tag::K_rec : Tag::K_and);
703 auto dbg = parse_name("recursive declaration");
704 auto type = accept(Tag::T_colon) ? parse_expr("type of a recursive declaration") : ptr<HoleExpr>(curr_);
705 expect(Tag::T_assign, "recursive declaration");
706 auto body = parse_expr("body of a recursive declaration");
707 auto next = ahead().isa(Tag::K_and) ? parse_and_decl() : nullptr;
708 return ptr<RecDecl>(track, dbg, std::move(type), std::move(body), std::move(next));
709}
710
711Ptr<ValDecl> Parser::parse_rule_decl() {
712 auto track = tracker();
713 auto is_norm = lex().tag() == Tag::K_norm;
714 auto dbg = parse_name("rewrite rule");
715 auto ptrn = parse_ptrn(0, "meta variables in rewrite rule");
716 expect(Tag::T_colon, "rewrite rule declaration");
717 auto lhs = parse_expr("rewrite pattern");
718 auto guard = ahead().isa(Tag::K_when) ? (eat(Tag::K_when), parse_expr("rewrite guard"))
719 : ptr<PrimaryExpr>(track, std::move(Tag::K_tt));
720 expect(Tag::T_fat_arrow, "rewrite rule declaration");
721 auto rhs = parse_expr("rewrite result");
722 return ptr<RuleDecl>(track, dbg, std::move(ptrn), std::move(lhs), std::move(rhs), std::move(guard), is_norm);
723}
724
725Ptr<LamDecl> Parser::parse_lam_decl() {
726 auto track = tracker();
727 auto tag = lex().tag();
728 auto prec = tag == Tag::K_cn || tag == Tag::K_con ? Prec::Bot : Prec::Pi;
729 bool external = (bool)accept(Tag::K_extern);
730
731 bool decl;
732 std::string entity;
733 // clang-format off
734 switch (tag) {
735 case Tag::T_lm: decl = false; entity = "function expression"; break;
736 case Tag::K_cn: decl = false; entity = "continuation expression"; break;
737 case Tag::K_fn: decl = false; entity = "returning continuation expression"; break;
738 case Tag::K_lam: decl = true ; entity = "function declaration"; break;
739 case Tag::K_con: decl = true ; entity = "continuation declaration"; break;
740 case Tag::K_fun: decl = true ; entity = "returning continuation declaration"; break;
741 default: fe::unreachable();
742 }
743 // clang-format on
744
745 auto dbg = decl ? parse_name(entity) : Dbg();
747 while (true) {
748 auto track = tracker();
749 auto ptrn = parse_ptrn(Paren_Style | Implicit, "domain pattern of a "s + entity, prec);
750 auto filter = accept(Tag::T_at) ? parse_expr("filter") : nullptr;
751 doms.emplace_back(ptr<LamDecl::Dom>(track, std::move(ptrn), std::move(filter)));
752
753 switch (ahead().tag()) {
754 case Tag::C_CURRIED_P: continue;
755 default: break;
756 }
757 break;
758 }
759
760 auto codom = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Prec::Arrow) : nullptr;
761 if (tag == Tag::K_fn || tag == Tag::K_fun)
762 doms.back()->add_ret(ast(), codom ? std::move(codom) : ptr<HoleExpr>(curr_));
763
764 expect(Tag::T_assign, "body of a "s + entity);
765 auto body = parse_expr("body of a "s + entity);
766 auto next = ahead().isa(Tag::K_and) ? parse_and_decl() : nullptr;
767
768 return ptr<LamDecl>(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body), std::move(next));
769}
770
771Ptr<RecDecl> Parser::parse_and_decl() {
772 switch (ahead(1).tag()) {
773 case Tag::C_LAM: return lex(), parse_lam_decl();
774 default: return parse_rec_decl(false);
775 }
776}
777
778} // namespace mim::ast
void load(Sym name)
Definition driver.cpp:76
Error & warn(Loc loc, std::format_string< Args... > fmt, Args &&... args) const
Definition ast.h:92
Error & note(Loc loc, std::format_string< Args... > fmt, Args &&... args) const
Definition ast.h:93
Error & error()
Definition ast.h:69
static Ptr< IdPtrn > make_type(AST &ast, Ptr< Expr > &&type)
Definition ast.h:223
static Ptr< IdPtrn > make_id(AST &ast, Dbg dbg, Ptr< Expr > &&type)
Definition ast.h:227
Ptr< Module > import_main(std::string_view input, View< std::string > plugins, std::ostream *md=nullptr)
Definition parser.cpp:164
Ptr< Module > import(std::string_view sv, Tok::Tag tag=Tok::Tag::K_import)
Definition parser.h:39
AST & ast()
Definition parser.h:37
Driver & driver()
Definition parser.h:38
static Ptr< Ptrn > to_ptrn(Ptr< Expr > &&)
Definition ast.cpp:230
static Ptr< Expr > to_expr(AST &, Ptr< Ptrn > &&)
Definition ast.cpp:220
Definition ast.h:14
std::deque< Dbg > Dbgs
Definition ast.h:25
fe::Arena::Ptr< const T > Ptr
Definition ast.h:22
constexpr bool should_reduce(Prec curr, Prec op)
Should a Pratt parser reduce when the current binding power is curr and the infix operator has preced...
Definition tok.h:60
std::deque< Ptr< T > > Ptrs
Definition ast.h:24
Tok::Tag Tag
Definition bind.cpp:7
Prec
Expression precedences used by the parser and the dumper; ordered low to high.
Definition tok.h:38
Span< const T, N > View
Definition span.h:98
constexpr decltype(auto) get(Span< T, N > span) noexcept
Definition span.h:115