From 1e40a0403da996f5aae52cfffa9fbb2b864eeee1 Mon Sep 17 00:00:00 2001 From: Yura Lazarev Date: Sun, 14 Jun 2026 21:04:04 +0200 Subject: [PATCH] feat: bring st to the canon and add ST unit tests Migrate purescript-lua-st off the JavaScript-era tooling onto the package-set canon: an overlay flake (purs 0.15.16, spago 0.21.0, Lua 5.1, pslua at the current main), hardened CI, scripts/build, AGENTS.md and CLAUDE.md, a clean .gitignore, and the org package-set URL. Drop the .eslintrc, package.json and the JavaScript FFI files. Add a systematic test suite: spago-test.dhall compiles test/Main.purs to dist/test.lua through pslua and scripts/test runs it under Lua 5.1. It covers STRef new/read/write/modify/modify', ST.run recursion, ST.for (hi-exclusive, lo-inclusive, empty range), ST.while and ST.foreach. Fixes surfaced by the new tests and luacheck: ST.for looped over an inclusive upper bound (for i = lo, hi) though the contract is hi-exclusive, so it ran one extra iteration -- corrected to hi - 1. Declare the effect dependency that Control.Monad.ST.Global needs, and wrap an over-long line in the Uncurried FFI so luacheck passes. --- .eslintrc.json | 26 -- .github/workflows/ci.yml | 30 +- .gitignore | 4 - AGENTS.md | 45 +++ CLAUDE.md | 1 + README.md | 17 +- flake.lock | 505 ++++++++++++++--------------- flake.nix | 55 ++-- package.json | 14 - packages.dhall | 2 +- scripts/build | 3 +- scripts/test | 13 + spago-test.dhall | 14 + spago.dhall | 6 +- src/Control/Monad/ST/.editorconfig | 18 - src/Control/Monad/ST/Internal.js | 90 ----- src/Control/Monad/ST/Internal.lua | 2 +- src/Control/Monad/ST/Uncurried.js | 229 ------------- src/Control/Monad/ST/Uncurried.lua | 4 +- test/Main.purs | 111 ++++++- 20 files changed, 483 insertions(+), 706 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 AGENTS.md create mode 100644 CLAUDE.md delete mode 100644 package.json create mode 100755 scripts/test create mode 100644 spago-test.dhall delete mode 100644 src/Control/Monad/ST/.editorconfig delete mode 100644 src/Control/Monad/ST/Internal.js delete mode 100644 src/Control/Monad/ST/Uncurried.js diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 1c6afb9..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "parserOptions": { - "ecmaVersion": 6, - "sourceType": "module" - }, - "extends": "eslint:recommended", - "rules": { - "strict": [2, "global"], - "block-scoped-var": 2, - "consistent-return": 2, - "eqeqeq": [2, "smart"], - "guard-for-in": 2, - "no-caller": 2, - "no-extend-native": 2, - "no-loop-func": 2, - "no-new": 2, - "no-param-reassign": 2, - "no-return-assign": 2, - "no-unused-expressions": 2, - "no-use-before-define": 2, - "radix": [2, "always"], - "indent": [2, 2], - "quotes": [2, "double"], - "semi": [2, "always"] - } -} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c69237a..d624d2e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,32 +4,24 @@ on: push: branches: [master] pull_request: - branches: [master] jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - - uses: purescript-contrib/setup-purescript@main - with: - purescript: "unstable" + - uses: actions/checkout@v4 - - uses: actions/setup-node@v2 + - uses: cachix/install-nix-action@v27 with: - node-version: "14.x" + extra_nix_config: | + extra-substituters = https://cache.iog.io https://purescript-lua.cachix.org + extra-trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= purescript-lua.cachix.org-1:yLs4ei2HtnuPtzLekOrW3xdfm95+Etw15gwgyIGTayA= - - name: Install dependencies - run: | - npm install -g bower - npm install - bower install --production + - name: Build + run: nix develop -c ./scripts/build - - name: Build source - run: npm run-script build + - name: Test + run: if [ -f scripts/test ]; then nix develop -c bash ./scripts/test; fi - - name: Run tests - run: | - bower install - npm run-script test --if-present + - name: Luacheck + run: nix develop -c luacheck --quiet --std lua51 --no-unused-args src/ diff --git a/.gitignore b/.gitignore index b846b63..db67e9a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,4 @@ /.* !/.gitignore -!/.eslintrc.json !/.github/ -/bower_components/ -/node_modules/ /output/ -package-lock.json diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..dde531a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,45 @@ +# AGENTS.md + +A PureScript→Lua FFI fork in the [`purescript-lua`](https://github.com/purescript-lua/purescript-lua) package set. Generated code targets **Lua 5.1**. + +## Commands + +All commands run inside the nix dev shell: + +- Build: `nix develop -c ./scripts/build` +- Test (only if the fork has `scripts/test`): `nix develop -c bash ./scripts/test` +- Lint: `nix develop -c luacheck --quiet --std lua51 --no-unused-args src/` + +## Lua 5.1 target + +The output runs on Lua 5.1, which is stricter than 5.3: + +- No `table.unpack`, `bit32`, `utf8`, or the `//` operator. `math.pow` and `math.atan2` do exist. +- Array-style tables are 1-indexed: the first element is `t[1]`, not `t[0]`. +- `unit` is `{}`, never `nil`: a `nil` table element silently disappears, which would collapse `Array Unit` into an empty table. +- Lua 5.1 mangles some Lua 5.3 string escapes, so keep FFI string escapes 5.1-safe. + +## FFI files (under `src/`) + +pslua's foreign-file parser needs every exported value wrapped in parentheses: + +```lua +return { + identity = (function(x) return x end), + answer = (42), +} +``` + +A bare `function … end` or an unparenthesised expression fails to parse. + +## Toolchain + +`flake.nix` pins everything through [`purescript-overlay`](https://github.com/thomashoneyman/purescript-overlay): purs 0.15.16 (`purs-bin.purs-0_15_16`), spago 0.21.0 (`spago-bin.spago-0_21_0`), Lua 5.1 (`lua51Packages`). The `pslua` input tracks `github:purescript-lua/purescript-lua`; keep `flake.lock` reasonably current, since a long-stale pslua pin won't create the `--lua-output-file` directory and CI fails. + +## Releasing + +Tag-driven, with no GitHub Release or changelog entry. The full conventions live in the [package-set repo](https://github.com/purescript-lua/purescript-lua-package-sets/blob/master/CONTRIBUTING.md): push an annotated tag on `master`, bump this fork's `version` in the package set's `src/packages.dhall`, refresh `latest-compatible-sets.json`, and push a `psc-*` set tag. + +## Decisions + +Cross-cutting decisions are recorded as ADRs in the [package-set repo](https://github.com/purescript-lua/purescript-lua-package-sets/tree/master/docs/adr). Read them before a decision that affects the set, and add one after making such a decision. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/README.md b/README.md index 6b9b40f..6d6326a 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,22 @@ -# purescript-st +# purescript-lua-st -[![Latest release](http://img.shields.io/github/release/purescript/purescript-st.svg)](https://github.com/purescript/purescript-st/releases) -[![Build status](https://github.com/purescript/purescript-st/workflows/CI/badge.svg?branch=master)](https://github.com/purescript/purescript-st/actions?query=workflow%3ACI+branch%3Amaster) -[![Pursuit](https://pursuit.purescript.org/packages/purescript-st/badge)](https://pursuit.purescript.org/packages/purescript-st) +[![CI](https://github.com/purescript-lua/purescript-lua-st/actions/workflows/ci.yml/badge.svg)](https://github.com/purescript-lua/purescript-lua-st/actions/workflows/ci.yml) -The ST effect, for safe local mutation. +The ST effect, for safe local mutation. This is the Lua fork of +[`purescript-st`](https://github.com/purescript/purescript-st) for the +[pslua](https://github.com/purescript-lua/purescript-lua) compiler backend: it +keeps the upstream PureScript API and replaces the JavaScript FFI with Lua that +runs on Lua 5.1. ## Installation +It ships in the [purescript-lua package set](https://github.com/purescript-lua/purescript-lua-package-sets): + ``` spago install st ``` ## Documentation -Module documentation is [published on Pursuit](http://pursuit.purescript.org/packages/purescript-st). +The API matches upstream, so the module docs are +[published on Pursuit](https://pursuit.purescript.org/packages/purescript-st). diff --git a/flake.lock b/flake.lock index 6f8b26a..6b6c417 100644 --- a/flake.lock +++ b/flake.lock @@ -16,23 +16,6 @@ "type": "github" } }, - "cabal-32": { - "flake": false, - "locked": { - "lastModified": 1603716527, - "narHash": "sha256-X0TFfdD4KZpwl0Zr6x+PLxUt/VyKQfX7ylXHdmZIL+w=", - "owner": "haskell", - "repo": "cabal", - "rev": "48bf10787e27364730dd37a42b603cee8d6af7ee", - "type": "github" - }, - "original": { - "owner": "haskell", - "ref": "3.2", - "repo": "cabal", - "type": "github" - } - }, "cabal-34": { "flake": false, "locked": { @@ -88,11 +71,11 @@ "flake-utils": "flake-utils_2" }, "locked": { - "lastModified": 1710161569, - "narHash": "sha256-lcIRIOFCdIWEGyKyG/tB4KvxM9zoWuBRDxW+T+mvIb0=", + "lastModified": 1763814099, + "narHash": "sha256-YazeA9u0JdxykexV6HHG5DMtsnwqXoiAcWPjncO1XHM=", "owner": "justinwoo", "repo": "easy-purescript-nix", - "rev": "117fd96acb69d7d1727df95b6fde9d8715e031fc", + "rev": "8fcd84f54d75d9007b2f1c7c9da5af843105a55f", "type": "github" }, "original": { @@ -101,35 +84,35 @@ "type": "github" } }, - "easyps": { + "flake-compat": { "flake": false, "locked": { - "lastModified": 1710161569, - "narHash": "sha256-lcIRIOFCdIWEGyKyG/tB4KvxM9zoWuBRDxW+T+mvIb0=", - "owner": "justinwoo", - "repo": "easy-purescript-nix", - "rev": "117fd96acb69d7d1727df95b6fde9d8715e031fc", + "lastModified": 1672831974, + "narHash": "sha256-z9k3MfslLjWQfnjBtEtJZdq3H7kyi2kQtUThfTgdRk0=", + "owner": "input-output-hk", + "repo": "flake-compat", + "rev": "45f2638735f8cdc40fe302742b79f248d23eb368", "type": "github" }, "original": { - "owner": "justinwoo", - "repo": "easy-purescript-nix", + "owner": "input-output-hk", + "ref": "hkm/gitlab-fix", + "repo": "flake-compat", "type": "github" } }, - "flake-compat": { + "flake-compat_2": { "flake": false, "locked": { - "lastModified": 1672831974, - "narHash": "sha256-z9k3MfslLjWQfnjBtEtJZdq3H7kyi2kQtUThfTgdRk0=", - "owner": "input-output-hk", + "lastModified": 1765121682, + "narHash": "sha256-4VBOP18BFeiPkyhy9o4ssBNQEvfvv1kXkasAYd0+rrA=", + "owner": "edolstra", "repo": "flake-compat", - "rev": "45f2638735f8cdc40fe302742b79f248d23eb368", + "rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3", "type": "github" }, "original": { - "owner": "input-output-hk", - "ref": "hkm/gitlab-fix", + "owner": "edolstra", "repo": "flake-compat", "type": "github" } @@ -139,11 +122,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -175,11 +158,11 @@ "systems": "systems_3" }, "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -188,68 +171,47 @@ "type": "github" } }, - "ghc-8.6.5-iohk": { + "hackage": { "flake": false, "locked": { - "lastModified": 1600920045, - "narHash": "sha256-DO6kxJz248djebZLpSzTGD6s8WRpNI9BTwUeOf5RwY8=", + "lastModified": 1781226159, + "narHash": "sha256-BD3MeXxK03Tnh1KxVKMYlU+H8hks+dVMOQLeriAkK8M=", "owner": "input-output-hk", - "repo": "ghc", - "rev": "95713a6ecce4551240da7c96b6176f980af75cae", + "repo": "hackage.nix", + "rev": "cc1f434e3407d58970261cbff2e4a5dab00b803b", "type": "github" }, "original": { "owner": "input-output-hk", - "ref": "release/8.6.5-iohk", - "repo": "ghc", + "repo": "hackage.nix", "type": "github" } }, - "ghc910X": { - "flake": false, - "locked": { - "lastModified": 1709693152, - "narHash": "sha256-j7K/oZLy1ZZIpOsjq101IF7cz/i/UxY1ofIeNUfuuXc=", - "ref": "ghc-9.10", - "rev": "21e3f3250e88640087a1a60bee2cc113bf04509f", - "revCount": 62524, - "submodules": true, - "type": "git", - "url": "https://gitlab.haskell.org/ghc/ghc" - }, - "original": { - "ref": "ghc-9.10", - "submodules": true, - "type": "git", - "url": "https://gitlab.haskell.org/ghc/ghc" - } - }, - "ghc911": { + "hackage-for-stackage": { "flake": false, "locked": { - "lastModified": 1710286031, - "narHash": "sha256-fz71zsU/ZukFMUsRNk2Ro3xTNMKsNrpvQtRtPqRI60c=", - "ref": "refs/heads/master", - "rev": "e6bfb85c842edca36754bb8914e725fbaa1a83a6", - "revCount": 62586, - "submodules": true, - "type": "git", - "url": "https://gitlab.haskell.org/ghc/ghc" + "lastModified": 1781226148, + "narHash": "sha256-95My9dq0a6wCV1v/78OJ+NUKBdD1TwyZomuTc/AxJFg=", + "owner": "input-output-hk", + "repo": "hackage.nix", + "rev": "6233e06fc1f6345f27324f55c485561848d784db", + "type": "github" }, "original": { - "submodules": true, - "type": "git", - "url": "https://gitlab.haskell.org/ghc/ghc" + "owner": "input-output-hk", + "ref": "for-stackage", + "repo": "hackage.nix", + "type": "github" } }, - "hackage": { + "hackage-internal": { "flake": false, "locked": { - "lastModified": 1710807758, - "narHash": "sha256-lQY4KSZQlMyKizC+Xbsl29hxNPHV52pRTDZac+vPaeU=", + "lastModified": 1750307553, + "narHash": "sha256-iiafNoeLHwlSLQTyvy8nPe2t6g5AV4PPcpMeH/2/DLs=", "owner": "input-output-hk", "repo": "hackage.nix", - "rev": "dc3cafd9dbaeebe37c96613a9d145e162cadcf79", + "rev": "f7867baa8817fab296528f4a4ec39d1c7c4da4f3", "type": "github" }, "original": { @@ -261,48 +223,50 @@ "haskellNix": { "inputs": { "HTTP": "HTTP", - "cabal-32": "cabal-32", "cabal-34": "cabal-34", "cabal-36": "cabal-36", "cardano-shell": "cardano-shell", "flake-compat": "flake-compat", - "ghc-8.6.5-iohk": "ghc-8.6.5-iohk", - "ghc910X": "ghc910X", - "ghc911": "ghc911", "hackage": "hackage", + "hackage-for-stackage": "hackage-for-stackage", + "hackage-internal": "hackage-internal", + "hls": "hls", "hls-1.10": "hls-1.10", "hls-2.0": "hls-2.0", + "hls-2.10": "hls-2.10", + "hls-2.11": "hls-2.11", + "hls-2.12": "hls-2.12", "hls-2.2": "hls-2.2", "hls-2.3": "hls-2.3", "hls-2.4": "hls-2.4", "hls-2.5": "hls-2.5", "hls-2.6": "hls-2.6", + "hls-2.7": "hls-2.7", + "hls-2.8": "hls-2.8", + "hls-2.9": "hls-2.9", "hpc-coveralls": "hpc-coveralls", - "hydra": "hydra", "iserv-proxy": "iserv-proxy", - "nix-tools-static": "nix-tools-static", "nixpkgs": [ "pslua", "haskellNix", "nixpkgs-unstable" ], - "nixpkgs-2003": "nixpkgs-2003", - "nixpkgs-2105": "nixpkgs-2105", - "nixpkgs-2111": "nixpkgs-2111", - "nixpkgs-2205": "nixpkgs-2205", - "nixpkgs-2211": "nixpkgs-2211", "nixpkgs-2305": "nixpkgs-2305", "nixpkgs-2311": "nixpkgs-2311", + "nixpkgs-2405": "nixpkgs-2405", + "nixpkgs-2411": "nixpkgs-2411", + "nixpkgs-2505": "nixpkgs-2505", + "nixpkgs-2511": "nixpkgs-2511", "nixpkgs-unstable": "nixpkgs-unstable", "old-ghc-nix": "old-ghc-nix", "stackage": "stackage" }, "locked": { - "lastModified": 1710809412, - "narHash": "sha256-uLn/+4rBqk/+y5OPqe0LqUZHW7uEnWiljO/oGEx3L7c=", + "lastModified": 1781228148, + "narHash": "sha256-Qu6Zml4PHTgV1vs5RuLZzHuNOZYbeOtjeQq8yLIUbTU=", "owner": "input-output-hk", "repo": "haskell.nix", - "rev": "bc43eea89699683d1659eed3c3cc787e432ebfe7", + "rev": "fe9f2b0bfc6fc1bcc15eba41c729228135cda6ed", "type": "github" }, "original": { @@ -311,6 +275,22 @@ "type": "github" } }, + "hls": { + "flake": false, + "locked": { + "lastModified": 1741604408, + "narHash": "sha256-tuq3+Ip70yu89GswZ7DSINBpwRprnWnl6xDYnS4GOsc=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "682d6894c94087da5e566771f25311c47e145359", + "type": "github" + }, + "original": { + "owner": "haskell", + "repo": "haskell-language-server", + "type": "github" + } + }, "hls-1.10": { "flake": false, "locked": { @@ -345,6 +325,57 @@ "type": "github" } }, + "hls-2.10": { + "flake": false, + "locked": { + "lastModified": 1743069404, + "narHash": "sha256-q4kDFyJDDeoGqfEtrZRx4iqMVEC2MOzCToWsFY+TOzY=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "2318c61db3a01e03700bd4b05665662929b7fe8b", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.10.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.11": { + "flake": false, + "locked": { + "lastModified": 1747306193, + "narHash": "sha256-/MmtpF8+FyQlwfKHqHK05BdsxC9LHV70d/FiMM7pzBM=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "46ef4523ea4949f47f6d2752476239f1c6d806fe", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.11.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.12": { + "flake": false, + "locked": { + "lastModified": 1758709460, + "narHash": "sha256-xkI8MIIVEVARskfWbGAgP5sHG/lyeKnkm0LIOJ19X5w=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "7d983de4fa7ff54369f6dd31444bdb9869aec83e", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.12.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, "hls-2.2": { "flake": false, "locked": { @@ -430,124 +461,97 @@ "type": "github" } }, - "hpc-coveralls": { + "hls-2.7": { "flake": false, "locked": { - "lastModified": 1607498076, - "narHash": "sha256-8uqsEtivphgZWYeUo5RDUhp6bO9j2vaaProQxHBltQk=", - "owner": "sevanspowell", - "repo": "hpc-coveralls", - "rev": "14df0f7d229f4cd2e79f8eabb1a740097fdfa430", + "lastModified": 1708965829, + "narHash": "sha256-LfJ+TBcBFq/XKoiNI7pc4VoHg4WmuzsFxYJ3Fu+Jf+M=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "50322b0a4aefb27adc5ec42f5055aaa8f8e38001", "type": "github" }, "original": { - "owner": "sevanspowell", - "repo": "hpc-coveralls", + "owner": "haskell", + "ref": "2.7.0.0", + "repo": "haskell-language-server", "type": "github" } }, - "hydra": { - "inputs": { - "nix": "nix", - "nixpkgs": [ - "pslua", - "haskellNix", - "hydra", - "nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1671755331, - "narHash": "sha256-hXsgJj0Cy0ZiCiYdW2OdBz5WmFyOMKuw4zyxKpgUKm4=", - "owner": "NixOS", - "repo": "hydra", - "rev": "f48f00ee6d5727ae3e488cbf9ce157460853fea8", - "type": "github" - }, - "original": { - "id": "hydra", - "type": "indirect" - } - }, - "iserv-proxy": { + "hls-2.8": { "flake": false, "locked": { - "lastModified": 1708894040, - "narHash": "sha256-Rv+PajrnuJ6AeyhtqzMN+bcR8z9+aEnrUass+N951CQ=", - "owner": "stable-haskell", - "repo": "iserv-proxy", - "rev": "2f2a318fd8837f8063a0d91f329aeae29055fba9", + "lastModified": 1715153580, + "narHash": "sha256-Vi/iUt2pWyUJlo9VrYgTcbRviWE0cFO6rmGi9rmALw0=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "dd1be1beb16700de59e0d6801957290bcf956a0a", "type": "github" }, "original": { - "owner": "stable-haskell", - "ref": "iserv-syms", - "repo": "iserv-proxy", + "owner": "haskell", + "ref": "2.8.0.0", + "repo": "haskell-language-server", "type": "github" } }, - "lowdown-src": { + "hls-2.9": { "flake": false, "locked": { - "lastModified": 1633514407, - "narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=", - "owner": "kristapsdz", - "repo": "lowdown", - "rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8", + "lastModified": 1719993701, + "narHash": "sha256-wy348++MiMm/xwtI9M3vVpqj2qfGgnDcZIGXw8sF1sA=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "90319a7e62ab93ab65a95f8f2bcf537e34dae76a", "type": "github" }, "original": { - "owner": "kristapsdz", - "repo": "lowdown", + "owner": "haskell", + "ref": "2.9.0.1", + "repo": "haskell-language-server", "type": "github" } }, - "nix": { - "inputs": { - "lowdown-src": "lowdown-src", - "nixpkgs": "nixpkgs_2", - "nixpkgs-regression": "nixpkgs-regression" - }, + "hpc-coveralls": { + "flake": false, "locked": { - "lastModified": 1661606874, - "narHash": "sha256-9+rpYzI+SmxJn+EbYxjGv68Ucp22bdFUSy/4LkHkkDQ=", - "owner": "NixOS", - "repo": "nix", - "rev": "11e45768b34fdafdcf019ddbd337afa16127ff0f", + "lastModified": 1607498076, + "narHash": "sha256-8uqsEtivphgZWYeUo5RDUhp6bO9j2vaaProQxHBltQk=", + "owner": "sevanspowell", + "repo": "hpc-coveralls", + "rev": "14df0f7d229f4cd2e79f8eabb1a740097fdfa430", "type": "github" }, "original": { - "owner": "NixOS", - "ref": "2.11.0", - "repo": "nix", + "owner": "sevanspowell", + "repo": "hpc-coveralls", "type": "github" } }, - "nix-tools-static": { + "iserv-proxy": { "flake": false, "locked": { - "lastModified": 1706266250, - "narHash": "sha256-9t+GRk3eO9muCtKdNAwBtNBZ5dH1xHcnS17WaQyftwA=", - "owner": "input-output-hk", - "repo": "haskell-nix-example", - "rev": "580cb6db546a7777dad3b9c0fa487a366c045c4e", + "lastModified": 1778457436, + "narHash": "sha256-bzZAHGzwcQGzBTipJuUs9tvMGO28kp0373zqnpn0g5A=", + "owner": "stable-haskell", + "repo": "iserv-proxy", + "rev": "8cdc446f8e2d91b120ecc075063e9475d387df52", "type": "github" }, "original": { - "owner": "input-output-hk", - "ref": "nix", - "repo": "haskell-nix-example", + "owner": "stable-haskell", + "ref": "iserv-syms", + "repo": "iserv-proxy", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1711703276, - "narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=", + "lastModified": 1781074563, + "narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d8fe5e6c92d0d190646fb9f1056741a229980089", + "rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca", "type": "github" }, "original": { @@ -556,162 +560,114 @@ "type": "indirect" } }, - "nixpkgs-2003": { - "locked": { - "lastModified": 1620055814, - "narHash": "sha256-8LEHoYSJiL901bTMVatq+rf8y7QtWuZhwwpKE2fyaRY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "1db42b7fe3878f3f5f7a4f2dc210772fd080e205", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-20.03-darwin", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-2105": { - "locked": { - "lastModified": 1659914493, - "narHash": "sha256-lkA5X3VNMKirvA+SUzvEhfA7XquWLci+CGi505YFAIs=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "022caabb5f2265ad4006c1fa5b1ebe69fb0c3faf", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-21.05-darwin", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-2111": { + "nixpkgs-2305": { "locked": { - "lastModified": 1659446231, - "narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=", + "lastModified": 1705033721, + "narHash": "sha256-K5eJHmL1/kev6WuqyqqbS1cdNnSidIZ3jeqJ7GbrYnQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", + "rev": "a1982c92d8980a0114372973cbdfe0a307f1bdea", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-21.11-darwin", + "ref": "nixpkgs-23.05-darwin", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-2205": { + "nixpkgs-2311": { "locked": { - "lastModified": 1685573264, - "narHash": "sha256-Zffu01pONhs/pqH07cjlF10NnMDLok8ix5Uk4rhOnZQ=", + "lastModified": 1719957072, + "narHash": "sha256-gvFhEf5nszouwLAkT9nWsDzocUTqLWHuL++dvNjMp9I=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "380be19fbd2d9079f677978361792cb25e8a3635", + "rev": "7144d6241f02d171d25fba3edeaf15e0f2592105", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-22.05-darwin", + "ref": "nixpkgs-23.11-darwin", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-2211": { + "nixpkgs-2405": { "locked": { - "lastModified": 1688392541, - "narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=", + "lastModified": 1735564410, + "narHash": "sha256-HB/FA0+1gpSs8+/boEavrGJH+Eq08/R2wWNph1sM1Dg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b", + "rev": "1e7a8f391f1a490460760065fa0630b5520f9cf8", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-22.11-darwin", + "ref": "nixpkgs-24.05-darwin", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-2305": { + "nixpkgs-2411": { "locked": { - "lastModified": 1701362232, - "narHash": "sha256-GVdzxL0lhEadqs3hfRLuj+L1OJFGiL/L7gCcelgBlsw=", + "lastModified": 1751290243, + "narHash": "sha256-kNf+obkpJZWar7HZymXZbW+Rlk3HTEIMlpc6FCNz0Ds=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d2332963662edffacfddfad59ff4f709dde80ffe", + "rev": "5ab036a8d97cb9476fbe81b09076e6e91d15e1b6", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-23.05-darwin", + "ref": "nixpkgs-24.11-darwin", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-2311": { + "nixpkgs-2505": { "locked": { - "lastModified": 1701386440, - "narHash": "sha256-xI0uQ9E7JbmEy/v8kR9ZQan6389rHug+zOtZeZFiDJk=", + "lastModified": 1764560356, + "narHash": "sha256-M5aFEFPppI4UhdOxwdmceJ9bDJC4T6C6CzCK1E2FZyo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "293822e55ec1872f715a66d0eda9e592dc14419f", + "rev": "6c8f0cca84510cc79e09ea99a299c9bc17d03cb6", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-23.11-darwin", + "ref": "nixpkgs-25.05-darwin", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-regression": { + "nixpkgs-2511": { "locked": { - "lastModified": 1643052045, - "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "lastModified": 1775749320, + "narHash": "sha256-msT6frWJSQ2WR+0cpk+KPcZdLTLagUIsJwQwIX9JNSo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "rev": "74b87959b2d16f59f54d8559cf3cf26b9d907949", "type": "github" }, "original": { "owner": "NixOS", + "ref": "nixpkgs-25.11-darwin", "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", "type": "github" } }, "nixpkgs-unstable": { "locked": { - "lastModified": 1694822471, - "narHash": "sha256-6fSDCj++lZVMZlyqOe9SIOL8tYSBz1bI8acwovRwoX8=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "47585496bcb13fb72e4a90daeea2f434e2501998", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "47585496bcb13fb72e4a90daeea2f434e2501998", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1657693803, - "narHash": "sha256-G++2CJ9u0E7NNTAi9n5G8TdDmGJXcIjkJ3NF8cetQB8=", + "lastModified": 1775888245, + "narHash": "sha256-nwASzrRDD1JBEu/o8ekKYEXm/oJW6EMCzCRdrwcLe90=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "365e1b3a859281cf11b94f87231adeabbdd878a2", + "rev": "13043924aaa7375ce482ebe2494338e058282925", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-22.05-small", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } @@ -745,35 +701,56 @@ ] }, "locked": { - "lastModified": 1711814006, - "narHash": "sha256-0ctC7yeiB6C1dGncs/qm1LFrQnangMYctGkBmItWBZo=", - "owner": "Unisay", + "lastModified": 1781449244, + "narHash": "sha256-evfLWZ+i55b0cSfd/jgU5mXuBg2KDEP5WhEj2iuzIiM=", + "owner": "purescript-lua", "repo": "purescript-lua", - "rev": "0d87156005a87631191ff15d7163e03fd20378c2", + "rev": "94c13cecd1146494de56196a7badb3b1374d364d", "type": "github" }, "original": { - "owner": "Unisay", + "owner": "purescript-lua", "repo": "purescript-lua", "type": "github" } }, + "purescript-overlay": { + "inputs": { + "flake-compat": "flake-compat_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1780972251, + "narHash": "sha256-PwHYPpfLP+WjSwj765zJ1N0Xp4ET3+8vRqxJ031ua3M=", + "owner": "thomashoneyman", + "repo": "purescript-overlay", + "rev": "1cf88ab9d83596db0e0c0d304a16809c410e2917", + "type": "github" + }, + "original": { + "owner": "thomashoneyman", + "repo": "purescript-overlay", + "type": "github" + } + }, "root": { "inputs": { - "easyps": "easyps", "flake-utils": "flake-utils", "nixpkgs": "nixpkgs", - "pslua": "pslua" + "pslua": "pslua", + "purescript-overlay": "purescript-overlay" } }, "stackage": { "flake": false, "locked": { - "lastModified": 1710461339, - "narHash": "sha256-l2/ekwA4Z4NjiaCZytZrBTag2VaAOBUvsNttsH6kH4E=", + "lastModified": 1781225038, + "narHash": "sha256-eG1GGyHdEI8y2chHOmgx0rypbHyjIn9ViawYmN2CEd4=", "owner": "input-output-hk", "repo": "stackage.nix", - "rev": "724970b7dc837bf0d813b91f821948c3c5cc719f", + "rev": "e2af13c92a93da96529a874428acae18d085bafe", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index fbde00f..5198865 100644 --- a/flake.nix +++ b/flake.nix @@ -4,34 +4,45 @@ inputs = { flake-utils.url = "github:numtide/flake-utils"; nixpkgs.url = "nixpkgs/nixos-unstable"; - easyps = { - url = "github:justinwoo/easy-purescript-nix"; - flake = false; + purescript-overlay = { + url = "github:thomashoneyman/purescript-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; }; - pslua.url = "github:Unisay/purescript-lua"; + pslua.url = "github:purescript-lua/purescript-lua"; }; - outputs = { self, nixpkgs, flake-utils, easyps, pslua }: + outputs = { self, nixpkgs, flake-utils, purescript-overlay, pslua }: flake-utils.lib.eachDefaultSystem (system: let - p = nixpkgs.legacyPackages.${system}; - e = import easyps { pkgs = p; }; - l = p.lua51Packages; + pkgs = import nixpkgs { + inherit system; + overlays = [ purescript-overlay.overlays.default ]; + }; in { - devShell = p.mkShell { - buildInputs = [ - p.dhall - l.lua - l.luacheck - p.luaformatter - p.nixfmt - pslua.packages.${system}.default - e.purs-0_15_15 - e.purs-tidy - e.spago - p.treefmt - ]; + devShell = pkgs.mkShell { + buildInputs = with pkgs; [ + dhall + lua51Packages.lua + lua51Packages.luacheck + luaformatter + nixfmt-rfc-style + pslua.packages.${system}.default + purs-bin.purs-0_15_16 + spago-bin.spago-0_21_0 + treefmt + ]; }; }); -} + # --- Flake Local Nix Configuration ---------------------------- + nixConfig = { + extra-substituters = [ + "https://cache.iog.io" + "https://purescript-lua.cachix.org" + ]; + extra-trusted-public-keys = [ + "hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=" + "purescript-lua.cachix.org-1:yLs4ei2HtnuPtzLekOrW3xdfm95+Etw15gwgyIGTayA=" + ]; + }; +} diff --git a/package.json b/package.json deleted file mode 100644 index a1d6811..0000000 --- a/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "private": true, - "scripts": { - "clean": "rimraf output && rimraf .pulp-cache", - "build": "eslint src && pulp build -- --censor-lib --strict", - "test": "pulp test" - }, - "devDependencies": { - "eslint": "^7.15.0", - "pulp": "16.0.0-0", - "purescript-psa": "^0.8.2", - "rimraf": "^3.0.2" - } -} diff --git a/packages.dhall b/packages.dhall index 2416b25..b934417 100644 --- a/packages.dhall +++ b/packages.dhall @@ -3,7 +3,7 @@ let upstream-ps = sha256:ae8a25645e81ff979beb397a21e5d272fae7c9ebdb021a96b1b431388c8f3c34 let upstream-lua = - https://github.com/Unisay/purescript-lua-package-sets/releases/download/psc-0.15.15-20240336/packages.dhall + https://github.com/purescript-lua/purescript-lua-package-sets/releases/download/psc-0.15.15-20240336/packages.dhall sha256:2d548c8f4260d629ed65b9dfa83d93bf0abbeb5275a77a90a5d7c4a6df80bbe4 in upstream-ps // upstream-lua diff --git a/scripts/build b/scripts/build index a75a55a..c66490d 100755 --- a/scripts/build +++ b/scripts/build @@ -1,5 +1,6 @@ #!/usr/bin/env bash +set -euo pipefail echo "Building..." -spago build --quiet +spago build diff --git a/scripts/test b/scripts/test new file mode 100755 index 0000000..789e5c1 --- /dev/null +++ b/scripts/test @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Testing..." + +spago build --config spago-test.dhall --quiet + +if lua -e 'dofile("dist/test.lua").main()'; then + echo "✅ Tests succeeded." +else + echo "❌ Tests failed." + exit 1 +fi diff --git a/spago-test.dhall b/spago-test.dhall new file mode 100644 index 0000000..b27031f --- /dev/null +++ b/spago-test.dhall @@ -0,0 +1,14 @@ +let conf = ./spago.dhall + +in conf + // { sources = conf.sources # [ "test/**/*.purs" ] + , dependencies = conf.dependencies # [ "assert", "console" ] + , backend = + '' + pslua \ + --foreign-path . \ + --ps-output output \ + --lua-output-file dist/test.lua \ + --entry Test.Main + '' + } diff --git a/spago.dhall b/spago.dhall index 127c8c1..d5cb214 100644 --- a/spago.dhall +++ b/spago.dhall @@ -1,5 +1,5 @@ { name = "purescript-lua-st" -, dependencies = [ "partial", "prelude", "tailrec", "unsafe-coerce" ] +, dependencies = [ "effect", "partial", "prelude", "tailrec", "unsafe-coerce" ] , packages = ./packages.dhall , sources = [ "src/**/*.purs" ] , backend = @@ -7,7 +7,7 @@ pslua \ --foreign-path . \ --ps-output output \ - --lua-output-file dist/Control_Monad_ST_Class.lua \ - --entry Control.Monad.ST.Class + --lua-output-file dist/Control_Monad_ST.lua \ + --entry Control.Monad.ST '' } diff --git a/src/Control/Monad/ST/.editorconfig b/src/Control/Monad/ST/.editorconfig deleted file mode 100644 index 042cf81..0000000 --- a/src/Control/Monad/ST/.editorconfig +++ /dev/null @@ -1,18 +0,0 @@ -# EditorConfig is awesome: https://EditorConfig.org - -# top-most EditorConfig file -root = true - -# Unix-style newlines with a newline ending every file -[*] -end_of_line = lf -insert_final_newline = true - -# Matches multiple files with brace expansion notation -# Set default charset -[*.{purs,lua}] -charset = utf-8 - -[*.lua] -indent_style = space -indent_size = 2 diff --git a/src/Control/Monad/ST/Internal.js b/src/Control/Monad/ST/Internal.js deleted file mode 100644 index 24d2ed8..0000000 --- a/src/Control/Monad/ST/Internal.js +++ /dev/null @@ -1,90 +0,0 @@ -export const map_ = function (f) { - return function (a) { - return function () { - return f(a()); - }; - }; -}; - -export const pure_ = function (a) { - return function () { - return a; - }; -}; - -export const bind_ = function (a) { - return function (f) { - return function () { - return f(a())(); - }; - }; -}; - -export const run = function (f) { - return f(); -}; - -function whileST(f) { - return function (a) { - return function () { - while (f()) { - a(); - } - }; - }; -} -export { whileST as while }; - -function forST(lo) { - return function (hi) { - return function (f) { - return function () { - for (var i = lo; i < hi; i++) { - f(i)(); - } - }; - }; - }; -} -export { forST as for }; - -export const foreach = function (as) { - return function (f) { - return function () { - for (var i = 0, l = as.length; i < l; i++) { - f(as[i])(); - } - }; - }; -}; - -function newSTRef(val) { - return function () { - return { value: val }; - }; -} -export { newSTRef as new }; - -export const read = function (ref) { - return function () { - return ref.value; - }; -}; - -export const modifyImpl = function (f) { - return function (ref) { - return function () { - var t = f(ref.value); - ref.value = t.state; - return t.value; - }; - }; -}; - -export const write = function (a) { - return function (ref) { - return function () { - return ref.value = a; // eslint-disable-line no-return-assign - }; - }; -}; diff --git a/src/Control/Monad/ST/Internal.lua b/src/Control/Monad/ST/Internal.lua index 1ae9838..0fc115b 100644 --- a/src/Control/Monad/ST/Internal.lua +++ b/src/Control/Monad/ST/Internal.lua @@ -10,7 +10,7 @@ return { ["while"] = (function(f) return function(a) return function() while f() do a() end end end end), ["for"] = (function(lo) - return function(hi) return function(f) return function() for i = lo, hi do f(i)() end end end end + return function(hi) return function(f) return function() for i = lo, hi - 1 do f(i)() end end end end end), foreach = (function(as) return function(f) return function() for i = 1, #as do f(as[i])() end end end end), diff --git a/src/Control/Monad/ST/Uncurried.js b/src/Control/Monad/ST/Uncurried.js deleted file mode 100644 index 7745ade..0000000 --- a/src/Control/Monad/ST/Uncurried.js +++ /dev/null @@ -1,229 +0,0 @@ -export const mkSTFn1 = function mkSTFn1(fn) { - return function(x) { - return fn(x)(); - }; -}; - -export const mkSTFn2 = function mkSTFn2(fn) { - return function(a, b) { - return fn(a)(b)(); - }; -}; - -export const mkSTFn3 = function mkSTFn3(fn) { - return function(a, b, c) { - return fn(a)(b)(c)(); - }; -}; - -export const mkSTFn4 = function mkSTFn4(fn) { - return function(a, b, c, d) { - return fn(a)(b)(c)(d)(); - }; -}; - -export const mkSTFn5 = function mkSTFn5(fn) { - return function(a, b, c, d, e) { - return fn(a)(b)(c)(d)(e)(); - }; -}; - -export const mkSTFn6 = function mkSTFn6(fn) { - return function(a, b, c, d, e, f) { - return fn(a)(b)(c)(d)(e)(f)(); - }; -}; - -export const mkSTFn7 = function mkSTFn7(fn) { - return function(a, b, c, d, e, f, g) { - return fn(a)(b)(c)(d)(e)(f)(g)(); - }; -}; - -export const mkSTFn8 = function mkSTFn8(fn) { - return function(a, b, c, d, e, f, g, h) { - return fn(a)(b)(c)(d)(e)(f)(g)(h)(); - }; -}; - -export const mkSTFn9 = function mkSTFn9(fn) { - return function(a, b, c, d, e, f, g, h, i) { - return fn(a)(b)(c)(d)(e)(f)(g)(h)(i)(); - }; -}; - -export const mkSTFn10 = function mkSTFn10(fn) { - return function(a, b, c, d, e, f, g, h, i, j) { - return fn(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(); - }; -}; - -export const runSTFn1 = function runSTFn1(fn) { - return function(a) { - return function() { - return fn(a); - }; - }; -}; - -export const runSTFn2 = function runSTFn2(fn) { - return function(a) { - return function(b) { - return function() { - return fn(a, b); - }; - }; - }; -}; - -export const runSTFn3 = function runSTFn3(fn) { - return function(a) { - return function(b) { - return function(c) { - return function() { - return fn(a, b, c); - }; - }; - }; - }; -}; - -export const runSTFn4 = function runSTFn4(fn) { - return function(a) { - return function(b) { - return function(c) { - return function(d) { - return function() { - return fn(a, b, c, d); - }; - }; - }; - }; - }; -}; - -export const runSTFn5 = function runSTFn5(fn) { - return function(a) { - return function(b) { - return function(c) { - return function(d) { - return function(e) { - return function() { - return fn(a, b, c, d, e); - }; - }; - }; - }; - }; - }; -}; - -export const runSTFn6 = function runSTFn6(fn) { - return function(a) { - return function(b) { - return function(c) { - return function(d) { - return function(e) { - return function(f) { - return function() { - return fn(a, b, c, d, e, f); - }; - }; - }; - }; - }; - }; - }; -}; - -export const runSTFn7 = function runSTFn7(fn) { - return function(a) { - return function(b) { - return function(c) { - return function(d) { - return function(e) { - return function(f) { - return function(g) { - return function() { - return fn(a, b, c, d, e, f, g); - }; - }; - }; - }; - }; - }; - }; - }; -}; - -export const runSTFn8 = function runSTFn8(fn) { - return function(a) { - return function(b) { - return function(c) { - return function(d) { - return function(e) { - return function(f) { - return function(g) { - return function(h) { - return function() { - return fn(a, b, c, d, e, f, g, h); - }; - }; - }; - }; - }; - }; - }; - }; - }; -}; - -export const runSTFn9 = function runSTFn9(fn) { - return function(a) { - return function(b) { - return function(c) { - return function(d) { - return function(e) { - return function(f) { - return function(g) { - return function(h) { - return function(i) { - return function() { - return fn(a, b, c, d, e, f, g, h, i); - }; - }; - }; - }; - }; - }; - }; - }; - }; - }; -}; - -export const runSTFn10 = function runSTFn10(fn) { - return function(a) { - return function(b) { - return function(c) { - return function(d) { - return function(e) { - return function(f) { - return function(g) { - return function(h) { - return function(i) { - return function(j) { - return function() { - return fn(a, b, c, d, e, f, g, h, i, j); - }; - }; - }; - }; - }; - }; - }; - }; - }; - }; - }; -}; \ No newline at end of file diff --git a/src/Control/Monad/ST/Uncurried.lua b/src/Control/Monad/ST/Uncurried.lua index bb7140c..6e21d81 100644 --- a/src/Control/Monad/ST/Uncurried.lua +++ b/src/Control/Monad/ST/Uncurried.lua @@ -17,7 +17,9 @@ return { mkSTFn9 = (function(fn) return function(a, b, c, d, e, f, g, h, i) return fn(a)(b)(c)(d)(e)(f)(g)(h)(i)() end end), - mkSTFn10 = (function(fn) return function(a, b, c, d, e, f, g, h, i, j) return fn(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)() end end), + mkSTFn10 = (function(fn) + return function(a, b, c, d, e, f, g, h, i, j) return fn(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)() end + end), runSTFn1 = (function(fn) return function(a) return function() return fn(a) end end end), diff --git a/test/Main.purs b/test/Main.purs index c3b834a..9c30429 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -2,20 +2,117 @@ module Test.Main where import Prelude -import Effect (Effect) -import Effect.Console (logShow) import Control.Monad.ST as ST import Control.Monad.ST.Ref as STRef +import Effect (Effect) +import Effect.Console (log) +import Test.Assert (assertEqual) + +-------------------------------------------------------------------------------- +-- STRef ---------------------------------------------------------------------- + +-- | A fresh ref reads back its initial value. +newRead :: Int +newRead = ST.run (STRef.new 7 >>= STRef.read) + +-- | `write` replaces the cell and a later `read` observes the new value. +writeThenRead :: Int +writeThenRead = ST.run do + ref <- STRef.new 1 + _ <- STRef.write 42 ref + STRef.read ref + +-- | `modify` returns the updated value. +modifyReturnsNew :: Int +modifyReturnsNew = ST.run do + ref <- STRef.new 10 + STRef.modify (_ + 5) ref + +-- | `modify'` returns the chosen `value`... +modifyPrimeValue :: Int +modifyPrimeValue = ST.run do + ref <- STRef.new 5 + STRef.modify' (\s -> { state: s + 1, value: s * 10 }) ref + +-- | ...and stores the chosen `state`. +modifyPrimeState :: Int +modifyPrimeState = ST.run do + ref <- STRef.new 5 + _ <- STRef.modify' (\s -> { state: s + 1, value: s * 10 }) ref + STRef.read ref + +-------------------------------------------------------------------------------- +-- run + recursion ------------------------------------------------------------ +-- | Sum of squares 1..100 (= 338350), driven by a mutable `STRef` in a +-- | recursive loop. Exercises `new`, `read`, `modify` and `run` together. sumOfSquares :: Int sumOfSquares = ST.run do total <- STRef.new 0 - let loop 0 = STRef.read total - loop n = do - _ <- STRef.modify (_ + (n * n)) total - loop (n - 1) + let + loop 0 = STRef.read total + loop n = do + _ <- STRef.modify (_ + (n * n)) total + loop (n - 1) loop 100 +-------------------------------------------------------------------------------- +-- ST.for --------------------------------------------------------------------- + +-- | `ST.for lo hi` runs `hi` exclusive, so summing the indices of `for 0 5` +-- | is 0+1+2+3+4 = 10, not 15. Guards against an off-by-one that includes `hi`. +forSumExclusive :: Int +forSumExclusive = ST.run do + acc <- STRef.new 0 + ST.for 0 5 \i -> void (STRef.modify (_ + i) acc) + STRef.read acc + +-- | `ST.for lo hi` runs `lo` inclusive, so `for 3 4` executes exactly once. +forIterationCount :: Int +forIterationCount = ST.run do + acc <- STRef.new 0 + ST.for 3 4 \_ -> void (STRef.modify (_ + 1) acc) + STRef.read acc + +-- | An empty range (`hi == lo`) runs zero times. +forEmptyRange :: Int +forEmptyRange = ST.run do + acc <- STRef.new 0 + ST.for 2 2 \_ -> void (STRef.modify (_ + 1) acc) + STRef.read acc + +-------------------------------------------------------------------------------- +-- ST.while / ST.foreach ------------------------------------------------------ + +-- | `ST.while` repeats the body while the condition holds; counting up from +-- | 0 while `< 5` stops at exactly 5. +whileCountUp :: Int +whileCountUp = ST.run do + ref <- STRef.new 0 + ST.while (map (_ < 5) (STRef.read ref)) (void (STRef.modify (_ + 1) ref)) + STRef.read ref + +-- | `ST.foreach` visits every element of the array exactly once. +foreachSum :: Int +foreachSum = ST.run do + acc <- STRef.new 0 + ST.foreach [ 1, 2, 3, 4 ] \x -> void (STRef.modify (_ + x) acc) + STRef.read acc + +-------------------------------------------------------------------------------- +-- Entry point ---------------------------------------------------------------- + main :: Effect Unit main = do - logShow sumOfSquares + assertEqual { actual: newRead, expected: 7 } + assertEqual { actual: writeThenRead, expected: 42 } + assertEqual { actual: modifyReturnsNew, expected: 15 } + assertEqual { actual: modifyPrimeValue, expected: 50 } + assertEqual { actual: modifyPrimeState, expected: 6 } + assertEqual { actual: sumOfSquares, expected: 338350 } + assertEqual { actual: forSumExclusive, expected: 10 } + assertEqual { actual: forIterationCount, expected: 1 } + assertEqual { actual: forEmptyRange, expected: 0 } + assertEqual { actual: whileCountUp, expected: 5 } + assertEqual { actual: foreachSum, expected: 10 } + log "purescript-lua-st: all ST tests passed"