Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add js BigInts #16409

Merged
merged 84 commits into from
Jan 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
45800ea
Add BigInts
juancarlospaco Dec 20, 2020
091109a
Merge branch 'devel' of https://github.com/nim-lang/Nim into bigy
juancarlospaco Dec 21, 2020
1fd6edc
Renames tos plurals
juancarlospaco Dec 21, 2020
2492d72
Bear review
juancarlospaco Dec 21, 2020
ceeecbe
Bear review
juancarlospaco Dec 21, 2020
bdc6386
Pear review
juancarlospaco Dec 21, 2020
71a6db5
Peer review
juancarlospaco Dec 22, 2020
230f375
Peer review
juancarlospaco Dec 22, 2020
472546c
Improve Stringifications
juancarlospaco Dec 22, 2020
a1d71a9
Improve Stringifications
juancarlospaco Dec 22, 2020
464f626
Update changelog.md
juancarlospaco Dec 22, 2020
7a8b9f0
RunnableExamplerize
juancarlospaco Dec 22, 2020
516d537
Merge branch 'bigy' of https://github.com/juancarlospaco/Nim into bigy
juancarlospaco Dec 22, 2020
464c0b1
discard the discardable pragma
juancarlospaco Dec 22, 2020
7309b55
Several improvements from peer reviews, more docs
juancarlospaco Dec 22, 2020
c4ddb1f
More doc, more test
juancarlospaco Dec 22, 2020
bd81660
More doc, more test
juancarlospaco Dec 22, 2020
cbed450
More doc, more test
juancarlospaco Dec 22, 2020
816d0fe
More doc, more test
juancarlospaco Dec 22, 2020
38abc40
Better error message 'Error: usage of low is an {.error.} defined at …
juancarlospaco Dec 22, 2020
d546f0f
is an overload, rename
juancarlospaco Dec 22, 2020
cc70f55
proc to scare kids away
juancarlospaco Dec 22, 2020
2759950
moar test moar
juancarlospaco Dec 22, 2020
0fa9599
This useful proc
juancarlospaco Dec 22, 2020
9719ffa
Minor changes
juancarlospaco Dec 22, 2020
79e23c8
Minor changes
juancarlospaco Dec 22, 2020
985d5ce
Update lib/js/jsbigints.nim
juancarlospaco Dec 22, 2020
c0cc419
Get int from BigInt
juancarlospaco Dec 22, 2020
aa0d39a
Update lib/js/jsbigints.nim
juancarlospaco Dec 22, 2020
9292d29
Merge branch 'devel' of https://github.com/nim-lang/Nim into bigy
juancarlospaco Dec 27, 2020
3aad4f0
Bigint moves house
juancarlospaco Dec 27, 2020
75c0b51
Merge branch 'bigy' of https://github.com/juancarlospaco/Nim into bigy
juancarlospaco Dec 27, 2020
efb2dc5
koch bigint
juancarlospaco Dec 27, 2020
5240526
move test
juancarlospaco Dec 28, 2020
7a940aa
fixes
juancarlospaco Dec 28, 2020
36b927d
fixes
juancarlospaco Dec 28, 2020
e450d19
is dangerous
juancarlospaco Dec 28, 2020
e71f420
Merge branch 'devel' of https://github.com/nim-lang/Nim into bigy
juancarlospaco Jan 4, 2021
cc25689
No better naming found, then newJsBigInt is used, later we can add a …
juancarlospaco Jan 4, 2021
3316879
clean out
juancarlospaco Jan 4, 2021
4fa4a35
clean out
juancarlospaco Jan 4, 2021
f56981f
Update lib/std/jsbigints.nim
juancarlospaco Jan 4, 2021
0334d89
Update lib/std/jsbigints.nim
juancarlospaco Jan 4, 2021
00c0d6c
Addres some comments
juancarlospaco Jan 4, 2021
8958fe8
ReSyncin
juancarlospaco Jan 4, 2021
6d8eba2
https://github.com/nim-lang/Nim/pull/16409#discussion_r551180020
juancarlospaco Jan 4, 2021
181f037
https://github.com/nim-lang/Nim/pull/16409#discussion_r551180898
juancarlospaco Jan 4, 2021
ee8853a
Try to make error messages a little more usable
juancarlospaco Jan 4, 2021
ee9c1a3
Merge branch 'devel' of https://github.com/nim-lang/Nim into bigy
juancarlospaco Jan 5, 2021
9c31275
Flip args reversed
juancarlospaco Jan 5, 2021
6668104
Fix inc/dec problem
juancarlospaco Jan 5, 2021
ed6ceda
simple
juancarlospaco Jan 5, 2021
cbb76a1
simple
juancarlospaco Jan 5, 2021
390a5ae
simple
juancarlospaco Jan 5, 2021
03d61c6
Update lib/std/jsbigints.nim
juancarlospaco Jan 6, 2021
05f3fcb
Use BiggestInt
juancarlospaco Jan 7, 2021
c14daf7
Merge branch 'devel' of https://github.com/nim-lang/Nim into bigy
juancarlospaco Jan 7, 2021
a88eac0
Use BiggestInt
juancarlospaco Jan 7, 2021
42e77b6
Use BiggestInt
juancarlospaco Jan 7, 2021
39e6572
Merge branch 'bigy' of https://github.com/juancarlospaco/Nim into bigy
juancarlospaco Jan 7, 2021
60f54bf
https://github.com/nim-lang/Nim/pull/16606
juancarlospaco Jan 7, 2021
7ae47f6
Merge branch 'devel' of https://github.com/nim-lang/Nim into bigy
juancarlospaco Jan 7, 2021
a6f65f8
https://github.com/nim-lang/Nim/pull/16606
juancarlospaco Jan 7, 2021
a88c401
Merge branch 'devel' of https://github.com/nim-lang/Nim into bigy
juancarlospaco Jan 7, 2021
c16c8df
Green test
juancarlospaco Jan 7, 2021
afff5b0
Merge branch 'devel' of https://github.com/nim-lang/Nim into bigy
juancarlospaco Jan 7, 2021
6a53e03
Green test
juancarlospaco Jan 7, 2021
82efc22
Merge branch 'devel' of https://github.com/nim-lang/Nim into bigy
juancarlospaco Jan 8, 2021
d78f6ce
ReSync
juancarlospaco Jan 8, 2021
a7a9dcf
Fix CI
juancarlospaco Jan 8, 2021
23b7560
ReSync
juancarlospaco Jan 8, 2021
f71ceb3
Update lib/std/jsbigints.nim
juancarlospaco Jan 8, 2021
89e81c7
Merge branch 'devel' of https://github.com/nim-lang/Nim into bigy
juancarlospaco Jan 8, 2021
bf7da66
Merge branch 'bigy' of https://github.com/juancarlospaco/Nim into bigy
juancarlospaco Jan 8, 2021
d727b79
String representation is now like 999n
juancarlospaco Jan 9, 2021
a26ca38
Going big. Is not perfect but it works.
juancarlospaco Jan 9, 2021
af01469
Going big. Is not perfect but it works.
juancarlospaco Jan 9, 2021
f045b7b
Update lib/std/jsbigints.nim
juancarlospaco Jan 9, 2021
37d6c66
Update lib/std/jsbigints.nim
juancarlospaco Jan 9, 2021
3ed3672
Update lib/std/jsbigints.nim
juancarlospaco Jan 9, 2021
b879961
Update lib/std/jsbigints.nim
juancarlospaco Jan 9, 2021
b849823
Update lib/std/jsbigints.nim
juancarlospaco Jan 9, 2021
24af3e0
Merge branch 'devel' of https://github.com/nim-lang/Nim into bigy
juancarlospaco Jan 9, 2021
9503383
https://github.com/nim-lang/Nim/pull/16409#discussion_r554365041
juancarlospaco Jan 9, 2021
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
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
- `echo` and `debugEcho` will now raise `IOError` if writing to stdout fails. Previous behavior
silently ignored errors. See #16366. Use `-d:nimLegacyEchoNoRaise` for previous behavior.

