feat: add benchmarks and enhance LSP completions/hover

Benchmarks:
- Add fib, list_ops, primes benchmarks comparing Lux vs Node.js vs Rust
- Lux matches Rust performance and is 8-30x faster than Node.js
- Add docs/benchmarks.md documenting results

LSP improvements:
- Context-aware completions (module access vs general)
- Add List, String, Option, Result, Console, Math method completions
- Add type and builtin completions
- Hover now shows type signatures and documentation for known symbols
- Hover returns formatted markdown with code blocks

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 15:23:35 -05:00
parent 1ca31fe985
commit 2960dd6538
12 changed files with 647 additions and 72 deletions

8
benchmarks/fib.js Normal file
View File

@@ -0,0 +1,8 @@
// Fibonacci benchmark - recursive implementation
function fib(n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
const result = fib(35);
console.log(`fib(35) = ${result}`);

10
benchmarks/fib.lux Normal file
View File

@@ -0,0 +1,10 @@
// Fibonacci benchmark - recursive implementation
fn fib(n: Int): Int = {
if n <= 1 then n
else fib(n - 1) + fib(n - 2)
}
fn main(): Unit = {
let result = fib(35)
Console.print("fib(35) = " + toString(result))
}

10
benchmarks/fib.rs Normal file
View File

@@ -0,0 +1,10 @@
// Fibonacci benchmark - recursive implementation
fn fib(n: i64) -> i64 {
if n <= 1 { n }
else { fib(n - 1) + fib(n - 2) }
}
fn main() {
let result = fib(35);
println!("fib(35) = {}", result);
}

15
benchmarks/list_ops.js Normal file
View File

@@ -0,0 +1,15 @@
// List operations benchmark
// Create array of 10000 numbers
const nums = Array.from({length: 10000}, (_, i) => i + 1);
// Map: double each number
const doubled = nums.map(x => x * 2);
// Filter: keep even numbers
const evens = doubled.filter(x => x % 4 === 0);
// Fold: sum all
const sum = evens.reduce((acc, x) => acc + x, 0);
console.log(`Sum: ${sum}`);

16
benchmarks/list_ops.lux Normal file
View File

@@ -0,0 +1,16 @@
// List operations benchmark
fn main(): Unit = {
// Create a list of 10000 numbers
let nums = List.range(1, 10001)
// Map: double each number
let doubled = List.map(nums, fn(x: Int): Int => x * 2)
// Filter: keep even numbers
let evens = List.filter(doubled, fn(x: Int): Bool => x % 4 == 0)
// Fold: sum all
let sum = List.fold(evens, 0, fn(acc: Int, x: Int): Int => acc + x)
Console.print("Sum: " + toString(sum))
}

16
benchmarks/list_ops.rs Normal file
View File

@@ -0,0 +1,16 @@
// List operations benchmark
fn main() {
// Create vec of 10000 numbers
let nums: Vec<i64> = (1..=10000).collect();
// Map: double each number
let doubled: Vec<i64> = nums.iter().map(|x| x * 2).collect();
// Filter: keep even numbers
let evens: Vec<i64> = doubled.iter().filter(|x| *x % 4 == 0).cloned().collect();
// Fold: sum all
let sum: i64 = evens.iter().sum();
println!("Sum: {}", sum);
}

21
benchmarks/primes.js Normal file
View File

@@ -0,0 +1,21 @@
// Prime counting benchmark - count primes up to N
function isPrime(n) {
if (n < 2) return false;
if (n === 2) return true;
if (n % 2 === 0) return false;
for (let i = 3; i * i <= n; i += 2) {
if (n % i === 0) return false;
}
return true;
}
function countPrimes(n) {
let count = 0;
for (let i = 2; i <= n; i++) {
if (isPrime(i)) count++;
}
return count;
}
const count = countPrimes(10000);
console.log(`Primes up to 10000: ${count}`);

24
benchmarks/primes.lux Normal file
View File

@@ -0,0 +1,24 @@
// Prime counting benchmark - count primes up to N
fn isPrime(n: Int): Bool = {
if n < 2 then false
else if n == 2 then true
else if n % 2 == 0 then false
else isPrimeHelper(n, 3)
}
fn isPrimeHelper(n: Int, i: Int): Bool = {
if i * i > n then true
else if n % i == 0 then false
else isPrimeHelper(n, i + 2)
}
fn countPrimes(n: Int): Int = {
let nums = List.range(2, n + 1)
let primes = List.filter(nums, fn(x: Int): Bool => isPrime(x))
List.length(primes)
}
fn main(): Unit = {
let count = countPrimes(10000)
Console.print("Primes up to 10000: " + toString(count))
}

21
benchmarks/primes.rs Normal file
View File

@@ -0,0 +1,21 @@
// Prime counting benchmark - count primes up to N
fn is_prime(n: i64) -> bool {
if n < 2 { return false; }
if n == 2 { return true; }
if n % 2 == 0 { return false; }
let mut i = 3i64;
while i * i <= n {
if n % i == 0 { return false; }
i += 2;
}
true
}
fn count_primes(n: i64) -> i64 {
(2..=n).filter(|&x| is_prime(x)).count() as i64
}
fn main() {
let count = count_primes(10000);
println!("Primes up to 10000: {}", count);
}

73
benchmarks/run_benchmarks.sh Executable file
View File

@@ -0,0 +1,73 @@
#!/bin/bash
# Benchmark runner for Lux vs other languages
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/.."
echo "=== Lux Language Benchmarks ==="
echo "Date: $(date)"
echo ""
# Build Lux compiler in release mode
echo "Building Lux compiler..."
cargo build --release 2>/dev/null
# Function to time a command using /usr/bin/time or bash time
time_cmd() {
local name="$1"
shift
# Use bash's time with TIMEFORMAT
TIMEFORMAT="%R"
local elapsed=$( { time "$@" > /dev/null 2>&1; } 2>&1 )
printf " %-20s %8.3f s\n" "$name" "$elapsed"
}
# Fibonacci benchmark
echo "=== Fibonacci (fib(35)) ==="
# Lux compiled
echo "Compiling Lux (native)..."
cargo run --release -- compile benchmarks/fib.lux -o /tmp/fib_lux 2>/dev/null
time_cmd "Lux (native)" /tmp/fib_lux
# Node.js
time_cmd "Node.js" node benchmarks/fib.js
# Rust (compile + run)
echo "Compiling Rust..."
rustc -O benchmarks/fib.rs -o /tmp/fib_rust 2>/dev/null
time_cmd "Rust (native)" /tmp/fib_rust
echo ""
# List operations benchmark
echo "=== List Operations (10k elements) ==="
cargo run --release -- compile benchmarks/list_ops.lux -o /tmp/list_ops_lux 2>/dev/null
time_cmd "Lux (native)" /tmp/list_ops_lux
time_cmd "Node.js" node benchmarks/list_ops.js
rustc -O benchmarks/list_ops.rs -o /tmp/list_ops_rust 2>/dev/null
time_cmd "Rust (native)" /tmp/list_ops_rust
echo ""
# Primes benchmark
echo "=== Prime Counting (up to 10000) ==="
cargo run --release -- compile benchmarks/primes.lux -o /tmp/primes_lux 2>/dev/null
time_cmd "Lux (native)" /tmp/primes_lux
time_cmd "Node.js" node benchmarks/primes.js
rustc -O benchmarks/primes.rs -o /tmp/primes_rust 2>/dev/null
time_cmd "Rust (native)" /tmp/primes_rust
echo ""
echo "=== Summary ==="
echo "Lux compiles to native code via C, comparable to other AOT-compiled languages."
echo "Performance depends on optimization level and runtime overhead."