# Lux Language Issues — blu-site SSG Project

Issues discovered while building a static site generator in Lux. Each entry includes a reproduction case and the workaround used.

---

## Issue 1: `Html.render()` / `Html.document()` not available in interpreter

**Category**: Missing feature
**Severity**: High

The Html module only works in the JS backend, not the interpreter. All HTML must be generated via string concatenation.

**Workaround**: Build all HTML as concatenated strings.

---

## Issue 2: String interpolation `{}` has no escape mechanism

**Category**: Missing feature → **Fixed** (added `\{` and `\}` escape sequences)
**Severity**: High

Any `{` inside a string literal triggers interpolation mode, and there was no way to include literal braces. This breaks when generating JavaScript like `function() { ... }` or JSON like `{}`.

**Reproduction**:
```lux
let s = "function() { return 1; }"  // Parse error: treats { } as interpolation
```

**Fix**: Added `\{` and `\}` as escape sequences in the lexer (src/lexer.rs). Also fixed the formatter (src/formatter.rs) to re-escape `{` and `}` in string literals so that `lux fmt` doesn't break escaped braces. Now:
```lux
let s = "function() \{ return 1; \}"  // Works, produces literal braces
```

---

## Issue 3: Module-qualified constructors not supported in pattern matching

**Category**: Parser limitation
**Severity**: High

Cannot use `module.Constructor` in match patterns. The parser expects `=>` but finds `.`.

**Reproduction**:
```lux
import frontmatter
let result = frontmatter.parse(content);
match result {
    frontmatter.ParseResult(front, body) => ...  // ERROR: Expected =>, found .
}
```

**Workaround**: Consolidated everything into a single file. Alternatively, use `import foo.*` (wildcard imports), though this can cause name conflicts.

---

## Issue 4: Tuple field access (`.0`, `.1`) not supported

**Category**: Missing feature
**Severity**: High

The parser's field access only works on Records (with named fields), not tuples. The `.` operator expects an identifier.

**Reproduction**:
```lux
let pair = ("hello", 42);
let x = pair.0;  // ERROR: Expected identifier
```

**Workaround**: Use ADTs (algebraic data types) with accessor functions:
```lux
type Pair = | Pair(String, Int)
fn first(p: Pair): String = match p { Pair(a, _) => a }
```

---

## Issue 5: Multi-line function arguments cause parse errors

**Category**: Parser limitation
**Severity**: High

Function call arguments cannot span multiple lines. The parser sees `\n` where it expects `,` or `)`.

**Reproduction**:
```lux
let result = someFunction(
    arg1,
    arg2
);  // ERROR: Expected ,, found \n
```

**Workaround**: Keep all function arguments on a single line, or use `let` bindings for intermediate values:
```lux
let a = arg1;
let b = arg2;
let result = someFunction(a, b);
```

---

## Issue 6: Multi-line lambdas in function call arguments fail

**Category**: Parser limitation
**Severity**: High

Lambda bodies that span multiple lines inside function call arguments cause parse errors.

**Reproduction**:
```lux
List.map(items, fn(x: Int): Int =>
    x + 1  // ERROR: Expected ,, found \n
);
```

**Workaround**: Either keep lambdas on one line or extract to named functions:
```lux
fn addOne(x: Int): Int = x + 1
List.map(items, addOne)
```

---

## Issue 7: Effectful callbacks in `List.map`/`forEach`/`fold`

**Category**: Type checker limitation
**Severity**: Medium

The type checker requires pure callbacks for higher-order List functions, but effectful callbacks are often needed (e.g., reading files in a map operation).

**Reproduction**:
```lux
fn readFile(path: String): String with {File} = File.read(path)
let contents = List.map(paths, fn(p: String): String => readFile(p));
// ERROR: Effect mismatch: expected {File}, got {}
```

**Workaround**: Use manual recursion instead of List.map/forEach:
```lux
fn mapRead(paths: List<String>): List<String> with {File} =
    match List.head(paths) {
        None => [],
        Some(p) => {
            let content = readFile(p);
            match List.tail(paths) {
                Some(rest) => List.concat([content], mapRead(rest)),
                None => [content]
            }
        }
    }
```

