aboutsummaryrefslogtreecommitdiff
path: root/src/compile/cli.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/compile/cli.c')
-rw-r--r--src/compile/cli.c142
1 files changed, 74 insertions, 68 deletions
diff --git a/src/compile/cli.c b/src/compile/cli.c
index e5756521..b92a5784 100644
--- a/src/compile/cli.c
+++ b/src/compile/cli.c
@@ -58,80 +58,86 @@ static OptionalText_t flagify(const char *name, bool prefix) {
return flag;
}
-public
-Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version) {
+static Text_t generate_usage(env_t *env, type_t *fn_type) {
DeclareMatch(fn_info, fn_type, FunctionType);
-
- env_t *main_env = fresh_scope(env);
-
- Text_t code = EMPTY_TEXT;
- binding_t *usage_binding = get_binding(env, "_USAGE");
- Text_t usage_code = usage_binding ? usage_binding->code : Text("usage");
- binding_t *help_binding = get_binding(env, "_HELP");
- Text_t help_code = help_binding ? help_binding->code : usage_code;
- if (!usage_binding) {
- bool explicit_help_flag = false;
- for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
- if (streq(arg->name, "help")) {
- explicit_help_flag = true;
- break;
- }
+ bool explicit_help_flag = false;
+ for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
+ if (streq(arg->name, "help")) {
+ explicit_help_flag = true;
+ break;
}
-
- Text_t usage = explicit_help_flag ? EMPTY_TEXT : Text(" [\x1b[1m--help\x1b[m]");
- for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
- usage = Texts(usage, " ");
- type_t *t = get_arg_type(main_env, arg);
- OptionalText_t flag = flagify(arg->name, arg->default_val != NULL);
- assert(flag.tag != TEXT_NONE);
- OptionalText_t alias_flag = flagify(arg->alias, arg->default_val != NULL);
- Text_t flags = Texts("\x1b[1m", flag, "\x1b[m");
- if (alias_flag.tag != TEXT_NONE) flags = Texts(flags, ",\x1b[1m", alias_flag, "\x1b[m");
+ }
+ env_t *main_env = fresh_scope(env);
+ Text_t usage = explicit_help_flag ? EMPTY_TEXT : Text(" [\x1b[1m--help\x1b[m]");
+ for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
+ usage = Texts(usage, " ");
+ type_t *t = get_arg_type(main_env, arg);
+ OptionalText_t flag = flagify(arg->name, arg->default_val != NULL);
+ assert(flag.tag != TEXT_NONE);
+ OptionalText_t alias_flag = flagify(arg->alias, arg->default_val != NULL);
+ Text_t flags = Texts("\x1b[1m", flag, "\x1b[m");
+ if (alias_flag.tag != TEXT_NONE) flags = Texts(flags, ",\x1b[1m", alias_flag, "\x1b[m");
+ if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
+ flags = Texts(flags, "|\x1b[1m--no-", Text$without_prefix(flag, Text("--")), "\x1b[m");
+ if (arg->default_val || value_type(t)->tag == BoolType) {
if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
- flags = Texts(flags, "|\x1b[1m--no-", Text$without_prefix(flag, Text("--")), "\x1b[m");
- if (arg->default_val || value_type(t)->tag == BoolType) {
- if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
- usage = Texts(usage, "[", flags, "]");
- else if (t->tag == ListType) usage = Texts(usage, "[", flags, " ", get_flag_options(t, Text("|")), "]");
- else usage = Texts(usage, "[", flags, " ", get_flag_options(t, Text("|")), "]");
- } else {
- usage = Texts(usage, "\x1b[1m", get_flag_options(t, Text("|")), "\x1b[m");
- }
+ usage = Texts(usage, "[", flags, "]");
+ else if (t->tag == ListType) usage = Texts(usage, "[", flags, " ", get_flag_options(t, Text("|")), "]");
+ else usage = Texts(usage, "[", flags, " ", get_flag_options(t, Text("|")), "]");
+ } else {
+ usage = Texts(usage, "\x1b[1m", get_flag_options(t, Text("|")), "\x1b[m");
}
- code = Texts(code,
- "Text_t usage = Texts(Text(\"\\x1b[1mUsage:\\x1b[m \"), "
- "Text$from_str(argv[0])",
- usage.length == 0 ? EMPTY_TEXT : Texts(", Text(", quoted_text(usage), ")"), ");\n");
}
- if (!help_binding) {
- Text_t help_text = fn_info->args ? Text("\n") : Text("\n\n\x1b[2;3m No arguments...\x1b[m");
-
- for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
- help_text = Texts(help_text, "\n");
- type_t *t = get_arg_type(main_env, arg);
- OptionalText_t flag = flagify(arg->name, true);
- assert(flag.tag != TEXT_NONE);
- OptionalText_t alias_flag = flagify(arg->alias, true);
- Text_t flags = Texts("\x1b[33;1m", flag, "\x1b[m");
- if (alias_flag.tag != TEXT_NONE) flags = Texts(flags, ",\x1b[33;1m", alias_flag, "\x1b[m");
- if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
- flags = Texts(flags, "|\x1b[33;1m--no-", Text$without_prefix(flag, Text("--")), "\x1b[m");
- if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
- help_text = Texts(help_text, " ", flags);
- else
- help_text = Texts(help_text, " ", flags, " \x1b[1;34m",
- get_flag_options(t, Text("\x1b[m | \x1b[1;34m")), "\x1b[m");
-
- if (arg->comment.length > 0) help_text = Texts(help_text, " \x1b[3m", arg->comment, "\x1b[m");
- if (arg->default_val) {
- Text_t default_text =
- Text$from_strn(arg->default_val->start, (size_t)(arg->default_val->end - arg->default_val->start));
- help_text = Texts(help_text, " \x1b[2m(default:", default_text, ")\x1b[m");
- }
+ return usage;
+}
+
+static Text_t generate_help(env_t *env, type_t *fn_type) {
+ DeclareMatch(fn_info, fn_type, FunctionType);
+ env_t *main_env = fresh_scope(env);
+ Text_t help_text = EMPTY_TEXT;
+
+ for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
+ help_text = Texts(help_text, "\n");
+ type_t *t = get_arg_type(main_env, arg);
+ OptionalText_t flag = flagify(arg->name, true);
+ assert(flag.tag != TEXT_NONE);
+ OptionalText_t alias_flag = flagify(arg->alias, true);
+ Text_t flags = Texts("\x1b[33;1m", flag, "\x1b[m");
+ if (alias_flag.tag != TEXT_NONE) flags = Texts(flags, ",\x1b[33;1m", alias_flag, "\x1b[m");
+ if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
+ flags = Texts(flags, "|\x1b[33;1m--no-", Text$without_prefix(flag, Text("--")), "\x1b[m");
+ if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
+ help_text = Texts(help_text, " ", flags);
+ else
+ help_text = Texts(help_text, " ", flags, " \x1b[1;34m", get_flag_options(t, Text("\x1b[m | \x1b[1;34m")),
+ "\x1b[m");
+
+ if (arg->comment.length > 0) help_text = Texts(help_text, " \x1b[3m", arg->comment, "\x1b[m");
+ if (arg->default_val) {
+ Text_t default_text =
+ Text$from_strn(arg->default_val->start, (size_t)(arg->default_val->end - arg->default_val->start));
+ help_text = Texts(help_text, " \x1b[2m(default:", default_text, ")\x1b[m");
}
- code = Texts(code, "Text_t help = Texts(usage, ", quoted_text(Texts(help_text, "\n")), ");\n");
- help_code = Text("help");
}
+ return help_text;
+}
+
+public
+Text_t compile_cli_arg_call(env_t *env, ast_t *ast, Text_t fn_name, type_t *fn_type, const char *version) {
+ DeclareMatch(fn_info, fn_type, FunctionType);
+
+ Text_t code = EMPTY_TEXT;
+ OptionalText_t usage = ast_metadata(ast, "USAGE");
+ if (usage.tag == TEXT_NONE) usage = generate_usage(env, fn_type);
+
+ OptionalText_t help = ast_metadata(ast, "HELP");
+ if (help.tag == TEXT_NONE) help = generate_help(env, fn_type);
+
+ code = Texts(code,
+ "Text_t usage = Texts(Text(\"\\x1b[1mUsage:\\x1b[m \"), "
+ "Text$from_str(argv[0]), Text(\" \")",
+ usage.length == 0 ? EMPTY_TEXT : Texts(", Text(", quoted_text(usage), ")"), ");\n",
+ "Text_t help = Texts(usage, Text(\"\\n\\n\"", quoted_text(help), "));\n");
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
code = Texts(code, compile_declaration(arg->type, Texts("_$", Text$from_str(arg->name))), " = ",
@@ -151,7 +157,7 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c
"},\n");
}
code = Texts(code, "};\n");
- code = Texts(code, "tomo_parse_args(argc, argv, ", usage_code, ", ", help_code, ", ", version_code,
+ code = Texts(code, "tomo_parse_args(argc, argv, usage, help, ", version_code,
", sizeof(cli_args)/sizeof(cli_args[0]), cli_args);\n");
// Lazily initialize default values to prevent side effects