- Added `jsbigints` module, arbitrary precision integers for JavaScript target.

- Added `math.copySign`.
- Added new operations for singly- and doubly linked lists: `lists.toSinglyLinkedList`
and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements
Expand Down
193 changes: 193 additions & 0 deletions lib/std/jsbigints.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
## Arbitrary precision integers.
## * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
when not defined(js):
{.fatal: "Module jsbigints is designed to be used with the JavaScript backend.".}

type JsBigIntImpl {.importc: "bigint".} = int # https://github.com/nim-lang/Nim/pull/16606
type JsBigInt* = distinct JsBigIntImpl ## Arbitrary precision integer for JavaScript target.

func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".} =
juancarlospaco marked this conversation as resolved.
Show resolved Hide resolved
## Constructor for `JsBigInt`.
runnableExamples:
doAssert big(1234567890) == big"1234567890"

func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".} =
## Constructor for `JsBigInt`.
runnableExamples:
doAssert big"-1" == big"1" - big"2"

func toCstring*(this: JsBigInt; radix: 2..36): cstring {.importjs: "#.toString(#)".} =
## Converts from `JsBigInt` to `cstring` representation.
## * `radix` Base to use for representing numeric values.
## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toString
runnableExamples:
doAssert big"2147483647".toCstring(2) == "1111111111111111111111111111111".cstring

