The JS backend now processes imported modules, emitting their type
constructors and functions with module-prefixed mangled names. Module
function calls (both via Expr::Call with Expr::Field and via
Expr::EffectOp) are resolved to the correct mangled names.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Handler declarations now emit as JavaScript objects with operation
methods. Each operation defines resume as an identity function,
matching the simple handler model used by the interpreter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The JS backend now detects `let main = fn() => ...` patterns and
auto-invokes them at the end of the generated code, matching the
interpreter's behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
List.get(list, index) now correctly compiles to JavaScript, returning
Lux.Some(value) for valid indices and Lux.None() for out-of-bounds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements WISH-013 mutable state primitives. Ref<T> is a mutable container
using existing module call syntax. Supported across interpreter, JS, and C backends.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add support for `extern let name: Type` and `extern let name: Type = "jsName"`
syntax for declaring external JavaScript values. This follows the same pattern
as extern fn across all compiler passes: parser, typechecker, interpreter
(runtime error placeholder), JS backend (emits JS name directly without
mangling), formatter, linter, modules, and symbol table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add find, findIndex, any, all, zip, flatten, contains, take, drop,
and forEach to the JS backend's emit_list_operation function. These
operations previously worked in the interpreter and C backend but
caused "Unknown List operation" errors when compiled to JS.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add safe variants of File operations that return Result<T, String> instead
of crashing with RuntimeError. This prevents server crashes when a file
is missing or unwritable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Html: add RawHtml, Attribute, meta/link/script/iframe/figure/figcaption
elements, attr() helper, rawHtml() helper, seoDocument() for SEO meta
tags, fix document() to use Attribute instead of DataAttr for standard
HTML attributes.
Http: add serveStaticFile(), parseFormBody(), getFormField(),
sendResponse() convenience helpers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add File.glob(pattern) effect operation that returns a list of file
paths matching a glob pattern (e.g., "src/**/*.lux"). Implemented
across interpreter (using glob crate), JS backend (handler-based),
and C backend (using POSIX glob.h).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Support """...""" syntax for multiline strings with:
- Automatic indent stripping (based on minimum indentation)
- Leading newline after opening """ is skipped
- Trailing whitespace-only line before closing """ is stripped
- String interpolation ({expr}) support
- All escape sequences supported
- Formatter outputs multiline strings for strings containing newlines
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add sorting support to the List module across all backends:
- List.sort for natural ordering (Int, Float, String, Bool, Char)
- List.sortBy for custom comparator-based sorting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added module: Option<Ident> to Pattern::Constructor, updated parser to
handle module.Constructor(args) syntax in patterns, exported ADT
constructors from modules, and copied type definitions during module
import so types like Shape are usable in importing files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added skip_newlines() calls throughout the parser so that newlines are
properly handled in parameter lists, tuple expressions, and pattern
matching constructs. Fixes Issue 5 and Issue 6 from ISSUES.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three bugs fixed:
- Global let bindings always typed as LuxInt; now inferred from value
- Option inner type not tracked for function params; added
var_option_inner_types map so match extraction uses correct type
- indexOf/lastIndexOf stored ints as (void*)(intptr_t) but extraction
expected boxed pointers; now uses lux_box_int consistently
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
File.copy(source, dest) copies files via interpreter (std::fs::copy) and
C backend (fread/fwrite). Effectful callbacks passed to higher-order
functions like List.map/forEach now propagate their effects to the
enclosing function's inferred effect set.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- WISH-008: `and`/`or` as aliases for `&&`/`||` boolean operators
- WISH-006: `handle` as alias for `run ... with` (same AST output)
- WISH-005: `--watch` flag for `lux compile` recompiles on file change
- WISH-009: Tree-shake unused runtime sections from JS output based on
which effects are actually used (Console, Random, Time, Http, Dom)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds interpreter, JS compilation, and C compilation checks for all
examples, showcase programs, standard examples, and projects (113 total
checks). Skip lists exclude programs requiring unsupported effects or
interactive I/O.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Top-level let bindings with function calls (e.g., `let result = factorial(10)`)
were emitted as static initializers, which is invalid C since function calls
aren't compile-time constants. Now globals are declared with zero-init and
initialized inside main() before any run expressions execute.
Also fixes validate.sh to use exit codes instead of grep for cargo check/build.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- JS backend: Add Int/Float module dispatch in both Call and EffectOp paths
for toFloat, toInt, and toString operations
- C backend: Fix lux_strdup → lux_string_dup in Map module codegen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Map<String, V> as a first-class built-in type for key-value storage,
needed for self-hosting the compiler (parser/typechecker/interpreter all
rely heavily on hashmaps).
- types.rs: Type::Map(K,V) variant, all match arms (unify, apply, etc.)
- interpreter.rs: Value::Map, 12 BuiltinFn variants (new/set/get/contains/
remove/keys/values/size/isEmpty/fromList/toList/merge), immutable semantics
- typechecker.rs: Map<K,V> resolution in resolve_type
- js_backend.rs: Map as JS Map with emit_map_operation()
- c_backend.rs: LuxMap struct (linear-scan), runtime fns, emit_map_operation()
- main.rs: 12 tests covering all Map operations
- validate.sh: now checks all projects/ directories too
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The parser now skips newlines between the condition and `then` keyword,
enabling multiline if expressions like:
if long_condition
then expr1
else expr2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three related bugs fixed:
- BUG-009: let bindings inside lambdas hoisted to top-level
- BUG-011: match expressions inside lambdas hoisted to top-level
- BUG-012: variable name deduplication leaked across function scopes
Root cause: emit_expr() uses writeln() for statements, but lambdas
captured only the return value, not the emitted statements. Also,
var_substitutions from emit_function() leaked to subsequent code.
Fix: Lambda handler now captures all output emitted during body
evaluation and places it inside the function body. Both emit_function
and Lambda save/restore var_substitutions to prevent cross-scope leaks.
Lambda params are registered as identity substitutions to override any
outer bindings with the same name.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve type aliases (e.g. Player -> { pos: Vec2, speed: Float })
before checking if spread expression is a record type. Previously
{ ...p, field: val } failed with "must be a record type, got Player"
when the variable had a named type annotation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds spread operator for records, allowing concise record updates:
let p2 = { ...p, x: 5.0 }
Changes across the full pipeline:
- Lexer: new DotDotDot (...) token
- AST: optional spread field on Record variant
- Parser: detect ... at start of record expression
- Typechecker: merge spread record fields with explicit overrides
- Interpreter: evaluate spread, overlay explicit fields
- JS backend: emit native JS spread syntax
- C backend: copy spread into temp, assign overrides
- Formatter, linter, LSP, symbol table: propagate spread
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds trigonometric functions to the Math module across interpreter,
type system, and C backend. JS backend already supported them.
Also adds #include <math.h> to C preamble and handles Math module
calls through both Call and EffectOp paths in C backend.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- JS backend now emits wildcard let bindings as side-effect statements
instead of const _ declarations, fixing SyntaxError on multiple let _ = ...
- Version string now uses env!("CARGO_PKG_VERSION") to auto-sync with Cargo.toml
- Add -lm linker flag for math library support
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BUG-004: Add ++ operator for string and list concatenation across all
backends (interpreter, C, JS) with type checking and formatting support.
BUG-001: Auto-invoke top-level `let main = fn () => ...` when main is
a zero-parameter function, instead of just printing the function value.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>