Some tests require network access or specific environment conditions
that aren't available during Nix build sandboxing. Skip tests in the
package derivation to allow consuming this flake as a dependency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- JS_WASM_BACKEND_PLAN: Mark phases 1-5 complete, deprioritize WASM
- LANGUAGE_COMPARISON: Update package manager status
- OVERVIEW: Add completed features list
- ROADMAP: Mark JS backend and package manager complete
- Add PACKAGES.md documenting the package system
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Parser and typechecker updates for new features
- Schema evolution refinements
- Type system enhancements
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- stdlib/html.lux: Type-safe HTML construction
- stdlib/browser.lux: Browser utilities
- examples/web/: Counter app with DOM manipulation
- examples/counter.lux: Simple counter example
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Auto-discover .lux files for fmt and check commands
- Add --target js flag for JavaScript compilation
- Improve help text for new features
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add full Dom effect: querySelector, createElement, addEventListener,
setAttribute, classList, styles, forms, scrolling, etc.
- Add Html module for type-safe HTML construction (Elm-style)
- Add TEA (The Elm Architecture) runtime for browser apps
- Add view dependency analysis for Svelte-style optimizations
- Support both browser and Node.js environments
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Auto-add .lux_packages/ to module search paths
- Find project root by looking for lux.toml
- Enable importing modules from installed packages
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add magic number system (LUX_RC_MAGIC) to distinguish RC-managed
allocations from static string literals, preventing crashes on decref
- Convert string helpers (trim, lines, split) to use lux_rc_alloc
- Track inline RC temps from effect operations (Process.exec, File.read,
Console.readLine, Http ops, String ops) by creating temp variables
- Implement ownership transfer: when RC temp is bound to a variable,
unregister temp and only track bound variable to avoid double-free
- Result: grapho runs with 0 memory leaks
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 2 of JS backend: implement effect handlers in runtime
Effects added:
- Console: print, readLine, readInt
- Random: int, bool, float
- Time: now, sleep
- Http: get, post, postJson (async with fetch)
Bug fixes:
- Fix if-else with blocks executing both branches (use if-else
statement instead of ternary for branches with statements)
- Fix main function being called twice when top-level let binding
already invokes it
- Fix List module operations incorrectly treated as effect operations
New tests:
- test_js_random_int
- test_js_random_bool
- test_js_random_float
- test_js_time_now
All 19 JS backend tests pass.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add 10 integration tests that compile Lux to JavaScript and verify
correct execution in Node.js:
- test_js_factorial: Recursion and effects
- test_js_fibonacci: Classic recursive algorithm
- test_js_adt_and_pattern_matching: Custom ADTs with match
- test_js_option_type: Built-in Option type handling
- test_js_closures: Closure creation and variable capture
- test_js_higher_order_functions: Functions as values
- test_js_list_operations: List.map, List.foldl
- test_js_pipe_operator: Pipe (|>) operator
- test_js_records: Record literal and field access
- test_js_string_concatenation: String operations
Also fix List module operations being incorrectly treated as effects
by adding special-case handling in EffectOp emission.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Website Plan (docs/WEBSITE_PLAN.md):
- Research from Elm, Gleam, Rust, Go, Elixir, Zig websites
- Messaging strategy: "Effects you can see, tests you can trust"
- Section structure: Hero, Problem, Solution (3 pillars), Examples
- Self-hosting goal: Build lux-lang.org in Lux itself
JS/WASM Backend Plan (docs/JS_WASM_BACKEND_PLAN.md):
- Type mappings: Lux types → JavaScript equivalents
- Code generation examples for functions, closures, ADTs, effects
- 6-phase implementation: Core → StdLib → Effects → DOM → CLI → WASM
- New Dom effect for browser manipulation
- Timeline: 11-15 weeks for full support
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add benchmarks comparing Lux against 7 languages:
- Rust, C, Go (compiled)
- Node.js, Bun (JavaScript JIT)
- Python (interpreted)
Benchmarks:
- Fibonacci (fib 35): recursive function calls
- Prime counting (10k): loops and conditionals
- Sum loop (10M): tight numeric loops
- Ackermann (3,10): deep recursion
- Selection sort (1k): sorting algorithm
- List operations (10k): map/filter/fold with closures
Results show Lux:
- Matches C and Rust performance
- 2-5x faster than Go
- 7-15x faster than Node.js
- 10-285x faster than Python
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix unused import std::io::Read in interpreter.rs by using qualified call
- Add #[allow(dead_code)] to CGenError.span (kept for future error reporting)
- Add #[allow(dead_code)] to local_vars field (planned for free variable analysis)
- Add #[allow(dead_code)] to unbox_value and emit_all_scope_cleanup methods
All 263 tests pass.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Benchmarks:
- Add fib, list_ops, primes benchmarks comparing Lux vs Node.js vs Rust
- Lux matches Rust performance and is 8-30x faster than Node.js
- Add docs/benchmarks.md documenting results
LSP improvements:
- Context-aware completions (module access vs general)
- Add List, String, Option, Result, Console, Math method completions
- Add type and builtin completions
- Hover now shows type signatures and documentation for known symbols
- Hover returns formatted markdown with code blocks
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- toString now stores result in temp variable and registers for RC
- String concatenation stores result and registers for RC
- Immediately decref temporary input strings after concat to avoid leaks
- Add is_rc_temp() helper to identify RC temporary variables
This fixes the memory leak where dynamically created strings from
toString() and string concatenation were not being freed.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add runtime counters tracking FBIP reuse vs copy operations:
- lux_fbip_reuse_count: incremented when rc=1 allows in-place mutation
- lux_fbip_copy_count: incremented when rc>1 forces allocation
Output now shows both memory stats and FBIP stats:
[RC] No leaks: 13 allocs, 13 frees
[FBIP] 3 reuses, 0 copies
Rename test_no_fbip.lux to test_ownership_transfer.lux to better
reflect that ownership transfer enables FBIP even with aliases.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- stress_rc.lux: Single-owner chains testing FBIP optimization
- stress_shared_rc.lux: Shared-reference chains (rc>1) forcing copy path
Both process lists of 100, 200, 500, and 1000 elements with map/filter/reverse.
Verifies no memory leaks with large data sets.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add test cases demonstrating FBIP (Functional But In-Place) optimization:
- test_fbip_clean.lux: Basic FBIP chain (map, filter, reverse)
- test_fbip_allocs.lux: Single-owner allocation test with range/map/filter/reverse
- test_no_fbip.lux: Demonstrates shared reference forcing rc>1 path
- test_rc_comparison.lux: Comparison of FBIP vs non-FBIP allocations
All tests verify no memory leaks with the RC system.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When rc=1 at update sites, mutate in-place instead of allocating new:
List.reverse:
- Swap element pointers in-place instead of creating new list
List.take:
- Truncate list in-place, decref dropped elements
List.drop:
- Shift elements to front in-place, decref dropped elements
List.map:
- Mutate elements in-place, decref old values before storing new
List.filter:
- Filter in-place by shifting kept elements, decref filtered-out elements
All operations check LUX_RC_HEADER(list)->rc == 1 at runtime and
fall back to allocation when rc > 1 (list is shared).
This completes Phase B performance optimizations:
- B1: Last-use optimization (ownership transfer) ✅
- B2: Reuse analysis (FBIP) ✅
- B3: Drop specialization ✅
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase B Performance Optimizations:
Drop Specialization:
- Add specialized decref functions: lux_decref_list, lux_decref_closure,
lux_decref_string, lux_decref_boxed
- Inline drop logic eliminates polymorphic dispatch through lux_drop
- Forward type declarations (typedef struct X_s X) for proper C ordering
Ownership Transfer (Last-Use Optimization):
- Track variable types in var_types HashMap for type inference
- When assigning let b = a where a is RC-tracked:
- Unregister source variable from RC cleanup
- Register destination variable instead
- Prevents double-free and eliminates unnecessary incref/decref pairs
Also:
- Fix type inference for variable references in infer_expr_type
- Add is_rc_tracked() and unregister_rc_var() helper functions
- Update REFERENCE_COUNTING.md with Phase B progress
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add escape_c_keyword() to mangle C reserved words (double, int, etc.)
- Implement toString() mapping to lux_int_to_string()
- Add string concatenation detection for BinaryOp::Add using lux_string_concat()
- Add is_string_expr() helper for string expression detection
- Update infer_expr_type() for toString, string concat, and if expressions
- Implement complex conditionals RC handling: use if-statements instead of
ternaries when branches create RC values to avoid allocating unused branches
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add pop_rc_scope_except() to skip decref'ing returned variables
- Block expressions now properly preserve returned RC variables
- Function returns skip cleanup for variables being returned
- Track function return types for call expression type inference
- Function calls returning RC types now register for cleanup
- Fix main() entry point to call main_lux() when present
Test result: [RC] No leaks: 17 allocs, 17 frees
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
ADT values with pointer fields (like recursive Tree types) now properly
manage memory:
- Assign unique type tags (starting at 100) to each ADT type
- Track which ADTs have pointer fields that need cleanup
- Generate lux_drop_adt() function with per-ADT drop logic
- Allocate ADT pointer fields with lux_rc_alloc instead of malloc
- Track ADT variables with pointer fields in scope
- Emit field cleanup code at scope exit (switch on tag, decref fields)
Test results:
- ADT test: [RC] No leaks: 6 allocs, 6 frees
- List test: [RC] No leaks: 31 allocs, 31 frees
- Closure test: [RC] No leaks: 8 allocs, 8 frees
- All 263 tests pass
Remaining: early returns, complex conditionals.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>