code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(251 lines)

Changes

2026-03-14

  • Added Path.each_child() and Path.walk() for iterating over files without the need to allocate a list of every iterated file.
  • Added Text.matches_glob(glob) and Path.matches_glob(glob)
  • Overhaul to package system (previously: modules)

2026-02-08

  • Path syntax no longer requires parentheses, any value starting with ., /, or ~ is treated as a path.
  • Changed Path implementation to use C-style strings instead of an enum with array components.
  • Added Text.distance(a,b) for calculating text distances.
  • List.random() now returns an optional value, which is none when the list is empty, instead of failing.
  • Improved error messages for misspelled variables and field/method names.

2025-12-31

  • Added support for 123.foo() parsing the same as (123).foo()
  • Changed is_between() to be bidirectional so 5.is_between(10, 1) == yes

2025-12-23.2

  • Fixes for OpenBSD and Mac.

2025-12-23

  • Improved C preprocessing performance by eliminating expensive macro calls.

2025-12-22

  • Use static linking instead of dynamic linking for the Tomo standard library as well as for user libraries. This produces binaries that do not depend on having Tomo and the library installed at runtime.
  • Added Path.writer() and Path.byte_writer() for multiple successive writes

2025-12-21.6

  • Add smarter default behavior if run without any args (REPL-like script runner)

2025-12-21.5

  • Various fixes for versioning and builds.

2025-12-21.4

  • Version bump and deprecated --changelog flag

2025-12-21.3

  • Version bump

2025-12-21.2

  • Update build process

2025-12-21

  • You can now discard empty struct values.
  • For an enum Foo(A,B,C), the syntax f! now desugars to f.A! using the first tag defined in the enum.
  • Error messages are more helpful for foo.Whatever! enum field accessing.
  • Simplified logic for enums so there is less difference between enums that have tags with member fields and those without.
  • Rename Empty() to Present() for set-like tables.
  • Paths are now an enum Path(AbsolutePath(components:[Text]), RelativePath(components:[Text]), HomePath(components:[Text]))
  • Added enum Result(Success, Failure(message:Text)) type for indicating success or failure.
  • Some path methods now use Result return types instead of failing:
    • Path.append()
    • Path.append_bytes()
    • Path.create_directory()
    • Path.remove()
    • Path.set_owner()
    • Path.write()
    • Path.write_bytes()
  • Path.parent() returns none if path is (/) (file root)
  • Added check for unused variables.

2025-11-30

API changes

  • Added base parameter to various Int.parse() methods to allow explicitly setting the numeric base from 1-36.

Bugfixes

  • Fixed various issues around parsing integers.

v2025-11-29.2

Bugfixes

  • Fix for undefined behavior on enums and structs with padding.

2025-11-29

Syntax changes

  • Syntax for tables has changed to use colons ({k: v}) instead of equals ({k=v}).
  • Syntax for text literals and inline C code has been simplified.
  • Added metadata format instead of _HELP/_USAGE:
    HELP: "Help text"
    USAGE: "Usage text"
    MANPAGE_SYNOPSYS: "Synopsys..."
    MANPAGE_DESCRIPTION: (./description.txt)
    
  • Deprecated: extern keyword for declaring external symbols from C.
    • Use C_code instead.
  • Deprecated: postfix ? to make values optional.
    • Explicitly optional values can be declared as my_var : T? = value.
  • Deprecated: >> ... = ... form of doctests. They are now called "debug logs" and you can specify multiple values: >> a, b, c
  • Deprecated: extend blocks
  • Deprecated: deserialize operation and .serialized() method call
    • Instead, convert to and from [Byte]

Versioning and library changes

  • Tomo versioning now uses dates instead of semantic versioning.
  • Tomo libraries are now installed to $TOMO_PATH/lib/tomo@TOMO_VERSION/library@LIBRARY_VERSION instead of $TOMO_PATH/share/tomo_TOMO_VERSION/installed/module_LIBRARY_VERSION
  • Core libraries are no longer shipped with the compiler, they have moved to separate repositories.
  • Library installation has been cleaned up a bit.

Type Changes

  • List indexing now gives an optional value.
  • Added support for inline anonymous enums
  • Accessing a field on an enum now gives an optional value instead of a boolean.
  • Deprecated: Sets are no longer a separate type with separate methods.
    • Instead of sets, use tables with a value type of {KeyType:Empty}.
    • As a shorthand, you can use {a,b,c} instead of {a:Empty(), b:Empty(), c:Empty()} and the type annotation {K} as shorthand for {K:Empty}.
  • Added Empty for a built-in empty struct type and EMPTY for an instance of the empty struct.
  • Struct fields that start with underscores can be accessed again and function arguments that start with underscore can be passed (but only as keyword arguments).

