Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
*.wave linguist-language=Wave
*.wave linguist-language=Wave
tests/** linguist-detectable=false
205 changes: 197 additions & 8 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,78 @@ jobs:
- name: Run Rust tests
run: cargo test --locked --all-targets --verbose

- name: Run x86_64 SysV ABI contract tests
if: ${{ always() }}
env:
WAVE_RUN_X86_64_INTEROP_TESTS: "1"
run: >-
cargo test --locked --test codegen_regressions
x86_64_c_abi_interoperates_with_c --verbose

- name: Run Wave end-to-end tests
run: python3 tools/run_tests.py

build-linux-arm64:
name: Build Linux arm64
runs-on: ubuntu-24.04-arm
timeout-minutes: 45

steps:
- uses: actions/checkout@v4

- name: Setup Rust
uses: dtolnay/rust-toolchain@1.89.0
with:
components: rustfmt, clippy

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install LLVM 21
run: |
sudo apt-get update
sudo apt-get install -y wget software-properties-common
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 21
echo "LLVM_SYS_211_PREFIX=/usr/lib/llvm-21" >> "$GITHUB_ENV"
echo "LLVM_CONFIG_PATH=/usr/lib/llvm-21/bin/llvm-config" >> "$GITHUB_ENV"
echo "/usr/lib/llvm-21/bin" >> "$GITHUB_PATH"

- name: Install Wave stdlib
run: |
mkdir -p "$HOME/.wave/lib/wave"
rm -rf "$HOME/.wave/lib/wave/std"
cp -R std "$HOME/.wave/lib/wave/std"

- name: Check Rust formatting
run: cargo fmt --all --check

- name: Run Clippy
run: cargo clippy --locked --all-targets -- -D warnings

- name: Validate Python tooling
run: python3 -m py_compile x.py tools/run_tests.py

- name: Build release compiler
run: cargo build --locked --release --verbose

- name: Run Rust tests
run: cargo test --locked --all-targets --verbose

- name: Run AArch64 AAPCS64 contract tests
if: ${{ always() }}
env:
WAVE_RUN_AARCH64_INTEROP_TESTS: "1"
run: >-
cargo test --locked --test codegen_regressions
aarch64_c_abi_interoperates_with_c --verbose

- name: Run Wave end-to-end tests
if: ${{ always() }}
run: python3 tools/run_tests.py

build-linux-riscv64:
name: Build Linux riscv64
runs-on: ubuntu-24.04
Expand All @@ -80,6 +149,12 @@ jobs:

- name: Setup Rust
uses: dtolnay/rust-toolchain@1.89.0
with:
components: rustfmt, clippy

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install LLVM 21 and RISC-V runtime tools
run: |
Expand Down Expand Up @@ -110,18 +185,70 @@ jobs:
riscv64-linux-gnu-gcc --version
riscv64-linux-gnu-readelf --version
qemu-riscv64 --version
test -f /usr/riscv64-linux-gnu/lib/crt1.o
test -f /usr/riscv64-linux-gnu/lib/libc.so
test -f /usr/riscv64-linux-gnu/lib/ld-linux-riscv64-lp64d.so.1

- name: Install Wave stdlib
run: |
mkdir -p "$HOME/.wave/lib/wave"
rm -rf "$HOME/.wave/lib/wave/std"
cp -R std "$HOME/.wave/lib/wave/std"

- name: Check Rust formatting
run: cargo fmt --all --check

- name: Run Clippy
run: cargo clippy --locked --all-targets -- -D warnings

- name: Validate Python tooling
run: python3 -m py_compile x.py tools/run_tests.py

- name: Build release compiler
run: cargo build --locked --release --verbose

- name: Run Rust tests
run: cargo test --locked --all-targets --verbose

- name: Verify bundled Linux CRT matrix
if: ${{ always() }}
run: |
set -euo pipefail

crt_root="$(find target/release/build -type d -path '*/out/crt' -print -quit)"
test -n "$crt_root"

for target in x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu; do
for crt_name in crt1.o Scrt1.o rcrt1.o crti.o crtn.o; do
test -f "$crt_root/$target/$crt_name"
done
done

for abi in lp64 lp64f lp64d; do
for crt_name in crt1.o Scrt1.o rcrt1.o crti.o crtn.o; do
crt_path="$crt_root/riscv64-unknown-linux-gnu/$abi/$crt_name"
test -f "$crt_path"
llvm-readelf -h "$crt_path" | grep -Eq 'Machine:[[:space:]]+RISC-V'
done
done

llvm-readelf -h "$crt_root/riscv64-unknown-linux-gnu/lp64/crt1.o" \
| grep -Eq 'Flags:[[:space:]]+0x1.*RVC'
llvm-readelf -h "$crt_root/riscv64-unknown-linux-gnu/lp64f/crt1.o" \
| grep -Eq 'Flags:[[:space:]]+0x3.*single-float ABI'
llvm-readelf -h "$crt_root/riscv64-unknown-linux-gnu/lp64d/crt1.o" \
| grep -Eq 'Flags:[[:space:]]+0x5.*double-float ABI'