func toCstring*(this: JsBigInt): cstring {.importjs: "#.toString()".}
## Converts from `JsBigInt` to `cstring` representation.
## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toString

func `$`*(this: JsBigInt): string =
## Returns a `string` representation of `JsBigInt`.
runnableExamples: doAssert $big"1024" == "1024n"
$toCstring(this) & 'n'

func wrapToInt*(this: JsBigInt; bits: Natural): JsBigInt {.importjs:
"(() => { const i = #, b = #; return BigInt.asIntN(b, i) })()".} =
## Wraps `this` to a signed `JsBigInt` of `bits` bits in `-2 ^ (bits - 1)` .. `2 ^ (bits - 1) - 1`.
## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/asIntN
runnableExamples:
doAssert (big("3") + big("2") ** big("66")).wrapToInt(13) == big("3")

func wrapToUint*(this: JsBigInt; bits: Natural): JsBigInt {.importjs:
"(() => { const i = #, b = #; return BigInt.asUintN(b, i) })()".} =
## Wraps `this` to an unsigned `JsBigInt` of `bits` bits in 0 .. `2 ^ bits - 1`.
## https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/asUintN
runnableExamples:
doAssert (big("3") + big("2") ** big("66")).wrapToUint(66) == big("3")

func toNumber*(this: JsBigInt): BiggestInt {.importjs: "Number(#)".} =
## Does not do any bounds check and may or may not return an inexact representation.
runnableExamples:
doAssert toNumber(big"2147483647") == 2147483647.BiggestInt

func `+`*(x, y: JsBigInt): JsBigInt {.importjs: "(# $1 #)".} =
runnableExamples:
doAssert (big"9" + big"1") == big"10"

func `-`*(x, y: JsBigInt): JsBigInt {.importjs: "(# $1 #)".} =
runnableExamples:
doAssert (big"9" - big"1") == big"8"

func `*`*(x, y: JsBigInt): JsBigInt {.importjs: "(# $1 #)".} =
runnableExamples:
doAssert (big"42" * big"9") == big"378"

func `div`*(x, y: JsBigInt): JsBigInt {.importjs: "(# / #)".} =
## Same as `div` but for `JsBigInt`(uses JavaScript `BigInt() / BigInt()`).
runnableExamples:
doAssert big"13" div big"3" == big"4"
doAssert big"-13" div big"3" == big"-4"
doAssert big"13" div big"-3" == big"-4"
doAssert big"-13" div big"-3" == big"4"

func `mod`*(x, y: JsBigInt): JsBigInt {.importjs: "(# % #)".} =
## Same as `mod` but for `JsBigInt` (uses JavaScript `BigInt() % BigInt()`).
runnableExamples:
doAssert big"13" mod big"3" == big"1"
doAssert big"-13" mod big"3" == big"-1"
doAssert big"13" mod big"-3" == big"1"
doAssert big"-13" mod big"-3" == big"-1"

func `<`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".} =
runnableExamples:
doAssert big"2" < big"9"

func `<=`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".} =
runnableExamples:
doAssert big"1" <= big"5"

func `==`*(x, y: JsBigInt): bool {.importjs: "(# == #)".} =
runnableExamples:
doAssert big"42" == big"42"

func `**`*(x, y: JsBigInt): JsBigInt {.importjs: "((#) $1 #)".} =
runnableExamples:
doAssert (big"9" ** big"5") == big"59049"

func `xor`*(x, y: JsBigInt): JsBigInt {.importjs: "(# ^ #)".} =
runnableExamples:
doAssert (big"555" xor big"2") == big"553"

func `shl`*(a, b: JsBigInt): JsBigInt {.importjs: "(# << #)".} =
runnableExamples:
doAssert (big"999" shl big"2") == big"3996"

func `shr`*(a, b: JsBigInt): JsBigInt {.importjs: "(# >> #)".} =
runnableExamples:
doAssert (big"999" shr big"2") == big"249"

func `-`*(this: JsBigInt): JsBigInt {.importjs: "($1#)".} =
runnableExamples:
doAssert -(big"10101010101") == big"-10101010101"

func inc*(this: var JsBigInt) {.importjs: "(++[#][0][0])".} =
runnableExamples:
var big1: JsBigInt = big"1"
inc big1
doAssert big1 == big"2"

func dec*(this: var JsBigInt) {.importjs: "(--[#][0][0])".} =
runnableExamples:
var big1: JsBigInt = big"2"
dec big1
doAssert big1 == big"1"