API changes

  • Added Path.lines().
  • Added Text.find(text, target, start=1).
  • Added at_cleanup() to register cleanup functions.
  • Added recursive argument to Path.create_directory() to create parent directories if needed.
  • setenv() now takes an optional parameter for value, which allows for unsetting environment values.
  • Tables now have and, or, xor, and - (minus) metamethods.
  • Added table.with(other), table.without(other), table.intersection(other), and table.difference(other).
  • Changed list.unique() to return a table with Empty() values for each unique list item.
  • Added a --format flag to the tomo binary that autoformats your code (currently unstable, do not rely on it just yet).
  • Standardized text methods for Unicode encodings:
    • Text.from_utf8()/Text.utf8()
    • Text.from_utf16()/Text.utf16()
    • Text.from_utf32()/Text.utf32()

Bug fixes

  • Int.parse() had a memory bug.
  • Breaking out of a for line in file.by_line()! loop would leak file handle resources, which could lead to exhausting the number of open file handles. When that happens, the standard library now forces a GC collection to clean up resources, which can result in file handles being freed up.
  • & references failed to propagate when accessing fields like foo.baz.method() when foo is a &Foo and baz.method() takes a &Baz.
  • Optional paths no longer fail to compile when you check them for none.
  • Text replacement no longer infinitely loops when given an empty text to replace.
  • Short CLI flag aliases now no longer use the first letter of the argument.
  • Stack memory was not correctly detected in some cases, leading to potential memory errors.

Other changes

  • Added automatic manpage generation.
  • Major improvements to robustness of CLI argument parsing.

v0.3

  • Added a versioning system based on CHANGES.md files and modules.ini configuration for module aliases.
  • When attempting to run a program with a module that is not installed, Tomo can prompt the user to automatically install it.
  • Programs can use --version as a CLI flag to print a Tomo program's version number and exit.
  • Significant improvements to type inference to allow more expressions to be compiled into known types in a less verbose manner. For example:
    enum NumberOrText(Number(n:Num), SomeText(text:Text))
    func needs_number_or_text(n:NumberOrText)
        >> n
    func main()
        needs_number_or_text(123)
        needs_number_or_text(123.5)
        needs_number_or_text("Hello")
    
  • Added tomo --prefix to print the Tomo install prefix.
  • Sets now support infix operations for and, or, xor, and -.
  • Added new json module for JSON parsing and encoding.
  • Added Path.sibling().
  • Added Path.has_extension().
  • Added Table.with_fallback().
  • Added Int*.get_bit() and Byte.get_bit().
  • Added Byte.parse() to parse bytes from text.
  • Added optional remainder parameter to parse() methods, which (if non-none) receives the remaining text after the match. If none, the match will fail unless it consumes the whole text.
  • Added optional remainder parameter to Text.starts_with() and Text.ends_with() to allow you to get the rest of the text without two function calls.
  • Improved space efficiency of Text that contains non-ASCII codepoints.
  • Doctests now use equality checking instead of converting to text.
  • Fixed the following bugs:
    • Negative integers weren't converting to text properly.
    • Mutation of a collection during iteration was violating value semantics.
    • extend statements weren't properly checking that the type name was valid.
    • Lazy recompilation wasn't happening when use ./foo.c was used for local C/assembly files or their #includes.
    • Memory offsets for enums with different member alignments were miscalculated.
    • Optional types with trailing padding were not correctly being detected as none
    • Tomo identifiers that happened to coincide with C keywords were not allowed.
    • Compatibility issues caused compilation failure on some platforms.

v0.2

  • Improved compatibility on different platforms.
  • Switched to use a per-file unique ID suffix instead of renaming symbols after compilation with objcopy.
  • Installation process now sets user permissions as needed, which fixes an issue where a user not in the sudoers file couldn't install even to a local directory.
  • Fixed some bugs with Table and Text hashing.
  • Various other bugfixes and internal optimizations.

v0.1

First version to get a version number.