- name: Run Wave end-to-end tests
if: ${{ always() }}
run: python3 tools/run_tests.py

- name: Run RISC-V contract tests
if: ${{ always() }}
env:
WAVE_RUN_RISCV64_INTEROP_TESTS: "1"
run: >-
cargo test --locked --test codegen_regressions riscv64_ --verbose

- name: Build release compiler with RISC-V backend
run: cargo build --locked --release --verbose

- name: Link and run Linux riscv64 binary
if: ${{ always() }}
run: |
set -euo pipefail

Expand All @@ -130,7 +257,7 @@ jobs:
binary="$output_dir/test2"
mkdir -p "$output_dir"

target/release/wavec build test/test2.wave \
target/release/wavec build tests/cases/test2.wave \
--target riscv64-unknown-linux-gnu \
--sysroot "$riscv_sysroot" \
--out-dir "$output_dir"
Expand Down Expand Up @@ -209,8 +336,70 @@ jobs:
- name: Run Wave end-to-end tests
run: python3 tools/run_tests.py

build-macos-amd64:
name: Build macOS amd64
runs-on: macos-15-intel
continue-on-error: true
timeout-minutes: 45

steps:
- uses: actions/checkout@v4

- name: Setup Rust
uses: dtolnay/rust-toolchain@1.89.0
with:
components: rustfmt, clippy

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install LLVM 21 and LLD
run: |
brew install llvm@21 lld

- name: Set LLVM env
run: |
LLVM_PREFIX="$(brew --prefix llvm@21)"
LLD_PREFIX="$(brew --prefix lld)"
echo "LLVM_SYS_211_PREFIX=$LLVM_PREFIX" >> "$GITHUB_ENV"
echo "LLVM_CONFIG_PATH=$LLVM_PREFIX/bin/llvm-config" >> "$GITHUB_ENV"
echo "$LLVM_PREFIX/bin" >> "$GITHUB_PATH"
echo "$LLD_PREFIX/bin" >> "$GITHUB_PATH"
echo "WAVE_LD64_LLD=$LLD_PREFIX/bin/ld64.lld" >> "$GITHUB_ENV"

- name: Verify LLVM tools
run: |
llvm-config --version
command -v ld64.lld
ld64.lld --version || true

- name: Install Wave stdlib
run: |
mkdir -p "$HOME/.wave/lib/wave"
rm -rf "$HOME/.wave/lib/wave/std"
cp -R std "$HOME/.wave/lib/wave/std"

- name: Check Rust formatting
run: cargo fmt --all --check

- name: Run Clippy
run: cargo clippy --locked --all-targets -- -D warnings

- name: Validate Python tooling
run: python3 -m py_compile x.py tools/run_tests.py

- name: Build release compiler
run: cargo build --locked --release --verbose

- name: Run Rust tests
run: cargo test --locked --all-targets --verbose

- name: Run Wave end-to-end tests
run: python3 tools/run_tests.py

build-windows-amd64:
name: Build Windows amd64
name: Build Windows GNU amd64
runs-on: windows-latest
timeout-minutes: 60

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ All additional functionality should be provided through external libraries (e.g.

Wave uses:
- Rust unit tests (`cargo test`)
- Manually executed `.wave` examples in `test/` (not automated)
- Automated `.wave` language cases in `tests/cases/`

Contributors should:

Expand Down
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ F: src/

[Test Suite]
M: luna@lunastev.org
F: test/
F: tests/cases/
1 change: 1 addition & 0 deletions front/parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub struct ExternFunctionNode {
pub abi: String,
pub symbol: Option<String>,
pub params: Vec<(String, WaveType)>,
pub variadic: bool,
pub return_type: WaveType,
}

Expand Down
29 changes: 29 additions & 0 deletions front/parser/src/parser/decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ fn parse_extern_fun_decl(
// params
let mut params: Vec<(String, WaveType)> = Vec::new();
let mut idx: usize = 0;
let mut variadic = false;

loop {
skip_ws(tokens);
Expand All @@ -509,6 +510,33 @@ fn parse_extern_fun_decl(
break;
}

let mut lookahead = tokens.clone();
let is_variadic = (0..3).all(|_| {
matches!(
lookahead.next().map(|token| &token.token_type),
Some(TokenType::Dot)
)
});
if is_variadic {
if params.is_empty() {
println!("Error: C variadic extern function requires a fixed parameter");
return None;
}
for _ in 0..3 {
tokens.next();
}
skip_ws(tokens);
if !expect(
tokens,
TokenType::Rparen,
"Expected ')' immediately after '...' in extern function",
) {
return None;
}
variadic = true;
break;
}

// named param? (Identifier ... :)
let is_named = match tokens.peek() {
Some(Token {
Expand Down Expand Up @@ -658,6 +686,7 @@ fn parse_extern_fun_decl(
abi,
symbol,
params,
variadic,
return_type,
})
}
Expand Down
Loading
Loading