From cb7e095be3a2ab36da22291e2cfbe63664193f1c Mon Sep 17 00:00:00 2001 From: Yura Lazarev Date: Sun, 14 Jun 2026 23:19:40 +0200 Subject: [PATCH] chore: add treefmt formatting (nix fmt) and format the tree Wire treefmt via treefmt-nix: nixfmt, dhall format, purs-tidy (.tidyrc.json) and LuaFormatter for the FFI (.lua-format, kept over StyLua because it preserves the parentheses pslua's parser needs). `nix fmt` formats; the dev shell installs a content-based pre-commit hook and CI runs `nix fmt && git diff --exit-code` (content-based, since the in-place formatters bump mtime and would trip treefmt --fail-on-change). Lua lines budget 130 cols, matching the raised `luacheck --max-line-length`. The bulk of the diff is the first format pass. --- .github/workflows/ci.yml | 5 ++- .gitignore | 2 + .lua-format | 10 +++++ .tidyrc.json | 10 +++++ AGENTS.md | 16 +++++-- flake.lock | 23 +++++++++- flake.nix | 43 ++++++++++++++++-- src/Data/Enum.purs | 60 ++++++++++++++++--------- src/Data/Enum/Gen.purs | 6 ++- src/Data/Enum/Generic.purs | 76 +++++++++++++++++++++++--------- test/Test/Data/Enum.purs | 51 ++++++++++----------- test/Test/Data/Enum/Generic.purs | 46 ++++++++++++++++--- treefmt.nix | 43 ++++++++++++++++++ 13 files changed, 306 insertions(+), 85 deletions(-) create mode 100644 .lua-format create mode 100644 .tidyrc.json create mode 100644 treefmt.nix diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d624d2e..4dc2d20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,4 +24,7 @@ jobs: run: if [ -f scripts/test ]; then nix develop -c bash ./scripts/test; fi - name: Luacheck - run: nix develop -c luacheck --quiet --std lua51 --no-unused-args src/ + run: nix develop -c luacheck --quiet --std lua51 --no-unused-args --max-line-length 130 src/ + + - name: Format check + run: nix fmt && git diff --exit-code diff --git a/.gitignore b/.gitignore index db67e9a..e070528 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /.* !/.gitignore !/.github/ +!/.tidyrc.json +!/.lua-format /output/ diff --git a/.lua-format b/.lua-format new file mode 100644 index 0000000..2945014 --- /dev/null +++ b/.lua-format @@ -0,0 +1,10 @@ +# LuaFormatter config for the hand-written FFI under src/. +# 2-space indent. Keep simple functions on one line; column_limit sits a few +# columns under luacheck's 130 limit because lua-format under-counts the leading +# indent and trailing comma, so this keeps every emitted line within 130. +indent_width: 2 +use_tab: false +column_limit: 126 +continuation_indent_width: 2 +keep_simple_function_one_line: true +keep_simple_control_block_one_line: true diff --git a/.tidyrc.json b/.tidyrc.json new file mode 100644 index 0000000..8636af8 --- /dev/null +++ b/.tidyrc.json @@ -0,0 +1,10 @@ +{ + "importSort": "source", + "importWrap": "source", + "indent": 2, + "operatorsFile": null, + "ribbon": 1, + "typeArrowPlacement": "first", + "unicode": "source", + "width": 80 +} diff --git a/AGENTS.md b/AGENTS.md index dde531a..a312901 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,11 +4,21 @@ A PureScript→Lua FFI fork in the [`purescript-lua`](https://github.com/purescr ## 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/` +- Lint: `nix develop -c luacheck --quiet --std lua51 --no-unused-args --max-line-length 130 src/` +- Format: `nix fmt` (check: `nix fmt && git diff --exit-code`) + +## Formatting + +`nix fmt` runs treefmt (`treefmt.nix`): nixfmt for Nix, `dhall format`, purs-tidy +for `*.purs` (config in `.tidyrc.json`), and LuaFormatter for the `*.lua` FFI +(config in `.lua-format`). LuaFormatter is used over StyLua because it keeps the +parentheses pslua's foreign-file parser requires. The Lua line budget is 130 +columns, matching the `luacheck --max-line-length` above. The check is +content-based (`nix fmt && git diff --exit-code`) rather than `treefmt --ci`, +since the in-place formatters bump mtime even when content is unchanged, which +trips treefmt's `--fail-on-change`. CI and the pre-commit hook use it. ## Lua 5.1 target diff --git a/flake.lock b/flake.lock index 6b6c417..c47b792 100644 --- a/flake.lock +++ b/flake.lock @@ -740,7 +740,8 @@ "flake-utils": "flake-utils", "nixpkgs": "nixpkgs", "pslua": "pslua", - "purescript-overlay": "purescript-overlay" + "purescript-overlay": "purescript-overlay", + "treefmt-nix": "treefmt-nix" } }, "stackage": { @@ -803,6 +804,26 @@ "repo": "default", "type": "github" } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1780220602, + "narHash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "db947814a175b7ca6ded66e21383d938df01c227", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 5198865..4d86c4b 100644 --- a/flake.nix +++ b/flake.nix @@ -9,16 +9,33 @@ inputs.nixpkgs.follows = "nixpkgs"; }; pslua.url = "github:purescript-lua/purescript-lua"; + treefmt-nix = { + url = "github:numtide/treefmt-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; - outputs = { self, nixpkgs, flake-utils, purescript-overlay, pslua }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + self, + nixpkgs, + flake-utils, + purescript-overlay, + pslua, + treefmt-nix, + }: + flake-utils.lib.eachDefaultSystem ( + system: let pkgs = import nixpkgs { inherit system; overlays = [ purescript-overlay.overlays.default ]; }; - in { + treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix; + in + { + formatter = treefmtEval.config.build.wrapper; + checks.formatting = treefmtEval.config.build.check self; devShell = pkgs.mkShell { buildInputs = with pkgs; [ dhall @@ -31,8 +48,26 @@ spago-bin.spago-0_21_0 treefmt ]; + # Install a content-based pre-commit hook. It compares the working + # tree diff before and after `nix fmt`, so it only objects to changes + # the formatter itself introduces (not the developer's existing + # unstaged work) and is not fooled by formatters that only bump mtime. + # Rewritten each shell entry to stay in sync with this flake. + shellHook = '' + hook=.git/hooks/pre-commit + if [ -d .git ]; then + printf '%s\n' \ + '#!/usr/bin/env bash' \ + 'before=$(git diff)' \ + 'nix fmt >/dev/null 2>&1 || exit 0' \ + '[ "$before" = "$(git diff)" ] || { echo "nix fmt changed files; re-stage them, then commit." >&2; exit 1; }' \ + > "$hook" + chmod +x "$hook" + fi + ''; }; - }); + } + ); # --- Flake Local Nix Configuration ---------------------------- nixConfig = { diff --git a/src/Data/Enum.purs b/src/Data/Enum.purs index 0d4b097..0bc1a3e 100644 --- a/src/Data/Enum.purs +++ b/src/Data/Enum.purs @@ -1,6 +1,11 @@ module Data.Enum - ( class Enum, succ, pred - , class BoundedEnum, cardinality, toEnum, fromEnum + ( class Enum + , succ + , pred + , class BoundedEnum + , cardinality + , toEnum + , fromEnum , toEnumWithDefaults , Cardinality(..) , enumFromTo @@ -55,7 +60,7 @@ instance enumBoolean :: Enum Boolean where succ false = Just true succ _ = Nothing pred true = Just false - pred _= Nothing + pred _ = Nothing instance enumInt :: Enum Int where succ n = if n < top then Just (n + 1) else Nothing @@ -90,8 +95,10 @@ instance enumEither :: (BoundedEnum a, BoundedEnum b) => Enum (Either a b) where pred (Right b) = maybe (Just (Left top)) (Just <<< Right) (pred b) instance enumTuple :: (Enum a, BoundedEnum b) => Enum (Tuple a b) where - succ (Tuple a b) = maybe (flip Tuple bottom <$> succ a) (Just <<< Tuple a) (succ b) - pred (Tuple a b) = maybe (flip Tuple top <$> pred a) (Just <<< Tuple a) (pred b) + succ (Tuple a b) = maybe (flip Tuple bottom <$> succ a) (Just <<< Tuple a) + (succ b) + pred (Tuple a b) = maybe (flip Tuple top <$> pred a) (Just <<< Tuple a) + (pred b) -- | Type class for finite enumerations. -- | @@ -189,7 +196,7 @@ enumFromTo = case _, _ of | from < to -> unfoldr1 (go succ (<=) to) from | otherwise -> unfoldr1 (go pred (>=) to) from where - go step op to a = Tuple a (step a >>= \a' -> guard (a' `op` to) $> a') + go step op to a = Tuple a (step a >>= \a' -> guard (a' `op` to) $> a') -- | Returns a sequence of elements from the first value, taking steps -- | according to the difference between the first and second value, up to @@ -205,7 +212,15 @@ enumFromTo = case _, _ of -- | -- | The example shows `Array` return values, but the result can be any type -- | with an `Unfoldable1` instance. -enumFromThenTo :: forall f a. Unfoldable f => Functor f => BoundedEnum a => a -> a -> a -> f a +enumFromThenTo + :: forall f a + . Unfoldable f + => Functor f + => BoundedEnum a + => a + -> a + -> a + -> f a enumFromThenTo = unsafePartial \a b c -> let a' = fromEnum a @@ -214,9 +229,9 @@ enumFromThenTo = unsafePartial \a b c -> in (toEnum >>> fromJust) <$> unfoldr (go (b' - a') c') a' where - go step to e - | e <= to = Just (Tuple e (e + step)) - | otherwise = Nothing + go step to e + | e <= to = Just (Tuple e (e + step)) + | otherwise = Nothing -- | Produces all successors of an `Enum` value, excluding the start value. upFrom :: forall a u. Enum a => Unfoldable u => a -> u a @@ -271,7 +286,8 @@ defaultPred toEnum' fromEnum' a = toEnum' (fromEnum' a - 1) -- | -- | Runs in `O(n)` where `n` is `fromEnum top` defaultCardinality :: forall a. Bounded a => Enum a => Cardinality a -defaultCardinality = Cardinality $ go 1 (bottom :: a) where +defaultCardinality = Cardinality $ go 1 (bottom :: a) + where go i x = case succ x of Just x' -> go (i + 1) x' @@ -285,17 +301,15 @@ defaultCardinality = Cardinality $ go 1 (bottom :: a) where -- | Runs in `O(n)` where `n` is `fromEnum a`. defaultToEnum :: forall a. Bounded a => Enum a => Int -> Maybe a defaultToEnum i' = - if i' < 0 - then Nothing - else go i' bottom + if i' < 0 then Nothing + else go i' bottom where go i x = - if i == 0 - then Just x - -- We avoid using >>= here because it foils tail-call optimization - else case succ x of - Just x' -> go (i - 1) x' - Nothing -> Nothing + if i == 0 then Just x + -- We avoid using >>= here because it foils tail-call optimization + else case succ x of + Just x' -> go (i - 1) x' + Nothing -> Nothing -- | Provides a default implementation for `fromEnum`. -- | @@ -304,7 +318,8 @@ defaultToEnum i' = -- | -- | Runs in `O(n)` where `n` is `fromEnum a`. defaultFromEnum :: forall a. Enum a => a -> Int -defaultFromEnum = go 0 where +defaultFromEnum = go 0 + where go i x = case pred x of Just x' -> go (i + 1) x' @@ -314,7 +329,8 @@ diag :: forall a. a -> Tuple a a diag a = Tuple a a charToEnum :: Int -> Maybe Char -charToEnum n | n >= toCharCode bottom && n <= toCharCode top = Just (fromCharCode n) +charToEnum n | n >= toCharCode bottom && n <= toCharCode top = Just + (fromCharCode n) charToEnum _ = Nothing foreign import toCharCode :: Char -> Int diff --git a/src/Data/Enum/Gen.purs b/src/Data/Enum/Gen.purs index 86caebd..d0be596 100644 --- a/src/Data/Enum/Gen.purs +++ b/src/Data/Enum/Gen.purs @@ -12,7 +12,9 @@ genBoundedEnum :: forall m a. MonadGen m => BoundedEnum a => m a genBoundedEnum = case succ bottom of Just a → - let possibilities = enumFromTo a top :: Array a - in elements (bottom :| possibilities) + let + possibilities = enumFromTo a top :: Array a + in + elements (bottom :| possibilities) Nothing → pure bottom diff --git a/src/Data/Enum/Generic.purs b/src/Data/Enum/Generic.purs index 0d59cca..84cfd65 100644 --- a/src/Data/Enum/Generic.purs +++ b/src/Data/Enum/Generic.purs @@ -20,11 +20,19 @@ instance genericEnumArgument :: Enum a => GenericEnum (Argument a) where genericPred' (Argument a) = Argument <$> pred a genericSucc' (Argument a) = Argument <$> succ a -instance genericEnumConstructor :: GenericEnum a => GenericEnum (Constructor name a) where +instance genericEnumConstructor :: + GenericEnum a => + GenericEnum (Constructor name a) where genericPred' (Constructor a) = Constructor <$> genericPred' a genericSucc' (Constructor a) = Constructor <$> genericSucc' a -instance genericEnumSum :: (GenericEnum a, GenericTop a, GenericEnum b, GenericBottom b) => GenericEnum (Sum a b) where +instance genericEnumSum :: + ( GenericEnum a + , GenericTop a + , GenericEnum b + , GenericBottom b + ) => + GenericEnum (Sum a b) where genericPred' = case _ of Inl a -> Inl <$> genericPred' a Inr b -> case genericPred' b of @@ -36,7 +44,15 @@ instance genericEnumSum :: (GenericEnum a, GenericTop a, GenericEnum b, GenericB Just a' -> Just (Inl a') Inr b -> Inr <$> genericSucc' b -instance genericEnumProduct :: (GenericEnum a, GenericTop a, GenericBottom a, GenericEnum b, GenericTop b, GenericBottom b) => GenericEnum (Product a b) where +instance genericEnumProduct :: + ( GenericEnum a + , GenericTop a + , GenericBottom a + , GenericEnum b + , GenericTop b + , GenericBottom b + ) => + GenericEnum (Product a b) where genericPred' (Product a b) = case genericPred' b of Just p -> Just $ Product a p Nothing -> flip Product genericTop' <$> genericPred' a @@ -44,7 +60,6 @@ instance genericEnumProduct :: (GenericEnum a, GenericTop a, GenericBottom a, Ge Just s -> Just $ Product a s Nothing -> flip Product genericBottom' <$> genericSucc' a - -- | A `Generic` implementation of the `pred` member from the `Enum` type class. genericPred :: forall a rep. Generic a rep => GenericEnum rep => a -> Maybe a genericPred = map to <<< genericPred' <<< from @@ -63,21 +78,30 @@ instance genericBoundedEnumNoArguments :: GenericBoundedEnum NoArguments where genericToEnum' i = if i == 0 then Just NoArguments else Nothing genericFromEnum' _ = 0 -instance genericBoundedEnumArgument :: BoundedEnum a => GenericBoundedEnum (Argument a) where +instance genericBoundedEnumArgument :: + BoundedEnum a => + GenericBoundedEnum (Argument a) where genericCardinality' = Cardinality (unwrap (cardinality :: Cardinality a)) genericToEnum' i = Argument <$> toEnum i genericFromEnum' (Argument a) = fromEnum a -instance genericBoundedEnumConstructor :: GenericBoundedEnum a => GenericBoundedEnum (Constructor name a) where - genericCardinality' = Cardinality (unwrap (genericCardinality' :: Cardinality a)) +instance genericBoundedEnumConstructor :: + GenericBoundedEnum a => + GenericBoundedEnum (Constructor name a) where + genericCardinality' = Cardinality + (unwrap (genericCardinality' :: Cardinality a)) genericToEnum' i = Constructor <$> genericToEnum' i genericFromEnum' (Constructor a) = genericFromEnum' a -instance genericBoundedEnumSum :: (GenericBoundedEnum a, GenericBoundedEnum b) => GenericBoundedEnum (Sum a b) where +instance genericBoundedEnumSum :: + ( GenericBoundedEnum a + , GenericBoundedEnum b + ) => + GenericBoundedEnum (Sum a b) where genericCardinality' = Cardinality $ unwrap (genericCardinality' :: Cardinality a) - + unwrap (genericCardinality' :: Cardinality b) + + unwrap (genericCardinality' :: Cardinality b) genericToEnum' n = to genericCardinality' where to :: Cardinality a -> Maybe (Sum a b) @@ -88,31 +112,41 @@ instance genericBoundedEnumSum :: (GenericBoundedEnum a, GenericBoundedEnum b) = Inl a -> genericFromEnum' a Inr b -> genericFromEnum' b + unwrap (genericCardinality' :: Cardinality a) - -instance genericBoundedEnumProduct :: (GenericBoundedEnum a, GenericBoundedEnum b) => GenericBoundedEnum (Product a b) where +instance genericBoundedEnumProduct :: + ( GenericBoundedEnum a + , GenericBoundedEnum b + ) => + GenericBoundedEnum (Product a b) where genericCardinality' = Cardinality $ unwrap (genericCardinality' :: Cardinality a) - * unwrap (genericCardinality' :: Cardinality b) + * unwrap (genericCardinality' :: Cardinality b) genericToEnum' n = to genericCardinality' - where to :: Cardinality b -> Maybe (Product a b) - to (Cardinality cb) = Product <$> (genericToEnum' $ n `div` cb) <*> (genericToEnum' $ n `mod` cb) + where + to :: Cardinality b -> Maybe (Product a b) + to (Cardinality cb) = Product <$> (genericToEnum' $ n `div` cb) <*> + (genericToEnum' $ n `mod` cb) genericFromEnum' = from genericCardinality' - where from :: Cardinality b -> (Product a b) -> Int - from (Cardinality cb) (Product a b) = genericFromEnum' a * cb + genericFromEnum' b - + where + from :: Cardinality b -> (Product a b) -> Int + from (Cardinality cb) (Product a b) = genericFromEnum' a * cb + + genericFromEnum' b -- | A `Generic` implementation of the `cardinality` member from the -- | `BoundedEnum` type class. -genericCardinality :: forall a rep. Generic a rep => GenericBoundedEnum rep => Cardinality a -genericCardinality = Cardinality (unwrap (genericCardinality' :: Cardinality rep)) +genericCardinality + :: forall a rep. Generic a rep => GenericBoundedEnum rep => Cardinality a +genericCardinality = Cardinality + (unwrap (genericCardinality' :: Cardinality rep)) -- | A `Generic` implementation of the `toEnum` member from the `BoundedEnum` -- | type class. -genericToEnum :: forall a rep. Generic a rep => GenericBoundedEnum rep => Int -> Maybe a +genericToEnum + :: forall a rep. Generic a rep => GenericBoundedEnum rep => Int -> Maybe a genericToEnum = map to <<< genericToEnum' -- | A `Generic` implementation of the `fromEnum` member from the `BoundedEnum` -- | type class. -genericFromEnum :: forall a rep. Generic a rep => GenericBoundedEnum rep => a -> Int +genericFromEnum + :: forall a rep. Generic a rep => GenericBoundedEnum rep => a -> Int genericFromEnum = genericFromEnum' <<< from diff --git a/test/Test/Data/Enum.purs b/test/Test/Data/Enum.purs index a71d2c2..5dc631e 100644 --- a/test/Test/Data/Enum.purs +++ b/test/Test/Data/Enum.purs @@ -12,7 +12,7 @@ import Test.Assert (assertEqual) data T = A | B | C | D | E -derive instance eqT :: Eq T +derive instance eqT :: Eq T derive instance ordT :: Ord T instance showT :: Show T where @@ -59,8 +59,9 @@ instance boundedUpto100k :: Bounded Upto100k where bottom = Upto100k 0 instance enumUpto100k :: Enum Upto100k where - succ (Upto100k x) = if (x+1) > 100000 then Nothing else Just (Upto100k (x+1)) - pred (Upto100k x) = if (x-1) < 0 then Nothing else Just (Upto100k (x-1)) + succ (Upto100k x) = + if (x + 1) > 100000 then Nothing else Just (Upto100k (x + 1)) + pred (Upto100k x) = if (x - 1) < 0 then Nothing else Just (Upto100k (x - 1)) instance boundedEnumUpto100k :: BoundedEnum Upto100k where cardinality = defaultCardinality @@ -72,59 +73,59 @@ testEnum = do log "enumFromTo" assertEqual { actual: enumFromTo A A - , expected: [A] + , expected: [ A ] } assertEqual { actual: enumFromTo B A - , expected: [B, A] + , expected: [ B, A ] } assertEqual { actual: enumFromTo A C - , expected: [A, B, C] + , expected: [ A, B, C ] } assertEqual { actual: enumFromTo A E - , expected: [A, B, C, D, E] + , expected: [ A, B, C, D, E ] } assertEqual { actual: enumFromTo 0 3 - , expected: [0, 1, 2, 3] + , expected: [ 0, 1, 2, 3 ] } assertEqual { actual: enumFromTo 'c' 'a' - , expected: ['c', 'b', 'a'] + , expected: [ 'c', 'b', 'a' ] } log "enumFromThenTo" assertEqual { actual: enumFromThenTo A B E - , expected: [A, B, C, D, E] + , expected: [ A, B, C, D, E ] } assertEqual { actual: enumFromThenTo A C E - , expected: [A, C, E] + , expected: [ A, C, E ] } assertEqual { actual: enumFromThenTo A E E - , expected: [A, E] + , expected: [ A, E ] } assertEqual { actual: enumFromThenTo A C C - , expected: [A, C] + , expected: [ A, C ] } assertEqual { actual: enumFromThenTo A C D - , expected: [A, C] + , expected: [ A, C ] } log "upFrom" assertEqual { actual: upFrom B - , expected: [C, D, E] + , expected: [ C, D, E ] } assertEqual { actual: upFrom D - , expected: [E] + , expected: [ E ] } assertEqual { actual: upFrom E @@ -134,15 +135,15 @@ testEnum = do log "upFromIncluding" assertEqual { actual: upFromIncluding B - , expected: [B, C, D, E] + , expected: [ B, C, D, E ] } assertEqual { actual: upFromIncluding B - , expected: B :| [C, D, E] + , expected: B :| [ C, D, E ] } assertEqual { actual: upFromIncluding D - , expected: D :| [E] + , expected: D :| [ E ] } assertEqual { actual: upFromIncluding E @@ -152,11 +153,11 @@ testEnum = do log "downFrom" assertEqual { actual: downFrom D - , expected: [C, B, A] + , expected: [ C, B, A ] } assertEqual { actual: downFrom B - , expected: [A] + , expected: [ A ] } assertEqual { actual: downFrom A @@ -166,15 +167,15 @@ testEnum = do log "downFromIncluding" assertEqual { actual: downFromIncluding D - , expected: [D, C, B, A] + , expected: [ D, C, B, A ] } assertEqual { actual: downFromIncluding B - , expected: [B, A] + , expected: [ B, A ] } assertEqual { actual: downFromIncluding A - , expected: [A] + , expected: [ A ] } log "defaultCardinality is stack safe" @@ -194,7 +195,7 @@ testEnum = do { actual: defaultFromEnum (Upto100k 100000) , expected: 100000 } - + log "charToEnum" assertEqual { actual: Nothing :: Maybe Char diff --git a/test/Test/Data/Enum/Generic.purs b/test/Test/Data/Enum/Generic.purs index 7472119..800731f 100644 --- a/test/Test/Data/Enum/Generic.purs +++ b/test/Test/Data/Enum/Generic.purs @@ -15,77 +15,105 @@ import Effect.Console (log) import Test.Assert (assert) data SimpleBounded = A | B | C | D + derive instance genericSimpleBounded :: G.Generic SimpleBounded _ instance eqSimpleBounded :: Eq SimpleBounded where eq x y = GEq.genericEq x y + instance ordSimpleBounded :: Ord SimpleBounded where compare x y = GOrd.genericCompare x y + instance showSimpleBounded :: Show SimpleBounded where show x = GShow.genericShow x + instance boundedSimpleBounded :: Bounded SimpleBounded where bottom = GBounded.genericBottom top = GBounded.genericTop + instance enumSimpleBounded :: Enum SimpleBounded where pred = GEnum.genericPred succ = GEnum.genericSucc + instance boundedEnumSimpleBounded :: BoundedEnum SimpleBounded where cardinality = GEnum.genericCardinality toEnum = GEnum.genericToEnum fromEnum = GEnum.genericFromEnum data Option a = None | Some a + derive instance genericOption :: G.Generic (Option a) _ instance eqOption :: Eq a => Eq (Option a) where eq x y = GEq.genericEq x y + instance ordOption :: Ord a => Ord (Option a) where compare x y = GOrd.genericCompare x y + instance showOption :: Show a => Show (Option a) where show x = GShow.genericShow x + instance boundedOption :: Bounded a => Bounded (Option a) where bottom = GBounded.genericBottom top = GBounded.genericTop + instance enumOption :: (Bounded a, Enum a) => Enum (Option a) where pred = GEnum.genericPred succ = GEnum.genericSucc + instance boundedEnumOption :: BoundedEnum a => BoundedEnum (Option a) where cardinality = GEnum.genericCardinality toEnum = GEnum.genericToEnum fromEnum = GEnum.genericFromEnum data Bit = Zero | One + derive instance genericBit :: G.Generic Bit _ instance eqBit :: Eq Bit where eq x y = GEq.genericEq x y + instance ordBit :: Ord Bit where compare x y = GOrd.genericCompare x y + instance showBit :: Show Bit where show x = GShow.genericShow x + instance boundedBit :: Bounded Bit where bottom = GBounded.genericBottom top = GBounded.genericTop + instance enumBit :: Enum Bit where pred = GEnum.genericPred succ = GEnum.genericSucc + instance boundedEnumBit :: BoundedEnum Bit where cardinality = GEnum.genericCardinality toEnum = GEnum.genericToEnum fromEnum = GEnum.genericFromEnum data Pair a b = Pair a b + derive instance genericPair :: G.Generic (Pair a b) _ instance eqPair :: (Eq a, Eq b) => Eq (Pair a b) where eq = GEq.genericEq + instance ordPair :: (Ord a, Ord b) => Ord (Pair a b) where compare = GOrd.genericCompare + instance showPair :: (Show a, Show b) => Show (Pair a b) where show = GShow.genericShow + instance boundedPair :: (Bounded a, Bounded b) => Bounded (Pair a b) where bottom = GBounded.genericBottom top = GBounded.genericTop + instance enumPair :: (Bounded a, Enum a, Bounded b, Enum b) => Enum (Pair a b) where pred = GEnum.genericPred succ = GEnum.genericSucc -instance boundedEnumPair :: (BoundedEnum a, BoundedEnum b) => BoundedEnum (Pair a b) where + +instance boundedEnumPair :: + ( BoundedEnum a + , BoundedEnum b + ) => + BoundedEnum (Pair a b) where cardinality = GEnum.genericCardinality toEnum = GEnum.genericToEnum fromEnum = GEnum.genericFromEnum @@ -120,7 +148,8 @@ testGenericEnum = do assert $ pred (bottom :: Pair Bit SimpleBounded) == Nothing log "Checking product (pred =<< succ bottom)" - assert $ (pred =<< succ (bottom :: Pair Bit SimpleBounded)) == Just (Pair Zero A) + assert $ (pred =<< succ (bottom :: Pair Bit SimpleBounded)) == Just + (Pair Zero A) log "Checking product succ top" assert $ succ (top :: Pair Bit SimpleBounded) == Nothing @@ -135,16 +164,21 @@ testGenericEnum = do assert $ (cardinality :: Cardinality (Option SimpleBounded)) == Cardinality 5 log "Checking product cardinality" - assert $ (cardinality :: Cardinality (Pair Bit SimpleBounded)) == Cardinality 8 + assert $ (cardinality :: Cardinality (Pair Bit SimpleBounded)) == Cardinality + 8 log "Checking simple toEnum/fromEnum roundtrip" assert $ toEnum (fromEnum A) == Just A assert $ toEnum (fromEnum B) == Just B log "Checking composite toEnum/fromEnum roundtrip" - assert $ toEnum (fromEnum (None :: Option SimpleBounded)) == Just (None :: Option SimpleBounded) + assert $ toEnum (fromEnum (None :: Option SimpleBounded)) == Just + (None :: Option SimpleBounded) assert $ toEnum (fromEnum (Some A)) == Just (Some A) log "Checking product toEnum/fromEnum roundtrip" - assert $ let allPairs = enumFromTo bottom top :: Array (Pair Bit SimpleBounded) - in (toEnum <<< fromEnum <$> allPairs) == (Just <$> allPairs) + assert $ + let + allPairs = enumFromTo bottom top :: Array (Pair Bit SimpleBounded) + in + (toEnum <<< fromEnum <$> allPairs) == (Just <$> allPairs) diff --git a/treefmt.nix b/treefmt.nix new file mode 100644 index 0000000..0f57573 --- /dev/null +++ b/treefmt.nix @@ -0,0 +1,43 @@ +{ pkgs, ... }: +{ + projectRootFile = "flake.nix"; + + # Nix — RFC 166 formatter. + programs.nixfmt.enable = true; + + # Dhall — spago.dhall / packages.dhall layout. + programs.dhall.enable = true; + + # PureScript — purs-tidy is not a first-class treefmt program, so wire it via + # the generic mechanism. It picks up `.tidyrc.json` from the project root. + settings.formatter.purs-tidy = { + command = "${pkgs.purs-tidy}/bin/purs-tidy"; + options = [ "format-in-place" ]; + includes = [ "*.purs" ]; + }; + + # Lua FFI — LuaFormatter keeps the parentheses pslua's foreign-file parser + # requires (unlike StyLua, which strips them). Config in `.lua-format`. + settings.formatter.lua-format = { + command = "${pkgs.luaformatter}/bin/lua-format"; + options = [ + "-i" + "-c" + ".lua-format" + ]; + includes = [ "*.lua" ]; + }; + + # Never format generated output or vendored trees. + settings.global.excludes = [ + "dist/*" + "output/*" + ".spago/*" + "node_modules/*" + "*.lock" + "flake.lock" + "spago.lock" + ".tidyrc.json" + ".lua-format" + ]; +}