plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


scripts/test-examples.sh
#!/usr/bin/env bash
#
# Integration test: compiles and runs every examples/*.plum file through the
# REAL toolchain — the `plum` CLI binary (which resolves `import`s against
# --lib-path, unlike plum-checker/plum-wasm-codegen's unit tests, which parse
# and compile a single file directly) and, if available, an external
# `wasmtime` runtime.
#
# This exists because the unit tests alone missed a real bug: examples/basics.plum
# had an `import std/io` where libs/std/io.plum doesn't exist. The unit tests
# never noticed since they don't touch plum-core's loader/import resolution at
# all — only compiling and running through the actual CLI catches that class
# of problem.
#
# Usage: scripts/test-examples.sh
# Exit code is 0 if every example compiled (and, where checked, ran) correctly.

set -uo pipefail

cd "$(dirname "${BASH_SOURCE[0]}")/.."

WORKDIR=$(mktemp -d)
trap 'rm -rf "$WORKDIR"' EXIT

echo "Building plum-cli..."
if ! cargo build -p plum-cli --quiet 2>"$WORKDIR/build.log"; then
  echo "FAIL: plum-cli failed to build" >&2
  cat "$WORKDIR/build.log" >&2
  exit 1
fi
PLUM_BIN="target/debug/plum"

HAVE_WASMTIME=0
if command -v wasmtime >/dev/null 2>&1; then
  HAVE_WASMTIME=1
else
  echo "note: wasmtime CLI not found on PATH — will compile every example but skip running them" >&2
fi

# Examples that export `main` and are expected to run without trapping. Kept
# in sync with plum-wasm-codegen/tests/examples_test.rs.
has_main() {
  case "$1" in
    basics|closures|match|methods) return 0 ;;
    *) return 1 ;;
  esac
}

# Expected `main` return value for examples whose result is asserted in
# plum-wasm-codegen/tests/examples_test.rs. Empty means "just don't trap"
# (e.g. basics.plum's main returns Unit, not a value to compare).
expected_value() {
  case "$1" in
    closures) echo 120 ;;
    match) echo 5 ;;
    methods) echo 10 ;;
    *) echo "" ;;
  esac
}

failed=0
passed=0

for src in examples/*.plum; do
  name=$(basename "$src" .plum)
  wasm="$WORKDIR/$name.wasm"

  printf '%-14s compile ... ' "$name"
  if ! "$PLUM_BIN" compile "$src" -o "$wasm" >"$WORKDIR/$name.compile.log" 2>&1; then
    echo "FAIL"
    sed 's/^/    /' "$WORKDIR/$name.compile.log"
    failed=$((failed + 1))
    continue
  fi
  echo "ok"

  if [ "$HAVE_WASMTIME" -eq 1 ] && has_main "$name"; then
    printf '%-14s run     ... ' "$name"
    if output=$(wasmtime run --invoke main "$wasm" 2>"$WORKDIR/$name.run.log"); then
      expected=$(expected_value "$name")
      if [ -n "$expected" ] && [ "$output" != "$expected" ]; then
        echo "FAIL (expected $expected, got '$output')"
        failed=$((failed + 1))
        continue
      fi
      if [ -n "$output" ]; then
        echo "ok (-> $output)"
      else
        echo "ok"
      fi
    else
      echo "FAIL (trapped)"
      sed 's/^/    /' "$WORKDIR/$name.run.log"
      failed=$((failed + 1))
      continue
    fi
  fi

  passed=$((passed + 1))
done

echo
echo "$passed passed, $failed failed"
[ "$failed" -eq 0 ]