Closures and their environments are now properly reference-counted:
- Allocate closures with lux_rc_alloc(sizeof(LuxClosure), LUX_TAG_CLOSURE)
- Allocate environments with lux_rc_alloc(sizeof(LuxEnv_N), LUX_TAG_ENV)
- Enable Lambda in expr_creates_rc_value() to track closure variables
- Add lux_decref() after List higher-order operations (map, filter, fold,
find, any, all) to clean up inline lambdas
Test results:
- Closure test: [RC] No leaks: 8 allocs, 8 frees
- List RC test: [RC] No leaks: 31 allocs, 31 frees
- All 263 tests pass
Remaining for full memory safety: ADT RC, early returns, conditionals.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- C_BACKEND.md: Update memory management from "Leaks" to "Scope-based RC",
update comparison tables with Koka/Rust/Zig/Go
- LANGUAGE_COMPARISON.md: Add status column to gap tables, add RC row
- OVERVIEW.md: Add C backend RC to completed features, update limitations
- REFERENCE_COUNTING.md: Add "Path to Koka/Rust Parity" section with:
- What we have vs what Koka/Rust have
- Remaining work for full memory safety (~230 lines)
- Performance optimizations for Koka parity (~600 lines)
- Cycle detection strategy
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add scope tracking for reference-counted variables in the C backend:
- Add RcVariable struct and rc_scopes stack to CBackend
- Track RC variables when assigned in let bindings
- Emit lux_decref() calls when scopes exit (functions, blocks)
- Add memory tracking counters (alloc/free) for leak detection
- Fix List.filter to incref elements before copying (prevents double-free)
- Handle return values by incref/decref to keep them alive through cleanup
The RC system now properly frees memory at scope exit. Verified with
test showing "[RC] No leaks: 28 allocs, 28 frees".
Remaining work: early returns, complex conditionals, closures, ADTs.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements Phase 1-3 of the RC system for automatic memory management:
- Add LuxRcHeader with refcount and type tag for all heap objects
- Add lux_rc_alloc, lux_incref, lux_decref, and lux_drop functions
- Update list allocation to use RC (lux_list_new uses lux_rc_alloc)
- List operations (concat, reverse, take, drop) now incref shared elements
- Update boxing functions (box_int, box_bool, box_float) to use RC
- String operations (concat, int_to_string, readLine) return RC strings
- File and HTTP operations return RC-managed strings
The infrastructure is ready for automatic decref insertion at scope exit
(Phase 4) and closure RC (Phase 5) in future work.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement HTTP client using POSIX sockets:
- Http.get(url) - GET request
- Http.post(url, body) - POST request
- Http.put(url, body) - PUT request
- Http.delete(url) - DELETE request
Features:
- Self-contained implementation (no libcurl dependency)
- URL parsing for host, port, and path
- HTTP/1.1 protocol with Connection: close
- Response body extraction
All Http operations use evidence passing for handler customization.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New effects with evidence passing support:
Random effect:
- int(min, max) - random integer in range
- float() - random float 0-1
- bool() - random boolean
Time effect:
- now() - milliseconds since epoch
- sleep(ms) - pause execution
File effect:
- read(path) - read file contents
- write(path, content) - write file
- append(path, content) - append to file
- exists(path) - check if file exists
- delete(path) - delete file
- isDir(path) - check if directory
- mkdir(path) - create directory
Also fixed:
- Function calls as statements now properly emit in generated C
- Return type inference for all effect operations
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
C backend now fully threads evidence through effectful function calls:
- Track effectful functions via effectful_functions HashSet
- Add has_evidence flag to track context during code generation
- Add LuxEvidence* ev parameter to effectful function signatures
- Transform effect operations to use ev->console->print() when evidence available
- Update function calls to pass evidence (ev or &default_evidence)
- Update main entry point to pass &default_evidence
Generated code now uses zero-cost evidence passing:
void greet_lux(LuxEvidence* ev) {
ev->console->print(ev->console->env, "Hello!");
}
This completes the evidence passing implementation for both interpreter
(O(1) HashMap lookup) and C backend (direct function pointer calls).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Interpreter changes:
- Add evidence HashMap for O(1) handler lookup instead of O(n) stack search
- Update eval_run to manage evidence when entering/exiting run blocks
- Modify handle_effect to use evidence.get() instead of stack iteration
C backend infrastructure:
- Add handler structs (LuxConsoleHandler, LuxStateHandler, LuxReaderHandler)
- Add LuxEvidence struct containing pointers to all handlers
- Add default handlers that delegate to built-in implementations
- Add Console.readLine built-in implementation
Documentation:
- Create docs/EVIDENCE_PASSING.md explaining design and implementation
- Update docs/C_BACKEND.md with current progress
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements full pattern matching with variable binding for the C backend:
- Extract variable bindings from patterns (Var, Constructor, Tuple, Record)
- Infer C types for bound variables using variant field type tracking
- Handle recursive ADTs with pointer fields and heap allocation
- Dereference pointer bindings automatically for value semantics
Key implementation details:
- variant_to_type: Maps variant names to parent type for tag generation
- variant_field_types: Maps (type, variant) to field types for inference
- Recursive type fields use Type* pointers with malloc/memcpy
- Pattern bindings dereference pointers to maintain value semantics
Examples that now work:
- match opt { Some(x) => x, None => 0 }
- match tree { Leaf(n) => n, Node(l, r) => sum(l) + sum(r) }
Updates documentation to reflect C backend progress.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement closures/lambdas in the C code generator:
- Add LuxClosure struct (env pointer + function pointer)
- Add ClosureInfo to track closure metadata during generation
- Implement free variable analysis to find captured variables
- Generate environment structs for each lambda's captured vars
- Generate lambda implementation functions
- Support indirect closure calls via function pointer casting
- Track functions returning closures for proper type inference
Example: fn(x) => x + n compiles to a LuxEnv struct holding n,
a lambda_N function taking env + x, and closure allocation code.
Limitations: No memory management (closures leak), types
mostly hardcoded to LuxInt.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove Cranelift JIT compiler and expose the existing C backend as the
compilation target. Generated C code can be compiled with GCC/Clang.
Changes:
- Remove cranelift-* dependencies from Cargo.toml
- Delete src/compiler.rs (565 lines of Cranelift code)
- Add compile_to_c() function with -o and --run flags
- Fix C backend name mangling (main -> main_lux) to avoid conflicts
- Update CLI help text and documentation
Usage:
lux compile <file.lux> # Output C to stdout
lux compile <file.lux> -o out.c # Write to file
lux compile <file.lux> --run # Compile and execute
C backend supports: functions, basic types, operators, if/then/else,
records, enums, Console.print. Future work: closures, lists, patterns.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- SKILLS.md: Update roadmap phases with actual completion status
- Phase 0-1 complete, Phase 2-5 partial, resolved design decisions
- OVERVIEW.md: Add HttpServer, Test effect, JIT to completed features
- ROADMAP.md: Add HttpServer, Process, Test effects to done list
- VISION.md: Update Phase 2-3 tables with current status
- guide/05-effects.md: Add Time, HttpServer, Test to effects table
- guide/09-stdlib.md: Add HttpServer, Time, Test effect docs
- reference/syntax.md: Fix interpolation syntax, remove unsupported literals
- testing.md: Add native Test effect documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Record equality: add Record case to values_equal in interpreter
- Invalid escapes: error on unknown escape sequences in lexer
- Unknown effects: validate effect names in check_function with suggestions
- Circular types: add DFS cycle detection in check_type_cycles
- Parser: require | for enum variants, enabling proper type alias syntax
All 265 tests pass.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Test effect with operations: assert, assertEqual, assertNotEqual,
assertTrue, assertFalse, fail
- Implement Test effect handlers in interpreter with TestResults tracking
- Add values_equal method for comparing Value types in tests
- Update lux test command to discover and run test_* functions
- Create example test files: test_math.lux, test_lists.lux
- Add TESTING_DESIGN.md documentation
- Fix AST mismatches in C backend and compiler.rs for compatibility
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Show specific expression type when JIT compilation fails, e.g.:
- "Unsupported in JIT: String literal"
- "Effect operation 'Console.print' - effects are not supported in JIT"
- "ADT constructor 'Success' - algebraic data types are not supported in JIT"
This helps users understand exactly which expression is blocking
JIT compilation instead of a generic "Unsupported expression type".
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 30 integration tests that verify all examples and projects
parse and type-check correctly
- Add scripts/lint-examples.sh for quick pre-commit validation
- Tests will catch regressions like missing `run ... with {}` syntax
or broken escape sequences
Run with: cargo test example_tests
Or quick check: ./scripts/lint-examples.sh
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- behavioral.lux: use verifiable behavioral patterns (abs for idempotent)
- behavioral_types.lux: use simpler verified patterns, proper main invocation
- schema_evolution.lux: simplify to runtime schema ops, fix record access
- jit_test.lux: add proper main function with console output
All examples now parse and run correctly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix string interpolation issues: escape curly braces with \{ and \}
since unescaped { triggers string interpolation
- Fix effectful function invocation: use "let _ = run main() with {}"
instead of bare "main()" calls
- Use inline record types instead of type aliases (structural typing)
- Fix flake.nix to show build progress instead of suppressing output
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Build release binary when entering nix shell
- Add target/release to PATH automatically
- Update shell help to show lux commands
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Schema Evolution:
- Preserve version info in type resolution (Type::Versioned)
- Track versioned type declarations in typechecker
- Detect version mismatches at compile time (@v1 vs @v2 errors)
- Support @v2+ (at least) and @latest version constraints
- Store migrations for future auto-migration support
- Fix let bindings to preserve declared type annotations
HTTP Server Effect:
- Add HttpServer effect with listen, accept, respond, respondWithHeaders, stop
- Implement blocking request handling via tiny_http
- Request record includes method, path, body, headers
- Add http_server.lux example with routing via pattern matching
- Add type-checking test for HttpServer effect
Tests: 222 passing (up from 217)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add `lux compile <file>` command that compiles and runs Lux code using
the Cranelift JIT compiler. Includes --benchmark flag for timing.
- Add compile_file() function in main.rs
- Add jit_test.lux example with fib(30) + factorial(10)
- Update VISION.md status
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Many features were documented as "missing" or "planned" but are actually
working: generics, string interpolation, File/HTTP/Random/Time effects,
JSON parsing, module system, and JIT CLI integration.
Updated IMPLEMENTATION_PLAN.md, OVERVIEW.md with accurate status.
Added ROADMAP.md (use-case-targeted) and LANGUAGE_COMPARISON.md.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add String.fromChar function to convert Char to String
- Create four stress test projects demonstrating Lux features:
- json-parser: recursive descent parsing with Char handling
- markdown-converter: string manipulation and ADTs
- todo-app: list operations and pattern matching
- mini-interpreter: AST evaluation and environments
- Add comprehensive testing documentation (docs/testing.md)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Neovim improvements:
- Add tree-sitter text objects for functions, types, blocks
- Add folding support
- Enhanced REPL integration (toggle, send line/selection)
- New commands: LuxCheck, LuxReplToggle, LuxSend
- Better keybindings with localleader
VS Code extension:
- Full syntax highlighting with TextMate grammar
- LSP client integration
- 20+ snippets for common patterns
- Commands: run, format, check, REPL
- Keybindings and context menu
Fixes:
- Fix all cargo warnings with #[allow(dead_code)] annotations
- Clean up unused variables
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Show 2 lines of context before and after errors (dimmed)
- Fix guessing_game.lux to be non-interactive for testing
- Use binary search simulation to demonstrate game logic
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add readLine and readInt operations to the Console effect for interactive
input. Create a number guessing game project demonstrating ADTs, pattern
matching, effects, and game state management.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a JIT compiler using Cranelift that compiles Lux functions to native
machine code. Achieves ~160x speedup over the tree-walking interpreter
(fib(30): 11.59ms JIT vs 1.87s interpreter).
Supports: arithmetic, comparisons, conditionals, let bindings, function
calls, and recursion. Compile time overhead is minimal (~500µs).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Http effect for making HTTP requests:
- Http.get(url) - GET request
- Http.post(url, body) - POST with string body
- Http.postJson(url, json) - POST with JSON body
- Http.put(url, body) - PUT request
- Http.delete(url) - DELETE request
Returns Result<HttpResponse, String> where HttpResponse contains
status code, body, and headers.
Includes reqwest dependency with blocking client, OpenSSL support
in flake.nix, and example at examples/http.lux demonstrating
API requests with JSON parsing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive JSON support via the Json module:
- Parse JSON strings with Json.parse() returning Result<Json, String>
- Stringify with Json.stringify() and Json.prettyPrint()
- Extract values with Json.get(), getIndex(), asString(), asInt(), etc.
- Build JSON with constructors: Json.null(), bool(), int(), string(), array(), object()
- Query with Json.isNull() and Json.keys()
Includes example at examples/json.lux demonstrating building, parsing,
and extracting JSON data with file I/O integration.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds two essential effects that enable Lux to interact with the system:
File effect:
- read(path) - Read file contents as string
- write(path, content) - Write string to file
- append(path, content) - Append to file
- exists(path) - Check if file/directory exists
- delete(path) - Delete a file
- readDir(path) - List directory contents
- isDir(path) - Check if path is directory
- mkdir(path) - Create directory (including parents)
Process effect:
- exec(cmd) - Run shell command, return stdout
- execStatus(cmd) - Run command, return exit code
- env(name) - Get environment variable (returns Option)
- args() - Get command line arguments
- exit(code) - Exit program with code
- cwd() - Get current working directory
- setCwd(path) - Change working directory
Also fixes formatter bug with empty handler blocks in `run ... with {}`.
These effects make Lux capable of writing real CLI tools and scripts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Math module: abs, min, max, sqrt, pow, floor, ceil, round
- Add List functions: isEmpty, find, any, all, take, drop
- Add String functions: startsWith, endsWith, toUpper, toLower, substring
- Add 12 tests for new standard library functions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Schema module with functions for creating and migrating versioned
values. This provides the runtime foundation for schema evolution.
Schema module functions:
- Schema.versioned(typeName, version, value) - create versioned value
- Schema.migrate(value, targetVersion) - migrate to new version
- Schema.getVersion(value) - get version number
Changes:
- Add Versioned, Migrate, GetVersion builtins to interpreter
- Add Schema module to global environment
- Add Schema module type to type environment
- Add 4 tests for schema operations
- Add examples/versioning.lux demonstrating usage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for the `resume(value)` expression in effect handler
bodies. When resume is called, the value becomes the return value
of the effect operation, allowing handlers to provide values back
to the calling code.
Implementation:
- Add Resume(Value) variant to EvalResult
- Add in_handler_depth tracking to Interpreter
- Update Expr::Resume evaluation to return Resume when in handler
- Handle Resume results in handle_effect to use as return value
- Add 2 tests for resumable handlers
Example usage:
```lux
handler prettyLogger: Logger {
fn log(level, msg) = {
Console.print("[" + level + "] " + msg)
resume(()) // Return Unit to the call site
}
}
```
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Random and Time effects for random number generation and
time-based operations. These effects can be used in any
effectful code block.
Random effect operations:
- Random.int(min, max) - random integer in range [min, max]
- Random.float() - random float in range [0.0, 1.0)
- Random.bool() - random boolean
Time effect operations:
- Time.now() - current Unix timestamp in milliseconds
- Time.sleep(ms) - sleep for specified milliseconds
Changes:
- Add rand crate dependency
- Add Random and Time effect definitions to types.rs
- Add effects to built-in effects list in typechecker
- Implement effect handlers in interpreter
- Add 4 new tests for Random and Time effects
- Add examples/random.lux demonstrating usage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add runtime support for the State, Reader, and Fail effects that
were already defined in the type system. These effects can now be
used in effectful code blocks.
Changes:
- Add builtin_state and builtin_reader fields to Interpreter
- Implement State.get and State.put in handle_builtin_effect
- Implement Reader.ask in handle_builtin_effect
- Add Reader effect definition to types.rs
- Add Reader to built-in effects list in typechecker
- Add set_state/get_state/set_reader/get_reader methods
- Add 6 new tests for built-in effects
- Add examples/builtin_effects.lux demonstrating usage
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Levenshtein distance-based similarity matching for undefined
variables, unknown types, unknown effects, and unknown traits.
When a name is not found, the error now suggests similar names
within edit distance 2.
Changes:
- Add levenshtein_distance() function to diagnostics module
- Add find_similar_names() and format_did_you_mean() helpers
- Update typechecker to suggest similar names for:
- Undefined variables
- Unknown types
- Unknown effects
- Unknown traits
- Add 17 new tests for similarity matching
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add full support for user-defined generic types and functions:
- Add type_params field to TypeChecker to track type parameters in scope
- Update resolve_type() to resolve type parameters to their bound variables
- Update function_type() to bind type parameters and return polymorphic TypeScheme
- Update type declaration handling for generic ADTs (e.g., Pair<A, B>)
Generic functions and types now work:
fn identity<T>(x: T): T = x
type Pair<A, B> = | MkPair(A, B)
fn first<A, B>(p: Pair<A, B>): A = ...
Add examples/generics.lux demonstrating:
- Generic identity function
- Generic Pair type with first/second accessors
- Generic mapOption function
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add string concatenation support to + operator in typechecker
- Register ADT constructors in both type environment and interpreter
- Bind handlers as values so they can be referenced in run...with
- Fix effect checking to use subset instead of exact match
- Add built-in effects (Console, Fail, State) to run block contexts
- Suppress dead code warnings in diagnostics, modules, parser
Update all example programs with:
- Expected output documented in comments
- Proper run...with statements to execute code
Add new example programs:
- behavioral.lux: pure, idempotent, deterministic, commutative functions
- pipelines.lux: pipe operator demonstrations
- statemachine.lux: ADT-based state machines
- tailcall.lux: tail call optimization examples
- traits.lux: type classes and pattern matching
Add documentation:
- docs/IMPLEMENTATION_PLAN.md: feature roadmap and status
- docs/PERFORMANCE_AND_TRADEOFFS.md: performance analysis
Add benchmarks for performance testing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a Language Server Protocol (LSP) server to enable IDE integration.
The server provides:
- Real-time diagnostics (parse errors and type errors)
- Basic hover information
- Keyword completions (fn, let, if, match, type, effect, etc.)
- Go-to-definition stub (ready for implementation)
Usage: lux --lsp
The LSP server can be integrated with any editor that supports LSP,
including VS Code, Neovim, Emacs, and others.
Dependencies added:
- lsp-server 0.7
- lsp-types 0.94
- serde with derive feature
- serde_json
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>