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
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/.*
!/.gitignore
!/.github/
!/.tidyrc.json
!/.lua-format
/output/
38 changes: 8 additions & 30 deletions .lua-format
Original file line number Diff line number Diff line change
@@ -1,32 +1,10 @@
align_args: true
align_parameter: true
align_table_field: true
break_after_functioncall_lp: false
break_after_functiondef_lp: false
break_after_operator: true
break_after_table_lb: true
break_before_functioncall_rp: false
break_before_functiondef_rp: false
break_before_table_rb: true
chop_down_kv_table: true
chop_down_parameter: false
chop_down_table: false
column_limit: 120
column_table_limit: 120
continuation_indent_width: 2
double_quote_to_single_quote: false
extra_sep_at_table_end: false
# 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
keep_simple_control_block_one_line: true
keep_simple_function_one_line: true
line_breaks_after_function_body: 1
line_separator: input
single_quote_to_double_quote: false
spaces_around_equals_in_field: true
spaces_before_call: 1
spaces_inside_functioncall_parens: false
spaces_inside_functiondef_parens: false
spaces_inside_table_braces: false
tab_width: 2
table_sep: ","
use_tab: false
column_limit: 126
continuation_indent_width: 2
keep_simple_function_one_line: true
keep_simple_control_block_one_line: true
10 changes: 10 additions & 0 deletions .tidyrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"importSort": "source",
"importWrap": "source",
"indent": 2,
"operatorsFile": null,
"ribbon": 1,
"typeArrowPlacement": "first",
"unicode": "source",
"width": 80
}
16 changes: 13 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
23 changes: 22 additions & 1 deletion flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 39 additions & 4 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Comment thread
Unisay marked this conversation as resolved.
'';
};
});
}
);

