feat(argparse): 添加命令行参数约束和错误处理功能
- 添加了命令行参数约束相关数据结构定义 - 新增错误上下文字段用于更好的错误提示 - 实现了参数验证功能,包括必需参数检查和值选择验证 - 改进错误处理流程,支持添加帮助信息和使用说明 - 优化调试输出格式,增加更多错误场景的处理 fix(parser): 修复语义分析器资源释放问题 - 在scc_sema_drop函数中添加空指针检查,避免空指针释放导致崩溃 refactor(dump): 重构AST节点转储实现 - 将树形转储上下文重构为更简洁的数据结构 - 修改转储回调函数签名以支持更好的缓冲区管理 - 优化内存拷贝操作,提高转储性能 style(amd64): 移除未使用的变量声明 - 删除scc_mcode_amd64_mov_r64_m64_sib函数中未使用的disp8变量
This commit is contained in:
@@ -11,6 +11,8 @@ void scc_argparse_init(scc_argparse_t *parser, const char *program_name,
|
||||
parser->need_help = true;
|
||||
parser->need_version = true;
|
||||
parser->need_debug = false;
|
||||
parser->need_error_add_help = false;
|
||||
parser->need_error_add_usage = true;
|
||||
scc_argparse_cmd_init(&parser->root_cmd, parser->prog_name,
|
||||
parser->description);
|
||||
}
|
||||
@@ -37,9 +39,9 @@ static inline scc_argparse_cmd_t *is_subcommand(scc_argparse_cmd_t *cmd,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline void parse_cmd(scc_optparse_t *optparse,
|
||||
scc_optparse_opt_vec_t *opts,
|
||||
scc_argparse_cmd_t *cmd) {
|
||||
static inline void prepare_cmd(scc_optparse_t *optparse,
|
||||
scc_optparse_opt_vec_t *opts,
|
||||
scc_argparse_cmd_t *cmd) {
|
||||
scc_vec_free(*opts);
|
||||
scc_vec_init(*opts);
|
||||
scc_vec_foreach(cmd->opts, i) {
|
||||
@@ -85,6 +87,7 @@ static inline void parse_cmd(scc_optparse_t *optparse,
|
||||
scc_vec_push(*opts, (scc_optparse_opt_t)SCC_OPTPARSE_OPT_END());
|
||||
scc_optparse_set(optparse, opts->data);
|
||||
}
|
||||
|
||||
static void push_help(scc_argparse_cmd_t *cmd) {
|
||||
if (cmd == nullptr) {
|
||||
return;
|
||||
@@ -108,15 +111,12 @@ static void init_context(scc_argparse_context_t *ctx, scc_argparse_t *parser,
|
||||
}
|
||||
scc_optparse_init(&ctx->optparse, argc, argv);
|
||||
scc_vec_init(ctx->opts);
|
||||
parse_cmd(&ctx->optparse, &ctx->opts, ctx->current_cmd);
|
||||
prepare_cmd(&ctx->optparse, &ctx->opts, ctx->current_cmd);
|
||||
ctx->positional_index = 0;
|
||||
ctx->parsing_done = false;
|
||||
ctx->lang = parser->lang;
|
||||
}
|
||||
|
||||
static int handle_parse_error(scc_argparse_t *parser,
|
||||
scc_argparse_context_t *ctx) {
|
||||
(void)parser; // TODO
|
||||
static int transite_error(scc_argparse_context_t *ctx) {
|
||||
scc_argparse_err_t error = SCC_ARGPARSE_ERR_NONE;
|
||||
switch (ctx->result.error) {
|
||||
case SCC_OPT_ERROR_NOT_FOUND_SHORT_ARG:
|
||||
@@ -133,27 +133,68 @@ static int handle_parse_error(scc_argparse_t *parser,
|
||||
error = SCC_ARGPARSE_ERR_UNKNOWN_ERR;
|
||||
break;
|
||||
}
|
||||
scc_argparse_print_error(ctx, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int check_choices(const scc_argparse_spec_t *spec, const char *value) {
|
||||
if (!spec->choices.values || spec->choices.count == 0) {
|
||||
return SCC_ARGPARSE_ERR_NONE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < spec->choices.count; i += 1) {
|
||||
if (scc_strcmp(value, spec->choices.values[i]) == 0) {
|
||||
return SCC_ARGPARSE_ERR_NONE;
|
||||
}
|
||||
}
|
||||
return SCC_ARGPARSE_ERR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
static int validate_and_cleanup(scc_argparse_context_t *ctx,
|
||||
scc_argparse_t *parser, int errcode) {
|
||||
(void)parser; // TODO
|
||||
if (errcode == SCC_ARGPARSE_ERR_NONE) {
|
||||
// 检查必需参数是否都已提供
|
||||
scc_vec_foreach(ctx->current_cmd->args, i) {
|
||||
scc_argparse_arg_t *arg = &scc_vec_at(ctx->current_cmd->args, i);
|
||||
if (arg->spec.flag_required &&
|
||||
if (errcode != SCC_ARGPARSE_ERR_NONE) {
|
||||
goto END;
|
||||
}
|
||||
// 检查必需的位置参数
|
||||
scc_vec_foreach(ctx->current_cmd->args, i) {
|
||||
scc_argparse_arg_t *arg = &scc_vec_at(ctx->current_cmd->args, i);
|
||||
if (arg->spec.flag_required) {
|
||||
// 检查是否已存储(非空)
|
||||
if (arg->spec.store.str_store == nullptr ||
|
||||
*arg->spec.store.str_store == nullptr) {
|
||||
errcode = SCC_ARGPARSE_ERR_MISSING_ARG;
|
||||
scc_argparse_print_error(ctx, errcode);
|
||||
break;
|
||||
ctx->err_ctx = arg->name;
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
}
|
||||
scc_vec_foreach(ctx->current_cmd->opts, i) {
|
||||
scc_argparse_opt_t *opt = &scc_vec_at(ctx->current_cmd->opts, i);
|
||||
if (opt->spec.flag_required) {
|
||||
int provided = 0;
|
||||
if (opt->spec.flag_store_as_count) {
|
||||
provided = (opt->spec.store.int_store &&
|
||||
*opt->spec.store.int_store > 0);
|
||||
} else if (opt->spec.value_type == SCC_ARGPARSE_VAL_TYPE_BOOL) {
|
||||
provided =
|
||||
(opt->spec.store.bool_store && *opt->spec.store.bool_store);
|
||||
} else if (opt->spec.value_type == SCC_ARGPARSE_VAL_TYPE_LIST) {
|
||||
provided = (opt->spec.store.vec_store &&
|
||||
scc_vec_size(*opt->spec.store.vec_store) > 0);
|
||||
} else {
|
||||
provided = (opt->spec.store.str_store &&
|
||||
*opt->spec.store.str_store != nullptr);
|
||||
}
|
||||
if (!provided) {
|
||||
errcode = SCC_ARGPARSE_ERR_MISSING_ARG;
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清理资源
|
||||
END:
|
||||
if (errcode != SCC_ARGPARSE_ERR_NONE) {
|
||||
scc_argparse_print_error(ctx, parser, errcode);
|
||||
}
|
||||
scc_vec_free(ctx->opts);
|
||||
scc_optparse_drop(&ctx->optparse);
|
||||
return errcode;
|
||||
@@ -191,26 +232,6 @@ static int handle_option(scc_argparse_context_t *ctx, scc_argparse_t *parser) {
|
||||
*opt->spec.store.str_store = ctx->result.value;
|
||||
}
|
||||
|
||||
// // opt value == nullptr or value != nullptr
|
||||
// scc_argparse_opt_t *org_opt =
|
||||
// (scc_argparse_opt_t *)opt_res.opt->user_data;
|
||||
// if (parser->need_help) {
|
||||
// if (scc_strcmp(org_opt->long_name, "help") == 0) {
|
||||
// scc_argparse_print_help(parser, current_cmd);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (org_opt->spec.store_as_count) {
|
||||
// *org_opt->spec.store.int_store += 1;
|
||||
// }
|
||||
// if (org_opt->spec.value_type == SCC_ARGPARSE_VAL_TYPE_BOOL) {
|
||||
// *org_opt->spec.store.bool_store = true;
|
||||
// }
|
||||
// if (opt_res.value) {
|
||||
// org_opt->spec.raw_value = opt_res.value;
|
||||
// // TODO
|
||||
// *org_opt->spec.store.str_store = opt_res.value;
|
||||
// }
|
||||
return SCC_ARGPARSE_ERR_NONE;
|
||||
}
|
||||
|
||||
@@ -221,7 +242,7 @@ static int handle_positional_arg(scc_argparse_context_t *ctx,
|
||||
is_subcommand(ctx->current_cmd, ctx->result.value);
|
||||
if (subcmd != nullptr) {
|
||||
ctx->current_cmd = subcmd;
|
||||
parse_cmd(&ctx->optparse, &ctx->opts, ctx->current_cmd);
|
||||
prepare_cmd(&ctx->optparse, &ctx->opts, ctx->current_cmd);
|
||||
return SCC_ARGPARSE_ERR_NONE;
|
||||
}
|
||||
|
||||
@@ -232,28 +253,9 @@ static int handle_positional_arg(scc_argparse_context_t *ctx,
|
||||
arg->spec.raw_value = ctx->result.value;
|
||||
ctx->positional_index++;
|
||||
} else {
|
||||
scc_argparse_print_error(ctx, SCC_ARGPARSE_ERR_UNKNOWN_ARG);
|
||||
ctx->parsing_done = true;
|
||||
return SCC_ARGPARSE_ERR_UNKNOWN_ARG;
|
||||
}
|
||||
|
||||
// // position arg
|
||||
// scc_argparse_cmd_t *cmd = is_subcommand(current_cmd,
|
||||
// opt_res.value);
|
||||
|
||||
// if (cmd != nullptr) {
|
||||
// current_cmd = cmd;
|
||||
// parse_cmd(&optparse, &opts, current_cmd);
|
||||
// } else {
|
||||
// // TODO argument
|
||||
// scc_vec_foreach(current_cmd->args, i) {
|
||||
// scc_argparse_arg_t *arg = &scc_vec_at(current_cmd->args,
|
||||
// i); if (*arg->spec.store.str_store == 0) {
|
||||
// *arg->spec.store.str_store = opt_res.value;
|
||||
// arg->spec.raw_value = opt_res.value;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return SCC_ARGPARSE_ERR_NONE;
|
||||
}
|
||||
|
||||
@@ -265,14 +267,15 @@ int scc_argparse_parse(scc_argparse_t *parser, int argc, const char **argv) {
|
||||
while (!ctx.parsing_done &&
|
||||
scc_optparse_parse(&ctx.optparse, &ctx.result)) {
|
||||
if (parser->need_debug) {
|
||||
scc_printf("[%c:%s:%d] %s\n",
|
||||
scc_printf("debug:[%c:%s:%d] %s\n",
|
||||
ctx.result.opt ? ctx.result.opt->short_name : '-',
|
||||
ctx.result.opt ? ctx.result.opt->long_name : "--",
|
||||
ctx.result.error, ctx.result.value);
|
||||
ctx.result.error,
|
||||
ctx.result.value ? ctx.result.value : "<nullptr>");
|
||||
}
|
||||
|
||||
if (ctx.result.error) {
|
||||
errcode = handle_parse_error(parser, &ctx);
|
||||
errcode = transite_error(&ctx);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user