func inc*(this: var JsBigInt; amount: JsBigInt) {.importjs: "([#][0][0] += #)".} =
runnableExamples:
var big1: JsBigInt = big"1"
inc big1, big"2"
doAssert big1 == big"3"

func dec*(this: var JsBigInt; amount: JsBigInt) {.importjs: "([#][0][0] -= #)".} =
runnableExamples:
var big1: JsBigInt = big"1"
dec big1, big"2"
doAssert big1 == big"-1"

func `+=`*(x: var JsBigInt; y: JsBigInt) {.importjs: "([#][0][0] $1 #)".} =
runnableExamples:
var big1: JsBigInt = big"1"
big1 += big"2"
doAssert big1 == big"3"

func `-=`*(x: var JsBigInt; y: JsBigInt) {.importjs: "([#][0][0] $1 #)".} =
runnableExamples:
var big1: JsBigInt = big"1"
big1 -= big"2"
doAssert big1 == big"-1"

func `*=`*(x: var JsBigInt; y: JsBigInt) {.importjs: "([#][0][0] $1 #)".} =
runnableExamples:
var big1: JsBigInt = big"2"
big1 *= big"4"
doAssert big1 == big"8"

func `/=`*(x: var JsBigInt; y: JsBigInt) {.importjs: "([#][0][0] $1 #)".} =
## Same as `x = x div y`.
runnableExamples:
var big1: JsBigInt = big"11"
big1 /= big"2"
doAssert big1 == big"5"

proc `+`*(_: JsBigInt): JsBigInt {.error:
"See https://github.com/tc39/proposal-bigint/blob/master/ADVANCED.md#dont-break-asmjs".} # Can not be used by design
## **Do NOT use.** https://github.com/tc39/proposal-bigint/blob/master/ADVANCED.md#dont-break-asmjs

proc low*(_: typedesc[JsBigInt]): JsBigInt {.error:
"Arbitrary precision integers do not have a known low.".} ## **Do NOT use.**

proc high*(_: typedesc[JsBigInt]): JsBigInt {.error:
"Arbitrary precision integers do not have a known high.".} ## **Do NOT use.**


runnableExamples:
juancarlospaco marked this conversation as resolved.
Show resolved Hide resolved
let big1: JsBigInt = big"2147483647"
let big2: JsBigInt = big"666"
doAssert JsBigInt isnot int
doAssert big1 != big2
doAssert big1 > big2
doAssert big1 >= big2
doAssert big2 < big1
doAssert big2 <= big1
doAssert not(big1 == big2)
let z = JsBigInt.default
doAssert $z == "0n"
block:
var a: seq[JsBigInt]
a.setLen 2
doAssert a == @[big"0", big"0"]
doAssert a[^1] == big"0"
var b: JsBigInt
doAssert b == big"0"
doAssert b == JsBigInt.default
38 changes: 38 additions & 0 deletions tests/stdlib/tjsbigints.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
discard """
targets: "js"
"""

import std/jsbigints


let big1: JsBigInt = big"2147483647"
let big2: JsBigInt = big"666"
var big3: JsBigInt = big"2"

doAssert big3 == big"2"
doAssert (big3 xor big2) == big"664"
doAssert (big1 mod big2) == big"613"
doAssert -big1 == big"-2147483647"
doAssert big1 div big2 == big"3224449"
doAssert big1 + big2 == big"2147484313"
doAssert big1 - big2 == big"2147482981"
doAssert big1 shl big3 == big"8589934588"
doAssert big1 shr big3 == big"536870911"
doAssert big1 * big2 == big"1430224108902"
doAssert $big1 == "2147483647n"
doAssert big1.toCstring(10) == "2147483647".cstring
doAssert big2 ** big3 == big(443556)
var huge = big"999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
huge.inc
huge = huge + big"-999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
doAssert huge == big"1"
var list: seq[JsBigInt]
for i in big"0" .. big"5":
doAssert i is JsBigInt
list.add i
doAssert list == @[big"0", big"1", big"2", big"3", big"4", big"5"]
list = @[]
for i in big"0" ..< big"5":
doAssert i is JsBigInt
list.add i
doAssert list == @[big"0", big"1", big"2", big"3", big"4"]
5 changes: 4 additions & 1 deletion tools/kochdocs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ const
webUploadOutput = "web/upload"

var nimExe*: string
const allowList = ["jsbigints.nim"]

template isJsOnly(file: string): bool = file.isRelativeTo("lib/js")
template isJsOnly(file: string): bool =
file.isRelativeTo("lib/js") or
file.extractFilename in allowList

proc exe*(f: string): string =
result = addFileExt(f, ExeExt)
Expand Down