diff --git a/.github/scripts/install-exotic-toolchains.sh b/.github/scripts/install-exotic-toolchains.sh new file mode 100755 index 0000000..fe0eade --- /dev/null +++ b/.github/scripts/install-exotic-toolchains.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${RUNNER_TEMP:?RUNNER_TEMP must be set}" +: "${GITHUB_PATH:?GITHUB_PATH must be set}" +: "${GITHUB_ENV:?GITHUB_ENV must be set}" + +readonly ARK_VERSION="4.7.1" +readonly ARK_SHA256="3d9e46ac5a8ecb19c9e4e87391fc5a8bf7c582ad6cea9599c1976f843d662861" +readonly FAT_IMAGE="fatscript/fry@sha256:fa8bfe0d759ce4bd7146ce9c97521b2cc72f1905d496468a1537fd9e36addc80" +readonly BRUIJN_COMMIT="9f1ac8856d09666a7444874f80b91b876929eecf" +readonly BRUIJN_SHA256="5186ffd7898f081d2961b1e2a4f9b207bc6104f1cff0372761c513d46815b7ca" +readonly LANGUAGE84_VERSION="0.8" +readonly LANGUAGE84_SHA256="b51807d1b7d06f1fdba762fdbf99c8c7fe762ec1a0c96c0be054657c9551cec0" + +dotenv_excludes=( + "--exclude=.env" + "--exclude=*/.env" + "--exclude=*.env" + "--exclude=.env.*" + "--exclude=*/.env.*" + "--exclude=*.env.*" +) + +download_and_verify() { + local url=$1 + local output=$2 + local sha256=$3 + + curl --fail --location --retry 3 --show-error --silent \ + --output "$output" "$url" + printf '%s %s\n' "$sha256" "$output" | sha256sum --check - +} + +install_arkscript() { + local archive="$RUNNER_TEMP/arkscript-${ARK_VERSION}.zip" + local root="$RUNNER_TEMP/arkscript-${ARK_VERSION}" + + download_and_verify \ + "https://github.com/ArkScript-lang/Ark/releases/download/v${ARK_VERSION}/linux-clang-16.zip" \ + "$archive" \ + "$ARK_SHA256" + + mkdir -p "$root" + unzip -q "$archive" -d "$root" -x \ + '.env' '*/.env' '*.env' '.env.*' '*/.env.*' '*.env.*' + chmod +x "$root/arkscript" + "$root/arkscript" --version + printf '%s\n' "$root" >> "$GITHUB_PATH" +} + +install_fatscript() { + docker pull "$FAT_IMAGE" +} + +install_bruijn() { + local cache="$RUNNER_TEMP/bruijn-tool-v1.tar.gz" + local tool="$RUNNER_TEMP/bruijn-tool" + + mkdir -p "$tool" + if [ -f "$cache" ]; then + tar "${dotenv_excludes[@]}" -xzf "$cache" -C "$tool" + else + local archive="$RUNNER_TEMP/bruijn-${BRUIJN_COMMIT}.tar.gz" + local source="$RUNNER_TEMP/bruijn-source" + local stack_root="$RUNNER_TEMP/bruijn-stack-root" + + download_and_verify \ + "https://github.com/marvinborner/bruijn/archive/${BRUIJN_COMMIT}.tar.gz" \ + "$archive" \ + "$BRUIJN_SHA256" + + mkdir -p "$source" "$tool/bin" "$tool/share" + tar "${dotenv_excludes[@]}" -xzf "$archive" -C "$source" \ + --strip-components=1 + + ( + cd "$source" + stack --stack-root "$stack_root" \ + --local-bin-path "$tool/bin" \ + --no-terminal \ + install + ) + + local install_root + local data_dir + install_root=$( + cd "$source" + stack --stack-root "$stack_root" --no-terminal path --local-install-root + ) + data_dir=$(printf '%s\n' "$install_root"/share/*/bruijn-0.1.0.0) + [ -f "$data_dir/config" ] + + tar "${dotenv_excludes[@]}" -cf - -C "$data_dir" . | + tar "${dotenv_excludes[@]}" -xf - -C "$tool/share" + tar "${dotenv_excludes[@]}" -czf "$cache" -C "$tool" . + fi + + [ -x "$tool/bin/bruijn" ] + [ -f "$tool/share/config" ] + printf '%s\n' "$tool/bin" >> "$GITHUB_PATH" + printf 'bruijn_datadir=%s\n' "$tool/share" >> "$GITHUB_ENV" +} + +install_language84() { + local archive="$RUNNER_TEMP/language84-${LANGUAGE84_VERSION}.tar.xz" + local root="$RUNNER_TEMP/language84-${LANGUAGE84_VERSION}" + + download_and_verify \ + "https://norstrulde.org/language84/language84-${LANGUAGE84_VERSION}.tar.xz" \ + "$archive" \ + "$LANGUAGE84_SHA256" + + mkdir -p "$root" + tar "${dotenv_excludes[@]}" -xJf "$archive" -C "$root" \ + --strip-components=1 + [ -f "$root/84_stable.c" ] + printf 'LANGUAGE84_HOME=%s\n' "$root" >> "$GITHUB_ENV" +} + +install_arkscript +install_fatscript +install_bruijn +install_language84 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f727812..b0c7e4f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,8 +11,8 @@ jobs: steps: - uses: actions/checkout@v4 - # Python, Node.js, Perl, GCC/G++ 14, and the .NET SDK (F#) come - # preinstalled on the runner. + # Python, Node.js, Perl, GCC/G++ 14, Clang, Stack, Docker, and the + # .NET SDK (F#) come preinstalled on the runner. - name: Install toolchains not preinstalled on the runner run: | sudo apt-get update @@ -28,5 +28,16 @@ jobs: - uses: oven-sh/setup-bun@v2 + # Bruijn has no release binary. Cache only the finished, relocatable + # interpreter bundle; the source and all build dependencies remain pinned. + - name: Cache built Bruijn interpreter + uses: actions/cache@v4 + with: + path: ${{ runner.temp }}/bruijn-tool-v1.tar.gz + key: bruijn-${{ runner.os }}-${{ runner.arch }}-9f1ac885-lts-22.12-v1 + + - name: Install exotic language toolchains + run: .github/scripts/install-exotic-toolchains.sh + - name: Run all language tests run: ./run-tests.sh diff --git a/ROADMAP.md b/ROADMAP.md index d5715ea..8dda1db 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -35,10 +35,13 @@ Folders without a `test.sh` are skipped until backfilled. numeral typing so PRED works; add test.sh + expected output to that branch, let CI validate it, then merge #29. Kotlin: runner has a JDK; install kotlinc in the workflow. -- [ ] **Step 6 — exotic languages: ArkScript, FatScript, bruijn, Language 84.** - Each needs its own toolchain acquisition (GitHub releases, cargo/stack - installs, or building from source). If one is genuinely unobtainable in - CI, document that in its folder instead of leaving it silently untested. +- [x] **Step 6 — exotic languages: ArkScript, FatScript, bruijn, Language 84.** + ArkScript uses the checksum-verified official 4.7.1 archive; FatScript + uses its official 4.5.0 image pinned by digest in a read-only, + network-disabled container; bruijn is built from a pinned upstream commit + and locked Stack snapshot, then cached as a relocatable bundle; Language + 84 uses the checksum-verified official 0.8 source and its documented Clang + build. All four expected-output baselines came from observed runs. - [ ] **Step 7 — flip the default and update the front door.** Once all folders have tests: make `run-tests.sh` fail on folders *missing* a test.sh, update README contribution instructions to require diff --git a/languages/a/arkscript/README.md b/languages/a/arkscript/README.md index 394ea16..12e5cfe 100644 --- a/languages/a/arkscript/README.md +++ b/languages/a/arkscript/README.md @@ -1,26 +1,26 @@ # ArkScript -Running this solution requires either ArkScript 4.0.0 or a pre-release of ArkScript 4.0.0. +This implementation runs on ArkScript 4. -## Running the solution (docker) +GitHub Actions downloads the official ArkScript 4.7.1 Linux archive and +verifies its SHA-256 digest before running the program. For another platform, +use the matching archive from the +[official ArkScript releases](https://github.com/ArkScript-lang/Ark/releases). +Keep the interpreter and its supplied libraries together when extracting it. -``` -docker pull arkscript/nightly:latest -docker run -it --rm -v $(pwd):/tmp:ro arkscript/nightly /tmp/lambda-core.ark -``` +## Run -## Running the solution (binary) +Place the ArkScript directory on your PATH, then run: -Download the binary for your platform in [the latest 4.0.0 pre-release](https://github.com/ArkScript-lang/Ark/releases/tag/v4.0.0-10). + arkscript -fno-cache lambda-core.ark -Extract the zip, you will need both `arkscript` and `libArkReactor.(so|dll)` in the same directory. +The no-cache flag prevents ArkScript from creating a generated +`__arkscript__` directory beside this source file. -``` -chmod u+x arkscript -./arkscript lambda-core.ark -``` +## Test -## Other way of installing ArkScript - -See the documentation: [arkscript-lang.dev/tutorials/building.html](https://arkscript-lang.dev/tutorials/building.html). + sh test.sh +The repository test harness compares that command's output byte-for-byte with +`expected-output.txt`. If ArkScript is not installed, the test is reported as +a local toolchain skip; a missing interpreter is a failure in CI. diff --git a/languages/a/arkscript/expected-output.txt b/languages/a/arkscript/expected-output.txt new file mode 100644 index 0000000..60e94ea --- /dev/null +++ b/languages/a/arkscript/expected-output.txt @@ -0,0 +1,30 @@ +Logic +----- +True / False +true +false +Not +false +true +And +true +false +false +false +Or +true +true +true +false + +Church Numerals +--------------- +Zero / Succ +0 +1 +2 +3 +Pred +0 +1 +2 diff --git a/languages/a/arkscript/test.sh b/languages/a/arkscript/test.sh new file mode 100755 index 0000000..1e52fce --- /dev/null +++ b/languages/a/arkscript/test.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu + +command -v arkscript >/dev/null 2>&1 || exit 42 + +dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +arkscript -fno-cache "$dir/lambda-core.ark" diff --git a/languages/b/bruijn/README.md b/languages/b/bruijn/README.md index 7b781a8..05f4990 100644 --- a/languages/b/bruijn/README.md +++ b/languages/b/bruijn/README.md @@ -1,14 +1,34 @@ # bruijn -To run, follow the installation instructions on [bruijn's -wiki](https://bruijn.marvinborner.de/wiki/introduction/installation/) -and run - -``` bash -# to run main and check the tests! -bruijn -v lambda-core.bruijn -``` - -Further examples can be found in -[examples](https://bruijn.marvinborner.de/samples/) or in the [standard -library](https://bruijn.marvinborner.de/std/). +This implementation requires the +[bruijn interpreter](https://github.com/marvinborner/bruijn). Bruijn does not +publish release binaries, so GitHub Actions builds upstream commit +`9f1ac8856d09666a7444874f80b91b876929eecf` using the project's locked +Stack snapshot (LTS 22.12). + +## Install + + git clone https://github.com/marvinborner/bruijn.git + cd bruijn + git checkout 9f1ac8856d09666a7444874f80b91b876929eecf + stack install + +## Run + + bruijn -v lambda-core.bruijn + +Verbose mode prints one success line for every `:test` expression in the +source. The final `main` term is printed after those checks. + +## Test + + sh test.sh + +The interpreter always emits terminal color codes, even when output is not a +terminal. The test removes only those ANSI color codes before comparing the +actual text with `expected-output.txt`; all test results and the final term +remain in the comparison. + +Further examples are available in bruijn's +[samples](https://bruijn.marvinborner.de/samples/) and +[standard library](https://bruijn.marvinborner.de/std/). diff --git a/languages/b/bruijn/expected-output.txt b/languages/b/bruijn/expected-output.txt new file mode 100644 index 0000000..4fe2fd6 --- /dev/null +++ b/languages/b/bruijn/expected-output.txt @@ -0,0 +1,15 @@ + OK test passed: (¬‣ true) = false + OK test passed: (¬‣ false) = true + OK test passed: (true ⋀ true) = true + OK test passed: (true ⋀ false) = false + OK test passed: (false ⋀ true) = false + OK test passed: (false ⋀ false) = false + OK test passed: (true ⋁ true) = true + OK test passed: (true ⋁ false) = true + OK test passed: (false ⋁ true) = true + OK test passed: (false ⋁ false) = false + OK test passed: (++‣ (++‣ zero)) = [[(1 (1 0))]] + OK test passed: (--‣ (++‣ zero)) = zero + OK test passed: (--‣ [[(1 (1 0))]]) = [[(1 0)]] + OK test passed: (--‣ [[(1 (1 (1 0)))]]) = [[(1 (1 0))]] +*> [0] diff --git a/languages/b/bruijn/test.sh b/languages/b/bruijn/test.sh new file mode 100755 index 0000000..559c538 --- /dev/null +++ b/languages/b/bruijn/test.sh @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu + +command -v bruijn >/dev/null 2>&1 || exit 42 +command -v sed >/dev/null 2>&1 || exit 42 + +dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +raw=$(mktemp) +trap 'rm -f "$raw"' 0 1 2 15 + +bruijn -v "$dir/lambda-core.bruijn" >"$raw" +LC_ALL=C sed 's/\x1b\[[0-9;]*m//g' "$raw" diff --git a/languages/f/fatscript/README.md b/languages/f/fatscript/README.md index 24172ae..d7d4310 100644 --- a/languages/f/fatscript/README.md +++ b/languages/f/fatscript/README.md @@ -1,19 +1,23 @@ -# FatScript interpreter setup +# FatScript -https://fatscript.org/en/general/setup.html +This implementation requires the +[fry interpreter](https://fatscript.org/en/general/setup.html). -# Run code +## Run with a native fry installation -```sh -chmod +x ./lambda-core.fat + fry lambda-core.fat -./lambda-core.fat -``` +## Run and test with Docker -# Run on web playground (alternative) +The automated test uses the official FatScript 4.5.0 image pinned by its +multi-platform digest: -> no installation required + docker pull fatscript/fry@sha256:fa8bfe0d759ce4bd7146ce9c97521b2cc72f1905d496468a1537fd9e36addc80 + sh test.sh -https://fatscript.org/playground/ +The container receives this folder read-only and runs without network access. +The test does not silently switch to a newer image. Its output is compared +byte-for-byte with `expected-output.txt`. -Select `lambda-core.fat` file on "run fat code" input. +The [FatScript playground](https://fatscript.org/playground/) is also useful +for interactive exploration, but it is not used for automated verification. diff --git a/languages/f/fatscript/expected-output.txt b/languages/f/fatscript/expected-output.txt new file mode 100644 index 0000000..1b055f1 --- /dev/null +++ b/languages/f/fatscript/expected-output.txt @@ -0,0 +1,30 @@ +LOGIC +--------------- +TRUE/FALSE +t +f +NOT +f +t +AND +t +f +f +f +OR +t +t +t +f + +CHURCH NUMERALS +--------------- +ZERO/SUCC +0 +1 +2 +3 +PRED +0 +1 +2 diff --git a/languages/f/fatscript/test.sh b/languages/f/fatscript/test.sh new file mode 100755 index 0000000..c7a35f6 --- /dev/null +++ b/languages/f/fatscript/test.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu + +command -v docker >/dev/null 2>&1 || exit 42 + +image='fatscript/fry@sha256:fa8bfe0d759ce4bd7146ce9c97521b2cc72f1905d496468a1537fd9e36addc80' +docker image inspect "$image" >/dev/null 2>&1 || exit 42 + +dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +docker run --rm --network none --read-only \ + -v "$dir:/app:ro" \ + "$image" \ + lambda-core.fat diff --git a/languages/l/language84/README.md b/languages/l/language84/README.md index bd9bd76..8f71c78 100644 --- a/languages/l/language84/README.md +++ b/languages/l/language84/README.md @@ -1,19 +1,35 @@ +# Language 84 -(Note: You need x86 Linux to run this code.) +Language 84 version 0.8 runs on x86-64 Linux and uses a self-hosting compiler. +Build it with Clang. During verification, the 0.8 bootstrap compiler +segfaulted when built with GCC 13.3, while the documented Clang build completed +and ran successfully. -Get Language 84 version 0.8 from https://norstrulde.org/language84/ and unpack. +## Build and run - $ wget https://norstrulde.org/language84/language84-0.8.tar.xz - $ tar xfJ language84-0.8.tar.xz +Download the +[official Language 84 0.8 archive](https://norstrulde.org/language84/language84-0.8.tar.xz) +and unpack it. Its SHA-256 digest is: -Copy `lambda-core.84` and `local.make` from this repo into the `language84-0.8` directory created above. + b51807d1b7d06f1fdba762fdbf99c8c7fe762ec1a0c96c0be054657c9551cec0 -Build +Copy `lambda-core.84` and `local.make` from this folder into the extracted +`language84-0.8` directory, then run: - $ make CC=clang + make CC=clang + ./lambda-core -Run +## Test - $ ./lambda-core +Point the test at the extracted, otherwise unmodified Language 84 source tree: -Note that there are some functions defined with and without syntactic sugar to show both forms and how they relate. Look for `BITTER`, `SWEET`, `SWEETEST`. + LANGUAGE84_HOME=/path/to/language84-0.8 sh test.sh + +The test copies only the compiler's required `.84`, `.c`, and `.h` +sources into a temporary directory, builds with Clang, runs the resulting +program, and removes the temporary build. The output is compared byte-for-byte +with `expected-output.txt`. + +Several functions are shown both with and without Language 84's syntactic +sugar. Search the source for `BITTER`, `SWEET`, and `SWEETEST` to compare +the forms. diff --git a/languages/l/language84/expected-output.txt b/languages/l/language84/expected-output.txt new file mode 100644 index 0000000..36e6e85 --- /dev/null +++ b/languages/l/language84/expected-output.txt @@ -0,0 +1,62 @@ + +LOGIC +--- + +TRUE/FALSE +t +f + +NOT +f +t + +AND +t +f +f +f + +OR +t +t +t +f + +CHURCH NUMERALS +--- + +ZERO/SUCC +0 +1 +2 +3 + +PRED +0 +0 +1 +2 + +ADD +5 + +MUL +0 +0 +6 + +FACT +1 +1 +2 +6 +24 +120 + +FIB +1 +1 +2 +3 +5 +8 diff --git a/languages/l/language84/test.sh b/languages/l/language84/test.sh new file mode 100755 index 0000000..7779c8a --- /dev/null +++ b/languages/l/language84/test.sh @@ -0,0 +1,24 @@ +#!/bin/sh +set -eu + +command -v clang >/dev/null 2>&1 || exit 42 +command -v make >/dev/null 2>&1 || exit 42 + +language84_home=${LANGUAGE84_HOME:-} +[ -n "$language84_home" ] || exit 42 +[ -f "$language84_home/84_stable.c" ] || exit 42 + +dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +build_dir=$(mktemp -d) +trap 'rm -r "$build_dir"' 0 1 2 15 + +cp "$language84_home"/*.84 "$build_dir"/ +cp "$language84_home/84_stable.c" "$language84_home/support.c" \ + "$language84_home/support.h" "$language84_home/Makefile" "$build_dir"/ +cp "$dir/lambda-core.84" "$dir/local.make" "$build_dir"/ + +( + cd "$build_dir" + make CC=clang 1>&2 +) +"$build_dir/lambda-core"