---

## Issue 8: `String.indexOf` and `String.lastIndexOf` missing from type checker

**Category**: Type checker gap → **Fixed**
**Severity**: Medium

These functions exist in the interpreter but were not registered in the type checker, causing "Module 'String' has no member" errors.

**Fix**: Added type registrations in src/types.rs:
- `String.indexOf(String, String) -> Option<Int>`
- `String.lastIndexOf(String, String) -> Option<Int>`

---

## Issue 9: No `List.sort` / `List.sortBy`

**Category**: Missing feature
**Severity**: Medium

No built-in sorting for lists. Must implement manually.

**Workaround**: Insertion sort via `List.fold`:
```lux
fn sortByDateDesc(items: List<Page>): List<Page> =
    List.fold(items, [], sortInsert)

fn insertByDate(sorted: List<Page>, item: Page): List<Page> = {
    match List.head(sorted) {
        None => [item],
        Some(first) =>
            if pgDate(item) >= pgDate(first) then
                List.concat([item], sorted)
            else
                match List.tail(sorted) {
                    Some(rest) => List.concat([first], insertByDate(rest, item)),
                    None => [first, item]
                }
    }
}
```

---

## Issue 10: No HashMap/Map type

**Category**: Missing feature
**Severity**: Medium

No associative data structure available. Tag grouping required manual list scanning.

**Workaround**: Use `List<(key, value)>` with `List.filter`/`List.find` for lookups. O(n) per lookup.

---

## Issue 11: No regex support

**Category**: Missing feature
**Severity**: Medium

Inline markdown parsing (bold, italic, links, code) required manual character-by-character scanning with index tracking.

**Workaround**: Recursive `processInlineFrom(text, i, len, acc)` function scanning character by character.

---

## Issue 12: No multiline string literals

**Category**: Missing feature
**Severity**: Medium

HTML templates require very long single-line strings with many `+` concatenations and `\"` escapes.

**Workaround**: Concatenate multiple single-line strings with `+`.

---

## Issue 13: `Json.parse` returns `Result<Json, String>`

**Category**: Documentation gap
**Severity**: Low

Not immediately obvious that `Json.parse` wraps the result in `Ok`/`Err`. Error message "Json.get expects Json, got Constructor" is confusing.

**Workaround**: Pattern match on `Ok(j)` / `Err(_)`:
```lux
let json = match Json.parse(raw) { Ok(j) => j, Err(_) => ... };
```

---

## Issue 14: No `File.copy`

**Category**: Missing feature
**Severity**: Low

Must shell out to copy files/directories.

**Workaround**: `Process.exec("cp -r static/* _site/")`.

---

## Issue 15: No file globbing

**Category**: Missing feature
**Severity**: Low

Must manually scan directories and filter by extension.

**Workaround**: `File.readDir(dir)` + `List.filter(entries, fn(e) => String.endsWith(e, ".md"))`.

---

## Summary

| # | Issue | Severity | Status |
|---|-------|----------|--------|
| 1 | Html module interpreter-only | High | Open |
| 2 | No `\{` `\}` string escapes | High | **Fixed** |
| 3 | Module-qualified pattern matching | High | Open |
| 4 | Tuple field access `.0` `.1` | High | Open |
| 5 | Multi-line function arguments | High | Open |
| 6 | Multi-line lambdas in calls | High | Open |
| 7 | Effectful callbacks in List HOFs | Medium | Open |
| 8 | String.indexOf/lastIndexOf types | Medium | **Fixed** |
| 9 | No List.sort | Medium | Open |
| 10 | No HashMap/Map | Medium | Open |
| 11 | No regex | Medium | Open |
| 12 | No multiline strings | Medium | Open |
| 13 | Json.parse return type docs | Low | Open |
| 14 | No File.copy | Low | Open |
| 15 | No file globbing | Low | Open |
