21int main(
int argc,
char** argv) {
22 enum Backends { AST, Dot, H, LL, Md, Mim,
Nest, Num_Backends };
25 static const auto version =
"mim command-line utility version " MIM_VER "\n";
28 bool show_help =
false;
29 bool show_version =
false;
30 bool list_search_paths =
false;
31 bool dot_follow_types =
false;
32 bool dot_all_annexes =
false;
33 std::string input, prefix;
35 std::vector<std::string> plugins, search_paths;
36#ifdef MIM_ENABLE_CHECKS
37 std::vector<uint32_t> breakpoints;
38 std::vector<uint32_t> watchpoints;
40 std::array<std::string, Num_Backends> output;
43 auto inc_verbose = [&](
bool) { ++verbose; };
44 auto& flags = driver.
flags();
47 auto cli = lyra::cli()
48 | lyra::help(show_help)
49 | lyra::opt(show_version )[
"-v"][
"--version" ](
"Display version info and exit.")
50 | lyra::opt(list_search_paths )[
"-l"][
"--list-search-paths" ](
"List search paths in order and exit.")
51 | lyra::opt(clang,
"clang" )[
"-c"][
"--clang" ](
"Path to clang executable (default: '" MIM_WHICH " clang').")
52 | lyra::opt(plugins,
"plugin" )[
"-p"][
"--plugin" ](
"Dynamically load plugin.")
53 | lyra::opt(search_paths,
"path" )[
"-P"][
"--plugin-path" ](
"Path to search for plugins.")
54 | lyra::opt(inc_verbose )[
"-V"][
"--verbose" ](
"Verbose mode. Multiple -V options increase the verbosity. The maximum is 4.").cardinality(0, 4)
55 | lyra::opt(opt,
"level" )[
"-O"][
"--optimize" ](
"Optimization level (default: 2).")
56 | lyra::opt(output[AST],
"file" ) [
"--output-ast" ](
"Directly emits AST represntation of input.")
57 | lyra::opt(output[Dot],
"file" ) [
"--output-dot" ](
"Emits the Mim program as a MimIR graph using Graphviz' DOT language.")
58 | lyra::opt(output[H ],
"file" ) [
"--output-h" ](
"Emits a header file to be used to interface with a plugin in C++.")
59 | lyra::opt(output[LL ],
"file" ) [
"--output-ll" ](
"Compiles the Mim program to LLVM.")
60 | lyra::opt(output[Md ],
"file" ) [
"--output-md" ](
"Emits the input formatted as Markdown.")
61 | lyra::opt(output[Mim],
"file" )[
"-o"][
"--output-mim" ](
"Emits the Mim program again.")
62 | lyra::opt(output[
Nest],
"file" ) [
"--output-nest" ](
"Emits program nesting tree as Dot.")
63 | lyra::opt(flags.ascii )[
"-a"][
"--ascii" ](
"Use ASCII alternatives in output instead of UTF-8.")
64 | lyra::opt(flags.bootstrap ) [
"--bootstrap" ](
"Puts mim into \"bootstrap mode\". This means a 'plugin' directive has the same effect as an 'import' and will not load a library. In addition, no standard plugins will be loaded.")
65 | lyra::opt(dot_follow_types ) [
"--dot-follow-types" ](
"Follow type dependencies in DOT output.")
66 | lyra::opt(dot_all_annexes ) [
"--dot-all-annexes" ](
"Output all annexes - even if unused - in DOT output.")
67 | lyra::opt(flags.dump_gid,
"level" ) [
"--dump-gid" ](
"Dumps gid of inline expressions as a comment in output if <level> > 0. Use a <level> of 2 to also emit the gid of trivial defs.")
68 | lyra::opt(flags.dump_recursive ) [
"--dump-recursive" ](
"Dumps Mim program with a simple recursive algorithm that is not readable again from Mim but is less fragile and also works for broken Mim programs.")
69 | lyra::opt(flags.aggressive_lam_spec ) [
"--aggr-lam-spec" ](
"Overrides LamSpec behavior to follow recursive calls.")
70 | lyra::opt(flags.scalarize_threshold,
"threshold") [
"--scalarize-threshold" ](
"MimIR will not scalarize tuples/packs/sigmas/arrays with a number of elements greater than or equal this threshold.")
72 | lyra::opt(breakpoints,
"gid" )[
"-b"][
"--break" ](
"*Triggers breakpoint when creating a node whose global id is <gid>.")
73 | lyra::opt(watchpoints,
"gid" )[
"-w"][
"--watch" ](
"*Triggers breakpoint when setting a node whose global id is <gid>.")
74 | lyra::opt(flags.reeval_breakpoints ) [
"--reeval-breakpoints" ](
"*Triggers breakpoint even upon unfying a node that has already been built.")
75 | lyra::opt(flags.break_on_alpha ) [
"--break-on-alpha" ](
"*Triggers breakpoint as soon as two expressions turn out to be not alpha-equivalent.")
76 | lyra::opt(flags.break_on_error ) [
"--break-on-error" ](
"*Triggers breakpoint on ELOG.")
77 | lyra::opt(flags.break_on_warn ) [
"--break-on-warn" ](
"*Triggers breakpoint on WLOG.")
78 | lyra::opt(flags.trace_gids ) [
"--trace-gids" ](
"*Output gids during World::unify/insert.")
80 | lyra::arg(input,
"file" ) (
"Input file.")
84 if (
auto result = cli.parse({argc, argv}); !result)
throw std::invalid_argument(result.message());
87 std::cout << cli << std::endl;
88#ifdef MIM_ENABLE_CHECKS
89 std::cout <<
"*These are developer options only enabled, if 'MIM_ENABLE_CHECKS' is ON." << std::endl;
91 std::cout <<
"Use \"-\" as <file> to output to stdout." << std::endl;
97 std::exit(EXIT_SUCCESS);
102 if (list_search_paths) {
103 for (
auto&& path : driver.
search_paths() | std::views::drop(1))
104 std::cout << path << std::endl;
105 std::exit(EXIT_SUCCESS);
109#ifdef MIM_ENABLE_CHECKS
110 for (
auto b : breakpoints) world.
breakpoint(b);
111 for (
auto w : watchpoints) world.
watchpoint(w);
116 std::array<std::ofstream, Num_Backends> ofs;
117 std::array<std::ostream*, Num_Backends> os;
119 for (
size_t be = 0; be != Num_Backends; ++be) {
120 if (output[be].empty())
continue;
121 if (output[be] ==
"-") {
124 ofs[be].open(output[be]);
129 if (input.empty())
throw std::invalid_argument(
"error: no input given");
130 if (input[0] ==
'-' || input.substr(0, 2) ==
"--")
131 throw std::invalid_argument(
"error: unknown option " + input);
134 auto path = fs::path(input);
135 world.
set(path.filename().replace_extension().string());
141 if (!flags.bootstrap) {
142 plugins.insert(plugins.begin(),
"compile"s);
143 if (opt >= 2) plugins.emplace_back(
"opt"s);
146 for (
const auto& plugin : plugins) {
147 auto mod = parser.plugin(plugin);
149 =
ast.ptr<
ast::Import>(Loc(), ast::Tok::Tag::K_plugin,
Dbg(driver.sym(plugin)), std::move(mod));
150 imports.emplace_back(std::move(
import));
153 auto mod = parser.import(driver.sym(input), os[Md]);
154 mod->add_implicit_imports(std::move(imports));
156 if (
auto s = os[AST]) {
158 mod->stream(tab, *s);
161 if (
auto h = os[H]) {
164 auto plugin = world.
sym(fs::path{path}.filename().replace_extension().
string());
165 ast.bootstrap(plugin, *h);
175 default:
error(
"illegal optimization level '{}'", opt);
178 if (
auto s = os[Dot]) world.
dot(*s, dot_all_annexes, dot_follow_types);
179 if (
auto s = os[Mim]) world.
dump(*s);
182 if (
auto s = os[LL]) {
183 if (
auto backend = driver.
backend(
"ll"))
186 error(
"'ll' emitter not loaded; try loading 'mem' plugin");
188 }
catch (
const Error& e) {
192 }
catch (
const std::exception& e) {
193 errln(
"{}", e.what());
196 errln(
"error: unknown exception");
int main(int argc, char **argv)