24std::optional<fs::path> prefix_of(
const fs::path& libmim_path) {
25 for (
auto dir = libmim_path.parent_path(); !dir.empty(); dir = dir.parent_path()) {
26 std::error_code ignore;
27 if (fs::is_directory(dir /
MIM_LIBDIR /
"mim", ignore) && !ignore)
return dir;
28 if (dir == dir.root_path())
break;
34std::optional<fs::path> path_to_libmim() {
return fe::sys::path_to_lib((
const void*)&
mim_lib_anchor); }
37void push(fe::Vector<fs::path>& paths, fs::path path) {
38 if (std::ranges::find(paths, path) == paths.end()) paths.emplace_back(std::move(path));
46 for (
const auto& entry : entries_)
47 if (entry.tag == tag && entry.src == src)
return;
49 entries_.emplace_back(
Entry{src, sym, tag, is_path});
55 , world_(this, sym(name)) {
56#define CODE(t, str) keys_.emplace(sym(str), ast::Tok::Tag::t);
61 if (ast::Tok::Tag::t != ast::Tok::Tag::Nil) keys_.emplace(sym(str), ast::Tok::Tag::t);
65 auto from_env = [](
const char* var,
auto&& add) {
66 if (
auto env = std::getenv(var)) {
67 auto stream = std::stringstream{env};
68 auto path = std::string{};
69 while (std::getline(stream, path, fe::sys::Path_Sep))
74 from_env(
"MIM_PLUGIN_PATH", [
this](fs::path path) {
add_plugin_path(std::move(path)); });
75 from_env(
"MIM_IMPORT_PATH", [
this](fs::path path) {
add_import_path(std::move(path)); });
76 from_env(
"MIM_PREFIX_PATH", [
this](fs::path path) {
add_prefix_path(std::move(path)); });
78 if (
auto path = path_to_libmim()) {
81 if (
auto prefix = prefix_of(*path))
add_prefix_path(*std::move(prefix));
93 auto res = fe::Vector<fs::path>();
95 for (
const auto& dir : plugin_dirs_)
97 for (
const auto& prefix : prefixes_)
103 auto res = fe::Vector<fs::path>();
105 for (
const auto& dir : import_dirs_)
107 for (
const auto& dir : plugin_dirs_)
109 for (
const auto& prefix : prefixes_) {
117 auto res = fe::Vector<fs::path>();
118 res.emplace_back(
"rt");
119 for (
const auto& dir : plugin_dirs_)
120 push(res, dir /
"rt");
121 for (
const auto& prefix : prefixes_)
122 push(res, prefix /
MIM_LIBDIR /
"mim" /
"rt");
127 log().i(
"💾 load plugin `{}`", name);
130 log().w(
"plugin `{}` already loaded", name);
135 auto dir = fs::path{};
136 if (
auto path = fs::path{name}; path.is_absolute() && fs::is_regular_file(path)) {
137 auto path_str = path.string();
138 if (handle.reset(fe::dl::open(path_str.c_str())); handle) dir = path.parent_path();
142 auto full_path = path / std::format(
"libmim_{}.{}", name, fe::dl::Ext);
143 std::error_code ignore;
144 if (
bool reg_file = fs::is_regular_file(full_path, ignore); reg_file && !ignore) {
145 auto path_str = full_path.string();
146 if (handle.reset(fe::dl::open(path_str.c_str())); handle) {
154 if (!handle) fe::throwf(
"cannot open plugin `{}`", name);
156 if (
auto get_info =
reinterpret_cast<decltype(&
mim_get_plugin)
>(fe::dl::get(handle.get(),
"mim_get_plugin"))) {
157 auto plugin = get_info();
158 if (
version() != plugin.version) {
159 std::ostringstream oss;
160 std::print(oss,
"plugin {} has version {} while MimIR has version {}", plugin.name, plugin.version,
162 if (
flags().force_load)
163 std::cerr <<
"warning: " << oss.str() <<
'\n';
165 throw std::logic_error(oss.str());
167 fe::assert_emplace(plugins_, std::string(name), std::move(handle));
168 plugin2dir_.emplace(std::string(name), std::move(dir));
170 if (
auto reg = plugin.register_normalizers) reg(normalizers_);
171 if (
auto reg = plugin.register_phases) reg(phases_);
173 if (plugin.args) known_args_.emplace_back(name, fe::View<PluginArg>(plugin.args, plugin.num_args));
174 if (plugin.envs) known_envs_.emplace_back(name, fe::View<PluginEnv>(plugin.envs, plugin.num_envs));
176 fe::throwf(
"plugin `{}` has no `mim_get_plugin()`", name);
181 if (
auto handle = fe::lookup(plugins_, plugin))
return fe::dl::get(handle->get(), name);
185const fe::Vector<std::string>&
Driver::args(std::string_view plugin)
const {
186 static const fe::Vector<std::string> empty;
187 if (
auto i = plugin_args_.find(plugin); i != plugin_args_.end())
return i->second;
193 if (!driver_)
return;
195 auto& names = driver_->names();
196 if (names.depth++ == 0) {
197 names.clashed = false;
198 names.sym2gid.clear();
203 if (driver_) --driver_->names().depth;
209 auto& names = driver.
names();
210 if (names.depth == 0)
return false;
211 if (
auto [i, ins] = names.sym2gid.emplace(sym, gid); !ins && i->second != gid) names.
clashed =
true;
215std::string
Diag::render(
const std::function<std::string()>& fmt)
const {
216 bool clashed =
false;
217 auto str = std::string();
220 str = CodeDiag::render(fmt);
221 clashed = plain.clashed();
223 return clashed ? CodeDiag::render(fmt) : str;
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 add_import_path(fs::path path)
void load(std::string_view name)
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.
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)
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.
#define MIM_INSTALL_PREFIX
mim::Plugin mim_get_plugin()
std::unique_ptr< void, void(*)(void *)> Handle