diff options
| -rw-r--r-- | src/ast.h | 1 | ||||
| -rw-r--r-- | src/compile/cli.c | 45 | ||||
| -rw-r--r-- | src/parse/functions.c | 26 | ||||
| -rw-r--r-- | src/tomo.c | 1 | ||||
| -rw-r--r-- | src/typecheck.c | 13 | ||||
| -rw-r--r-- | src/types.h | 1 |
6 files changed, 70 insertions, 17 deletions
@@ -68,6 +68,7 @@ typedef struct arg_ast_s { file_t *file; const char *start, *end; const char *name, *alias; + Text_t comment; type_ast_t *type; ast_t *value; struct arg_ast_s *next; diff --git a/src/compile/cli.c b/src/compile/cli.c index 3337e250..71943a17 100644 --- a/src/compile/cli.c +++ b/src/compile/cli.c @@ -20,10 +20,23 @@ static Text_t get_flag_options(type_t *t, const char *separator) { if (tag->next) options = Texts(options, separator); } return options; - } else if (t->tag == IntType || t->tag == NumType || t->tag == BigIntType) { + } else if (t->tag == StructType) { + Text_t options = EMPTY_TEXT; + for (arg_t *field = Match(t, StructType)->fields; field; field = field->next) { + options = Texts(options, get_flag_options(field->type, separator)); + if (field->next) options = Texts(options, separator); + } + return options; + } else if (is_numeric_type(t)) { return Text("N"); + } else if (t->tag == TextType || t->tag == CStringType) { + return Text("text"); + } else if (t->tag == ListType || (t->tag == TableType && Match(t, TableType)->value_type == EMPTY_TYPE)) { + return Text("value1 value2..."); + } else if (t->tag == TableType) { + return Text("key1:value1 key2:value2..."); } else { - return Text("..."); + return Text("value"); } } @@ -81,10 +94,32 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c } } code = Texts(code, - "Text_t usage = Texts(Text(\"Usage: \"), " + "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 = 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 = alias_flag.tag != TEXT_NONE ? Texts(flag, "|", alias_flag) : flag; + if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType)) + help_text = Texts(help_text, " \x1b[1m", flags, "|--no-", flag, "\x1b[m"); + else help_text = Texts(help_text, " \x1b[1m", flags, " \x1b[34m", get_flag_options(t, "|"), "\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[2mdefault:", default_text, "\x1b[m"); + } + if (arg->comment.length > 0) help_text = Texts(help_text, " \x1b[3m", arg->comment, "\x1b[m"); + } + code = Texts(code, "Text_t help = Texts(usage, ", quoted_text(help_text), ");\n"); + help_code = Text("help"); + } for (arg_t *arg = fn_info->args; arg; arg = arg->next) { code = Texts(code, compile_declaration(arg->type, Texts("_$", Text$from_str(arg->name))), " = ", @@ -162,6 +197,10 @@ Text_t compile_manpage(Text_t program, OptionalText_t synopsis, OptionalText_t d } else { man = Texts(man, " \\f[I]value\\f[R]"); } + + if (arg->comment.length > 0) { + man = Texts(man, "\n", arg->comment); + } } return man; diff --git a/src/parse/functions.c b/src/parse/functions.c index ea20e385..8fb9f78e 100644 --- a/src/parse/functions.c +++ b/src/parse/functions.c @@ -9,6 +9,9 @@ #include <uniname.h> #include "../ast.h" +#include "../formatter/utils.h" +#include "../stdlib/datatypes.h" +#include "../stdlib/text.h" #include "../stdlib/util.h" #include "context.h" #include "controlflow.h" @@ -19,6 +22,7 @@ #include "utils.h" arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos) { + const char *comment_start = *pos; arg_ast_t *args = NULL; for (;;) { const char *batch_start = *pos; @@ -28,6 +32,7 @@ arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos) { typedef struct name_list_s { const char *start, *end; const char *name, *alias; + Text_t comment; struct name_list_s *next; } name_list_t; @@ -46,21 +51,28 @@ arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos) { if (!alias) parser_err(ctx, *pos, *pos, "I expected an argument alias after `|`"); } + Text_t comments = EMPTY_TEXT; + for (OptionalText_t com; + (com = next_comment(ctx->comments, &comment_start, name_start)).tag != TEXT_NONE;) { + if (comments.length > 0) comments = Texts(comments, " "); + comments = Texts(comments, Text$trim(Text$without_prefix(com, Text("#")), Text(" \t"), true, true)); + } + if (match(pos, ":")) { type = expect(ctx, *pos, pos, parse_type, "I expected a type here"); whitespace(ctx, pos); if (match(pos, "=")) default_val = expect(ctx, *pos, pos, parse_term, "I expected a value here"); - names = - new (name_list_t, .start = name_start, .end = *pos, .name = name, .alias = alias, .next = names); + names = new (name_list_t, .start = name_start, .end = *pos, .name = name, .alias = alias, .next = names, + .comment = comments); break; } else if (strncmp(*pos, "==", 2) != 0 && match(pos, "=")) { default_val = expect(ctx, *pos, pos, parse_term, "I expected a value here"); - names = - new (name_list_t, .start = name_start, .end = *pos, .name = name, .alias = alias, .next = names); + names = new (name_list_t, .start = name_start, .end = *pos, .name = name, .alias = alias, .next = names, + .comment = comments); break; } else if (name) { - names = - new (name_list_t, .start = name_start, .end = *pos, .name = name, .alias = alias, .next = names); + names = new (name_list_t, .start = name_start, .end = *pos, .name = name, .alias = alias, .next = names, + .comment = comments); spaces(pos); if (!match(pos, ",")) break; } else { @@ -76,7 +88,7 @@ arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos) { REVERSE_LIST(names); for (; names; names = names->next) args = new (arg_ast_t, .start = names->start, .end = names->end, .name = names->name, .alias = names->alias, - .type = type, .value = default_val, .next = args); + .comment = names->comment, .type = type, .value = default_val, .next = args); if (!match_separator(ctx, pos)) break; } @@ -29,7 +29,6 @@ #include "stdlib/cli.h" #include "stdlib/datatypes.h" #include "stdlib/lists.h" -#include "stdlib/metamethods.h" #include "stdlib/optionals.h" #include "stdlib/paths.h" #include "stdlib/print.h" diff --git a/src/typecheck.c b/src/typecheck.c index 1ce88806..9c4ab5b8 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -93,7 +93,7 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast) { "longer exist on the stack."); arg_t *type_args = NULL; for (arg_ast_t *arg = fn->args; arg; arg = arg->next) { - type_args = new (arg_t, .name = arg->name, .alias = arg->alias, .next = type_args); + type_args = new (arg_t, .name = arg->name, .alias = arg->alias, .comment = arg->comment, .next = type_args); if (arg->type) type_args->type = parse_type_ast(env, arg->type); else if (arg->value) type_args->type = get_type(env, arg->value); @@ -135,7 +135,7 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast) { type_t *field_type = field_ast->type ? parse_type_ast(env, field_ast->type) : get_type(env, field_ast->value); fields = new (arg_t, .name = field_ast->name, .type = field_type, .default_val = field_ast->value, - .next = fields); + .alias = field_ast->alias, .comment = field_ast->comment, .next = fields); } REVERSE_LIST(fields); const char *struct_name = String(enum_name, "$", tag_ast->name); @@ -420,7 +420,7 @@ void bind_statement(env_t *env, ast_t *statement) { type_to_text(field_t), " pointer for this field."); } fields = new (arg_t, .name = field_ast->name, .alias = field_ast->alias, .type = field_t, - .default_val = field_ast->value, .next = fields); + .comment = field_ast->comment, .default_val = field_ast->value, .next = fields); } REVERSE_LIST(fields); type->__data.StructType.fields = fields; // populate placeholder @@ -476,7 +476,7 @@ void bind_statement(env_t *env, ast_t *statement) { type_to_text(field_t), " pointer for this field."); } fields = new (arg_t, .name = field_ast->name, .alias = field_ast->alias, .type = field_t, - .default_val = field_ast->value, .next = fields); + .comment = field_ast->comment, .default_val = field_ast->value, .next = fields); } REVERSE_LIST(fields); env_t *member_ns = namespace_env(env, String(def->name, "$", tag_ast->name)); @@ -590,7 +590,8 @@ type_t *get_function_type(env_t *env, ast_t *ast) { env_t *scope = fresh_scope(env); for (arg_ast_t *arg = arg_asts; arg; arg = arg->next) { type_t *t = arg->type ? parse_type_ast(env, arg->type) : get_type(env, arg->value); - args = new (arg_t, .name = arg->name, .alias = arg->alias, .type = t, .default_val = arg->value, .next = args); + args = new (arg_t, .name = arg->name, .alias = arg->alias, .comment = arg->comment, .type = t, + .default_val = arg->value, .next = args); set_binding(scope, arg->name, t, EMPTY_TEXT); } REVERSE_LIST(args); @@ -917,7 +918,7 @@ type_t *get_type(env_t *env, ast_t *ast) { arg_t *arg_types = NULL; for (arg_ast_t *arg = call->args; arg; arg = arg->next) arg_types = new (arg_t, .type = get_type(env, arg->value), .name = arg->name, .alias = arg->alias, - .next = arg_types); + .comment = arg->comment, .next = arg_types); REVERSE_LIST(arg_types); code_err(call->fn, "I couldn't find a type constructor for ", type_to_text(Type(FunctionType, .args = arg_types, .ret = t))); diff --git a/src/types.h b/src/types.h index 05a97333..2a94a512 100644 --- a/src/types.h +++ b/src/types.h @@ -12,6 +12,7 @@ typedef struct arg_s { const char *name, *alias; type_t *type; ast_t *default_val; + Text_t comment; struct arg_s *next; } arg_t; |