1 # Changes
3 ## 2026-03-14
5 - Added `Path.each_child()` and `Path.walk()` for iterating over files without
6 the need to allocate a list of every iterated file.
7 - Added `Text.matches_glob(glob)` and `Path.matches_glob(glob)`
8 - Overhaul to package system (previously: modules)
10 ## 2026-02-08
12 - Path syntax no longer requires parentheses, any value starting with `.`, `/`,
13 or `~` is treated as a path.
14 - Changed `Path` implementation to use C-style strings instead of an `enum`
15 with array components.
16 - Added `Text.distance(a,b)` for calculating text distances.
17 - `List.random()` now returns an optional value, which is `none` when the list
18 is empty, instead of failing.
19 - Improved error messages for misspelled variables and field/method names.
21 ## 2025-12-31
23 - Added support for `123.foo()` parsing the same as `(123).foo()`
24 - Changed `is_between()` to be bidirectional so `5.is_between(10, 1) == yes`
26 ## 2025-12-23.2
28 - Fixes for OpenBSD and Mac.
30 ## 2025-12-23
32 - Improved C preprocessing performance by eliminating expensive macro calls.
34 ## 2025-12-22
36 - Use static linking instead of dynamic linking for the Tomo standard library
37 as well as for user libraries. This produces binaries that do not depend on
38 having Tomo and the library installed at runtime.
39 - Added `Path.writer()` and `Path.byte_writer()` for multiple successive writes
41 ## 2025-12-21.6
43 - Add smarter default behavior if run without any args (REPL-like script runner)
45 ## 2025-12-21.5
47 - Various fixes for versioning and builds.
49 ## 2025-12-21.4
51 - Version bump and deprecated `--changelog` flag
53 ## 2025-12-21.3
55 - Version bump
57 ## 2025-12-21.2
59 - Update build process
61 ## 2025-12-21
63 - You can now discard empty struct values.
64 - For an enum `Foo(A,B,C)`, the syntax `f!` now desugars to `f.A!` using the
65 first tag defined in the enum.
66 - Error messages are more helpful for `foo.Whatever!` enum field accessing.
67 - Simplified logic for enums so there is less difference between enums that
68 have tags with member fields and those without.
69 - Rename `Empty()` to `Present()` for set-like tables.
70 - Paths are now an `enum Path(AbsolutePath(components:[Text]), RelativePath(components:[Text]), HomePath(components:[Text]))`
71 - Added `enum Result(Success, Failure(message:Text))` type for indicating
72 success or failure.
73 - Some path methods now use `Result` return types instead of failing:
74 - `Path.append()`
75 - `Path.append_bytes()`
76 - `Path.create_directory()`
77 - `Path.remove()`
78 - `Path.set_owner()`
79 - `Path.write()`
80 - `Path.write_bytes()`
81 - `Path.parent()` returns `none` if path is `(/)` (file root)
82 - Added check for unused variables.
84 ## 2025-11-30
86 ### API changes
88 - Added `base` parameter to various `Int.parse()` methods to allow explicitly
89 setting the numeric base from 1-36.
91 ### Bugfixes
93 - Fixed various issues around parsing integers.
95 ## v2025-11-29.2
97 ### Bugfixes
99 - Fix for undefined behavior on enums and structs with padding.
101 ## 2025-11-29
103 ### Syntax changes
105 - Syntax for tables has changed to use colons (`{k: v}`) instead of equals
106 (`{k=v}`).
107 - Syntax for text literals and inline C code has been simplified.
108 - Added metadata format instead of `_HELP`/`_USAGE`:
109 ```
110 HELP: "Help text"
111 USAGE: "Usage text"
112 MANPAGE_SYNOPSYS: "Synopsys..."
113 MANPAGE_DESCRIPTION: (./description.txt)
114 ```
115 - **Deprecated:** `extern` keyword for declaring external symbols from C.
116 - Use `C_code` instead.
117 - **Deprecated:** postfix `?` to make values optional.
118 - Explicitly optional values can be declared as `my_var : T? = value`.
119 - **Deprecated:** `>> ... = ...` form of doctests. They are now called "debug logs"
120 and you can specify multiple values: `>> a, b, c`
121 - **Deprecated:** `extend` blocks
122 - **Deprecated:** `deserialize` operation and `.serialized()` method call
123 - Instead, convert to and from `[Byte]`
125 ### Versioning and library changes
127 - Tomo versioning now uses dates instead of semantic versioning.
128 - Tomo libraries are now installed to
129 `$TOMO_PATH/lib/tomo@TOMO_VERSION/library@LIBRARY_VERSION` instead of
130 `$TOMO_PATH/share/tomo_TOMO_VERSION/installed/module_LIBRARY_VERSION`
131 - Core libraries are no longer shipped with the compiler, they have moved to
132 separate repositories.
133 - Library installation has been cleaned up a bit.
135 ### Type Changes
137 - List indexing now gives an optional value.
138 - Added support for inline anonymous enums
139 - Accessing a field on an enum now gives an optional value instead of a boolean.
140 - **Deprecated**: Sets are no longer a separate type with separate methods.
141 - Instead of sets, use tables with a value type of `{KeyType:Empty}`.
142 - As a shorthand, you can use `{a,b,c}` instead of `{a:Empty(),
143 b:Empty(), c:Empty()}` and the type annotation `{K}` as shorthand for
144 `{K:Empty}`.
145 - Added `Empty` for a built-in empty struct type and `EMPTY` for an instance of
146 the empty struct.
147 - Struct fields that start with underscores can be accessed again and function
148 arguments that start with underscore can be passed (but only as keyword
149 arguments).
151 ### API changes
153 - Added `Path.lines()`.
154 - Added `Text.find(text, target, start=1)`.
155 - Added `at_cleanup()` to register cleanup functions.
156 - Added `recursive` argument to `Path.create_directory()` to create parent
157 directories if needed.
158 - `setenv()` now takes an optional parameter for value, which allows for
159 unsetting environment values.
160 - Tables now have `and`, `or`, `xor`, and `-` (minus) metamethods.
161 - Added `table.with(other)`, `table.without(other)`,
162 `table.intersection(other)`, and `table.difference(other)`.
163 - Changed `list.unique()` to return a table with `Empty()` values for each
164 unique list item.
165 - Added a `--format` flag to the `tomo` binary that autoformats your code
166 (currently unstable, do not rely on it just yet).
167 - Standardized text methods for Unicode encodings:
168 - `Text.from_utf8()`/`Text.utf8()`
169 - `Text.from_utf16()`/`Text.utf16()`
170 - `Text.from_utf32()`/`Text.utf32()`
172 ### Bug fixes
174 - `Int.parse()` had a memory bug.
175 - Breaking out of a `for line in file.by_line()!` loop would leak file handle
176 resources, which could lead to exhausting the number of open file handles.
177 When that happens, the standard library now forces a GC collection to clean
178 up resources, which can result in file handles being freed up.
179 - `&` references failed to propagate when accessing fields like
180 `foo.baz.method()` when `foo` is a `&Foo` and `baz.method()` takes a `&Baz`.
181 - Optional paths no longer fail to compile when you check them for `none`.
182 - Text replacement no longer infinitely loops when given an empty text to replace.
183 - Short CLI flag aliases now no longer use the first letter of the argument.
184 - Stack memory was not correctly detected in some cases, leading to potential
185 memory errors.
187 ### Other changes
189 - Added automatic manpage generation.
190 - Major improvements to robustness of CLI argument parsing.
192 ## v0.3
194 - Added a versioning system based on `CHANGES.md` files and `modules.ini`
195 configuration for module aliases.
196 - When attempting to run a program with a module that is not installed, Tomo
197 can prompt the user to automatically install it.
198 - Programs can use `--version` as a CLI flag to print a Tomo program's version
199 number and exit.
200 - Significant improvements to type inference to allow more expressions to be
201 compiled into known types in a less verbose manner. For example:
202 ```tomo
203 enum NumberOrText(Number(n:Num), SomeText(text:Text))
204 func needs_number_or_text(n:NumberOrText)
205 >> n
206 func main()
207 needs_number_or_text(123)
208 needs_number_or_text(123.5)
209 needs_number_or_text("Hello")
210 ```
211 - Added `tomo --prefix` to print the Tomo install prefix.
212 - Sets now support infix operations for `and`, `or`, `xor`, and `-`.
213 - Added new `json` module for JSON parsing and encoding.
214 - Added `Path.sibling()`.
215 - Added `Path.has_extension()`.
216 - Added `Table.with_fallback()`.
217 - Added `Int*.get_bit()` and `Byte.get_bit()`.
218 - Added `Byte.parse()` to parse bytes from text.
219 - Added optional `remainder` parameter to `parse()` methods, which (if
220 non-none) receives the remaining text after the match. If `none`, the match
221 will fail unless it consumes the whole text.
222 - Added optional `remainder` parameter to `Text.starts_with()` and
223 `Text.ends_with()` to allow you to get the rest of the text without two
224 function calls.
225 - Improved space efficiency of Text that contains non-ASCII codepoints.
226 - Doctests now use equality checking instead of converting to text.
227 - Fixed the following bugs:
228 - Negative integers weren't converting to text properly.
229 - Mutation of a collection during iteration was violating value semantics.
230 - `extend` statements weren't properly checking that the type name was valid.
231 - Lazy recompilation wasn't happening when `use ./foo.c` was used for local
232 C/assembly files or their `#include`s.
233 - Memory offsets for enums with different member alignments were miscalculated.
234 - Optional types with trailing padding were not correctly being detected as `none`
235 - Tomo identifiers that happened to coincide with C keywords were not allowed.
236 - Compatibility issues caused compilation failure on some platforms.
238 ## v0.2
240 - Improved compatibility on different platforms.
241 - Switched to use a per-file unique ID suffix instead of renaming symbols after
242 compilation with `objcopy`.
243 - Installation process now sets user permissions as needed, which fixes an
244 issue where a user not in the sudoers file couldn't install even to a local
245 directory.
246 - Fixed some bugs with Table and Text hashing.
247 - Various other bugfixes and internal optimizations.
249 ## v0.1
251 First version to get a version number.