aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-05-17 16:31:37 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-05-17 16:31:37 -0400
commit4636eeb4bf93b260e5c5cbecfb18c8c9b2a6976d (patch)
tree64520e477f3b5d80354553a006a10565ff1546d0
parent13e7d04a74f7ad0b9b9dc96f681d091b65dce5ec (diff)
Add --version flag for executables and more documentation.
-rw-r--r--docs/versions.md21
-rw-r--r--src/compile.c5
-rw-r--r--src/compile.h2
-rw-r--r--src/stdlib/stdlib.c12
-rw-r--r--src/stdlib/stdlib.h6
-rw-r--r--src/tomo.c33
6 files changed, 47 insertions, 32 deletions
diff --git a/docs/versions.md b/docs/versions.md
index 6297dbfd..db7a1036 100644
--- a/docs/versions.md
+++ b/docs/versions.md
@@ -51,6 +51,27 @@ The version for the Tomo language itself will come into play in a few ways:
4. Tomo libraries will be installed to a separate subdirectory for each version
of the compiler (e.g. `~/.local/share/tomo_v1.2/installed`).
+## Tomo Program Versions
+
+When you write a Tomo program (say, `foo.tm`) and run it, Tomo will
+automatically add support for parsing a version number out of an accompanying
+`CHANGES.md` file in the same directory. You can use the `--version` flag to
+print the version number and exit. For example, if I run `tomo foo.tm --
+--version`, it will print `v0.0` if no `CHANGES.md` file exists, otherwise it
+will compile the program with the most recent version number from that file and
+print it instead. Similarly, if you run `tomo -e foo.tm` to build `foo` as a
+standalone executable and then run `./foo --version`, it will print the version
+number and exit without running the program.
+
+## Tomo Library Versions
+
+Tomo libraries also have version numbers. When you install a library, its
+version number will be used to determine its installation location and how it's
+used in code. You must either explicitly import the library with its version
+number (e.g. `use foo_v1.2`) or include a `modules.ini` configuration file that
+maps a shorthand alias to a specific version of a library. For example, if the
+`modules.ini` file has `foo=foo_v1.2`, you can put `use foo` to use v1.2 of the
+`foo` library (assuming you have it installed).
# Rationale
diff --git a/src/compile.c b/src/compile.c
index 410ee364..cd6aef72 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -4015,7 +4015,7 @@ static CORD get_flag_options(type_t *t, CORD separator)
}
}
-CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type)
+CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type, const char *version)
{
DeclareMatch(fn_info, fn_type, FunctionType);
@@ -4084,7 +4084,8 @@ CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type)
code = CORD_all(code, ";\n");
}
- code = CORD_all(code, "tomo_parse_args(argc, argv, ", usage_code, ", ", help_code);
+ CORD version_code = CORD_quoted(version);
+ code = CORD_all(code, "tomo_parse_args(argc, argv, ", usage_code, ", ", help_code, ", ", version_code);
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
code = CORD_all(code, ",\n{", CORD_quoted(CORD_replace(arg->name, "_", "-")), ", ",
(arg->default_val || arg->type->tag == OptionalType) ? "false" : "true", ", ",
diff --git a/src/compile.h b/src/compile.h
index ae9e510b..f4452288 100644
--- a/src/compile.h
+++ b/src/compile.h
@@ -20,6 +20,6 @@ CORD compile_statement(env_t *env, ast_t *ast);
CORD compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast);
CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast);
CORD compile_type_info(type_t *t);
-CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type);
+CORD compile_cli_arg_call(env_t *env, CORD fn_name, type_t *fn_type, const char *version);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/stdlib.c b/src/stdlib/stdlib.c
index 6a855c66..6dfc735b 100644
--- a/src/stdlib/stdlib.c
+++ b/src/stdlib/stdlib.c
@@ -232,7 +232,7 @@ static Table_t parse_table(const TypeInfo_t *table, int n, char *args[])
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstack-protector"
#endif
-public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, int spec_len, cli_arg_t spec[spec_len])
+public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, cli_arg_t spec[spec_len])
{
bool populated_args[spec_len];
bool used_args[argc];
@@ -310,7 +310,11 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
}
if (streq(argv[i], "--help")) {
- say(help, true);
+ print(help);
+ exit(0);
+ }
+ if (streq(argv[i], "--version")) {
+ print(version);
exit(0);
}
print_err("Unrecognized argument: ", argv[i], "\n", usage);
@@ -361,7 +365,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
}
if (*f == 'h') {
- say(help, true);
+ print(help);
exit(0);
}
print_err("Unrecognized flag: ", flag, "\n", usage);
@@ -554,7 +558,7 @@ public void say(Text_t text, bool newline)
public _Noreturn void tomo_exit(Text_t text, int32_t status)
{
if (text.length > 0)
- say(text, true);
+ print(text);
_exit(status);
}
diff --git a/src/stdlib/stdlib.h b/src/stdlib/stdlib.h
index 04c504fe..2dd3c5b7 100644
--- a/src/stdlib/stdlib.h
+++ b/src/stdlib/stdlib.h
@@ -25,9 +25,9 @@ typedef struct {
} cli_arg_t;
void tomo_init(void);
-void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, int spec_len, cli_arg_t spec[spec_len]);
-#define tomo_parse_args(argc, argv, usage, help, ...) \
- _tomo_parse_args(argc, argv, usage, help, sizeof((cli_arg_t[]){__VA_ARGS__})/sizeof(cli_arg_t), (cli_arg_t[]){__VA_ARGS__})
+void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, cli_arg_t spec[spec_len]);
+#define tomo_parse_args(argc, argv, usage, help, version, ...) \
+ _tomo_parse_args(argc, argv, usage, help, version, sizeof((cli_arg_t[]){__VA_ARGS__})/sizeof(cli_arg_t), (cli_arg_t[]){__VA_ARGS__})
#define fail(...) ({ \
fflush(stdout); \
diff --git a/src/tomo.c b/src/tomo.c
index 3fcd0ade..24a407a4 100644
--- a/src/tomo.c
+++ b/src/tomo.c
@@ -62,7 +62,6 @@ static OptionalList_t files = NONE_LIST,
uninstall = NONE_LIST,
libraries = NONE_LIST;
static OptionalBool_t verbose = false,
- show_version = false,
quiet = false,
show_parse_tree = false,
stop_at_transpile = false,
@@ -183,12 +182,11 @@ int main(int argc, char *argv[])
);
Text_t help = Texts(Text("\x1b[1mtomo\x1b[m: a compiler for the Tomo programming language"), Text("\n\n"), usage);
tomo_parse_args(
- argc, argv, usage, help,
+ argc, argv, usage, help, TOMO_VERSION,
{"files", true, List$info(&Path$info), &files},
{"args", true, List$info(&Text$info), &args},
{"verbose", false, &Bool$info, &verbose},
{"v", false, &Bool$info, &verbose},
- {"version", false, &Bool$info, &show_version},
{"parse", false, &Bool$info, &show_parse_tree},
{"p", false, &Bool$info, &show_parse_tree},
{"quiet", false, &Bool$info, &quiet},
@@ -215,14 +213,6 @@ int main(int argc, char *argv[])
{"m", false, &Bool$info, &source_mapping},
);
- if (show_version) {
- if (verbose)
- print("Tomo version: ", TOMO_VERSION, " (", GIT_VERSION, ")");
- else
- print("Tomo version: ", TOMO_VERSION);
- return 0;
- }
-
bool is_gcc = (system(String(cc, " -v 2>&1 | grep -q 'gcc version'")) == 0);
if (is_gcc) {
cflags = Texts(cflags, Text(" -fsanitize=signed-integer-overflow -fno-sanitize-recover"
@@ -371,25 +361,23 @@ Path_t build_file(Path_t path, const char *extension)
return Path$child(build_dir, Texts(Path$base_name(path), Text$from_str(extension)));
}
-static Text_t get_version_suffix(Path_t lib_dir)
+static const char *get_version(Path_t lib_dir)
{
Path_t changes_file = Path$child(lib_dir, Text("CHANGES.md"));
OptionalText_t changes = Path$read(changes_file);
if (changes.length <= 0) {
- print_err("I couldn't find a valid CHANGES.md for the library in ", lib_dir, "\n"
- "In order to install a library, it has to have a version defined in CHANGES.md\n"
- "\n"
- "Example CHANGES.md:\n"
- "\n"
- "# Version History\n"
- "## v0.1\n"
- "First version");
+ return "v0.0";
}
const char *changes_str = Text$as_c_string(Texts(Text("\n"), changes));
const char *version_line = strstr(changes_str, "\n## ");
if (version_line == NULL)
print_err("CHANGES.md in ", lib_dir, " does not have any valid versions starting with '## '");
- return Texts(Text("_"), Text$from_strn(version_line + 4, strcspn(version_line + 4, "\r\n")));
+ return String(string_slice(version_line + 4, strcspn(version_line + 4, "\r\n")));
+}
+
+static Text_t get_version_suffix(Path_t lib_dir)
+{
+ return Texts(Text("_"), Text$from_str(get_version(lib_dir)));
}
void build_library(Path_t lib_dir)
@@ -721,6 +709,7 @@ void transpile_code(env_t *base_env, Path_t path)
CORD_put(c_code, c_file);
+ const char *version = get_version(Path$parent(path));
binding_t *main_binding = get_binding(module_env, "main");
if (main_binding && main_binding->type->tag == FunctionType) {
type_t *ret = Match(main_binding->type, FunctionType)->ret;
@@ -735,7 +724,7 @@ void transpile_code(env_t *base_env, Path_t path)
"tomo_init();\n",
namespace_name(module_env, module_env->namespace, "$initialize"), "();\n"
"\n",
- compile_cli_arg_call(module_env, main_binding->code, main_binding->type),
+ compile_cli_arg_call(module_env, main_binding->code, main_binding->type, version),
"return 0;\n"
"}\n"), c_file);
}