aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast.h1
-rw-r--r--src/compile/cli.c45
-rw-r--r--src/parse/functions.c26
-rw-r--r--src/tomo.c1
-rw-r--r--src/typecheck.c13
-rw-r--r--src/types.h1
6 files changed, 70 insertions, 17 deletions
diff --git a/src/ast.h b/src/ast.h
index 38959dd5..aaa2a993 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -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;
}
diff --git a/src/tomo.c b/src/tomo.c
index 8c73e7be..f260d528 100644
--- a/src/tomo.c
+++ b/src/tomo.c
@@ -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;