Skip to content
Closed
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
29 changes: 29 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on: push

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- uses: purescript-contrib/setup-purescript@main

- name: Cache PureScript dependencies
uses: actions/cache@v2
# This cache uses the .dhall files to know when it should reinstall
# and rebuild packages. It caches both the installed packages from
# the `.spago` directory and compilation artifacts from the `output`
# directory. When restored the compiler will rebuild any files that
# have changed. If you do not want to cache compiled output, remove
# the `output` path.
with:
key: ${{ runner.os }}-spago-${{ hashFiles('**/*.dhall') }}
path: |
.spago
output

- run: spago -x test.dhall build

- run: spago -x test.dhall test
64 changes: 32 additions & 32 deletions src/JS/BigInt.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,43 @@ export const fromStringImpl = (just) => (nothing) => (s) => {
}
};

// Pretty much copy/paste from https://stackoverflow.com/questions/55646698/base-36-to-bigint
export const fromStringAsImpl = function (just) {
return function (nothing) {
return function (radix) {
return function (_value) {

// Preprocess for potentially negative numbers. Since the toString
// function simply prepends a '-' character for negative numbers,
// we need this to make fromStringAs an inverse function.
var value, op;
if (_value[0] === "-") {
op = function (v) {return BigInt(-1) * v};
value = _value.slice(1);
} else {
op = function (v) {return v};
value = _value;
}

var digits;
if (radix < 11) {
digits = "[0-" + (radix - 1).toString() + "]";
} else if (radix === 11) {
digits = "[0-9a]";
} else {
digits = "[0-9a-" + String.fromCharCode(86 + radix) + "]";
}
var pattern = new RegExp("^[\\+\\-]?" + digits + "+$", "i");

return function (s) {
// Not yet in the standard: https://github.com/tc39/proposal-number-fromstring
// Code converted from https://stackoverflow.com/a/55646905/1833322

/* jshint bitwise: false */
if (pattern.test(s)) {
var size = 10;
var factor = BigInt(radix ** size);
var r = 0n

for (var i = 0; i < s.length; i += size) {
var n = parseInt(s.slice(i, i + size), radix);

// check for NaN
if ((n | 0) !== n) {
return nothing;
}

r = r * factor + BigInt(n);
}
var size = 10,
factor = BigInt(radix ** size),
i = value.length % size || size,
parts = [value.slice(0, i)];

return just(r);
} else {
while (i < value.length) parts.push(value.slice(i, i += size));

function f(acc, chunk) {
let n = BigInt(parseInt(chunk, radix));
if (n === NaN) {
throw new Error("Invalid number");
} else {
return acc * factor + n;
}
};

try {
return just(op(parts.reduce(f, 0n)));
} catch (err) {
return nothing;
}
};
Expand Down
1 change: 1 addition & 0 deletions test.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ in conf
, "effect"
, "quickcheck"
, "assert"
, "newtype"
, "quickcheck-laws"
, "arrays"
, "console"
Expand Down
14 changes: 11 additions & 3 deletions test/Main.purs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
module Test.Main where

import Prelude
import Prelude hiding (not)

import Data.Array (foldMap)
import Data.Array.NonEmpty (cons')
import Data.Foldable (fold)
import Data.Int (base36)
import Data.Maybe (Maybe(..), fromMaybe)
import Data.Monoid.Conj (Conj(..))
import Data.Newtype (un)
import Debug (spy)
import Effect (Effect)
import Effect.Console (log)
import JS.BigInt (BigInt, and, fromInt, fromString, fromTLInt, not, or, pow, shl, shr, toString, xor, even, odd, parity, toInt, toStringAs, binary, octal)
import Prelude (class CommutativeRing, class Eq, class EuclideanRing, class Ord, class Ring, class Semiring, Unit, bind, compare, discard, identity, map, mod, negate, one, pure, show, zero, ($), (*), (+), (-), (/), (<$>), (<<<), (==))
import JS.BigInt (BigInt, and, binary, decimal, even, fromInt, fromString, fromStringAs, fromTLInt, hexadecimal, not, octal, odd, or, pow, shl, shr, toInt, toString, toStringAs, xor)
import Test.Assert (assert)
import Test.QuickCheck (quickCheck)
import Test.QuickCheck.Arbitrary (class Arbitrary)
Expand Down Expand Up @@ -76,6 +80,10 @@ main = do
assert $ fromString "123456789" == Just (fromInt 123456789)
assert $ fromString "10000000" == Just (fromInt 10000000)
quickCheck $ \(TestBigInt a) -> (fromString <<< toString) a == Just a
quickCheck $ \(TestBigInt a) ->
let radixes = [binary, octal, decimal, hexadecimal, base36]
in un Conj $ flip foldMap radixes $ \r ->
Conj $ (fromStringAs r $ toStringAs r a) == Just a

log "Parsing strings with a different base"
assert $ fromString "0b100" == Just four
Expand Down