MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
tok.h
Go to the documentation of this file.
1#pragma once
2
3#include <optional>
4#include <string_view>
5#include <utility>
6
7#include <fe/assert.h>
8#include <fe/format.h>
9
10#include "mim/util/dbg.h"
11
12namespace mim {
13
14class Def;
15
16namespace ast {
17
18/// @name Precedence Table
19/// X-macro listing all expression precedences from lowest to highest as `m(name, assoc)`.
20/// @p assoc is `L`eft-, `R`ight-, or `N`on-associative; `a op b op c` is an error for an `N` level.
21/// Only a level named by MIM_PREFIX, MIM_INFIX, or by an entry below is an actual operator:
22/// `Err`, `Bot`, `Pi`, and `Lit` merely serve as a `curr_prec` bound while parsing.
23/// Application binds tighter than every operator - only `Extract` and `Lit` bind tighter still.
24///@{
25// clang-format off
26#define MIM_PREC(m) \
27 m(Err, N) \
28 m(Bot, N) \
29 m(Where, L) \
30 m(Ins, R) \
31 m(Inj, R) \
32 m(Union, L) \
33 m(Arrow, R) \
34 m(Pi, N) \
35 m(Eq, N) \
36 m(Rel, N) \
37 m(Add, L) \
38 m(Mul, L) \
39 m(Shift, L) \
40 m(Prefix, N) \
41 m(App, L) \
42 m(Extract, L) \
43 m(Lit, N)
44// clang-format on
45///@}
46
47/// Associativity of an infix expression.
48enum class Assoc { N, L, R };
49
50/// Expression precedences used by the parser and the dumper; ordered low to high.
51enum class Prec {
52#define CODE(name, ...) name,
54#undef CODE
55};
56
57/// Associativity of precedence level @p p.
58constexpr Assoc prec_assoc(Prec p) {
59 switch (p) {
60#define CODE(name, assoc) \
61 case Prec::name: return Assoc::assoc;
63#undef CODE
64 }
65 std::unreachable();
66}
67
68constexpr bool is_rassoc(Prec p) { return prec_assoc(p) == Assoc::R; }
69
70/// Should a Pratt parser reduce when the current binding power is @p curr
71/// and the infix operator has precedence @p op?
72constexpr bool should_reduce(Prec curr, Prec op) { return is_rassoc(op) ? curr > op : curr >= op; }
73
74// clang-format off
75#define MIM_KEY(m) \
76 m(K_Bool, "Bool" ) \
77 m(K_Cn, "Cn" ) \
78 m(K_Fn, "Fn" ) \
79 m(K_I1, "I1" ) \
80 m(K_I16, "I16" ) \
81 m(K_I32, "I32" ) \
82 m(K_I64, "I64" ) \
83 m(K_I8, "I8" ) \
84 m(K_Idx, "Idx" ) \
85 m(K_Nat, "Nat" ) \
86 m(K_Type, "Type" ) \
87 m(K_Level, "Level" ) \
88 m(K_anx, "anx" ) \
89 m(K_as, "as" ) \
90 m(K_axm, "axm" ) \
91 m(K_cn, "cn" ) \
92 m(K_con, "con" ) \
93 m(K_end, "end" ) \
94 m(K_extern, "extern") \
95 m(K_ff, "ff" ) \
96 m(K_fn, "fn" ) \
97 m(K_fun, "fun" ) \
98 m(K_i1, "i1" ) \
99 m(K_i16, "i16" ) \
100 m(K_i32, "i32" ) \
101 m(K_i64, "i64" ) \
102 m(K_i8, "i8" ) \
103 m(K_import, "import") \
104 m(K_inj, "inj" ) \
105 m(K_lam, "lam" ) \
106 m(K_let, "let" ) \
107 m(K_match, "match" ) \
108 m(K_mod, "mod" ) \
109 m(K_mutual, "mutual") \
110 m(K_nom, "nom" ) \
111 m(K_norm, "norm" ) \
112 m(K_plugin, "plugin") \
113 m(K_priv, "priv" ) \
114 m(K_pub, "pub" ) \
115 m(K_rec, "rec" ) \
116 m(K_ret, "ret" ) \
117 m(K_rule, "rule" ) \
118 m(K_Rule, "Rule" ) \
119 m(K_tt, "tt" ) \
120 m(K_use, "use" ) \
121 m(K_when, "when" ) \
122 m(K_where, "where" ) \
123 m(K_with, "with" ) \
124
125#define CODE(t, str) + size_t(1)
126constexpr auto Num_Keys = size_t(0) MIM_KEY(CODE);
127#undef CODE
128
129#define MIM_TOK(m) \
130 m(EoF, "<end of file>" ) \
131 /* literals */ \
132 m(L_s, "<signed integer literal>") \
133 m(L_u, "<integer literal>" ) \
134 m(L_i, "<index literal>" ) \
135 m(L_f, "<floating-point literal>") \
136 m(L_c, "<char literal>" ) \
137 m(L_str, "<string literal>" ) \
138 /* misc */ \
139 m(M_id, "<identifier>" ) \
140 /* delimiters */ \
141 m(D_angle_l, "‹") \
142 m(D_angle_r, "›") \
143 m(D_brace_l, "{") \
144 m(D_brace_r, "}") \
145 m(D_brckt_l, "[") \
146 m(D_brckt_r, "]") \
147 m(D_paren_l, "(") \
148 m(D_paren_r, ")") \
149 m(D_quote_l, "«") \
150 m(D_quote_r, "»") \
151 /* further tokens */ \
152 m(T_add, "+") \
153 m(T_arrow_r, "→") \
154 m(T_fat_arrow, "=>") \
155 m(T_assign, "=") \
156 m(T_at, "@") \
157 m(T_bot, "⊥") \
158 m(T_top, "⊤") \
159 m(T_box, "□") \
160 m(T_colon, ":") \
161 m(T_comma, ",") \
162 m(T_div, "/") \
163 m(T_dollar, "$") \
164 m(T_dot, ".") \
165 m(T_eq, "==") \
166 m(T_extract, "#") \
167 m(T_ge, ">=") \
168 m(T_gt, ">") \
169 m(T_arrow_l, "←") \
170 m(T_le, "<=") \
171 m(T_lm, "λ") \
172 m(T_lt, "<") \
173 m(T_ne, "!=") \
174 m(T_rem, "%") \
175 m(T_semicolon, ";") \
176 m(T_shl, "<<") \
177 m(T_shr, ">>") \
178 m(T_star, "*") \
179 m(T_sub, "-") \
180 m(T_union, "∪") \
181 m(T_pipe, "|") \
182
183/// @name Prefix Operator Table
184/// X-macro listing all prefix operators as `m(tag, str)`; they all live at Prec::Prefix.
185/// PrefixExpr::emit_ dispatches on the tag.
186///@{
187
188/// `#` is a prefix operator *and* an infix one; which one it is depends on the position it occurs in.
189#define MIM_PREFIX(m) \
190 m(T_extract, "#")
191///@}
192
193/// @name Infix Operator Table
194/// X-macros listing all infix operators as `m(tag, str, prec)`.
195///@{
196
197/// `a str b` is sugar for `` `str (a, b) ``; what `` `str `` means is up to whatever the user binds it to.
198#define MIM_INFIX_SUGAR(m) \
199 m(T_eq, "==", Eq ) \
200 m(T_ne, "!=", Eq ) \
201 m(T_lt, "<", Rel ) \
202 m(T_le, "<=", Rel ) \
203 m(T_gt, ">", Rel ) \
204 m(T_ge, ">=", Rel ) \
205 m(T_shl, "<<", Shift) \
206 m(T_shr, ">>", Shift) \
207 m(T_add, "+", Add ) \
208 m(T_sub, "-", Add ) \
209 m(T_star, "*", Mul ) \
210 m(T_div, "/", Mul ) \
211 m(T_rem, "%", Mul )
212
213/// These have a meaning of their own; InfixExpr::emit_ dispatches on the tag.
214#define MIM_INFIX_CORE(m) \
215 m(T_extract, "#", Extract) \
216 m(T_union, "∪", Union ) \
217 m(K_inj, "inj", Inj ) \
218 m(T_arrow_r, "→", Arrow ) \
219 m(T_arrow_l, "←", Ins ) \
220 m(T_at, "@", App )
221
222#define MIM_INFIX(m) MIM_INFIX_SUGAR(m) MIM_INFIX_CORE(m)
223///@}
224
225#define MIM_SUBST(m) \
226 m("lm", T_lm ) \
227 m("bot", T_bot ) \
228 m("top", T_top ) \
229
230#define CODE(str, t) + size_t(1)
231constexpr auto Num_Subst = size_t(0) MIM_SUBST(CODE);
232#undef CODE
233
234class Tok {
235public:
236 /// @name Tag
237 ///@{
238 enum class Tag {
239 Nil,
240#define CODE(t, str) t,
242#undef CODE
243 };
244
245 static const char* tag2str(Tok::Tag);
246 /// Is @p tag something the keyword table yields? MIM_KEY occupies `[1, Num_Keys]`; MIM_SUBST adds a few more.
247 static constexpr bool is_key(Tag tag) {
248 if (tag == Tag::Nil) return false;
249 if (size_t(tag) <= Num_Keys) return true;
250 switch (tag) {
251#define CODE(str, t) case Tag::t:
253#undef CODE
254 return true;
255 default: return false;
256 }
257 }
258 /// Is @p tag a prefix operator? @see MIM_PREFIX.
259 static constexpr bool is_prefix(Tag tag) {
260 switch (tag) {
261#define CODE(t, str) case Tag::t:
263#undef CODE
264 return true;
265 default: return false;
266 }
267 }
268 /// Precedence of the infix operator @p tag; `std::nullopt` if @p tag isn't one.
269 static constexpr std::optional<Prec> infix_prec(Tag tag) {
270 switch (tag) {
271#define CODE(t, str, prec) \
272 case Tag::t: return Prec::prec;
274#undef CODE
275 default: return {};
276 }
277 }
278 /// Name the infix operator @p tag desugars to - including the leading `` ` ``; empty for MIM_INFIX_CORE.
279 static constexpr std::string_view infix_sym(Tag tag) {
280 switch (tag) {
281#define CODE(t, str, prec) \
282 case Tag::t: return "`" str;
284#undef CODE
285 default: return {};
286 }
287 }
288 static constexpr Tok::Tag delim_l2r(Tag tag) { return Tok::Tag(int(tag) + 1); }
289 static constexpr bool is_delim_r(Tag tag) {
290 return Tag::D_angle_l <= tag && tag <= Tag::D_quote_r && (int(tag) - int(Tag::D_angle_l)) % 2 == 1;
291 }
292 ///@}
293
294 // clang-format on
295
296 Tok() {}
298 : loc_(loc)
299 , tag_(tag) {}
300 Tok(Loc loc, char8_t c)
301 : loc_(loc)
302 , tag_(Tag::L_c)
303 , c_(c) {}
304 Tok(Loc loc, uint64_t u)
305 : loc_(loc)
306 , tag_(Tag::L_u)
307 , u_(u) {}
308 Tok(Loc loc, int64_t s)
309 : loc_(loc)
310 , tag_(Tag::L_s)
311 , u_(std::bit_cast<uint64_t>(s)) {}
312 Tok(Loc loc, double d)
313 : loc_(loc)
314 , tag_(Tag::L_f)
315 , u_(std::bit_cast<uint64_t>(d)) {}
316 /// @p size and @p val of an Idx literal; World::lit_idx makes a Lit of it at emit time.
317 Tok(Loc loc, uint64_t size, uint64_t val)
318 : loc_(loc)
319 , tag_(Tag::L_i)
320 , idx_{size, val} {}
321 Tok(Loc loc, Tag tag, Sym sym)
322 : loc_(loc)
323 , tag_(tag)
324 , sym_(sym) {
325 assert(has_sym() || is_key(tag));
326 }
327
328 bool isa(Tag tag) const { return tag == tag_; }
329 Tag tag() const { return tag_; }
330 bool has_sym() const { return isa(Tag::M_id) || isa(Tag::L_str); }
331 /// @note A failed Parser::expect yields a Nil Tok; its Dbg is anonymous instead of asserting in Tok::sym.
332 Dbg dbg() const { return {loc(), has_sym() ? sym_ : Sym()}; }
333 Loc loc() const { return loc_; }
334 explicit operator bool() const { return tag_ != Tag::Nil; }
335 // clang-format off
336 std::pair<uint64_t, uint64_t> lit_i() const { assert(isa(Tag::L_i)); return {idx_.size, idx_.val}; }
337 char8_t lit_c() const { assert(isa(Tag::L_c)); return c_; }
338 uint64_t lit_u() const { assert(isa(Tag::L_u ) || isa(Tag::L_s ) || isa(Tag::L_f )); return u_; }
339 Sym sym() const { assert(has_sym()); return sym_; }
340 // clang-format on
341 std::string str() const;
342
343 friend std::ostream& operator<<(std::ostream&, Tok);
344 friend std::ostream& operator<<(std::ostream& os, Tok::Tag tag) { return os << tag2str(tag); }
345
346private:
347 Loc loc_;
348 Tag tag_ = Tag::Nil;
349 union {
350 Sym sym_ = {};
351 uint64_t u_;
352 char8_t c_;
353 struct {
354 uint64_t size, val;
355 } idx_;
356 };
357};
358
359} // namespace ast
360} // namespace mim
361
362#ifndef DOXYGEN // clang-format off
363template<> struct std::formatter<mim::ast::Tok > : fe::ostream_formatter {};
364template<> struct std::formatter<mim::ast::Tok::Tag> : fe::ostream_formatter {};
365#endif // clang-format on
Base class for all Defs.
Definition def.h:289
Tok(Loc loc, uint64_t u)
Definition tok.h:304
static constexpr bool is_delim_r(Tag tag)
Definition tok.h:289
bool has_sym() const
Definition tok.h:330
Sym sym() const
Definition tok.h:339
Tok(Loc loc, Tag tag)
Definition tok.h:297
Tok(Loc loc, Tag tag, Sym sym)
Definition tok.h:321
Tok(Loc loc, uint64_t size, uint64_t val)
size and val of an Idx literal; World::lit_idx makes a Lit of it at emit time.
Definition tok.h:317
static constexpr std::string_view infix_sym(Tag tag)
Name the infix operator tag desugars to - including the leading ` ; empty for MIM_INFIX_CORE.
Definition tok.h:279
std::pair< uint64_t, uint64_t > lit_i() const
Definition tok.h:336
Dbg dbg() const
Definition tok.h:332
Loc loc() const
Definition tok.h:333
uint64_t lit_u() const
Definition tok.h:338
static constexpr std::optional< Prec > infix_prec(Tag tag)
Precedence of the infix operator tag; std::nullopt if tag isn't one.
Definition tok.h:269
bool isa(Tag tag) const
Definition tok.h:328
static constexpr Tok::Tag delim_l2r(Tag tag)
Definition tok.h:288
Tok(Loc loc, int64_t s)
Definition tok.h:308
static constexpr bool is_prefix(Tag tag)
Is tag a prefix operator?
Definition tok.h:259
Tok(Loc loc, char8_t c)
Definition tok.h:300
friend std::ostream & operator<<(std::ostream &os, Tok::Tag tag)
Definition tok.h:344
static const char * tag2str(Tok::Tag)
Definition tok.cpp:10
static constexpr bool is_key(Tag tag)
Is tag something the keyword table yields? MIM_KEY occupies [1, Num_Keys]; MIM_SUBST adds a few more.
Definition tok.h:247
std::string str() const
Definition tok.cpp:22
Tok(Loc loc, double d)
Definition tok.h:312
Tag tag() const
Definition tok.h:329
char8_t lit_c() const
Definition tok.h:337
Definition ast.h:16
Assoc
Associativity of an infix expression.
Definition tok.h:48
constexpr bool is_rassoc(Prec p)
Definition tok.h:68
constexpr auto Num_Subst
Definition tok.h:231
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:72
constexpr auto Num_Keys
Definition tok.h:126
Tok::Tag Tag
Definition bind.cpp:11
std::ostream & operator<<(std::ostream &os, Tok tok)
Definition tok.cpp:30
constexpr Assoc prec_assoc(Prec p)
Associativity of precedence level p.
Definition tok.h:58
Prec
Expression precedences used by the parser and the dumper; ordered low to high.
Definition tok.h:51
Definition ast.h:16
#define MIM_PREC(m)
Definition tok.h:26
#define CODE(name,...)
Definition tok.h:52
#define MIM_SUBST(m)
Definition tok.h:225
#define MIM_TOK(m)
Definition tok.h:129
#define MIM_INFIX(m)
Definition tok.h:222
#define MIM_KEY(m)
Definition tok.h:75
#define MIM_INFIX_SUGAR(m)
a str b is sugar for `str (a, b) ; what `str means is up to whatever the user binds it to.
Definition tok.h:198
#define MIM_PREFIX(m)
# is a prefix operator and an infix one; which one it is depends on the position it occurs in.
Definition tok.h:189