From 83a2bff4bb04b0189d17419baf8ca520992d5033 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 23 Nov 2025 15:57:44 -0500 Subject: Added Metadata section for files instead of _HELP and _USAGE --- src/compile/cli.c | 142 ++++++++++++++++++++++++----------------------- src/compile/cli.h | 3 +- src/compile/files.c | 1 + src/compile/statements.c | 1 + 4 files changed, 78 insertions(+), 69 deletions(-) (limited to 'src/compile') 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 diff --git a/src/compile/cli.h b/src/compile/cli.h index fa60eccf..fbb7347b 100644 --- a/src/compile/cli.h +++ b/src/compile/cli.h @@ -2,9 +2,10 @@ #pragma once +#include "../ast.h" #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); +Text_t compile_cli_arg_call(env_t *env, ast_t *ast, Text_t fn_name, type_t *fn_type, const char *version); Text_t compile_manpage(Text_t program, OptionalText_t synopsis, OptionalText_t description, arg_t *args); diff --git a/src/compile/files.c b/src/compile/files.c index a4cc07fe..b916f23f 100644 --- a/src/compile/files.c +++ b/src/compile/files.c @@ -142,6 +142,7 @@ Text_t compile_top_level_code(env_t *env, ast_t *ast) { } return code; } + case Metadata: default: return EMPTY_TEXT; } } diff --git a/src/compile/statements.c b/src/compile/statements.c index 0cd85b5d..c6ceccd9 100644 --- a/src/compile/statements.c +++ b/src/compile/statements.c @@ -216,6 +216,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast) { return EMPTY_TEXT; } } + case Metadata: return EMPTY_TEXT; default: // print("Is discardable: ", ast_to_sexp_str(ast), " ==> ", // is_discardable(env, ast)); -- cgit v1.2.3