MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
lexer.h
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4
5#include <fe/lexer.h>
6
7#include "mim/driver.h"
8
9#include "mim/ast/tok.h"
10
11namespace mim::ast {
12
13class Lexer : public fe::Lexer<3, Lexer> {
14 using Super = fe::Lexer<3, Lexer>;
15
16public:
17 /// Creates a lexer to read `*.mim` files (see [Lexical Structure](@ref lex)).
18 /// If @p md is not `nullptr`, a Markdown output will be generated.
19 Lexer(Driver& driver, const fe::Src& src, std::ostream* md = nullptr)
20 : Lexer(driver, src.buf(), &src, md) {}
21 /// As above, but the Loc%ations of the Tok%s produced have no fe::Src to resolve against.
22 Lexer(Driver& driver, std::string_view buf, std::ostream* md = nullptr)
23 : Lexer(driver, buf, nullptr, md) {}
24
25 Driver& driver() { return driver_; } ///< fe::Lexer's default diagnostics go to its Driver::error.
26 Tok lex();
27
28 /// Does @p str match the `id` production - the same rule Lexer::lex_id applies to the input?
29 static bool is_id(std::string_view str);
30
31 /// Inverse of Lexer::lex_char: renders @p str as the body of a Mim string literal.
32 static std::string escape(std::string_view str);
33
34private:
35 Lexer(Driver&, std::string_view, const fe::Src*, std::ostream*);
36
37 Tok tok(Tok::Tag tag) { return {loc_, tag}; }
38 Sym sym() { return driver().sym(view()); }
39 bool lex_id();
40 char8_t lex_char();
41 Tok lex_str();
42 Tok lex_lit();
43 void lex_digits(int base = 10);
44 bool lex_exp(int base = 10);
45 void eat_comments();
46
47 /// Interns the string literal occupying `[begin, end)` of Lexer::buf_; @p esc resolves its escapes first.
48 Sym sym_str(uint32_t begin, uint32_t end, bool esc);
49 /// Resolves the escapes of @p body, which starts at byte @p begin of Lexer::buf_.
50 std::string unquote(std::string_view body, uint32_t begin);
51
52 /// @name Markdown
53 /// Whatever is consumed lands in Lexer::md_ verbatim, wrapped in a `mim` code fence.
54 /// A `///` line interrupts that fence and goes through as Markdown, its marker skipped.
55 ///@{
56 bool start_md() const { return ahead(0) == '/' && ahead(1) == '/' && ahead(2) == '/'; }
57 void emit_md(bool start_of_file = false);
58 size_t pos() const { return peek().begin.off; } ///< First byte not yet consumed.
59 void md_flush() {
60 if (md_) *md_ << buf_.substr(md_pos_, pos() - md_pos_);
61 md_pos_ = pos();
62 }
63 void md_skip() { md_pos_ = pos(); }
64 /// The language tag switches on Mim syntax highlighting in the generated documentation.
65 void md_open() {
66 if (md_) *md_ << "```mim\n";
67 fenced_ = md_ != nullptr;
68 }
69 void md_close() {
70 if (md_) *md_ << "```\n";
71 fenced_ = false;
72 }
73 ///@}
74
75 Driver& driver_;
76 std::ostream* md_;
77 size_t md_pos_ = 0;
78 bool fenced_ = false; ///< Is a code fence currently open?
79
80 friend class fe::Lexer<3, Lexer>;
81};
82
83} // namespace mim::ast
Some "global" variables needed all over the place.
Definition driver.h:63
Driver & driver()
fe::Lexer's default diagnostics go to its Driver::error.
Definition lexer.h:25
static bool is_id(std::string_view str)
Does str match the id production - the same rule Lexer::lex_id applies to the input?
Definition lexer.cpp:221
static std::string escape(std::string_view str)
Inverse of Lexer::lex_char: renders str as the body of a Mim string literal.
Definition lexer.cpp:199
Lexer(Driver &driver, const fe::Src &src, std::ostream *md=nullptr)
Creates a lexer to read *.mim files (see Lexical Structure).
Definition lexer.h:19
Lexer(Driver &driver, std::string_view buf, std::ostream *md=nullptr)
As above, but the Locations of the Toks produced have no fe::Src to resolve against.
Definition lexer.h:22
Definition ast.h:16