NAME
tomo - The programming language of tomorrow.
SYNOPSIS
tomo [global flags] [command] [command flags] [args...]
Run a program:
: tomo [run] program.tm [-- args...]
Build an executable:
: tomo build [-o output] program.tm
Build a package:
: tomo package [-o libname.a] [dir-or-file...]
DESCRIPTION
Tomo is a programming language that is statically typed, compiled, small, and garbage-collected, with concise syntax and built-in support for high-performance, low-overhead datastructures. It compiles by first outputting C code, which is then compiled using the Zig toolchain bundled with the Tomo installation.
A Tomo installation is relocatable: the tomo binary lives at
prefix/bin/tomo@version, and it locates its libraries, headers, bundled
toolchain, and man pages at startup relative to its own path (the prefix is
the grandparent directory of the binary), so the whole tree can be moved or
extracted into any prefix without rebuilding. The prefix is not fixed at build
time; set $TOMO_PATH to override the automatically determined location (see
ENVIRONMENT).
With no command, tomo file.tm runs the file (like tomo run), and bare
tomo opens a scratch file in $EDITOR to edit and run (or compiles and runs
a program piped in on standard input).
COMMANDS
Every command takes a --verbose/-v flag that turns on all build logs (the
compile steps, up-to-date "Unchanged" notices, and the toolchain commands being
run). Commands that print build progress by default (build, package,
install) also take --quiet/-q to silence it. The run-style commands
(tomo file.tm, run, eval) are silent by default: use tomo run -v
file.tm to see the compiler's work.
run [--instrument] [--debug] file.tm [-- args...]
: Compile and run the given program. Anything after -- is passed to the
program as its own arguments. The command name is optional: tomo file.tm
does the same thing. With --instrument, the program is compiled with
profiling instrumentation and prints a breakdown of where its time went when
it exits (see PROFILING). With --debug/-d, it runs under a debugger
that stops on breakpoint() calls, runtime errors, and fatal signals (see
DEBUGGING).
eval 'expr'
: Evaluate a Tomo expression and print its result. The argument may be several
statements separated by newlines or ; (for example tomo eval 'use random; random.int(1, 100)'); every statement that evaluates to something prints what
it evaluated to, with syntax coloring when standard output is a terminal. The
argument is ordinary Tomo source, so it can also declare variables and
functions and use other modules.
build [-o output] [--install] [--prefix dir] [-y]
[--instrument] [--debug] [--package-sources dir] [--skip-source]
file.tm
: Compile the given program to a standalone executable, placed as a sibling
of the .tm file (or at -o output). With --package-sources dir, pinned
packages are found by content digest in dir (a directory of package sources,
like the packages/ directory of an extracted source archive) instead of
being downloaded; run and test take the same flag. With --skip-source,
the program's sources are not embedded in the executable, which makes it
smaller but means tomo source cannot unpack it back into a buildable
project. With --instrument, the executable
is compiled with profiling instrumentation and prints a breakdown of where its
time went when it exits (see PROFILING). With --debug/-d, it is compiled
so a debugger can follow it (see DEBUGGING). With --install, the executable and
its generated manpage are also copied into a prefix's bin/ and man/man1/,
the installation prefix by default, or --prefix dir to choose another.
Existing files at those destinations are overwritten only after confirmation,
or immediately with --yes/-y; a warning is printed if the target bin/ is
not on your $PATH. Remove installed programs again with tomo uninstall
name.
transpile [--raw] [--instrument] [--debug] file.tm
: Transpile the given file to C and print the generated header and source to
standard output, each preceded by a // file: line. The output is formatted
with clang-format and (when standard output is a terminal)
syntax-highlighted with bat, whichever of the two is installed; --raw
prints the raw generated code instead. The generated .h/.c files are also
written into the file's .tomo/ directory.
parse file.tm...
: Print the parse tree of the given files as S-expressions.
format [-i] file.tm...
: Autoformat the given files and print them to standard output, or rewrite
them in place with --in-place/-i. Also available as fmt.
package [-o libname.a] [dir-or-file...]
: Build packages into static archives. With no arguments, the current
directory is built as a package: every .tm file not starting with an
underscore (or dot or digit) is compiled and archived into package.a.
Directory arguments are each built the same way; .tm file arguments are
compiled into a single archive. -o sets the archive path (single package
only).
uninstall [-y] [name-or-path...]
: With one or more arguments, uninstall those installed programs. Each
argument is either a bare name (looked up in the prefix's bin/) or a
path to a binary. A binary is removed only if it is a Tomo program (it
carries Tomo's embedded build info), and its Tomo-generated manpage in
man/man1/ is removed along with it. Files Tomo did not create are left
untouched, and a missing binary or manpage is only a warning. Install
programs with tomo build --install.
: With no arguments, uninstall this whole Tomo installation: remove this
version's files from the installation prefix, along with its per-user state,
cross-compilation target packs, and any bundled toolchains no remaining
installation shares. If other Tomo versions remain in the same prefix, the
tomo and man page symlinks are repointed to the newest one; otherwise they
are removed too. If no tomo remains anywhere on $PATH afterwards, the
cache (~/.cache/tomo: package downloads and the bundled Zig toolchain's
compile cache) is also cleared. Asks for confirmation unless --yes/-y is
given.
vendor [-e|-u] package...
: Copy the named packages' digest-verified source archives into the current
project's vendor/ directory and update ./packages.ini to use the vendored
copies as the primary sources (keeping the digest pins and demoting the
previous sources to fallbacks). With --editable/-e, extract each package's
sources into vendor/<name>/ and drop its digest pin, so the vendored copy
can be edited freely. With --unvendor/-u, undo vendoring: restore each
package's ./packages.ini entry to its first non-vendored fallback source
(or the compiler's default pin), re-install the package into the project's
package store (re-pinning the digest if editable vendoring dropped it), and
delete the vendored copy.
version
: Print the compiler version and exit (with --verbose/-v: plus the git
revision).
info binary...
: Print the build info embedded in the given compiled files (executables or
package archives).
source [-o dest] binary...
: List the contents of the source archive embedded in each of the given
compiled programs. With --output/-o dest, get the archive out instead
(one binary at a time): a dest ending in .zip is written as a zip file of
the archive itself, and any other dest is a directory to unpack into. The
extracted directory is a self-contained project: src/ holds the program's
sources, embedded files, and relatively-used C files, packages/ holds the
sources of every used package by content digest, licenses/ holds the license
texts, and a generated README.md and Makefile document and perform the
rebuild (plain make, or tomo build --package-sources ./packages on the
entry file), with no network access needed. Not every program carries an
archive: tomo build --skip-source leaves it out, and so do the executables
tomo run and tomo eval build, which are run once and discarded.
GLOBAL OPTIONS
Global options are valid anywhere on the command line, before or after the
command name. Command-specific flags (like build's -o) are only valid
after their command.
--help, -h
: Print the usage (or a command's usage) and exit.
--optimization level, -O level
: Set the optimization level.
--force-rebuild, -f
: Force rebuilding/recompiling.
--source-mapping=, -m= <yes|no>
: Toggle whether source mapping should be enabled or disabled.
--target platform
: Cross-compile for another platform instead of this machine's. The target
platform's libraries are installed on demand from its Tomo distribution
archive. Cross-compiled executables get the platform as a filename suffix
(e.g. foo.aarch64-macos) and cannot be run or installed on this machine.
Valid platforms are: x86_64-linux, aarch64-linux, riscv64-linux,
powerpc64le-linux, s390x-linux, x86_64-macos, aarch64-macos,
x86_64-freebsd, aarch64-freebsd, x86_64-netbsd, aarch64-netbsd,
x86_64-openbsd, and aarch64-openbsd.
--install-target
: When using --target, download and install the target platform's libraries
without asking for confirmation.
PROFILING
A program compiled with --instrument (tomo build --instrument file.tm,
or tomo run --instrument file.tm) times every function, conversion, and
lambda it defines, and prints a report to standard error when it exits: for
each function that ran, the number of calls, the time spent inside it (with
its callees' time subtracted), the time spent in it and everything it called,
and the per-call average, sorted by the first of those. The report is printed
even when the program exits early, fails, or crashes. Instrumented calls cost
around 13ns each (two reads of the CPU's cycle counter), charged to the calling
function, so --instrument is for finding where the time goes rather than for
measuring absolute speed.
Setting FLAME_GRAPH to a path additionally writes the call tree there as an
SVG flame graph: one box per frame, as wide as its share of the run and stacked
on the frame that called it, each carrying its details in a hover tooltip.
The program's own arguments are left alone; the report is controlled by
PROFILE, PROFILE_FILE, and FLAME_GRAPH (see ENVIRONMENT). See also
docs/profiling.md.
DEBUGGING
tomo run --debug file.tm runs a program under gdb(1), with Tomo's
debugger integration loaded into it. The program starts immediately and runs
as it normally would; it stops when something stops it, whether a
breakpoint() call in the source, a runtime error, a fatal signal, or an
interrupt, and leaves
you at a debugger prompt showing the Tomo function, the source around the line
it stopped on, and the Tomo variables in scope. A program that finishes on its
own leaves the debugger with its own exit status, exactly as tomo run would
have.
Because Tomo's generated C carries #line directives back to the .tm file,
gdb's own commands work in Tomo's terms: break file.tm:line, step,
next, finish, continue, list, watch, and conditional breakpoints all
behave as they would for a C program written in the .tm file. Function names
are reported as Tomo names rather than the mangled C symbols they compile to.
Commands are added on top of gdb's own: tlocals lists the Tomo variables in
scope, p var prints one of them, and tframe re-shows where the program is
stopped. frame, up, and down report the frame they select the way a stop
is reported: the Tomo name of the function, the source around the line, and the
variables in scope. backtrace (and bt/where) is likewise replaced by one
that prints the stack in Tomo's terms, helper(label="widgets", count=7),
with argument values cut short; gdb's own backtrace remains available as info stack. These print values with Tomo's own formatter, the same output say()
would produce with syntax coloring included, rather than the C structures they
compile to. gdb's own print does the same for values whose C type belongs to
exactly one Tomo type.
A Num is exact, so it prints exactly as 32768/3, pi, or
1/2 + sqrt(5)/2, and the debugger shows a rounded decimal beside it (32768/3 \[u2248] 10922.6666666667)
for the ones no decimal expresses. set tomo-num-digits n sets how many
fractional digits that carries, and 0 turns it off.
A Tomo value is formatted whole and the variables in scope are printed at every
stop, so values are cut off to keep one large one from
burying the screen, using gdb's own set print elements as the cutoff.
A Tomo variable x is _$x in the generated C, so a bare Tomo name typed at
gdb finds either nothing or some unrelated C symbol of that name. p (which
replaces gdb's alias for print) rewrites Tomo names to the C names
they compile to; print and every other command are untouched and still take C
names (a watchpoint on x is watch _$x), and anything p does not recognize is passed to print unchanged, so
format letters and value history behave as they always did.
--debug makes two changes to how the program is compiled. It defaults to
-O0 (an explicit -O still wins) so that the program a debugger sees is the
one that was written, and it emits, beside every variable, the type information
Tomo's formatter needs to print that variable, which is the only way a
debugger can show what is inside a list, table, or optional, since those do not
record their contents in their C type.
breakpoint() is a built-in that stops the program where it is called. Only a
program compiled with --debug contains it at all: without that flag it
compiles to nothing, so leaving one in the source costs a release build
nothing.
Runtime errors stop in the debugger too. tomo run --debug sets
TOMO_CORE_DUMP, which makes fail(), a failed assertion, or an out-of-range
access raise SIGABRT after printing its usual report, instead of exiting, so
the failing frame and its variables are still there to look at. SIGSEGV,
SIGFPE, SIGILL, SIGBUS, and SIGSYS stop the same way; an interrupt
(SIGINT) stops the program without killing it, so continue resumes.
--debug is also available on build, transpile, and test. A program
built with it can be started under the debugger by hand by loading
prefix/lib/tomo@version/tomo-gdb.py with gdb -x. See also
docs/debugging.md.
ENVIRONMENT
TOMO_PATH
: The installation prefix Tomo compiles and links against (its lib/,
include/, libexec/, and man/ trees) and installs into. By default this
is determined at runtime from the location of the running tomo binary (the
grandparent of the resolved executable path), so an installation is
relocatable. Set TOMO_PATH to override it, for example to point at a tree in
an unusual location or one whose tomo binary has been copied away from its
sibling directories.
TOMO_DIST_URL
: Base URL for downloading distribution archives (used by --target and
--install-target to fetch a target platform's libraries). Defaults to
https://tomo.bruce-hill.com/dist.
EDITOR
: The editor bare tomo opens the scratch file in. Defaults to vim.
NO_COLOR, COLOR
: Set NO_COLOR to any non-empty value to disable colored output. Set COLOR
to 1 to force it on; otherwise color is used only when standard output is a
terminal.
TOMO_STACKTRACE, TOMO_PLAIN_ERRORS, TOMO_CORE_DUMP
: Diagnostics for compiler and runtime errors: TOMO_STACKTRACE prints a
stack trace on errors, TOMO_PLAIN_ERRORS disables the fancy source-quoting
error formatting, and setting TOMO_CORE_DUMP to a truthy value makes a fatal
error abort (dumping core) instead of exiting cleanly.
TOMO_TEST_FILTER, TOMO_TEST_TIMEOUT, TOMO_TEST_VERBOSE
: Control tomo test runs: only run tests whose label contains
TOMO_TEST_FILTER, cap each test at TOMO_TEST_TIMEOUT seconds, and print
verbose output when TOMO_TEST_VERBOSE is set.
PROFILE, PROFILE_FILE, FLAME_GRAPH
: Control the profile report of a program compiled with --instrument (see
PROFILING). Setting PROFILE to 0 (or no/false) makes the program
collect nothing and print nothing, so an instrumented binary can also be run
as a normal one. PROFILE_FILE writes the table to that path instead of
standard error (- means standard output). FLAME_GRAPH writes an SVG flame
graph to that path as well as the table. All three are read by the compiled
program, not by tomo.
TOMO_DEBUGGER
: The debugger tomo run --debug launches. Defaults to gdb, found on
$PATH; set this to use a different gdb build or a gdb-compatible debugger
(see DEBUGGING).
ZIG_GLOBAL_CACHE_DIR
: Where the bundled Zig toolchain keeps its global compile cache. If unset,
Tomo points it at its own cache directory (under $XDG_CACHE_HOME/tomo) rather
than Zig's default, so it never mingles with a separately-run Zig's cache; an
explicit value is respected.
FILES
prefix/bin/tomo@version
: The compiler binary, with a bin/tomo symlink to the newest coresident
version. Programs installed with tomo build --install also land in
prefix/bin/.
prefix/lib/tomo@version/, prefix/include/tomo@version/
: The Tomo standard library archive and headers this version links against.
prefix/lib/tomo@version/tomo-gdb.py
: Tomo's debugger integration, loaded into gdb by tomo run --debug (see
DEBUGGING).
prefix/man/man1/
: Man pages, including those installed for programs built with tomo build --install.