Compare commits
3 Commits
3a2376cd49
...
v0.1.4
| Author | SHA1 | Date | |
|---|---|---|---|
| b0ccde749c | |||
| 4ba7a23ae3 | |||
| 89741b4a32 |
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lux"
|
name = "lux"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A functional programming language with first-class effects, schema evolution, and behavioral types"
|
description = "A functional programming language with first-class effects, schema evolution, and behavioral types"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
printf "\n"
|
printf "\n"
|
||||||
printf " \033[1;35m╦ ╦ ╦╦ ╦\033[0m\n"
|
printf " \033[1;35m╦ ╦ ╦╦ ╦\033[0m\n"
|
||||||
printf " \033[1;35m║ ║ ║╔╣\033[0m\n"
|
printf " \033[1;35m║ ║ ║╔╣\033[0m\n"
|
||||||
printf " \033[1;35m╩═╝╚═╝╩ ╩\033[0m v0.1.3\n"
|
printf " \033[1;35m╩═╝╚═╝╩ ╩\033[0m v0.1.4\n"
|
||||||
printf "\n"
|
printf "\n"
|
||||||
printf " Functional language with first-class effects\n"
|
printf " Functional language with first-class effects\n"
|
||||||
printf "\n"
|
printf "\n"
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
|
|
||||||
packages.default = pkgs.rustPlatform.buildRustPackage {
|
packages.default = pkgs.rustPlatform.buildRustPackage {
|
||||||
pname = "lux";
|
pname = "lux";
|
||||||
version = "0.1.3";
|
version = "0.1.4";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
cargoLock.lockFile = ./Cargo.lock;
|
cargoLock.lockFile = ./Cargo.lock;
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
};
|
};
|
||||||
in muslPkgs.rustPlatform.buildRustPackage {
|
in muslPkgs.rustPlatform.buildRustPackage {
|
||||||
pname = "lux";
|
pname = "lux";
|
||||||
version = "0.1.3";
|
version = "0.1.4";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
cargoLock.lockFile = ./Cargo.lock;
|
cargoLock.lockFile = ./Cargo.lock;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Lux Full Validation Script
|
# Lux Full Validation Script
|
||||||
# Runs all checks: Rust tests, package tests, type checking, formatting, linting.
|
# Runs all checks: Rust tests, package tests, type checking, example compilation.
|
||||||
# Run after every committable change to ensure no regressions.
|
# Run after every committable change to ensure no regressions.
|
||||||
|
|
||||||
# cd to repo root (directory containing this script's parent)
|
# cd to repo root (directory containing this script's parent)
|
||||||
@@ -11,6 +11,8 @@ cd "$SCRIPT_DIR/.."
|
|||||||
|
|
||||||
LUX="$(pwd)/target/release/lux"
|
LUX="$(pwd)/target/release/lux"
|
||||||
PACKAGES_DIR="$(pwd)/../packages"
|
PACKAGES_DIR="$(pwd)/../packages"
|
||||||
|
PROJECTS_DIR="$(pwd)/projects"
|
||||||
|
EXAMPLES_DIR="$(pwd)/examples"
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
CYAN='\033[0;36m'
|
CYAN='\033[0;36m'
|
||||||
@@ -30,7 +32,7 @@ fail() { printf "${RED}FAIL${NC} %s\n" "${1:-}"; FAILED=$((FAILED + 1)); }
|
|||||||
|
|
||||||
# --- Rust checks ---
|
# --- Rust checks ---
|
||||||
step "cargo check"
|
step "cargo check"
|
||||||
if nix develop --command cargo check 2>&1 | grep -q "Finished"; then ok; else fail; fi
|
if nix develop --command cargo check 2>/dev/null; then ok; else fail; fi
|
||||||
|
|
||||||
step "cargo test"
|
step "cargo test"
|
||||||
OUTPUT=$(nix develop --command cargo test 2>&1 || true)
|
OUTPUT=$(nix develop --command cargo test 2>&1 || true)
|
||||||
@@ -39,7 +41,7 @@ if echo "$RESULT" | grep -q "0 failed"; then ok "$RESULT"; else fail "$RESULT";
|
|||||||
|
|
||||||
# --- Build release binary ---
|
# --- Build release binary ---
|
||||||
step "cargo build --release"
|
step "cargo build --release"
|
||||||
if nix develop --command cargo build --release 2>&1 | grep -q "Finished"; then ok; else fail; fi
|
if nix develop --command cargo build --release 2>/dev/null; then ok; else fail; fi
|
||||||
|
|
||||||
# --- Package tests ---
|
# --- Package tests ---
|
||||||
for pkg in path frontmatter xml rss markdown; do
|
for pkg in path frontmatter xml rss markdown; do
|
||||||
@@ -64,7 +66,6 @@ for pkg in path frontmatter xml rss markdown; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# --- Project checks ---
|
# --- Project checks ---
|
||||||
PROJECTS_DIR="$(pwd)/projects"
|
|
||||||
for proj_dir in "$PROJECTS_DIR"/*/; do
|
for proj_dir in "$PROJECTS_DIR"/*/; do
|
||||||
proj=$(basename "$proj_dir")
|
proj=$(basename "$proj_dir")
|
||||||
if [ -f "$proj_dir/main.lux" ]; then
|
if [ -f "$proj_dir/main.lux" ]; then
|
||||||
@@ -83,6 +84,123 @@ for proj_dir in "$PROJECTS_DIR"/*/; do
|
|||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# === Compilation & Interpreter Checks ===
|
||||||
|
|
||||||
|
# --- Interpreter: examples ---
|
||||||
|
# Skip: http_api, http, http_router, http_server (network), postgres_demo (db),
|
||||||
|
# random, property_testing (Random effect), shell (Process), json (File I/O),
|
||||||
|
# file_io (File I/O), test_math, test_lists (Test effect), stress_shared_rc,
|
||||||
|
# test_rc_comparison (internal tests), modules/* (need cwd)
|
||||||
|
INTERP_SKIP="http_api http http_router http_server postgres_demo random property_testing shell json file_io test_math test_lists stress_shared_rc test_rc_comparison"
|
||||||
|
for f in "$EXAMPLES_DIR"/*.lux; do
|
||||||
|
name=$(basename "$f" .lux)
|
||||||
|
skip=false
|
||||||
|
for s in $INTERP_SKIP; do [ "$name" = "$s" ] && skip=true; done
|
||||||
|
$skip && continue
|
||||||
|
step "interpreter (examples/$name)"
|
||||||
|
if timeout 10 "$LUX" "$f" >/dev/null 2>&1; then ok; else fail; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- Interpreter: examples/standard ---
|
||||||
|
# Skip: guessing_game (reads stdin)
|
||||||
|
for f in "$EXAMPLES_DIR"/standard/*.lux; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
name=$(basename "$f" .lux)
|
||||||
|
[ "$name" = "guessing_game" ] && continue
|
||||||
|
step "interpreter (standard/$name)"
|
||||||
|
if timeout 10 "$LUX" "$f" >/dev/null 2>&1; then ok; else fail; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- Interpreter: examples/showcase ---
|
||||||
|
# Skip: task_manager (parse error in current version)
|
||||||
|
for f in "$EXAMPLES_DIR"/showcase/*.lux; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
name=$(basename "$f" .lux)
|
||||||
|
[ "$name" = "task_manager" ] && continue
|
||||||
|
step "interpreter (showcase/$name)"
|
||||||
|
if timeout 10 "$LUX" "$f" >/dev/null 2>&1; then ok; else fail; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- Interpreter: projects ---
|
||||||
|
# Skip: guessing-game (Random), rest-api (HttpServer)
|
||||||
|
PROJ_INTERP_SKIP="guessing-game rest-api"
|
||||||
|
for proj_dir in "$PROJECTS_DIR"/*/; do
|
||||||
|
proj=$(basename "$proj_dir")
|
||||||
|
[ -f "$proj_dir/main.lux" ] || continue
|
||||||
|
skip=false
|
||||||
|
for s in $PROJ_INTERP_SKIP; do [ "$proj" = "$s" ] && skip=true; done
|
||||||
|
$skip && continue
|
||||||
|
step "interpreter (project: $proj)"
|
||||||
|
if timeout 10 "$LUX" "$proj_dir/main.lux" >/dev/null 2>&1; then ok; else fail; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- JS compilation: examples ---
|
||||||
|
# Skip files that fail JS compilation (unsupported features)
|
||||||
|
JS_SKIP="http_api http http_router postgres_demo property_testing json test_lists test_rc_comparison"
|
||||||
|
for f in "$EXAMPLES_DIR"/*.lux; do
|
||||||
|
name=$(basename "$f" .lux)
|
||||||
|
skip=false
|
||||||
|
for s in $JS_SKIP; do [ "$name" = "$s" ] && skip=true; done
|
||||||
|
$skip && continue
|
||||||
|
step "compile JS (examples/$name)"
|
||||||
|
if "$LUX" compile "$f" --target js -o /tmp/lux_validate.js >/dev/null 2>&1; then ok; else fail; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- JS compilation: examples/standard ---
|
||||||
|
# Skip: stdlib_demo (uses String.toUpper not in JS backend)
|
||||||
|
for f in "$EXAMPLES_DIR"/standard/*.lux; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
name=$(basename "$f" .lux)
|
||||||
|
[ "$name" = "stdlib_demo" ] && continue
|
||||||
|
step "compile JS (standard/$name)"
|
||||||
|
if "$LUX" compile "$f" --target js -o /tmp/lux_validate.js >/dev/null 2>&1; then ok; else fail; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- JS compilation: examples/showcase ---
|
||||||
|
# Skip: task_manager (unsupported features)
|
||||||
|
for f in "$EXAMPLES_DIR"/showcase/*.lux; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
name=$(basename "$f" .lux)
|
||||||
|
[ "$name" = "task_manager" ] && continue
|
||||||
|
step "compile JS (showcase/$name)"
|
||||||
|
if "$LUX" compile "$f" --target js -o /tmp/lux_validate.js >/dev/null 2>&1; then ok; else fail; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- JS compilation: projects ---
|
||||||
|
# Skip: json-parser, rest-api (unsupported features)
|
||||||
|
JS_PROJ_SKIP="json-parser rest-api"
|
||||||
|
for proj_dir in "$PROJECTS_DIR"/*/; do
|
||||||
|
proj=$(basename "$proj_dir")
|
||||||
|
[ -f "$proj_dir/main.lux" ] || continue
|
||||||
|
skip=false
|
||||||
|
for s in $JS_PROJ_SKIP; do [ "$proj" = "$s" ] && skip=true; done
|
||||||
|
$skip && continue
|
||||||
|
step "compile JS (project: $proj)"
|
||||||
|
if "$LUX" compile "$proj_dir/main.lux" --target js -o /tmp/lux_validate.js >/dev/null 2>&1; then ok; else fail; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- C compilation: examples ---
|
||||||
|
# Only compile examples known to work with C backend
|
||||||
|
C_EXAMPLES="hello factorial pipelines tailcall jit_test"
|
||||||
|
for name in $C_EXAMPLES; do
|
||||||
|
f="$EXAMPLES_DIR/$name.lux"
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
step "compile C (examples/$name)"
|
||||||
|
if "$LUX" compile "$f" -o /tmp/lux_validate_bin >/dev/null 2>&1; then ok; else fail; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- C compilation: examples/standard ---
|
||||||
|
C_STD_EXAMPLES="hello_world factorial fizzbuzz primes guessing_game"
|
||||||
|
for name in $C_STD_EXAMPLES; do
|
||||||
|
f="$EXAMPLES_DIR/standard/$name.lux"
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
step "compile C (standard/$name)"
|
||||||
|
if "$LUX" compile "$f" -o /tmp/lux_validate_bin >/dev/null 2>&1; then ok; else fail; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- Cleanup ---
|
||||||
|
rm -f /tmp/lux_validate.js /tmp/lux_validate_bin
|
||||||
|
|
||||||
# --- Summary ---
|
# --- Summary ---
|
||||||
printf "\n${BOLD}═══ Validation Summary ═══${NC}\n"
|
printf "\n${BOLD}═══ Validation Summary ═══${NC}\n"
|
||||||
if [ $FAILED -eq 0 ]; then
|
if [ $FAILED -eq 0 ]; then
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ impl CBackend {
|
|||||||
Declaration::Let(let_decl) => {
|
Declaration::Let(let_decl) => {
|
||||||
// Skip run expressions - they're handled in the main wrapper
|
// Skip run expressions - they're handled in the main wrapper
|
||||||
if !matches!(&let_decl.value, Expr::Run { .. }) {
|
if !matches!(&let_decl.value, Expr::Run { .. }) {
|
||||||
self.emit_global_let(&let_decl.name, &let_decl.value)?;
|
self.emit_global_let(&let_decl.name)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -5561,9 +5561,9 @@ impl CBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_global_let(&mut self, name: &Ident, value: &Expr) -> Result<(), CGenError> {
|
fn emit_global_let(&mut self, name: &Ident) -> Result<(), CGenError> {
|
||||||
let val = self.emit_expr(value)?;
|
// Declare global variable without initializer (initialized in main)
|
||||||
self.writeln(&format!("static LuxInt {} = {};", name.name, val));
|
self.writeln(&format!("static LuxInt {} = 0;", name.name));
|
||||||
self.writeln("");
|
self.writeln("");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -5574,12 +5574,16 @@ impl CBackend {
|
|||||||
matches!(d, Declaration::Function(f) if f.name.name == "main")
|
matches!(d, Declaration::Function(f) if f.name.name == "main")
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check for top-level run expressions
|
// Check for top-level run expressions or let bindings
|
||||||
let has_run = program.declarations.iter().any(|d| {
|
let has_run = program.declarations.iter().any(|d| {
|
||||||
matches!(d, Declaration::Let(let_decl) if matches!(&let_decl.value, Expr::Run { .. }))
|
matches!(d, Declaration::Let(let_decl) if matches!(&let_decl.value, Expr::Run { .. }))
|
||||||
});
|
});
|
||||||
|
|
||||||
if has_main || has_run {
|
let has_global_lets = program.declarations.iter().any(|d| {
|
||||||
|
matches!(d, Declaration::Let(let_decl) if !matches!(&let_decl.value, Expr::Run { .. }))
|
||||||
|
});
|
||||||
|
|
||||||
|
if has_main || has_run || has_global_lets {
|
||||||
self.writeln("int main(int argc, char** argv) {");
|
self.writeln("int main(int argc, char** argv) {");
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
|
|
||||||
@@ -5588,6 +5592,16 @@ impl CBackend {
|
|||||||
self.writeln("lux_argv = argv;");
|
self.writeln("lux_argv = argv;");
|
||||||
self.writeln("");
|
self.writeln("");
|
||||||
|
|
||||||
|
// Initialize top-level let bindings (non-run) inside main
|
||||||
|
for decl in &program.declarations {
|
||||||
|
if let Declaration::Let(let_decl) = decl {
|
||||||
|
if !matches!(&let_decl.value, Expr::Run { .. }) {
|
||||||
|
let val = self.emit_expr(&let_decl.value)?;
|
||||||
|
self.writeln(&format!("{} = {};", let_decl.name.name, val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Execute top-level let bindings with run expressions
|
// Execute top-level let bindings with run expressions
|
||||||
// Track if main was already called via a run expression
|
// Track if main was already called via a run expression
|
||||||
let mut main_called_via_run = false;
|
let mut main_called_via_run = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user