diff options
| -rw-r--r-- | src/compile/cli.c | 42 | ||||
| -rw-r--r-- | src/stdlib/cli.c | 18 | ||||
| -rw-r--r-- | src/stdlib/cli.h | 13 | ||||
| -rw-r--r-- | src/tomo.c | 42 |
4 files changed, 61 insertions, 54 deletions
diff --git a/src/compile/cli.c b/src/compile/cli.c index eec2f941..820f0e2e 100644 --- a/src/compile/cli.c +++ b/src/compile/cli.c @@ -86,7 +86,29 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c } for (arg_t *arg = fn_info->args; arg; arg = arg->next) { - code = Texts(code, compile_declaration(arg->type, Texts("_$", Text$from_str(arg->name)))); + code = Texts(code, compile_declaration(arg->type, Texts("_$", Text$from_str(arg->name))), " = ", + compile_empty(arg->type), ";\n"); + } + + Text_t version_code = quoted_str(version); + code = Texts(code, "cli_arg_t cli_args[] = {\n"); + for (arg_t *arg = fn_info->args; arg; arg = arg->next) { + code = Texts(code, "{", quoted_text(Text$replace(Text$from_str(arg->name), Text("_"), Text("-"))), ", &", + Texts("_$", Text$from_str(arg->name)), ", ", compile_type_info(arg->type), + arg->default_val ? Text("") : Text(", .required=true"), + arg->alias ? Texts(", .short_flag=", quoted_text(Text$from_str(arg->name)), + "[0]") // TODO: escape char properly + : Text(""), + + "},\n"); + } + code = Texts(code, "};\n"); + code = Texts(code, "tomo_parse_args(argc, argv, ", usage_code, ", ", help_code, ", ", version_code, + ", sizeof(cli_args)/sizeof(cli_args[0]), cli_args);\n"); + + // Lazily initialize default values to prevent side effects + int64_t i = 0; + for (arg_t *arg = fn_info->args; arg; arg = arg->next) { if (arg->default_val) { Text_t default_val; if (arg->type) { @@ -95,23 +117,11 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c } else { default_val = compile(env, arg->default_val); } - code = Texts(code, " = ", default_val); - } else { - code = Texts(code, " = ", compile_empty(arg->type)); + code = Texts(code, "if (!cli_args[", i, "].populated) ", Texts("_$", Text$from_str(arg->name)), " = ", + default_val, ";\n"); } - 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->alias ? Texts(quoted_text(Text$from_str(arg->name)), "[0]") // TODO: escape char properly - : Text("'\\0'"), - ", ", arg->default_val ? "false" : "true", ", ", compile_type_info(arg->type), ", &", - Texts("_$", Text$from_str(arg->name)), "}"); + i += 1; } - code = Texts(code, ");\n"); code = Texts(code, fn_name, "("); for (arg_t *arg = fn_info->args; arg; arg = arg->next) { diff --git a/src/stdlib/cli.c b/src/stdlib/cli.c index 6e0a4b81..0f8bff4a 100644 --- a/src/stdlib/cli.c +++ b/src/stdlib/cli.c @@ -195,15 +195,14 @@ static bool pop_boolean_cli_flag(List_t *args, char short_flag, const char *flag } public -void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, - cli_arg_t spec[spec_len]) { - bool *parsed = GC_MALLOC_ATOMIC(sizeof(bool[spec_len])); +void tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, + cli_arg_t spec[spec_len]) { List_t args = EMPTY_LIST; for (int i = 1; i < argc; i++) { List$insert(&args, &argv[i], I(0), sizeof(const char *)); } for (int i = 0; i < spec_len; i++) { - parsed[i] = pop_cli_flag(&args, spec[i].short_flag, spec[i].name, spec[i].dest, spec[i].type); + spec[i].populated = pop_cli_flag(&args, spec[i].short_flag, spec[i].name, spec[i].dest, spec[i].type); } bool show_help = false; @@ -230,18 +229,19 @@ void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const c } for (int i = 0; i < spec_len && before_double_dash.length > 0; i++) { - if (!parsed[i]) { - parsed[i] = pop_cli_positional(&before_double_dash, spec[i].name, spec[i].dest, spec[i].type, false); + if (!spec[i].populated) { + spec[i].populated = + pop_cli_positional(&before_double_dash, spec[i].name, spec[i].dest, spec[i].type, false); } } for (int i = 0; i < spec_len && after_double_dash.length > 0; i++) { - if (!parsed[i]) { - parsed[i] = pop_cli_positional(&after_double_dash, spec[i].name, spec[i].dest, spec[i].type, true); + if (!spec[i].populated) { + spec[i].populated = pop_cli_positional(&after_double_dash, spec[i].name, spec[i].dest, spec[i].type, true); } } for (int i = 0; i < spec_len; i++) { - if (!parsed[i] && spec[i].required) print_err("Missing required flag: --", spec[i].name, "\n", usage); + if (!spec[i].populated && spec[i].required) print_err("Missing required flag: --", spec[i].name, "\n", usage); } List_t remaining_args = List$concat(before_double_dash, after_double_dash, sizeof(const char *)); diff --git a/src/stdlib/cli.h b/src/stdlib/cli.h index 596409c1..5026edb3 100644 --- a/src/stdlib/cli.h +++ b/src/stdlib/cli.h @@ -9,17 +9,14 @@ typedef struct { const char *name; - char short_flag; - bool required; - const TypeInfo_t *type; void *dest; + const TypeInfo_t *type; + char short_flag; + bool required, populated; } cli_arg_t; -void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, - cli_arg_t spec[spec_len]); -#define tomo_parse_args(argc, argv, usage, help, version, ...) \ - _tomo_parse_args(argc, argv, usage, help, version, sizeof((cli_arg_t[]){__VA_ARGS__}) / sizeof(cli_arg_t), \ - (cli_arg_t[]){__VA_ARGS__}) +void tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, + cli_arg_t spec[spec_len]); bool pop_cli_flag(List_t *args, char short_flag, const char *flag, void *dest, const TypeInfo_t *type); bool pop_cli_positional(List_t *args, const char *flag, void *dest, const TypeInfo_t *type, bool allow_dashes); @@ -218,28 +218,28 @@ int main(int argc, char *argv[]) { " --run|-r: run a program from ", TOMO_PATH, "/share/tomo_" TOMO_VERSION "/installed\n"); Text_t help = Texts(Text("\x1b[1mtomo\x1b[m: a compiler for the Tomo programming language"), Text("\n\n"), usage); - tomo_parse_args(argc, argv, usage, help, TOMO_VERSION, // - {"run", 'r', false, List$info(&Path$info), &run_files}, // - {"args", '\0', false, List$info(&Text$info), &args}, // - {"format", 'F', false, List$info(&Path$info), &format_files}, // - {"format-inplace", '\0', false, List$info(&Path$info), &format_files_inplace}, // - {"transpile", 't', false, List$info(&Path$info), &transpile_files}, // - {"compile-obj", 'c', false, List$info(&Path$info), &compile_objects}, // - {"compile-exe", 'e', false, List$info(&Path$info), &compile_executables}, // - {"library", 'L', false, List$info(&Path$info), &libraries}, // - {"uninstall", 'u', false, List$info(&Text$info), &uninstall_libraries}, // - {"verbose", 'v', false, &Bool$info, &verbose}, // - {"version", 'V', false, &Bool$info, &show_version}, // - {"install", 'I', false, &Bool$info, &should_install}, // - {"prefix", '\0', false, &Bool$info, &show_prefix}, // - {"quiet", 'q', false, &Bool$info, &quiet}, // - {"show-codegen", 'C', false, &Text$info, &show_codegen}, // - {"optimization", 'O', false, &Text$info, &optimization}, // - {"force-rebuild", 'f', false, &Bool$info, &clean_build}, // - {"source-mapping", 'm', false, &Bool$info, &source_mapping}, - {"changelog", '\0', false, &Bool$info, &show_changelog}, // - ); + cli_arg_t tomo_args[] = { + {"run", &run_files, List$info(&Path$info), .short_flag = 'r'}, // + {"args", &args, List$info(&Text$info)}, // + {"format", &format_files, List$info(&Path$info), .short_flag = 'F'}, // + {"format-inplace", &format_files_inplace, List$info(&Path$info)}, // + {"transpile", &transpile_files, List$info(&Path$info), .short_flag = 't'}, // + {"compile-obj", &compile_objects, List$info(&Path$info), .short_flag = 'c'}, // + {"compile-exe", &compile_executables, List$info(&Path$info), .short_flag = 'e'}, // + {"library", &libraries, List$info(&Path$info), .short_flag = 'L'}, // + {"uninstall", &uninstall_libraries, List$info(&Text$info), .short_flag = 'u'}, // + {"verbose", &verbose, &Bool$info, .short_flag = 'v'}, // + {"install", &should_install, &Bool$info, .short_flag = 'I'}, // + {"prefix", &show_prefix, &Bool$info}, // + {"quiet", &quiet, &Bool$info, .short_flag = 'q'}, // + {"show-codegen", &show_codegen, &Text$info, .short_flag = 'C'}, // + {"optimization", &optimization, &Text$info, .short_flag = 'O'}, // + {"force-rebuild", &clean_build, &Bool$info, .short_flag = 'f'}, // + {"source-mapping", &source_mapping, &Bool$info, .short_flag = 'm'}, + {"changelog", &show_changelog, &Bool$info}, // + }; + tomo_parse_args(argc, argv, usage, help, TOMO_VERSION, sizeof(tomo_args) / sizeof(tomo_args[0]), tomo_args); if (show_prefix) { print(TOMO_PATH); return 0; |
