27std::optional<fs::path> prefix_of(
const fs::path& libmim_path) {
28 for (
auto dir = libmim_path.parent_path(); !dir.empty(); dir = dir.parent_path()) {
29 if (std::error_code ec; fs::is_directory(dir /
MIM_LIBDIR /
"mim", ec))
return dir;
30 if (dir == dir.root_path())
break;
36std::optional<fs::path> path_to_libmim() {
return fe::sys::path_to_lib((
const void*)&
mim_lib_anchor); }
39fe::StrMap<
Plugin (*)()>& static_plugins() {
40 static auto map = fe::StrMap<Plugin (*)()>();
45void push(fe::Vector<fs::path>& paths, fs::path path) {
46 if (std::ranges::find(paths, path) == paths.end()) paths.emplace_back(std::move(path));
54 for (
const auto& entry : entries_)
55 if (entry.tag == tag && entry.src == src)
return;
57 entries_.emplace_back(
Entry{src, sym, tag, is_path});
63 , world_(this, sym(name)) {
64#define CODE(t, str) keys_.emplace(sym(str), ast::Tok::Tag::t);
69 if (ast::Tok::Tag::t != ast::Tok::Tag::Nil) keys_.emplace(sym(str), ast::Tok::Tag::t);
73 auto from_env = [](
const char* var,
auto&& add) {
74 if (
auto env = std::getenv(var)) {
75 auto stream = std::stringstream{env};
76 auto path = std::string{};
77 while (std::getline(stream, path, fe::sys::Path_Sep))
82 from_env(
"MIM_PLUGIN_PATH", [
this](fs::path path) {
add_plugin_path(std::move(path)); });
83 from_env(
"MIM_IMPORT_PATH", [
this](fs::path path) {
add_import_path(std::move(path)); });
84 from_env(
"MIM_PREFIX_PATH", [
this](fs::path path) {
add_prefix_path(std::move(path)); });
86 if (
auto path = path_to_libmim()) {
89 if (
auto prefix = prefix_of(*path))
add_prefix_path(*std::move(prefix));
101 auto res = fe::Vector<fs::path>();
103 for (
const auto& dir : plugin_dirs_)
105 for (
const auto& prefix : prefixes_)
111 auto res = fe::Vector<fs::path>();
113 for (
const auto& dir : import_dirs_)
115 for (
const auto& dir : plugin_dirs_)
117 for (
const auto& prefix : prefixes_) {
125 auto res = fe::Vector<fs::path>();
126 res.emplace_back(
"rt");
127 for (
const auto& dir : plugin_dirs_)
128 push(res, dir /
"rt");
129 for (
const auto& prefix : prefixes_)
130 push(res, prefix /
MIM_LIBDIR /
"mim" /
"rt");
135 constexpr auto prefix = std::string_view(
"libmim_");
136 auto stem = fs::path(name).stem().string();
137 if (stem.starts_with(prefix)) stem.erase(0, prefix.size());
143 swap(
world, *library_);
144 for (
auto mut : library_->externals().muts())
152 log().i(
"💾 load plugin `{}`", spec);
155 log().w(
"plugin `{}` already loaded", name);
160 auto dir = fs::path{};
161 auto path = fs::path{spec};
162 auto sub = path.parent_path();
166 auto find = [&,
this](
const std::string& file,
auto&& accept) {
168 if (std::error_code ec; fs::is_regular_file(search / sub / file, ec) && accept(search / sub / file))
173 if (
auto get = fe::lookup(static_plugins(), name)) {
176 dir = find(std::format(
"{}.mim", name), [](
const fs::path&) {
return true; });
178 auto ext = std::format(
".{}", fe::dl::Ext);
179 auto open = [&handle](
const fs::path& p) {
180 auto str = p.string();
181 return handle.reset(fe::dl::open(str.c_str())), bool(handle);
185 if (path.is_absolute() && path.extension() == ext && fs::is_regular_file(path) && open(path))
186 dir = path.parent_path();
187 if (!handle) dir = find(std::format(
"libmim_{}{}", name, ext), open);
189 if (!handle) error().e(loc,
"cannot open plugin `{}`", spec).bail();
190 get_info =
reinterpret_cast<decltype(&
mim_get_plugin)
>(fe::dl::get(handle.get(),
"mim_get_plugin"));
193 auto plugin = get_info();
194 if (
version() != plugin.version) {
195 if (!
flags().force_load)
197 .e(loc,
"plugin `{}` has version {} while MimIR has version {}", plugin.name, plugin.version,
version())
198 .n(
"use `--force-load` to load it anyway")
200 std::println(std::cerr,
"warning: plugin {} has version {} while MimIR has version {}", plugin.name,
203 fe::assert_emplace(plugins_, name,
204 Loaded{std::move(handle), std::move(dir), fe::View<PluginSym>(plugin.syms, plugin.num_syms)});
206 if (
auto reg = plugin.register_normalizers) reg(normalizers_);
207 if (
auto reg = plugin.register_phases) reg(phases_);
209 if (plugin.args) known_args_.emplace_back(name, fe::View<PluginArg>(plugin.args, plugin.num_args));
210 if (plugin.envs) known_envs_.emplace_back(name, fe::View<PluginEnv>(plugin.envs, plugin.num_envs));
214 auto loaded = fe::lookup(plugins_, plugin);
215 if (!loaded)
return nullptr;
216 for (
const auto& sym : loaded->syms)
217 if (std::strcmp(sym.name, name) == 0)
return sym.ptr;
218 return loaded->handle ? fe::dl::get(loaded->handle.get(), name) :
nullptr;
221const fe::Vector<std::string>&
Driver::args(std::string_view plugin)
const {
222 static const fe::Vector<std::string> empty;
223 if (
auto args = fe::lookup(plugin_args_, plugin))
return *
args;
231 auto end = val->data() + val->size();
232 if (
auto [ptr, ec] = std::from_chars(val->data(), end, n); ec != std::errc() || ptr != end) {
233 log().w(
"ignoring `-X {}:{}={}`: not a number", plugin, key, *val);
241 if (!driver_)
return;
243 auto& names = driver_->names();
244 if (names.depth++ == 0) {
245 names.clashed = false;
246 names.sym2gid.clear();
251 if (driver_) --driver_->names().depth;
257 auto& names = driver.
names();
258 if (names.depth == 0)
return false;
259 if (
auto [i, ins] = names.sym2gid.emplace(sym, gid); !ins && i->second != gid) names.
clashed =
true;
263std::string
Diag::render(
const std::function<std::string()>& fmt)
const {
264 bool clashed =
false;
265 auto str = std::string();
268 str = CodeDiag::render(fmt);
269 clashed = plain.clashed();
271 return clashed ? CodeDiag::render(fmt) : str;
T * as_mut() const
Asserts that this is a mutable, casts constness away and performs a static_cast to T.
Renders a diagnostic through PlainNames and - if that turned out ambiguous - once more with Def::uniq...
std::string render(const std::function< std::string()> &) const override
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.
Some "global" variables needed all over the place.
void add_prefix_path(fs::path path)
Driver(std::string name={})
void load(std::string_view name, Loc loc={})
static std::string plugin_name(std::string_view name)
Bare plugin name of a possibly path-qualified name: foo/libmim_bar.so → bar.
void add_import_path(fs::path path)
const Version & version() const
MimIR Version.
fe::Vector< fs::path > import_paths() const
Where ast::Parser looks for <name>.mim; plugin directories are included, as a plugin ships both halve...
bool is_loaded(std::string_view name) const
fe::Vector< fs::path > rt_paths() const
Where a backend looks for its runtime modules.
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....
void move_to_library(World &world)
Moves everything of world into library() and imports only its externals back.
const fe::Vector< std::string > & args(std::string_view plugin) const
Yields an empty fe::Vector if plugin has none.
void add_plugin_path(fs::path path)
fe::Vector< fs::path > plugin_paths() const
Where Driver::load looks for libmim_<name>.
void * get_fun_ptr(std::string_view plugin, const char *name)
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.
PlainNames(const Driver *driver)
Activates plain naming on driver until this guard dies; a null driver leaves it off.
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.
The World represents the whole program and manages creation of MimIR nodes (Defs).
std::unique_ptr< World > inherit()
Inherits the State into the new World.
const Def * import(const Def *def)
Imports def of Driver::library into this World.
#define MIM_INSTALL_PREFIX
mim::Plugin mim_get_plugin()
std::optional< std::string_view > arg_value(fe::View< std::string > args, Keys... keys)
Basic info and registration function pointer to be returned from a specific plugin.
std::unique_ptr< void, void(*)(void *)> Handle