Changelog
What's changed
A record of all notable changes to code-lang. The project follows a rolling development model — breaking changes will be noted explicitly once v1.0 stabilizes.
Toolchain- code-lang-fmt check — validate .cl files for parse errors, exits 1 on failure
- code-lang-fmt lint — run UnusedImport and ShadowedBinding rules with optional --fix
- cargo-dist release pipeline — pushes a git tag and GitHub Actions builds native binaries for Linux x64/ARM, macOS ARM, and Windows
- install.sh — curl | sh installs both code-lang and code-lang-fmt into ~/.code-lang/bin on Linux and macOS
- install.ps1 — equivalent one-liner installer for Windows PowerShell
- ci.yml — GitHub Actions CI runs build, test, clippy -D warnings, and rustfmt --check on every push and pull request
- ci.sh — local mirror of CI so you can run all four checks before pushing
Language- null keyword — write null as a literal value in any expression
- let x; — uninitialized declaration defaults to null (no more required initializer)
- ?? null coalescing operator — 'a ?? b' returns b only when a is null
- typeof keyword — 'typeof expr' returns the type name as a string
- Array destructuring in let/const — 'let [a, b] = arr' binds elements by position
- Hash destructuring in let/const — 'let { x, y } = hash' extracts keys by name, 'let { x: alias } = hash' renames
- Default function parameters — 'fn(name, greeting = "hi")' uses the default when the argument is omitted
Bug fixes- Struct self-methods with zero extra args no longer panic — 'point.get_x()' works correctly
- Array index assignment now bounds-checks — out-of-range index returns an error instead of silently doing nothing
- Importing a .cl file that fails at runtime now surfaces the error instead of swallowing it
Safety- Float operations (sqrt, log, pow, trig) return a clean error on NaN or Infinity instead of propagating IEEE 754 special values
- Number parsing in the lexer no longer panics on malformed literals — emits ILLEGAL token instead
Language- String interpolation — embed expressions directly in strings with ${...} syntax
- for-in loops — iterate arrays with 'for (i in arr)' and hashes with 'for (k, v in hash)'
- switch statement — pattern matching with 'switch (subject) { pattern => body }', compared with ==
- Enum types — define named variant sets with 'enum Direction { North, South, East, West }' and access via 'Direction.North'
Errors- is_error(val) global builtin — test whether a value is an error without importing anything
- Errors stored in let/const are recoverable values — only bare expression statements propagate errors
- Module member errors now name the module: 'fmt has no member x', 'utils has no public member x'
Errors- All errors now show the source line with a caret pointing to the exact column
- break and continue outside a loop now report the correct line/column
- import errors now point to the import statement location
- Hint messages added for common mistakes — type mismatches, undefined variables, arity errors, and more
- REPL now checks for parse errors before evaluating, preventing confusing partial-AST results
- Parse errors in imported .cl files are surfaced with the file name
Safety- Recursion depth limit of 500 — infinite recursion now gives a clean error instead of a segfault
- Integer arithmetic (+ - * **) now uses checked operations — overflow produces a clear error
- Float operations that produce NaN or Infinity now return an error
- Function calls enforce arity — wrong argument count is an error, not silent truncation
Standard library- arrays.map, filter, reduce, find, any, all — higher-order functions that accept user-defined functions
- fmt.format(template, ...args) — printf-style string formatting with %s %d %f %%
- math.log2, math.sign, math.gcd, math.lcm
- strings.lines, strings.is_empty, strings.pad_left, strings.pad_right
- hash.get(h, key, default) — safe key access with a fallback value
Language- Tree-walking interpreter rewritten from Go to Rust
- First-class functions, closures, and recursion
- Structs with default field values and dot-notation access
- Module and import system for stdlib and .cl files
- Control flow: if / elseif / else, while, for, break, continue
- Operators: arithmetic (** //), comparison, logical (&& ||), compound assignment, prefix/postfix ++/--
- Types: Integer, Float, String, Char, Boolean, Array, Hash, Null, Function, Struct, Module
Standard library- fmt — print, eprint, input, typeof, to_int, to_float, to_str, clear
- math — PI, E, sqrt, abs, pow, floor, ceil, round, log, sin, cos, tan, min, max, clamp
- strings — to_upper, to_lower, split, join, contains, replace, trim, reverse, to_chars, from_chars, parse_int, parse_float
- arrays — 20 functions including push, pop, slice, sort, zip, flatten, unique
- hash — keys, values, entries, has_key, merge, delete, len
- fs — read_file, write_file, append_file, read_lines, exists, list_dir, mkdir, copy, rename, remove
- path — join, basename, dirname, stem, extension, absolute, is_absolute
- os — args, platform, arch, get_env, set_env, get_wd, hostname, exit
- time — now, unix, sleep, since, format, year/month/day/hour/minute/second
- json — parse, stringify
- rand — int, float, choice, shuffle
- http — get, post, post_json (blocking, returns status/body/ok)
Errors- All errors carry line and column from the call site
- Error output shows source line with caret pointer
- Parse errors surface to the user before evaluation begins
- Non-zero exit code on any error in script mode
REPL- Persistent history across sessions (~/.code_lang_history)
- exit, exit(), and quit all exit cleanly
- Errors print to stderr without crashing the session