78 case Tag::D_angle_l: \
79 case Tag::D_brckt_l: \
80 case Tag::D_curly_l: \
81 case Tag::D_paren_l: \
86 case Tag::D_brckt_l: \
91 case Tag::D_brckt_l: \
95using namespace std::string_literals;
106 auto track = tracker();
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));
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 ';'?");
124 auto name = dbg.sym();
125 if (tag == Tag::K_plugin && !
driver().is_loaded(name) && !
driver().flags().bootstrap)
driver().
load(name);
127 auto filename = fs::path(name.view());
128 driver().VLOG(
"📥 import: {}", name);
130 if (!filename.has_extension()) filename.replace_extension(
"mim");
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;
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);
149 driver().VLOG(
"📄 reading: {}", path ? path->string() :
"<unknown file>"s);
151 ast().
error(loc,
"cannot read file {}", path->string());
155 auto state = std::tuple(curr_, ahead_, lexer_);
156 auto lexer =
Lexer(
ast(), is, path, md);
159 auto mod = parse_module();
160 std::tie(curr_, ahead_, lexer_) = state;
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)));
171 auto mod =
import({Loc(),
driver().sym(input)}, md);
172 if (mod) mod->add_implicit_imports(std::move(imports));
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));
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>")};
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>"));
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_);
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);
223 switch (ahead().tag()) {
224 case Tag::T_extract: {
227 if (
auto tok = accept(Tag::M_id))
228 lhs = ptr<ExtractExpr>(track, std::move(lhs), tok.dbg());
230 auto rhs = parse_expr(
"right-hand side of an extract", Prec::Extract);
231 lhs = ptr<ExtractExpr>(track, std::move(lhs), std::move(rhs));
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));
246 types.emplace_back(std::move(lhs));
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));
257 auto rhs = parse_expr(
"type a value is injected in", Prec::Inj);
258 lhs = ptr<InjExpr>(track, std::move(lhs), std::move(rhs));
264 auto rhs = parse_expr(
"explicit argument to an application", Prec::App);
265 lhs = ptr<AppExpr>(track,
true, std::move(lhs), std::move(rhs));
270 switch (ahead().tag()) {
272 ast().
warn(ahead().loc(),
"you are passing a declaration expression as argument");
273 ast().
note(lhs->loc(),
"to this expression");
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 ';'");
279 auto rhs = parse_expr(
"argument to an application", Prec::App);
280 lhs = ptr<AppExpr>(track,
false, std::move(lhs), std::move(rhs));
286 auto decls = parse_decls();
287 lhs = ptr<DeclExpr>(track, std::move(decls), std::move(lhs),
true);
289 bool where = ahead().tag() == Tag::K_where;
290 expect(Tag::K_end,
"end of a where declaration block");
292 ast().
note(lhs->loc().anew_finis(),
293 "did you accidentally end your declaration expression with a ';'?");
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));
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));
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");
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));
337 return ptr<MatchExpr>(track, std::move(scrutinee), std::move(arms));
340Ptr<Expr> Parser::parse_primary_expr(std::string_view ctxt) {
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();
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();
360 if (ctxt.empty())
return nullptr;
361 syntax_err(
"primary expression", ctxt);
364 return ptr<ErrorExpr>(curr_);
368 auto track = tracker();
369 bool is_pack = accept(Tag::D_angle_l) ? true : (eat(Tag::D_quote_l),
false);
371 std::deque<std::pair<Ptr<IdPtrn>,
Ptr<Expr>>> arities;
375 if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon)) {
376 dbg = eat(Tag::M_id).dbg();
380 auto expr = parse_expr(is_pack ?
"shape of pack" :
"shape of a array");
382 arities.emplace_back(std::move(ptrn), std::move(expr));
383 }
while (accept(Tag::T_comma));
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");
390 for (
auto& [ptrn, expr] : arities | std::views::reverse)
391 body = ptr<SeqExpr>(track, is_pack, std::move(ptrn), std::move(body));
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);
404 auto track = tracker();
406 auto type = accept(Tag::T_colon) ? parse_expr(
"literal", Prec::Lit) : nullptr;
407 return ptr<LitExpr>(track, tok, std::move(type));
411 auto track = tracker();
412 auto ptrn = parse_tuple_ptrn(Brckt_Style);
413 switch (ahead().tag()) {
416 auto alias = ptr<AliasPtrn>(track, std::move(ptrn), parse_name(
"alias pattern"));
417 return parse_pi_expr(std::move(alias));
419 case Tag::C_CURRIED_B:
420 case Tag::T_arrow:
return parse_pi_expr(std::move(ptrn));
421 default:
return ptr<SigmaExpr>(std::move(ptrn));
426 auto track = tracker();
428 parse_list(
"tuple", Tag::D_paren_l, [&]() { elems.emplace_back(parse_expr(
"tuple element")); });
429 return ptr<TupleExpr>(track, std::move(elems));
433 auto track = tracker();
435 auto level = parse_expr(
"type level", Prec::App);
436 return ptr<TypeExpr>(track, std::move(level));
440 auto track = tracker();
442 return ptr<RuleExpr>(track, parse_expr(
"domain of rule", Prec::App));
446 auto track = tracker();
447 auto tag = ahead().tag();
448 auto entity =
"dependent function type"s;
450 if (accept(Tag::K_Cn))
451 entity =
"continuation type";
452 else if (accept(Tag::K_Fn))
453 entity =
"returning continuation type";
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));
460 auto codom = tag != Tag::K_Cn ? (expect(Tag::T_arrow, entity), parse_expr(
"codomain of a "s + entity, Prec::Arrow))
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));
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));
476Ptr<Expr> Parser::parse_lam_expr() {
return ptr<LamExpr>(parse_lam_decl()); }
479 auto track = tracker();
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));
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"));
502Ptr<Ptrn> Parser::parse_ptrn_(
int style, std::string_view ctxt,
Prec prec) {
503 auto track = tracker();
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);
512 if (ahead(0).isa(Tag::M_id)) {
513 if (ahead(1).isa(Tag::T_colon)) {
515 auto dbg = eat(Tag::M_id).dbg();
517 auto type = parse_expr(ctxt, prec);
518 return ptr<IdPtrn>(track, dbg, std::move(type));
519 }
else if (is_paren_style(style)) {
521 auto dbg = eat(Tag::M_id).dbg();
522 return ptr<IdPtrn>(track, dbg,
nullptr);
525 auto type = parse_expr(ctxt, prec);
526 return ptr<IdPtrn>(track,
type->loc().anew_begin(), std::move(type));
528 }
else if (is_brket_style(style)) {
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()) {
535 syntax_err(
"pattern", ctxt);
536 return ptr<ErrorPtrn>(curr_);
543 auto track = tracker();
544 auto delim_l = ahead().tag();
547 parse_list(
"tuple pattern", delim_l, [&]() {
548 auto track = tracker();
551 if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::M_id)) {
553 while (
auto tok = accept(Tag::M_id))
554 dbgs.emplace_back(tok.dbg());
556 if (accept(Tag::T_colon)) {
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));
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));
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));
573 auto expr = parse_infix_expr(track, std::move(lhs));
576 ptrn = parse_ptrn(style & Style_Bit,
"element of a tuple pattern");
578 if (is_brket_style(style)) {
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));
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));
598 ptrns.emplace_back(std::move(ptrn));
601 return ptr<TuplePtrn>(track, delim_l, std::move(ptrns));
612 switch (ahead().tag()) {
613 case Tag::T_semicolon: lex();
break;
614 case Tag::K_axm: decls.emplace_back(parse_axm_decl());
break;
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;
621 case Tag::K_lam: decls.emplace_back(parse_lam_decl());
break;
623 case Tag::K_rule: decls.emplace_back(parse_rule_decl());
break;
624 default:
return decls;
631 auto track = tracker();
636 if (
auto name = expect(Tag::M_anx,
"annex name of an axm"))
640 dbg = Dbg(curr_,
ast().sym(
"<error annex name>"));
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")));
653 auto type = parse_type_ascr(
"type ascription of an axm");
655 if (ahead(0).isa(Tag::T_comma) && ahead(1).isa(Tag::M_id)) {
657 normalizer = lex().dbg();
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;
666 return ptr<AxmDecl>(track, dbg, std::move(subs), std::move(type), normalizer, curry, trip);
670 auto track = tracker();
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));
678 ptrn = parse_ptrn(Paren_Style,
"binding pattern of a let declaration", Prec::Bot);
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));
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);
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");
697 return ptr<CDecl>(track, tag,
id.dbg(), std::move(dom), std::move(codom));
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));
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);
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);
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();
745 auto dbg = decl ? parse_name(entity) : Dbg();
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)));
753 switch (ahead().tag()) {
754 case Tag::C_CURRIED_P:
continue;
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_));
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;
768 return ptr<LamDecl>(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body), std::move(next));
772 switch (ahead(1).tag()) {
773 case Tag::C_LAM:
return lex(), parse_lam_decl();
774 default:
return parse_rec_decl(
false);
Error & warn(Loc loc, std::format_string< Args... > fmt, Args &&... args) const
Error & note(Loc loc, std::format_string< Args... > fmt, Args &&... args) const
static Ptr< IdPtrn > make_type(AST &ast, Ptr< Expr > &&type)
static Ptr< IdPtrn > make_id(AST &ast, Dbg dbg, Ptr< Expr > &&type)
Ptr< Module > import_main(std::string_view input, View< std::string > plugins, std::ostream *md=nullptr)
Ptr< Module > import(std::string_view sv, Tok::Tag tag=Tok::Tag::K_import)
static Ptr< Ptrn > to_ptrn(Ptr< Expr > &&)
static Ptr< Expr > to_expr(AST &, Ptr< Ptrn > &&)
fe::Arena::Ptr< const T > Ptr
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...
std::deque< Ptr< T > > Ptrs
Prec
Expression precedences used by the parser and the dumper; ordered low to high.
constexpr decltype(auto) get(Span< T, N > span) noexcept