aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtins/functions.c4
-rw-r--r--compile.c88
-rw-r--r--tomo.c54
3 files changed, 85 insertions, 61 deletions
diff --git a/builtins/functions.c b/builtins/functions.c
index c11dd7e6..0ccc44cb 100644
--- a/builtins/functions.c
+++ b/builtins/functions.c
@@ -38,8 +38,8 @@ public void tomo_init(void)
srand48(seed);
Int$init_random(seed);
- if (register_printf_specifier('k', printf_text, printf_text_size))
- errx(1, "Couldn't set printf specifier");
+ if (register_printf_specifier('k', printf_text, printf_text_size))
+ errx(1, "Couldn't set printf specifier");
}
static void print_stack_trace(FILE *out)
diff --git a/compile.c b/compile.c
index caba764b..08dce21d 100644
--- a/compile.c
+++ b/compile.c
@@ -3059,58 +3059,65 @@ static CORD get_flag_options(type_t *t, CORD separator)
CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type)
{
auto fn_info = Match(fn_type, FunctionType);
+
+ binding_t *usage_binding = get_binding(env, "USAGE");
+ CORD usage_code = usage_binding ? usage_binding->code : "usage";
+ binding_t *help_binding = get_binding(env, "HELP");
+ CORD help_code = help_binding ? help_binding->code : usage_code;
+
+ CORD code = CORD_all(
+ "#define USAGE_ERR(fmt, ...) errx(1, fmt \"\\n%s\" __VA_OPT__(,) __VA_ARGS__, Text$as_c_string(", usage_code, "))\n"
+ "#define IS_FLAG(str, flag) (strncmp(str, flag, strlen(flag) == 0 && (str[strlen(flag)] == 0 || str[strlen(flag)] == '=')) == 0)\n");
+
if (!fn_info->args) {
+ code = CORD_all(code, "Text_t usage = Texts(Text(\"Usage: \"), Text$from_str(argv[0]), Text(\" [--help]\"));\n");
+ code = CORD_all(code, "if (argc > 1 && streq(argv[1], \"--help\")) {\n",
+ "Text$print(stdout, ", help_code, ");\n"
+ "puts(\"\");\n"
+ "return 0;\n}\n");
+
return CORD_all(
+ code,
"if (argc > 1)\n"
- "errx(1, \"This program doesn't take any arguments.\");\n",
+ "USAGE_ERR(\"This program doesn't take any arguments.\");\n",
fn_name, "();\n");
}
+
env_t *main_env = fresh_scope(env);
- CORD usage = CORD_EMPTY;
- bool has_help = false;
+ bool explicit_help_flag = false;
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
- if (streq(arg->name, "help")) has_help = true;
- usage = CORD_cat(usage, " ");
- type_t *t = get_arg_type(main_env, arg);
- CORD flag = CORD_replace(arg->name, "_", "-");
- if (arg->default_val) {
- if (t->tag == BoolType)
- usage = CORD_all(usage, "[--", flag, "|--no-", flag, "]");
- else
- usage = CORD_all(usage, "[--", flag, "=", get_flag_options(t, "|"), "]");
- } else {
- if (t->tag == BoolType)
- usage = CORD_all(usage, "[--", flag, "|--no-", flag, "]");
- else if (t->tag == EnumType)
- usage = CORD_all(usage, get_flag_options(t, "|"));
- else if (t->tag == ArrayType)
- usage = CORD_all(usage, "<", flag, "...>");
- else
- usage = CORD_all(usage, "<", flag, ">");
+ if (streq(arg->name, "help")) {
+ explicit_help_flag = true;
+ break;
}
}
- if (!has_help)
- usage = CORD_all(" [--help]", usage);
-
-
- CORD code = CORD_EMPTY;
- CORD usage_code = "usage";
- binding_t *usage_binding = get_binding(env, "USAGE");
- if (usage_binding)
- usage_code = usage_binding->code;
- else
+ if (!usage_binding) {
+ CORD usage = explicit_help_flag ? CORD_EMPTY : " [--help]";
+ for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
+ usage = CORD_cat(usage, " ");
+ type_t *t = get_arg_type(main_env, arg);
+ CORD flag = CORD_replace(arg->name, "_", "-");
+ if (arg->default_val) {
+ if (t->tag == BoolType)
+ usage = CORD_all(usage, "[--", flag, "|--no-", flag, "]");
+ else
+ usage = CORD_all(usage, "[--", flag, "=", get_flag_options(t, "|"), "]");
+ } else {
+ if (t->tag == BoolType)
+ usage = CORD_all(usage, "[--", flag, "|--no-", flag, "]");
+ else if (t->tag == EnumType)
+ usage = CORD_all(usage, get_flag_options(t, "|"));
+ else if (t->tag == ArrayType)
+ usage = CORD_all(usage, "<", flag, "...>");
+ else
+ usage = CORD_all(usage, "<", flag, ">");
+ }
+ }
code = CORD_all(code, "Text_t usage = Texts(Text(\"Usage: \"), Text$from_str(argv[0])",
usage == CORD_EMPTY ? CORD_EMPTY : CORD_all(", Text(", CORD_quoted(usage), ")"), ");\n");
-
- CORD help_code = "usage";
- binding_t *help_binding = get_binding(env, "HELP");
- if (help_binding)
- help_code = help_binding->code;
-
- code = CORD_all(code, "#define USAGE_ERR(fmt, ...) errx(1, fmt \"\\n%s\" __VA_OPT__(,) __VA_ARGS__, Text$as_c_string(", usage_code, "))\n"
- "#define IS_FLAG(str, flag) (strncmp(str, flag, strlen(flag) == 0 && (str[strlen(flag)] == 0 || str[strlen(flag)] == '=')) == 0)\n");
+ }
// Declare args:
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
@@ -3129,7 +3136,8 @@ CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type)
"break;\n"
"}\n"
"if (strncmp(argv[i], \"--\", 2) != 0) {\n++i;\ncontinue;\n}\n");
- if (!has_help) {
+
+ if (!explicit_help_flag) {
code = CORD_all(code, "else if (pop_flag(argv, &i, \"help\", &flag)) {\n"
"Text$print(stdout, ", help_code, ");\n"
"puts(\"\");\n"
diff --git a/tomo.c b/tomo.c
index 0bcdb29b..4f353ce0 100644
--- a/tomo.c
+++ b/tomo.c
@@ -421,17 +421,38 @@ int transpile_code(env_t *base_env, const char *filename, bool force_retranspile
CORD c_code = compile_file(module_env, ast);
+ FILE *out;
+ bool is_popened = false;
if (autofmt) {
- FILE *prog = CORD_RUN(autofmt, " 2>/dev/null >", c_filename);
- CORD_put(c_code, prog);
- if (pclose(prog) == -1)
- errx(1, "Failed to output autoformatted C code to %s: %s", c_filename, autofmt);
+ out = CORD_RUN(autofmt, " 2>/dev/null >'", c_filename, "'");
+ if (!out)
+ errx(1, "Failed to run autoformat program: %s", autofmt);
+ is_popened = true;
} else {
- FILE *c_file = fopen(c_filename, "w");
- if (!c_file)
+ out = fopen(c_filename, "w");
+ if (!out)
errx(1, "Couldn't open file: %s", c_filename);
- CORD_put(c_code, c_file);
- if (fclose(c_file))
+ is_popened = false;
+ }
+
+ CORD_put(c_code, out);
+
+ binding_t *main_binding = get_binding(module_env, "main");
+ if (main_binding && main_binding->type->tag == FunctionType) {
+ CORD_put(CORD_all(
+ "int ", main_binding->code, "$parse_and_run(int argc, char *argv[]) {\n"
+ "tomo_init();\n"
+ "\n",
+ compile_cli_arg_call(module_env, main_binding->code, main_binding->type),
+ "return 0;\n"
+ "}\n"), out);
+ }
+
+ if (is_popened) {
+ if (pclose(out) == -1)
+ errx(1, "Failed to output autoformatted C code to %s: %s", c_filename, autofmt);
+ } else {
+ if (fclose(out))
errx(1, "Failed to close file: %s", c_filename);
}
@@ -439,7 +460,7 @@ int transpile_code(env_t *base_env, const char *filename, bool force_retranspile
printf("Transpiled to %s\n", c_filename);
if (show_codegen) {
- FILE *out = CORD_RUN("bat -P ", c_filename);
+ out = CORD_RUN("bat -P ", c_filename);
pclose(out);
}
@@ -471,26 +492,21 @@ int compile_executable(env_t *base_env, const char *filename, CORD object_files)
errx(1, "Could not parse file %s", filename);
env_t *env = load_module_env(base_env, ast);
binding_t *main_binding = get_binding(env, "main");
- if (!main_binding || main_binding->type->tag != FunctionType) {
+ if (!main_binding || main_binding->type->tag != FunctionType)
errx(1, "No main() function has been defined for %s, so it can't be run!", filename);
- }
const char *bin_name = GC_strndup(filename, strlen(filename) - strlen(".tm"));
- FILE *runner = CORD_RUN(autofmt, " | ", cc, " ", cflags, " ", ldflags, " ", ldlibs, " ", object_files, " -x c - -o ", bin_name);
+ FILE *runner = CORD_RUN(cc, " ", cflags, " ", ldflags, " ", ldlibs, " ", object_files, " -x c - -o ", bin_name);
CORD program = CORD_all(
- "#include <tomo/tomo.h>\n"
- "#include \"", filename, ".h\"\n"
- "\n"
+ "extern int ", main_binding->code, "$parse_and_run(int argc, char *argv[]);\n"
"int main(int argc, char *argv[]) {\n"
- "tomo_init();\n"
- "\n",
- CORD_all(compile_cli_arg_call(env, main_binding->code, main_binding->type), "return 0;\n"),
+ "\treturn ", main_binding->code, "$parse_and_run(argc, argv);\n"
"}\n"
);
if (show_codegen) {
- FILE *out = CORD_RUN(autofmt, " | bat -P --file-name=run.c");
+ FILE *out = CORD_RUN("bat -P --file-name=run.c");
CORD_put(program, out);
pclose(out);
}