# --- Flake Local Nix Configuration ----------------------------
nixConfig = {
Expand Down
7 changes: 5 additions & 2 deletions src/Data/Number.purs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ module Data.Number
, max
, min
, pow
, remainder, (%)
, remainder
, (%)
, round
, sign
, sin
Expand Down Expand Up @@ -112,7 +113,9 @@ foreign import isFinite :: Number -> Boolean
fromString :: String -> Maybe Number
fromString str = runFn4 fromStringImpl str isFinite Just Nothing

foreign import fromStringImpl :: Fn4 String (Number -> Boolean) (forall a. a -> Maybe a) (forall a. Maybe a) (Maybe Number)
foreign import fromStringImpl
:: Fn4 String (Number -> Boolean) (forall a. a -> Maybe a) (forall a. Maybe a)
(Maybe Number)

-- | Returns the absolute value of the argument.
-- | ```purs
Expand Down
10 changes: 5 additions & 5 deletions src/Data/Number/Approximate.purs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ newtype Fraction = Fraction Number
-- | true
-- | ```
eqRelative :: Fraction -> Number -> Number -> Boolean
eqRelative (Fraction frac) 0.0 y = abs y <= frac
eqRelative (Fraction frac) x 0.0 = abs x <= frac
eqRelative (Fraction frac) x y = abs (x - y) <= frac * abs (x + y) / 2.0
eqRelative (Fraction frac) 0.0 y = abs y <= frac
eqRelative (Fraction frac) x 0.0 = abs x <= frac
eqRelative (Fraction frac) x y = abs (x - y) <= frac * abs (x + y) / 2.0

-- | Test if two numbers are approximately equal, up to a relative difference
-- | of one part in a million:
Expand All @@ -63,8 +63,8 @@ eqRelative (Fraction frac) x y = abs (x - y) <= frac * abs (x + y) / 2.0
eqApproximate :: Number -> Number -> Boolean
eqApproximate = eqRelative onePPM
where
onePPM :: Fraction
onePPM = Fraction 1.0e-6
onePPM :: Fraction
onePPM = Fraction 1.0e-6

infix 4 eqApproximate as ~=
infix 4 eqApproximate as ≅
Expand Down
8 changes: 4 additions & 4 deletions src/Data/Number/Format.purs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ module Data.Number.Format

import Prelude

foreign import toPrecisionNative :: Int -> Number -> String
foreign import toFixedNative :: Int -> Number -> String
foreign import toPrecisionNative :: Int -> Number -> String
foreign import toFixedNative :: Int -> Number -> String
foreign import toExponentialNative :: Int -> Number -> String

-- | The `Format` data type specifies how a number will be formatted.
Expand All @@ -57,8 +57,8 @@ exponential = Exponential <<< clamp 0 20

-- | Convert a number to a string with a given format.
toStringWith :: Format -> Number -> String
toStringWith (Precision p) = toPrecisionNative p
toStringWith (Fixed p) = toFixedNative p
toStringWith (Precision p) = toPrecisionNative p
toStringWith (Fixed p) = toFixedNative p
toStringWith (Exponential p) = toExponentialNative p

-- | Convert a number to a string via JavaScript's toString method.
Expand Down
35 changes: 20 additions & 15 deletions test/Test/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,27 @@ infix 1 eqAbsolute' as =~=
numbersTestCode :: Effect Unit
numbersTestCode = do


log "Data.Number.fromString"
log "\tvalid number string"
assertTrue' "integer strings are coerced" $
fromMaybe false $ map (_ == 123.0) $ fromString "123"

assertTrue' "decimals are coerced" $
fromMaybe false $ map (_ == 12.34) $ fromString "12.34"

assertTrue' "exponents are coerced" $
fromMaybe false $ map (_ == 1e4) $ fromString "1e4"

assertTrue' "decimals exponents are coerced" $
fromMaybe false $ map (_ == 1.2e4) $ fromString "1.2e4"
assertTrue' "integer strings are coerced"
$ fromMaybe false
$ map (_ == 123.0)
$ fromString "123"

assertTrue' "decimals are coerced"
$ fromMaybe false
$ map (_ == 12.34)
$ fromString "12.34"

assertTrue' "exponents are coerced"
$ fromMaybe false
$ map (_ == 1e4)
$ fromString "1e4"

assertTrue' "decimals exponents are coerced"
$ fromMaybe false
$ map (_ == 1.2e4)
$ fromString "1.2e4"

log "\tinvalid number string"
assertTrue' "invalid strings are not coerced" $
Expand Down Expand Up @@ -215,7 +222,7 @@ numbersTestCode = do
assertFalse' "should return false for differences larger than 10%" $
0.000000000001 ~= 0.00000000000111

-- assertFalse
-- assertFalse
assertFalse' "should return false for differences larger than 10%" $
0.000000000001 ~= 0.0000000000009

Expand Down Expand Up @@ -259,7 +266,6 @@ numbersTestCode = do
assertTrue' "should work for 'fractions' larger than one" $
eqRelative (Fraction 3.0) 10.0 29.5


log "Data.Number.Approximate.eqApproximate"
log "\t0.1 + 0.2 ≅ 0.3"
assertTrue' "0.1 + 0.2 should be approximately equal to 0.3" $
Expand All @@ -268,7 +274,6 @@ numbersTestCode = do
assertTrue' "0.1 + 0.200001 should not be approximately equal to 0.3" $
0.1 + 0.200001 ≇ 0.3


log "Data.Number.Approximate.eqAbsolute"
log "\teqAbsolute"
assertTrue' "should succeed for differences smaller than the tolerance" $
Expand Down
2 changes: 1 addition & 1 deletion test/regression/format.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
local M = assert(dofile("src/Data/Number/Format.lua"))

assert(type(M.toPrecisionNative(6)(1234.56789)) == "string",
"toPrecisionNative must format its bound argument, not error on a nil global")
"toPrecisionNative must format its bound argument, not error on a nil global")

print("OK Format.lua uses the bound argument n")
43 changes: 43 additions & 0 deletions treefmt.nix
Original file line number Diff line number Diff line change
@@ -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"
];
}
Loading