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