# Lux Language Limitations (grapho CLI) This document tracks limitations encountered while developing the grapho CLI in Lux, to help improve the language. ## Fixed Issues ### 1. Double Execution Bug (FIXED) **Severity:** Critical **Status:** Fixed in Lux c_backend.rs When using `let result = run main() with {}` to invoke the main function, the entire program was executing twice. **Root Cause:** In `c_backend.rs:3878-3907`, the generated C code was: 1. Executing all `run` expressions (including `run main() with {}`) 2. Then ALSO calling `main_lux()` separately because `has_main` was true **Fix:** Added tracking of whether main was already called via a `run` expression, and skip the separate `main_lux()` call if so. --- ## String Handling Issues ### 2. No Escape Sequences in String Literals **Severity:** High **Status:** Confirmed Lux does not support backslash escape sequences like `\"`, `\n`, `\t` in string literals. ```lux // This FAILS - backslash causes parse error Console.print("Hello \"World\"") // ERROR: Unexpected character: '\' // This FAILS Console.print("Line1\nLine2") // ERROR: Unexpected character: '\' ``` **Impact:** Cannot include quotes in strings, cannot create multi-line strings, cannot output JSON with proper formatting. **Workaround:** - Use shell commands via `Process.exec` to generate quoted output - Use `String.fromChar('"')` for quotes (but this had issues too) - For JSON output, use key=value format instead ### 3. Dollar Sign in Strings Causes Parse Error **Severity:** Medium **Status:** Confirmed The `$` character in strings triggers the string interpolation lexer, even inside shell command strings. ```lux // This FAILS execQuiet("jq -n --arg x '$foo' ...") // ERROR: Unexpected character: '$' ``` **Impact:** Cannot use shell variable syntax or jq arguments in command strings. **Workaround:** Avoid `$` in strings, or construct commands differently. ### 4. String.fromChar Returns Int, Not String **Severity:** Medium **Status:** Bug `String.fromChar('"')` appears to return an Int instead of a String, causing C compilation errors. ```lux let q = String.fromChar('"') // Compiles but C code is wrong Console.print(q + "hello") // C error: int + string ``` **Impact:** Cannot use character literals to build strings. **Workaround:** Use `execQuiet("printf '%s' '\"'")` to get a quote character. --- ## Type System Issues ### 5. Record Type Definitions Don't Work as Expected **Severity:** Medium **Status:** Needs Investigation Defining a record type and then creating values of that type doesn't work: ```lux type ComponentStatus = { name: String, status: HealthStatus, message: String, fix: String } fn checkNb(): ComponentStatus with {Process} = { // ... { name: "nb", status: Healthy, message: "ok", fix: "" } // ERROR: Cannot unify { name: String, ... } with ComponentStatus } ``` **Impact:** Cannot use structured types for cleaner code organization. **Workaround:** Avoid record types, use multiple return values via tuples or restructure code. ### 6. Int.parse Doesn't Exist or Has Wrong Signature **Severity:** Low **Status:** Confirmed There's no obvious way to parse a string to an integer. ```lux let count = Int.parse(someString) // ERROR: Unknown effect operation ``` **Impact:** Cannot convert string output from shell commands to numbers. **Workaround:** Keep numbers as strings, use shell for numeric comparisons. --- ## C Backend Issues ### 7. String Equality Comparison Generates Incorrect C Code **Severity:** High **Status:** Bug Using `==` to compare strings generates C code that compares pointers instead of string contents. ```lux let result = execQuiet("echo yes") if result == "yes" then ... // C code: (result == "yes") - pointer comparison! ``` **Impact:** String comparisons fail in compiled binaries. **Workaround:** Use `String.contains` for comparison: ```lux fn isYes(s: String): Bool = String.contains(s, "yes") if result |> isYes then ... ``` ### 8. String.startsWith Not Available in C Backend **Severity:** Medium **Status:** Bug `String.startsWith` works in interpreter but generates undefined function calls in C. ```lux String.startsWith(s, "prefix") // C error: lux_string__startsWith undefined ``` **Workaround:** Use `String.contains` instead. ### 9. `let _ = expr` Pattern Not Supported **Severity:** Low **Status:** Bug The underscore wildcard pattern for discarding results doesn't work. ```lux let _ = Process.exec("...") // ERROR: Expected identifier ``` **Workaround:** Use a named binding: ```lux let ignore = Process.exec("...") ``` ### 10. List Literals and Recursion Cause Segfaults **Severity:** High **Status:** Bug Combining list literals with recursive functions can cause segmentation faults in compiled binaries while working fine in interpreter. ```lux // This crashes when compiled: let dirs = ["a", "b", "c"] fn processDirs(dirs: List): Unit = match List.head(dirs) { Some(d) => { ...; match List.tail(dirs) { Some(rest) => processDirs(rest), ... } } None => () } ``` **Workaround:** Avoid list literals with recursive processing. Inline the operations: ```lux fn processA(): Unit = ... fn processB(): Unit = ... fn processC(): Unit = ... // Call each individually ``` --- ## Suggestions for Lux 1. **Add escape sequence support** - At minimum `\"`, `\\`, `\n`, `\t` 2. **Fix String.fromChar** to return String, not Int 3. **Add raw string literals** - Something like `r"..."` or `'''...'''` for shell commands 4. **Fix the double execution bug** in the runtime (DONE) 5. **Support record type literals** matching their declared type 6. **Add Int.parse and Float.parse** for string-to-number conversion 7. **Consider a heredoc syntax** for multi-line strings with special characters 8. **Fix string equality** - Use strcmp in C backend for string == 9. **Support `let _ = `** - Allow underscore as discard binding 10. **Fix String.startsWith** in C backend 11. **Fix list literals with recursion** causing segfaults --- ## Current Workarounds in grapho CLI 1. **Double output:** FIXED in Lux c_backend.rs 2. **JSON output:** Using key=value format instead of proper JSON 3. **Quotes in output:** Avoided entirely or generated via shell 4. **Structured types:** Using individual variables instead of records 5. **Numeric parsing:** Keeping counts as strings throughout 6. **String comparison:** Using `String.contains` with helper functions instead of `==` 7. **Discarding results:** Using `let ignore = ...` instead of `let _ = ...` 8. **Lists with recursion:** Replaced with individual function calls