MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
driver.h
Go to the documentation of this file.
1#pragma once
2
3#include <filesystem>
4#include <list>
5#include <string>
6#include <utility>
7
8#include <absl/container/flat_hash_map.h>
9#include <absl/container/node_hash_map.h>
10#include <fe/driver.h>
11#include <fe/log.h>
12#include <fe/profile.h>
13
14#include "mim/flags.h"
15#include "mim/plugin.h"
16#include "mim/world.h"
17
18#include "mim/ast/tok.h"
19
20namespace mim {
21
22namespace fs = std::filesystem;
23
24class Driver;
25
26/// The reserved words the ast::Lexer looks up, keyed by the Sym it has just interned.
27using Keys = fe::SymTab<ast::Tok::Tag, ast::Num_Keys + ast::Num_Subst>;
28
29/// Renders Def%s with their plain Def::sym instead of Def::unique_name while alive.
30/// A gid is noise in a diagnostic about the user's source - but it is also the only thing that tells two
31/// same-named Def%s apart, so PlainNames::clashed reports when a message has to be rendered again with gids.
32/// The state lives in Driver::names, so two Driver%s formatting at once never share it.
34public:
35 /// Activates plain naming on @p driver until this guard dies; a null @p driver leaves it off.
36 explicit PlainNames(const Driver* driver);
38
39 bool clashed() const;
40
41 /// Registers that @p gid renders as @p sym and reports whether the plain @p sym may be used.
42 /// Sets the clash flag - but still answers `true` - if another gid already claimed @p sym.
43 static bool claim(const Driver&, Sym sym, uint32_t gid);
44
45private:
46 const Driver* driver_;
47};
48
49/// Renders a diagnostic through PlainNames and - if that turned out ambiguous - once more with Def::unique_name.
50class Diag : public fe::CodeDiag {
51public:
52 explicit Diag(const Driver& driver)
53 : driver_(driver) {}
54
55 std::string render(const std::function<std::string()>&) const override;
56
57private:
58 const Driver& driver_;
59};
60
61/// Some "global" variables needed all over the place.
62/// Well, there are not really global - that's the point of this class.
63class Driver : public fe::Driver {
64public:
65 /// @name Construction
66 ///@{
67 Driver(std::string name = {});
68
69 Driver(const Driver&) = delete;
70 Driver(Driver&&) = delete;
72 ///@}
73
74 /// @name Getters
75 ///@{
76 Flags& flags() { return flags_; }
77 const Flags& flags() const { return flags_; }
78 fe::Log& log() { return log_; }
79 const fe::Log& log() const { return log_; }
80 fe::Profiler& profiler() { return profiler_; }
81 const fe::Profiler& profiler() const { return profiler_; }
82 World& world() { return world_; }
83 const Version& version() const { return version_; } ///< MimIR Version.
84 const Keys& keys() const { return keys_; } ///< Interned once here: every ast::Lexer borrows them.
85 ///@}
86
87 /// @name Diagnostic Naming
88 /// Scratch state for PlainNames: which plain Def::sym each gid claimed while one message is formatted.
89 /// It lives here - not in a global - so that concurrent Driver%s never share it.
90 ///@{
91 struct Names {
92 size_t depth = 0;
93 bool clashed = false;
94 absl::flat_hash_map<Sym, u32> sym2gid;
95 };
96
97 Names& names() const { return names_; }
98 ///@}
99
100 /// An ordered list of directories.
101 class Paths {
102 public:
103 void add(fs::path path) {
104 if (fs::exists(path) && fs::is_directory(path)) paths_.insert(insert_, std::move(path));
105 }
106
107 /// Later Paths::add calls insert in front of everything added so far.
108 void seal() { insert_ = paths_.begin(); }
109
110 auto begin() const { return paths_.cbegin(); }
111 auto end() const { return paths_.cend(); }
112
113 private:
114 std::list<fs::path> paths_;
115 std::list<fs::path>::iterator insert_ = paths_.end();
116 };
117
118 /// @name Manage Search Paths
119 /// A *plain directory* is probed as-is; a *prefix root* stands for an install tree and derives
120 /// `<root>/<libdir>/mim` (plugins), `<root>/<datadir>/mim` (imports), and `<root>/<libdir>/mim/rt` (runtimes).
121 /// Each lookup starts with the empty path, which probes the current working directory without an absolute path.
122 /// Within a list, paths added first are searched first; CLI paths precede the environment and derived ones.
123 ///@{
124 void add_plugin_path(fs::path path) { plugin_dirs_.add(std::move(path)); }
125 void add_import_path(fs::path path) { import_dirs_.add(std::move(path)); }
126 void add_prefix_path(fs::path path) { prefixes_.add(std::move(path)); }
127
128 /// Where Driver::load looks for `libmim_<name>`.
129 fe::Vector<fs::path> plugin_paths() const;
130 /// Where ast::Parser looks for `<name>.mim`; plugin directories are included, as a plugin ships both halves.
131 fe::Vector<fs::path> import_paths() const;
132 /// Where a backend looks for its runtime modules.
133 fe::Vector<fs::path> rt_paths() const;
134 ///@}
135
136 /// @name Manage Imports
137 /// Tracks the distinct import or plugin directives that World::dump should emit again later.
138 ///@{
139 class Imports {
140 public:
141 struct Entry {
142 const fe::Src* src;
143 Sym sym;
145 bool path; ///< The directive spelled a path (`import "a/b.mim"`) rather than a name.
146 };
147
148 /// @name Get imports
149 ///@{
150 const auto& entries() const { return entries_; }
151 ///@}
152
153 /// @name Iterators
154 ///@{
155 auto begin() const { return entries_.cbegin(); }
156 auto end() const { return entries_.cend(); }
157 ///@}
158
159 /// Remembers the directive that pulled in @p src; a repeated import of the same file adds nothing.
160 void add(const fe::Src* src, Sym, ast::Tok::Tag, bool path);
161
162 private:
163 std::deque<Entry> entries_;
164 };
165
166 const Imports& imports() const { return imports_; }
167 Imports& imports() { return imports_; }
168 ///@}
169
170 /// @name Load Plugin
171 /// Finds and loads a shared object file that implements the MimIR Plugin @p name.
172 /// If \a name is an absolute path to a `.so`/`.dll` file, this is used.
173 /// Otherwise, "name", "libmim_name.so" (Linux, Mac), "mim_name.dll" (Win)
174 /// are searched for in Driver::search_paths().
175 ///@{
176 void load(std::string_view name);
177 bool is_loaded(std::string_view name) const { return fe::lookup(plugins_, name); }
178 /// Directory `libmim_<name>` was loaded from, so that its `<name>.mim` half cannot come from elsewhere.
179 const fs::path* plugin_dir(std::string_view name) const { return fe::lookup(plugin2dir_, name); }
180 void* get_fun_ptr(std::string_view plugin, const char* name);
181
182 template<class F>
183 auto get_fun_ptr(std::string_view plugin, const char* name) {
184 return reinterpret_cast<F*>(get_fun_ptr(plugin, name));
185 }
186 ///@}
187
188 /// @name Manage Plugins
189 /// All these lookups yield `nullptr` if the key has not been found.
190 ///@{
191 auto phase(flags_t flags) { return fe::lookup(phases_, flags); }
192 const auto& phases() const { return phases_; }
193 auto normalizer(flags_t flags) const { return fe::lookup(normalizers_, flags); }
194 auto normalizer(plugin_t d, tag_t t, sub_t s) const { return normalizer(Annex::flags(d, t, s)); }
195 ///@}
196
197 /// @name Plugin/Phase Arguments
198 /// Freeform command-line arguments addressed to a plugin/phase (`-X <plugin>:<arg>`).
199 /// A Phase reads its own arguments via Phase::args().
200 ///@{
201 void add_arg(std::string_view plugin, std::string arg) { plugin_args_[plugin].emplace_back(std::move(arg)); }
202 /// Yields an empty fe::Vector if @p plugin has none.
203 const fe::Vector<std::string>& args(std::string_view plugin) const;
204
205 /// The PluginArg%s each loaded Plugin declares, in load order; only for listing them, see PluginArg.
206 const auto& known_args() const { return known_args_; }
207
208 /// The PluginEnv%s each loaded Plugin declares, in load order; only for listing them, see PluginEnv.
209 const auto& known_envs() const { return known_envs_; }
210 ///@}
211
212private:
213 // This must go *first* so plugins will be unloaded *last* in the d'tor; otherwise funny things might happen ...
214 absl::node_hash_map<std::string, Plugin::Handle> plugins_;
215 Version version_;
216 Flags flags_;
217 fe::Log log_;
218 mutable Names names_;
219 fe::Profiler profiler_;
220 World world_;
221 Paths plugin_dirs_, import_dirs_, prefixes_;
222 absl::flat_hash_map<std::string, fs::path> plugin2dir_;
223 Flags2Phases phases_;
224 Normalizers normalizers_;
225 absl::flat_hash_map<std::string, fe::Vector<std::string>> plugin_args_;
226 std::vector<std::pair<std::string, fe::View<PluginArg>>> known_args_;
227 std::vector<std::pair<std::string, fe::View<PluginEnv>>> known_envs_;
228 Imports imports_;
229 Keys keys_;
230};
231
232#define GET_FUN_PTR(plugin, f) get_fun_ptr<decltype(f)>(plugin, #f)
233
234} // namespace mim
Diag(const Driver &driver)
Definition driver.h:52
std::string render(const std::function< std::string()> &) const override
Definition driver.cpp:215
auto end() const
Definition driver.h:156
const fe::Src * src
Definition driver.h:142
auto begin() const
Definition driver.h:155
void add(const fe::Src *src, Sym, ast::Tok::Tag, bool path)
Remembers the directive that pulled in src; a repeated import of the same file adds nothing.
Definition driver.cpp:43
const auto & entries() const
Definition driver.h:150
bool path
The directive spelled a path (import "a/b.mim") rather than a name.
Definition driver.h:145
An ordered list of directories.
Definition driver.h:101
void add(fs::path path)
Definition driver.h:103
void seal()
Later Paths::add calls insert in front of everything added so far.
Definition driver.h:108
auto end() const
Definition driver.h:111
auto begin() const
Definition driver.h:110
Some "global" variables needed all over the place.
Definition driver.h:63
const auto & known_envs() const
The PluginEnvs each loaded Plugin declares, in load order; only for listing them, see PluginEnv.
Definition driver.h:209
void add_prefix_path(fs::path path)
Definition driver.h:126
const Imports & imports() const
Definition driver.h:166
auto get_fun_ptr(std::string_view plugin, const char *name)
Definition driver.h:183
Driver(std::string name={})
Definition driver.cpp:52
void add_import_path(fs::path path)
Definition driver.h:125
void load(std::string_view name)
Definition driver.cpp:126
const Version & version() const
MimIR Version.
Definition driver.h:83
const auto & known_args() const
The PluginArgs each loaded Plugin declares, in load order; only for listing them, see PluginArg.
Definition driver.h:206
auto normalizer(plugin_t d, tag_t t, sub_t s) const
Definition driver.h:194
World & world()
Definition driver.h:82
const Flags & flags() const
Definition driver.h:77
fe::Vector< fs::path > import_paths() const
Where ast::Parser looks for <name>.mim; plugin directories are included, as a plugin ships both halve...
Definition driver.cpp:102
bool is_loaded(std::string_view name) const
Definition driver.h:177
Driver & operator=(Driver)=delete
const fe::Profiler & profiler() const
Definition driver.h:81
const fs::path * plugin_dir(std::string_view name) const
Directory libmim_<name> was loaded from, so that its <name>.mim half cannot come from elsewhere.
Definition driver.h:179
Names & names() const
Definition driver.h:97
void add_arg(std::string_view plugin, std::string arg)
Definition driver.h:201
auto normalizer(flags_t flags) const
Definition driver.h:193
fe::Vector< fs::path > rt_paths() const
Where a backend looks for its runtime modules.
Definition driver.cpp:116
absl::flat_hash_map< Sym, u32 > sym2gid
Definition driver.h:94
Imports & imports()
Definition driver.h:167
Driver(const Driver &)=delete
Flags & flags()
Definition driver.h:76
const fe::Vector< std::string > & args(std::string_view plugin) const
Yields an empty fe::Vector if plugin has none.
Definition driver.cpp:185
void add_plugin_path(fs::path path)
Definition driver.h:124
fe::Vector< fs::path > plugin_paths() const
Where Driver::load looks for libmim_<name>.
Definition driver.cpp:92
void * get_fun_ptr(std::string_view plugin, const char *name)
Definition driver.cpp:180
fe::Profiler & profiler()
Definition driver.h:80
const auto & phases() const
Definition driver.h:192
const Keys & keys() const
Interned once here: every ast::Lexer borrows them.
Definition driver.h:84
fe::Log & log()
Definition driver.h:78
auto phase(flags_t flags)
Definition driver.h:191
const fe::Log & log() const
Definition driver.h:79
Driver(Driver &&)=delete
PlainNames(const Driver *driver)
Activates plain naming on driver until this guard dies; a null driver leaves it off.
Definition driver.cpp:191
bool clashed() const
Definition driver.cpp:206
static bool claim(const Driver &, Sym sym, uint32_t gid)
Registers that gid renders as sym and reports whether the plain sym may be used.
Definition driver.cpp:208
The World represents the whole program and manages creation of MimIR nodes (Defs).
Definition world.h:40
Definition ast.h:16
u8 sub_t
Definition types.h:42
u64 flags_t
Definition types.h:39
absl::flat_hash_map< flags_t, std::function< std::unique_ptr< Phase >(World &)> > Flags2Phases
Maps an axiom of a Phase to a function that creates one.
Definition plugin.h:30
absl::flat_hash_map< flags_t, NormalizeFn > Normalizers
Definition plugin.h:27
u64 plugin_t
Definition types.h:40
fe::SymTab< ast::Tok::Tag, ast::Num_Keys+ast::Num_Subst > Keys
The reserved words the ast::Lexer looks up, keyed by the Sym it has just interned.
Definition driver.h:27
u8 tag_t
Definition types.h:41
static constexpr flags_t flags(plugin_t p, tag_t t, sub_t s=0)
Assembles the full flags from its plugin, tag, and sub fields.
Definition plugin.h:240
Compiler switches that must be saved and looked up in later phases of compilation.
Definition flags.h:11