MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
parser.h
Go to the documentation of this file.
1#pragma once
2
3#include <fe/parser.h>
4
5#include "mim/ast/ast.h"
6#include "mim/ast/lexer.h"
7
8namespace mim::ast {
9
10constexpr size_t Look_Ahead = 2;
11
12/// Parses Mim code as AST.
13///
14/// The logic behind the various parse methods is as follows:
15/// 1. The `parse_*` method does **not** have a `fe::Cite ctxt` parameter:
16///
17/// It's the **caller's responsibility** to first make appropriate
18/// [FIRST/FOLLOW](https://www.cs.uaf.edu/~cs331/notes/FirstFollow.pdf) checks.
19/// Otherwise, an assertion will be triggered in the case of a syntax error.
20///
21/// 2. The `parse_*` method does have a `fe::Cite ctxt` parameter:
22///
23/// The **called method** checks this and spits out an appropriate error message using `ctxt` in the case of a
24/// syntax error.
25///
26/// 3. The `parse_*` method does have a `fe::Cite ctxt = {}` parameter **with default argument**:
27///
28/// * If default argument is **elided** we have the same behavior as in 1.
29/// * If default argument is **provided** we have the same behavior as in 2.
30class Parser : public fe::Parser<Tok, Tok::Tag, Look_Ahead, Parser> {
31 using Super = fe::Parser<Tok, Tok::Tag, Look_Ahead, Parser>;
32
33public:
35 : ast_(ast) {}
36
37 AST& ast() { return ast_; }
38 Driver& driver() { return ast().driver(); } ///< fe::Parser's default diagnostics go to its Driver::error.
39 Lexer& lexer() { return *lexer_; } ///< fe::Parser::lex pulls the next Tok%en from here.
40 const File* import(std::string_view sv, Tok::Tag tag = Tok::Tag::K_import) {
41 return import({Loc(), driver().sym(sv)}, false, tag, nullptr);
42 }
43 /// @p is_path selects the `import "some/path.mim"` form over the search-path lookup by name.
44 /// @p record is `false` for the compilation root: it is not a directive that a dump should reproduce.
45 const File*
46 import(Dbg, bool is_path, Tok::Tag tag = Tok::Tag::K_import, std::ostream* md = nullptr, bool record = true);
47 const File* import(const fe::Src&, std::ostream* md = nullptr, Loc = {});
48 /// Imports the @p plugins the Driver was told about via `-p` as anonymous, unaliased UseDecl%s.
49 Ptrs<UseDecl> import_plugins(fe::View<std::string> plugins, Tok::Tag);
50 /// Slurps @p is, registers it in Driver::src under @p path, and parses it.
51 const File* import(std::istream& is, fs::path path, Loc = {}, std::ostream* md = nullptr);
52 const File* import_main(std::string_view input, fe::View<std::string> plugins, std::ostream* md = nullptr);
53
54private:
55 template<class T, class... Args>
56 auto ptr(Args&&... args) {
57 return ast_.ptr<const T>(std::forward<Args>(args)...);
58 }
59
60 /// Empty Loc right after the last consumed token - where a node sits that is *missing* rather than wrong.
61 Loc missing() const { return curr_.anew_end(); }
62
63 /// @name parse misc
64 ///@{
65 Ptr<File> parse_file();
66 Dbg parse_id(fe::Cite ctxt = {});
67 Ptr<Path> parse_path(fe::Cite ctxt = {});
68 Ptr<UseDecl> parse_import_or_plugin(Tracker, Mods);
69 Ptr<Expr> parse_type_ascr(fe::Cite ctxt);
70
71 /// Directory of the file currently being parsed; empty if its Loc%s have no fe::Src.
72 fs::path curr_dir() const { return curr_.src ? curr_.src->path().parent_path() : fs::path(); }
73 /// A Path of a single component.
74 Ptr<Path> path(Dbg dbg) { return ptr<Path>(dbg.loc(), Dbgs{dbg}); }
75 Ptr<Expr> path_expr(Dbg dbg) { return ptr<PathExpr>(path(dbg)); }
76
77 void parse_list(fe::Cite ctxt, Tok::Tag delim_l, std::invocable auto f, Tok::Tag sep = Tok::Tag::T_comma) {
78 auto delim_r = Tok::delim_l2r(delim_l);
79 auto _ = anchor(expect(delim_l, ctxt), delim_r);
80 do {
81 recover(ctxt);
82 if (ahead().isa(delim_r)) break;
83 f();
84 recover(ctxt);
85 } while (accept(sep));
86 expect(delim_r, "closing delimiter of a {}", ctxt);
87 }
88
89 /// Discard all closing delimiters that no enclosing context is waiting for.
90 void recover(fe::Cite ctxt) { Super::recover(Tok::is_delim_r, ctxt); }
91 ///@}
92
93 /// @name parse exprs
94 ///@{
95 Ptr<Expr> parse_expr(fe::Cite ctxt, Prec = Prec::Bot);
96
97 /// As above but builds @p ctxt via fe::format_cite.
98 template<class... Args>
99 Ptr<Expr> parse_expr(fe::cite_string<Args...> fmt, Args&&... args) {
100 return parse_expr(fe::format_cite(fmt, std::forward<Args>(args)...));
101 }
102
103 /// As above but with @p prec.
104 template<class... Args>
105 Ptr<Expr> parse_expr(Prec prec, fe::cite_string<Args...> fmt, Args&&... args) {
106 return parse_expr(fe::format_cite(fmt, std::forward<Args>(args)...), prec);
107 }
108 Ptr<Expr> parse_primary_expr(fe::Cite ctxt);
109 Ptr<Expr> parse_prefix_expr();
110 Ptr<Expr> parse_infix_expr(Tracker, Ptr<Expr> lhs, Prec = Prec::Bot, fe::Cite ctxt = {});
111
112 /// The `` `op `` a MIM_INFIX_SUGAR operator desugars to; `nullptr` for a MIM_INFIX_CORE one.
113 Ptr<Expr> sugar_callee(Tok op);
114 ///@}
115
116 /// @name parse primary exprs
117 ///@{
118 Ptr<Expr> parse_decl_expr();
119 Ptr<Expr> parse_lit_expr();
120 Ptr<Expr> parse_type_expr();
121 Ptr<Expr> parse_rule_expr();
122 Ptr<Expr> parse_ret_expr();
123 Ptr<Expr> parse_pi_expr();
124 Ptr<Expr> parse_pi_expr(Ptr<Ptrn>);
125 Ptr<Expr> parse_lam_expr();
126 Ptr<Expr> parse_seq_or_single_expr();
127 Ptr<Expr> parse_sigma_expr();
128 Ptr<Expr> parse_tuple_expr();
129 Ptr<Expr> parse_match_expr();
130 Ptr<Expr> parse_variant_expr();
131 ///@}
132
133 /// @name parse ptrns
134 ///@{
135
136 /// A pattern `p` binds names for a body, whereas a telescope `b` (PtrnStyle::brckt) describes a type and names a
137 /// component only so that later components or the codomain may depend on it.
138 struct PtrnStyle {
139 bool brckt = false;
140 bool implicit = false; ///< Also accept `{p, ..., p}` / `{b, ..., b}`.
141 };
142
143 Ptr<Ptrn> parse_ptrn(PtrnStyle, fe::Cite ctxt, Prec = Prec::Bot);
144
145 /// As above but builds @p ctxt via fe::format_cite.
146 template<class... Args>
147 Ptr<Ptrn> parse_ptrn(PtrnStyle style, Prec prec, fe::cite_string<Args...> fmt, Args&&... args) {
148 return parse_ptrn(style, fe::format_cite(fmt, std::forward<Args>(args)...), prec);
149 }
150 Ptr<Ptrn> parse_ptrn_(PtrnStyle, fe::Cite ctxt, Prec = Prec::Bot);
151 Ptr<TuplePtrn> parse_tuple_ptrn(PtrnStyle);
152
153 /// The empty Sym - as opposed to `_` - is what lets Ptrn::to_expr turn this binder back into an expression.
154 Ptr<IdPtrn> anon_ptrn(Loc loc, Ptr<Expr> type) { return ptr<IdPtrn>(loc, Dbg(loc.anew_begin()), type); }
155 ///@}
156
157 /// @name parse decls
158 ///@{
159 Ptrs<ValDecl> parse_decls(Mods group = {});
160
161 /// Parses any combination of `priv`/`pub`/`extern`/`anx` modifier tokens, in any order.
162 /// Only rejects a modifier being repeated (`priv priv`, `extern extern`, ...);
163 /// whether a given combination makes sense for the decl that follows is up to that decl's own parser.
164 Mods parse_modifiers();
165 /// Errors if @p mods sets `extern`, for decl kinds that don't support it (`let`/bare `rec`):
166 /// currently only a function declaration (`lam`/`con`/`fun`, see Parser::parse_lam_decl) may be `extern`.
167 /// The default-`Vis` nudge itself lives in Mods::default_vis, resolved lazily by ValDecl::vis.
168 void check_no_extern(const Mods&, fe::Cite entity);
169 Ptr<ValDecl> parse_axm_decl(Tracker, Mods);
170 /// `(tag_0 [= alias]*, ...)` of an `axm` family.
171 Ptrs<AxmDecl::Name> parse_axm_names();
172 std::tuple<Ptr<Expr>, Dbg, Tok, Tok> parse_axm_tail();
173 Ptr<ValDecl> parse_alias_decl(Tracker, Mods);
174 Ptr<ValDecl> parse_let_decl(Tracker, Mods);
175 Ptr<ValDecl> parse_mod_decl(Tracker, Mods);
176 Ptr<RecDecl> parse_nom_decl(Tracker, Mods);
177 Ptr<ValDecl> parse_use_decl(Tracker, Mods);
178 Ptr<ValDecl> parse_rule_decl(Tracker, Mods);
179 Ptr<LamDecl> parse_lam_decl(Tracker, Mods);
180 Ptr<RecDecl> parse_rec_decl(Tracker, Mods);
181 Ptr<ValDecl> parse_mutual_decl(Tracker, Mods);
182 ///@}
183
184 AST& ast_;
185 Lexer* lexer_ = nullptr;
186
187 friend Super;
188};
189
190} // namespace mim::ast
Some "global" variables needed all over the place.
Definition driver.h:64
Owns the arena all AST nodes live in as well as the AnnexInfos of all plugins.
Definition ast.h:107
auto ptr(Args &&... args)
The VLA ranges of a fe::VLA node come last, in the order its VLA_Types declares them.
Definition ast.h:132
Driver & driver() const
Definition ast.h:117
The AST of one source file: an anonymous ModDecl that a UseDecl binds under a name of its own.
Definition ast.h:1355
const File * import_main(std::string_view input, fe::View< std::string > plugins, std::ostream *md=nullptr)
Definition parser.cpp:123
Lexer & lexer()
fe::Parser::lex pulls the next Token from here.
Definition parser.h:39
Parser(AST &ast)
Definition parser.h:34
Ptrs< UseDecl > import_plugins(fe::View< std::string > plugins, Tok::Tag)
Imports the plugins the Driver was told about via -p as anonymous, unaliased UseDecls.
Definition parser.cpp:112
AST & ast()
Definition parser.h:37
Driver & driver()
fe::Parser's default diagnostics go to its Driver::error.
Definition parser.h:38
static constexpr bool is_delim_r(Tag tag)
Definition tok.h:289
static constexpr Tok::Tag delim_l2r(Tag tag)
Definition tok.h:288
Definition ast.h:16
constexpr size_t Look_Ahead
Definition parser.h:10
fe::Vector< Dbg > Dbgs
Definition ast.h:35
fe::Arena::Ref< const T > Ptr
Nodes live in the AST's Arena and are never destroyed, so this merely points at one.
Definition ast.h:27
fe::Vector< Ptr< T > > Ptrs
Definition ast.h:34
Prec
Expression precedences used by the parser and the dumper; ordered low to high.
Definition tok.h:51