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>
Bare `print()` calls in Lux now emit `console.log()` in JS output
instead of undefined `print()`. Fixes BUG-006.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Release script now supports: patch (default), minor, major, or explicit
version. Auto-updates Cargo.toml and flake.nix before building.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Expand type aliases via unify_with_env() everywhere in the type checker,
not just in a few places. This fixes named record types like
`type Vec2 = { x: Float, y: Float }` — they now properly unify with
anonymous records and support field access (v.x, v.y).
Also adds scripts/validate.sh for automated full-suite regression
testing (Rust tests + all 5 package test suites + type checking).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch reqwest from native-tls (openssl) to rustls-tls for a pure-Rust
TLS stack, enabling fully static musl builds. Add `nix build .#static`
for portable Linux binaries and `scripts/release.sh` for automated
Gitea releases with changelog generation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The `lux test` command used Parser::parse_source() and
check_program() directly, which meant test files with `import`
statements would fail with type errors. Now uses ModuleLoader
and check_program_with_modules() to properly resolve imports,
and run_with_modules() for execution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The C backend can now compile programs that import user-defined modules.
Module-qualified calls like `mymodule.func(args)` are resolved to prefixed
C functions (e.g., `mymodule_func_lux`), with full support for transitive
imports and effect-passing. Also adds Int.toString/Float.toString to type
system, interpreter, and C backend, and Test.assertEqualMsg for labeled
test assertions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Write comprehensive PHILOSOPHY.md covering Lux's six core principles
(explicit over implicit, composition over configuration, safety without
ceremony, practical over academic, one right way, tools are the language)
with detailed comparisons against JS/TS, Python, Rust, Go, Java/C#,
Haskell/Elm, and Gleam/Elixir. Includes tooling audit and improvement
suggestions.
Add `lux philosophy` command to the compiler, update help screen with
abbreviated philosophy, and link from README.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add PACKAGES.md analyzing the Lux package ecosystem gaps vs stdlib,
with prioritized implementation plans for markdown, xml, rss, frontmatter,
path, and sitemap packages. Add CLAUDE.md instructions for documenting
Lux language errors in ISSUES.md during every major task.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
build.rs captures the absolute path to cc/gcc/clang during compilation
and bakes it into the binary. On Nix systems this embeds the full
/nix/store path so `lux compile` works without cc on PATH.
Lookup order: $CC env var > embedded build-time path > PATH search.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously `lux` with no args entered the REPL. Now it shows the help
menu. Use `lux repl` to start the REPL explicitly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Second round of C backend fixes, building on d8871ac which reduced
errors from 286 to 111. This eliminates all 79 non-json errors:
- Fix function references as values (wrap in LuxClosure*)
- Fix fold/map/filter with type-aware calling conventions
- Add String.indexOf/lastIndexOf emission and C runtime functions
- Add File.readDir with dirent.h implementation
- Fix string concat in closure bodies
- Exclude ADT constructors from closure free variable capture
- Fix match result type inference (prioritize pattern binding types)
- Fix Option inner type inference (usage-based for List.head)
- Fix void* to struct cast (dereference through pointer)
- Handle constructors in emit_expr_with_env
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix closure captured variable types: look up actual types from var_types
instead of hardcoding LuxInt for all captured variables
- Register function parameters in var_types so closures can find their types
- Replace is_string_expr() with infer_expr_type() for more accurate string
detection in binary ops (concat, comparison)
- Add missing String operations to infer_expr_type (substring, indexOf, etc.)
- Add module method call type inference (String.*, List.*, Int.*, Float.*)
- Add built-in Result type (Ok/Err) to C prelude alongside Option
- Register Ok/Err/Some/None in variant_to_type and variant_field_types
- Fix variable scoping: use if-statement pattern instead of ternary when
branches emit statements (prevents redefinition of h2/h3 etc.)
- Add RC scope management for if-else branches and match arms to prevent
undeclared variable errors from cleanup code
- Add infer_pattern_binding_type for better match result type inference
- Add expr_emits_statements helper to detect statement-emitting expressions
- Add infer_option_inner_type for String.indexOf (returns Option<Int>)
Reduces blu-site compilation errors from 286 to 111 (remaining are mostly
unsupported json effect and function-as-value references).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Tuple index: `pair.0`, `pair.1` syntax across parser, typechecker,
interpreter, C/JS backends, formatter, linter, and symbol table
- Multi-line function args: allow newlines inside argument lists
- Fix effect unification for callback parameters (empty expected
effects means "no constraint", not "must be pure")
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>