diff --git a/.gitignore b/.gitignore index 4b9a797..d67efc3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,10 @@ result result-* .direnv/ +# Compiled binaries +grapho +*_test + # Secrets (NEVER commit unencrypted secrets) secrets/*.yaml !secrets/secrets.yaml.example diff --git a/README.md b/README.md index 251ff4f..4cd7157 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Ultimate Notetaking, Sync & Backup System -A NixOS-based system for managing the three types of data in a computer: +A NixOS-based system for managing the three types of data across devices: | Tier | Type | Examples | Sync Model | |------|------|----------|------------| diff --git a/docs/LUX-LIMITATIONS.md b/docs/LUX-LIMITATIONS.md deleted file mode 100644 index 31cbc2f..0000000 --- a/docs/LUX-LIMITATIONS.md +++ /dev/null @@ -1,218 +0,0 @@ -# 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 diff --git a/grapho b/grapho deleted file mode 100755 index f6c565b..0000000 Binary files a/grapho and /dev/null differ