aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-08-24 17:37:08 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-08-24 17:37:08 -0400
commit4347eff736db4da9f8841793d63d282e694de080 (patch)
tree47dae97a3454d2481817af02dd0b04442c0ff03d
parente3e7c60dd75ef0f06a25ddde2685868062302eeb (diff)
Split CLI into its own file
-rw-r--r--src/compile.c99
-rw-r--r--src/compile.h1
-rw-r--r--src/compile/cli.c112
-rw-r--r--src/compile/cli.h5
-rw-r--r--src/tomo.c1
5 files changed, 118 insertions, 100 deletions
diff --git a/src/compile.c b/src/compile.c
index 6c10c763..2ead44c4 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -734,103 +734,4 @@ Text_t compile(env_t *env, ast_t *ast) {
return EMPTY_TEXT;
}
-static Text_t get_flag_options(type_t *t, const char *separator) {
- if (t->tag == BoolType) {
- return Text("yes|no");
- } else if (t->tag == EnumType) {
- Text_t options = EMPTY_TEXT;
- for (tag_t *tag = Match(t, EnumType)->tags; tag; tag = tag->next) {
- options = Texts(options, tag->name);
- if (tag->next) options = Texts(options, separator);
- }
- return options;
- } else if (t->tag == IntType || t->tag == NumType || t->tag == BigIntType) {
- return Text("N");
- } else {
- return Text("...");
- }
-}
-
-Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version) {
- 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;
- }
- }
-
- Text_t usage = explicit_help_flag ? EMPTY_TEXT : Text(" [--help]");
- for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
- usage = Texts(usage, " ");
- type_t *t = get_arg_type(main_env, arg);
- Text_t flag = Text$replace(Text$from_str(arg->name), Text("_"), Text("-"));
- if (arg->default_val || arg->type->tag == OptionalType) {
- if (strlen(arg->name) == 1) {
- if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
- usage = Texts(usage, "[-", flag, "]");
- else usage = Texts(usage, "[-", flag, " ", get_flag_options(t, "|"), "]");
- } else {
- if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
- usage = Texts(usage, "[--", flag, "]");
- else if (t->tag == ListType) usage = Texts(usage, "[--", flag, " ", get_flag_options(t, "|"), "]");
- else usage = Texts(usage, "[--", flag, "=", get_flag_options(t, "|"), "]");
- }
- } else {
- if (t->tag == BoolType) usage = Texts(usage, "<--", flag, "|--no-", flag, ">");
- else if (t->tag == EnumType) usage = Texts(usage, get_flag_options(t, "|"));
- else if (t->tag == ListType) usage = Texts(usage, "[", flag, "...]");
- else usage = Texts(usage, "<", flag, ">");
- }
- }
- code = Texts(code,
- "Text_t usage = Texts(Text(\"Usage: \"), "
- "Text$from_str(argv[0])",
- usage.length == 0 ? EMPTY_TEXT : Texts(", Text(", quoted_text(usage), ")"), ");\n");
- }
-
- for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
- type_t *opt_type = arg->type->tag == OptionalType ? arg->type : Type(OptionalType, .type = arg->type);
- code = Texts(code, compile_declaration(opt_type, Texts("_$", arg->name)));
- if (arg->default_val) {
- Text_t default_val = compile(env, arg->default_val);
- if (arg->type->tag != OptionalType) default_val = promote_to_optional(arg->type, default_val);
- code = Texts(code, " = ", default_val);
- } else {
- code = Texts(code, " = ", compile_none(arg->type));
- }
- code = Texts(code, ";\n");
- }
-
- Text_t version_code = quoted_str(version);
- code = Texts(code, "tomo_parse_args(argc, argv, ", usage_code, ", ", help_code, ", ", version_code);
- for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
- code = Texts(code, ",\n{", quoted_text(Text$replace(Text$from_str(arg->name), Text("_"), Text("-"))), ", ",
- (arg->default_val || arg->type->tag == OptionalType) ? "false" : "true", ", ",
- compile_type_info(arg->type), ", &", Texts("_$", arg->name), "}");
- }
- code = Texts(code, ");\n");
-
- code = Texts(code, fn_name, "(");
- for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
- Text_t arg_code = Texts("_$", arg->name);
- if (arg->type->tag != OptionalType) arg_code = optional_into_nonnone(arg->type, arg_code);
-
- code = Texts(code, arg_code);
- if (arg->next) code = Texts(code, ", ");
- }
- code = Texts(code, ");\n");
- return code;
-}
-
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/compile.h b/src/compile.h
index 361acbb6..8e9e5f82 100644
--- a/src/compile.h
+++ b/src/compile.h
@@ -8,7 +8,6 @@
#include "types.h"
Text_t compile(env_t *env, ast_t *ast);
-Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version);
Text_t compile_empty(type_t *t);
Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t);
diff --git a/src/compile/cli.c b/src/compile/cli.c
new file mode 100644
index 00000000..868e9075
--- /dev/null
+++ b/src/compile/cli.c
@@ -0,0 +1,112 @@
+#include "../compile.h"
+#include "../environment.h"
+#include "../stdlib/datatypes.h"
+#include "../stdlib/text.h"
+#include "../stdlib/util.h"
+#include "../typecheck.h"
+#include "../types.h"
+#include "assignments.h"
+#include "optionals.h"
+#include "promotions.h"
+#include "text.h"
+#include "types.h"
+
+static Text_t get_flag_options(type_t *t, const char *separator) {
+ if (t->tag == BoolType) {
+ return Text("yes|no");
+ } else if (t->tag == EnumType) {
+ Text_t options = EMPTY_TEXT;
+ for (tag_t *tag = Match(t, EnumType)->tags; tag; tag = tag->next) {
+ options = Texts(options, tag->name);
+ if (tag->next) options = Texts(options, separator);
+ }
+ return options;
+ } else if (t->tag == IntType || t->tag == NumType || t->tag == BigIntType) {
+ return Text("N");
+ } else {
+ return Text("...");
+ }
+}
+
+public
+Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version) {
+ 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;
+ }
+ }
+
+ Text_t usage = explicit_help_flag ? EMPTY_TEXT : Text(" [--help]");
+ for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
+ usage = Texts(usage, " ");
+ type_t *t = get_arg_type(main_env, arg);
+ Text_t flag = Text$replace(Text$from_str(arg->name), Text("_"), Text("-"));
+ if (arg->default_val || arg->type->tag == OptionalType) {
+ if (strlen(arg->name) == 1) {
+ if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
+ usage = Texts(usage, "[-", flag, "]");
+ else usage = Texts(usage, "[-", flag, " ", get_flag_options(t, "|"), "]");
+ } else {
+ if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
+ usage = Texts(usage, "[--", flag, "]");
+ else if (t->tag == ListType) usage = Texts(usage, "[--", flag, " ", get_flag_options(t, "|"), "]");
+ else usage = Texts(usage, "[--", flag, "=", get_flag_options(t, "|"), "]");
+ }
+ } else {
+ if (t->tag == BoolType) usage = Texts(usage, "<--", flag, "|--no-", flag, ">");
+ else if (t->tag == EnumType) usage = Texts(usage, get_flag_options(t, "|"));
+ else if (t->tag == ListType) usage = Texts(usage, "[", flag, "...]");
+ else usage = Texts(usage, "<", flag, ">");
+ }
+ }
+ code = Texts(code,
+ "Text_t usage = Texts(Text(\"Usage: \"), "
+ "Text$from_str(argv[0])",
+ usage.length == 0 ? EMPTY_TEXT : Texts(", Text(", quoted_text(usage), ")"), ");\n");
+ }
+
+ for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
+ type_t *opt_type = arg->type->tag == OptionalType ? arg->type : Type(OptionalType, .type = arg->type);
+ code = Texts(code, compile_declaration(opt_type, Texts("_$", arg->name)));
+ if (arg->default_val) {
+ Text_t default_val = compile(env, arg->default_val);
+ if (arg->type->tag != OptionalType) default_val = promote_to_optional(arg->type, default_val);
+ code = Texts(code, " = ", default_val);
+ } else {
+ code = Texts(code, " = ", compile_none(arg->type));
+ }
+ code = Texts(code, ";\n");
+ }
+
+ Text_t version_code = quoted_str(version);
+ code = Texts(code, "tomo_parse_args(argc, argv, ", usage_code, ", ", help_code, ", ", version_code);
+ for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
+ code = Texts(code, ",\n{", quoted_text(Text$replace(Text$from_str(arg->name), Text("_"), Text("-"))), ", ",
+ (arg->default_val || arg->type->tag == OptionalType) ? "false" : "true", ", ",
+ compile_type_info(arg->type), ", &", Texts("_$", arg->name), "}");
+ }
+ code = Texts(code, ");\n");
+
+ code = Texts(code, fn_name, "(");
+ for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
+ Text_t arg_code = Texts("_$", arg->name);
+ if (arg->type->tag != OptionalType) arg_code = optional_into_nonnone(arg->type, arg_code);
+
+ code = Texts(code, arg_code);
+ if (arg->next) code = Texts(code, ", ");
+ }
+ code = Texts(code, ");\n");
+ return code;
+}
diff --git a/src/compile/cli.h b/src/compile/cli.h
new file mode 100644
index 00000000..dc18fd3c
--- /dev/null
+++ b/src/compile/cli.h
@@ -0,0 +1,5 @@
+#include "../environment.h"
+#include "../stdlib/datatypes.h"
+#include "../types.h"
+
+Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version);
diff --git a/src/tomo.c b/src/tomo.c
index 5d932ef1..4c875b62 100644
--- a/src/tomo.c
+++ b/src/tomo.c
@@ -15,6 +15,7 @@
#include "ast.h"
#include "changes.md.h"
#include "compile.h"
+#include "compile/cli.h"
#include "compile/files.h"
#include "config.h"
#include "modules.h"