llm
Download
60 lines 2.2 KiBCModified 2026-09-17 raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
// `tomo eval`: evaluate a Tomo expression and print its result

#include <string.h>

#include "../config.h"
#include "../sha256.h"
#include "../stdlib/datatypes.h"
#include "../stdlib/path.h"
#include "../stdlib/print.h"
#include "../stdlib/result.h"
#include "../stdlib/text.h"
#include "commands.h"
#include "common.h"

static Text_t expr = EMPTY_TEXT;

static cli_arg_t eval_spec[] = {
    {"expr", &expr, &Text$info, .positional = true, .required = true, .metavar = "'<expr>'",
     .description = "the Tomo expression to evaluate"},
    OPTIMIZATION_FLAG,
    VERBOSE_FLAG,
};

static int cmd_eval(cli_command_t *self, List_t extra_args) {
    (void)self;
    set_default_logs(0);

    Path_t dir = Path$child(xdg_tomo_dir("XDG_STATE_HOME", "~/.local/state"), Texts("tomo@", TOMO_VERSION));
    Result_t created = Path$create_directory(dir, 0755, true);
    if (created.Failure.reason.tag != TEXT_NONE) print_err(created.Failure.reason);

    // Name the scratch file by a hash of its contents so that distinct
    // expressions never share a stale cached executable (the build system's
    // mtime staleness check has second granularity, which would otherwise
    // reuse the previous eval's binary for a different expression written in
    // the same second), while re-evaluating the same expression reuses its
    // cached build:
    const char *program_str = Text$as_c_string(expr);
    char hash[SHA256_HEX_SIZE];
    sha256_hex(program_str, strlen(program_str), hash);
    hash[12] = '\0';

    Path_t eval_file = Path$child(dir, Texts("eval-", Text$from_str(hash), ".tm"));
    if (!Path$exists(eval_file)) {
        Result_t written = Path$write(eval_file, expr, 0644);
        if (written.Failure.reason.tag != TEXT_NONE) print_err(written.Failure.reason);
    }

    return compile_and_exec(eval_file, extra_args, /*print_values=*/true);
}

cli_command_t eval_command = {
    .name = "eval",
    .summary = "Evaluate a Tomo expression and print its result",
    .description = "The expression is printed the way `>>` prints a value, with syntax coloring\n"
                   "when stdout is a terminal, e.g. `tomo eval '[n for n in 100 if n.is_prime()]'`. ",
    .spec_len = sizeof(eval_spec) / sizeof(eval_spec[0]),
    .spec = eval_spec,
    .handler = cmd_eval,
};