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 const File* import(std::string_view sv, Tok::Tag tag = Tok::Tag::K_import) {
40 return import({Loc(), driver().sym(sv)}, false, tag, nullptr);
41 }
42 /// @p is_path selects the `import "some/path.mim"` form over the search-path lookup by name.
43 /// @p record is `false` for the compilation root: it is not a directive that a dump should reproduce.
44 const File*
45 import(Dbg, bool is_path, Tok::Tag tag = Tok::Tag::K_import, std::ostream* md = nullptr, bool record = true);
46 const File* import(const fe::Src&, std::ostream* md = nullptr, Loc = {});
47 /// Imports the @p plugins the Driver was told about via `-p` as anonymous, unaliased UseDecl%s.
48 Ptrs<UseDecl> import_plugins(fe::View<std::string> plugins, Tok::Tag);
49 /// Slurps @p is, registers it in Driver::src under @p path, and parses it.
50 const File* import(std::istream& is, fs::path path, Loc = {}, std::ostream* md = nullptr);
51 const File* import_main(std::string_view input, fe::View<std::string> plugins, std::ostream* md = nullptr);
52
53private:
54 template<class T, class... Args>
55 auto ptr(Args&&... args) {
56 return ast_.ptr<const T>(std::forward<Args>(args)...);
57 }
58
59 /// Empty Loc right after the last consumed token - where a node sits that is *missing* rather than wrong.
60 Loc missing() const { return curr_.anew_end(); }
61 Lexer& lexer() { return *lexer_; }
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 template<class F>
78 void parse_list(fe::Cite ctxt, Tok::Tag delim_l, F f, Tok::Tag sep = Tok::Tag::T_comma) {
79 expect(delim_l, ctxt);
80 auto delim_r = Tok::delim_l2r(delim_l);
81 auto _ = this->anchor(delim_r);
82 do {
83 recover(ctxt);
84 if (ahead().isa(delim_r)) break;
85 f();
86 recover(ctxt);
87 } while (accept(sep));
88 expect(delim_r, "closing delimiter of a {}", ctxt);
89 }
90
91 /// Discard all closing delimiters that no enclosing context is waiting for.
92 void recover(fe::Cite ctxt) { Super::recover(Tok::is_delim_r, ctxt); }
93 ///@}
94
95 /// @name parse exprs
96 ///@{
97 Ptr<Expr> parse_expr(fe::Cite ctxt, Prec = Prec::Bot);
98
99 /// As above but builds @p ctxt via fe::format_cite.
100 template<class... Args>
101 Ptr<Expr> parse_expr(fe::cite_string<Args...> fmt, Args&&... args) {
102 return parse_expr(fe::format_cite(fmt, std::forward<Args>(args)...));
103 }
104
105 /// As above but with @p prec.
106 template<class... Args>
107 Ptr<Expr> parse_expr(Prec prec, fe::cite_string<Args...> fmt, Args&&... args) {
108 return parse_expr(fe::format_cite(fmt, std::forward<Args>(args)...), prec);
109 }
110 Ptr<Expr> parse_primary_expr(fe::Cite ctxt);
111 Ptr<Expr> parse_infix_expr(Tracker, Ptr<Expr> lhs, Prec = Prec::Bot, fe::Cite ctxt = {});
112
113 /// The `` `op `` a MIM_INFIX_SUGAR operator desugars to; `nullptr` for a MIM_INFIX_CORE one.
114 Ptr<Expr> sugar_callee(Tok op);
115 ///@}
116
117 /// @name parse primary exprs
118 ///@{
119 Ptr<Expr> parse_decl_expr();
120 Ptr<Expr> parse_lit_expr();
121 Ptr<Expr> parse_extremum_expr();
122 Ptr<Expr> parse_type_expr();
123 Ptr<Expr> parse_rule_expr();
124 Ptr<Expr> parse_ret_expr();
125 Ptr<Expr> parse_pi_expr();
126 Ptr<Expr> parse_pi_expr(Ptr<Ptrn>);
127 Ptr<Expr> parse_lam_expr();
128 Ptr<Expr> parse_seq_expr();
129 Ptr<Expr> parse_sigma_expr();
130 Ptr<Expr> parse_tuple_expr();
131 Ptr<Expr> parse_uniq_expr();
132 Ptr<Expr> parse_match_expr();
133 ///@}
134
135 /// @name parse ptrns
136 ///@{
137
138 /// A pattern `p` binds names for a body, whereas a telescope `b` (PtrnStyle::brckt) describes a type and names a
139 /// component only so that later components or the codomain may depend on it.
140 struct PtrnStyle {
141 bool brckt = false;
142 bool implicit = false; ///< Also accept `{p, ..., p}` / `{b, ..., b}`.
143 };
144
145 Ptr<Ptrn> parse_ptrn(PtrnStyle, fe::Cite ctxt, Prec = Prec::Bot);
146
147 /// As above but builds @p ctxt via fe::format_cite.
148 template<class... Args>
149 Ptr<Ptrn> parse_ptrn(PtrnStyle style, Prec prec, fe::cite_string<Args...> fmt, Args&&... args) {
150 return parse_ptrn(style, fe::format_cite(fmt, std::forward<Args>(args)...), prec);
151 }
152 Ptr<Ptrn> parse_ptrn_(PtrnStyle, fe::Cite ctxt, Prec = Prec::Bot);
153 Ptr<TuplePtrn> parse_tuple_ptrn(PtrnStyle);
154
155 /// The empty Sym - as opposed to `_` - is what lets Ptrn::to_expr turn this binder back into an expression.
156 Ptr<IdPtrn> anon_ptrn(Loc loc, Ptr<Expr> type) { return ptr<IdPtrn>(loc, Dbg(loc.anew_begin()), type); }
157 ///@}
158
159 /// @name parse decls
160 ///@{
161 /// If @p ctxt ...
162 /// * ... empty: **Only** decls are parsed. @returns `nullptr`
163 /// * ... **non**-empty: Decls are parsed, then an expression. @returns expression.
164 Ptrs<ValDecl> parse_decls();
165
166 /// Parses any combination of `priv`/`pub`/`extern`/`anx` modifier tokens, in any order.
167 /// Only rejects a modifier being repeated (`priv priv`, `extern extern`, ...);
168 /// whether a given combination makes sense for the decl that follows is up to that decl's own parser.
169 Mods parse_modifiers();
170 /// Errors if @p mods sets `extern`, for decl kinds that don't support it (`let`/bare `rec`):
171 /// currently only a function declaration (`lam`/`con`/`fun`, see Parser::parse_lam_decl) may be `extern`.
172 /// The default-`Vis` nudge itself lives in Mods::default_vis, resolved lazily by ValDecl::vis.
173 /// `mod` doesn't call this at all: as pure AST grouping it supports neither `extern` nor `anx`
174 /// (see Parser::parse_mod_decl).
175 void check_no_extern(const Mods&, fe::Cite entity);
176 void parse_axm_decl(Tracker, Mods, Ptrs<ValDecl>&);
177 /// Parses the `(tag_0 [= alias]*, ...): type[, normalizer[, curry[, trip]]]` tail shared by a bare
178 /// `axm (...)` group and the `axm tag.(...)` family-sugar; each Dbgs is one tag's `[primary, alias, ...]`.
179 Ptrs<ValDecl> parse_axm_group(Vis);
180 /// The `: type[, normalizer[, curry[, trip]]]` tail shared by a plain `axm` and Parser::parse_axm_group.
181 std::tuple<Ptr<Expr>, Dbg, Tok, Tok> parse_axm_tail();
182 Ptr<ValDecl> parse_alias_decl(Tracker, Mods);
183 Ptr<ValDecl> parse_let_decl(Tracker, Mods);
184 Ptr<ValDecl> parse_mod_decl(Tracker, Mods);
185 Ptr<ValDecl> parse_use_decl(Tracker, Mods);
186 Ptr<ValDecl> parse_rule_decl();
187 Ptr<LamDecl> parse_lam_decl(Tracker, Mods);
188 Ptr<RecDecl> parse_rec_decl(Tracker, bool first, Mods);
189 Ptr<RecDecl> parse_and_decl();
190 ///@}
191
192 AST& ast_;
193 Lexer* lexer_ = nullptr;
194
195 friend Super;
196};
197
198} // namespace mim::ast
Some "global" variables needed all over the place.
Definition driver.h:63
Owns the arena all AST nodes live in as well as the AnnexInfos of all plugins.
Definition ast.h:99
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:125
Driver & driver() const
Definition ast.h:109
The AST of one source file: an anonymous ModDecl that a UseDecl binds under a name of its own.
Definition ast.h:1204
const File * import_main(std::string_view input, fe::View< std::string > plugins, std::ostream *md=nullptr)
Definition parser.cpp:126
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:116
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:270
static constexpr Tok::Tag delim_l2r(Tag tag)
Definition tok.h:269
Definition ast.h:16
constexpr size_t Look_Ahead
Definition parser.h:10
Vis
Visibility tier of a ValDecl.
Definition ast.h:41
fe::Vector< Dbg > Dbgs
Definition ast.h:34
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:26
fe::Vector< Ptr< T > > Ptrs
Definition ast.h:33
Prec
Expression precedences used by the parser and the dumper; ordered low to high.
Definition tok.h:50