Changelog: tramaj-go
On Sun, 04 Oct 2026, by @lucasdicioccio, 778 words, 0 code snippets, 0 links, 0images.
Changelog: tramaj-go
Release history of tramaj-go, the Go implementation, standard library only. Releases happen when there are
major changes rather than on a schedule; each entry below is one version.
Every implementation has its own page like this one, and each page is
tagged so the site builds one Atom feed per implementation:
#changelog #go #tramaj-go
tramaj-go 0.3.02026-10-24
The first release, as the Go module tag `tramaj-go/v0.3.0`: `go get github.com/lucasdicioccio/tramaj/tramaj-go@v0.3.0`. It is numbered with the other ports of this release, which carry the same language. Go port: parser, evaluator (concrete and symbolic modes), Node JSON codec, static analyses and a tramaj-go CLI. Standard library only, Go 1.21+. On pkg.go.dev.
- added Hand-written port checked against `corpus/cases` by `corpus_test.go`: every case passes in both modes.
- changed Breaking: numbers are two types, an integer and a float (decisions section 18). A literal and a JSON number are typed by their text: `3` is an integer, `3.0` and `3e0` are floats. Integers cover the signed 64-bit range; one outside it is a parse error as a literal and a `TypeMismatch` in the context.
- changed Breaking: a number keeps its type when written. `str(1.0)` is `1.0` where it was `1`, and `CompactJSON` and `PrettyJSON` write a float with a fraction or an exponent.
- changed Breaking: `eq` never equates an integer with a float, and `lt`/`lte`/`gt`/`gte` take two integers or two floats; a mixed pair is a `TypeMismatch`. An array index given to `has` or `lookup` is an integer.
- changed Breaking: in a `tramaj.JSON` value an integer is an `int64` and a float a `float64`, where every number was a `float64`. `ParseJSON` types a number by its text and refuses none; `NormalizeNumbers` is what refuses an integer beyond 64 bits or a float too large for a double. `NumberLit` is now `IntLit` and `FloatLit`. New: `FormatInteger`, `FormatFloat`.
- changed Breaking: `"$term"` is a reserved object key, and `int` and `float` replace `number` as v4 type primitives.
- added The arithmetic profile: `sum`, `product`, `negate`, `quotient`, `inverse`, `floor-quotient`, `modulo`, `floor` and `real`, and the `NotRepresentable` error kind. It is off by default: `Options`, `DefaultOptions`, `EvalProgramWith` and `RunProgramWith` turn it on, and so does the CLI's `--arithmetic`.
- added Terms: over a symbol an arithmetic builtin evaluates to `{"$term": op, "arguments": [...]}`, with its operands as written.
- added `ArithmeticNames`, `ArithmeticOps` and `DeepArithmeticOps`, the arithmetic names a program references; `tramaj-go analyze arithmetic` prints them.
- added `sort-by(list, fn)` and `sort-by-descending(list, fn)` (decisions section 20): a stable sort by a key function, over integer, float or string keys, strings by code point. Both are special forms lowered to one new AST constructor, `SortBy`, so neither name can be bound and called or passed by reference.
- added `format-number(x, decimals, group)`: a number as positional decimal text, rounding its exact value with ties away from zero, 0 to 20 decimals, never an exponent or a negative zero. An ordinary builtin that needs no option.
- added `round(x)`, the tenth name of the arithmetic profile: the nearest integer, ties away from zero. It builds a term over a symbol and is reported by `ArithmeticOps`.
- changed Breaking, symbolic mode only: a symbol or a term given as the key of `has` or `lookup` is `NotConcrete` (v3-symbols section 1.5), where it answered `false` or the fallback, reading an unknown key as a missing one. A concrete key keeps the tolerant behaviour: a missing key, an out-of-range index or a wrong-shaped container still answers `false` or the fallback.
- added `?shape(key, shape)` allocates a structure of symbols with one key and one site (v3-symbols section 1.2, decisions section 19). Each `~name` or `~name(e)` marker in the shape is a symbol `[key, "name"]` or `[key, "name", e]` at the form's site, and `{~name}` is short for `{name: ~name}`. It lowers at parse time, so the AST and the envelope are unchanged. A marker outside a shape or in a key, a bare marker under a lambda in the shape, a marker name used twice, a shape with no marker and a wrong argument count are parse errors. The corpus runner provides the `shape` profile.
- changed An unclosed `(`, `[`, `{`, string or interpolation is reported where the closer was looked for, naming its opener and where it is, instead of mostly at char 0 as `expected an expression`. Every parse error now gives a 1-based line and column after its offset: `at char 8 (line 1, column 9): expected ')' to close the '(' of .div at line 1, column 5`. Every program that parsed still parses to the same AST. `ParseError` gains `Line` and `Column` next to `Pos` and `Msg`, and `Error()` includes them.