aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-10-03 00:17:33 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-10-03 00:17:33 -0400
commitd053a3177df6abf6e014ac00c657e3263476b7b9 (patch)
tree3ab92cac33c90144a5b9382fb3334dd1a1701280
parentbaea09062482674220a3686d488a283e6b9b8821 (diff)
Fix for optional CLI arguments
-rw-r--r--src/compile/cli.c20
-rw-r--r--src/stdlib/cli.c48
2 files changed, 39 insertions, 29 deletions
diff --git a/src/compile/cli.c b/src/compile/cli.c
index d93e5f56..f138bd78 100644
--- a/src/compile/cli.c
+++ b/src/compile/cli.c
@@ -58,7 +58,7 @@ 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) {
usage = Texts(usage, " ");
type_t *t = get_arg_type(main_env, arg);
- if (arg->default_val || arg->type->tag == OptionalType) {
+ if (arg->default_val) {
OptionalText_t flag = flagify(arg->name, true);
assert(flag.tag != TEXT_NONE);
OptionalText_t alias_flag = flagify(arg->alias, true);
@@ -86,15 +86,14 @@ 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) {
- type_t *opt_type = arg->type->tag == OptionalType ? arg->type : Type(OptionalType, .type = arg->type);
- code = Texts(code, compile_declaration(opt_type, Texts("_$", Text$from_str(arg->name))));
+ code = Texts(code, compile_declaration(arg->type, Texts("_$", Text$from_str(arg->name))));
if (arg->default_val) {
Text_t default_val =
arg->type ? compile_to_type(env, arg->default_val, arg->type) : 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, " = ", compile_empty(arg->type));
}
code = Texts(code, ";\n");
}
@@ -103,22 +102,19 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c
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("_$", Text$from_str(arg->name)), "}");
+ arg->default_val ? "false" : "true", ", ", compile_type_info(arg->type), ", &",
+ Texts("_$", Text$from_str(arg->name)), "}");
if (arg->alias) {
code = Texts(code, ",\n{", quoted_text(Text$replace(Text$from_str(arg->alias), Text("_"), Text("-"))), ", ",
- (arg->default_val || arg->type->tag == OptionalType) ? "false" : "true", ", ",
- compile_type_info(arg->type), ", &", Texts("_$", Text$from_str(arg->name)), "}");
+ arg->default_val ? "false" : "true", ", ", compile_type_info(arg->type), ", &",
+ Texts("_$", Text$from_str(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);
+ code = Texts(code, Texts("_$", arg->name));
if (arg->next) code = Texts(code, ", ");
}
code = Texts(code, ");\n");
diff --git a/src/stdlib/cli.c b/src/stdlib/cli.c
index d5bb0ea2..2d54d330 100644
--- a/src/stdlib/cli.c
+++ b/src/stdlib/cli.c
@@ -34,52 +34,66 @@ static bool is_numeric_type(const TypeInfo_t *info) {
static bool parse_single_arg(const TypeInfo_t *info, char *arg, void *dest) {
if (!arg) return false;
- if (info->tag == OptionalInfo && streq(arg, "none")) return true;
-
- while (info->tag == OptionalInfo)
- info = info->OptionalInfo.type;
-
- if (info == &Int$info) {
+ if (info->tag == OptionalInfo) {
+ const TypeInfo_t *nonnull = info->OptionalInfo.type;
+ if (streq(arg, "none")) {
+ if (nonnull == &Num$info) *(double *)dest = (double)NAN;
+ else if (nonnull == &Num32$info) *(float *)dest = (float)NAN;
+ else memset(dest, 0, (size_t)info->size);
+ return true;
+ } else {
+ bool success = parse_single_arg(nonnull, arg, dest);
+ if (success) {
+ if (nonnull == &Int64$info) ((OptionalInt64_t *)dest)->has_value = true;
+ else if (nonnull == &Int32$info) ((OptionalInt32_t *)dest)->has_value = true;
+ else if (nonnull == &Int16$info) ((OptionalInt16_t *)dest)->has_value = true;
+ else if (nonnull == &Int8$info) ((OptionalInt8_t *)dest)->has_value = true;
+ else if (nonnull == &Byte$info) ((OptionalByte_t *)dest)->has_value = true;
+ else if (nonnull->tag == StructInfo && nonnull != &Path$info) *(bool *)(dest + nonnull->size) = true;
+ }
+ return success;
+ }
+ } else if (info == &Int$info) {
OptionalInt_t parsed = Int$from_str(arg);
- if (parsed.small != 0) *(OptionalInt_t *)dest = parsed;
+ if (parsed.small != 0) *(Int_t *)dest = parsed;
return parsed.small != 0;
} else if (info == &Int64$info) {
OptionalInt64_t parsed = Int64$parse(Text$from_str(arg), NULL);
- if (parsed.has_value) *(OptionalInt64_t *)dest = parsed;
+ if (parsed.has_value) *(Int64_t *)dest = parsed.value;
return parsed.has_value;
} else if (info == &Int32$info) {
OptionalInt32_t parsed = Int32$parse(Text$from_str(arg), NULL);
- if (parsed.has_value) *(OptionalInt32_t *)dest = parsed;
+ if (parsed.has_value) *(Int32_t *)dest = parsed.value;
return parsed.has_value;
} else if (info == &Int16$info) {
OptionalInt16_t parsed = Int16$parse(Text$from_str(arg), NULL);
- if (parsed.has_value) *(OptionalInt16_t *)dest = parsed;
+ if (parsed.has_value) *(Int16_t *)dest = parsed.value;
return parsed.has_value;
} else if (info == &Int8$info) {
OptionalInt8_t parsed = Int8$parse(Text$from_str(arg), NULL);
- if (parsed.has_value) *(OptionalInt8_t *)dest = parsed;
+ if (parsed.has_value) *(Int8_t *)dest = parsed.value;
return parsed.has_value;
} else if (info == &Byte$info) {
OptionalByte_t parsed = Byte$parse(Text$from_str(arg), NULL);
- if (parsed.has_value) *(OptionalByte_t *)dest = parsed;
+ if (parsed.has_value) *(Byte_t *)dest = parsed.value;
return parsed.has_value;
} else if (info == &Bool$info) {
OptionalBool_t parsed = Bool$parse(Text$from_str(arg), NULL);
- if (parsed != NONE_BOOL) *(OptionalBool_t *)dest = parsed;
+ if (parsed != NONE_BOOL) *(Bool_t *)dest = parsed;
return parsed != NONE_BOOL;
} else if (info == &Num$info) {
OptionalNum_t parsed = Num$parse(Text$from_str(arg), NULL);
- if (!isnan(parsed)) *(OptionalNum_t *)dest = parsed;
+ if (!isnan(parsed)) *(Num_t *)dest = parsed;
return !isnan(parsed);
} else if (info == &Num32$info) {
OptionalNum32_t parsed = Num32$parse(Text$from_str(arg), NULL);
- if (!isnan(parsed)) *(OptionalNum32_t *)dest = parsed;
+ if (!isnan(parsed)) *(Num32_t *)dest = parsed;
return !isnan(parsed);
} else if (info == &Path$info) {
- *(OptionalPath_t *)dest = Path$from_str(arg);
+ *(Path_t *)dest = Path$from_str(arg);
return true;
} else if (info->tag == TextInfo) {
- *(OptionalText_t *)dest = Text$from_str(arg);
+ *(Text_t *)dest = Text$from_str(arg);
return true;
} else if (info->tag == EnumInfo) {
for (int t = 0; t < info->EnumInfo.num_tags; t++) {