History

2020-01-19 release

bellard committed 6 years ago

Commit 0e8fffd1 parent 91459fb26 files · +4264 −3605Browse files

Unified · Split

26 files
  1. Changelog +12 −0
  2. Makefile +28 −6
  3. TODO +2 −3
  4. VERSION +1 −1
  5. doc/jsbignum.html +223 −531
  6. doc/jsbignum.pdf +0 −0
  7. doc/jsbignum.texi +179 −422
  8. doc/quickjs.html +12 −3
  9. doc/quickjs.pdf +0 −0
  10. doc/quickjs.texi +8 −1
  11. examples/pi_bigdecimal.js +8 −10
  12. libbf.c +677 −439
  13. libbf.h +77 −42
  14. qjs.c +22 −4
  15. qjsc.c +16 −8
  16. qjscalc.js +817 −618
  17. quickjs-atom.h +4 −22
  18. quickjs-libc.c +15 −0
  19. quickjs-opcode.h +0 −3
  20. quickjs.c +1788 −1418
  21. quickjs.h +11 −5
  22. repl.js +6 −28
  23. test262_errors.txt +13 −0
  24. tests/test_bignum.js +125 −40
  25. tests/test_op_overloading.js +207 −0
  26. tests/test_qjscalc.js +15 −3
Changelog+12−0
@@ -1,3 +1,15 @@
1+2020-01-19:
2+
3+- keep CONFIG_BIGNUM in the makefile
4+- added os.chdir()
5+- qjs: added -I option
6+- more memory checks in the bignum operations
7+- modified operator overloading semantics to be closer to the TC39
8+ proposal
9+- suppressed "use bigint" mode. Simplified "use math" mode
10+- BigDecimal: changed suffix from 'd' to 'm'
11+- misc bug fixes
12+
113 2020-01-05:
214
315 - always compile the bignum code. Added '--bignum' option to qjs.
Makefile+28−6
@@ -1,8 +1,8 @@
11 #
22 # QuickJS Javascript Engine
33 #
4−# Copyright (c) 2017-2019 Fabrice Bellard
5−# Copyright (c) 2017-2019 Charlie Gordon
4+# Copyright (c) 2017-2020 Fabrice Bellard
5+# Copyright (c) 2017-2020 Charlie Gordon
66 #
77 # Permission is hereby granted, free of charge, to any person obtaining a copy
88 # of this software and associated documentation files (the "Software"), to deal
@@ -47,6 +47,8 @@ prefix=/usr/local · 38 unmodified lines
4747 #CONFIG_PROFILE=y
4848 # use address sanitizer
4949 #CONFIG_ASAN=y
50+# include the code for BigInt/BigFloat/BigDecimal and math mode
51+CONFIG_BIGNUM=y
5052
5153 OBJDIR=.obj
5254
@@ -94,6 +96,9 @@ ifdef CONFIG_WERROR · 41 unmodified lines
9496 CFLAGS+=-Werror
9597 endif
9698 DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
99+ifdef CONFIG_BIGNUM
100+DEFINES+=-DCONFIG_BIGNUM
101+endif
97102 CFLAGS+=$(DEFINES)
98103 CFLAGS_DEBUG=$(CFLAGS) -O0
99104 CFLAGS_SMALL=$(CFLAGS) -Os
@@ -153,9 +158,13 @@ endif · 53 unmodified lines
153158
154159 all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS)
155160
156−QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/libbf.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o
161+QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o
157162
158−QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(OBJDIR)/qjscalc.o $(QJS_LIB_OBJS)
163+QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS)
164+ifdef CONFIG_BIGNUM
165+QJS_LIB_OBJS+=$(OBJDIR)/libbf.o
166+QJS_OBJS+=$(OBJDIR)/qjscalc.o
167+endif
159168
160169 LIBS=-lm
161170 ifndef CONFIG_WIN32
@@ -215,7 +224,7 @@ libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS)) · 53 unmodified lines
215224 $(AR) rcs $@ $^
216225 endif # CONFIG_LTO
217226
218−repl.c: $(QJSC) repl.js
227+repl.c: $(QJSC) repl.js
219228 $(QJSC) -c -o $@ -m repl.js
220229
221230 qjscalc.c: $(QJSC) qjscalc.js
@@ -301,7 +310,10 @@ endif · 79 unmodified lines
301310 HELLO_SRCS=examples/hello.js
302311 HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \
303312 -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
304− -fno-date -fno-module-loader -fno-bigint
313+ -fno-date -fno-module-loader
314+ifdef CONFIG_BIGNUM
315+HELLO_OPTS+=-fno-bigint
316+endif
305317
306318 hello.c: $(QJSC) $(HELLO_SRCS)
307319 $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS)
@@ -372,20 +384,30 @@ test: qjs · 64 unmodified lines
372384 ./qjs tests/test_loop.js
373385 ./qjs tests/test_std.js
374386 ifndef CONFIG_DARWIN
387+ifdef CONFIG_BIGNUM
375388 ./qjs --bignum tests/test_bjson.js
389+else
390+ ./qjs tests/test_bjson.js
391+endif
376392 ./qjs examples/test_point.js
377393 endif
394+ifdef CONFIG_BIGNUM
395+ ./qjs --bignum tests/test_op_overloading.js
378396 ./qjs --bignum tests/test_bignum.js
379397 ./qjs --qjscalc tests/test_qjscalc.js
398+endif
380399 ifdef CONFIG_M32
381400 ./qjs32 tests/test_closure.js
382401 ./qjs32 tests/test_op.js
383402 ./qjs32 tests/test_builtin.js
384403 ./qjs32 tests/test_loop.js
385404 ./qjs32 tests/test_std.js
405+ifdef CONFIG_BIGNUM
406+ ./qjs32 --bignum tests/test_op_overloading.js
386407 ./qjs32 --bignum tests/test_bignum.js
387408 ./qjs32 --qjscalc tests/test_qjscalc.js
388409 endif
410+endif
389411
390412 stats: qjs qjs32
391413 ./qjs -qd
TODO+2−3
@@ -73,6 +73,5 @@ REPL: · 72 unmodified lines
7373 Test262o: 0/11262 errors, 463 excluded
7474 Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
7575
76−Test262: 4/67619 errors, 913 excluded, 1660 skipped
77−Test262bn: 4/69722 errors, 846 excluded, 672 skipped
78−test262 commit: 19fd4bea797646ae9bbfc9d325f14052ca370b54
76+Test262: 17/69942 errors, 855 excluded, 581 skipped
77+test262 commit: 28b4fcca4b1b1d278dfe0cc0e69c7d9d59b31aab
VERSION+1−1
@@ -1 +1 @@
1−2020-01-05
1+2020-01-19
doc/jsbignum.html+223−531
@@ -1,7 +1,8 @@
11 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
22 <html>
3−<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
3+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
44 <head>
5+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
56 <title>Javascript Bignum Extensions</title>
67
78 <meta name="description" content="Javascript Bignum Extensions">
@@ -9,7 +10,6 @@ · 1 unmodified line
910 <meta name="resource-type" content="document">
1011 <meta name="distribution" content="global">
1112 <meta name="Generator" content="makeinfo">
12−<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
1313 <link href="#SEC_Contents" rel="contents" title="Table of Contents">
1414 <style type="text/css">
1515 <!--
@@ -52,61 +52,33 @@ ul.no-bullet {list-style: none} · 36 unmodified lines
5252 <div class="contents">
5353 <ul class="no-bullet">
5454 <li><a name="toc-Introduction" href="#Introduction">1 Introduction</a></li>
55−<li><a name="toc-Operator-overloading" href="#Operator-overloading">2 Operator overloading</a>
55+<li><a name="toc-Operator-overloading" href="#Operator-overloading">2 Operator overloading</a></li>
56+<li><a name="toc-BigInt-extensions" href="#BigInt-extensions">3 BigInt extensions</a></li>
57+<li><a name="toc-BigFloat" href="#BigFloat">4 BigFloat</a>
5658 <ul class="no-bullet">
57− <li><a name="toc-Introduction-1" href="#Introduction-1">2.1 Introduction</a></li>
58− <li><a name="toc-Builtin-Object-changes" href="#Builtin-Object-changes">2.2 Builtin Object changes</a>
59− <ul class="no-bullet">
60− <li><a name="toc-Symbol-constructor" href="#Symbol-constructor">2.2.1 <code>Symbol</code> constructor</a></li>
61− </ul></li>
62−</ul></li>
63−<li><a name="toc-The-BigInt-Mode" href="#The-BigInt-Mode">3 The BigInt Mode</a>
64−<ul class="no-bullet">
65− <li><a name="toc-Introduction-2" href="#Introduction-2">3.1 Introduction</a></li>
66− <li><a name="toc-Changes-that-introduce-incompatibilities-with-Javascript" href="#Changes-that-introduce-incompatibilities-with-Javascript">3.2 Changes that introduce incompatibilities with Javascript</a>
67− <ul class="no-bullet">
68− <li><a name="toc-Standard-mode" href="#Standard-mode">3.2.1 Standard mode</a></li>
69− <li><a name="toc-Bigint-mode" href="#Bigint-mode">3.2.2 Bigint mode</a></li>
70− </ul></li>
71− <li><a name="toc-Operators" href="#Operators">3.3 Operators</a>
72− <ul class="no-bullet">
73− <li><a name="toc-Arithmetic-operators" href="#Arithmetic-operators">3.3.1 Arithmetic operators</a></li>
74− <li><a name="toc-Logical-operators" href="#Logical-operators">3.3.2 Logical operators</a></li>
75− <li><a name="toc-Relational-operators" href="#Relational-operators">3.3.3 Relational operators</a></li>
76− </ul></li>
77− <li><a name="toc-Number-literals" href="#Number-literals">3.4 Number literals</a></li>
78− <li><a name="toc-Builtin-Object-changes-1" href="#Builtin-Object-changes-1">3.5 Builtin Object changes</a>
79− <ul class="no-bullet">
80− <li><a name="toc-BigInt-function" href="#BigInt-function">3.5.1 <code>BigInt</code> function</a></li>
81− <li><a name="toc-BigInt_002eprototype" href="#BigInt_002eprototype">3.5.2 <code>BigInt.prototype</code></a></li>
82− <li><a name="toc-Number-constructor" href="#Number-constructor">3.5.3 <code>Number</code> constructor</a></li>
83− <li><a name="toc-Number_002eprototype" href="#Number_002eprototype">3.5.4 <code>Number.prototype</code></a></li>
84− <li><a name="toc-Math-object" href="#Math-object">3.5.5 <code>Math</code> object</a></li>
85− </ul></li>
86−</ul></li>
87−<li><a name="toc-Arbitrarily-large-floating-point-numbers" href="#Arbitrarily-large-floating-point-numbers">4 Arbitrarily large floating point numbers</a>
88−<ul class="no-bullet">
89− <li><a name="toc-Introduction-3" href="#Introduction-3">4.1 Introduction</a></li>
59+ <li><a name="toc-Introduction-1" href="#Introduction-1">4.1 Introduction</a></li>
9060 <li><a name="toc-Floating-point-rounding" href="#Floating-point-rounding">4.2 Floating point rounding</a></li>
91− <li><a name="toc-Operators-1" href="#Operators-1">4.3 Operators</a></li>
61+ <li><a name="toc-Operators" href="#Operators">4.3 Operators</a></li>
9262 <li><a name="toc-BigFloat-literals" href="#BigFloat-literals">4.4 BigFloat literals</a></li>
93− <li><a name="toc-Builtin-Object-changes-2" href="#Builtin-Object-changes-2">4.5 Builtin Object changes</a>
63+ <li><a name="toc-Builtin-Object-changes" href="#Builtin-Object-changes">4.5 Builtin Object changes</a>
9464 <ul class="no-bullet">
9565 <li><a name="toc-BigFloat-function" href="#BigFloat-function">4.5.1 <code>BigFloat</code> function</a></li>
9666 <li><a name="toc-BigFloat_002eprototype" href="#BigFloat_002eprototype">4.5.2 <code>BigFloat.prototype</code></a></li>
9767 <li><a name="toc-BigFloatEnv-constructor" href="#BigFloatEnv-constructor">4.5.3 <code>BigFloatEnv</code> constructor</a></li>
98− <li><a name="toc-Math-object-1" href="#Math-object-1">4.5.4 <code>Math</code> object</a></li>
9968 </ul></li>
10069 </ul></li>
101−<li><a name="toc-Math-mode" href="#Math-mode">5 Math mode</a>
70+<li><a name="toc-BigDecimal" href="#BigDecimal">5 BigDecimal</a>
10271 <ul class="no-bullet">
103− <li><a name="toc-Introduction-4" href="#Introduction-4">5.1 Introduction</a></li>
104− <li><a name="toc-Builtin-Object-changes-3" href="#Builtin-Object-changes-3">5.2 Builtin Object changes</a>
72+ <li><a name="toc-Operators-1" href="#Operators-1">5.1 Operators</a></li>
73+ <li><a name="toc-BigDecimal-literals" href="#BigDecimal-literals">5.2 BigDecimal literals</a></li>
74+ <li><a name="toc-Builtin-Object-changes-1" href="#Builtin-Object-changes-1">5.3 Builtin Object changes</a>
10575 <ul class="no-bullet">
106− <li><a name="toc-Symbol-constructor-1" href="#Symbol-constructor-1">5.2.1 <code>Symbol</code> constructor</a></li>
76+ <li><a name="toc-The-BigDecimal-function_002e" href="#The-BigDecimal-function_002e">5.3.1 The <code>BigDecimal</code> function.</a></li>
77+ <li><a name="toc-Properties-of-the-BigDecimal-object" href="#Properties-of-the-BigDecimal-object">5.3.2 Properties of the <code>BigDecimal</code> object</a></li>
78+ <li><a name="toc-Properties-of-the-BigDecimal_002eprototype-object" href="#Properties-of-the-BigDecimal_002eprototype-object">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</a></li>
10779 </ul></li>
108− <li><a name="toc-Remaining-issues" href="#Remaining-issues">5.3 Remaining issues</a></li>
10980 </ul></li>
81+<li><a name="toc-Math-mode" href="#Math-mode">6 Math mode</a></li>
11082
11183 </ul>
11284 </div>
@@ -119,379 +91,52 @@ ul.no-bullet {list-style: none} · 6 unmodified lines
11991 language while being 100% backward compatible:
12092 </p>
12193 <ul>
122−<li> Overloading of the standard operators
123−to support new types such as complex numbers, fractions or matrices.
124−
125−</li><li> Bigint mode where arbitrarily large integers are available by default (no <code>n</code> suffix is necessary as in the TC39 BigInt proposal<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>).
94+<li> Operator overloading with a dispatch logic inspired from the proposal available at <a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>.
12695
12796 </li><li> Arbitrarily large floating point numbers (<code>BigFloat</code>) in base 2 using the IEEE 754 semantics.
12897
129−</li><li> Optional <code>math</code> mode which modifies the semantics of the division, modulo and power operator. The division and power operator return a fraction with integer operands and the modulo operator is defined as the Euclidian remainder.
98+</li><li> Arbitrarily large floating point numbers (<code>BigDecimal</code>) in base 10 based on the proposal available at
99+<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
100+
101+</li><li> <code>math</code> mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (<code>%</code>) is defined as the Euclidian
102+remainder. <code>^</code> is an alias to the power operator
103+(<code>**</code>). <code>^^</code> is used as the exclusive or operator.
130104
131105 </li></ul>
132106
133107 <p>The extensions are independent from each other except the <code>math</code>
134−mode which relies on the bigint mode and the operator overloading.
108+mode which relies on BigFloat and operator overloading.
135109 </p>
136110 <a name="Operator-overloading"></a>
137111 <h2 class="chapter">2 Operator overloading</h2>
138112
139−<a name="Introduction-1"></a>
140−<h3 class="section">2.1 Introduction</h3>
141−
142−<p>If the operands of an operator have at least one object type, a custom
143−operator method is searched before doing the legacy Javascript
144−<code>ToNumber</code> conversion.
145−</p>
146−<p>For unary operators, the custom function is looked up in the object
147−and has the following name:
148−</p>
149−<dl compact="compact">
150−<dt><code>unary +</code></dt>
151−<dd><p><code>Symbol.operatorPlus</code>
152−</p>
153−</dd>
154−<dt><code>unary -</code></dt>
155−<dd><p><code>Symbol.operatorNeg</code>
156−</p>
157−</dd>
158−<dt><code>++</code></dt>
159−<dd><p><code>Symbol.operatorInc</code>
160−</p>
161−</dd>
162−<dt><code>--</code></dt>
163−<dd><p><code>Symbol.operatorDec</code>
164−</p>
165−</dd>
166−<dt><code>~</code></dt>
167−<dd><p><code>Symbol.operatorNot</code>
168−</p>
169−</dd>
170−</dl>
171−
172−<p>For binary operators:
173−</p>
174−<ul>
175−<li> If both operands have the same constructor function, then the operator
176−is looked up in the constructor.
177−
178−</li><li> Otherwise, the property <code>Symbol.operatorOrder</code> is looked up in both
179−constructors and converted to <code>Int32</code>. The operator is then
180−looked in the constructor with the larger <code>Symbol.operatorOrder</code>
181−value. A <code>TypeError</code> is raised if both constructors have the same
182−<code>Symbol.operatorOrder</code> value.
183−
184−</li></ul>
185−
186−<p>The operator is looked up with the following name:
187−</p>
188−<dl compact="compact">
189−<dt><code>+</code></dt>
190−<dd><p><code>Symbol.operatorAdd</code>
191−</p>
192−</dd>
193−<dt><code>-</code></dt>
194−<dd><p><code>Symbol.operatorSub</code>
195−</p>
196−</dd>
197−<dt><code>*</code></dt>
198−<dd><p><code>Symbol.operatorMul</code>
199−</p>
200−</dd>
201−<dt><code>/</code></dt>
202−<dd><p><code>Symbol.operatorDiv</code>
203−</p>
204−</dd>
205−<dt><code>%</code></dt>
206−<dd><p><code>Symbol.operatorMod</code>
207−</p>
208−</dd>
209−<dt><code>% (math mode)</code></dt>
210−<dd><p><code>Symbol.operatorMathMod</code>
211−</p>
212−</dd>
213−<dt><code>**</code></dt>
214−<dd><p><code>Symbol.operatorPow</code>
215−</p>
216−</dd>
217−<dt><code>|</code></dt>
218−<dd><p><code>Symbol.operatorOr</code>
219−</p>
220−</dd>
221−<dt><code>^</code></dt>
222−<dd><p><code>Symbol.operatorXor</code>
223−</p>
224−</dd>
225−<dt><code>&amp;</code></dt>
226−<dd><p><code>Symbol.operatorAnd</code>
227−</p>
228−</dd>
229−<dt><code>&lt;&lt;</code></dt>
230−<dd><p><code>Symbol.operatorShl</code>
231−</p>
232−</dd>
233−<dt><code>&gt;&gt;</code></dt>
234−<dd><p><code>Symbol.operatorShr</code>
235−</p>
236−</dd>
237−<dt><code>&lt;</code></dt>
238−<dd><p><code>Symbol.operatorCmpLT</code>
239−</p>
240−</dd>
241−<dt><code>&gt;</code></dt>
242−<dd><p><code>Symbol.operatorCmpLT</code>, operands swapped
243−</p>
244−</dd>
245−<dt><code>&lt;=</code></dt>
246−<dd><p><code>Symbol.operatorCmpLE</code>
247−</p>
248−</dd>
249−<dt><code>&gt;=</code></dt>
250−<dd><p><code>Symbol.operatorCmpLE</code>, operands swapped
251−</p>
252−</dd>
253−<dt><code>==, !=</code></dt>
254−<dd><p><code>Symbol.operatorCmpEQ</code>
255−</p>
256−</dd>
257−</dl>
258−
259−<p>The return value of <code>Symbol.operatorCmpLT</code>, <code>Symbol.operatorCmpLE</code> and
260−<code>Symbol.operatorCmpEQ</code> is converted to <code>Boolean</code>.
113+<p>Operator overloading is inspired from the proposal available at
114+<a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>. It
115+implements the same dispatch logic but finds the operator sets by
116+looking at the <code>Symbol.operatorSet</code> property in the objects. The
117+changes were done in order to simplify the implementation.
261118 </p>
262−<a name="Builtin-Object-changes"></a>
263−<h3 class="section">2.2 Builtin Object changes</h3>
264−
265−<a name="Symbol-constructor"></a>
266−<h4 class="subsection">2.2.1 <code>Symbol</code> constructor</h4>
267−
268−<p>The following global symbols are added for the operator overloading:
269−</p><dl compact="compact">
270−<dt><code>operatorOrder</code></dt>
271−<dt><code>operatorAdd</code></dt>
272−<dt><code>operatorSub</code></dt>
273−<dt><code>operatorMul</code></dt>
274−<dt><code>operatorDiv</code></dt>
275−<dt><code>operatorMod</code></dt>
276−<dt><code>operatorPow</code></dt>
277−<dt><code>operatorShl</code></dt>
278−<dt><code>operatorShr</code></dt>
279−<dt><code>operatorAnd</code></dt>
280−<dt><code>operatorOr</code></dt>
281−<dt><code>operatorXor</code></dt>
282−<dt><code>operatorCmpLT</code></dt>
283−<dt><code>operatorCmpLE</code></dt>
284−<dt><code>operatorCmpEQ</code></dt>
285−<dt><code>operatorPlus</code></dt>
286−<dt><code>operatorNeg</code></dt>
287−<dt><code>operatorNot</code></dt>
288−<dt><code>operatorInc</code></dt>
289−<dt><code>operatorDec</code></dt>
290−</dl>
291−
292−
293−<a name="The-BigInt-Mode"></a>
294−<h2 class="chapter">3 The BigInt Mode</h2>
295−
296−<a name="Introduction-2"></a>
297−<h3 class="section">3.1 Introduction</h3>
298−
299−<p>The bigint mode is enabled with the <code>&quot;use bigint&quot;</code> directive. It
300−propagates the same way as the strict mode. In bigint mode, all
301−integers are considered as <code>bigint</code> (arbitrarily large integer,
302−similar to the TC39 BigInt
303−proposal<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>)
304−instead of <code>number</code> (floating point number). In order to be able
305−to exchange data between standard and bigint modes, numbers are
306−internally represented as 3 different types:
119+<p>More precisely, the following modifications were made:
307120 </p>
308121 <ul>
309−<li> Small integer (SmallInt): 32 bit integer<a name="DOCF3" href="#FOOT3"><sup>3</sup></a>.
122+<li> <code>with operators from</code> is not supported. Operator overloading is always enabled.
310123
311−</li><li> Big integer (BigInt): arbitrarily large integer.
124+</li><li> The dispatch is not based on a static <code>[[OperatorSet]]</code> field in all instances. Instead, a dynamic lookup the of the <code>Symbol.operatorSet</code> property is done. This property is typically added in the prototype of each object.
312125
313−</li><li> Floating point number (Float).
126+</li><li> <code>Operators.create(...dictionaries)</code> is used to create a new OperatorSet object. The <code>Operators</code> function is supported as an helper to be closer to the TC39 proposal.
314127
315−</li></ul>
316−
317−<p>In standard mode, the semantics of each operation is modified so that
318−when it returns a <code>number</code>, it is either of SmallInt or
319−Float. But the difference between SmallInt and Float is not observable
320−in standard mode.
321−</p>
322−<p>In bigint mode, each operation behaves differently whether its
323−operands are integer or float. The difference between SmallInt and
324−BigInt is not observable (i.e. they are both integers).
325−</p>
326−<p>The following table summarizes the observable types:
327−</p>
328−<table>
329−<thead><tr><th width="30%">Internal type</th><th width="30%">Observable type<br> (standard mode)</th><th width="30%">Observable type<br> (bigint mode)</th></tr></thead>
330−<tr><td width="30%">SmallInt</td><td width="30%">number</td><td width="30%">bigint</td></tr>
331−<tr><td width="30%">BigInt</td><td width="30%">bigint</td><td width="30%">bigint</td></tr>
332−<tr><td width="30%">Float</td><td width="30%">number</td><td width="30%">number</td></tr>
333−</table>
334−
335−<a name="Changes-that-introduce-incompatibilities-with-Javascript"></a>
336−<h3 class="section">3.2 Changes that introduce incompatibilities with Javascript</h3>
128+</li><li> <code>[]</code> cannot be overloaded.
337129
338−<a name="Standard-mode"></a>
339−<h4 class="subsection">3.2.1 Standard mode</h4>
340−
341−<p>There is no incompatibility with Javascript.
342−</p>
343−<a name="Bigint-mode"></a>
344−<h4 class="subsection">3.2.2 Bigint mode</h4>
345−
346−<p>The following changes are visible:
347−</p>
348−<ul>
349−<li> Integer and Float are different types. Constants are typed. For example: <code>typeof 1.0 === &quot;number&quot;</code> and <code>typeof 1 === &quot;bigint&quot;</code>. Another consequence is that <code>1.0 === 1</code> is false.
350−
351−</li><li> The range of integers is unlimited. In standard mode: <code>2**53 + 1 === 2**53</code>. This is no longer true with the bignum extensions.
352−
353−</li><li> Binary bitwise operators do not truncate to 32 bits i.e. <code>0x800000000 | 1 === 0x800000001</code> while it gives <code>1</code> in standard mode.
354−
355−</li><li> Bitwise shift operators do not truncate to 32 bits and do not mask the shift count with <code>0x1f</code> i.e. <code>1 &lt;&lt; 32 === 4294967296</code> while it gives <code>1</code> in standard mode. However, the <code>&gt;&gt;&gt;</code> operator (unsigned right shift) which is useless with bignums keeps its standard mode behavior<a name="DOCF4" href="#FOOT4"><sup>4</sup></a>.
356−
357−</li><li> Operators with integer operands never return the minus zero floating point value as result. Hence <code>Object.is(0, -0) === true</code>. Use <code>-0.0</code> to create a minus zero floating point value.
358−
359−</li><li> The <code>ToPrimitive</code> abstract operation is called with the <code>&quot;integer&quot;</code> preferred type when an integer is required (e.g. for bitwise binary or shift operations).
360−
361−</li><li> The prototype of integers is no longer <code>Number.prototype</code>. Instead<br> <code>Object.getPrototypeOf(1) === BigInt.prototype</code>. The prototype of floats remains Number.prototype.
362−
363−</li><li> If the TC39 BigInt proposal is supported, there is no observable difference between integers and <code>bigint</code>s.
130+</li><li> In math mode, the BigInt division and power operators can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
364131
365132 </li></ul>
366133
367−<a name="Operators"></a>
368−<h3 class="section">3.3 Operators</h3>
369−
370−<a name="Arithmetic-operators"></a>
371−<h4 class="subsection">3.3.1 Arithmetic operators</h4>
372−
373−<p>The operands are converted to number values as in normal
374−Javascript. Then the general case is that an Integer is returned if
375−both operands are Integer. Otherwise, a float is returned.
376−</p>
377−<p>The <code>+</code> operator also accepts strings as input and behaves like
378−standard Javascript in this case.
379−</p>
380−<p>The binary operator <code>%</code> returns the truncated remainder of the
381−division. When the result is an Integer type, a dividend of zero yields a
382−RangeError exception.
383−</p>
384−<p>The binary operator <code>%</code> in math mode returns the Euclidian
385−remainder of the division i.e. it is always positive.
386−</p>
387−<p>The binary operator <code>/</code> returns a float.
388−</p>
389−<p>The binary operator <code>/</code> in math mode returns a float if one of
390−the operands is float. Otherwise, <code>BigInt[Symbol.operatorDiv]</code> is
391−invoked.
392−</p>
393−<p>The returned type of <code>a ** b</code> is Float if <em>a</em> or <em>b</em>
394−are Float. If <em>a</em> and <em>b</em> are integers:
395−</p><ul>
396−<li> <em>b &lt; 0</em> returns a Float in bigint mode. In math mode, <code>BigInt[Symbol.operatorPow]</code> is invoked.
397−
398−</li><li> <em>b &gt;= 0</em> returns an integer.
399−</li></ul>
400−
401−<p>The unary <code>-</code> and unary <code>+</code> return the same type as their
402−operand. They performs no floating point rounding when the result is a
403−float.
404−</p>
405−<p>The unary operators <code>++</code> and <code>--</code> return the same type as
406−their operand.
407−</p>
408−<p>In standard mode:
409−</p>
410−<p>If the operator returns an Integer and that the result fits a
411−SmallInt, it is converted to SmallInt. Otherwise, the Integer is
412−converted to a Float.
413−</p>
414−<p>In bigint mode:
415−</p>
416−<p>If the operator returns an Integer and that the result fits a
417−SmallInt, it is converted to SmallInt. Otherwise it is a BigInt.
418−</p>
419−<a name="Logical-operators"></a>
420−<h4 class="subsection">3.3.2 Logical operators</h4>
421−
422−<p>In standard mode:
423−</p>
424−<p>The operands have their standard behavior. If the result fits a
425−SmallInt it is converted to a SmallInt. Otherwise it is a Float.
426−</p>
427−<p>In bigint mode:
428−</p>
429−<p>The operands are converted to integer values. The floating point
430−values are converted to integer by rounding them to zero.
431−</p>
432−<p>The logical operators are defined assuming the integers are
433−represented in two complement notation.
434−</p>
435−<p>For <code>&lt;&lt;</code> and <code>&lt;&lt;</code>, the shift can be positive or negative. So
436−<code>a &lt;&lt; b</code> is defined as <em>\lfloor a/2^{-b} \rfloor</em> and
437−<code>a &gt;&gt; b</code> is defined as <em>\lfloor a/2^{b} \rfloor</em>.
438−</p>
439−<p>The operator <code>&gt;&gt;&gt;</code> is supported for backward compatibility and
440−behaves the same way as Javascript i.e. implicit conversion to <code>Uint32</code>.
441−</p>
442−<p>If the result fits a SmallInt it is converted to a SmallInt. Otherwise
443−it is a BigInt.
444−</p>
445−<a name="Relational-operators"></a>
446−<h4 class="subsection">3.3.3 Relational operators</h4>
447−
448−<p>The relational operators &lt;, &lt;=, &gt;, &gt;=, ==, != work as expected with
449−integers and floating point numbers (e.g. <code>1.0 == 1</code> is true).
450−</p>
451−<p>The strict equality operators === and !== have the usual Javascript
452−semantics. In particular, different types never equal, so <code>1.0
453−=== 1</code> is false.
454−</p>
455−<a name="Number-literals"></a>
456−<h3 class="section">3.4 Number literals</h3>
134+<a name="BigInt-extensions"></a>
135+<h2 class="chapter">3 BigInt extensions</h2>
457136
458−<p>Number literals in bigint mode have a slightly different behavior than
459−in standard Javascript:
460−</p>
461−<ol>
462−<li> A number literal without a decimal point or an exponent is considered
463−as an Integer. Otherwise it is a Float.
464−
465−</li><li> Hexadecimal, octal or binary floating point literals are accepted with
466−a decimal point or an exponent. The exponent is specified with the
467−<code>p</code> letter assuming a base 2. The same convention is used by
468−C99. Example: <code>0x1p3</code> is the same as <code>8.0</code>.
469−
470−</li></ol>
471−
472−<a name="Builtin-Object-changes-1"></a>
473−<h3 class="section">3.5 Builtin Object changes</h3>
474−
475−<a name="BigInt-function"></a>
476−<h4 class="subsection">3.5.1 <code>BigInt</code> function</h4>
477−
478−<p>The <code>BigInt</code> function cannot be invoked as a constructor. When
479−invoked as a function, it converts its first parameter to an
480−integer. When a floating point number is given as parameter, it is
481−truncated to an integer with infinite precision.
482−</p>
483−<p><code>BigInt</code> properties:
137+<p>A few properties are added to the BigInt object:
484138 </p>
485139 <dl compact="compact">
486−<dt><code>asIntN(bits, a)</code></dt>
487−<dd><p>Set <em>b=a \pmod{2^{bits}}</em>. Return <em>b</em> if <em>b &lt; 2^{bits-1}</em>
488−otherwise <em>b-2^{bits}</em>.
489−</p>
490−</dd>
491−<dt><code>asUintN(bits, a)</code></dt>
492−<dd><p>Return <em>a \pmod{2^{bits}}</em>.
493−</p>
494−</dd>
495140 <dt><code>tdiv(a, b)</code></dt>
496141 <dd><p>Return <em>trunc(a/b)</em>. <code>b = 0</code> raises a RangeError
497142 exception.
@@ -542,70 +187,10 @@ raised if <em>a &lt; 0</em>. · 44 unmodified lines
542187 </dd>
543188 </dl>
544189
545−<a name="BigInt_002eprototype"></a>
546−<h4 class="subsection">3.5.2 <code>BigInt.prototype</code></h4>
190+<a name="BigFloat"></a>
191+<h2 class="chapter">4 BigFloat</h2>
547192
548−<p>It is a normal object.
549−</p>
550−<a name="Number-constructor"></a>
551−<h4 class="subsection">3.5.3 <code>Number</code> constructor</h4>
552−
553−<p>The number constructor returns its argument rounded to a Float using
554−the global floating point environment. In bigint mode, the Number
555−constructor returns a Float. In standard mode, it returns a SmallInt
556−if the value fits it, otherwise a Float.
557−</p>
558−<a name="Number_002eprototype"></a>
559−<h4 class="subsection">3.5.4 <code>Number.prototype</code></h4>
560−
561−<p>The following properties are modified:
562−</p>
563−<dl compact="compact">
564−<dt><code>toString(radix)</code></dt>
565−<dd>
566−<p>In bigint mode, integers are converted to the specified radix with
567−infinite precision.
568−</p>
569−</dd>
570−<dt><code>toPrecision(p)</code></dt>
571−<dt><code>toFixed(p)</code></dt>
572−<dt><code>toExponential(p)</code></dt>
573−<dd>
574−<p>In bigint mode, integers are accepted and converted to string with
575−infinite precision.
576−</p>
577−</dd>
578−<dt><code>parseInt(string, radix)</code></dt>
579−<dd>
580−<p>In bigint mode, an integer is returned and the conversion is done with
581−infinite precision.
582−</p>
583−</dd>
584−</dl>
585−
586−<a name="Math-object"></a>
587−<h4 class="subsection">3.5.5 <code>Math</code> object</h4>
588−
589−<p>The following properties are modified:
590−</p>
591−<dl compact="compact">
592−<dt><code>abs(x)</code></dt>
593−<dd><p>Absolute value. Return an integer if <code>x</code> is an Integer. Otherwise
594−return a Float. No rounding is performed.
595−</p>
596−</dd>
597−<dt><code>min(a, b)</code></dt>
598−<dt><code>max(a, b)</code></dt>
599−<dd><p>No rounding is performed. The returned type is the same one as the
600−minimum (resp. maximum) value.
601−</p>
602−</dd>
603−</dl>
604−
605−<a name="Arbitrarily-large-floating-point-numbers"></a>
606−<h2 class="chapter">4 Arbitrarily large floating point numbers</h2>
607−
608−<a name="Introduction-3"></a>
193+<a name="Introduction-1"></a>
609194 <h3 class="section">4.1 Introduction</h3>
610195
611196 <p>This extension adds the <code>BigFloat</code> primitive type. The
@@ -628,8 +213,8 @@ environment are also set according to the result of the operation. · 16 unmodified lines
628213 point environment is used.
629214 </p>
630215 <p>The rounding mode of the global floating point environment is always
631−<code>RNDN</code> (&ldquo;round to nearest with ties to even&rdquo;)<a name="DOCF5" href="#FOOT5"><sup>5</sup></a>. The status flags of the global environment cannot be
632−read<a name="DOCF6" href="#FOOT6"><sup>6</sup></a>. The precision of the global environment is
216+<code>RNDN</code> (&ldquo;round to nearest with ties to even&rdquo;)<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>. The status flags of the global environment cannot be
217+read<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>. The precision of the global environment is
633218 <code>BigFloatEnv.prec</code>. The number of exponent bits of the global
634219 environment is <code>BigFloatEnv.expBits</code>. If <code>BigFloatEnv.expBits</code> is
635220 strictly smaller than the maximum allowed number of exponent bits
@@ -646,7 +231,7 @@ when calling a function (see <code>BigFloatEnv.setPrec</code>). Hence a · 10 unmodified lines
646231 function can change the global floating point environment for its
647232 callees but not for its caller.
648233 </p>
649−<a name="Operators-1"></a>
234+<a name="Operators"></a>
650235 <h3 class="section">4.3 Operators</h3>
651236
652237 <p>The builtin operators are extended so that a BigFloat is returned if
@@ -669,9 +254,9 @@ equal when using the strict comparison operators (e.g. <code>0.0 === · 16 unmodified lines
669254 <p>BigFloat literals are floating point numbers with a trailing <code>l</code>
670255 suffix. BigFloat literals have an infinite precision. They are rounded
671256 according to the global floating point environment when they are
672−evaluated.<a name="DOCF7" href="#FOOT7"><sup>7</sup></a>
257+evaluated.<a name="DOCF3" href="#FOOT3"><sup>3</sup></a>
673258 </p>
674−<a name="Builtin-Object-changes-2"></a>
259+<a name="Builtin-Object-changes"></a>
675260 <h3 class="section">4.5 Builtin Object changes</h3>
676261
677262 <a name="BigFloat-function"></a>
@@ -739,6 +324,10 @@ point number <code>a</code> according to the floating point environment · 61 unmodified lines
739324 <dd><p>Round to an integer. No additional rounding is performed.
740325 </p>
741326 </dd>
327+<dt><code>abs(x)</code></dt>
328+<dd><p>Return the absolute value of x. No additional rounding is performed.
329+</p>
330+</dd>
742331 <dt><code>fmod(x, y[, e])</code></dt>
743332 <dt><code>remainder(x, y[, e])</code></dt>
744333 <dd><p>Floating point remainder. The quotient is truncated to zero (fmod) or
@@ -773,6 +362,10 @@ number. <code>e</code> is an optional floating point environment. · 28 unmodified lines
773362 <p>The following properties are modified:
774363 </p>
775364 <dl compact="compact">
365+<dt><code>valueOf()</code></dt>
366+<dd><p>Return the bigfloat primitive value corresponding to <code>this</code>.
367+</p>
368+</dd>
776369 <dt><code>toString(radix)</code></dt>
777370 <dd>
778371 <p>For floating point numbers:
@@ -787,14 +380,17 @@ the global precision and round to nearest gives the same number. · 8 unmodified lines
787380
788381 </li></ul>
789382
383+<p>The exponent letter is <code>e</code> for base 10, <code>p</code> for bases 2, 8,
384+16 with a binary exponent and <code>@</code> for the other bases.
385+</p>
790386 </dd>
791−<dt><code>toPrecision(p[, rnd_mode])</code></dt>
792−<dt><code>toFixed(p[, rnd_mode])</code></dt>
793−<dt><code>toExponential(p[, rnd_mode])</code></dt>
387+<dt><code>toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
388+<dt><code>toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
389+<dt><code>toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
794390 <dd><p>Same semantics as the corresponding <code>Number</code> functions with
795391 BigFloats. There is no limit on the accepted precision <code>p</code>. The
796−rounding mode can be optionally specified. It is set by default to
797−<code>BigFloatEnv.RNDNA</code>.
392+rounding mode and radix can be optionally specified. The radix must be
393+between 2 and 36.
798394 </p>
799395 </dd>
800396 </dl>
@@ -832,14 +428,14 @@ subnormal flags is set to <code>false</code>. If <code>rndMode</code> is · 31 unmodified lines
832428 <dl compact="compact">
833429 <dt><code>prec</code></dt>
834430 <dd><p>Getter. Return the precision in bits of the global floating point
835−environment. The initial value is <code>53</code>.
431+environment. The initial value is <code>113</code>.
836432 </p>
837433 </dd>
838434 <dt><code>expBits</code></dt>
839435 <dd><p>Getter. Return the exponent size in bits of the global floating point
840436 environment assuming an IEEE 754 representation. If <code>expBits &lt;
841437 expBitsMax</code>, then subnormal numbers are supported. The initial value
842−is <code>11</code>.
438+is <code>15</code>.
843439 </p>
844440 </dd>
845441 <dt><code>setPrec(f, p[, e])</code></dt>
@@ -848,9 +444,7 @@ and the exponent size to <code>e</code> then call the function · 2 unmodified lines
848444 <code>f</code>. Then the Float precision and exponent size are reset to
849445 their precious value and the return value of <code>f</code> is returned (or
850446 an exception is raised if <code>f</code> raised an exception). If <code>e</code>
851−is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>. <code>p</code>
852−must be &gt;= 53 and <code>e</code> must be &gt;= 11 so that the global precision
853−is at least equivalent to the IEEE 754 64 bit doubles.
447+is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>.
854448 </p>
855449 </dd>
856450 <dt><code>precMin</code></dt>
@@ -858,7 +452,7 @@ is at least equivalent to the IEEE 754 64 bit doubles. · 1 unmodified line
858452 </p>
859453 </dd>
860454 <dt><code>precMax</code></dt>
861−<dd><p>Read-only integer. Return the maximum allowed precision. Must be at least 53.
455+<dd><p>Read-only integer. Return the maximum allowed precision. Must be at least 113.
862456 </p>
863457 </dd>
864458 <dt><code>expBitsMin</code></dt>
@@ -868,7 +462,7 @@ bits. Must be at least 3. · 3 unmodified lines
868462 </dd>
869463 <dt><code>expBitsMax</code></dt>
870464 <dd><p>Read-only integer. Return the maximum allowed exponent size in
871−bits. Must be at least 11.
465+bits. Must be at least 15.
872466 </p>
873467 </dd>
874468 <dt><code>RNDN</code></dt>
@@ -891,11 +485,11 @@ bits. Must be at least 11. · 16 unmodified lines
891485 <dd><p>Read-only integer. Round to nearest, with ties away from zero rounding mode.
892486 </p>
893487 </dd>
894−<dt><code>RNDNU</code></dt>
895−<dd><p>Read-only integer. Round to nearest, with ties to +Infinity rounding mode.
488+<dt><code>RNDA</code></dt>
489+<dd><p>Read-only integer. Round away from zero rounding mode.
896490 </p>
897491 </dd>
898−<dt><code>RNDF<a name="DOCF8" href="#FOOT8"><sup>8</sup></a></code></dt>
492+<dt><code>RNDF<a name="DOCF4" href="#FOOT4"><sup>4</sup></a></code></dt>
899493 <dd><p>Read-only integer. Faithful rounding mode. The result is
900494 non-deterministically rounded to -Infinity or +Infinity. This rounding
901495 mode usually gives a faster and deterministic running time for the
@@ -939,102 +533,200 @@ assuming an IEEE 754 representation. · 37 unmodified lines
939533 </dd>
940534 </dl>
941535
942−<a name="Math-object-1"></a>
943−<h4 class="subsection">4.5.4 <code>Math</code> object</h4>
536+<a name="BigDecimal"></a>
537+<h2 class="chapter">5 BigDecimal</h2>
944538
945−<p>The following properties are modified:
539+<p>This extension adds the <code>BigDecimal</code> primitive type. The
540+<code>BigDecimal</code> type represents floating point numbers in base
541+10. It is inspired from the proposal available at
542+<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
543+</p>
544+<p>The <code>BigDecimal</code> floating point numbers are always normalized and
545+finite. There is no concept of <code>-0</code>, <code>Infinity</code> or
546+<code>NaN</code>. By default, all the computations are done with infinite
547+precision.
548+</p>
549+<a name="Operators-1"></a>
550+<h3 class="section">5.1 Operators</h3>
551+
552+<p>The following builtin operators support BigDecimal:
946553 </p>
947554 <dl compact="compact">
948−<dt><code>abs(x)</code></dt>
949−<dd><p>Absolute value. If <code>x</code> is a BigFloat, its absolute value is
950−returned as a BigFloat. No rounding is performed.
555+<dt><code>+</code></dt>
556+<dt><code>-</code></dt>
557+<dt><code>*</code></dt>
558+<dd><p>Both operands must be BigDecimal. The result is computed with infinite
559+precision.
560+</p></dd>
561+<dt><code>%</code></dt>
562+<dd><p>Both operands must be BigDecimal. The result is computed with infinite
563+precision. A range error is throws in case of division by zero.
951564 </p>
952565 </dd>
953−<dt><code>min(a, b)</code></dt>
954−<dt><code>max(a, b)</code></dt>
955−<dd><p>The returned type is the same one as the minimum (resp. maximum)
956−value, so <code>BigFloat</code> values are accepted. When a <code>BigFloat</code>
957−is returned, no rounding is performed.
566+<dt><code>/</code></dt>
567+<dd><p>Both operands must be BigDecimal. A range error is throws in case of
568+division by zero or if the result cannot be represented with infinite
569+precision (use <code>BigDecimal.div</code> to specify the rounding).
570+</p>
571+</dd>
572+<dt><code>**</code></dt>
573+<dd><p>Both operands must be BigDecimal. The exponent must be a positive
574+integer. The result is computed with infinite precision.
575+</p>
576+</dd>
577+<dt><code>===</code></dt>
578+<dd><p>When one of the operand is a BigDecimal, return true if both operands
579+are a BigDecimal and if they are equal.
580+</p>
581+</dd>
582+<dt><code>==</code></dt>
583+<dt><code>!=</code></dt>
584+<dt><code>&lt;=</code></dt>
585+<dt><code>&gt;=</code></dt>
586+<dt><code>&lt;</code></dt>
587+<dt><code>&gt;</code></dt>
588+<dd>
589+<p>Numerical comparison. When one of the operand is not a BigDecimal, it is
590+converted to BigDecimal by using ToString(). Hence comparisons between
591+Number and BigDecimal do not use the exact mathematical value of the
592+Number value.
958593 </p>
959594 </dd>
960595 </dl>
961596
962−<a name="Math-mode"></a>
963−<h2 class="chapter">5 Math mode</h2>
597+<a name="BigDecimal-literals"></a>
598+<h3 class="section">5.2 BigDecimal literals</h3>
964599
965−<a name="Introduction-4"></a>
966−<h3 class="section">5.1 Introduction</h3>
600+<p>BigDecimal literals are decimal floating point numbers with a trailing
601+<code>m</code> suffix.
602+</p>
603+<a name="Builtin-Object-changes-1"></a>
604+<h3 class="section">5.3 Builtin Object changes</h3>
967605
968−<p>A new <em>math mode</em> is enabled with the <code>&quot;use math&quot;</code>
969−directive. <code>&quot;use bigint&quot;</code> is implied in math mode. With this
970−mode, writing mathematical expressions is more intuitive, exact
971−results (e.g. fractions) can be computed for all operators and floating
972−point literals have the <code>BigFloat</code> type by default.
606+<a name="The-BigDecimal-function_002e"></a>
607+<h4 class="subsection">5.3.1 The <code>BigDecimal</code> function.</h4>
608+
609+<p>It returns <code>0m</code> if no parameter is provided. Otherwise the first
610+parameter is converted to a bigdecimal by using ToString(). Hence
611+Number value are not converted to their exact numerical value as
612+BigDecimal.
973613 </p>
974−<p>It propagates the same way as the <em>strict mode</em>. In
975−this mode:
614+<a name="Properties-of-the-BigDecimal-object"></a>
615+<h4 class="subsection">5.3.2 Properties of the <code>BigDecimal</code> object</h4>
616+
617+<dl compact="compact">
618+<dt><code>add(a, b[, e])</code></dt>
619+<dt><code>sub(a, b[, e])</code></dt>
620+<dt><code>mul(a, b[, e])</code></dt>
621+<dt><code>div(a, b[, e])</code></dt>
622+<dt><code>mod(a, b[, e])</code></dt>
623+<dt><code>sqrt(a, e)</code></dt>
624+<dt><code>round(a, e)</code></dt>
625+<dd><p>Perform the specified floating point operation and round the floating
626+point result according to the rounding object <code>e</code>. If the
627+rounding object is not present, the operation is executed with
628+infinite precision.
976629 </p>
977−<ul>
978−<li> The <code>^</code> operator is a similar to the power operator (<code>**</code>).
630+<p>For <code>div</code>, a <code>RangeError</code> exception is thrown in case of
631+division by zero or if the result cannot be represented with infinite
632+precision if no rounding object is present.
633+</p>
634+<p>For <code>sqrt</code>, a range error is thrown if <code>a</code> is less than
635+zero.
636+</p>
637+<p>The rounding object must contain the following properties:
638+<code>roundingMode</code> is a string specifying the rounding mode
639+(<code>&quot;floor&quot;</code>, <code>&quot;ceiling&quot;</code>, <code>&quot;down&quot;</code>, <code>&quot;up&quot;</code>,
640+<code>&quot;half-even&quot;</code>, <code>&quot;half-up&quot;</code>). Either
641+<code>maximumSignificantDigits</code> or <code>maximumFractionDigits</code> must
642+be present to specify respectively the number of significant digits
643+(must be &gt;= 1) or the number of digits after the decimal point (must
644+be &gt;= 0).
645+</p>
646+</dd>
647+</dl>
979648
980−</li><li> The power operator (both <code>^</code> and <code>**</code>) grammar is modified so that <code>-2^2</code> is allowed and yields <code>-4</code>.
649+<a name="Properties-of-the-BigDecimal_002eprototype-object"></a>
650+<h4 class="subsection">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</h4>
981651
982−</li><li> The logical xor operator is still available with the <code>^^</code> operator.
652+<dl compact="compact">
653+<dt><code>valueOf()</code></dt>
654+<dd><p>Return the bigdecimal primitive value corresponding to <code>this</code>.
655+</p>
656+</dd>
657+<dt><code>toString()</code></dt>
658+<dd><p>Convert <code>this</code> to a string with infinite precision in base 10.
659+</p>
660+</dd>
661+<dt><code>toPrecision(p, rnd_mode = &quot;half-up&quot;)</code></dt>
662+<dt><code>toFixed(p, rnd_mode = &quot;half-up&quot;)</code></dt>
663+<dt><code>toExponential(p, rnd_mode = &quot;half-up&quot;)</code></dt>
664+<dd><p>Convert the BigDecimal <code>this</code> to string with the specified
665+precision <code>p</code>. There is no limit on the accepted precision
666+<code>p</code>. The rounding mode can be optionally
667+specified. <code>toPrecision</code> outputs either in decimal fixed notation
668+or in decimal exponential notation with a <code>p</code> digits of
669+precision. <code>toExponential</code> outputs in decimal exponential
670+notation with <code>p</code> digits after the decimal point. <code>toFixed</code>
671+outputs in decimal notation with <code>p</code> digits after the decimal
672+point.
673+</p>
674+</dd>
675+</dl>
983676
984−</li><li> The division operator invokes <code>BigInt[Symbol.operatorDiv]</code> in case both operands are integers.
677+<a name="Math-mode"></a>
678+<h2 class="chapter">6 Math mode</h2>
985679
986−</li><li> The power operator invokes <code>BigInt[Symbol.operatorPow]</code> in case both operands are integers and the exponent is strictly negative.
680+<p>A new <em>math mode</em> is enabled with the <code>&quot;use math&quot;</code>
681+directive. It propagates the same way as the <em>strict mode</em>. It is
682+designed so that arbitrarily large integers and floating point numbers
683+are available by default. In order to minimize the number of changes
684+in the Javascript semantics, integers are represented either as Number
685+or BigInt depending on their magnitude. Floating point numbers are
686+always represented as BigFloat.
687+</p>
688+<p>The following changes are made to the Javascript semantics:
689+</p>
690+<ul>
691+<li> Floating point literals (i.e. number with a decimal point or an exponent) are <code>BigFloat</code> by default (i.e. a <code>l</code> suffix is implied). Hence <code>typeof 1.0 === &quot;bigfloat&quot;</code>.
987692
988−</li><li> The modulo operator returns the Euclidian remainder (always positive) instead of the truncated remainder.
693+</li><li> Integer literals (i.e. numbers without a decimal point or an exponent) with or without the <code>n</code> suffix are <code>BigInt</code> if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to <code>2**53-1</code>. Hence <code>typeof 1 === &quot;number &quot;</code>, <code>typeof 1n === &quot;number&quot;</code> but <code>typeof 9007199254740992 === &quot;bigint&quot; </code>.
989694
990−</li><li> Floating point literals are <code>BigFloat</code> by default (i.e. a <code>l</code> suffix is implied).
695+</li><li> All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt.
991696
992−</li></ul>
697+</li><li> The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result.
993698
994−<a name="Builtin-Object-changes-3"></a>
995−<h3 class="section">5.2 Builtin Object changes</h3>
699+</li><li> The <code>^</code> operator is an alias to the power operator (<code>**</code>).
996700
997−<a name="Symbol-constructor-1"></a>
998−<h4 class="subsection">5.2.1 <code>Symbol</code> constructor</h4>
701+</li><li> The power operator (both <code>^</code> and <code>**</code>) grammar is modified so that <code>-2^2</code> is allowed and yields <code>-4</code>.
999702
1000−<p>The following global symbol is added for the operator overloading:
1001−</p><dl compact="compact">
1002−<dt><code>operatorMathMod</code></dt>
1003−</dl>
703+</li><li> The logical xor operator is still available with the <code>^^</code> operator.
1004704
1005−<a name="Remaining-issues"></a>
1006−<h3 class="section">5.3 Remaining issues</h3>
705+</li><li> The integer division operator can be overloaded by modifying the corresponding operator in <code>BigInt.prototype.[[OperatorSet]]</code>.
1007706
1008−<ol>
1009−<li> A new floating point literal suffix could be added for <code>Number</code> literals.
707+</li><li> The integer power operator with a non zero negative exponent can be overloaded by modifying the corresponding operator in <code>BigInt.prototype.[[OperatorSet]]</code>.
1010708
1011−</li></ol>
709+</li><li> The modulo operator (<code>%</code>) returns the Euclidian remainder (always positive) instead of the truncated remainder.
710+
711+</li></ul>
1012712
1013713 <div class="footnote">
1014714 <hr>
1015715 <h4 class="footnotes-heading">Footnotes</h4>
1016716
1017717 <h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>
1018−<p><a href="https://tc39.github.io/proposal-bigint/">https://tc39.github.io/proposal-bigint/</a></p>
1019−<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
1020−<p><a href="https://tc39.github.io/proposal-bigint/">https://tc39.github.io/proposal-bigint/</a></p>
1021−<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
1022−<p>Could be extended to 53 bits without changing the principle.</p>
1023−<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
1024−<p>The unsigned right right operator could be removed in bigint mode.</p>
1025−<h3><a name="FOOT5" href="#DOCF5">(5)</a></h3>
1026718 <p>The
1027719 rationale is that the rounding mode changes must always be
1028720 explicit.</p>
1029−<h3><a name="FOOT6" href="#DOCF6">(6)</a></h3>
721+<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
1030722 <p>The rationale is to avoid side effects for the built-in
1031723 operators.</p>
1032−<h3><a name="FOOT7" href="#DOCF7">(7)</a></h3>
724+<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
1033725 <p>Base 10 floating point literals cannot usually be
1034726 exactly represented as base 2 floating point number. In order to
1035727 ensure that the literal is represented accurately with the current
1036728 precision, it must be evaluated at runtime.</p>
1037−<h3><a name="FOOT8" href="#DOCF8">(8)</a></h3>
729+<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
1038730 <p>Could be removed in case a deterministic behavior for floating point operations is required.</p>
1039731 </div>
1040732 <hr>
doc/jsbignum.pdf+0−0

Binary file not shown.

doc/jsbignum.texi+179−422
@@ -10,12 +10,12 @@ · 9 unmodified lines
1010 @sp 7
1111 @center @titlefont{Javascript Bignum Extensions}
1212 @sp 3
13−@center Version 2018-06-16
13+@center Version 2020-01-11
1414 @sp 3
1515 @center Author: Fabrice Bellard
1616 @end titlepage
1717
18−@setfilename spec.info
18+@setfilename jsbignum.info
1919 @settitle Javascript Bignum Extensions
2020
2121 @contents
@@ -27,348 +27,52 @@ language while being 100% backward compatible: · 5 unmodified lines
2727
2828 @itemize
2929
30−@item Overloading of the standard operators
31−to support new types such as complex numbers, fractions or matrices.
32−
33−@item Bigint mode where arbitrarily large integers are available by default (no @code{n} suffix is necessary as in the TC39 BigInt proposal@footnote{@url{https://tc39.github.io/proposal-bigint/}}).
30+@item Operator overloading with a dispatch logic inspired from the proposal available at @url{https://github.com/tc39/proposal-operator-overloading/}.
3431
3532 @item Arbitrarily large floating point numbers (@code{BigFloat}) in base 2 using the IEEE 754 semantics.
3633
37−@item Optional @code{math} mode which modifies the semantics of the division, modulo and power operator. The division and power operator return a fraction with integer operands and the modulo operator is defined as the Euclidian remainder.
34+@item Arbitrarily large floating point numbers (@code{BigDecimal}) in base 10 based on the proposal available at
35+@url{https://github.com/littledan/proposal-bigdecimal}.
36+
37+@item @code{math} mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (@code{%}) is defined as the Euclidian
38+remainder. @code{^} is an alias to the power operator
39+(@code{**}). @code{^^} is used as the exclusive or operator.
3840
3941 @end itemize
4042
4143 The extensions are independent from each other except the @code{math}
42−mode which relies on the bigint mode and the operator overloading.
44+mode which relies on BigFloat and operator overloading.
4345
4446 @chapter Operator overloading
4547
46−@section Introduction
47−
48−If the operands of an operator have at least one object type, a custom
49−operator method is searched before doing the legacy Javascript
50−@code{ToNumber} conversion.
51−
52−For unary operators, the custom function is looked up in the object
53−and has the following name:
54−
55−@table @code
56−@item unary +
57−@code{Symbol.operatorPlus}
58−
59−@item unary -
60−@code{Symbol.operatorNeg}
61−
62−@item ++
63−@code{Symbol.operatorInc}
64−
65−@item --
66−@code{Symbol.operatorDec}
67−
68−@item ~
69−@code{Symbol.operatorNot}
70−
71−@end table
72−
73−For binary operators:
74−
75−@itemize
76−
77−@item
78−If both operands have the same constructor function, then the operator
79−is looked up in the constructor.
80−
81−@item
82−Otherwise, the property @code{Symbol.operatorOrder} is looked up in both
83−constructors and converted to @code{Int32}. The operator is then
84−looked in the constructor with the larger @code{Symbol.operatorOrder}
85−value. A @code{TypeError} is raised if both constructors have the same
86−@code{Symbol.operatorOrder} value.
87−
88−@end itemize
89−
90−The operator is looked up with the following name:
91−
92−@table @code
93−@item +
94−@code{Symbol.operatorAdd}
95−
96−@item -
97−@code{Symbol.operatorSub}
98−
99−@item *
100−@code{Symbol.operatorMul}
101−
102−@item /
103−@code{Symbol.operatorDiv}
104−
105−@item %
106−@code{Symbol.operatorMod}
107−
108−@item % (math mode)
109−@code{Symbol.operatorMathMod}
110−
111−@item **
112−@code{Symbol.operatorPow}
113−
114−@item |
115−@code{Symbol.operatorOr}
116−
117−@item ^
118−@code{Symbol.operatorXor}
119−
120−@item &
121−@code{Symbol.operatorAnd}
122−
123−@item <<
124−@code{Symbol.operatorShl}
125−
126−@item >>
127−@code{Symbol.operatorShr}
128−
129−@item <
130−@code{Symbol.operatorCmpLT}
131−
132−@item >
133−@code{Symbol.operatorCmpLT}, operands swapped
134−
135−@item <=
136−@code{Symbol.operatorCmpLE}
137−
138−@item >=
139−@code{Symbol.operatorCmpLE}, operands swapped
140−
141−@item ==, !=
142−@code{Symbol.operatorCmpEQ}
143−
144−@end table
145−
146−The return value of @code{Symbol.operatorCmpLT}, @code{Symbol.operatorCmpLE} and
147−@code{Symbol.operatorCmpEQ} is converted to @code{Boolean}.
148−
149−@section Builtin Object changes
150−
151−@subsection @code{Symbol} constructor
152−
153−The following global symbols are added for the operator overloading:
154−@table @code
155−@item operatorOrder
156−@item operatorAdd
157−@item operatorSub
158−@item operatorMul
159−@item operatorDiv
160−@item operatorMod
161−@item operatorPow
162−@item operatorShl
163−@item operatorShr
164−@item operatorAnd
165−@item operatorOr
166−@item operatorXor
167−@item operatorCmpLT
168−@item operatorCmpLE
169−@item operatorCmpEQ
170−@item operatorPlus
171−@item operatorNeg
172−@item operatorNot
173−@item operatorInc
174−@item operatorDec
175−@end table
176−
177−
178−@chapter The BigInt Mode
48+Operator overloading is inspired from the proposal available at
49+@url{https://github.com/tc39/proposal-operator-overloading/}. It
50+implements the same dispatch logic but finds the operator sets by
51+looking at the @code{Symbol.operatorSet} property in the objects. The
52+changes were done in order to simplify the implementation.
17953
180−@section Introduction
181−
182−The bigint mode is enabled with the @code{"use bigint"} directive. It
183−propagates the same way as the strict mode. In bigint mode, all
184−integers are considered as @code{bigint} (arbitrarily large integer,
185−similar to the TC39 BigInt
186−proposal@footnote{@url{https://tc39.github.io/proposal-bigint/}})
187−instead of @code{number} (floating point number). In order to be able
188−to exchange data between standard and bigint modes, numbers are
189−internally represented as 3 different types:
54+More precisely, the following modifications were made:
19055
19156 @itemize
19257
193−@item Small integer (SmallInt): 32 bit integer@footnote{Could be extended to 53 bits without changing the principle.}.
194−
195−@item Big integer (BigInt): arbitrarily large integer.
196−
197−@item Floating point number (Float).
198−
199−@end itemize
200−
201−In standard mode, the semantics of each operation is modified so that
202−when it returns a @code{number}, it is either of SmallInt or
203−Float. But the difference between SmallInt and Float is not observable
204−in standard mode.
205−
206−In bigint mode, each operation behaves differently whether its
207−operands are integer or float. The difference between SmallInt and
208−BigInt is not observable (i.e. they are both integers).
209−
210−The following table summarizes the observable types:
211−
212−@multitable @columnfractions .3 .3 .3
213−@headitem Internal type @tab Observable type@* (standard mode) @tab Observable type@* (bigint mode)
214−@item SmallInt @tab number @tab bigint
215−@item BigInt @tab bigint @tab bigint
216−@item Float @tab number @tab number
217−@end multitable
218−
219−@section Changes that introduce incompatibilities with Javascript
220−
221−@subsection Standard mode
222−
223−There is no incompatibility with Javascript.
224−
225−@subsection Bigint mode
226−
227−The following changes are visible:
228−
229−@itemize
230−
231−@item Integer and Float are different types. Constants are typed. For example: @code{typeof 1.0 === "number"} and @code{typeof 1 === "bigint"}. Another consequence is that @code{1.0 === 1} is false.
232−
233−@item The range of integers is unlimited. In standard mode: @code{2**53 + 1 === 2**53}. This is no longer true with the bignum extensions.
234−
235−@item Binary bitwise operators do not truncate to 32 bits i.e. @code{0x800000000 | 1 === 0x800000001} while it gives @code{1} in standard mode.
58+@item @code{with operators from} is not supported. Operator overloading is always enabled.
23659
237−@item Bitwise shift operators do not truncate to 32 bits and do not mask the shift count with @code{0x1f} i.e. @code{1 << 32 === 4294967296} while it gives @code{1} in standard mode. However, the @code{>>>} operator (unsigned right shift) which is useless with bignums keeps its standard mode behavior@footnote{The unsigned right right operator could be removed in bigint mode.}.
60+@item The dispatch is not based on a static @code{[[OperatorSet]]} field in all instances. Instead, a dynamic lookup the of the @code{Symbol.operatorSet} property is done. This property is typically added in the prototype of each object.
23861
239−@item Operators with integer operands never return the minus zero floating point value as result. Hence @code{Object.is(0, -0) === true}. Use @code{-0.0} to create a minus zero floating point value.
62+@item @code{Operators.create(...dictionaries)} is used to create a new OperatorSet object. The @code{Operators} function is supported as an helper to be closer to the TC39 proposal.
24063
241−@item The @code{ToPrimitive} abstract operation is called with the @code{"integer"} preferred type when an integer is required (e.g. for bitwise binary or shift operations).
64+@item @code{[]} cannot be overloaded.
24265
243−@item The prototype of integers is no longer @code{Number.prototype}. Instead@* @code{Object.getPrototypeOf(1) === BigInt.prototype}. The prototype of floats remains Number.prototype.
66+@item In math mode, the BigInt division and power operators can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
24467
245−@item If the TC39 BigInt proposal is supported, there is no observable difference between integers and @code{bigint}s.
246−
247−@end itemize
248−
249−@section Operators
250−
251−@subsection Arithmetic operators
252−
253−The operands are converted to number values as in normal
254−Javascript. Then the general case is that an Integer is returned if
255−both operands are Integer. Otherwise, a float is returned.
256−
257−The @code{+} operator also accepts strings as input and behaves like
258−standard Javascript in this case.
259−
260−The binary operator @code{%} returns the truncated remainder of the
261−division. When the result is an Integer type, a dividend of zero yields a
262−RangeError exception.
263−
264−The binary operator @code{%} in math mode returns the Euclidian
265−remainder of the division i.e. it is always positive.
266−
267−The binary operator @code{/} returns a float.
268−
269−The binary operator @code{/} in math mode returns a float if one of
270−the operands is float. Otherwise, @code{BigInt[Symbol.operatorDiv]} is
271−invoked.
272−
273−The returned type of @code{a ** b} is Float if @math{a} or @math{b}
274−are Float. If @math{a} and @math{b} are integers:
275−@itemize
276−@item @math{b < 0} returns a Float in bigint mode. In math mode, @code{BigInt[Symbol.operatorPow]} is invoked.
277−
278−@item @math{b >= 0} returns an integer.
27968 @end itemize
28069
281−The unary @code{-} and unary @code{+} return the same type as their
282−operand. They performs no floating point rounding when the result is a
283−float.
284−
285−The unary operators @code{++} and @code{--} return the same type as
286−their operand.
287−
288−In standard mode:
289−
290−If the operator returns an Integer and that the result fits a
291−SmallInt, it is converted to SmallInt. Otherwise, the Integer is
292−converted to a Float.
293−
294−In bigint mode:
295−
296−If the operator returns an Integer and that the result fits a
297−SmallInt, it is converted to SmallInt. Otherwise it is a BigInt.
298−
299−@subsection Logical operators
300−
301−In standard mode:
302−
303−The operands have their standard behavior. If the result fits a
304−SmallInt it is converted to a SmallInt. Otherwise it is a Float.
305−
306−In bigint mode:
307−
308−The operands are converted to integer values. The floating point
309−values are converted to integer by rounding them to zero.
310−
311−The logical operators are defined assuming the integers are
312−represented in two complement notation.
313−
314−For @code{<<} and @code{<<}, the shift can be positive or negative. So
315−@code{a << b} is defined as @math{\lfloor a/2^{-b} \rfloor} and
316−@code{a >> b} is defined as @math{\lfloor a/2^{b} \rfloor}.
317−
318−The operator @code{>>>} is supported for backward compatibility and
319−behaves the same way as Javascript i.e. implicit conversion to @code{Uint32}.
70+@chapter BigInt extensions
32071
321−If the result fits a SmallInt it is converted to a SmallInt. Otherwise
322−it is a BigInt.
323−
324−@subsection Relational operators
325−
326−The relational operators <, <=, >, >=, ==, != work as expected with
327−integers and floating point numbers (e.g. @code{1.0 == 1} is true).
328−
329−The strict equality operators === and !== have the usual Javascript
330−semantics. In particular, different types never equal, so @code{1.0
331−=== 1} is false.
332−
333−@section Number literals
334−
335−Number literals in bigint mode have a slightly different behavior than
336−in standard Javascript:
337−
338−@enumerate
339−
340−@item
341−A number literal without a decimal point or an exponent is considered
342−as an Integer. Otherwise it is a Float.
343−
344−@item
345−Hexadecimal, octal or binary floating point literals are accepted with
346−a decimal point or an exponent. The exponent is specified with the
347−@code{p} letter assuming a base 2. The same convention is used by
348−C99. Example: @code{0x1p3} is the same as @code{8.0}.
349−
350−@end enumerate
351−
352−@section Builtin Object changes
353−
354−@subsection @code{BigInt} function
355−
356−The @code{BigInt} function cannot be invoked as a constructor. When
357−invoked as a function, it converts its first parameter to an
358−integer. When a floating point number is given as parameter, it is
359−truncated to an integer with infinite precision.
360−
361−@code{BigInt} properties:
72+A few properties are added to the BigInt object:
36273
36374 @table @code
36475
365−@item asIntN(bits, a)
366−Set @math{b=a \pmod{2^{bits}}}. Return @math{b} if @math{b < 2^{bits-1}}
367−otherwise @math{b-2^{bits}}.
368−
369−@item asUintN(bits, a)
370−Return @math{a \pmod{2^{bits}}}.
371−
37276 @item tdiv(a, b)
37377 Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError
37478 exception.
@@ -410,58 +114,7 @@ Return the number of trailing zeros in the two's complement binary representatio · 35 unmodified lines
410114
411115 @end table
412116
413−@subsection @code{BigInt.prototype}
414−
415−It is a normal object.
416−
417−@subsection @code{Number} constructor
418−
419−The number constructor returns its argument rounded to a Float using
420−the global floating point environment. In bigint mode, the Number
421−constructor returns a Float. In standard mode, it returns a SmallInt
422−if the value fits it, otherwise a Float.
423−
424−@subsection @code{Number.prototype}
425−
426−The following properties are modified:
427−
428−@table @code
429−@item toString(radix)
430−
431−In bigint mode, integers are converted to the specified radix with
432−infinite precision.
433−
434−@item toPrecision(p)
435−@item toFixed(p)
436−@item toExponential(p)
437−
438−In bigint mode, integers are accepted and converted to string with
439−infinite precision.
440−
441−@item parseInt(string, radix)
442−
443−In bigint mode, an integer is returned and the conversion is done with
444−infinite precision.
445−
446−@end table
447−
448−@subsection @code{Math} object
449−
450−The following properties are modified:
451−
452−@table @code
453−@item abs(x)
454−Absolute value. Return an integer if @code{x} is an Integer. Otherwise
455−return a Float. No rounding is performed.
456−
457−@item min(a, b)
458−@item max(a, b)
459−No rounding is performed. The returned type is the same one as the
460−minimum (resp. maximum) value.
461−
462−@end table
463−
464−@chapter Arbitrarily large floating point numbers
117+@chapter BigFloat
465118
466119 @section Introduction
467120
@@ -590,6 +243,9 @@ point number @code{a} according to the floating point environment · 122 unmodified lines
590243 @item trunc(x)
591244 Round to an integer. No additional rounding is performed.
592245
246+@item abs(x)
247+Return the absolute value of x. No additional rounding is performed.
248+
593249 @item fmod(x, y[, e])
594250 @item remainder(x, y[, e])
595251 Floating point remainder. The quotient is truncated to zero (fmod) or
@@ -620,6 +276,9 @@ number. @code{e} is an optional floating point environment. · 24 unmodified lines
620276 The following properties are modified:
621277
622278 @table @code
279+@item valueOf()
280+Return the bigfloat primitive value corresponding to @code{this}.
281+
623282 @item toString(radix)
624283
625284 For floating point numbers:
@@ -636,13 +295,16 @@ the global precision and round to nearest gives the same number. · 10 unmodified lines
636295
637296 @end itemize
638297
639−@item toPrecision(p[, rnd_mode])
640−@item toFixed(p[, rnd_mode])
641−@item toExponential(p[, rnd_mode])
298+The exponent letter is @code{e} for base 10, @code{p} for bases 2, 8,
299+16 with a binary exponent and @code{@@} for the other bases.
300+
301+@item toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
302+@item toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
303+@item toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
642304 Same semantics as the corresponding @code{Number} functions with
643305 BigFloats. There is no limit on the accepted precision @code{p}. The
644−rounding mode can be optionally specified. It is set by default to
645−@code{BigFloatEnv.RNDNA}.
306+rounding mode and radix can be optionally specified. The radix must be
307+between 2 and 36.
646308
647309 @end table
648310
@@ -679,13 +341,13 @@ subnormal flags is set to @code{false}. If @code{rndMode} is · 30 unmodified lines
679341
680342 @item prec
681343 Getter. Return the precision in bits of the global floating point
682−environment. The initial value is @code{53}.
344+environment. The initial value is @code{113}.
683345
684346 @item expBits
685347 Getter. Return the exponent size in bits of the global floating point
686348 environment assuming an IEEE 754 representation. If @code{expBits <
687349 expBitsMax}, then subnormal numbers are supported. The initial value
688−is @code{11}.
350+is @code{15}.
689351
690352 @item setPrec(f, p[, e])
691353 Set the precision of the global floating point environment to @code{p}
@@ -693,15 +355,13 @@ and the exponent size to @code{e} then call the function · 1 unmodified line
693355 @code{f}. Then the Float precision and exponent size are reset to
694356 their precious value and the return value of @code{f} is returned (or
695357 an exception is raised if @code{f} raised an exception). If @code{e}
696−is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}. @code{p}
697−must be >= 53 and @code{e} must be >= 11 so that the global precision
698−is at least equivalent to the IEEE 754 64 bit doubles.
358+is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}.
699359
700360 @item precMin
701361 Read-only integer. Return the minimum allowed precision. Must be at least 2.
702362
703363 @item precMax
704−Read-only integer. Return the maximum allowed precision. Must be at least 53.
364+Read-only integer. Return the maximum allowed precision. Must be at least 113.
705365
706366 @item expBitsMin
707367 Read-only integer. Return the minimum allowed exponent size in
@@ -709,7 +369,7 @@ bits. Must be at least 3. · 1 unmodified line
709369
710370 @item expBitsMax
711371 Read-only integer. Return the maximum allowed exponent size in
712−bits. Must be at least 11.
372+bits. Must be at least 15.
713373
714374 @item RNDN
715375 Read-only integer. Round to nearest, with ties to even rounding mode.
@@ -726,8 +386,8 @@ Read-only integer. Round to +Infinity rounding mode. · 10 unmodified lines
726386 @item RNDNA
727387 Read-only integer. Round to nearest, with ties away from zero rounding mode.
728388
729−@item RNDNU
730−Read-only integer. Round to nearest, with ties to +Infinity rounding mode.
389+@item RNDA
390+Read-only integer. Round away from zero rounding mode.
731391
732392 @item RNDF@footnote{Could be removed in case a deterministic behavior for floating point operations is required.}
733393 Read-only integer. Faithful rounding mode. The result is
@@ -767,69 +427,166 @@ Getter and setter (Boolean). Status flags. · 33 unmodified lines
767427
768428 @end table
769429
770−@subsection @code{Math} object
430+@chapter BigDecimal
771431
772−The following properties are modified:
432+This extension adds the @code{BigDecimal} primitive type. The
433+@code{BigDecimal} type represents floating point numbers in base
434+10. It is inspired from the proposal available at
435+@url{https://github.com/littledan/proposal-bigdecimal}.
436+
437+The @code{BigDecimal} floating point numbers are always normalized and
438+finite. There is no concept of @code{-0}, @code{Infinity} or
439+@code{NaN}. By default, all the computations are done with infinite
440+precision.
441+
442+@section Operators
443+
444+The following builtin operators support BigDecimal:
773445
774446 @table @code
775−@item abs(x)
776−Absolute value. If @code{x} is a BigFloat, its absolute value is
777−returned as a BigFloat. No rounding is performed.
778447
779−@item min(a, b)
780−@item max(a, b)
781−The returned type is the same one as the minimum (resp. maximum)
782−value, so @code{BigFloat} values are accepted. When a @code{BigFloat}
783−is returned, no rounding is performed.
448+@item +
449+@item -
450+@item *
451+Both operands must be BigDecimal. The result is computed with infinite
452+precision.
453+@item %
454+Both operands must be BigDecimal. The result is computed with infinite
455+precision. A range error is throws in case of division by zero.
784456
785−@end table
457+@item /
458+Both operands must be BigDecimal. A range error is throws in case of
459+division by zero or if the result cannot be represented with infinite
460+precision (use @code{BigDecimal.div} to specify the rounding).
786461
787−@chapter Math mode
462+@item **
463+Both operands must be BigDecimal. The exponent must be a positive
464+integer. The result is computed with infinite precision.
788465
789−@section Introduction
466+@item ===
467+When one of the operand is a BigDecimal, return true if both operands
468+are a BigDecimal and if they are equal.
790469
791−A new @emph{math mode} is enabled with the @code{"use math"}
792−directive. @code{"use bigint"} is implied in math mode. With this
793−mode, writing mathematical expressions is more intuitive, exact
794−results (e.g. fractions) can be computed for all operators and floating
795−point literals have the @code{BigFloat} type by default.
470+@item ==
471+@item !=
472+@item <=
473+@item >=
474+@item <
475+@item >
796476
797−It propagates the same way as the @emph{strict mode}. In
798−this mode:
477+Numerical comparison. When one of the operand is not a BigDecimal, it is
478+converted to BigDecimal by using ToString(). Hence comparisons between
479+Number and BigDecimal do not use the exact mathematical value of the
480+Number value.
799481
800−@itemize
482+@end table
801483
802−@item The @code{^} operator is a similar to the power operator (@code{**}).
484+@section BigDecimal literals
803485
804−@item The power operator (both @code{^} and @code{**}) grammar is modified so that @code{-2^2} is allowed and yields @code{-4}.
486+BigDecimal literals are decimal floating point numbers with a trailing
487+@code{m} suffix.
805488
806−@item The logical xor operator is still available with the @code{^^} operator.
489+@section Builtin Object changes
807490
808−@item The division operator invokes @code{BigInt[Symbol.operatorDiv]} in case both operands are integers.
491+@subsection The @code{BigDecimal} function.
809492
810−@item The power operator invokes @code{BigInt[Symbol.operatorPow]} in case both operands are integers and the exponent is strictly negative.
493+It returns @code{0m} if no parameter is provided. Otherwise the first
494+parameter is converted to a bigdecimal by using ToString(). Hence
495+Number value are not converted to their exact numerical value as
496+BigDecimal.
811497
812−@item The modulo operator returns the Euclidian remainder (always positive) instead of the truncated remainder.
498+@subsection Properties of the @code{BigDecimal} object
813499
814−@item Floating point literals are @code{BigFloat} by default (i.e. a @code{l} suffix is implied).
500+@table @code
815501
816−@end itemize
502+@item add(a, b[, e])
503+@item sub(a, b[, e])
504+@item mul(a, b[, e])
505+@item div(a, b[, e])
506+@item mod(a, b[, e])
507+@item sqrt(a, e)
508+@item round(a, e)
509+Perform the specified floating point operation and round the floating
510+point result according to the rounding object @code{e}. If the
511+rounding object is not present, the operation is executed with
512+infinite precision.
817513
818−@section Builtin Object changes
514+For @code{div}, a @code{RangeError} exception is thrown in case of
515+division by zero or if the result cannot be represented with infinite
516+precision if no rounding object is present.
517+
518+For @code{sqrt}, a range error is thrown if @code{a} is less than
519+zero.
520+
521+The rounding object must contain the following properties:
522+@code{roundingMode} is a string specifying the rounding mode
523+(@code{"floor"}, @code{"ceiling"}, @code{"down"}, @code{"up"},
524+@code{"half-even"}, @code{"half-up"}). Either
525+@code{maximumSignificantDigits} or @code{maximumFractionDigits} must
526+be present to specify respectively the number of significant digits
527+(must be >= 1) or the number of digits after the decimal point (must
528+be >= 0).
819529
820−@subsection @code{Symbol} constructor
530+@end table
531+
532+@subsection Properties of the @code{BigDecimal.prototype} object
821533
822−The following global symbol is added for the operator overloading:
823534 @table @code
824−@item operatorMathMod
535+@item valueOf()
536+Return the bigdecimal primitive value corresponding to @code{this}.
537+
538+@item toString()
539+Convert @code{this} to a string with infinite precision in base 10.
540+
541+@item toPrecision(p, rnd_mode = "half-up")
542+@item toFixed(p, rnd_mode = "half-up")
543+@item toExponential(p, rnd_mode = "half-up")
544+Convert the BigDecimal @code{this} to string with the specified
545+precision @code{p}. There is no limit on the accepted precision
546+@code{p}. The rounding mode can be optionally
547+specified. @code{toPrecision} outputs either in decimal fixed notation
548+or in decimal exponential notation with a @code{p} digits of
549+precision. @code{toExponential} outputs in decimal exponential
550+notation with @code{p} digits after the decimal point. @code{toFixed}
551+outputs in decimal notation with @code{p} digits after the decimal
552+point.
553+
825554 @end table
826555
827−@section Remaining issues
556+@chapter Math mode
828557
829−@enumerate
558+A new @emph{math mode} is enabled with the @code{"use math"}
559+directive. It propagates the same way as the @emph{strict mode}. It is
560+designed so that arbitrarily large integers and floating point numbers
561+are available by default. In order to minimize the number of changes
562+in the Javascript semantics, integers are represented either as Number
563+or BigInt depending on their magnitude. Floating point numbers are
564+always represented as BigFloat.
565+
566+The following changes are made to the Javascript semantics:
830567
831−@item A new floating point literal suffix could be added for @code{Number} literals.
568+@itemize
832569
833−@end enumerate
570+@item Floating point literals (i.e. number with a decimal point or an exponent) are @code{BigFloat} by default (i.e. a @code{l} suffix is implied). Hence @code{typeof 1.0 === "bigfloat"}.
571+
572+@item Integer literals (i.e. numbers without a decimal point or an exponent) with or without the @code{n} suffix are @code{BigInt} if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to @code{2**53-1}. Hence @code{typeof 1 === "number "}, @code{typeof 1n === "number"} but @code{typeof 9007199254740992 === "bigint" }.
573+
574+@item All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt.
575+
576+@item The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result.
577+
578+@item The @code{^} operator is an alias to the power operator (@code{**}).
579+
580+@item The power operator (both @code{^} and @code{**}) grammar is modified so that @code{-2^2} is allowed and yields @code{-4}.
581+
582+@item The logical xor operator is still available with the @code{^^} operator.
583+
584+@item The integer division operator can be overloaded by modifying the corresponding operator in @code{BigInt.prototype.[[OperatorSet]]}.
585+
586+@item The integer power operator with a non zero negative exponent can be overloaded by modifying the corresponding operator in @code{BigInt.prototype.[[OperatorSet]]}.
587+
588+@item The modulo operator (@code{%}) returns the Euclidian remainder (always positive) instead of the truncated remainder.
589+
590+@end itemize
834591
835592 @bye
doc/quickjs.html+12−3
@@ -1,7 +1,8 @@
11 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
22 <html>
3−<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
3+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
44 <head>
5+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
56 <title>QuickJS Javascript Engine</title>
67
78 <meta name="description" content="QuickJS Javascript Engine">
@@ -9,7 +10,6 @@ · 1 unmodified line
910 <meta name="resource-type" content="document">
1011 <meta name="distribution" content="global">
1112 <meta name="Generator" content="makeinfo">
12−<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
1313 <link href="#SEC_Contents" rel="contents" title="Table of Contents">
1414 <style type="text/css">
1515 <!--
@@ -206,7 +206,7 @@ Javascript files and/or expressions as arguments to execute them: · 190 unmodified lines
206206 <a name="qjs-interpreter"></a>
207207 <h4 class="subsection">2.3.1 <code>qjs</code> interpreter</h4>
208208
209−<pre class="verbatim">usage: qjs [options] [files]
209+<pre class="verbatim">usage: qjs [options] [file [args]]
210210 </pre>
211211 <p>Options are:
212212 </p><dl compact="compact">
@@ -241,6 +241,11 @@ source is <code>import</code>. · 28 unmodified lines
241241 the <code>&quot;use bigint&quot;</code> and <code>&quot;use math&quot;</code> directives.
242242 </p>
243243 </dd>
244+<dt><code>-I file</code></dt>
245+<dt><code>--include file</code></dt>
246+<dd><p>Include an additional file.
247+</p>
248+</dd>
244249 </dl>
245250
246251 <p>Advanced options are:
@@ -767,6 +772,10 @@ pathname of <code>path</code> and <code>err</code> the error code. · 520 unmodified lines
767772 and <code>err</code> the error code.
768773 </p>
769774 </dd>
775+<dt><code>chdir(path)</code></dt>
776+<dd><p>Change the current directory. Return the error code.
777+</p>
778+</dd>
770779 <dt><code>mkdir(path, mode = 0o777)</code></dt>
771780 <dd><p>Create a directory at <code>path</code>. Return the error code.
772781 </p>
doc/quickjs.pdf+0−0

Binary file not shown.

doc/quickjs.texi+8−1
@@ -92,7 +92,7 @@ generates a @code{hello} executable with no external dependency. · 91 unmodified lines
9292 @subsection @code{qjs} interpreter
9393
9494 @verbatim
95−usage: qjs [options] [files]
95+usage: qjs [options] [file [args]]
9696 @end verbatim
9797
9898 Options are:
@@ -122,6 +122,10 @@ Load as ES6 script (default=autodetect). · 23 unmodified lines
122122 Enable the bignum extensions: BigDecimal object, BigFloat object and
123123 the @code{"use bigint"} and @code{"use math"} directives.
124124
125+@item -I file
126+@item --include file
127+Include an additional file.
128+
125129 @end table
126130
127131 Advanced options are:
@@ -576,6 +580,9 @@ pathname of @code{path} and @code{err} the error code. · 448 unmodified lines
576580 Return @code{[str, err]} where @code{str} is the current working directory
577581 and @code{err} the error code.
578582
583+@item chdir(path)
584+Change the current directory. Return the error code.
585+
579586 @item mkdir(path, mode = 0o777)
580587 Create a directory at @code{path}. Return the error code.
581588
examples/pi_bigdecimal.js+8−10
@@ -6,10 +6,10 @@ · 5 unmodified lines
66
77 /* compute PI with a precision of 'prec' digits */
88 function calc_pi(prec) {
9− const CHUD_A = 13591409d;
10− const CHUD_B = 545140134d;
11− const CHUD_C = 640320d;
12− const CHUD_C3 = 10939058860032000d; /* C^3/24 */
9+ const CHUD_A = 13591409m;
10+ const CHUD_B = 545140134m;
11+ const CHUD_C = 640320m;
12+ const CHUD_C3 = 10939058860032000m; /* C^3/24 */
1313 const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */
1414
1515 /* return [P, Q, G] */
@@ -17,7 +17,7 @@ function calc_pi(prec) { · 1 unmodified line
1717 var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1;
1818 if (a == (b - 1n)) {
1919 b1 = BigDecimal(b);
20− G = (2d * b1 - 1d) * (6d * b1 - 1d) * (6d * b1 - 5d);
20+ G = (2m * b1 - 1m) * (6m * b1 - 1m) * (6m * b1 - 5m);
2121 P = G * (CHUD_B * b1 + CHUD_A);
2222 if (b & 1n)
2323 P = -P;
@@ -32,7 +32,7 @@ function calc_pi(prec) { · 8 unmodified lines
3232 if (need_G)
3333 G = G1 * G2;
3434 else
35− G = 0d;
35+ G = 0m;
3636 }
3737 return [P, Q, G];
3838 }
@@ -44,7 +44,7 @@ function calc_pi(prec) { · 5 unmodified lines
4444 Q = BigDecimal.div(Q, (P + Q * CHUD_A),
4545 { roundingMode: "half-even",
4646 maximumSignificantDigits: prec });
47− G = (CHUD_C / 12d) * BigDecimal.sqrt(CHUD_C,
47+ G = (CHUD_C / 12m) * BigDecimal.sqrt(CHUD_C,
4848 { roundingMode: "half-even",
4949 maximumSignificantDigits: prec });
5050 return Q * G;
@@ -64,7 +64,5 @@ function calc_pi(prec) { · 13 unmodified lines
6464 /* we add more digits to reduce the probability of bad rounding for
6565 the last digits */
6666 r = calc_pi(n_digits + 20);
67− r = BigDecimal.round(r, { roundingMode: "down",
68− maximumFractionDigits: n_digits })
69− print(r);
67+ print(r.toFixed(n_digits, "down"));
7068 })();
libbf.c+677−439
@@ -86,7 +86,6 @@ static no_inline int fft_mul(bf_context_t *s, · 85 unmodified lines
8686 static void fft_clear_cache(bf_context_t *s);
8787 #endif
8888 #ifdef USE_BF_DEC
89−static void mp_pow_init(void);
9089 static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos);
9190 #endif
9291
@@ -154,6 +153,17 @@ static inline limb_t smod(slimb_t a, slimb_t b) · 61 unmodified lines
154153 return a;
155154 }
156155
156+/* signed addition with saturation */
157+static inline slimb_t sat_add(slimb_t a, slimb_t b)
158+{
159+ slimb_t r;
160+ r = a + b;
161+ /* overflow ? */
162+ if (((a ^ r) & (b ^ r)) < 0)
163+ r = (a >> (LIMB_BITS - 1)) ^ (((limb_t)1 << (LIMB_BITS - 1)) - 1);
164+ return r;
165+}
166+
157167 #define malloc(s) malloc_is_forbidden(s)
158168 #define free(p) free_is_forbidden(p)
159169 #define realloc(p, s) realloc_is_forbidden(p, s)
@@ -164,9 +174,6 @@ void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func, · 4 unmodified lines
164174 memset(s, 0, sizeof(*s));
165175 s->realloc_func = realloc_func;
166176 s->realloc_opaque = realloc_opaque;
167−#ifdef USE_BF_DEC
168− mp_pow_init();
169−#endif
170177 }
171178
172179 void bf_context_end(bf_context_t *s)
@@ -422,18 +429,13 @@ static int bf_get_rnd_add(int *pret, const bf_t *r, limb_t l, · 249 unmodified lines
422429 if (r->sign == (rnd_mode == BF_RNDD))
423430 add_one = inexact;
424431 break;
432+ case BF_RNDA:
433+ add_one = inexact;
434+ break;
425435 case BF_RNDNA:
426436 case BF_RNDF:
427437 add_one = bit1;
428438 break;
429− case BF_RNDNU:
430− if (bit1) {
431− if (r->sign)
432− add_one = bit0;
433− else
434− add_one = 1;
435− }
436− break;
437439 default:
438440 abort();
439441 }
@@ -452,7 +454,7 @@ static int bf_set_overflow(bf_t *r, int sign, limb_t prec, bf_flags_t flags) · 12 unmodified lines
452454 if (prec == BF_PREC_INF ||
453455 rnd_mode == BF_RNDN ||
454456 rnd_mode == BF_RNDNA ||
455− rnd_mode == BF_RNDNU ||
457+ rnd_mode == BF_RNDA ||
456458 (rnd_mode == BF_RNDD && sign == 1) ||
457459 (rnd_mode == BF_RNDU && sign == 0)) {
458460 bf_set_inf(r, sign);
@@ -476,12 +478,14 @@ static int bf_set_overflow(bf_t *r, int sign, limb_t prec, bf_flags_t flags) · 17 unmodified lines
476478
477479 /* round to prec1 bits assuming 'r' is non zero and finite. 'r' is
478480 assumed to have length 'l' (1 <= l <= r->len). Note: 'prec1' can be
479− infinite (BF_PREC_INF). Can fail with BF_ST_MEM_ERROR in case of
481+ infinite (BF_PREC_INF). 'ret' is 0 or BF_ST_INEXACT if the result
482+ is known to be inexact. Can fail with BF_ST_MEM_ERROR in case of
480483 overflow not returning infinity. */
481−static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l)
484+static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l,
485+ int ret)
482486 {
483487 limb_t v, a;
484− int shift, add_one, ret, rnd_mode;
488+ int shift, add_one, rnd_mode;
485489 slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;
486490
487491 /* e_min and e_max are computed to match the IEEE 754 conventions */
@@ -506,7 +510,6 @@ static int __bf_round(bf_t *r, limb_t prec1, bf_flags_t flags, limb_t l) · 18 unmodified lines
506510
507511 /* round to prec bits */
508512 rnd_mode = flags & BF_RND_MASK;
509− ret = 0;
510513 add_one = bf_get_rnd_add(&ret, r, l, prec, rnd_mode);
511514
512515 if (prec <= 0) {
@@ -615,7 +618,7 @@ int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags) · 102 unmodified lines
615618 }
616619 r->expn -= shift;
617620 }
618− ret = __bf_round(r, prec1, flags, l);
621+ ret = __bf_round(r, prec1, flags, l, 0);
619622 }
620623 // bf_print_str("r_final", r);
621624 return ret;
@@ -638,8 +641,7 @@ int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k) · 16 unmodified lines
638641 }
639642 if (a->expn == BF_EXP_ZERO)
640643 return FALSE;
641− is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA ||
642− rnd_mode == BF_RNDNU);
644+ is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
643645 if (k < (prec + 2))
644646 return FALSE;
645647 bit_pos = a->len * LIMB_BITS - 1 - prec;
@@ -666,7 +668,7 @@ int bf_round(bf_t *r, limb_t prec, bf_flags_t flags) · 20 unmodified lines
666668 {
667669 if (r->len == 0)
668670 return 0;
669− return __bf_round(r, prec, flags, r->len);
671+ return __bf_round(r, prec, flags, r->len, 0);
670672 }
671673
672674 /* for debugging */
@@ -780,51 +782,26 @@ int bf_cmp_full(const bf_t *a, const bf_t *b) · 107 unmodified lines
780782 return res;
781783 }
782784
783−#define BF_CMP_EQ 1
784−#define BF_CMP_LT 2
785−#define BF_CMP_LE 3
786−
787−static int bf_cmp(const bf_t *a, const bf_t *b, int op)
785+/* Standard floating point comparison: return 2 if one of the operands
786+ is NaN (unordered) or -1, 0, 1 depending on the ordering assuming
787+ -0 == +0 */
788+int bf_cmp(const bf_t *a, const bf_t *b)
788789 {
789− BOOL is_both_zero;
790790 int res;
791791
792− if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN)
793− return 0;
794− if (a->sign != b->sign) {
795− is_both_zero = (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO);
796− if (is_both_zero) {
797− return op & BF_CMP_EQ;
798− } else if (op & BF_CMP_LT) {
799− return a->sign;
800− } else {
801− return FALSE;
802− }
792+ if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
793+ res = 2;
794+ } else if (a->sign != b->sign) {
795+ if (a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO)
796+ res = 0;
797+ else
798+ res = 1 - 2 * a->sign;
803799 } else {
804800 res = bf_cmpu(a, b);
805− if (res == 0) {
806− return op & BF_CMP_EQ;
807− } else if (op & BF_CMP_LT) {
808− return (res < 0) ^ a->sign;
809− } else {
810− return FALSE;
811− }
801+ if (a->sign)
802+ res = -res;
812803 }
813−}
814−
815−int bf_cmp_eq(const bf_t *a, const bf_t *b)
816−{
817− return bf_cmp(a, b, BF_CMP_EQ);
818−}
819−
820−int bf_cmp_le(const bf_t *a, const bf_t *b)
821−{
822− return bf_cmp(a, b, BF_CMP_LE);
823−}
824−
825−int bf_cmp_lt(const bf_t *a, const bf_t *b)
826−{
827− return bf_cmp(a, b, BF_CMP_LT);
804+ return res;
828805 }
829806
830807 /* Compute the number of bits 'n' matching the pattern:
@@ -1631,11 +1608,11 @@ int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags) · 800 unmodified lines
16311608 slimb_t e_max;
16321609 if (r->len == 0)
16331610 return 0;
1634− e_max = ((limb_t)1 << BF_EXP_BITS_MAX) - 1;
1611+ e_max = ((limb_t)1 << BF_EXT_EXP_BITS_MAX) - 1;
16351612 e = bf_max(e, -e_max);
16361613 e = bf_min(e, e_max);
16371614 r->expn += e;
1638− return __bf_round(r, prec, flags, r->len);
1615+ return __bf_round(r, prec, flags, r->len, 0);
16391616 }
16401617
16411618 /* Return e such as a=m*2^e with m odd integer. return 0 if a is zero,
@@ -1777,8 +1754,7 @@ int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, · 135 unmodified lines
17771754 }
17781755
17791756 q_sign = a->sign ^ b->sign;
1780− is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA ||
1781− rnd_mode == BF_RNDNU);
1757+ is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
17821758 switch(rnd_mode) {
17831759 default:
17841760 case BF_RNDZ:
@@ -1792,12 +1768,12 @@ int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, · 7 unmodified lines
17921768 case BF_RNDU:
17931769 is_ceil = q_sign ^ 1;
17941770 break;
1771+ case BF_RNDA:
1772+ is_ceil = TRUE;
1773+ break;
17951774 case BF_DIVREM_EUCLIDIAN:
17961775 is_ceil = a->sign;
17971776 break;
1798− case BF_RNDNU:
1799− /* XXX: unsupported yet */
1800− abort();
18011777 }
18021778
18031779 a1->expn = a->expn;
@@ -1845,26 +1821,14 @@ int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, · 41 unmodified lines
18451821 return BF_ST_MEM_ERROR;
18461822 }
18471823
1848−int bf_fmod(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
1849− bf_flags_t flags)
1824+int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
1825+ bf_flags_t flags, int rnd_mode)
18501826 {
18511827 bf_t q_s, *q = &q_s;
18521828 int ret;
18531829
18541830 bf_init(r->ctx, q);
1855− ret = bf_divrem(q, r, a, b, prec, flags, BF_RNDZ);
1856− bf_delete(q);
1857− return ret;
1858−}
1859−
1860−int bf_remainder(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
1861− bf_flags_t flags)
1862−{
1863− bf_t q_s, *q = &q_s;
1864− int ret;
1865−
1866− bf_init(r->ctx, q);
1867− ret = bf_divrem(q, r, a, b, prec, flags, BF_RNDN);
1831+ ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);
18681832 bf_delete(q);
18691833 return ret;
18701834 }
@@ -1879,13 +1843,13 @@ static inline int bf_get_limb(slimb_t *pres, const bf_t *a, int flags) · 8 unmodified lines
18791843 }
18801844
18811845 int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
1882− bf_flags_t flags)
1846+ bf_flags_t flags, int rnd_mode)
18831847 {
18841848 bf_t q_s, *q = &q_s;
18851849 int ret;
18861850
18871851 bf_init(r->ctx, q);
1888− ret = bf_divrem(q, r, a, b, prec, flags, BF_RNDN);
1852+ ret = bf_divrem(q, r, a, b, prec, flags, rnd_mode);
18891853 bf_get_limb(pq, q, BF_GET_INT_MOD);
18901854 bf_delete(q);
18911855 return ret;
@@ -2791,14 +2755,14 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, · 899 unmodified lines
27912755 /* XXX: correct overflow/underflow handling */
27922756 /* XXX: rigorous error analysis needed */
27932757 extra_bits = ceil_log2(e) * 2 + 1;
2794− ret = bf_pow_ui_ui(B, radix, e, prec1 + extra_bits, BF_RNDN);
2758+ ret = bf_pow_ui_ui(B, radix, e, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
27952759 overflow = !bf_is_finite(B);
27962760 /* XXX: if bf_pow_ui_ui returns an exact result, can stop
27972761 after the next operation */
27982762 if (expn_sign)
2799− ret |= bf_div(r, T, B, prec1 + extra_bits, BF_RNDN);
2763+ ret |= bf_div(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
28002764 else
2801− ret |= bf_mul(r, T, B, prec1 + extra_bits, BF_RNDN);
2765+ ret |= bf_mul(r, T, B, prec1 + extra_bits, BF_RNDN | BF_FLAG_EXT_EXP);
28022766 if (ret & BF_ST_MEM_ERROR)
28032767 break;
28042768 if ((ret & BF_ST_INEXACT) &&
@@ -2807,6 +2771,8 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, · 2 unmodified lines
28072771 /* and more precision and retry */
28082772 ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);
28092773 } else {
2774+ /* XXX: need to use __bf_round() to pass the inexact
2775+ flag for the subnormal case */
28102776 ret = bf_round(r, prec, flags) | (ret & BF_ST_INEXACT);
28112777 break;
28122778 }
@@ -3062,7 +3028,7 @@ static int bf_atof_internal(bf_t *r, slimb_t *pexponent, · 249 unmodified lines
30623028 c = to_digit(*p);
30633029 if (c >= 10)
30643030 break;
3065− if (unlikely(expn > ((EXP_MAX - 2 - 9) / 10))) {
3031+ if (unlikely(expn > ((BF_RAW_EXP_MAX - 2 - 9) / 10))) {
30663032 /* exponent overflow */
30673033 if (exp_is_neg) {
30683034 bf_set_zero(r, is_neg);
@@ -3501,11 +3467,14 @@ static int bf_convert_to_radix(bf_t *r, slimb_t *pE, · 432 unmodified lines
35013467 prec = prec0 + ziv_extra_bits;
35023468 /* XXX: rigorous error analysis needed */
35033469 extra_bits = ceil_log2(e) * 2 + 1;
3504− ret = bf_pow_ui_ui(r, radix, e, prec + extra_bits, BF_RNDN);
3470+ ret = bf_pow_ui_ui(r, radix, e, prec + extra_bits,
3471+ BF_RNDN | BF_FLAG_EXT_EXP);
35053472 if (!e_sign)
3506− ret |= bf_mul(r, r, a, prec + extra_bits, BF_RNDN);
3473+ ret |= bf_mul(r, r, a, prec + extra_bits,
3474+ BF_RNDN | BF_FLAG_EXT_EXP);
35073475 else
3508− ret |= bf_div(r, a, r, prec + extra_bits, BF_RNDN);
3476+ ret |= bf_div(r, a, r, prec + extra_bits,
3477+ BF_RNDN | BF_FLAG_EXT_EXP);
35093478 if (ret & BF_ST_MEM_ERROR)
35103479 return BF_ST_MEM_ERROR;
35113480 /* if the result is not exact, check that it can be safely
@@ -3605,7 +3574,15 @@ static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits, · 93 unmodified lines
36053574 pos = a->len;
36063575 pos_incr = 1;
36073576 first_buf_pos = 0;
3608− } else if ((radix & (radix - 1)) != 0) {
3577+ } else if ((radix & (radix - 1)) == 0) {
3578+ a = (bf_t *)a1;
3579+ radix_bits = ceil_log2(radix);
3580+ digits_per_limb = LIMB_BITS / radix_bits;
3581+ pos_incr = digits_per_limb * radix_bits;
3582+ /* digits are aligned relative to the radix point */
3583+ pos = a->len * LIMB_BITS + smod(-a->expn, radix_bits);
3584+ first_buf_pos = 0;
3585+ } else {
36093586 limb_t n, radixl;
36103587
36113588 digits_per_limb = digits_per_limb_table[radix - 2];
@@ -3619,13 +3596,6 @@ static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits, · 7 unmodified lines
36193596 pos = n;
36203597 pos_incr = 1;
36213598 first_buf_pos = pos * digits_per_limb - n_digits;
3622− } else {
3623− a = (bf_t *)a1;
3624− radix_bits = ceil_log2(radix);
3625− digits_per_limb = LIMB_BITS / radix_bits;
3626− pos_incr = digits_per_limb * radix_bits;
3627− pos = a->len * LIMB_BITS - a->expn + n_digits * radix_bits;
3628− first_buf_pos = 0;
36293599 }
36303600 buf_pos = digits_per_limb;
36313601 i = 0;
@@ -3668,12 +3638,13 @@ static void *bf_dbuf_realloc(void *opaque, void *ptr, size_t size) · 36 unmodified lines
36683638 static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix,
36693639 limb_t prec, bf_flags_t flags, BOOL is_dec)
36703640 {
3641+ bf_context_t *ctx = a2->ctx;
36713642 DynBuf s_s, *s = &s_s;
36723643 int radix_bits;
36733644
36743645 // bf_print_str("ftoa", a2);
36753646 // printf("radix=%d\n", radix);
3676− dbuf_init2(s, a2->ctx, bf_dbuf_realloc);
3647+ dbuf_init2(s, ctx, bf_dbuf_realloc);
36773648 if (a2->expn == BF_EXP_NAN) {
36783649 dbuf_putstr(s, "NaN");
36793650 } else {
@@ -3687,77 +3658,160 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, · 7 unmodified lines
36873658 } else {
36883659 int fmt, ret;
36893660 slimb_t n_digits, n, i, n_max, n1;
3690− bf_t a1_s, *a1;
3691− bf_t a_s, *a = &a_s;
3692−
3693− /* make a positive number */
3694− a->tab = a2->tab;
3695− a->len = a2->len;
3696− a->expn = a2->expn;
3697− a->sign = 0;
3698−
3661+ bf_t a1_s, *a1 = &a1_s;
3662+
36993663 if ((radix & (radix - 1)) != 0)
37003664 radix_bits = 0;
37013665 else
37023666 radix_bits = ceil_log2(radix);
37033667
37043668 fmt = flags & BF_FTOA_FORMAT_MASK;
3705− a1 = &a1_s;
3706− bf_init(a2->ctx, a1);
3669+ bf_init(ctx, a1);
37073670 if (fmt == BF_FTOA_FORMAT_FRAC) {
3708− size_t pos, start;
3709− assert(!is_dec);
3710− /* one more digit for the rounding */
3711− n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, TRUE, TRUE);
3712− n_digits = n + prec;
3713− n1 = n;
3714− if (bf_convert_to_radix(a1, &n1, a, radix, n_digits,
3715− flags & BF_RND_MASK, TRUE))
3716− goto fail1;
3717− start = s->size;
3718− output_digits(s, a1, radix, n_digits, n, is_dec);
3719− /* remove leading zeros because we allocated one more digit */
3720− pos = start;
3721− while ((pos + 1) < s->size && s->buf[pos] == '0' &&
3722− s->buf[pos + 1] != '.')
3723− pos++;
3724− if (pos > start) {
3725− memmove(s->buf + start, s->buf + pos, s->size - pos);
3726− s->size -= (pos - start);
3671+ if (is_dec || radix_bits != 0) {
3672+ if (bf_set(a1, a2))
3673+ goto fail1;
3674+#ifdef USE_BF_DEC
3675+ if (is_dec) {
3676+ if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)
3677+ goto fail1;
3678+ n = a1->expn;
3679+ } else
3680+#endif
3681+ {
3682+ if (bf_round(a1, prec * radix_bits, (flags & BF_RND_MASK) | BF_FLAG_RADPNT_PREC) & BF_ST_MEM_ERROR)
3683+ goto fail1;
3684+ n = ceil_div(a1->expn, radix_bits);
3685+ }
3686+ if (flags & BF_FTOA_ADD_PREFIX) {
3687+ if (radix == 16)
3688+ dbuf_putstr(s, "0x");
3689+ else if (radix == 8)
3690+ dbuf_putstr(s, "0o");
3691+ else if (radix == 2)
3692+ dbuf_putstr(s, "0b");
3693+ }
3694+ if (a1->expn == BF_EXP_ZERO) {
3695+ dbuf_putstr(s, "0");
3696+ if (prec > 0) {
3697+ dbuf_putstr(s, ".");
3698+ for(i = 0; i < prec; i++) {
3699+ dbuf_putc(s, '0');
3700+ }
3701+ }
3702+ } else {
3703+ n_digits = prec + n;
3704+ if (n <= 0) {
3705+ /* 0.x */
3706+ dbuf_putstr(s, "0.");
3707+ for(i = 0; i < -n; i++) {
3708+ dbuf_putc(s, '0');
3709+ }
3710+ if (n_digits > 0) {
3711+ output_digits(s, a1, radix, n_digits, n_digits, is_dec);
3712+ }
3713+ } else {
3714+ output_digits(s, a1, radix, n_digits, n, is_dec);
3715+ }
3716+ }
3717+ } else {
3718+ size_t pos, start;
3719+ bf_t a_s, *a = &a_s;
3720+
3721+ /* make a positive number */
3722+ a->tab = a2->tab;
3723+ a->len = a2->len;
3724+ a->expn = a2->expn;
3725+ a->sign = 0;
3726+
3727+ /* one more digit for the rounding */
3728+ n = 1 + bf_mul_log2_radix(bf_max(a->expn, 0), radix, TRUE, TRUE);
3729+ n_digits = n + prec;
3730+ n1 = n;
3731+ if (bf_convert_to_radix(a1, &n1, a, radix, n_digits,
3732+ flags & BF_RND_MASK, TRUE))
3733+ goto fail1;
3734+ start = s->size;
3735+ output_digits(s, a1, radix, n_digits, n, is_dec);
3736+ /* remove leading zeros because we allocated one more digit */
3737+ pos = start;
3738+ while ((pos + 1) < s->size && s->buf[pos] == '0' &&
3739+ s->buf[pos + 1] != '.')
3740+ pos++;
3741+ if (pos > start) {
3742+ memmove(s->buf + start, s->buf + pos, s->size - pos);
3743+ s->size -= (pos - start);
3744+ }
37273745 }
37283746 } else {
37293747 #ifdef USE_BF_DEC
37303748 if (is_dec) {
3749+ if (bf_set(a1, a2))
3750+ goto fail1;
37313751 if (fmt == BF_FTOA_FORMAT_FIXED) {
37323752 n_digits = prec;
37333753 n_max = n_digits;
3754+ if (bfdec_round((bfdec_t *)a1, prec, (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)
3755+ goto fail1;
37343756 } else {
37353757 /* prec is ignored */
3736− prec = n_digits = a->len * LIMB_DIGITS;
3737− /* remove trailing zero digits */
3758+ prec = n_digits = a1->len * LIMB_DIGITS;
3759+ /* remove the trailing zero digits */
37383760 while (n_digits > 1 &&
3739− get_digit(a->tab, a->len, prec - n_digits) == 0) {
3761+ get_digit(a1->tab, a1->len, prec - n_digits) == 0) {
37403762 n_digits--;
37413763 }
37423764 n_max = n_digits + 4;
37433765 }
3744− bf_init(a2->ctx, a1);
3745− bf_set(a1, a);
37463766 n = a1->expn;
37473767 } else
37483768 #endif
3749− {
3769+ if (radix_bits != 0) {
3770+ if (bf_set(a1, a2))
3771+ goto fail1;
3772+ if (fmt == BF_FTOA_FORMAT_FIXED) {
3773+ slimb_t prec_bits;
3774+ n_digits = prec;
3775+ n_max = n_digits;
3776+ /* align to the radix point */
3777+ prec_bits = prec * radix_bits -
3778+ smod(-a1->expn, radix_bits);
3779+ if (bf_round(a1, prec_bits,
3780+ (flags & BF_RND_MASK)) & BF_ST_MEM_ERROR)
3781+ goto fail1;
3782+ } else {
3783+ limb_t digit_mask;
3784+ slimb_t pos;
3785+ /* position of the digit before the most
3786+ significant digit in bits */
3787+ pos = a1->len * LIMB_BITS +
3788+ smod(-a1->expn, radix_bits);
3789+ n_digits = ceil_div(pos, radix_bits);
3790+ /* remove the trailing zero digits */
3791+ digit_mask = ((limb_t)1 << radix_bits) - 1;
3792+ while (n_digits > 1 &&
3793+ (get_bits(a1->tab, a1->len, pos - n_digits * radix_bits) & digit_mask) == 0) {
3794+ n_digits--;
3795+ }
3796+ n_max = n_digits + 4;
3797+ }
3798+ n = ceil_div(a1->expn, radix_bits);
3799+ } else {
3800+ bf_t a_s, *a = &a_s;
3801+
3802+ /* make a positive number */
3803+ a->tab = a2->tab;
3804+ a->len = a2->len;
3805+ a->expn = a2->expn;
3806+ a->sign = 0;
3807+
37503808 if (fmt == BF_FTOA_FORMAT_FIXED) {
37513809 n_digits = prec;
37523810 n_max = n_digits;
37533811 } else {
37543812 slimb_t n_digits_max, n_digits_min;
37553813
3756− if (prec == BF_PREC_INF) {
3757− assert(radix_bits != 0);
3758− /* XXX: could use the exact number of bits */
3759− prec = a->len * LIMB_BITS;
3760− }
3814+ assert(prec != BF_PREC_INF);
37613815 n_digits = 1 + bf_mul_log2_radix(prec, radix, TRUE, TRUE);
37623816 /* max number of digits for non exponential
37633817 notation. The rational is to have the same rule
@@ -3771,7 +3825,7 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, · 7 unmodified lines
37713825 /* XXX: inefficient */
37723826 n_digits_max = n_digits;
37733827 n_digits_min = 1;
3774− bf_init(a2->ctx, b);
3828+ bf_init(ctx, b);
37753829 while (n_digits_min < n_digits_max) {
37763830 n_digits = (n_digits_min + n_digits_max) / 2;
37773831 if (bf_convert_to_radix(a1, &n, a, radix, n_digits,
@@ -3869,7 +3923,7 @@ static char *bf_ftoa_internal(size_t *plen, const bf_t *a2, int radix, · 91 unmodified lines
38693923 *plen = s->size - 1;
38703924 return (char *)s->buf;
38713925 fail:
3872− bf_free(a2->ctx, s->buf);
3926+ bf_free(ctx, s->buf);
38733927 if (plen)
38743928 *plen = 0;
38753929 return NULL;
@@ -4035,7 +4089,7 @@ static void bf_const_pi_internal(bf_t *Q, limb_t prec) · 159 unmodified lines
40354089
40364090 static int bf_const_get(bf_t *T, limb_t prec, bf_flags_t flags,
40374091 BFConstCache *c,
4038− void (*func)(bf_t *res, limb_t prec))
4092+ void (*func)(bf_t *res, limb_t prec), int sign)
40394093 {
40404094 limb_t ziv_extra_bits, prec1;
40414095
@@ -4051,6 +4105,7 @@ static int bf_const_get(bf_t *T, limb_t prec, bf_flags_t flags, · 9 unmodified lines
40514105 prec1 = c->prec;
40524106 }
40534107 bf_set(T, &c->val);
4108+ T->sign = sign;
40544109 if (!bf_can_round(T, prec, flags & BF_RND_MASK, prec1)) {
40554110 /* and more precision and retry */
40564111 ziv_extra_bits = ziv_extra_bits + (ziv_extra_bits / 2);
@@ -4070,13 +4125,20 @@ static void bf_const_free(BFConstCache *c) · 13 unmodified lines
40704125 int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags)
40714126 {
40724127 bf_context_t *s = T->ctx;
4073− return bf_const_get(T, prec, flags, &s->log2_cache, bf_const_log2_internal);
4128+ return bf_const_get(T, prec, flags, &s->log2_cache, bf_const_log2_internal, 0);
40744129 }
40754130
4076−int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags)
4131+/* return rounded pi * (1 - 2 * sign) */
4132+static int bf_const_pi_signed(bf_t *T, int sign, limb_t prec, bf_flags_t flags)
40774133 {
40784134 bf_context_t *s = T->ctx;
4079− return bf_const_get(T, prec, flags, &s->pi_cache, bf_const_pi_internal);
4135+ return bf_const_get(T, prec, flags, &s->pi_cache, bf_const_pi_internal,
4136+ sign);
4137+}
4138+
4139+int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags)
4140+{
4141+ return bf_const_pi_signed(T, 0, prec, flags);
40804142 }
40814143
40824144 void bf_clear_cache(bf_context_t *s)
@@ -4126,9 +4188,29 @@ static int bf_ziv_rounding(bf_t *r, const bf_t *a, · 43 unmodified lines
41264188 break;
41274189 }
41284190 ziv_extra_bits = ziv_extra_bits * 2;
4191+ // printf("ziv_extra_bits=%" PRId64 "\n", (int64_t)ziv_extra_bits);
41294192 }
41304193 }
4131− return bf_round(r, prec, flags) | ret;
4194+ if (r->len == 0)
4195+ return ret;
4196+ else
4197+ return __bf_round(r, prec, flags, r->len, ret);
4198+}
4199+
4200+/* add (1 - 2*e_sign) * 2^e */
4201+static int bf_add_epsilon(bf_t *r, const bf_t *a, slimb_t e, int e_sign,
4202+ limb_t prec, int flags)
4203+{
4204+ bf_t T_s, *T = &T_s;
4205+ int ret;
4206+ /* small argument case: result = 1 + epsilon * sign(x) */
4207+ bf_init(a->ctx, T);
4208+ bf_set_ui(T, 1);
4209+ T->sign = e_sign;
4210+ T->expn += e;
4211+ ret = bf_add(r, r, T, prec, flags);
4212+ bf_delete(T);
4213+ return ret;
41324214 }
41334215
41344216 /* Compute the exponential using faithful rounding at precision 'prec'.
@@ -4193,18 +4275,70 @@ static int bf_exp_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 58 unmodified lines
41934275
41944276 /* undo the range reduction */
41954277 for(i = 0; i < K; i++) {
4196− bf_mul(r, r, r, prec1, BF_RNDN);
4278+ bf_mul(r, r, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
41974279 }
41984280
41994281 /* undo the argument reduction */
4200− bf_mul_2exp(r, n, BF_PREC_INF, BF_RNDZ);
4282+ bf_mul_2exp(r, n, BF_PREC_INF, BF_RNDZ | BF_FLAG_EXT_EXP);
42014283
42024284 return BF_ST_INEXACT;
42034285 }
42044286
4287+/* crude overflow and underflow tests for exp(a). a_low <= a <= a_high */
4288+static int check_exp_underflow_overflow(bf_context_t *s, bf_t *r,
4289+ const bf_t *a_low, const bf_t *a_high,
4290+ limb_t prec, bf_flags_t flags)
4291+{
4292+ bf_t T_s, *T = &T_s;
4293+ bf_t log2_s, *log2 = &log2_s;
4294+ slimb_t e_min, e_max;
4295+
4296+ if (a_high->expn <= 0)
4297+ return 0;
4298+
4299+ e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
4300+ e_min = -e_max + 3;
4301+ if (flags & BF_FLAG_SUBNORMAL)
4302+ e_min -= (prec - 1);
4303+
4304+ bf_init(s, T);
4305+ bf_init(s, log2);
4306+ bf_const_log2(log2, LIMB_BITS, BF_RNDU);
4307+ bf_mul_ui(T, log2, e_max, LIMB_BITS, BF_RNDU);
4308+ /* a_low > e_max * log(2) implies exp(a) > e_max */
4309+ if (bf_cmp_lt(T, a_low) > 0) {
4310+ /* overflow */
4311+ bf_delete(T);
4312+ bf_delete(log2);
4313+ return bf_set_overflow(r, 0, prec, flags);
4314+ }
4315+ /* a_high < (e_min - 2) * log(2) implies exp(a) < (e_min - 2) */
4316+ bf_const_log2(log2, LIMB_BITS, BF_RNDD);
4317+ bf_mul_si(T, log2, e_min - 2, LIMB_BITS, BF_RNDD);
4318+ if (bf_cmp_lt(a_high, T)) {
4319+ int rnd_mode = flags & BF_RND_MASK;
4320+
4321+ /* underflow */
4322+ bf_delete(T);
4323+ bf_delete(log2);
4324+ if (rnd_mode == BF_RNDU) {
4325+ /* set the smallest value */
4326+ bf_set_ui(r, 1);
4327+ r->expn = e_min;
4328+ } else {
4329+ bf_set_zero(r, 0);
4330+ }
4331+ return BF_ST_UNDERFLOW | BF_ST_INEXACT;
4332+ }
4333+ bf_delete(log2);
4334+ bf_delete(T);
4335+ return 0;
4336+}
4337+
42054338 int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
42064339 {
42074340 bf_context_t *s = r->ctx;
4341+ int ret;
42084342 assert(r != a);
42094343 if (a->len == 0) {
42104344 if (a->expn == BF_EXP_NAN) {
@@ -4220,48 +4354,15 @@ int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) · 9 unmodified lines
42204354 return 0;
42214355 }
42224356
4223− /* crude overflow and underflow tests */
4224− if (a->expn > 0) {
4225− bf_t T_s, *T = &T_s;
4226− bf_t log2_s, *log2 = &log2_s;
4227− slimb_t e_min, e_max;
4228− e_max = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
4229− e_min = -e_max + 3;
4230− if (flags & BF_FLAG_SUBNORMAL)
4231− e_min -= (prec - 1);
4232−
4233− bf_init(s, T);
4234− bf_init(s, log2);
4235− bf_const_log2(log2, LIMB_BITS, BF_RNDU);
4236− bf_mul_ui(T, log2, e_max, LIMB_BITS, BF_RNDU);
4237− /* a > e_max * log(2) implies exp(a) > e_max */
4238− if (bf_cmp_lt(T, a) > 0) {
4239− /* overflow */
4240− bf_delete(T);
4241− bf_delete(log2);
4242− return bf_set_overflow(r, 0, prec, flags);
4243− }
4244− /* a < e_min * log(2) implies exp(a) < e_min */
4245− bf_mul_si(T, log2, e_min, LIMB_BITS, BF_RNDD);
4246− if (bf_cmp_lt(a, T)) {
4247− int rnd_mode = flags & BF_RND_MASK;
4248−
4249− /* underflow */
4250− bf_delete(T);
4251− bf_delete(log2);
4252− if (rnd_mode == BF_RNDU) {
4253− /* set the smallest value */
4254− bf_set_ui(r, 1);
4255− r->expn = e_min;
4256− } else {
4257− bf_set_zero(r, 0);
4258− }
4259− return BF_ST_UNDERFLOW | BF_ST_INEXACT;
4260− }
4261− bf_delete(log2);
4262− bf_delete(T);
4357+ ret = check_exp_underflow_overflow(s, r, a, a, prec, flags);
4358+ if (ret)
4359+ return ret;
4360+ if (a->expn < 0 && (-a->expn) >= (prec + 2)) {
4361+ /* small argument case: result = 1 + epsilon * sign(x) */
4362+ bf_set_ui(r, 1);
4363+ return bf_add_epsilon(r, r, -(prec + 2), a->sign, prec, flags);
42634364 }
4264−
4365+
42654366 return bf_ziv_rounding(r, a, prec, flags, bf_exp_internal, NULL);
42664367 }
42674368
@@ -4404,7 +4505,6 @@ int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) · 136 unmodified lines
44044505 }
44054506
44064507 /* x and y finite and x > 0 */
4407−/* XXX: overflow/underflow handling */
44084508 static int bf_pow_generic(bf_t *r, const bf_t *x, limb_t prec, void *opaque)
44094509 {
44104510 bf_context_t *s = r->ctx;
@@ -4415,15 +4515,17 @@ static int bf_pow_generic(bf_t *r, const bf_t *x, limb_t prec, void *opaque) · 4 unmodified lines
44154515 bf_init(s, T);
44164516 /* XXX: proof for the added precision */
44174517 prec1 = prec + 32;
4418− bf_log(T, x, prec1, BF_RNDF);
4419− bf_mul(T, T, y, prec1, BF_RNDF);
4420− bf_exp(r, T, prec1, BF_RNDF);
4518+ bf_log(T, x, prec1, BF_RNDF | BF_FLAG_EXT_EXP);
4519+ bf_mul(T, T, y, prec1, BF_RNDF | BF_FLAG_EXT_EXP);
4520+ if (bf_is_nan(T))
4521+ bf_set_nan(r);
4522+ else
4523+ bf_exp_internal(r, T, prec1, NULL); /* no overflow/underlow test needed */
44214524 bf_delete(T);
44224525 return BF_ST_INEXACT;
44234526 }
44244527
44254528 /* x and y finite, x > 0, y integer and y fits on one limb */
4426−/* XXX: overflow/underflow handling */
44274529 static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque)
44284530 {
44294531 bf_context_t *s = r->ctx;
@@ -4438,11 +4540,11 @@ static int bf_pow_int(bf_t *r, const bf_t *x, limb_t prec, void *opaque) · 8 unmodified lines
44384540 y1 = -y1;
44394541 /* XXX: proof for the added precision */
44404542 prec1 = prec + ceil_log2(y1) * 2 + 8;
4441− ret = bf_pow_ui(r, x, y1 < 0 ? -y1 : y1, prec1, BF_RNDN);
4543+ ret = bf_pow_ui(r, x, y1 < 0 ? -y1 : y1, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
44424544 if (y->sign) {
44434545 bf_init(s, T);
44444546 bf_set_ui(T, 1);
4445− ret |= bf_div(r, T, r, prec1, BF_RNDN);
4547+ ret |= bf_div(r, T, r, prec1, BF_RNDN | BF_FLAG_EXT_EXP);
44464548 bf_delete(T);
44474549 }
44484550 return ret;
@@ -4508,7 +4610,7 @@ int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags) · 59 unmodified lines
45084610 int cmp_x_abs_1;
45094611 bf_set_ui(r, 1);
45104612 cmp_x_abs_1 = bf_cmpu(x, r);
4511− if (cmp_x_abs_1 == 0 && (flags & BF_POW_JS_QUICKS) &&
4613+ if (cmp_x_abs_1 == 0 && (flags & BF_POW_JS_QUIRKS) &&
45124614 (y->expn >= BF_EXP_INF)) {
45134615 bf_set_nan(r);
45144616 } else if (cmp_x_abs_1 == 0 &&
@@ -4565,70 +4667,95 @@ int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags) · 50 unmodified lines
45654667 if (bf_cmp_eq(T, r)) {
45664668 /* abs(x) = 1: nothing more to do */
45674669 ret = 0;
4568− } else if (y_is_int) {
4569− slimb_t T_bits, e;
4570− int_pow:
4571− T_bits = T->expn - bf_get_exp_min(T);
4572− if (T_bits == 1) {
4573− /* pow(2^b, y) = 2^(b*y) */
4574− bf_mul_si(T, y, T->expn - 1, LIMB_BITS, BF_RNDZ);
4575− bf_get_limb(&e, T, 0);
4576− bf_set_ui(r, 1);
4577− ret = bf_mul_2exp(r, e, prec, flags);
4578− } else if (prec == BF_PREC_INF) {
4579− slimb_t y1;
4580− /* specific case for infinite precision (integer case) */
4581− bf_get_limb(&y1, y, 0);
4582− assert(!y->sign);
4583− /* x must be an integer, so abs(x) >= 2 */
4584− if (y1 >= ((slimb_t)1 << BF_EXP_BITS_MAX)) {
4585− bf_delete(T);
4586− return bf_set_overflow(r, 0, BF_PREC_INF, flags);
4587− }
4588− ret = bf_pow_ui(r, T, y1, BF_PREC_INF, BF_RNDZ);
4589− } else {
4590− if (y->expn <= 31) {
4591− /* small enough power: use exponentiation in all cases */
4592− } else if (y->sign) {
4593− /* cannot be exact */
4594− goto general_case;
4670+ } else {
4671+ /* check the overflow/underflow cases */
4672+ {
4673+ bf_t al_s, *al = &al_s;
4674+ bf_t ah_s, *ah = &ah_s;
4675+ limb_t precl = LIMB_BITS;
4676+
4677+ bf_init(s, al);
4678+ bf_init(s, ah);
4679+ /* compute bounds of log(abs(x)) * y with a low precision */
4680+ /* XXX: compute bf_log() once */
4681+ /* XXX: add a fast test before this slow test */
4682+ bf_log(al, T, precl, BF_RNDD);
4683+ bf_log(ah, T, precl, BF_RNDU);
4684+ bf_mul(al, al, y, precl, BF_RNDD ^ y->sign);
4685+ bf_mul(ah, ah, y, precl, BF_RNDU ^ y->sign);
4686+ ret = check_exp_underflow_overflow(s, r, al, ah, prec, flags);
4687+ bf_delete(al);
4688+ bf_delete(ah);
4689+ if (ret)
4690+ goto done;
4691+ }
4692+
4693+ if (y_is_int) {
4694+ slimb_t T_bits, e;
4695+ int_pow:
4696+ T_bits = T->expn - bf_get_exp_min(T);
4697+ if (T_bits == 1) {
4698+ /* pow(2^b, y) = 2^(b*y) */
4699+ bf_mul_si(T, y, T->expn - 1, LIMB_BITS, BF_RNDZ);
4700+ bf_get_limb(&e, T, 0);
4701+ bf_set_ui(r, 1);
4702+ ret = bf_mul_2exp(r, e, prec, flags);
4703+ } else if (prec == BF_PREC_INF) {
4704+ slimb_t y1;
4705+ /* specific case for infinite precision (integer case) */
4706+ bf_get_limb(&y1, y, 0);
4707+ assert(!y->sign);
4708+ /* x must be an integer, so abs(x) >= 2 */
4709+ if (y1 >= ((slimb_t)1 << BF_EXP_BITS_MAX)) {
4710+ bf_delete(T);
4711+ return bf_set_overflow(r, 0, BF_PREC_INF, flags);
4712+ }
4713+ ret = bf_pow_ui(r, T, y1, BF_PREC_INF, BF_RNDZ);
45954714 } else {
4596− if (rnd_mode == BF_RNDF)
4597− goto general_case; /* no need to track exact results */
4598− /* see if the result has a chance to be exact:
4599− if x=a*2^b (a odd), x^y=a^y*2^(b*y)
4600− x^y needs a precision of at least floor_log2(a)*y bits
4601− */
4602− bf_mul_si(r, y, T_bits - 1, LIMB_BITS, BF_RNDZ);
4603− bf_get_limb(&e, r, 0);
4604− if (prec < e)
4715+ if (y->expn <= 31) {
4716+ /* small enough power: use exponentiation in all cases */
4717+ } else if (y->sign) {
4718+ /* cannot be exact */
46054719 goto general_case;
4720+ } else {
4721+ if (rnd_mode == BF_RNDF)
4722+ goto general_case; /* no need to track exact results */
4723+ /* see if the result has a chance to be exact:
4724+ if x=a*2^b (a odd), x^y=a^y*2^(b*y)
4725+ x^y needs a precision of at least floor_log2(a)*y bits
4726+ */
4727+ bf_mul_si(r, y, T_bits - 1, LIMB_BITS, BF_RNDZ);
4728+ bf_get_limb(&e, r, 0);
4729+ if (prec < e)
4730+ goto general_case;
4731+ }
4732+ ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_int, (void *)y);
46064733 }
4607− ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_int, (void *)y);
4608− }
4609− } else {
4610− if (rnd_mode != BF_RNDF) {
4611− bf_t *y1;
4612− if (y_emin < 0 && check_exact_power2n(r, T, -y_emin)) {
4613− /* the problem is reduced to a power to an integer */
4734+ } else {
4735+ if (rnd_mode != BF_RNDF) {
4736+ bf_t *y1;
4737+ if (y_emin < 0 && check_exact_power2n(r, T, -y_emin)) {
4738+ /* the problem is reduced to a power to an integer */
46144739 #if 0
4615− printf("\nn=%ld\n", -y_emin);
4616− bf_print_str("T", T);
4617− bf_print_str("r", r);
4740+ printf("\nn=%" PRId64 "\n", -(int64_t)y_emin);
4741+ bf_print_str("T", T);
4742+ bf_print_str("r", r);
46184743 #endif
4619− bf_set(T, r);
4620− y1 = &ytmp_s;
4621− y1->tab = y->tab;
4622− y1->len = y->len;
4623− y1->sign = y->sign;
4624− y1->expn = y->expn - y_emin;
4625− y = y1;
4626− goto int_pow;
4744+ bf_set(T, r);
4745+ y1 = &ytmp_s;
4746+ y1->tab = y->tab;
4747+ y1->len = y->len;
4748+ y1->sign = y->sign;
4749+ y1->expn = y->expn - y_emin;
4750+ y = y1;
4751+ goto int_pow;
4752+ }
46274753 }
4754+ general_case:
4755+ ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_generic, (void *)y);
46284756 }
4629− general_case:
4630− ret = bf_ziv_rounding(r, T, prec, flags, bf_pow_generic, (void *)y);
46314757 }
4758+ done:
46324759 bf_delete(T);
46334760 r->sign = r_sign;
46344761 return ret;
@@ -4649,7 +4776,7 @@ static void bf_sqrt_sin(bf_t *r, const bf_t *x, limb_t prec1) · 14 unmodified lines
46494776 bf_delete(T);
46504777 }
46514778
4652−int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec)
4779+static int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec)
46534780 {
46544781 bf_context_t *s1 = a->ctx;
46554782 bf_t T_s, *T = &T_s;
@@ -4659,27 +4786,6 @@ int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec) · 3 unmodified lines
46594786 int is_neg;
46604787
46614788 assert(c != a && s != a);
4662− if (a->len == 0) {
4663− if (a->expn == BF_EXP_NAN) {
4664− if (c)
4665− bf_set_nan(c);
4666− if (s)
4667− bf_set_nan(s);
4668− return 0;
4669− } else if (a->expn == BF_EXP_INF) {
4670− if (c)
4671− bf_set_nan(c);
4672− if (s)
4673− bf_set_nan(s);
4674− return BF_ST_INVALID_OP;
4675− } else {
4676− if (c)
4677− bf_set_ui(c, 1);
4678− if (s)
4679− bf_set_zero(s, a->sign);
4680− return 0;
4681− }
4682− }
46834789
46844790 bf_init(s1, T);
46854791 bf_init(s1, U);
@@ -4699,10 +4805,10 @@ int bf_sincos(bf_t *s, bf_t *c, const bf_t *a, limb_t prec) · 13 unmodified lines
46994805 slimb_t cancel;
47004806 cancel = 0;
47014807 for(;;) {
4702− prec2 = prec1 + cancel;
4808+ prec2 = prec1 + a->expn + cancel;
47034809 bf_const_pi(U, prec2, BF_RNDF);
47044810 bf_mul_2exp(U, -1, BF_PREC_INF, BF_RNDZ);
4705− bf_remquo(&mod, T, a, U, prec2, BF_RNDN);
4811+ bf_remquo(&mod, T, a, U, prec2, BF_RNDN, BF_RNDN);
47064812 // printf("T.expn=%ld prec2=%ld\n", T->expn, prec2);
47074813 if (mod == 0 || (T->expn != BF_EXP_ZERO &&
47084814 (T->expn + prec2) >= (prec1 - 1)))
@@ -4774,6 +4880,30 @@ static int bf_cos_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 65 unmodified lines
47744880
47754881 int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
47764882 {
4883+ if (a->len == 0) {
4884+ if (a->expn == BF_EXP_NAN) {
4885+ bf_set_nan(r);
4886+ return 0;
4887+ } else if (a->expn == BF_EXP_INF) {
4888+ bf_set_nan(r);
4889+ return BF_ST_INVALID_OP;
4890+ } else {
4891+ bf_set_ui(r, 1);
4892+ return 0;
4893+ }
4894+ }
4895+
4896+ /* small argument case: result = 1+r(x) with r(x) = -x^2/2 +
4897+ O(X^4). We assume r(x) < 2^(2*EXP(x) - 1). */
4898+ if (a->expn < 0) {
4899+ slimb_t e;
4900+ e = 2 * a->expn - 1;
4901+ if (e < -(prec + 2)) {
4902+ bf_set_ui(r, 1);
4903+ return bf_add_epsilon(r, r, e, 1, prec, flags);
4904+ }
4905+ }
4906+
47774907 return bf_ziv_rounding(r, a, prec, flags, bf_cos_internal, NULL);
47784908 }
47794909
@@ -4784,15 +4914,6 @@ static int bf_sin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 4 unmodified lines
47844914
47854915 int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
47864916 {
4787− return bf_ziv_rounding(r, a, prec, flags, bf_sin_internal, NULL);
4788−}
4789−
4790−static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
4791−{
4792− bf_context_t *s = r->ctx;
4793− bf_t T_s, *T = &T_s;
4794− limb_t prec1;
4795−
47964917 if (a->len == 0) {
47974918 if (a->expn == BF_EXP_NAN) {
47984919 bf_set_nan(r);
@@ -4806,6 +4927,26 @@ static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 7 unmodified lines
48064927 }
48074928 }
48084929
4930+ /* small argument case: result = x+r(x) with r(x) = -x^3/6 +
4931+ O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */
4932+ if (a->expn < 0) {
4933+ slimb_t e;
4934+ e = sat_add(2 * a->expn, a->expn - 2);
4935+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
4936+ bf_set(r, a);
4937+ return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);
4938+ }
4939+ }
4940+
4941+ return bf_ziv_rounding(r, a, prec, flags, bf_sin_internal, NULL);
4942+}
4943+
4944+static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
4945+{
4946+ bf_context_t *s = r->ctx;
4947+ bf_t T_s, *T = &T_s;
4948+ limb_t prec1;
4949+
48094950 /* XXX: precision analysis */
48104951 prec1 = prec + 8;
48114952 bf_init(s, T);
@@ -4817,6 +4958,31 @@ static int bf_tan_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 5 unmodified lines
48174958
48184959 int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
48194960 {
4961+ assert(r != a);
4962+ if (a->len == 0) {
4963+ if (a->expn == BF_EXP_NAN) {
4964+ bf_set_nan(r);
4965+ return 0;
4966+ } else if (a->expn == BF_EXP_INF) {
4967+ bf_set_nan(r);
4968+ return BF_ST_INVALID_OP;
4969+ } else {
4970+ bf_set_zero(r, a->sign);
4971+ return 0;
4972+ }
4973+ }
4974+
4975+ /* small argument case: result = x+r(x) with r(x) = x^3/3 +
4976+ O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */
4977+ if (a->expn < 0) {
4978+ slimb_t e;
4979+ e = sat_add(2 * a->expn, a->expn - 1);
4980+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
4981+ bf_set(r, a);
4982+ return bf_add_epsilon(r, r, e, a->sign, prec, flags);
4983+ }
4984+ }
4985+
48204986 return bf_ziv_rounding(r, a, prec, flags, bf_tan_internal, NULL);
48214987 }
48224988
@@ -4834,50 +5000,15 @@ static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec, · 11 unmodified lines
48345000 int cmp_1;
48355001 slimb_t prec1, i, K, l;
48365002
4837− if (a->len == 0) {
4838− if (a->expn == BF_EXP_NAN) {
4839− bf_set_nan(r);
4840− return 0;
4841− } else {
4842− if (a->expn == BF_EXP_INF)
4843− i = 1 - 2 * a->sign;
4844− else
4845− i = 0;
4846− i += add_pi2;
4847− /* return i*(pi/2) with -1 <= i <= 2 */
4848− if (i == 0) {
4849− bf_set_zero(r, add_pi2 ? 0 : a->sign);
4850− return 0;
4851− } else {
4852− /* PI or PI/2 */
4853− bf_const_pi(r, prec, BF_RNDF);
4854− if (i != 2)
4855− bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
4856− r->sign = (i < 0);
4857− return BF_ST_INEXACT;
4858− }
4859− }
4860− }
4861−
4862− bf_init(s, T);
4863− bf_set_ui(T, 1);
4864− cmp_1 = bf_cmpu(a, T);
4865− if (cmp_1 == 0 && !add_pi2) {
4866− /* short cut: abs(a) == 1 -> +/-pi/4 */
4867− bf_const_pi(r, prec, BF_RNDF);
4868− bf_mul_2exp(r, -2, BF_PREC_INF, BF_RNDZ);
4869− r->sign = a->sign;
4870− bf_delete(T);
4871− return BF_ST_INEXACT;
4872− }
4873−
48745003 /* XXX: precision analysis */
48755004 K = bf_isqrt((prec + 1) / 2);
48765005 l = prec / (2 * K) + 1;
48775006 prec1 = prec + K + 2 * l + 32;
4878− // printf("prec=%ld K=%ld l=%ld prec1=%ld\n", prec, K, l, prec1);
5007+ // printf("prec=%d K=%d l=%d prec1=%d\n", (int)prec, (int)K, (int)l, (int)prec1);
48795008
4880− if (cmp_1 > 0) {
5009+ bf_init(s, T);
5010+ cmp_1 = (a->expn >= 1); /* a >= 1 */
5011+ if (cmp_1) {
48815012 bf_set_ui(T, 1);
48825013 bf_div(T, T, a, prec1, BF_RNDN);
48835014 } else {
@@ -4945,6 +5076,47 @@ static int bf_atan_internal(bf_t *r, const bf_t *a, limb_t prec, · 61 unmodified lines
49455076
49465077 int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
49475078 {
5079+ bf_context_t *s = r->ctx;
5080+ bf_t T_s, *T = &T_s;
5081+ int res;
5082+
5083+ if (a->len == 0) {
5084+ if (a->expn == BF_EXP_NAN) {
5085+ bf_set_nan(r);
5086+ return 0;
5087+ } else if (a->expn == BF_EXP_INF) {
5088+ /* -PI/2 or PI/2 */
5089+ bf_const_pi_signed(r, a->sign, prec, flags);
5090+ bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
5091+ return BF_ST_INEXACT;
5092+ } else {
5093+ bf_set_zero(r, a->sign);
5094+ return 0;
5095+ }
5096+ }
5097+
5098+ bf_init(s, T);
5099+ bf_set_ui(T, 1);
5100+ res = bf_cmpu(a, T);
5101+ bf_delete(T);
5102+ if (res == 0) {
5103+ /* short cut: abs(a) == 1 -> +/-pi/4 */
5104+ bf_const_pi_signed(r, a->sign, prec, flags);
5105+ bf_mul_2exp(r, -2, BF_PREC_INF, BF_RNDZ);
5106+ return BF_ST_INEXACT;
5107+ }
5108+
5109+ /* small argument case: result = x+r(x) with r(x) = -x^3/3 +
5110+ O(X^5). We assume r(x) < 2^(3*EXP(x) - 1). */
5111+ if (a->expn < 0) {
5112+ slimb_t e;
5113+ e = sat_add(2 * a->expn, a->expn - 1);
5114+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
5115+ bf_set(r, a);
5116+ return bf_add_epsilon(r, r, e, 1 - a->sign, prec, flags);
5117+ }
5118+ }
5119+
49485120 return bf_ziv_rounding(r, a, prec, flags, bf_atan_internal, (void *)FALSE);
49495121 }
49505122
@@ -4998,38 +5170,6 @@ static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 47 unmodified lines
49985170 BOOL is_acos = (BOOL)(intptr_t)opaque;
49995171 bf_t T_s, *T = &T_s;
50005172 limb_t prec1, prec2;
5001− int res;
5002−
5003− if (a->len == 0) {
5004− if (a->expn == BF_EXP_NAN) {
5005− bf_set_nan(r);
5006− return 0;
5007− } else if (a->expn == BF_EXP_INF) {
5008− bf_set_nan(r);
5009− return BF_ST_INVALID_OP;
5010− } else {
5011− if (is_acos) {
5012− bf_const_pi(r, prec, BF_RNDF);
5013− bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
5014− return BF_ST_INEXACT;
5015− } else {
5016− bf_set_zero(r, a->sign);
5017− return 0;
5018− }
5019− }
5020− }
5021− bf_init(s, T);
5022− bf_set_ui(T, 1);
5023− res = bf_cmpu(a, T);
5024− if (res > 0) {
5025− bf_delete(T);
5026− bf_set_nan(r);
5027− return BF_ST_INVALID_OP;
5028− } else if (res == 0 && a->sign == 0 && is_acos) {
5029− bf_set_zero(r, 0);
5030− bf_delete(T);
5031− return 0;
5032− }
50335173
50345174 /* asin(x) = atan(x/sqrt(1-x^2))
50355175 acos(x) = pi/2 - asin(x) */
@@ -5041,6 +5181,7 @@ static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 5 unmodified lines
50415181 prec2 = BF_PREC_INF;
50425182 else
50435183 prec2 = prec1;
5184+ bf_init(s, T);
50445185 bf_mul(T, a, a, prec2, BF_RNDN);
50455186 bf_neg(T);
50465187 bf_add_si(T, T, 1, prec2, BF_RNDN);
@@ -5056,11 +5197,76 @@ static int bf_asin_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque) · 9 unmodified lines
50565197
50575198 int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
50585199 {
5200+ bf_context_t *s = r->ctx;
5201+ bf_t T_s, *T = &T_s;
5202+ int res;
5203+
5204+ if (a->len == 0) {
5205+ if (a->expn == BF_EXP_NAN) {
5206+ bf_set_nan(r);
5207+ return 0;
5208+ } else if (a->expn == BF_EXP_INF) {
5209+ bf_set_nan(r);
5210+ return BF_ST_INVALID_OP;
5211+ } else {
5212+ bf_set_zero(r, a->sign);
5213+ return 0;
5214+ }
5215+ }
5216+ bf_init(s, T);
5217+ bf_set_ui(T, 1);
5218+ res = bf_cmpu(a, T);
5219+ bf_delete(T);
5220+ if (res > 0) {
5221+ bf_set_nan(r);
5222+ return BF_ST_INVALID_OP;
5223+ }
5224+
5225+ /* small argument case: result = x+r(x) with r(x) = x^3/6 +
5226+ O(X^5). We assume r(x) < 2^(3*EXP(x) - 2). */
5227+ if (a->expn < 0) {
5228+ slimb_t e;
5229+ e = sat_add(2 * a->expn, a->expn - 2);
5230+ if (e < a->expn - bf_max(prec + 2, a->len * LIMB_BITS + 2)) {
5231+ bf_set(r, a);
5232+ return bf_add_epsilon(r, r, e, a->sign, prec, flags);
5233+ }
5234+ }
5235+
50595236 return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)FALSE);
50605237 }
50615238
50625239 int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags)
50635240 {
5241+ bf_context_t *s = r->ctx;
5242+ bf_t T_s, *T = &T_s;
5243+ int res;
5244+
5245+ if (a->len == 0) {
5246+ if (a->expn == BF_EXP_NAN) {
5247+ bf_set_nan(r);
5248+ return 0;
5249+ } else if (a->expn == BF_EXP_INF) {
5250+ bf_set_nan(r);
5251+ return BF_ST_INVALID_OP;
5252+ } else {
5253+ bf_const_pi(r, prec, flags);
5254+ bf_mul_2exp(r, -1, BF_PREC_INF, BF_RNDZ);
5255+ return BF_ST_INEXACT;
5256+ }
5257+ }
5258+ bf_init(s, T);
5259+ bf_set_ui(T, 1);
5260+ res = bf_cmpu(a, T);
5261+ bf_delete(T);
5262+ if (res > 0) {
5263+ bf_set_nan(r);
5264+ return BF_ST_INVALID_OP;
5265+ } else if (res == 0 && a->sign == 0) {
5266+ bf_set_zero(r, 0);
5267+ return 0;
5268+ }
5269+
50645270 return bf_ziv_rounding(r, a, prec, flags, bf_asin_internal, (void *)TRUE);
50655271 }
50665272
@@ -5124,14 +5330,14 @@ int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) · 57 unmodified lines
51245330
51255331 #endif /* LIMB_BITS != 64 */
51265332
5127−static inline limb_t shrd(limb_t low, limb_t high, long shift)
5333+static inline __maybe_unused limb_t shrd(limb_t low, limb_t high, long shift)
51285334 {
51295335 if (shift != 0)
51305336 low = (low >> shift) | (high << (LIMB_BITS - shift));
51315337 return low;
51325338 }
51335339
5134−static inline limb_t shld(limb_t a1, limb_t a0, long shift)
5340+static inline __maybe_unused limb_t shld(limb_t a1, limb_t a0, long shift)
51355341 {
51365342 if (shift != 0)
51375343 return (a1 << shift) | (a0 >> (LIMB_BITS - shift));
@@ -5185,21 +5391,18 @@ do {\ · 47 unmodified lines
51855391 /* fast integer division by a fixed constant */
51865392
51875393 typedef struct FastDivData {
5188− limb_t d; /* divisor (only user visible field) */
51895394 limb_t m1; /* multiplier */
5190− int shift1;
5191− int shift2;
5395+ int8_t shift1;
5396+ int8_t shift2;
51925397 } FastDivData;
51935398
5194−#if 1
51955399 /* From "Division by Invariant Integers using Multiplication" by
51965400 Torborn Granlund and Peter L. Montgomery */
51975401 /* d must be != 0 */
5198−static inline void fast_udiv_init(FastDivData *s, limb_t d)
5402+static inline __maybe_unused void fast_udiv_init(FastDivData *s, limb_t d)
51995403 {
52005404 int l;
52015405 limb_t q, r, m1;
5202− s->d = d;
52035406 if (d == 1)
52045407 l = 0;
52055408 else
@@ -5225,52 +5428,78 @@ static inline limb_t fast_udiv(limb_t a, const FastDivData *s) · 19 unmodified lines
52255428 return (t1 + t0) >> s->shift2;
52265429 }
52275430
5228−static inline limb_t fast_urem(limb_t a, const FastDivData *s)
5229−{
5230− limb_t q;
5231− q = fast_udiv(a, s);
5232− return a - q * s->d;
5233−}
5431+/* contains 10^i */
5432+const limb_t mp_pow_dec[LIMB_DIGITS + 1] = {
5433+ 1U,
5434+ 10U,
5435+ 100U,
5436+ 1000U,
5437+ 10000U,
5438+ 100000U,
5439+ 1000000U,
5440+ 10000000U,
5441+ 100000000U,
5442+ 1000000000U,
5443+#if LIMB_BITS == 64
5444+ 10000000000U,
5445+ 100000000000U,
5446+ 1000000000000U,
5447+ 10000000000000U,
5448+ 100000000000000U,
5449+ 1000000000000000U,
5450+ 10000000000000000U,
5451+ 100000000000000000U,
5452+ 1000000000000000000U,
5453+ 10000000000000000000U,
5454+#endif
5455+};
52345456
5235−#define fast_udivrem(q, r, a, s) q = fast_udiv(a, s), r = a - q * (s)->d
5236−
5457+/* precomputed from fast_udiv_init(10^i) */
5458+static const FastDivData mp_pow_div[LIMB_DIGITS + 1] = {
5459+#if LIMB_BITS == 32
5460+ { 0x00000001, 0, 0 },
5461+ { 0x9999999a, 1, 3 },
5462+ { 0x47ae147b, 1, 6 },
5463+ { 0x0624dd30, 1, 9 },
5464+ { 0xa36e2eb2, 1, 13 },
5465+ { 0x4f8b588f, 1, 16 },
5466+ { 0x0c6f7a0c, 1, 19 },
5467+ { 0xad7f29ac, 1, 23 },
5468+ { 0x5798ee24, 1, 26 },
5469+ { 0x12e0be83, 1, 29 },
52375470 #else
5238−
5239−static inline void fast_udiv_init(FastDivData *s, limb_t d)
5240−{
5241− s->d = d;
5242−}
5243−static inline limb_t fast_udiv(limb_t a, const FastDivData *s)
5244−{
5245− return a / s->d;
5246−}
5247−static inline limb_t fast_urem(limb_t a, const FastDivData *s)
5248−{
5249− return a % s->d;
5250−}
5251−
5252−#define fast_udivrem(q, r, a, s) q = a / (s)->d, r = a % (s)->d
5253−
5471+ { 0x0000000000000001, 0, 0 },
5472+ { 0x999999999999999a, 1, 3 },
5473+ { 0x47ae147ae147ae15, 1, 6 },
5474+ { 0x0624dd2f1a9fbe77, 1, 9 },
5475+ { 0xa36e2eb1c432ca58, 1, 13 },
5476+ { 0x4f8b588e368f0847, 1, 16 },
5477+ { 0x0c6f7a0b5ed8d36c, 1, 19 },
5478+ { 0xad7f29abcaf48579, 1, 23 },
5479+ { 0x5798ee2308c39dfa, 1, 26 },
5480+ { 0x12e0be826d694b2f, 1, 29 },
5481+ { 0xb7cdfd9d7bdbab7e, 1, 33 },
5482+ { 0x5fd7fe17964955fe, 1, 36 },
5483+ { 0x19799812dea11198, 1, 39 },
5484+ { 0xc25c268497681c27, 1, 43 },
5485+ { 0x6849b86a12b9b01f, 1, 46 },
5486+ { 0x203af9ee756159b3, 1, 49 },
5487+ { 0xcd2b297d889bc2b7, 1, 53 },
5488+ { 0x70ef54646d496893, 1, 56 },
5489+ { 0x2725dd1d243aba0f, 1, 59 },
5490+ { 0xd83c94fb6d2ac34d, 1, 63 },
52545491 #endif
5492+};
52555493
5256−/* contains 10^i */
5257−/* XXX: make it const */
5258−limb_t mp_pow_dec[LIMB_DIGITS + 1];
5259−static FastDivData mp_pow_div[LIMB_DIGITS + 1];
5260−
5261−static void mp_pow_init(void)
5494+/* divide by 10^shift with 0 <= shift <= LIMB_DIGITS */
5495+static inline limb_t fast_shr_dec(limb_t a, int shift)
52625496 {
5263− limb_t a;
5264− int i;
5265−
5266− a = 1;
5267− for(i = 0; i <= LIMB_DIGITS; i++) {
5268− mp_pow_dec[i] = a;
5269− fast_udiv_init(&mp_pow_div[i], a);
5270− a = a * 10;
5271− }
5497+ return fast_udiv(a, &mp_pow_div[shift]);
52725498 }
52735499
5500+/* division and remainder by 10^shift */
5501+#define fast_shr_rem_dec(q, r, a, shift) q = fast_shr_dec(a, shift), r = a - q * mp_pow_dec[shift]
5502+
52745503 limb_t mp_add_dec(limb_t *res, const limb_t *op1, const limb_t *op2,
52755504 mp_size_t n, limb_t carry)
52765505 {
@@ -5653,7 +5882,7 @@ static limb_t mp_shr_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, · 376 unmodified lines
56535882 l = high;
56545883 for(i = n - 1; i >= 0; i--) {
56555884 a = tab[i];
5656− fast_udivrem(q, r, a, &mp_pow_div[shift]);
5885+ fast_shr_rem_dec(q, r, a, shift);
56575886 tab_r[i] = q + l * mp_pow_dec[LIMB_DIGITS - shift];
56585887 l = r;
56595888 }
@@ -5671,7 +5900,7 @@ static limb_t mp_shl_dec(limb_t *tab_r, const limb_t *tab, mp_size_t n, · 11 unmodified lines
56715900 l = low;
56725901 for(i = 0; i < n; i++) {
56735902 a = tab[i];
5674− fast_udivrem(q, r, a, &mp_pow_div[LIMB_DIGITS - shift]);
5903+ fast_shr_rem_dec(q, r, a, LIMB_DIGITS - shift);
56755904 tab_r[i] = r * mp_pow_dec[shift] + l;
56765905 l = q;
56775906 }
@@ -6011,7 +6240,7 @@ static inline limb_t scan_digit_nz(const bfdec_t *r, slimb_t bit_pos) · 333 unmodified lines
60116240 return 0;
60126241 pos = (limb_t)bit_pos / LIMB_DIGITS;
60136242 shift = (limb_t)bit_pos % LIMB_DIGITS;
6014− fast_udivrem(q, v, r->tab[pos], &mp_pow_div[shift + 1]);
6243+ fast_shr_rem_dec(q, v, r->tab[pos], shift + 1);
60156244 (void)q;
60166245 if (v != 0)
60176246 return 1;
@@ -6032,7 +6261,7 @@ static limb_t get_digit(const limb_t *tab, limb_t len, slimb_t pos) · 14 unmodified lines
60326261 if (i < 0 || i >= len)
60336262 return 0;
60346263 shift = pos - i * LIMB_DIGITS;
6035− return fast_udiv(tab[i], &mp_pow_div[shift]) % 10;
6264+ return fast_shr_dec(tab[i], shift) % 10;
60366265 }
60376266
60386267 #if 0
@@ -6056,7 +6285,7 @@ static limb_t get_digits(const limb_t *tab, limb_t len, slimb_t pos) · 17 unmodified lines
60566285 a1 = tab[i];
60576286 else
60586287 a1 = 0;
6059− return fast_udiv(a0, &mp_pow_div[shift]) +
6288+ return fast_shr_dec(a0, shift) +
60606289 fast_urem(a1, &mp_pow_div[LIMB_DIGITS - shift]) *
60616290 mp_pow_dec[shift];
60626291 }
@@ -6108,13 +6337,8 @@ static int bfdec_get_rnd_add(int *pret, const bfdec_t *r, limb_t l, · 45 unmodified lines
61086337 case BF_RNDF:
61096338 add_one = (digit1 >= 5);
61106339 break;
6111− case BF_RNDNU:
6112− if (digit1 >= 5) {
6113− if (r->sign)
6114− add_one = (digit0 != 0);
6115− else
6116− add_one = 1;
6117− }
6340+ case BF_RNDA:
6341+ add_one = inexact;
61186342 break;
61196343 default:
61206344 abort();
@@ -6135,8 +6359,7 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) · 14 unmodified lines
61356359 int shift, add_one, rnd_mode, ret;
61366360 slimb_t i, bit_pos, pos, e_min, e_max, e_range, prec;
61376361
6138− /* e_min and e_max are computed to match the IEEE 754 conventions */
6139− /* XXX: does not matter for decimal numbers */
6362+ /* XXX: align to IEEE 754 2008 for decimal numbers ? */
61406363 e_range = (limb_t)1 << (bf_get_exp_bits(flags) - 1);
61416364 e_min = -e_range + 3;
61426365 e_max = e_range;
@@ -6147,6 +6370,11 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) · 4 unmodified lines
61476370 prec = r->expn + prec1;
61486371 else
61496372 prec = prec1;
6373+ } else if (unlikely(r->expn < e_min) && (flags & BF_FLAG_SUBNORMAL)) {
6374+ /* restrict the precision in case of potentially subnormal
6375+ result */
6376+ assert(prec1 != BF_PREC_INF);
6377+ prec = prec1 - (e_min - r->expn);
61506378 } else {
61516379 prec = prec1;
61526380 }
@@ -6183,10 +6411,16 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) · 30 unmodified lines
61836411
61846412 /* check underflow */
61856413 if (unlikely(r->expn < e_min)) {
6186− underflow:
6187− bfdec_set_zero(r, r->sign);
6188− ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;
6189− return ret;
6414+ if (flags & BF_FLAG_SUBNORMAL) {
6415+ /* if inexact, also set the underflow flag */
6416+ if (ret & BF_ST_INEXACT)
6417+ ret |= BF_ST_UNDERFLOW;
6418+ } else {
6419+ underflow:
6420+ bfdec_set_zero(r, r->sign);
6421+ ret |= BF_ST_UNDERFLOW | BF_ST_INEXACT;
6422+ return ret;
6423+ }
61906424 }
61916425
61926426 /* check overflow */
@@ -6202,7 +6436,7 @@ static int __bfdec_round(bfdec_t *r, limb_t prec1, bf_flags_t flags, limb_t l) · 9 unmodified lines
62026436 if (i >= 0) {
62036437 shift = smod(bit_pos, LIMB_DIGITS);
62046438 if (shift != 0) {
6205− r->tab[i] = fast_udiv(r->tab[i], &mp_pow_div[shift]) *
6439+ r->tab[i] = fast_shr_dec(r->tab[i], shift) *
62066440 mp_pow_dec[shift];
62076441 }
62086442 } else {
@@ -6571,10 +6805,10 @@ static int __bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, · 362 unmodified lines
65716805 /* number of digits after the decimal point */
65726806 /* XXX: check (2 extra digits for rounding + 2 digits) */
65736807 precl = (bf_max(a->expn - b->expn, 0) + 2 +
6574− 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;
6808+ prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;
65756809 } else {
65766810 /* number of limbs of the quotient (2 extra digits for rounding) */
6577− precl = (prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;
6811+ precl = (prec + 2 + LIMB_DIGITS - 1) / LIMB_DIGITS;
65786812 }
65796813 n = bf_max(a->len, precl);
65806814
@@ -6679,8 +6913,7 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, · 98 unmodified lines
66796913 }
66806914
66816915 q_sign = a->sign ^ b->sign;
6682− is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA ||
6683− rnd_mode == BF_RNDNU);
6916+ is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
66846917 switch(rnd_mode) {
66856918 default:
66866919 case BF_RNDZ:
@@ -6694,12 +6927,12 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, · 7 unmodified lines
66946927 case BF_RNDU:
66956928 is_ceil = q_sign ^ 1;
66966929 break;
6930+ case BF_RNDA:
6931+ is_ceil = TRUE;
6932+ break;
66976933 case BF_DIVREM_EUCLIDIAN:
66986934 is_ceil = a->sign;
66996935 break;
6700− case BF_RNDNU:
6701− /* XXX: unsupported yet */
6702− abort();
67036936 }
67046937
67056938 a1->expn = a->expn;
@@ -6756,14 +6989,14 @@ int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b, · 50 unmodified lines
67566989 return BF_ST_MEM_ERROR;
67576990 }
67586991
6759−int bfdec_fmod(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
6760− bf_flags_t flags)
6992+int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
6993+ bf_flags_t flags, int rnd_mode)
67616994 {
67626995 bfdec_t q_s, *q = &q_s;
67636996 int ret;
67646997
67656998 bfdec_init(r->ctx, q);
6766− ret = bfdec_divrem(q, r, a, b, prec, flags, BF_RNDZ);
6999+ ret = bfdec_divrem(q, r, a, b, prec, flags, rnd_mode);
67677000 bfdec_delete(q);
67687001 return ret;
67697002 }
@@ -6779,7 +7012,7 @@ int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags) · 9 unmodified lines
67797012 bf_context_t *s = a->ctx;
67807013 int ret, k;
67817014 limb_t *a1, v;
6782− slimb_t n, n1;
7015+ slimb_t n, n1, prec1;
67837016 limb_t res;
67847017
67857018 assert(r != a);
@@ -6798,9 +7031,14 @@ int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags) · 12 unmodified lines
67987031 bfdec_set_nan(r);
67997032 ret = BF_ST_INVALID_OP;
68007033 } else {
7034+ if (flags & BF_FLAG_RADPNT_PREC) {
7035+ prec1 = bf_max(floor_div(a->expn + 1, 2) + prec, 1);
7036+ } else {
7037+ prec1 = prec;
7038+ }
68017039 /* convert the mantissa to an integer with at least 2 *
68027040 prec + 4 digits */
6803− n = (2 * (prec + 2) + 2 * LIMB_DIGITS - 1) / (2 * LIMB_DIGITS);
7041+ n = (2 * (prec1 + 2) + 2 * LIMB_DIGITS - 1) / (2 * LIMB_DIGITS);
68047042 if (bfdec_resize(r, n))
68057043 goto fail;
68067044 a1 = bf_malloc(s, sizeof(limb_t) * 2 * n);
@@ -6869,7 +7107,7 @@ int bfdec_get_int32(int *pres, const bfdec_t *a) · 62 unmodified lines
68697107 v = 0;
68707108 ret = 0;
68717109 } else if (a->expn <= 9) {
6872− v = fast_udiv(a->tab[a->len - 1], &mp_pow_div[LIMB_DIGITS - a->expn]);
7110+ v = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);
68737111 if (a->sign)
68747112 v = -v;
68757113 ret = 0;
@@ -6877,7 +7115,7 @@ int bfdec_get_int32(int *pres, const bfdec_t *a) · 1 unmodified line
68777115 uint64_t v1;
68787116 uint32_t v_max;
68797117 #if LIMB_BITS == 64
6880− v1 = fast_udiv(a->tab[a->len - 1], &mp_pow_div[LIMB_DIGITS - a->expn]);
7118+ v1 = fast_shr_dec(a->tab[a->len - 1], LIMB_DIGITS - a->expn);
68817119 #else
68827120 v1 = (uint64_t)a->tab[a->len - 1] * 10 +
68837121 get_digit(a->tab, a->len, (a->len - 1) * LIMB_DIGITS - 1);
libbf.h+77−42
@@ -41,8 +41,8 @@ typedef unsigned __int128 uint128_t; · 40 unmodified lines
4141 typedef int64_t slimb_t;
4242 typedef uint64_t limb_t;
4343 typedef uint128_t dlimb_t;
44−#define EXP_MIN INT64_MIN
45−#define EXP_MAX INT64_MAX
44+#define BF_RAW_EXP_MIN INT64_MIN
45+#define BF_RAW_EXP_MAX INT64_MAX
4646
4747 #define LIMB_DIGITS 19
4848 #define BF_DEC_BASE UINT64_C(10000000000000000000)
@@ -52,8 +52,8 @@ typedef uint128_t dlimb_t; · 3 unmodified lines
5252 typedef int32_t slimb_t;
5353 typedef uint32_t limb_t;
5454 typedef uint64_t dlimb_t;
55−#define EXP_MIN INT32_MIN
56−#define EXP_MAX INT32_MAX
55+#define BF_RAW_EXP_MIN INT32_MIN
56+#define BF_RAW_EXP_MAX INT32_MAX
5757
5858 #define LIMB_DIGITS 9
5959 #define BF_DEC_BASE 1000000000U
@@ -61,10 +61,17 @@ typedef uint64_t dlimb_t; · 1 unmodified line
6161 #endif
6262
6363 /* in bits */
64+/* minimum number of bits for the exponent */
6465 #define BF_EXP_BITS_MIN 3
65−#define BF_EXP_BITS_MAX (LIMB_BITS - 2)
66+/* maximum number of bits for the exponent */
67+#define BF_EXP_BITS_MAX (LIMB_BITS - 3)
68+/* extended range for exponent, used internally */
69+#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)
70+/* minimum possible precision */
6671 #define BF_PREC_MIN 2
67−#define BF_PREC_MAX (((limb_t)1 << BF_EXP_BITS_MAX) - 2)
72+/* minimum possible precision */
73+#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)
74+/* some operations support infinite precision */
6875 #define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */
6976
7077 #if LIMB_BITS == 64
@@ -73,9 +80,9 @@ typedef uint64_t dlimb_t; · 2 unmodified lines
7380 #define BF_CHKSUM_MOD 975620677U
7481 #endif
7582
76−#define BF_EXP_ZERO EXP_MIN
77−#define BF_EXP_INF (EXP_MAX - 1)
78−#define BF_EXP_NAN EXP_MAX
83+#define BF_EXP_ZERO BF_RAW_EXP_MIN
84+#define BF_EXP_INF (BF_RAW_EXP_MAX - 1)
85+#define BF_EXP_NAN BF_RAW_EXP_MAX
7986
8087 /* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,
8188 +/-infinity is represented with expn = BF_EXP_INF and len = 0,
@@ -101,27 +108,29 @@ typedef struct { · 19 unmodified lines
101108 typedef enum {
102109 BF_RNDN, /* round to nearest, ties to even */
103110 BF_RNDZ, /* round to zero */
104− BF_RNDD, /* round to -inf */
111+ BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */
105112 BF_RNDU, /* round to +inf */
106113 BF_RNDNA, /* round to nearest, ties away from zero */
107− BF_RNDNU, /* round to nearest, ties to +inf */
114+ BF_RNDA, /* round away from zero */
108115 BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,
109116 inexact flag is always set) */
110117 } bf_rnd_t;
111118
112119 /* allow subnormal numbers. Only available if the number of exponent
113− bits is < BF_EXP_BITS_MAX and prec != BF_PREC_INF. Not supported
114− for decimal floating point numbers. */
120+ bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */
115121 #define BF_FLAG_SUBNORMAL (1 << 3)
116122 /* 'prec' is the precision after the radix point instead of the whole
117− mantissa. Can only be used with bf_round(), bfdec_round() and
118− bfdev_div(). */
123+ mantissa. Can only be used with bf_round() and
124+ bfdec_[add|sub|mul|div|sqrt|round](). */
119125 #define BF_FLAG_RADPNT_PREC (1 << 4)
120126
121127 #define BF_RND_MASK 0x7
122128 #define BF_EXP_BITS_SHIFT 5
123129 #define BF_EXP_BITS_MASK 0x3f
124130
131+/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */
132+#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)
133+
125134 /* contains the rounding mode and number of exponents bits */
126135 typedef uint32_t bf_flags_t;
127136
@@ -142,12 +151,17 @@ typedef struct bf_context_t { · 14 unmodified lines
142151
143152 static inline int bf_get_exp_bits(bf_flags_t flags)
144153 {
145− return BF_EXP_BITS_MAX - ((flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK);
154+ int e;
155+ e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;
156+ if (e == BF_EXP_BITS_MASK)
157+ return BF_EXP_BITS_MAX + 1;
158+ else
159+ return BF_EXP_BITS_MAX - e;
146160 }
147161
148162 static inline bf_flags_t bf_set_exp_bits(int n)
149163 {
150− return (BF_EXP_BITS_MAX - n) << BF_EXP_BITS_SHIFT;
164+ return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;
151165 }
152166
153167 /* returned status */
@@ -249,9 +263,22 @@ int bf_set_float64(bf_t *a, double d); · 95 unmodified lines
249263
250264 int bf_cmpu(const bf_t *a, const bf_t *b);
251265 int bf_cmp_full(const bf_t *a, const bf_t *b);
252−int bf_cmp_eq(const bf_t *a, const bf_t *b);
253−int bf_cmp_le(const bf_t *a, const bf_t *b);
254−int bf_cmp_lt(const bf_t *a, const bf_t *b);
266+int bf_cmp(const bf_t *a, const bf_t *b);
267+static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)
268+{
269+ return bf_cmp(a, b) == 0;
270+}
271+
272+static inline int bf_cmp_le(const bf_t *a, const bf_t *b)
273+{
274+ return bf_cmp(a, b) <= 0;
275+}
276+
277+static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)
278+{
279+ return bf_cmp(a, b) < 0;
280+}
281+
255282 int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
256283 int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
257284 int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);
@@ -264,12 +291,10 @@ int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags) · 6 unmodified lines
264291 #define BF_DIVREM_EUCLIDIAN BF_RNDF
265292 int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
266293 limb_t prec, bf_flags_t flags, int rnd_mode);
267−int bf_fmod(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
268− bf_flags_t flags);
269−int bf_remainder(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
270− bf_flags_t flags);
294+int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
295+ bf_flags_t flags, int rnd_mode);
271296 int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
272− bf_flags_t flags);
297+ bf_flags_t flags, int rnd_mode);
273298 /* round to integer with infinite precision */
274299 int bf_rint(bf_t *r, int rnd_mode);
275300 int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);
@@ -304,8 +329,8 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, · 28 unmodified lines
304329 /* Conversion of floating point number to string. Return a null
305330 terminated string or NULL if memory error. *plen contains its
306331 length if plen != NULL. The exponent letter is "e" for base 10,
307− "p" for bases 2, 8, 16 with the binary exponent and "@" for the
308− other bases. */
332+ "p" for bases 2, 8, 16 with a binary exponent and "@" for the other
333+ bases. */
309334
310335 #define BF_FTOA_FORMAT_MASK (3 << 16)
311336
@@ -316,17 +341,23 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, · 4 unmodified lines
316341 /* fractional format: prec digits after the decimal point rounded with
317342 (flags & BF_RND_MASK) */
318343 #define BF_FTOA_FORMAT_FRAC (1 << 16)
319−/* free format: use as many digits as necessary so that bf_atof()
320− return the same number when using precision 'prec', rounding to
321− nearest and the subnormal+exponent configuration of 'flags'. The
322− result is meaningful only if 'a' is already rounded to the wanted
323− precision.
344+/* free format:
345+
346+ For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum
347+ number of digits to represent 'a'. The precision and the rounding
348+ mode are ignored.
324349
325− Infinite precision (BF_PREC_INF) is supported when the radix is a
326− power of two. */
350+ For the non binary radices with bf_ftoa(): use as many digits as
351+ necessary so that bf_atof() return the same number when using
352+ precision 'prec', rounding to nearest and the subnormal
353+ configuration of 'flags'. The result is meaningful only if 'a' is
354+ already rounded to 'prec' bits. If the subnormal flag is set, the
355+ exponent in 'flags' must also be set to the desired exponent range.
356+*/
327357 #define BF_FTOA_FORMAT_FREE (2 << 16)
328358 /* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits
329− (takes more computation time). */
359+ (takes more computation time). Identical to BF_FTOA_FORMAT_FREE for
360+ binary radices with bf_ftoa() and for bfdec_ftoa(). */
330361 #define BF_FTOA_FORMAT_FREE_MIN (3 << 16)
331362
332363 /* force exponential notation for fixed or free format */
@@ -370,7 +401,7 @@ int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags); · 37 unmodified lines
370401 int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);
371402 int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
372403 int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
373−#define BF_POW_JS_QUICKS (1 << 16)
404+#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */
374405 int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);
375406 int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
376407 int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
@@ -448,17 +479,21 @@ static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b) · 71 unmodified lines
448479 {
449480 return bf_cmp_full((const bf_t *)a, (const bf_t *)b);
450481 }
482+static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)
483+{
484+ return bf_cmp((const bf_t *)a, (const bf_t *)b);
485+}
451486 static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)
452487 {
453− return bf_cmp_eq((const bf_t *)a, (const bf_t *)b);
488+ return bfdec_cmp(a, b) == 0;
454489 }
455490 static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)
456491 {
457− return bf_cmp_le((const bf_t *)a, (const bf_t *)b);
492+ return bfdec_cmp(a, b) <= 0;
458493 }
459494 static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)
460495 {
461− return bf_cmp_lt((const bf_t *)a, (const bf_t *)b);
496+ return bfdec_cmp(a, b) < 0;
462497 }
463498
464499 int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
@@ -475,8 +510,8 @@ int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec, · 10 unmodified lines
475510 bf_flags_t flags);
476511 int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
477512 limb_t prec, bf_flags_t flags, int rnd_mode);
478−int bfdec_fmod(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
479− bf_flags_t flags);
513+int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
514+ bf_flags_t flags, int rnd_mode);
480515 int bfdec_rint(bfdec_t *r, int rnd_mode);
481516 int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);
482517 int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);
@@ -488,7 +523,7 @@ int bfdec_atof(bfdec_t *r, const char *str, const char **pnext, · 5 unmodified lines
488523 limb_t prec, bf_flags_t flags);
489524
490525 /* the following functions are exported for testing only. */
491−extern limb_t mp_pow_dec[LIMB_DIGITS + 1];
526+extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];
492527 void bfdec_print_str(const char *str, const bfdec_t *a);
493528 static inline int bfdec_resize(bfdec_t *r, limb_t len)
494529 {
qjs.c+22−4
@@ -41,9 +41,6 @@ · 40 unmodified lines
4141 #include "cutils.h"
4242 #include "quickjs-libc.h"
4343
44−/* enable bignums */
45−#define CONFIG_BIGNUM
46−
4744 extern const uint8_t qjsc_repl[];
4845 extern const uint32_t qjsc_repl_size;
4946 #ifdef CONFIG_BIGNUM
@@ -258,12 +255,13 @@ static const JSMallocFunctions trace_mf = { · 208 unmodified lines
258255 void help(void)
259256 {
260257 printf("QuickJS version " CONFIG_VERSION "\n"
261− "usage: " PROG_NAME " [options] [file]\n"
258+ "usage: " PROG_NAME " [options] [file [args]]\n"
262259 "-h --help list options\n"
263260 "-e --eval EXPR evaluate EXPR\n"
264261 "-i --interactive go to interactive mode\n"
265262 "-m --module load as ES6 module (default=autodetect)\n"
266263 " --script load as ES6 script (default=autodetect)\n"
264+ "-I --include file include an additional file\n"
267265 " --std make 'std' and 'os' available to the loaded script\n"
268266 #ifdef CONFIG_BIGNUM
269267 " --bignum enable the bignum extensions (BigFloat, BigDecimal)\n"
@@ -292,6 +290,8 @@ int main(int argc, char **argv) · 22 unmodified lines
292290 int load_std = 0;
293291 int dump_unhandled_promise_rejection = 0;
294292 size_t memory_limit = 0;
293+ char *include_list[32];
294+ int i, include_count = 0;
295295 #ifdef CONFIG_BIGNUM
296296 int load_jscalc, bignum_ext = 0;
297297 #endif
@@ -345,6 +345,18 @@ int main(int argc, char **argv) · 47 unmodified lines
345345 fprintf(stderr, "qjs: missing expression for -e\n");
346346 exit(2);
347347 }
348+ if (opt == 'I' || !strcmp(longopt, "include")) {
349+ if (optind >= argc) {
350+ fprintf(stderr, "expecting filename");
351+ exit(1);
352+ }
353+ if (include_count >= countof(include_list)) {
354+ fprintf(stderr, "too many included files");
355+ exit(1);
356+ }
357+ include_list[include_count++] = argv[optind++];
358+ continue;
359+ }
348360 if (opt == 'i' || !strcmp(longopt, "interactive")) {
349361 interactive++;
350362 continue;
@@ -426,6 +438,7 @@ int main(int argc, char **argv) · 75 unmodified lines
426438 if (bignum_ext || load_jscalc) {
427439 JS_AddIntrinsicBigFloat(ctx);
428440 JS_AddIntrinsicBigDecimal(ctx);
441+ JS_AddIntrinsicOperators(ctx);
429442 JS_EnableBignumExt(ctx, TRUE);
430443 }
431444 #endif
@@ -459,6 +472,11 @@ int main(int argc, char **argv) · 27 unmodified lines
459472 eval_buf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE);
460473 }
461474
475+ for(i = 0; i < include_count; i++) {
476+ if (eval_file(ctx, include_list[i], module))
477+ goto fail;
478+ }
479+
462480 if (expr) {
463481 if (eval_buf(ctx, expr, strlen(expr), "<cmdline>", 0))
464482 goto fail;
qjsc.c+16−8
@@ -36,9 +36,6 @@ · 35 unmodified lines
3636 #include "cutils.h"
3737 #include "quickjs-libc.h"
3838
39−/* enable bignums */
40−#define CONFIG_BIGNUM
41−
4239 typedef struct {
4340 char *name;
4441 char *short_name;
@@ -79,7 +76,9 @@ static const FeatureEntry feature_list[] = { · 34 unmodified lines
7976 { "promise", "Promise" },
8077 #define FE_MODULE_LOADER 9
8178 { "module-loader", NULL },
79+#ifdef CONFIG_BIGNUM
8280 { "bigint", "BigInt" },
81+#endif
8382 };
8483
8584 void namelist_add(namelist_t *lp, const char *name, const char *short_name,
@@ -485,9 +484,12 @@ int main(int argc, char **argv) · 399 unmodified lines
485484 FILE *fo;
486485 JSRuntime *rt;
487486 JSContext *ctx;
488− BOOL use_lto, bignum_ext;
487+ BOOL use_lto;
489488 int module;
490489 OutputTypeEnum output_type;
490+#ifdef CONFIG_BIGNUM
491+ BOOL bignum_ext = FALSE;
492+#endif
491493
492494 out_filename = NULL;
493495 output_type = OUTPUT_EXECUTABLE;
@@ -497,7 +499,6 @@ int main(int argc, char **argv) · 3 unmodified lines
497499 byte_swap = FALSE;
498500 verbose = 0;
499501 use_lto = FALSE;
500− bignum_ext = FALSE;
501502
502503 /* add system modules */
503504 namelist_add(&cmodule_list, "std", "std", 0);
@@ -538,9 +539,13 @@ int main(int argc, char **argv) · 34 unmodified lines
538539 }
539540 if (i == countof(feature_list))
540541 goto bad_feature;
541− } else if (!strcmp(optarg, "bignum")) {
542+ } else
543+#ifdef CONFIG_BIGNUM
544+ if (!strcmp(optarg, "bignum")) {
542545 bignum_ext = TRUE;
543− } else {
546+ } else
547+#endif
548+ {
544549 bad_feature:
545550 fprintf(stderr, "unsupported feature: %s\n", optarg);
546551 exit(1);
@@ -615,6 +620,7 @@ int main(int argc, char **argv) · 68 unmodified lines
615620 if (bignum_ext) {
616621 JS_AddIntrinsicBigFloat(ctx);
617622 JS_AddIntrinsicBigDecimal(ctx);
623+ JS_AddIntrinsicOperators(ctx);
618624 JS_EnableBignumExt(ctx, TRUE);
619625 }
620626 #endif
@@ -661,13 +667,15 @@ int main(int argc, char **argv) · 40 unmodified lines
661667 feature_list[i].init_name);
662668 }
663669 }
670+#ifdef CONFIG_BIGNUM
664671 if (bignum_ext) {
665672 fprintf(fo,
666673 " JS_AddIntrinsicBigFloat(ctx);\n"
667674 " JS_AddIntrinsicBigDecimal(ctx);\n"
675+ " JS_AddIntrinsicOperators(ctx);\n"
668676 " JS_EnableBignumExt(ctx, 1);\n");
669677 }
670−
678+#endif
671679 fprintf(fo, " js_std_add_helpers(ctx, argc, argv);\n");
672680
673681 for(i = 0; i < init_module_list.count; i++) {
qjscalc.js+817−618
@@ -1,7 +1,7 @@
11 /*
22 * QuickJS Javascript Calculator
33 *
4− * Copyright (c) 2017-2018 Fabrice Bellard
4+ * Copyright (c) 2017-2020 Fabrice Bellard
55 *
66 * Permission is hereby granted, free of charge, to any person obtaining a copy
77 * of this software and associated documentation files (the "Software"), to deal
@@ -27,20 +27,8 @@ · 19 unmodified lines
2727 var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunction, Series, Matrix;
2828
2929 (function(global) {
30− /* the types index are used to dispatch the operator functions */
31− var OT_INT = 0;
32− var OT_FRACTION = 10;
33− var OT_FLOAT64 = 19;
34− var OT_FLOAT = 20;
35− var OT_COMPLEX = 30;
36− var OT_MOD = 40;
37− var OT_POLY = 50;
38− var OT_POLYMOD = 55;
39− var OT_RFUNC = 60;
40− var OT_SERIES = 70;
41− var OT_ARRAY = 80;
42−
4330 global.Integer = global.BigInt;
31+ global.Float = global.BigFloat;
4432 global.algebraicMode = true;
4533
4634 /* add non enumerable properties */
@@ -63,6 +51,42 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 16 unmodified lines
6351 Object.defineProperty(obj, prop, desc);
6452 }
6553 }
54+
55+ /* same as proto[Symbol.operatorSet] = Operators.create(..op_list)
56+ but allow shortcuts: left: [], right: [] or both
57+ */
58+ function operators_set(proto, ...op_list)
59+ {
60+ var new_op_list, i, a, j, b, k, obj, tab;
61+ var fields = [ "left", "right" ];
62+ new_op_list = [];
63+ for(i = 0; i < op_list.length; i++) {
64+ a = op_list[i];
65+ if (a.left || a.right) {
66+ tab = [ a.left, a.right ];
67+ delete a.left;
68+ delete a.right;
69+ for(k = 0; k < 2; k++) {
70+ obj = tab[k];
71+ if (obj) {
72+ if (!Array.isArray(obj)) {
73+ obj = [ obj ];
74+ }
75+ for(j = 0; j < obj.length; j++) {
76+ b = {};
77+ Object.assign(b, a);
78+ b[fields[k]] = obj[j];
79+ new_op_list.push(b);
80+ }
81+ }
82+ }
83+ } else {
84+ new_op_list.push(a);
85+ }
86+ }
87+ proto[Symbol.operatorSet] =
88+ Operators.create.call(null, ...new_op_list);
89+ }
6690
6791 /* Integer */
6892
@@ -104,11 +128,12 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 35 unmodified lines
104128 var d, r, s, i, j, a;
105129 d = n - 1;
106130 s = 0;
107− while (d & 1) {
131+ while ((d & 1) == 0) {
108132 d >>= 1;
109133 s++;
110134 }
111− t = Math.min(t, small_primes.length);
135+ if (small_primes.length < t)
136+ t = small_primes.length;
112137 loop: for(j = 0; j < t; j++) {
113138 a = small_primes[j];
114139 r = Integer.pmod(a, d, n);
@@ -140,25 +165,31 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 25 unmodified lines
140165 return fact_rec(a, i) * fact_rec(i + 1, b);
141166 }
142167 }
143−
168+
169+ /* math mode specific quirk to overload the integer division and power */
170+ Operators.updateBigIntOperators(
171+ {
172+ "/"(a, b) {
173+ if (algebraicMode) {
174+ return Fraction.toFraction(a, b);
175+ } else {
176+ return Float(a) / Float(b);
177+ }
178+ },
179+ "**"(a, b) {
180+ if (algebraicMode) {
181+ return generic_pow(a, b);
182+ } else {
183+ return Float(a) ** Float(b);
184+ }
185+ }
186+ });
187+
144188 add_props(Integer, {
145189 isInteger(a) {
146− return typeof a === "bigint";
147− },
148− [Symbol.operatorOrder]: OT_INT,
149− [Symbol.operatorDiv](a, b) {
150− if (algebraicMode) {
151− return Fraction.toFraction(a, b);
152− } else {
153− return Float(a) / Float(b);
154− }
155− },
156− [Symbol.operatorPow](a, b) {
157− if (algebraicMode) {
158− return generic_pow(a, b);
159− } else {
160− return Float(a) ** Float(b);
161− }
190+ /* integers are represented either as bigint or as number */
191+ return typeof a === "bigint" ||
192+ (typeof a === "number" && Number.isSafeInteger(a));
162193 },
163194 gcd(a, b) {
164195 var r;
@@ -311,7 +342,10 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 146 unmodified lines
311342 return this * this;
312343 },
313344 abs() {
314− return Math.abs(this);
345+ var v = this;
346+ if (v < 0)
347+ v = -v;
348+ return v;
315349 },
316350 conj() {
317351 return this;
@@ -373,8 +407,119 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 55 unmodified lines
373407 return obj;
374408 }
375409
410+ function fraction_add(a, b) {
411+ a = Fraction(a);
412+ b = Fraction(b);
413+ return Fraction.toFraction(a.num * b.den + a.den * b.num, a.den * b.den);
414+ }
415+ function fraction_sub(a, b) {
416+ a = Fraction(a);
417+ b = Fraction(b);
418+ return Fraction.toFraction(a.num * b.den - a.den * b.num, a.den * b.den);
419+ }
420+ function fraction_mul(a, b) {
421+ a = Fraction(a);
422+ b = Fraction(b);
423+ return Fraction.toFraction(a.num * b.num, a.den * b.den);
424+ }
425+ function fraction_div(a, b) {
426+ a = Fraction(a);
427+ b = Fraction(b);
428+ return Fraction.toFraction(a.num * b.den, a.den * b.num);
429+ }
430+ function fraction_mod(a, b) {
431+ var a1 = Fraction(a);
432+ var b1 = Fraction(b);
433+ return a - Integer.ediv(a1.num * b1.den, a1.den * b1.num) * b;
434+ }
435+ function fraction_eq(a, b) {
436+ a = Fraction(a);
437+ b = Fraction(b);
438+ /* we assume the fractions are normalized */
439+ return (a.num == b.num && a.den == b.den);
440+ }
441+ function fraction_lt(a, b) {
442+ a = Fraction(a);
443+ b = Fraction(b);
444+ return (a.num * b.den < b.num * a.den);
445+ }
446+
447+ /* operators are needed for fractions */
448+ function float_add(a, b) {
449+ return Float(a) + Float(b);
450+ }
451+ function float_sub(a, b) {
452+ return Float(a) - Float(b);
453+ }
454+ function float_mul(a, b) {
455+ return Float(a) * Float(b);
456+ }
457+ function float_div(a, b) {
458+ return Float(a) / Float(b);
459+ }
460+ function float_mod(a, b) {
461+ return Float(a) % Float(b);
462+ }
463+ function float_pow(a, b) {
464+ return Float(a) ** Float(b);
465+ }
466+ function float_eq(a, b) {
467+ /* XXX: may be better to use infinite precision for the comparison */
468+ return Float(a) === Float(b);
469+ }
470+ function float_lt(a, b) {
471+ a = Float(a);
472+ b = Float(b);
473+ /* XXX: may be better to use infinite precision for the comparison */
474+ if (Float.isNaN(a) || Float.isNaN(b))
475+ return undefined;
476+ else
477+ return a < b;
478+ }
479+
480+ operators_set(Fraction.prototype,
481+ {
482+ "+": fraction_add,
483+ "-": fraction_sub,
484+ "*": fraction_mul,
485+ "/": fraction_div,
486+ "%": fraction_mod,
487+ "**": generic_pow,
488+ "==": fraction_eq,
489+ "<": fraction_lt,
490+ "pos"(a) {
491+ return a;
492+ },
493+ "neg"(a) {
494+ return Fraction(-a.num, a.den);
495+ },
496+ },
497+ {
498+ left: [Number, BigInt],
499+ right: [Number, BigInt],
500+ "+": fraction_add,
501+ "-": fraction_sub,
502+ "*": fraction_mul,
503+ "/": fraction_div,
504+ "%": fraction_mod,
505+ "**": generic_pow,
506+ "==": fraction_eq,
507+ "<": fraction_lt,
508+ },
509+ {
510+ left: Float,
511+ right: Float,
512+ "+": float_add,
513+ "-": float_sub,
514+ "*": float_mul,
515+ "/": float_div,
516+ "%": float_mod,
517+ "**": float_pow,
518+ "==": float_eq,
519+ "<": float_lt,
520+ });
521+
376522 add_props(Fraction, {
377− [Symbol.operatorOrder]: OT_FRACTION,
378523 /* (internal use) simplify 'a' to an integer when possible */
379524 toFraction(a, b) {
380525 var r = Fraction(a, b);
@@ -383,72 +528,16 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 2 unmodified lines
383528 else
384529 return r;
385530 },
386−
387− [Symbol.operatorAdd](a, b) {
388− a = Fraction(a);
389− b = Fraction(b);
390− return Fraction.toFraction(a.num * b.den + a.den * b.num, a.den * b.den);
391− },
392− [Symbol.operatorSub](a, b) {
393− a = Fraction(a);
394− b = Fraction(b);
395− return Fraction.toFraction(a.num * b.den - a.den * b.num, a.den * b.den);
396− },
397− [Symbol.operatorMul](a, b) {
398− a = Fraction(a);
399− b = Fraction(b);
400− return Fraction.toFraction(a.num * b.num, a.den * b.den);
401− },
402− [Symbol.operatorDiv](a, b) {
403− a = Fraction(a);
404− b = Fraction(b);
405− return Fraction.toFraction(a.num * b.den, a.den * b.num);
406− },
407− [Symbol.operatorMathMod](a, b) {
408− var a1 = Fraction(a);
409− var b1 = Fraction(b);
410− return a - Integer.ediv(a1.num * b1.den, a1.den * b1.num) * b;
411− },
412− [Symbol.operatorMod](a, b) {
413− var a1 = Fraction(a);
414− var b1 = Fraction(b);
415− return a - Integer.tdiv(a1.num * b1.den, a1.den * b1.num) * b;
416− },
417− [Symbol.operatorPow]: generic_pow,
418− [Symbol.operatorCmpEQ](a, b) {
419− a = Fraction(a);
420− b = Fraction(b);
421− /* we assume the fractions are normalized */
422− return (a.num == b.num && a.den == b.den);
423− },
424− [Symbol.operatorCmpLT](a, b) {
425− a = Fraction(a);
426− b = Fraction(b);
427− return (a.num * b.den < b.num * a.den);
428− },
429− [Symbol.operatorCmpLE](a, b) {
430− a = Fraction(a);
431− b = Fraction(b);
432− return (a.num * b.den <= b.num * a.den);
433− },
434531 });
435532
436533 add_props(Fraction.prototype, {
437534 [Symbol.toPrimitive](hint) {
438− if (hint === "integer") {
439− return Integer.tdiv(this.num, this.den);
440− } else if (hint === "string") {
535+ if (hint === "string") {
441536 return this.toString();
442537 } else {
443538 return Float(this.num) / this.den;
444539 }
445540 },
446− [Symbol.operatorPlus]() {
447− return this;
448− },
449− [Symbol.operatorNeg]() {
450− return Fraction(-this.num, this.den);
451− },
452541 inverse() {
453542 return Fraction(this.den, this.num);
454543 },
@@ -460,7 +549,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 5 unmodified lines
460549 },
461550 abs() {
462551 if (this.num < 0)
463− return this[Symbol.operatorNeg]();
552+ return -this;
464553 else
465554 return this;
466555 },
@@ -483,29 +572,9 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 16 unmodified lines
483572
484573 /* Number (Float64) */
485574
486− add_props(Number, {
487− [Symbol.operatorOrder]: OT_FLOAT64,
488− /* operators are needed for fractions */
489− [Symbol.operatorAdd](a, b) {
490− return Number(a) + Number(b);
491− },
492− [Symbol.operatorSub](a, b) {
493− return Number(a) - Number(b);
494− },
495− [Symbol.operatorMul](a, b) {
496− return Number(a) * Number(b);
497− },
498− [Symbol.operatorDiv](a, b) {
499− return Number(a) / Number(b);
500− },
501− [Symbol.operatorPow](a, b) {
502− return Number(a) ** Number(b);
503− },
504− });
505−
506575 add_props(Number.prototype, {
507576 inverse() {
508− return 1.0 / this;
577+ return 1 / this;
509578 },
510579 norm2() {
511580 return this * this;
@@ -536,8 +605,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 24 unmodified lines
536605
537606 /* Float */
538607
539− global.Float = global.BigFloat;
540−
541608 var const_tab = [];
542609
543610 /* we cache the constants for small precisions */
@@ -603,26 +670,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 59 unmodified lines
603670 get SQRT2() { return get_const(7); },
604671 });
605672
606− add_props(Float, {
607− [Symbol.operatorOrder]: OT_FLOAT,
608− /* operators are needed for fractions */
609− [Symbol.operatorAdd](a, b) {
610− return Float(a) + Float(b);
611− },
612− [Symbol.operatorSub](a, b) {
613− return Float(a) - Float(b);
614− },
615− [Symbol.operatorMul](a, b) {
616− return Float(a) * Float(b);
617− },
618− [Symbol.operatorDiv](a, b) {
619− return Float(a) / Float(b);
620− },
621− [Symbol.operatorPow](a, b) {
622− return Float(a) ** Float(b);
623− },
624− });
625−
626673 add_props(Float.prototype, {
627674 inverse() {
628675 return 1.0 / this;
@@ -631,7 +678,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 2 unmodified lines
631678 return this * this;
632679 },
633680 abs() {
634− return Math.abs(this);
681+ return Float.abs(this);
635682 },
636683 conj() {
637684 return this;
@@ -672,8 +719,61 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 34 unmodified lines
672719 return obj;
673720 }
674721
722+
723+ function complex_add(a, b) {
724+ a = Complex(a);
725+ b = Complex(b);
726+ return Complex.toComplex(a.re + b.re, a.im + b.im);
727+ }
728+ function complex_sub(a, b) {
729+ a = Complex(a);
730+ b = Complex(b);
731+ return Complex.toComplex(a.re - b.re, a.im - b.im);
732+ }
733+ function complex_mul(a, b) {
734+ a = Complex(a);
735+ b = Complex(b);
736+ return Complex.toComplex(a.re * b.re - a.im * b.im,
737+ a.re * b.im + a.im * b.re);
738+ }
739+ function complex_div(a, b) {
740+ a = Complex(a);
741+ b = Complex(b);
742+ return a * b.inverse();
743+ }
744+ function complex_eq(a, b) {
745+ a = Complex(a);
746+ b = Complex(b);
747+ return a.re == b.re && a.im == b.im;
748+ }
749+
750+ operators_set(Complex.prototype,
751+ {
752+ "+": complex_add,
753+ "-": complex_sub,
754+ "*": complex_mul,
755+ "/": complex_div,
756+ "**": generic_pow,
757+ "==": complex_eq,
758+ "pos"(a) {
759+ return a;
760+ },
761+ "neg"(a) {
762+ return Complex(-a.re, -a.im);
763+ }
764+ },
765+ {
766+ left: [Number, BigInt, Float, Fraction],
767+ right: [Number, BigInt, Float, Fraction],
768+ "+": complex_add,
769+ "-": complex_sub,
770+ "*": complex_mul,
771+ "/": complex_div,
772+ "**": generic_pow,
773+ "==": complex_eq,
774+ });
775+
675776 add_props(Complex, {
676− [Symbol.operatorOrder]: OT_COMPLEX,
677777 /* simplify to real number when possible */
678778 toComplex(re, im) {
679779 if (algebraicMode && im == 0)
@@ -681,43 +781,9 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 1 unmodified line
681781 else
682782 return Complex(re, im);
683783 },
684−
685− [Symbol.operatorAdd](a, b) {
686− a = Complex(a);
687− b = Complex(b);
688− return Complex.toComplex(a.re + b.re, a.im + b.im);
689− },
690− [Symbol.operatorSub](a, b) {
691− a = Complex(a);
692− b = Complex(b);
693− return Complex.toComplex(a.re - b.re, a.im - b.im);
694− },
695− [Symbol.operatorMul](a, b) {
696− a = Complex(a);
697− b = Complex(b);
698− return Complex.toComplex(a.re * b.re - a.im * b.im,
699− a.re * b.im + a.im * b.re);
700− },
701− [Symbol.operatorDiv](a, b) {
702− a = Complex(a);
703− b = Complex(b);
704− return a * b.inverse();
705− },
706− [Symbol.operatorPow]: generic_pow,
707− [Symbol.operatorCmpEQ](a, b) {
708− a = Complex(a);
709− b = Complex(b);
710− return a.re == b.re && a.im == b.im;
711− }
712784 });
713785
714786 add_props(Complex.prototype, {
715− [Symbol.operatorPlus]() {
716− return this;
717− },
718− [Symbol.operatorNeg]() {
719− return Complex(-this.re, -this.im);
720− },
721787 inverse() {
722788 var c = this.norm2();
723789 return Complex(this.re / c, -this.im / c);
@@ -785,14 +851,75 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 61 unmodified lines
785851 obj.mod = m;
786852 return obj;
787853 };
854+
855+ function mod_add(a, b) {
856+ if (!(a instanceof Mod)) {
857+ return Mod(a + b.res, b.mod);
858+ } else if (!(b instanceof Mod)) {
859+ return Mod(a.res + b, a.mod);
860+ } else {
861+ if (a.mod != b.mod)
862+ throw TypeError("different modulo for binary operator");
863+ return Mod(a.res + b.res, a.mod);
864+ }
865+ }
866+ function mod_sub(a, b) {
867+ if (!(a instanceof Mod)) {
868+ return Mod(a - b.res, b.mod);
869+ } else if (!(b instanceof Mod)) {
870+ return Mod(a.res - b, a.mod);
871+ } else {
872+ if (a.mod != b.mod)
873+ throw TypeError("different modulo for binary operator");
874+ return Mod(a.res - b.res, a.mod);
875+ }
876+ }
877+ function mod_mul(a, b) {
878+ if (!(a instanceof Mod)) {
879+ return Mod(a * b.res, b.mod);
880+ } else if (!(b instanceof Mod)) {
881+ return Mod(a.res * b, a.mod);
882+ } else {
883+ if (a.mod != b.mod)
884+ throw TypeError("different modulo for binary operator");
885+ return Mod(a.res * b.res, a.mod);
886+ }
887+ }
888+ function mod_div(a, b) {
889+ if (!(b instanceof Mod))
890+ b = Mod(b, a.mod);
891+ return mod_mul(a, b.inverse());
892+ }
893+ function mod_eq(a, b) {
894+ return (a.mod == b.mod && a.res == b.res);
895+ }
788896
789− add_props(Mod.prototype, {
790− [Symbol.operatorPlus]() {
791− return this;
792− },
793− [Symbol.operatorNeg]() {
794− return Mod(-this.res, this.mod);
897+ operators_set(Mod.prototype,
898+ {
899+ "+": mod_add,
900+ "-": mod_sub,
901+ "*": mod_mul,
902+ "/": mod_div,
903+ "**": generic_pow,
904+ "==": mod_eq,
905+ "pos"(a) {
906+ return a;
907+ },
908+ "neg"(a) {
909+ return Mod(-a.res, a.mod);
910+ }
795911 },
912+ {
913+ left: [Number, BigInt, Float, Fraction],
914+ right: [Number, BigInt, Float, Fraction],
915+ "+": mod_add,
916+ "-": mod_sub,
917+ "*": mod_mul,
918+ "/": mod_div,
919+ "**": generic_pow,
920+ });
921+
922+ add_props(Mod.prototype, {
796923 inverse() {
797924 var a = this, m = a.mod;
798925 if (Integer.isInteger(m)) {
@@ -806,57 +933,21 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 7 unmodified lines
806933 },
807934 });
808935
809− add_props(Mod, {
810− [Symbol.operatorOrder]: OT_MOD,
811− [Symbol.operatorAdd](a, b) {
812− if (!(a instanceof Mod)) {
813− return Mod(a + b.res, b.mod);
814− } else if (!(b instanceof Mod)) {
815− return Mod(a.res + b, a.mod);
816− } else {
817− if (a.mod != b.mod)
818− throw TypeError("different modulo for binary operator");
819− return Mod(a.res + b.res, a.mod);
820− }
821− },
822− [Symbol.operatorSub](a, b) {
823− if (!(a instanceof Mod)) {
824− return Mod(a - b.res, b.mod);
825− } else if (!(b instanceof Mod)) {
826− return Mod(a.res - b, a.mod);
827− } else {
828− if (a.mod != b.mod)
829− throw TypeError("different modulo for binary operator");
830− return Mod(a.res - b.res, a.mod);
831− }
832− },
833− [Symbol.operatorMul](a, b) {
834− if (!(a instanceof Mod)) {
835− return Mod(a * b.res, b.mod);
836− } else if (!(b instanceof Mod)) {
837− return Mod(a.res * b, a.mod);
838− } else {
839− if (a.mod != b.mod)
840− throw TypeError("different modulo for binary operator");
841− return Mod(a.res * b.res, a.mod);
842− }
843− },
844− [Symbol.operatorDiv](a, b) {
845− if (!(b instanceof Mod))
846− b = Mod(b, a.mod);
847− return Mod[Symbol.operatorMul](a, b.inverse());
848− },
849− [Symbol.operatorPow]: generic_pow,
850− [Symbol.operatorCmpEQ](a, b) {
851− if (!(a instanceof Mod) ||
852− !(b instanceof Mod))
853− return false;
854− return (a.mod == b.mod && a.res == b.res);
855− }
856− });
857−
858936 /* Polynomial */
859937
938+ function polynomial_is_scalar(a)
939+ {
940+ if (typeof a === "number" ||
941+ typeof a === "bigint" ||
942+ typeof a === "bigfloat")
943+ return true;
944+ if (a instanceof Fraction ||
945+ a instanceof Complex ||
946+ a instanceof Mod)
947+ return true;
948+ return false;
949+ }
950+
860951 Polynomial = function Polynomial(a)
861952 {
862953 if (new.target)
@@ -868,7 +959,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 5 unmodified lines
868959 a = [ 0 ];
869960 Object.setPrototypeOf(a, Polynomial.prototype);
870961 return a.trim();
871− } else if (a.constructor[Symbol.operatorOrder] <= OT_MOD) {
962+ } else if (polynomial_is_scalar(a)) {
872963 a = [a];
873964 Object.setPrototypeOf(a, Polynomial.prototype);
874965 return a;
@@ -1004,18 +1095,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 129 unmodified lines
10041095 a.length = i;
10051096 return a;
10061097 },
1007− [Symbol.operatorPlus]() {
1008− return this;
1009− },
1010− [Symbol.operatorNeg]() {
1011− var r, i, n, a;
1012− a = this;
1013− n = a.length;
1014− r = [];
1015− for(i = 0; i < n; i++)
1016− r[i] = -a[i];
1017− return Polynomial(r);
1018− },
10191098 conj() {
10201099 var r, i, n, a;
10211100 a = this;
@@ -1097,74 +1176,106 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 75 unmodified lines
10971176 },
10981177 });
10991178
1100− add_props(Polynomial, {
1101− [Symbol.operatorOrder]: OT_POLY,
1102− [Symbol.operatorAdd](a, b) {
1103− var tmp, r, i, n1, n2;
1104− a = Polynomial(a);
1105− b = Polynomial(b);
1106− if (a.length < b.length) {
1107− tmp = a;
1108− a = b;
1109− b = tmp;
1110− }
1111− n1 = b.length;
1112− n2 = a.length;
1113− r = [];
1114− for(i = 0; i < n1; i++)
1115− r[i] = a[i] + b[i];
1116− for(i = n1; i < n2; i++)
1117− r[i] = a[i];
1118− return Polynomial(r);
1119− },
1120− [Symbol.operatorSub](a, b) {
1121− return Polynomial[Symbol.operatorAdd](a, -b);
1122− },
1123− [Symbol.operatorMul](a, b) {
1124− var i, j, n1, n2, n, r;
1125− a = Polynomial(a);
1126− b = Polynomial(b);
1127− n1 = a.length;
1128− n2 = b.length;
1129− n = n1 + n2 - 1;
1130− r = [];
1131− for(i = 0; i < n; i++)
1132− r[i] = 0;
1133− for(i = 0; i < n1; i++) {
1134− for(j = 0; j < n2; j++) {
1135− r[i + j] += a[i] * b[j];
1136− }
1179+
1180+ function polynomial_add(a, b) {
1181+ var tmp, r, i, n1, n2;
1182+ a = Polynomial(a);
1183+ b = Polynomial(b);
1184+ if (a.length < b.length) {
1185+ tmp = a;
1186+ a = b;
1187+ b = tmp;
1188+ }
1189+ n1 = b.length;
1190+ n2 = a.length;
1191+ r = [];
1192+ for(i = 0; i < n1; i++)
1193+ r[i] = a[i] + b[i];
1194+ for(i = n1; i < n2; i++)
1195+ r[i] = a[i];
1196+ return Polynomial(r);
1197+ }
1198+ function polynomial_sub(a, b) {
1199+ return polynomial_add(a, -b);
1200+ }
1201+ function polynomial_mul(a, b) {
1202+ var i, j, n1, n2, n, r;
1203+ a = Polynomial(a);
1204+ b = Polynomial(b);
1205+ n1 = a.length;
1206+ n2 = b.length;
1207+ n = n1 + n2 - 1;
1208+ r = [];
1209+ for(i = 0; i < n; i++)
1210+ r[i] = 0;
1211+ for(i = 0; i < n1; i++) {
1212+ for(j = 0; j < n2; j++) {
1213+ r[i + j] += a[i] * b[j];
11371214 }
1138− return Polynomial(r);
1139− },
1140− [Symbol.operatorDiv](a, b) {
1141− if (b.constructor[Symbol.operatorOrder] <= OT_COMPLEX)
1142− return a * (1 / b);
1143− else
1144− return RationalFunction(Polynomial(a),
1145− Polynomial(b));
1146− },
1147− [Symbol.operatorPow]: generic_pow,
1148− [Symbol.operatorMathMod](a, b) {
1149− return Polynomial.divrem(a, b)[1];
1150− },
1151− [Symbol.operatorMod](a, b) {
1152− return Polynomial.divrem(a, b)[1];
1153− },
1154− [Symbol.operatorCmpEQ](a, b) {
1155− var n, i;
1156− if (!(a instanceof Polynomial) ||
1157− !(b instanceof Polynomial))
1158− return false;
1159− n = a.length;
1160− if (n != b.length)
1215+ }
1216+ return Polynomial(r);
1217+ }
1218+ function polynomial_div_scalar(a, b) {
1219+ return a * (1 / b);
1220+ }
1221+ function polynomial_div(a, b)
1222+ {
1223+ return RationalFunction(Polynomial(a),
1224+ Polynomial(b));
1225+ }
1226+ function polynomial_mod(a, b) {
1227+ return Polynomial.divrem(a, b)[1];
1228+ }
1229+ function polynomial_eq(a, b) {
1230+ var n, i;
1231+ n = a.length;
1232+ if (n != b.length)
1233+ return false;
1234+ for(i = 0; i < n; i++) {
1235+ if (a[i] != b[i])
11611236 return false;
1162− for(i = 0; i < n; i++) {
1163− if (a[i] != b[i])
1164− return false;
1165− }
1166− return true;
1167− },
1237+ }
1238+ return true;
1239+ }
1240+
1241+ operators_set(Polynomial.prototype,
1242+ {
1243+ "+": polynomial_add,
1244+ "-": polynomial_sub,
1245+ "*": polynomial_mul,
1246+ "/": polynomial_div,
1247+ "**": generic_pow,
1248+ "==": polynomial_eq,
1249+ "pos"(a) {
1250+ return a;
1251+ },
1252+ "neg"(a) {
1253+ var r, i, n, a;
1254+ n = a.length;
1255+ r = [];
1256+ for(i = 0; i < n; i++)
1257+ r[i] = -a[i];
1258+ return Polynomial(r);
1259+ },
1260+ },
1261+ {
1262+ left: [Number, BigInt, Float, Fraction, Complex, Mod],
1263+ "+": polynomial_add,
1264+ "-": polynomial_sub,
1265+ "*": polynomial_mul,
1266+ "/": polynomial_div,
1267+ "**": generic_pow, /* XXX: only for integer */
1268+ },
1269+ {
1270+ right: [Number, BigInt, Float, Fraction, Complex, Mod],
1271+ "+": polynomial_add,
1272+ "-": polynomial_sub,
1273+ "*": polynomial_mul,
1274+ "/": polynomial_div_scalar,
1275+ "**": generic_pow, /* XXX: only for integer */
1276+ });
1277+
1278+ add_props(Polynomial, {
11681279 divrem(a, b) {
11691280 var n1, n2, i, j, q, r, n, c;
11701281 if (b.deg() < 0)
@@ -1252,13 +1363,66 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 81 unmodified lines
12521363 return obj;
12531364 };
12541365
1366+ function polymod_add(a, b) {
1367+ if (!(a instanceof PolyMod)) {
1368+ return PolyMod(a + b.res, b.mod);
1369+ } else if (!(b instanceof PolyMod)) {
1370+ return PolyMod(a.res + b, a.mod);
1371+ } else {
1372+ if (a.mod != b.mod)
1373+ throw TypeError("different modulo for binary operator");
1374+ return PolyMod(a.res + b.res, a.mod);
1375+ }
1376+ }
1377+ function polymod_sub(a, b) {
1378+ return polymod_add(a, -b);
1379+ }
1380+ function polymod_mul(a, b) {
1381+ if (!(a instanceof PolyMod)) {
1382+ return PolyMod(a * b.res, b.mod);
1383+ } else if (!(b instanceof PolyMod)) {
1384+ return PolyMod(a.res * b, a.mod);
1385+ } else {
1386+ if (a.mod != b.mod)
1387+ throw TypeError("different modulo for binary operator");
1388+ return PolyMod(a.res * b.res, a.mod);
1389+ }
1390+ }
1391+ function polymod_div(a, b) {
1392+ if (!(b instanceof PolyMod))
1393+ b = PolyMod(b, a.mod);
1394+ return polymod_mul(a, b.inverse());
1395+ }
1396+ function polymod_eq(a, b) {
1397+ return (a.mod == b.mod && a.res == b.res);
1398+ }
1399+
1400+ operators_set(PolyMod.prototype,
1401+ {
1402+ "+": polymod_add,
1403+ "-": polymod_sub,
1404+ "*": polymod_mul,
1405+ "/": polymod_div,
1406+ "**": generic_pow,
1407+ "==": polymod_eq,
1408+ "pos"(a) {
1409+ return a;
1410+ },
1411+ "neg"(a) {
1412+ return PolyMod(-a.res, a.mod);
1413+ },
1414+ },
1415+ {
1416+ left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1417+ right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1418+ "+": polymod_add,
1419+ "-": polymod_sub,
1420+ "*": polymod_mul,
1421+ "/": polymod_div,
1422+ "**": generic_pow, /* XXX: only for integer */
1423+ });
1424+
12551425 add_props(PolyMod.prototype, {
1256− [Symbol.operatorPlus]() {
1257− return this;
1258− },
1259− [Symbol.operatorNeg]() {
1260− return PolyMod(-this.res, this.mod);
1261− },
12621426 inverse() {
12631427 var a = this, m = a.mod;
12641428 if (m instanceof Polynomial) {
@@ -1272,55 +1436,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 7 unmodified lines
12721436 },
12731437 });
12741438
1275− add_props(PolyMod, {
1276− [Symbol.operatorOrder]: OT_POLYMOD,
1277− [Symbol.operatorAdd](a, b) {
1278− if (!(a instanceof PolyMod)) {
1279− return PolyMod(a + b.res, b.mod);
1280− } else if (!(b instanceof PolyMod)) {
1281− return PolyMod(a.res + b, a.mod);
1282− } else {
1283− if (a.mod != b.mod)
1284− throw TypeError("different modulo for binary operator");
1285− return PolyMod(a.res + b.res, a.mod);
1286− }
1287− },
1288− [Symbol.operatorSub](a, b) {
1289− if (!(a instanceof PolyMod)) {
1290− return PolyMod(a - b.res, b.mod);
1291− } else if (!(b instanceof PolyMod)) {
1292− return PolyMod(a.res - b, a.mod);
1293− } else {
1294− if (a.mod != b.mod)
1295− throw TypeError("different modulo for binary operator");
1296− return PolyMod(a.res - b.res, a.mod);
1297− }
1298− },
1299− [Symbol.operatorMul](a, b) {
1300− if (!(a instanceof PolyMod)) {
1301− return PolyMod(a * b.res, b.mod);
1302− } else if (!(b instanceof PolyMod)) {
1303− return PolyMod(a.res * b, a.mod);
1304− } else {
1305− if (a.mod != b.mod)
1306− throw TypeError("different modulo for binary operator");
1307− return PolyMod(a.res * b.res, a.mod);
1308− }
1309− },
1310− [Symbol.operatorDiv](a, b) {
1311− if (!(b instanceof PolyMod))
1312− b = PolyMod(b, a.mod);
1313− return PolyMod[Symbol.operatorMul](a, b.inverse());
1314− },
1315− [Symbol.operatorPow]: generic_pow,
1316− [Symbol.operatorCmpEQ](a, b) {
1317− if (!(a instanceof PolyMod) ||
1318− !(b instanceof PolyMod))
1319− return false;
1320− return (a.mod == b.mod && a.res == b.res);
1321− }
1322− });
1323−
13241439 /* Rational function */
13251440
13261441 RationalFunction = function RationalFunction(a, b)
@@ -1347,12 +1462,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 20 unmodified lines
13471462 }
13481463
13491464 add_props(RationalFunction.prototype, {
1350− [Symbol.operatorPlus]() {
1351− return this;
1352− },
1353− [Symbol.operatorNeg]() {
1354− return RationalFunction(-this.num, this.den);
1355− },
13561465 inverse() {
13571466 return RationalFunction(this.den, this.num);
13581467 },
@@ -1378,8 +1487,59 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 19 unmodified lines
13781487 },
13791488 });
13801489
1490+ function ratfunc_add(a, b) {
1491+ a = RationalFunction.toRationalFunction(a);
1492+ b = RationalFunction.toRationalFunction(b);
1493+ return RationalFunction(a.num * b.den + a.den * b.num, a.den * b.den);
1494+ }
1495+ function ratfunc_sub(a, b) {
1496+ a = RationalFunction.toRationalFunction(a);
1497+ b = RationalFunction.toRationalFunction(b);
1498+ return RationalFunction(a.num * b.den - a.den * b.num, a.den * b.den);
1499+ }
1500+ function ratfunc_mul(a, b) {
1501+ a = RationalFunction.toRationalFunction(a);
1502+ b = RationalFunction.toRationalFunction(b);
1503+ return RationalFunction(a.num * b.num, a.den * b.den);
1504+ }
1505+ function ratfunc_div(a, b) {
1506+ a = RationalFunction.toRationalFunction(a);
1507+ b = RationalFunction.toRationalFunction(b);
1508+ return RationalFunction(a.num * b.den, a.den * b.num);
1509+ }
1510+ function ratfunc_eq(a, b) {
1511+ a = RationalFunction.toRationalFunction(a);
1512+ b = RationalFunction.toRationalFunction(b);
1513+ /* we assume the fractions are normalized */
1514+ return (a.num == b.num && a.den == b.den);
1515+ }
1516+
1517+ operators_set(RationalFunction.prototype,
1518+ {
1519+ "+": ratfunc_add,
1520+ "-": ratfunc_sub,
1521+ "*": ratfunc_mul,
1522+ "/": ratfunc_div,
1523+ "**": generic_pow,
1524+ "==": ratfunc_eq,
1525+ "pos"(a) {
1526+ return a;
1527+ },
1528+ "neg"(a) {
1529+ return RationalFunction(-this.num, this.den);
1530+ },
1531+ },
1532+ {
1533+ left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1534+ right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1535+ "+": ratfunc_add,
1536+ "-": ratfunc_sub,
1537+ "*": ratfunc_mul,
1538+ "/": ratfunc_div,
1539+ "**": generic_pow, /* should only be used with integers */
1540+ });
1541+
13811542 add_props(RationalFunction, {
1382− [Symbol.operatorOrder]: OT_RFUNC,
13831543 /* This function always return a RationalFunction object even
13841544 if it could simplified to a polynomial, so it is not
13851545 equivalent to RationalFunction(a) */
@@ -1394,33 +1554,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 8 unmodified lines
13941554 return obj;
13951555 }
13961556 },
1397− [Symbol.operatorAdd](a, b) {
1398− a = RationalFunction.toRationalFunction(a);
1399− b = RationalFunction.toRationalFunction(b);
1400− return RationalFunction(a.num * b.den + a.den * b.num, a.den * b.den);
1401− },
1402− [Symbol.operatorSub](a, b) {
1403− a = RationalFunction.toRationalFunction(a);
1404− b = RationalFunction.toRationalFunction(b);
1405− return RationalFunction(a.num * b.den - a.den * b.num, a.den * b.den);
1406− },
1407− [Symbol.operatorMul](a, b) {
1408− a = RationalFunction.toRationalFunction(a);
1409− b = RationalFunction.toRationalFunction(b);
1410− return RationalFunction(a.num * b.num, a.den * b.den);
1411− },
1412− [Symbol.operatorDiv](a, b) {
1413− a = RationalFunction.toRationalFunction(a);
1414− b = RationalFunction.toRationalFunction(b);
1415− return RationalFunction(a.num * b.den, a.den * b.num);
1416− },
1417− [Symbol.operatorPow]: generic_pow,
1418− [Symbol.operatorCmpEQ](a, b) {
1419− a = RationalFunction.toRationalFunction(a);
1420− b = RationalFunction.toRationalFunction(b);
1421− /* we assume the fractions are normalized */
1422− return (a.num == b.num && a.den == b.den);
1423− },
14241557 });
14251558
14261559 /* Power series */
@@ -1435,6 +1568,12 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 8 unmodified lines
14351568 }
14361569 return n;
14371570 };
1571+
1572+ function series_is_scalar_or_polynomial(a)
1573+ {
1574+ return polynomial_is_scalar(a) ||
1575+ (a instanceof Polynomial);
1576+ }
14381577
14391578 /* n is the maximum number of terms if 'a' is not a serie */
14401579 Series = function Series(a, n) {
@@ -1442,7 +1581,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 1 unmodified line
14421581
14431582 if (a instanceof Series) {
14441583 return a;
1445− } else if (a.constructor[Symbol.operatorOrder] <= OT_POLY) {
1584+ } else if (series_is_scalar_or_polynomial(a)) {
14461585 if (n <= 0) {
14471586 /* XXX: should still use the polynomial degree */
14481587 return Series.zero(0, 0);
@@ -1462,19 +1601,132 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 13 unmodified lines
14621601 }
14631602 };
14641603
1465− add_props(Series.prototype, {
1466− [Symbol.operatorPlus]() {
1467− return this;
1468− },
1469− [Symbol.operatorNeg]() {
1470− var obj, n, i;
1471− n = this.length;
1472− obj = Series.zero(this.length, this.emin);
1473− for(i = 0; i < n; i++) {
1474− obj[i] = -this[i];
1604+ function series_add(v1, v2) {
1605+ var tmp, d, emin, n, r, i, j, v2_emin, c1, c2;
1606+ if (!(v1 instanceof Series)) {
1607+ tmp = v1;
1608+ v1 = v2;
1609+ v2 = tmp;
1610+ }
1611+ d = v1.emin + v1.length;
1612+ if (series_is_scalar_or_polynomial(v2)) {
1613+ v2 = Polynomial(v2);
1614+ if (d <= 0)
1615+ return v1;
1616+ v2_emin = 0;
1617+ } else if (v2 instanceof RationalFunction) {
1618+ /* compute the emin of the rational fonction */
1619+ i = get_emin(v2.num) - get_emin(v2.den);
1620+ if (d <= i)
1621+ return v1;
1622+ /* compute the serie with the required terms */
1623+ v2 = Series(v2, d - i);
1624+ v2_emin = v2.emin;
1625+ } else {
1626+ v2_emin = v2.emin;
1627+ d = Math.min(d, v2_emin + v2.length);
1628+ }
1629+ emin = Math.min(v1.emin, v2_emin);
1630+ n = d - emin;
1631+ r = Series.zero(n, emin);
1632+ /* XXX: slow */
1633+ for(i = emin; i < d; i++) {
1634+ j = i - v1.emin;
1635+ if (j >= 0 && j < v1.length)
1636+ c1 = v1[j];
1637+ else
1638+ c1 = 0;
1639+ j = i - v2_emin;
1640+ if (j >= 0 && j < v2.length)
1641+ c2 = v2[j];
1642+ else
1643+ c2 = 0;
1644+ r[i - emin] = c1 + c2;
1645+ }
1646+ return r.trim();
1647+ }
1648+ function series_sub(a, b) {
1649+ return series_add(a, -b);
1650+ }
1651+ function series_mul(v1, v2) {
1652+ var n, i, j, r, n, emin, n1, n2, k;
1653+ if (!(v1 instanceof Series))
1654+ v1 = Series(v1, v2.length);
1655+ else if (!(v2 instanceof Series))
1656+ v2 = Series(v2, v1.length);
1657+ emin = v1.emin + v2.emin;
1658+ n = Math.min(v1.length, v2.length);
1659+ n1 = v1.length;
1660+ n2 = v2.length;
1661+ r = Series.zero(n, emin);
1662+ for(i = 0; i < n1; i++) {
1663+ k = Math.min(n2, n - i);
1664+ for(j = 0; j < k; j++) {
1665+ r[i + j] += v1[i] * v2[j];
14751666 }
1476− return obj;
1477− },
1667+ }
1668+ return r.trim();
1669+ }
1670+ function series_div(v1, v2) {
1671+ if (!(v2 instanceof Series))
1672+ v2 = Series(v2, v1.length);
1673+ return series_mul(v1, v2.inverse());
1674+ }
1675+ function series_pow(a, b) {
1676+ if (Integer.isInteger(b)) {
1677+ return generic_pow(a, b);
1678+ } else {
1679+ if (!(a instanceof Series))
1680+ a = Series(a, b.length);
1681+ return exp(log(a) * b);
1682+ }
1683+ }
1684+ function series_eq(a, b) {
1685+ var n, i;
1686+ if (a.emin != b.emin)
1687+ return false;
1688+ n = a.length;
1689+ if (n != b.length)
1690+ return false;
1691+ for(i = 0; i < n; i++) {
1692+ if (a[i] != b[i])
1693+ return false;
1694+ }
1695+ return true;
1696+ }
1697+
1698+ operators_set(Series.prototype,
1699+ {
1700+ "+": series_add,
1701+ "-": series_sub,
1702+ "*": series_mul,
1703+ "/": series_div,
1704+ "**": series_pow,
1705+ "==": series_eq,
1706+ "pos"(a) {
1707+ return a;
1708+ },
1709+ "neg"(a) {
1710+ var obj, n, i;
1711+ n = a.length;
1712+ obj = Series.zero(a.length, a.emin);
1713+ for(i = 0; i < n; i++) {
1714+ obj[i] = -a[i];
1715+ }
1716+ return obj;
1717+ },
1718+ },
1719+ {
1720+ left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1721+ right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1722+ "+": series_add,
1723+ "-": series_sub,
1724+ "*": series_mul,
1725+ "/": series_div,
1726+ "**": series_pow,
1727+ });
1728+
1729+ add_props(Series.prototype, {
14781730 conj() {
14791731 var obj, n, i;
14801732 n = this.length;
@@ -1610,7 +1862,6 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 129 unmodified lines
16101862 });
16111863
16121864 add_props(Series, {
1613− [Symbol.operatorOrder]: OT_SERIES,
16141865 /* new series of length n and first exponent emin */
16151866 zero(n, emin) {
16161867 var r, i, obj;
@@ -1624,108 +1875,12 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 7 unmodified lines
16241875 Object.setPrototypeOf(r, obj);
16251876 return r;
16261877 },
1627− [Symbol.operatorAdd](v1, v2) {
1628− var tmp, d, emin, n, r, i, j, v2_emin, c1, c2;
1629− if (!(v1 instanceof Series)) {
1630− tmp = v1;
1631− v1 = v2;
1632− v2 = tmp;
1633− }
1634− d = v1.emin + v1.length;
1635− if (v2.constructor[Symbol.operatorOrder] <= OT_POLY) {
1636− v2 = Polynomial(v2);
1637− if (d <= 0)
1638− return v1;
1639− v2_emin = 0;
1640− } else if (v2 instanceof RationalFunction) {
1641− /* compute the emin of the rational fonction */
1642− i = get_emin(v2.num) - get_emin(v2.den);
1643− if (d <= i)
1644− return v1;
1645− /* compute the serie with the required terms */
1646− v2 = Series(v2, d - i);
1647− v2_emin = v2.emin;
1648− } else {
1649− v2_emin = v2.emin;
1650− d = Math.min(d, v2_emin + v2.length);
1651− }
1652− emin = Math.min(v1.emin, v2_emin);
1653− n = d - emin;
1654− r = Series.zero(n, emin);
1655− /* XXX: slow */
1656− for(i = emin; i < d; i++) {
1657− j = i - v1.emin;
1658− if (j >= 0 && j < v1.length)
1659− c1 = v1[j];
1660− else
1661− c1 = 0;
1662− j = i - v2_emin;
1663− if (j >= 0 && j < v2.length)
1664− c2 = v2[j];
1665− else
1666− c2 = 0;
1667− r[i - emin] = c1 + c2;
1668− }
1669− return r.trim();
1670− },
1671− [Symbol.operatorSub](a, b) {
1672− return Series[Symbol.operatorAdd](a, -b);
1673− },
1674− [Symbol.operatorMul](v1, v2) {
1675− var n, i, j, r, n, emin, n1, n2, k;
1676− if (!(v1 instanceof Series))
1677− v1 = Series(v1, v2.length);
1678− else if (!(v2 instanceof Series))
1679− v2 = Series(v2, v1.length);
1680− emin = v1.emin + v2.emin;
1681− n = Math.min(v1.length, v2.length);
1682− n1 = v1.length;
1683− n2 = v2.length;
1684− r = Series.zero(n, emin);
1685− for(i = 0; i < n1; i++) {
1686− k = Math.min(n2, n - i);
1687− for(j = 0; j < k; j++) {
1688− r[i + j] += v1[i] * v2[j];
1689− }
1690− }
1691− return r.trim();
1692− },
1693− [Symbol.operatorDiv](v1, v2) {
1694− if (!(v2 instanceof Series))
1695− v2 = Series(v2, v1.length);
1696− return Series[Symbol.operatorMul](v1, v2.inverse());
1697− },
1698− [Symbol.operatorPow](a, b) {
1699− if (Integer.isInteger(b)) {
1700− return generic_pow(a, b);
1701− } else {
1702− if (!(a instanceof Series))
1703− a = Series(a, b.length);
1704− return exp(log(a) * b);
1705− }
1706− },
1707− [Symbol.operatorCmpEQ](a, b) {
1708− var n, i;
1709− if (!(a instanceof Series) ||
1710− !(b instanceof Series))
1711− return false;
1712− if (a.emin != b.emin)
1713− return false;
1714− n = a.length;
1715− if (n != b.length)
1716− return false;
1717− for(i = 0; i < n; i++) {
1718− if (a[i] != b[i])
1719− return false;
1720− }
1721− return true;
1722− },
17231878 O(a) {
17241879 function ErrorO() {
17251880 return TypeError("invalid O() argument");
17261881 }
17271882 var n;
1728− if (a.constructor[Symbol.operatorOrder] <= OT_POLY) {
1883+ if (series_is_scalar_or_polynomial(a)) {
17291884 a = Polynomial(a);
17301885 n = a.deg();
17311886 if (n < 0)
@@ -2061,130 +2216,138 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio · 329 unmodified lines
20612216 },
20622217 });
20632218
2064− add_props(Array, {
2065− [Symbol.operatorOrder]: OT_ARRAY,
2066− [Symbol.operatorAdd](a, b) {
2067− var r, i, n;
2068− if (!Array.isArray(a) || !Array.isArray(b))
2069− throw TypeError("array expected");
2070− n = a.length;
2071− if (n != b.length)
2072− throw TypeError("incompatible array size");
2073− r = [];
2074− for(i = 0; i < n; i++)
2075− r[i] = a[i] + b[i];
2076− return r;
2077− },
2078− [Symbol.operatorSub](a, b) {
2079− var r, i, n;
2080− n = a.length;
2081− if (!Array.isArray(a) || !Array.isArray(b))
2082− throw TypeError("array expected");
2083− if (n != b.length)
2084− throw TypeError("incompatible array size");
2085− r = [];
2086− for(i = 0; i < n; i++)
2087− r[i] = a[i] - b[i];
2088− return r;
2089− },
2090− scalar_mul(a, b) {
2091− var r, i, n;
2092− n = a.length;
2093− r = [];
2094− for(i = 0; i < n; i++)
2095− r[i] = a[i] * b;
2096− return r;
2097− },
2098− [Symbol.operatorMul](a, b) {
2099− var h, w, l, i, j, k, r, rl, sum, a_mat, b_mat, a_is_array, b_is_array;
2100− a_is_array = Array.isArray(a);
2101− b_is_array = Array.isArray(b);
2102− if (!a_is_array && !b_is_array) {
2103− throw TypeError("array expected");
2104− } else if (!a_is_array && b_is_array) {
2105− return Array.scalar_mul(b, a);
2106− } else if (a_is_array && !b_is_array) {
2107− return Array.scalar_mul(a, b);
2108− }
2109− h = a.length;
2110− a_mat = Array.isArray(a[0]);
2111− if (a_mat) {
2112− l = a[0].length;
2113− } else {
2114− l = 1;
2115− }
2116− if (l != b.length)
2117− throw RangeError("incompatible matrix size");
2118− b_mat = Array.isArray(b[0]);
2119− if (b_mat)
2120− w = b[0].length;
2121− else
2122− w = 1;
2123− r = [];
2124− if (a_mat && b_mat) {
2125− for(i = 0; i < h; i++) {
2126− rl = [];
2127− for(j = 0; j < w; j++) {
2128− sum = 0;
2129− for(k = 0; k < l; k++) {
2130− sum += a[i][k] * b[k][j];
2131− }
2132− rl[j] = sum;
2133− }
2134− r[i] = rl;
2135− }
2136− } else if (a_mat && !b_mat) {
2137− for(i = 0; i < h; i++) {
2219+ function array_add(a, b) {
2220+ var r, i, n;
2221+ n = a.length;
2222+ if (n != b.length)
2223+ throw TypeError("incompatible array size");
2224+ r = [];
2225+ for(i = 0; i < n; i++)
2226+ r[i] = a[i] + b[i];
2227+ return r;
2228+ }
2229+ function array_sub(a, b) {
2230+ var r, i, n;
2231+ n = a.length;
2232+ if (n != b.length)
2233+ throw TypeError("incompatible array size");
2234+ r = [];
2235+ for(i = 0; i < n; i++)
2236+ r[i] = a[i] - b[i];
2237+ return r;
2238+ }
2239+ function array_scalar_mul(a, b) {
2240+ var r, i, n;
2241+ n = a.length;
2242+ r = [];
2243+ for(i = 0; i < n; i++)
2244+ r[i] = a[i] * b;
2245+ return r;
2246+ }
2247+ function array_mul(a, b) {
2248+ var h, w, l, i, j, k, r, rl, sum, a_mat, b_mat;
2249+ h = a.length;
2250+ a_mat = Array.isArray(a[0]);
2251+ if (a_mat) {
2252+ l = a[0].length;
2253+ } else {
2254+ l = 1;
2255+ }
2256+ if (l != b.length)
2257+ throw RangeError("incompatible matrix size");
2258+ b_mat = Array.isArray(b[0]);
2259+ if (b_mat)
2260+ w = b[0].length;
2261+ else
2262+ w = 1;
2263+ r = [];
2264+ if (a_mat && b_mat) {
2265+ for(i = 0; i < h; i++) {
2266+ rl = [];
2267+ for(j = 0; j < w; j++) {
21382268 sum = 0;
21392269 for(k = 0; k < l; k++) {
2140− sum += a[i][k] * b[k];
2270+ sum += a[i][k] * b[k][j];
21412271 }
2142− r[i] = sum;
2272+ rl[j] = sum;
21432273 }
2144− } else if (!a_mat && b_mat) {
2145− for(i = 0; i < h; i++) {
2146− rl = [];
2147− for(j = 0; j < w; j++) {
2148− rl[j] = a[i] * b[0][j];
2149− }
2150− r[i] = rl;
2274+ r[i] = rl;
2275+ }
2276+ } else if (a_mat && !b_mat) {
2277+ for(i = 0; i < h; i++) {
2278+ sum = 0;
2279+ for(k = 0; k < l; k++) {
2280+ sum += a[i][k] * b[k];
21512281 }
2152− } else {
2153− for(i = 0; i < h; i++) {
2154− r[i] = a[i] * b[0];
2282+ r[i] = sum;
2283+ }
2284+ } else if (!a_mat && b_mat) {
2285+ for(i = 0; i < h; i++) {
2286+ rl = [];
2287+ for(j = 0; j < w; j++) {
2288+ rl[j] = a[i] * b[0][j];
21552289 }
2290+ r[i] = rl;
21562291 }
2157− return r;
2158− },
2159− [Symbol.operatorDiv](a, b) {
2160− return Array[Symbol.operatorMul](a, b.inverse());
2161− },
2162− [Symbol.operatorPow]: generic_pow,
2163− [Symbol.operatorCmpEQ](a, b) {
2164− var n, i;
2165− n = a.length;
2166− if (n != b.length)
2292+ } else {
2293+ for(i = 0; i < h; i++) {
2294+ r[i] = a[i] * b[0];
2295+ }
2296+ }
2297+ return r;
2298+ }
2299+ function array_div(a, b) {
2300+ return array_mul(a, b.inverse());
2301+ }
2302+ function array_scalar_div(a, b) {
2303+ return a * b.inverse();
2304+ }
2305+ function array_eq(a, b) {
2306+ var n, i;
2307+ n = a.length;
2308+ if (n != b.length)
2309+ return false;
2310+ for(i = 0; i < n; i++) {
2311+ if (a[i] != b[i])
21672312 return false;
2168− for(i = 0; i < n; i++) {
2169− if (a[i] != b[i])
2170− return false;
2313+ }
2314+ return true;
2315+ }
2316+
2317+ operators_set(Array.prototype,
2318+ {
2319+ "+": array_add,
2320+ "-": array_sub,
2321+ "*": array_mul,
2322+ "/": array_div,
2323+ "==": array_eq,
2324+ "pos"(a) {
2325+ return a;
2326+ },
2327+ "neg"(a) {
2328+ var i, n, r;
2329+ n = a.length;
2330+ r = [];
2331+ for(i = 0; i < n; i++)
2332+ r[i] = -a[i];
2333+ return r;
21712334 }
2172− return true;
21732335 },
2174− });
2336+ {
2337+ right: [Number, BigInt, Float, Fraction, Complex, Mod,
2338+ Polynomial, PolyMod, RationalFunction, Series],
2339+ "*": array_scalar_mul,
2340+ "/": array_scalar_div,
2341+ "**": generic_pow, /* XXX: only for integer */
2342+ },
2343+ {
2344+ left: [Number, BigInt, Float, Fraction, Complex, Mod,
2345+ Polynomial, PolyMod, RationalFunction, Series],
2346+ "*"(a, b) { return array_scalar_mul(b, a); },
2347+ "/"(a, b) { return array_scalar_div(b, a); },
2348+ });
21752349
21762350 add_props(Array.prototype, {
2177− [Symbol.operatorPlus]() {
2178− return this;
2179− },
2180− [Symbol.operatorNeg]() {
2181− var i, n, r;
2182− n = this.length;
2183− r = [];
2184− for(i = 0; i < n; i++)
2185− r[i] = -this[i];
2186− return r;
2187− },
21882351 conj() {
21892352 var i, n, r;
21902353 n = this.length;
@@ -2426,6 +2589,42 @@ function fromdeg(a) · 235 unmodified lines
24262589 return a * Float.PI / 180;
24272590 }
24282591
2592+function sinh(a)
2593+{
2594+ var e = Float.exp(Float(a));
2595+ return (e - 1/e) * 0.5;
2596+}
2597+
2598+function cosh(a)
2599+{
2600+ var e = Float.exp(Float(a));
2601+ return (e + 1/e) * 0.5;
2602+}
2603+
2604+function tanh(a)
2605+{
2606+ var e = Float.exp(Float(a) * 2);
2607+ return (e - 1) / (e + 1);
2608+}
2609+
2610+function asinh(a)
2611+{
2612+ var x = Float(a);
2613+ return log(sqrt(x * x + 1) + x);
2614+}
2615+
2616+function acosh(a)
2617+{
2618+ var x = Float(a);
2619+ return log(sqrt(x * x - 1) + x);
2620+}
2621+
2622+function atanh(a)
2623+{
2624+ var x = Float(a);
2625+ return 0.5 * log((1 + x) / (1 - x));
2626+}
2627+
24292628 var idn = Matrix.idn;
24302629 var diag = Matrix.diag;
24312630 var trans = Matrix.trans;
quickjs-atom.h+4−22
@@ -219,6 +219,8 @@ DEF(BigInt, "BigInt") · 218 unmodified lines
219219 DEF(BigFloat, "BigFloat")
220220 DEF(BigFloatEnv, "BigFloatEnv")
221221 DEF(BigDecimal, "BigDecimal")
222+DEF(OperatorSet, "OperatorSet")
223+DEF(Operators, "Operators")
222224 #endif
223225 DEF(Map, "Map")
224226 DEF(Set, "Set") /* Map + 1 */
@@ -263,27 +265,7 @@ DEF(Symbol_species, "Symbol.species") · 38 unmodified lines
263265 DEF(Symbol_unscopables, "Symbol.unscopables")
264266 DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
265267 #ifdef CONFIG_BIGNUM
266−DEF(Symbol_operatorOrder, "Symbol.operatorOrder")
267−DEF(Symbol_operatorAdd, "Symbol.operatorAdd")
268−DEF(Symbol_operatorSub, "Symbol.operatorSub")
269−DEF(Symbol_operatorMul, "Symbol.operatorMul")
270−DEF(Symbol_operatorDiv, "Symbol.operatorDiv")
271−DEF(Symbol_operatorMod, "Symbol.operatorMod")
272−DEF(Symbol_operatorPow, "Symbol.operatorPow")
273−DEF(Symbol_operatorShl, "Symbol.operatorShl")
274−DEF(Symbol_operatorShr, "Symbol.operatorShr")
275−DEF(Symbol_operatorAnd, "Symbol.operatorAnd")
276−DEF(Symbol_operatorOr, "Symbol.operatorOr")
277−DEF(Symbol_operatorXor, "Symbol.operatorXor")
278−DEF(Symbol_operatorCmpLT, "Symbol.operatorCmpLT")
279−DEF(Symbol_operatorCmpLE, "Symbol.operatorCmpLE")
280−DEF(Symbol_operatorCmpEQ, "Symbol.operatorCmpEQ")
281−DEF(Symbol_operatorPlus, "Symbol.operatorPlus")
282−DEF(Symbol_operatorNeg, "Symbol.operatorNeg")
283−DEF(Symbol_operatorNot, "Symbol.operatorNot")
284−DEF(Symbol_operatorInc, "Symbol.operatorInc")
285−DEF(Symbol_operatorDec, "Symbol.operatorDec")
286−DEF(Symbol_operatorMathMod, "Symbol.operatorMathMod")
268+DEF(Symbol_operatorSet, "Symbol.operatorSet")
287269 #endif
288−
270+
289271 #endif /* DEF */
quickjs-libc.c+15−0
@@ -2027,6 +2027,20 @@ static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val, · 2026 unmodified lines
20272027
20282028 #if !defined(_WIN32)
20292029
2030+static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val,
2031+ int argc, JSValueConst *argv)
2032+{
2033+ const char *target;
2034+ int err;
2035+
2036+ target = JS_ToCString(ctx, argv[0]);
2037+ if (!target)
2038+ return JS_EXCEPTION;
2039+ err = chdir(target);
2040+ JS_FreeCString(ctx, target);
2041+ return js_os_return(ctx, err);
2042+}
2043+
20302044 /* return [path, errorcode] */
20312045 static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
20322046 int argc, JSValueConst *argv)
@@ -2581,6 +2595,7 @@ static const JSCFunctionListEntry js_os_funcs[] = { · 548 unmodified lines
25812595 JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
25822596 JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
25832597 #if !defined(_WIN32)
2598+ JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
25842599 JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
25852600 JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ),
25862601 JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),
quickjs-opcode.h+0−3
@@ -260,9 +260,7 @@ DEF( or, 1, 2, 1, none) · 259 unmodified lines
260260 DEF(is_undefined_or_null, 1, 1, 1, none)
261261 #ifdef CONFIG_BIGNUM
262262 DEF( mul_pow10, 1, 2, 1, none)
263−DEF( math_div, 1, 2, 1, none)
264263 DEF( math_mod, 1, 2, 1, none)
265−DEF( math_pow, 1, 2, 1, none)
266264 #endif
267265 /* must be the last non short and non temporary opcode */
268266 DEF( nop, 1, 0, 0, none)
@@ -271,7 +269,6 @@ DEF( nop, 1, 0, 0, none) · 2 unmodified lines
271269
272270 def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */
273271
274−def(close_var_object, 1, 0, 0, none) /* emitted in phase 1, removed in phase 2 */
275272 def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
276273 def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
277274
quickjs.c+1788−1418
@@ -42,10 +42,6 @@ · 41 unmodified lines
4242 #include "list.h"
4343 #include "quickjs.h"
4444 #include "libregexp.h"
45−
46−/* enable bignums */
47−#define CONFIG_BIGNUM
48−
4945 #ifdef CONFIG_BIGNUM
5046 #include "libbf.h"
5147 #endif
@@ -151,7 +147,8 @@ enum { · 99 unmodified lines
151147 JS_CLASS_BIG_INT, /* u.object_data */
152148 JS_CLASS_BIG_FLOAT, /* u.object_data */
153149 JS_CLASS_FLOAT_ENV, /* u.float_env */
154− JS_CLASS_BIG_DECIMAL, /* u.object_data */
150+ JS_CLASS_BIG_DECIMAL, /* u.object_data */
151+ JS_CLASS_OPERATOR_SET, /* u.operator_set */
155152 #endif
156153 JS_CLASS_MAP, /* u.map_state */
157154 JS_CLASS_SET, /* u.map_state */
@@ -285,6 +282,7 @@ struct JSRuntime { · 127 unmodified lines
285282 JSNumericOperations bigint_ops;
286283 JSNumericOperations bigfloat_ops;
287284 JSNumericOperations bigdecimal_ops;
285+ uint32_t operator_count;
288286 #endif
289287 };
290288
@@ -300,8 +298,7 @@ struct JSClass { · 9 unmodified lines
300298
301299 #define JS_MODE_STRICT (1 << 0)
302300 #define JS_MODE_STRIP (1 << 1)
303−#define JS_MODE_BIGINT (1 << 2)
304−#define JS_MODE_MATH (1 << 3)
301+#define JS_MODE_MATH (1 << 2)
305302
306303 typedef struct JSStackFrame {
307304 struct JSStackFrame *prev_frame; /* NULL if first stack frame */
@@ -312,7 +309,7 @@ typedef struct JSStackFrame { · 4 unmodified lines
312309 const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
313310 instruction after the call */
314311 int arg_count;
315− int js_mode; /* 0 or JS_MODE_BIGINT for C functions */
312+ int js_mode; /* 0 or JS_MODE_MATH for C functions */
316313 /* only used in generators. Current stack pointer value. NULL if
317314 the function is running. */
318315 JSValue *cur_sp;
@@ -419,8 +416,8 @@ struct JSContext { · 100 unmodified lines
419416 #ifdef CONFIG_BIGNUM
420417 bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */
421418 JSFloatEnv fp_env; /* global FP environment */
422− BOOL bignum_ext; /* enable bigint mode, math mode and operator
423− overloading */
419+ BOOL bignum_ext : 8; /* enable math mode */
420+ BOOL allow_operator_overloading : 8;
424421 #endif
425422 /* when the counter reaches zero, JSRutime.interrupt_handler is called */
426423 int interrupt_counter;
@@ -653,6 +650,53 @@ typedef struct JSAsyncFunctionData { · 226 unmodified lines
653650 JSAsyncFunctionState func_state;
654651 } JSAsyncFunctionData;
655652
653+typedef enum {
654+ /* binary operators */
655+ JS_OVOP_ADD,
656+ JS_OVOP_SUB,
657+ JS_OVOP_MUL,
658+ JS_OVOP_DIV,
659+ JS_OVOP_MOD,
660+ JS_OVOP_POW,
661+ JS_OVOP_OR,
662+ JS_OVOP_AND,
663+ JS_OVOP_XOR,
664+ JS_OVOP_SHL,
665+ JS_OVOP_SAR,
666+ JS_OVOP_SHR,
667+ JS_OVOP_EQ,
668+ JS_OVOP_LESS,
669+
670+ JS_OVOP_BINARY_COUNT,
671+ /* unary operators */
672+ JS_OVOP_POS = JS_OVOP_BINARY_COUNT,
673+ JS_OVOP_NEG,
674+ JS_OVOP_INC,
675+ JS_OVOP_DEC,
676+ JS_OVOP_NOT,
677+
678+ JS_OVOP_COUNT,
679+} JSOverloadableOperatorEnum;
680+
681+typedef struct {
682+ uint32_t operator_index;
683+ JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */
684+} JSBinaryOperatorDefEntry;
685+
686+typedef struct {
687+ int count;
688+ JSBinaryOperatorDefEntry *tab;
689+} JSBinaryOperatorDef;
690+
691+typedef struct {
692+ uint32_t operator_counter;
693+ BOOL is_primitive; /* OperatorSet for a primitive type */
694+ /* NULL if no operator is defined */
695+ JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */
696+ JSBinaryOperatorDef left;
697+ JSBinaryOperatorDef right;
698+} JSOperatorSetData;
699+
656700 typedef struct JSReqModuleEntry {
657701 JSAtom module_name;
658702 JSModuleDef *module; /* used using resolution */
@@ -808,6 +852,7 @@ struct JSObject { · 149 unmodified lines
808852 struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
809853 #ifdef CONFIG_BIGNUM
810854 struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */
855+ struct JSOperatorSetData *operator_set; /* JS_CLASS_OPERATOR_SET */
811856 #endif
812857 struct JSMapState *map_state; /* JS_CLASS_MAP..JS_CLASS_WEAKSET */
813858 struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */
@@ -991,6 +1036,11 @@ static void js_promise_mark(JSRuntime *rt, JSValueConst val, · 177 unmodified lines
9911036 static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);
9921037 static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
9931038 JS_MarkFunc *mark_func);
1039+#ifdef CONFIG_BIGNUM
1040+static void js_operator_set_finalizer(JSRuntime *rt, JSValue val);
1041+static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
1042+ JS_MarkFunc *mark_func);
1043+#endif
9941044 static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
9951045 static int JS_ToBoolFree(JSContext *ctx, JSValue val);
9961046 static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
@@ -1021,10 +1071,27 @@ static JSProperty *add_property(JSContext *ctx, · 24 unmodified lines
10211071 JSObject *p, JSAtom prop, int prop_flags);
10221072 #ifdef CONFIG_BIGNUM
10231073 static void js_float_env_finalizer(JSRuntime *rt, JSValue val);
1024−static JSValue JS_NewBigFloat(JSContext *ctx, bf_t *a);
1025−static JSValue JS_NewBigDecimal(JSContext *ctx, bfdec_t *a);
1026−static JSValue JS_NewBigInt2(JSContext *ctx, bf_t *a, BOOL force_bigint);
1027−static JSValue JS_NewBigInt(JSContext *ctx, bf_t *a);
1074+static JSValue JS_NewBigFloat(JSContext *ctx);
1075+static inline bf_t *JS_GetBigFloat(JSValueConst val)
1076+{
1077+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
1078+ return &p->num;
1079+}
1080+static JSValue JS_NewBigDecimal(JSContext *ctx);
1081+static inline bfdec_t *JS_GetBigDecimal(JSValueConst val)
1082+{
1083+ JSBigDecimal *p = JS_VALUE_GET_PTR(val);
1084+ return &p->num;
1085+}
1086+static JSValue JS_NewBigInt(JSContext *ctx);
1087+static inline bf_t *JS_GetBigInt(JSValueConst val)
1088+{
1089+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
1090+ return &p->num;
1091+}
1092+static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
1093+ BOOL convert_to_safe_integer);
1094+static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
10281095 static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
10291096 static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
10301097 static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
@@ -1123,19 +1190,6 @@ static const JSClassExoticMethods js_proxy_exotic_methods; · 92 unmodified lines
11231190 static const JSClassExoticMethods js_module_ns_exotic_methods;
11241191 static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
11251192
1126−JS_BOOL JS_IsNumber(JSValueConst v)
1127−{
1128−#ifdef CONFIG_BIGNUM
1129− /* XXX: check the bignum case. Should use a different function */
1130− int tag = JS_VALUE_GET_TAG(v);
1131− return tag == JS_TAG_INT || tag == JS_TAG_BIG_INT ||
1132− tag == JS_TAG_BIG_FLOAT || JS_TAG_IS_FLOAT64(tag);
1133−#else
1134− int tag = JS_VALUE_GET_TAG(v);
1135− return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);
1136−#endif
1137−}
1138−
11391193 static void js_trigger_gc(JSRuntime *rt, size_t size)
11401194 {
11411195 BOOL force_gc;
@@ -1333,6 +1387,7 @@ static JSClassShortDef const js_std_class_def[] = { · 191 unmodified lines
13331387 { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_FLOAT */
13341388 { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL }, /* JS_CLASS_FLOAT_ENV */
13351389 { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_DECIMAL */
1390+ { JS_ATOM_OperatorSet, js_operator_set_finalizer, js_operator_set_mark }, /* JS_CLASS_OPERATOR_SET */
13361391 #endif
13371392 { JS_ATOM_Map, js_map_finalizer, js_map_mark }, /* JS_CLASS_MAP */
13381393 { JS_ATOM_Set, js_map_finalizer, js_map_mark }, /* JS_CLASS_SET */
@@ -2136,10 +2191,10 @@ static inline BOOL is_strict_mode(JSContext *ctx) · 797 unmodified lines
21362191 }
21372192
21382193 #ifdef CONFIG_BIGNUM
2139−static inline BOOL is_bigint_mode(JSContext *ctx)
2194+static inline BOOL is_math_mode(JSContext *ctx)
21402195 {
21412196 JSStackFrame *sf = ctx->current_stack_frame;
2142− return (sf && (sf->js_mode & JS_MODE_BIGINT));
2197+ return (sf && (sf->js_mode & JS_MODE_MATH));
21432198 }
21442199 #endif
21452200
@@ -2148,25 +2203,12 @@ JSValue JS_NewInt64(JSContext *ctx, int64_t v) · 2 unmodified lines
21482203 if (v == (int32_t)v) {
21492204 return JS_NewInt32(ctx, v);
21502205 } else {
2151−#ifdef CONFIG_BIGNUM
2152− if (is_bigint_mode(ctx)) {
2153− bf_t a_s, *a = &a_s;
2154− bf_init(ctx->bf_ctx, a);
2155− bf_set_si(a, v);
2156− return JS_NewBigInt(ctx, a);
2157− } else
2158−#endif
2159− {
2160− return __JS_NewFloat64(ctx, (double)v);
2161− }
2206+ return __JS_NewFloat64(ctx, (double)v);
21622207 }
21632208 }
21642209
21652210 static force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
21662211 {
2167−#ifdef CONFIG_BIGNUM
2168− return JS_NewInt64(ctx, val);
2169−#else
21702212 JSValue v;
21712213 if (val <= 0x7fffffff) {
21722214 v = JS_MKVAL(JS_TAG_INT, val);
@@ -2174,7 +2216,6 @@ static force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val) · 1 unmodified line
21742216 v = __JS_NewFloat64(ctx, val);
21752217 }
21762218 return v;
2177−#endif
21782219 }
21792220
21802221 /* JSAtom support */
@@ -5720,6 +5761,7 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) · 3539 unmodified lines
57205761 #ifdef CONFIG_BIGNUM
57215762 case JS_CLASS_BIG_INT: /* u.object_data */
57225763 case JS_CLASS_BIG_FLOAT: /* u.object_data */
5764+ case JS_CLASS_BIG_DECIMAL: /* u.object_data */
57235765 #endif
57245766 compute_value_size(p->u.object_data, hp);
57255767 break;
@@ -6515,28 +6557,17 @@ JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val) · 789 unmodified lines
65156557 case JS_TAG_BIG_INT:
65166558 val = ctx->class_proto[JS_CLASS_BIG_INT];
65176559 break;
6518− case JS_TAG_INT:
6519− if (is_bigint_mode(ctx)) {
6520− val = ctx->class_proto[JS_CLASS_BIG_INT];
6521− } else {
6522− val = ctx->class_proto[JS_CLASS_NUMBER];
6523− }
6524− break;
6525− case JS_TAG_FLOAT64:
6526− val = ctx->class_proto[JS_CLASS_NUMBER];
6527− break;
65286560 case JS_TAG_BIG_FLOAT:
65296561 val = ctx->class_proto[JS_CLASS_BIG_FLOAT];
65306562 break;
65316563 case JS_TAG_BIG_DECIMAL:
65326564 val = ctx->class_proto[JS_CLASS_BIG_DECIMAL];
65336565 break;
6534−#else
6566+#endif
65356567 case JS_TAG_INT:
65366568 case JS_TAG_FLOAT64:
65376569 val = ctx->class_proto[JS_CLASS_NUMBER];
65386570 break;
6539−#endif
65406571 case JS_TAG_BOOL:
65416572 val = ctx->class_proto[JS_CLASS_BOOLEAN];
65426573 break;
@@ -7750,11 +7781,7 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSProperty *prop, · 1207 unmodified lines
77507781 }
77517782 p->u.array.count = len;
77527783 }
7753−#ifdef CONFIG_BIGNUM
7754− set_value(ctx, &prop->u.value, JS_NewUint32(ctx, len));
7755−#else
77567784 prop->u.value = JS_NewUint32(ctx, len);
7757−#endif
77587785 } else {
77597786 /* Note: length is always a uint32 because the object is an
77607787 array */
@@ -9352,9 +9379,6 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id) · 1591 unmodified lines
93529379 #define HINT_STRING 0
93539380 #define HINT_NUMBER 1
93549381 #define HINT_NONE 2
9355−#ifdef CONFIG_BIGNUM
9356−#define HINT_INTEGER 3
9357−#endif
93589382 /* don't try Symbol.toPrimitive */
93599383 #define HINT_FORCE_ORDINARY (1 << 4)
93609384
@@ -9389,11 +9413,6 @@ static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint) · 28 unmodified lines
93899413 case HINT_NONE:
93909414 atom = JS_ATOM_default;
93919415 break;
9392−#ifdef CONFIG_BIGNUM
9393− case HINT_INTEGER:
9394− atom = JS_ATOM_integer;
9395− break;
9396−#endif
93979416 }
93989417 arg = JS_AtomToString(ctx, atom);
93999418 ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
@@ -9605,22 +9624,31 @@ static JSValue js_string_to_bigint(JSContext *ctx, const char *buf, · 205 unmodified lines
96059624 {
96069625 bf_t a_s, *a = &a_s;
96079626 int ret;
9608− bf_init(ctx->bf_ctx, a);
9627+ JSValue val;
9628+ val = JS_NewBigInt(ctx);
9629+ if (JS_IsException(val))
9630+ return val;
9631+ a = JS_GetBigInt(val);
96099632 ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);
96109633 if (ret & BF_ST_MEM_ERROR) {
9611− bf_delete(a);
9634+ JS_FreeValue(ctx, val);
96129635 return JS_ThrowOutOfMemory(ctx);
96139636 }
9614− return JS_NewBigInt2(ctx, a, !(flags & ATOD_MODE_BIGINT));
9637+ val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0);
9638+ return val;
96159639 }
96169640
96179641 static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf,
96189642 int radix, int flags, slimb_t *pexponent)
96199643 {
9620− bf_t a_s, *a = &a_s;
9644+ bf_t *a;
96219645 int ret;
9622−
9623− bf_init(ctx->bf_ctx, a);
9646+ JSValue val;
9647+
9648+ val = JS_NewBigFloat(ctx);
9649+ if (JS_IsException(val))
9650+ return val;
9651+ a = JS_GetBigFloat(val);
96249652 if (flags & ATOD_ACCEPT_SUFFIX) {
96259653 /* return the exponent to get infinite precision */
96269654 ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF,
@@ -9630,25 +9658,30 @@ static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf, · 3 unmodified lines
96309658 ctx->fp_env.flags);
96319659 }
96329660 if (ret & BF_ST_MEM_ERROR) {
9633− bf_delete(a);
9661+ JS_FreeValue(ctx, val);
96349662 return JS_ThrowOutOfMemory(ctx);
96359663 }
9636− return JS_NewBigFloat(ctx, a);
9664+ return val;
96379665 }
96389666
96399667 static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,
96409668 int radix, int flags, slimb_t *pexponent)
96419669 {
9642− bfdec_t a_s, *a = &a_s;
9670+ bfdec_t *a;
96439671 int ret;
9644− bfdec_init(ctx->bf_ctx, a);
9672+ JSValue val;
9673+
9674+ val = JS_NewBigDecimal(ctx);
9675+ if (JS_IsException(val))
9676+ return val;
9677+ a = JS_GetBigDecimal(val);
96459678 ret = bfdec_atof(a, buf, NULL, BF_PREC_INF,
96469679 BF_RNDZ | BF_ATOF_NO_NAN_INF);
96479680 if (ret & BF_ST_MEM_ERROR) {
9648− bfdec_delete(a);
9681+ JS_FreeValue(ctx, val);
96499682 return JS_ThrowOutOfMemory(ctx);
96509683 }
9651− return JS_NewBigDecimal(ctx, a);
9684+ return val;
96529685 }
96539686
96549687 #endif
@@ -9730,10 +9763,12 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, · 75 unmodified lines
97309763 strstart(p, "Infinity", &p)) {
97319764 #ifdef CONFIG_BIGNUM
97329765 if (atod_type == ATOD_TYPE_BIG_FLOAT) {
9733− bf_t a_s, *a = &a_s;
9734− bf_init(ctx->bf_ctx, a);
9766+ bf_t *a;
9767+ val = JS_NewBigFloat(ctx);
9768+ if (JS_IsException(val))
9769+ goto done;
9770+ a = JS_GetBigFloat(val);
97359771 bf_set_inf(a, is_neg);
9736− val = JS_NewBigFloat(ctx, a);
97379772 } else
97389773 #endif
97399774 {
@@ -9810,7 +9845,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, · 70 unmodified lines
98109845 } else if (*p == 'l') {
98119846 p++;
98129847 atod_type = ATOD_TYPE_BIG_FLOAT;
9813− } else if (*p == 'd') {
9848+ } else if (*p == 'm') {
98149849 p++;
98159850 atod_type = ATOD_TYPE_BIG_DECIMAL;
98169851 } else {
@@ -9901,7 +9936,6 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, · 84 unmodified lines
99019936
99029937 typedef enum JSToNumberHintEnum {
99039938 TON_FLAG_NUMBER,
9904− TON_FLAG_INTEGER,
99059939 TON_FLAG_NUMERIC,
99069940 } JSToNumberHintEnum;
99079941
@@ -9910,7 +9944,6 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, · 2 unmodified lines
99109944 {
99119945 uint32_t tag;
99129946 JSValue ret;
9913− int hint;
99149947
99159948 redo:
99169949 tag = JS_VALUE_GET_NORM_TAG(val);
@@ -9924,12 +9957,19 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, · 7 unmodified lines
99249957 ret = val;
99259958 break;
99269959 case JS_TAG_BIG_INT:
9927− if (flag == TON_FLAG_NUMBER && !is_bigint_mode(ctx)) {
9960+ if (flag != TON_FLAG_NUMERIC) {
99289961 JS_FreeValue(ctx, val);
99299962 return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
99309963 }
9931− /* fall thru */
9964+ ret = val;
9965+ break;
99329966 case JS_TAG_BIG_FLOAT:
9967+ if (flag != TON_FLAG_NUMERIC) {
9968+ JS_FreeValue(ctx, val);
9969+ return JS_ThrowTypeError(ctx, "cannot convert bigfloat to number");
9970+ }
9971+ ret = val;
9972+ break;
99339973 #endif
99349974 case JS_TAG_FLOAT64:
99359975 case JS_TAG_INT:
@@ -9944,12 +9984,7 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, · 8 unmodified lines
99449984 ret = JS_NAN;
99459985 break;
99469986 case JS_TAG_OBJECT:
9947−#ifdef CONFIG_BIGNUM
9948− hint = flag == TON_FLAG_INTEGER ? HINT_INTEGER : HINT_NUMBER;
9949−#else
9950− hint = HINT_NUMBER;
9951−#endif
9952− val = JS_ToPrimitiveFree(ctx, val, hint);
9987+ val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
99539988 if (JS_IsException(val))
99549989 return JS_EXCEPTION;
99559990 goto redo;
@@ -9969,10 +10004,6 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, · 13 unmodified lines
996910004 ret = JS_NewInt32(ctx, 0);
997010005 } else {
997110006 int flags = ATOD_ACCEPT_BIN_OCT;
9972−#ifdef CONFIG_BIGNUM
9973− if (is_bigint_mode(ctx))
9974− flags |= ATOD_MODE_BIGINT;
9975−#endif
997610007 ret = js_atof(ctx, p, &p, 0, flags);
997710008 if (!JS_IsException(ret)) {
997810009 p += skip_spaces(p);
@@ -10001,7 +10032,6 @@ static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val) · 22 unmodified lines
1000110032 return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
1000210033 }
1000310034
10004−#ifdef CONFIG_BIGNUM
1000510035 static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
1000610036 {
1000710037 return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
@@ -10011,7 +10041,6 @@ static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val) · 3 unmodified lines
1001110041 {
1001210042 return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
1001310043 }
10014−#endif
1001510044
1001610045 static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
1001710046 JSValue val)
@@ -10078,6 +10107,7 @@ static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val) · 60 unmodified lines
1007810107 return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
1007910108 }
1008010109
10110+/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
1008110111 static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
1008210112 {
1008310113 uint32_t tag;
@@ -10106,11 +10136,6 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) · 22 unmodified lines
1010610136 }
1010710137 break;
1010810138 #ifdef CONFIG_BIGNUM
10109− case JS_TAG_BIG_INT:
10110− if (!is_bigint_mode(ctx))
10111− goto to_number;
10112− ret = val;
10113− break;
1011410139 case JS_TAG_BIG_FLOAT:
1011510140 {
1011610141 bf_t a_s, *a, r_s, *r = &r_s;
@@ -10124,10 +10149,13 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) · 7 unmodified lines
1012410149 else
1012510150 ret = JS_DupValue(ctx, val);
1012610151 } else {
10127− bf_init(ctx->bf_ctx, r);
10128− bf_set(r, a);
10129− bf_rint(r, BF_RNDZ);
10130− ret = JS_NewBigInt(ctx, r);
10152+ ret = JS_NewBigInt(ctx);
10153+ if (!JS_IsException(ret)) {
10154+ r = JS_GetBigInt(ret);
10155+ bf_set(r, a);
10156+ bf_rint(r, BF_RNDZ);
10157+ ret = JS_CompactBigInt(ctx, ret);
10158+ }
1013110159 }
1013210160 if (a == &a_s)
1013310161 bf_delete(a);
@@ -10136,9 +10164,6 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) · 2 unmodified lines
1013610164 break;
1013710165 #endif
1013810166 default:
10139−#ifdef CONFIG_BIGNUM
10140− to_number:
10141−#endif
1014210167 val = JS_ToNumberFree(ctx, val);
1014310168 if (JS_IsException(val))
1014410169 return val;
@@ -10182,17 +10207,12 @@ static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val) · 37 unmodified lines
1018210207 break;
1018310208 #ifdef CONFIG_BIGNUM
1018410209 case JS_TAG_BIG_FLOAT:
10185− to_bf:
1018610210 {
1018710211 JSBigFloat *p = JS_VALUE_GET_PTR(val);
1018810212 bf_get_int32(&ret, &p->num, 0);
1018910213 JS_FreeValue(ctx, val);
1019010214 }
1019110215 break;
10192− case JS_TAG_BIG_INT:
10193− if (is_bigint_mode(ctx))
10194− goto to_bf;
10195− /* fall thru */
1019610216 #endif
1019710217 default:
1019810218 val = JS_ToNumberFree(ctx, val);
@@ -10261,17 +10281,12 @@ static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val) · 62 unmodified lines
1026110281 return 0;
1026210282 #ifdef CONFIG_BIGNUM
1026310283 case JS_TAG_BIG_FLOAT:
10264− to_bf:
1026510284 {
1026610285 JSBigFloat *p = JS_VALUE_GET_PTR(val);
1026710286 bf_get_int64(pres, &p->num, 0);
1026810287 JS_FreeValue(ctx, val);
1026910288 }
1027010289 return 0;
10271− case JS_TAG_BIG_INT:
10272− if (is_bigint_mode(ctx))
10273− goto to_bf;
10274− /* fall thru */
1027510290 #endif
1027610291 default:
1027710292 val = JS_ToNumberFree(ctx, val);
@@ -10346,17 +10361,12 @@ static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val) · 68 unmodified lines
1034610361 break;
1034710362 #ifdef CONFIG_BIGNUM
1034810363 case JS_TAG_BIG_FLOAT:
10349− to_bf:
1035010364 {
1035110365 JSBigFloat *p = JS_VALUE_GET_PTR(val);
1035210366 bf_get_int64(&ret, &p->num, BF_GET_INT_MOD);
1035310367 JS_FreeValue(ctx, val);
1035410368 }
1035510369 break;
10356− case JS_TAG_BIG_INT:
10357− if (is_bigint_mode(ctx))
10358− goto to_bf;
10359− /* fall thru */
1036010370 #endif
1036110371 default:
1036210372 val = JS_ToNumberFree(ctx, val);
@@ -10418,17 +10428,12 @@ static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val) · 55 unmodified lines
1041810428 break;
1041910429 #ifdef CONFIG_BIGNUM
1042010430 case JS_TAG_BIG_FLOAT:
10421− to_bf:
1042210431 {
1042310432 JSBigFloat *p = JS_VALUE_GET_PTR(val);
1042410433 bf_get_int32(&ret, &p->num, BF_GET_INT_MOD);
1042510434 JS_FreeValue(ctx, val);
1042610435 }
1042710436 break;
10428− case JS_TAG_BIG_INT:
10429− if (is_bigint_mode(ctx))
10430− goto to_bf;
10431− /* fall thru */
1043210437 #endif
1043310438 default:
1043410439 val = JS_ToNumberFree(ctx, val);
@@ -10486,15 +10491,6 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val) · 51 unmodified lines
1048610491 }
1048710492 break;
1048810493 #ifdef CONFIG_BIGNUM
10489− case JS_TAG_BIG_INT:
10490− {
10491− JSBigFloat *p = JS_VALUE_GET_PTR(val);
10492− if (!is_bigint_mode(ctx))
10493− goto to_number;
10494− bf_get_int32(&res, &p->num, 0);
10495− JS_FreeValue(ctx, val);
10496− }
10497− goto int_clamp;
1049810494 case JS_TAG_BIG_FLOAT:
1049910495 {
1050010496 JSBigFloat *p = JS_VALUE_GET_PTR(val);
@@ -10509,9 +10505,6 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val) · 8 unmodified lines
1050910505 goto int_clamp;
1051010506 #endif
1051110507 default:
10512−#ifdef CONFIG_BIGNUM
10513− to_number:
10514−#endif
1051510508 val = JS_ToNumberFree(ctx, val);
1051610509 if (JS_IsException(val)) {
1051710510 *pres = 0;
@@ -10584,6 +10577,12 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, · 66 unmodified lines
1058410577
1058510578 #define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
1058610579
10580+static BOOL is_safe_integer(double d)
10581+{
10582+ return isfinite(d) && floor(d) == d &&
10583+ fabs(d) <= (double)MAX_SAFE_INTEGER;
10584+}
10585+
1058710586 int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
1058810587 {
1058910588 int64_t v;
@@ -10609,7 +10608,6 @@ static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen, · 19 unmodified lines
1060910608 }
1061010609
1061110610 /* Note: can return an exception */
10612−/* XXX: bignum case */
1061310611 static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
1061410612 {
1061510613 double d;
@@ -10753,7 +10751,8 @@ static JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val) · 137 unmodified lines
1075310751 return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
1075410752 }
1075510753
10756−static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
10754+static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val,
10755+ limb_t prec, int flags)
1075710756 {
1075810757 JSValue ret;
1075910758 bfdec_t *a;
@@ -10764,8 +10763,7 @@ static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val) · 4 unmodified lines
1076410763 saved_sign = a->sign;
1076510764 if (a->expn == BF_EXP_ZERO)
1076610765 a->sign = 0;
10767− str = bfdec_ftoa(NULL, a, 0, BF_RNDZ | BF_FTOA_FORMAT_FREE |
10768− BF_FTOA_JS_QUIRKS);
10766+ str = bfdec_ftoa(NULL, a, prec, flags | BF_FTOA_JS_QUIRKS);
1076910767 a->sign = saved_sign;
1077010768 if (!str)
1077110769 return JS_ThrowOutOfMemory(ctx);
@@ -10774,6 +10772,12 @@ static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val) · 2 unmodified lines
1077410772 return ret;
1077510773 }
1077610774
10775+static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
10776+{
10777+ return js_bigdecimal_to_string1(ctx, val, 0,
10778+ BF_RNDZ | BF_FTOA_FORMAT_FREE);
10779+}
10780+
1077710781 #endif /* CONFIG_BIGNUM */
1077810782
1077910783 /* 2 <= base <= 36 */
@@ -11478,30 +11482,48 @@ static double js_pow(double a, double b) · 698 unmodified lines
1147811482
1147911483 #ifdef CONFIG_BIGNUM
1148011484
11485+JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v)
11486+{
11487+ JSValue val;
11488+ bf_t *a;
11489+ val = JS_NewBigInt(ctx);
11490+ if (JS_IsException(val))
11491+ return val;
11492+ a = JS_GetBigInt(val);
11493+ if (bf_set_si(a, v)) {
11494+ JS_FreeValue(ctx, val);
11495+ return JS_ThrowOutOfMemory(ctx);
11496+ }
11497+ return val;
11498+}
11499+
1148111500 JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
1148211501 {
11483− BOOL is_bignum = is_bigint_mode(ctx);
11484− if (is_bignum && v == (int32_t)v) {
11485− return JS_NewInt32(ctx, v);
11502+ if (is_math_mode(ctx) &&
11503+ v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
11504+ return JS_NewInt64(ctx, v);
1148611505 } else {
11487− bf_t a_s, *a = &a_s;
11488− bf_init(ctx->bf_ctx, a);
11489− bf_set_si(a, v);
11490− return JS_NewBigInt2(ctx, a, TRUE);
11506+ return JS_NewBigInt64_1(ctx, v);
1149111507 }
1149211508 }
1149311509
1149411510 JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
1149511511 {
11496− BOOL is_bignum = is_bigint_mode(ctx);
11497− if (is_bignum && v == (int32_t)v) {
11498− return JS_NewInt32(ctx, v);
11512+ JSValue val;
11513+ if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) {
11514+ val = JS_NewInt64(ctx, v);
1149911515 } else {
11500− bf_t a_s, *a = &a_s;
11501− bf_init(ctx->bf_ctx, a);
11502− bf_set_ui(a, v);
11503− return JS_NewBigInt2(ctx, a, TRUE);
11516+ bf_t *a;
11517+ val = JS_NewBigInt(ctx);
11518+ if (JS_IsException(val))
11519+ return val;
11520+ a = JS_GetBigInt(val);
11521+ if (bf_set_ui(a, v)) {
11522+ JS_FreeValue(ctx, val);
11523+ return JS_ThrowOutOfMemory(ctx);
11524+ }
1150411525 }
11526+ return val;
1150511527 }
1150611528
1150711529 /* if the returned bigfloat is allocated it is equal to
@@ -11582,13 +11604,10 @@ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) · 74 unmodified lines
1158211604 p = str;
1158311605 p += skip_spaces(p);
1158411606 if ((p - str) == len) {
11585− bf_t a_s, *a = &a_s;
11586− bf_init(ctx->bf_ctx, a);
11587− bf_set_si(a, 0);
11588− val = JS_NewBigInt(ctx, a);
11607+ val = JS_NewBigInt64(ctx, 0);
1158911608 } else {
1159011609 flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
11591− if (is_bigint_mode(ctx))
11610+ if (is_math_mode(ctx))
1159211611 flags |= ATOD_MODE_BIGINT;
1159311612 val = js_atof(ctx, p, &p, 0, flags);
1159411613 p += skip_spaces(p);
@@ -11625,7 +11644,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) · 30 unmodified lines
1162511644 case JS_TAG_INT:
1162611645 case JS_TAG_NULL:
1162711646 case JS_TAG_UNDEFINED:
11628− if (!is_bigint_mode(ctx))
11647+ if (!is_math_mode(ctx))
1162911648 goto fail;
1163011649 /* fall tru */
1163111650 case JS_TAG_BOOL:
@@ -11636,7 +11655,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) · 4 unmodified lines
1163611655 case JS_TAG_FLOAT64:
1163711656 {
1163811657 double d = JS_VALUE_GET_FLOAT64(val);
11639− if (!is_bigint_mode(ctx))
11658+ if (!is_math_mode(ctx))
1164011659 goto fail;
1164111660 if (!isfinite(d))
1164211661 goto fail;
@@ -11651,7 +11670,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) · 8 unmodified lines
1165111670 r = &p->num;
1165211671 break;
1165311672 case JS_TAG_BIG_FLOAT:
11654− if (!is_bigint_mode(ctx))
11673+ if (!is_math_mode(ctx))
1165511674 goto fail;
1165611675 p = JS_VALUE_GET_PTR(val);
1165711676 if (!bf_is_finite(&p->num))
@@ -11668,8 +11687,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) · 10 unmodified lines
1166811687 return NULL;
1166911688 goto redo;
1167011689 case JS_TAG_OBJECT:
11671− val = JS_ToPrimitiveFree(ctx, val,
11672− is_bigint_mode(ctx) ? HINT_INTEGER : HINT_NUMBER);
11690+ val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
1167311691 if (JS_IsException(val))
1167411692 return NULL;
1167511693 goto redo;
@@ -11692,21 +11710,26 @@ static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val) · 16 unmodified lines
1169211710 if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
1169311711 return val;
1169411712 } else {
11695− bf_t a_s, *a, b_s, *b;
11713+ bf_t a_s, *a, *r;
1169611714 int ret;
11697−
11715+ JSValue res;
11716+
11717+ res = JS_NewBigInt(ctx);
11718+ if (JS_IsException(res))
11719+ return JS_EXCEPTION;
1169811720 a = JS_ToBigIntFree(ctx, &a_s, val);
11699− if (!a)
11721+ if (!a) {
11722+ JS_FreeValue(ctx, res);
1170011723 return JS_EXCEPTION;
11701− b = &b_s;
11702− bf_init(ctx->bf_ctx, b);
11703− ret = bf_set(b, a);
11724+ }
11725+ r = JS_GetBigInt(res);
11726+ ret = bf_set(r, a);
1170411727 JS_FreeBigInt(ctx, a, &a_s);
1170511728 if (ret) {
11706− bf_delete(b);
11729+ JS_FreeValue(ctx, res);
1170711730 return JS_ThrowOutOfMemory(ctx);
1170811731 }
11709− return JS_NewBigInt2(ctx, b, TRUE);
11732+ return JS_CompactBigInt(ctx, res);
1171011733 }
1171111734 }
1171211735
@@ -11745,7 +11768,7 @@ int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val) · 32 unmodified lines
1174511768 static JSBigFloat *js_new_bf(JSContext *ctx)
1174611769 {
1174711770 JSBigFloat *p;
11748− p = js_mallocz(ctx, sizeof(*p));
11771+ p = js_malloc(ctx, sizeof(*p));
1174911772 if (!p)
1175011773 return NULL;
1175111774 p->header.ref_count = 1;
@@ -11753,224 +11776,387 @@ static JSBigFloat *js_new_bf(JSContext *ctx) · 1 unmodified line
1175311776 return p;
1175411777 }
1175511778
11756−/* WARNING: 'a' is freed */
11757−static JSValue JS_NewBigFloat(JSContext *ctx, bf_t *a)
11779+static JSValue JS_NewBigFloat(JSContext *ctx)
1175811780 {
11759− JSValue ret;
1176011781 JSBigFloat *p;
11761−
11762− p = js_new_bf(ctx);
11763− bf_memcpy(&p->num, a);
11764− ret = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
11765− return ret;
11782+ p = js_malloc(ctx, sizeof(*p));
11783+ if (!p)
11784+ return JS_EXCEPTION;
11785+ p->header.ref_count = 1;
11786+ bf_init(ctx->bf_ctx, &p->num);
11787+ return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
1176611788 }
1176711789
11768−/* WARNING: 'a' is freed */
11769−static JSValue JS_NewBigDecimal(JSContext *ctx, bfdec_t *a)
11790+static JSValue JS_NewBigDecimal(JSContext *ctx)
1177011791 {
11771− JSValue ret;
1177211792 JSBigDecimal *p;
11773−
11774− p = js_mallocz(ctx, sizeof(*p));
11793+ p = js_malloc(ctx, sizeof(*p));
1177511794 if (!p)
1177611795 return JS_EXCEPTION;
1177711796 p->header.ref_count = 1;
1177811797 bfdec_init(ctx->bf_ctx, &p->num);
11779− bfdec_memcpy(&p->num, a);
11780− ret = JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
11781− return ret;
11798+ return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
1178211799 }
1178311800
11784−/* WARNING: 'a' is freed */
11785−static JSValue JS_NewBigInt2(JSContext *ctx, bf_t *a, BOOL force_bigint)
11801+static JSValue JS_NewBigInt(JSContext *ctx)
1178611802 {
11787− JSValue ret;
1178811803 JSBigFloat *p;
11789− int32_t v;
11790−
11791− if (!force_bigint && bf_get_int32(&v, a, 0) == 0) {
11792− /* can fit in an int32 */
11793− ret = JS_NewInt32(ctx, v);
11794− bf_delete(a);
11795− } else {
11796− p = js_new_bf(ctx);
11797− bf_memcpy(&p->num, a);
11798− /* normalize the zero representation */
11799− if (bf_is_zero(&p->num))
11800− p->num.sign = 0;
11801− ret = JS_MKPTR(JS_TAG_BIG_INT, p);
11802− }
11803− return ret;
11804+ p = js_malloc(ctx, sizeof(*p));
11805+ if (!p)
11806+ return JS_EXCEPTION;
11807+ p->header.ref_count = 1;
11808+ bf_init(ctx->bf_ctx, &p->num);
11809+ return JS_MKPTR(JS_TAG_BIG_INT, p);
1180411810 }
1180511811
11806−static JSValue JS_NewBigInt(JSContext *ctx, bf_t *a)
11812+static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
11813+ BOOL convert_to_safe_integer)
1180711814 {
11808− return JS_NewBigInt2(ctx, a, !is_bigint_mode(ctx));
11815+ int64_t v;
11816+ bf_t *a;
11817+
11818+ if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
11819+ return val; /* fail safe */
11820+ a = JS_GetBigInt(val);
11821+ if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 &&
11822+ v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
11823+ JS_FreeValue(ctx, val);
11824+ return JS_NewInt64(ctx, v);
11825+ } else if (a->expn == BF_EXP_ZERO && a->sign) {
11826+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
11827+ assert(p->header.ref_count == 1);
11828+ a->sign = 0;
11829+ }
11830+ return val;
1180911831 }
1181011832
11811−/* return < 0 if exception, 0 if overloading method, 1 if overloading
11812− operator called */
11813−static __exception int js_call_binary_op_fallback(JSContext *ctx,
11814− JSValue *pret,
11815− JSValueConst op1,
11816− JSValueConst op2,
11817− OPCodeEnum op)
11818−{
11819− JSAtom op_name;
11820− JSValue method, ret, c1, c2;
11821− BOOL bool_result, swap_op;
11822− JSValueConst args[2];
11833+/* Convert the big int to a safe integer if in math mode. normalize
11834+ the zero representation. Could also be used to convert the bigint
11835+ to a short bigint value. The reference count of the value must be
11836+ 1. Cannot fail */
11837+static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
11838+{
11839+ return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
11840+}
11841+
11842+/* must be kept in sync with JSOverloadableOperatorEnum */
11843+static const char *js_overloadable_operator_names[JS_OVOP_COUNT] = {
11844+ "+",
11845+ "-",
11846+ "*",
11847+ "/",
11848+ "%",
11849+ "**",
11850+ "|",
11851+ "&",
11852+ "^",
11853+ "<<",
11854+ ">>",
11855+ ">>>",
11856+ "==",
11857+ "<",
11858+ "pos",
11859+ "neg",
11860+ "++",
11861+ "--",
11862+ "~",
11863+};
1182311864
11824− bool_result = FALSE;
11825− swap_op = FALSE;
11826− c1 = JS_UNDEFINED;
11827− c2 = JS_UNDEFINED;
11865+static int get_ovop_from_opcode(OPCodeEnum op)
11866+{
1182811867 switch(op) {
1182911868 case OP_add:
11830− op_name = JS_ATOM_Symbol_operatorAdd;
11831− break;
11869+ return JS_OVOP_ADD;
1183211870 case OP_sub:
11833− op_name = JS_ATOM_Symbol_operatorSub;
11834− break;
11871+ return JS_OVOP_SUB;
1183511872 case OP_mul:
11836− op_name = JS_ATOM_Symbol_operatorMul;
11837− break;
11873+ return JS_OVOP_MUL;
1183811874 case OP_div:
11839− case OP_math_div:
11840− op_name = JS_ATOM_Symbol_operatorDiv;
11841− break;
11875+ return JS_OVOP_DIV;
1184211876 case OP_mod:
11843− op_name = JS_ATOM_Symbol_operatorMod;
11844− break;
11845− case OP_pow:
11846− case OP_math_pow:
11847− op_name = JS_ATOM_Symbol_operatorPow;
11848− break;
1184911877 case OP_math_mod:
11850− op_name = JS_ATOM_Symbol_operatorMathMod;
11851− break;
11852− case OP_shl:
11853− op_name = JS_ATOM_Symbol_operatorShl;
11854− break;
11855− case OP_sar:
11856− op_name = JS_ATOM_Symbol_operatorShr;
11857− break;
11858− case OP_and:
11859− op_name = JS_ATOM_Symbol_operatorAnd;
11860− break;
11878+ return JS_OVOP_MOD;
11879+ case OP_pow:
11880+ return JS_OVOP_POW;
1186111881 case OP_or:
11862− op_name = JS_ATOM_Symbol_operatorOr;
11863− break;
11882+ return JS_OVOP_OR;
11883+ case OP_and:
11884+ return JS_OVOP_AND;
1186411885 case OP_xor:
11865− op_name = JS_ATOM_Symbol_operatorXor;
11866− break;
11886+ return JS_OVOP_XOR;
11887+ case OP_shl:
11888+ return JS_OVOP_SHL;
11889+ case OP_sar:
11890+ return JS_OVOP_SAR;
11891+ case OP_shr:
11892+ return JS_OVOP_SHR;
11893+ case OP_eq:
11894+ case OP_neq:
11895+ return JS_OVOP_EQ;
1186711896 case OP_lt:
11868− op_name = JS_ATOM_Symbol_operatorCmpLT;
11869− bool_result = TRUE;
11870− break;
1187111897 case OP_lte:
11872− op_name = JS_ATOM_Symbol_operatorCmpLE;
11873− bool_result = TRUE;
11874− break;
1187511898 case OP_gt:
11876− op_name = JS_ATOM_Symbol_operatorCmpLT;
11877− bool_result = TRUE;
11878− swap_op = TRUE;
11879− break;
1188011899 case OP_gte:
11881− op_name = JS_ATOM_Symbol_operatorCmpLE;
11882− bool_result = TRUE;
11883− swap_op = TRUE;
11884− break;
11885− case OP_eq:
11886− case OP_neq:
11887− op_name = JS_ATOM_Symbol_operatorCmpEQ;
11888− bool_result = TRUE;
11889− break;
11900+ return JS_OVOP_LESS;
11901+ case OP_plus:
11902+ return JS_OVOP_POS;
11903+ case OP_neg:
11904+ return JS_OVOP_NEG;
11905+ case OP_inc:
11906+ return JS_OVOP_INC;
11907+ case OP_dec:
11908+ return JS_OVOP_DEC;
1189011909 default:
11891− goto fail;
11910+ abort();
11911+ }
11912+}
11913+
11914+/* return NULL if not present */
11915+static JSObject *find_binary_op(JSBinaryOperatorDef *def,
11916+ uint32_t operator_index,
11917+ JSOverloadableOperatorEnum op)
11918+{
11919+ JSBinaryOperatorDefEntry *ent;
11920+ int i;
11921+ for(i = 0; i < def->count; i++) {
11922+ ent = &def->tab[i];
11923+ if (ent->operator_index == operator_index)
11924+ return ent->ops[op];
1189211925 }
11893− c1 = JS_GetProperty(ctx, op1, JS_ATOM_constructor);
11894− if (JS_IsException(c1))
11926+ return NULL;
11927+}
11928+
11929+/* return -1 if exception, 0 if no operator overloading, 1 if
11930+ overloaded operator called */
11931+static __exception int js_call_binary_op_fallback(JSContext *ctx,
11932+ JSValue *pret,
11933+ JSValueConst op1,
11934+ JSValueConst op2,
11935+ OPCodeEnum op,
11936+ BOOL is_numeric,
11937+ int hint)
11938+{
11939+ JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2;
11940+ JSOperatorSetData *opset1, *opset2;
11941+ JSOverloadableOperatorEnum ovop;
11942+ JSObject *p;
11943+ JSValueConst args[2];
11944+
11945+ if (!ctx->allow_operator_overloading)
11946+ return 0;
11947+
11948+ opset2_obj = JS_UNDEFINED;
11949+ opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
11950+ if (JS_IsException(opset1_obj))
1189511951 goto exception;
11896− c2 = JS_GetProperty(ctx, op2, JS_ATOM_constructor);
11897− if (JS_IsException(c2))
11952+ if (JS_IsUndefined(opset1_obj))
11953+ return 0;
11954+ opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
11955+ if (!opset1)
1189811956 goto exception;
11899− if (JS_VALUE_GET_TAG(c1) != JS_TAG_OBJECT ||
11900− JS_VALUE_GET_TAG(c2) != JS_TAG_OBJECT)
11901− goto fail;
11902− if (JS_VALUE_GET_OBJ(c1) == JS_VALUE_GET_OBJ(c2)) {
11903− /* if same constructor, there is no ambiguity */
11904− method = JS_GetProperty(ctx, c1, op_name);
11957+
11958+ opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet);
11959+ if (JS_IsException(opset2_obj))
11960+ goto exception;
11961+ if (JS_IsUndefined(opset2_obj)) {
11962+ JS_FreeValue(ctx, opset1_obj);
11963+ return 0;
11964+ }
11965+ opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET);
11966+ if (!opset2)
11967+ goto exception;
11968+
11969+ if (opset1->is_primitive && opset2->is_primitive) {
11970+ JS_FreeValue(ctx, opset1_obj);
11971+ JS_FreeValue(ctx, opset2_obj);
11972+ return 0;
11973+ }
11974+
11975+ ovop = get_ovop_from_opcode(op);
11976+
11977+ if (opset1->operator_counter == opset2->operator_counter) {
11978+ p = opset1->self_ops[ovop];
11979+ } else if (opset1->operator_counter > opset2->operator_counter) {
11980+ p = find_binary_op(&opset1->left, opset2->operator_counter, ovop);
1190511981 } else {
11906− JSValue val;
11907− int order1, order2;
11982+ p = find_binary_op(&opset2->right, opset1->operator_counter, ovop);
11983+ }
11984+ if (!p) {
11985+ JS_ThrowTypeError(ctx, "operator %s: no function defined",
11986+ js_overloadable_operator_names[ovop]);
11987+ goto exception;
11988+ }
1190811989
11909− /* different constructors: we use a user-defined ordering */
11910− val = JS_GetProperty(ctx, c1, JS_ATOM_Symbol_operatorOrder);
11911− if (JS_IsException(val))
11912− goto exception;
11913− if (JS_IsUndefined(val))
11914− goto undef_order;
11915− if (JS_ToInt32Free(ctx, &order1, val))
11916− goto exception;
11917− val = JS_GetProperty(ctx, c2, JS_ATOM_Symbol_operatorOrder);
11918− if (JS_IsException(val))
11919− goto exception;
11920− if (JS_IsUndefined(val)) {
11921− undef_order:
11922− JS_FreeValue(ctx, c1);
11923− JS_FreeValue(ctx, c2);
11924− *pret = JS_UNDEFINED;
11925− return 0;
11990+ if (opset1->is_primitive) {
11991+ if (is_numeric) {
11992+ new_op1 = JS_ToNumeric(ctx, op1);
11993+ } else {
11994+ new_op1 = JS_ToPrimitive(ctx, op1, hint);
1192611995 }
11927− if (JS_ToInt32Free(ctx, &order2, val))
11996+ if (JS_IsException(new_op1))
1192811997 goto exception;
11929− /* ambiguous priority: error */
11930− if (order1 == order2) {
11931− JS_ThrowTypeError(ctx, "operator_order is identical in both constructors");
11932− goto exception;
11933− }
11934− if (order1 > order2) {
11935− val = c1;
11998+ } else {
11999+ new_op1 = JS_DupValue(ctx, op1);
12000+ }
12001+
12002+ if (opset2->is_primitive) {
12003+ if (is_numeric) {
12004+ new_op2 = JS_ToNumeric(ctx, op2);
1193612005 } else {
11937− val = c2;
12006+ new_op2 = JS_ToPrimitive(ctx, op2, hint);
1193812007 }
11939− method = JS_GetProperty(ctx, val, op_name);
11940− }
11941− JS_FreeValue(ctx, c1);
11942− JS_FreeValue(ctx, c2);
11943− c1 = JS_UNDEFINED;
11944− c2 = JS_UNDEFINED;
11945− if (JS_IsException(method))
11946− goto exception;
11947− if (JS_IsUndefined(method) || JS_IsNull(method)) {
11948− *pret = JS_UNDEFINED;
11949− return 0;
12008+ if (JS_IsException(new_op2)) {
12009+ JS_FreeValue(ctx, new_op1);
12010+ goto exception;
12011+ }
12012+ } else {
12013+ new_op2 = JS_DupValue(ctx, op2);
1195012014 }
11951− if (swap_op) {
11952− args[0] = op2;
11953− args[1] = op1;
12015+
12016+ /* XXX: could apply JS_ToPrimitive() if primitive type so that the
12017+ operator function does not get a value object */
12018+
12019+ method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12020+ if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) {
12021+ args[0] = new_op2;
12022+ args[1] = new_op1;
1195412023 } else {
11955− args[0] = op1;
11956− args[1] = op2;
12024+ args[0] = new_op1;
12025+ args[1] = new_op2;
1195712026 }
1195812027 ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
12028+ JS_FreeValue(ctx, new_op1);
12029+ JS_FreeValue(ctx, new_op2);
1195912030 if (JS_IsException(ret))
1196012031 goto exception;
11961− if (bool_result) {
12032+ if (ovop == JS_OVOP_EQ) {
1196212033 BOOL res = JS_ToBoolFree(ctx, ret);
1196312034 if (op == OP_neq)
1196412035 res ^= 1;
1196512036 ret = JS_NewBool(ctx, res);
12037+ } else if (ovop == JS_OVOP_LESS) {
12038+ if (JS_IsUndefined(ret)) {
12039+ ret = JS_FALSE;
12040+ } else {
12041+ BOOL res = JS_ToBoolFree(ctx, ret);
12042+ if (op == OP_lte || op == OP_gte)
12043+ res ^= 1;
12044+ ret = JS_NewBool(ctx, res);
12045+ }
1196612046 }
12047+ JS_FreeValue(ctx, opset1_obj);
12048+ JS_FreeValue(ctx, opset2_obj);
1196712049 *pret = ret;
1196812050 return 1;
11969− fail:
11970− JS_ThrowTypeError(ctx, "invalid types for binary operator");
1197112051 exception:
11972− JS_FreeValue(ctx, c1);
11973− JS_FreeValue(ctx, c2);
12052+ JS_FreeValue(ctx, opset1_obj);
12053+ JS_FreeValue(ctx, opset2_obj);
12054+ *pret = JS_UNDEFINED;
12055+ return -1;
12056+}
12057+
12058+/* try to call the operation on the operatorSet field of 'obj'. Only
12059+ used for "/" and "**" on the BigInt prototype in math mode */
12060+static __exception int js_call_binary_op_simple(JSContext *ctx,
12061+ JSValue *pret,
12062+ JSValueConst obj,
12063+ JSValueConst op1,
12064+ JSValueConst op2,
12065+ OPCodeEnum op)
12066+{
12067+ JSValue opset1_obj, method, ret, new_op1, new_op2;
12068+ JSOperatorSetData *opset1;
12069+ JSOverloadableOperatorEnum ovop;
12070+ JSObject *p;
12071+ JSValueConst args[2];
12072+
12073+ opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
12074+ if (JS_IsException(opset1_obj))
12075+ goto exception;
12076+ if (JS_IsUndefined(opset1_obj))
12077+ return 0;
12078+ opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12079+ if (!opset1)
12080+ goto exception;
12081+ ovop = get_ovop_from_opcode(op);
12082+
12083+ p = opset1->self_ops[ovop];
12084+ if (!p) {
12085+ JS_FreeValue(ctx, opset1_obj);
12086+ return 0;
12087+ }
12088+
12089+ new_op1 = JS_ToNumeric(ctx, op1);
12090+ if (JS_IsException(new_op1))
12091+ goto exception;
12092+ new_op2 = JS_ToNumeric(ctx, op2);
12093+ if (JS_IsException(new_op2)) {
12094+ JS_FreeValue(ctx, new_op1);
12095+ goto exception;
12096+ }
12097+
12098+ method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12099+ args[0] = new_op1;
12100+ args[1] = new_op2;
12101+ ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
12102+ JS_FreeValue(ctx, new_op1);
12103+ JS_FreeValue(ctx, new_op2);
12104+ if (JS_IsException(ret))
12105+ goto exception;
12106+ JS_FreeValue(ctx, opset1_obj);
12107+ *pret = ret;
12108+ return 1;
12109+ exception:
12110+ JS_FreeValue(ctx, opset1_obj);
12111+ *pret = JS_UNDEFINED;
12112+ return -1;
12113+}
12114+
12115+/* return -1 if exception, 0 if no operator overloading, 1 if
12116+ overloaded operator called */
12117+static __exception int js_call_unary_op_fallback(JSContext *ctx,
12118+ JSValue *pret,
12119+ JSValueConst op1,
12120+ OPCodeEnum op)
12121+{
12122+ JSValue opset1_obj, method, ret;
12123+ JSOperatorSetData *opset1;
12124+ JSOverloadableOperatorEnum ovop;
12125+ JSObject *p;
12126+
12127+ if (!ctx->allow_operator_overloading)
12128+ return 0;
12129+
12130+ opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
12131+ if (JS_IsException(opset1_obj))
12132+ goto exception;
12133+ if (JS_IsUndefined(opset1_obj))
12134+ return 0;
12135+ opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
12136+ if (!opset1)
12137+ goto exception;
12138+ if (opset1->is_primitive) {
12139+ JS_FreeValue(ctx, opset1_obj);
12140+ return 0;
12141+ }
12142+
12143+ ovop = get_ovop_from_opcode(op);
12144+
12145+ p = opset1->self_ops[ovop];
12146+ if (!p) {
12147+ JS_ThrowTypeError(ctx, "no overloaded operator %s",
12148+ js_overloadable_operator_names[ovop]);
12149+ goto exception;
12150+ }
12151+ method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
12152+ ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1);
12153+ if (JS_IsException(ret))
12154+ goto exception;
12155+ JS_FreeValue(ctx, opset1_obj);
12156+ *pret = ret;
12157+ return 1;
12158+ exception:
12159+ JS_FreeValue(ctx, opset1_obj);
1197412160 *pret = JS_UNDEFINED;
1197512161 return -1;
1197612162 }
@@ -11993,16 +12179,22 @@ static JSValue throw_bf_exception(JSContext *ctx, int status) · 16 unmodified lines
1199312179 static int js_unary_arith_bigint(JSContext *ctx,
1199412180 JSValue *pres, OPCodeEnum op, JSValue op1)
1199512181 {
11996− bf_t a_s, r_s, *r = &r_s, *a;
12182+ bf_t a_s, *r, *a;
1199712183 int ret, v;
12184+ JSValue res;
1199812185
11999− if (op == OP_plus && !is_bigint_mode(ctx)) {
12186+ if (op == OP_plus && !is_math_mode(ctx)) {
1200012187 JS_ThrowTypeError(ctx, "bigint argument with unary +");
1200112188 JS_FreeValue(ctx, op1);
1200212189 return -1;
1200312190 }
12191+ res = JS_NewBigInt(ctx);
12192+ if (JS_IsException(res)) {
12193+ JS_FreeValue(ctx, op1);
12194+ return -1;
12195+ }
12196+ r = JS_GetBigInt(res);
1200412197 a = JS_ToBigInt(ctx, &a_s, op1);
12005− bf_init(ctx->bf_ctx, r);
1200612198 ret = 0;
1200712199 switch(op) {
1200812200 case OP_inc:
@@ -12027,28 +12219,35 @@ static int js_unary_arith_bigint(JSContext *ctx, · 18 unmodified lines
1202712219 JS_FreeBigInt(ctx, a, &a_s);
1202812220 JS_FreeValue(ctx, op1);
1202912221 if (unlikely(ret)) {
12030− bf_delete(r);
12222+ JS_FreeValue(ctx, res);
1203112223 throw_bf_exception(ctx, ret);
1203212224 return -1;
1203312225 }
12034− *pres = JS_NewBigInt(ctx, r);
12226+ res = JS_CompactBigInt(ctx, res);
12227+ *pres = res;
1203512228 return 0;
1203612229 }
1203712230
1203812231 static int js_unary_arith_bigfloat(JSContext *ctx,
1203912232 JSValue *pres, OPCodeEnum op, JSValue op1)
1204012233 {
12041− bf_t a_s, r_s, *r = &r_s, *a;
12234+ bf_t a_s, *r, *a;
1204212235 int ret, v;
12236+ JSValue res;
1204312237
12044− if (op == OP_plus && !is_bigint_mode(ctx)) {
12238+ if (op == OP_plus && !is_math_mode(ctx)) {
1204512239 JS_ThrowTypeError(ctx, "bigfloat argument with unary +");
1204612240 JS_FreeValue(ctx, op1);
1204712241 return -1;
1204812242 }
1204912243
12244+ res = JS_NewBigFloat(ctx);
12245+ if (JS_IsException(res)) {
12246+ JS_FreeValue(ctx, op1);
12247+ return -1;
12248+ }
12249+ r = JS_GetBigFloat(res);
1205012250 a = JS_ToBigFloat(ctx, &a_s, op1);
12051− bf_init(ctx->bf_ctx, r);
1205212251 ret = 0;
1205312252 switch(op) {
1205412253 case OP_inc:
@@ -12070,28 +12269,34 @@ static int js_unary_arith_bigfloat(JSContext *ctx, · 15 unmodified lines
1207012269 bf_delete(a);
1207112270 JS_FreeValue(ctx, op1);
1207212271 if (unlikely(ret & BF_ST_MEM_ERROR)) {
12073− bf_delete(r);
12272+ JS_FreeValue(ctx, res);
1207412273 throw_bf_exception(ctx, ret);
1207512274 return -1;
1207612275 }
12077− *pres = JS_NewBigFloat(ctx, r);
12276+ *pres = res;
1207812277 return 0;
1207912278 }
1208012279
1208112280 static int js_unary_arith_bigdecimal(JSContext *ctx,
1208212281 JSValue *pres, OPCodeEnum op, JSValue op1)
1208312282 {
12084− bfdec_t r_s, *r = &r_s, *a;
12283+ bfdec_t *r, *a;
1208512284 int ret, v;
12086−
12087− if (op == OP_plus && !is_bigint_mode(ctx)) {
12285+ JSValue res;
12286+
12287+ if (op == OP_plus && !is_math_mode(ctx)) {
1208812288 JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
1208912289 JS_FreeValue(ctx, op1);
1209012290 return -1;
1209112291 }
1209212292
12293+ res = JS_NewBigDecimal(ctx);
12294+ if (JS_IsException(res)) {
12295+ JS_FreeValue(ctx, op1);
12296+ return -1;
12297+ }
12298+ r = JS_GetBigDecimal(res);
1209312299 a = JS_ToBigDecimal(ctx, op1);
12094− bfdec_init(ctx->bf_ctx, r);
1209512300 ret = 0;
1209612301 switch(op) {
1209712302 case OP_inc:
@@ -12111,11 +12316,11 @@ static int js_unary_arith_bigdecimal(JSContext *ctx, · 13 unmodified lines
1211112316 }
1211212317 JS_FreeValue(ctx, op1);
1211312318 if (unlikely(ret)) {
12114− bfdec_delete(r);
12319+ JS_FreeValue(ctx, res);
1211512320 throw_bf_exception(ctx, ret);
1211612321 return -1;
1211712322 }
12118− *pres = JS_NewBigDecimal(ctx, r);
12323+ *pres = res;
1211912324 return 0;
1212012325 }
1212112326
@@ -12123,112 +12328,93 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, · 1 unmodified line
1212312328 JSValue *sp,
1212412329 OPCodeEnum op)
1212512330 {
12126− JSValue op1, val, method;
12127− BOOL is_legacy;
12128− JSAtom op_name;
12129− int v;
12331+ JSValue op1, val;
12332+ int v, ret;
1213012333 uint32_t tag;
1213112334
1213212335 op1 = sp[-1];
1213312336 /* fast path for float64 */
1213412337 if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
1213512338 goto handle_float64;
12136− if (JS_IsObject(op1) && ctx->bignum_ext) {
12137− switch(op) {
12138− case OP_plus:
12139− op_name = JS_ATOM_Symbol_operatorPlus;
12140− break;
12141− case OP_neg:
12142− op_name = JS_ATOM_Symbol_operatorNeg;
12143− break;
12144− case OP_inc:
12145− op_name = JS_ATOM_Symbol_operatorInc;
12146− break;
12147− case OP_dec:
12148− op_name = JS_ATOM_Symbol_operatorDec;
12149− break;
12150− default:
12151− abort();
12152− }
12153− method = JS_GetProperty(ctx, op1, op_name);
12154− if (JS_IsException(method))
12155− return -1;
12156− if (JS_IsUndefined(method) || JS_IsNull(method))
12157− goto to_number;
12158− val = JS_CallFree(ctx, method, op1, 0, NULL);
12159− if (JS_IsException(val))
12339+ if (JS_IsObject(op1)) {
12340+ ret = js_call_unary_op_fallback(ctx, &val, op1, op);
12341+ if (ret < 0)
1216012342 return -1;
12161− JS_FreeValue(ctx, op1);
12162− sp[-1] = val;
12163− } else {
12164− to_number:
12165− op1 = JS_ToNumericFree(ctx, op1);
12166− if (JS_IsException(op1))
12167− goto exception;
12168− is_legacy = is_bigint_mode(ctx) ^ 1;
12169− tag = JS_VALUE_GET_TAG(op1);
12170− switch(tag) {
12171− case JS_TAG_INT:
12172− {
12173− int64_t v64;
12174− v64 = JS_VALUE_GET_INT(op1);
12175− switch(op) {
12176− case OP_inc:
12177− case OP_dec:
12178− v = 2 * (op - OP_dec) - 1;
12179− v64 += v;
12180− break;
12181− case OP_plus:
12182− break;
12183− case OP_neg:
12184− if (v64 == 0 && is_legacy) {
12185− sp[-1] = __JS_NewFloat64(ctx, -0.0);
12186− return 0;
12187− } else {
12188− v64 = -v64;
12189− }
12190− break;
12191− default:
12192− abort();
12343+ if (ret) {
12344+ JS_FreeValue(ctx, op1);
12345+ sp[-1] = val;
12346+ return 0;
12347+ }
12348+ }
12349+
12350+ op1 = JS_ToNumericFree(ctx, op1);
12351+ if (JS_IsException(op1))
12352+ goto exception;
12353+ tag = JS_VALUE_GET_TAG(op1);
12354+ switch(tag) {
12355+ case JS_TAG_INT:
12356+ {
12357+ int64_t v64;
12358+ v64 = JS_VALUE_GET_INT(op1);
12359+ switch(op) {
12360+ case OP_inc:
12361+ case OP_dec:
12362+ v = 2 * (op - OP_dec) - 1;
12363+ v64 += v;
12364+ break;
12365+ case OP_plus:
12366+ break;
12367+ case OP_neg:
12368+ if (v64 == 0) {
12369+ sp[-1] = __JS_NewFloat64(ctx, -0.0);
12370+ return 0;
12371+ } else {
12372+ v64 = -v64;
1219312373 }
12194− sp[-1] = JS_NewInt64(ctx, v64);
12374+ break;
12375+ default:
12376+ abort();
1219512377 }
12196− break;
12197− case JS_TAG_BIG_INT:
12198− if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
12199− goto exception;
12200− break;
12201− case JS_TAG_BIG_FLOAT:
12202− if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
12203− goto exception;
12204− break;
12205− case JS_TAG_BIG_DECIMAL:
12206− if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
12207− goto exception;
12208− break;
12209− default:
12210− handle_float64:
12211− {
12212− double d;
12213− d = JS_VALUE_GET_FLOAT64(op1);
12214− switch(op) {
12215− case OP_inc:
12216− case OP_dec:
12217− v = 2 * (op - OP_dec) - 1;
12218− d += v;
12219− break;
12220− case OP_plus:
12221− break;
12222− case OP_neg:
12223− d = -d;
12224− break;
12225− default:
12226− abort();
12227− }
12228− sp[-1] = __JS_NewFloat64(ctx, d);
12378+ sp[-1] = JS_NewInt64(ctx, v64);
12379+ }
12380+ break;
12381+ case JS_TAG_BIG_INT:
12382+ handle_bigint:
12383+ if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
12384+ goto exception;
12385+ break;
12386+ case JS_TAG_BIG_FLOAT:
12387+ if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
12388+ goto exception;
12389+ break;
12390+ case JS_TAG_BIG_DECIMAL:
12391+ if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
12392+ goto exception;
12393+ break;
12394+ default:
12395+ handle_float64:
12396+ {
12397+ double d;
12398+ if (is_math_mode(ctx))
12399+ goto handle_bigint;
12400+ d = JS_VALUE_GET_FLOAT64(op1);
12401+ switch(op) {
12402+ case OP_inc:
12403+ case OP_dec:
12404+ v = 2 * (op - OP_dec) - 1;
12405+ d += v;
12406+ break;
12407+ case OP_plus:
12408+ break;
12409+ case OP_neg:
12410+ d = -d;
12411+ break;
12412+ default:
12413+ abort();
1222912414 }
12230− break;
12415+ sp[-1] = __JS_NewFloat64(ctx, d);
1223112416 }
12417+ break;
1223212418 }
1223312419 return 0;
1223412420 exception:
@@ -12255,39 +12441,33 @@ static __exception int js_post_inc_slow(JSContext *ctx, · 20 unmodified lines
1225512441
1225612442 static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
1225712443 {
12258− JSValue op1, method, val;
12259−
12444+ JSValue op1, val;
12445+ int ret;
12446+
1226012447 op1 = sp[-1];
1226112448 if (JS_IsObject(op1)) {
12262− if (!ctx->bignum_ext)
12263− goto to_number;
12264− method = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorNot);
12265− if (JS_IsException(method))
12266− return -1;
12267− if (JS_IsUndefined(method) || JS_IsNull(method))
12268− goto to_number;
12269− val = JS_CallFree(ctx, method, op1, 0, NULL);
12270− if (JS_IsException(val))
12449+ ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not);
12450+ if (ret < 0)
1227112451 return -1;
12272− JS_FreeValue(ctx, op1);
12273− sp[-1] = val;
12274− } else {
12275− if (JS_IsString(op1)) {
12276− to_number:
12277− op1 = JS_ToNumberHintFree(ctx, op1, TON_FLAG_INTEGER);
12278− if (JS_IsException(op1))
12279− goto exception;
12280− }
12281− if (is_bigint_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
12282− if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
12283− goto exception;
12284− } else {
12285− int32_t v1;
12286− if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
12287− goto exception;
12288− sp[-1] = JS_NewInt32(ctx, ~v1);
12452+ if (ret) {
12453+ JS_FreeValue(ctx, op1);
12454+ sp[-1] = val;
12455+ return 0;
1228912456 }
1229012457 }
12458+
12459+ op1 = JS_ToNumericFree(ctx, op1);
12460+ if (JS_IsException(op1))
12461+ goto exception;
12462+ if (is_math_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
12463+ if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
12464+ goto exception;
12465+ } else {
12466+ int32_t v1;
12467+ if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
12468+ goto exception;
12469+ sp[-1] = JS_NewInt32(ctx, ~v1);
12470+ }
1229112471 return 0;
1229212472 exception:
1229312473 sp[-1] = JS_UNDEFINED;
@@ -12297,12 +12477,19 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) · 3 unmodified lines
1229712477 static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
1229812478 JSValue *pres, JSValue op1, JSValue op2)
1229912479 {
12300− bf_t a_s, b_s, r_s, *r, *a, *b;
12301− int ret, rnd_mode;
12480+ bf_t a_s, b_s, *r, *a, *b;
12481+ int ret;
12482+ JSValue res;
1230212483
12484+ res = JS_NewBigFloat(ctx);
12485+ if (JS_IsException(res)) {
12486+ JS_FreeValue(ctx, op1);
12487+ JS_FreeValue(ctx, op2);
12488+ return -1;
12489+ }
12490+ r = JS_GetBigFloat(res);
1230312491 a = JS_ToBigFloat(ctx, &a_s, op1);
1230412492 b = JS_ToBigFloat(ctx, &b_s, op2);
12305− r = &r_s;
1230612493 bf_init(ctx->bf_ctx, r);
1230712494 switch(op) {
1230812495 case OP_add:
@@ -12314,29 +12501,21 @@ static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, · 5 unmodified lines
1231412501 case OP_mul:
1231512502 ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
1231612503 break;
12317− case OP_math_div:
1231812504 case OP_div:
1231912505 ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
1232012506 break;
1232112507 case OP_math_mod:
1232212508 /* Euclidian remainder */
12323− rnd_mode = BF_DIVREM_EUCLIDIAN;
12324− goto do_mod;
12509+ ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
12510+ BF_DIVREM_EUCLIDIAN);
12511+ break;
1232512512 case OP_mod:
12326− rnd_mode = BF_RNDZ;
12327− do_mod:
12328− {
12329− bf_t q_s, *q = &q_s;
12330− bf_init(ctx->bf_ctx, q);
12331− ret = bf_divrem(q, r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
12332− rnd_mode);
12333− bf_delete(q);
12334− }
12513+ ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
12514+ BF_RNDZ);
1233512515 break;
1233612516 case OP_pow:
12337− case OP_math_pow:
1233812517 ret = bf_pow(r, a, b, ctx->fp_env.prec,
12339− ctx->fp_env.flags | BF_POW_JS_QUICKS);
12518+ ctx->fp_env.flags | BF_POW_JS_QUIRKS);
1234012519 break;
1234112520 default:
1234212521 abort();
@@ -12348,21 +12527,24 @@ static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, · 5 unmodified lines
1234812527 JS_FreeValue(ctx, op1);
1234912528 JS_FreeValue(ctx, op2);
1235012529 if (unlikely(ret & BF_ST_MEM_ERROR)) {
12351− bf_delete(r);
12530+ JS_FreeValue(ctx, res);
1235212531 throw_bf_exception(ctx, ret);
1235312532 return -1;
1235412533 }
12355− *pres = JS_NewBigFloat(ctx, r);
12534+ *pres = res;
1235612535 return 0;
1235712536 }
1235812537
1235912538 static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
1236012539 JSValue *pres, JSValue op1, JSValue op2)
1236112540 {
12362− bf_t a_s, b_s, r_s, *r, *a, *b;
12363− int ret, rnd_mode;
12541+ bf_t a_s, b_s, *r, *a, *b;
12542+ int ret;
1236412543 JSValue res;
1236512544
12545+ res = JS_NewBigInt(ctx);
12546+ if (JS_IsException(res))
12547+ goto fail;
1236612548 a = JS_ToBigInt(ctx, &a_s, op1);
1236712549 if (!a)
1236812550 goto fail;
@@ -12371,8 +12553,7 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, · 2 unmodified lines
1237112553 JS_FreeBigInt(ctx, a, &a_s);
1237212554 goto fail;
1237312555 }
12374− r = &r_s;
12375− bf_init(ctx->bf_ctx, r);
12556+ r = JS_GetBigInt(res);
1237612557 ret = 0;
1237712558 switch(op) {
1237812559 case OP_add:
@@ -12384,73 +12565,75 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, · 5 unmodified lines
1238412565 case OP_mul:
1238512566 ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
1238612567 break;
12387− case OP_math_div:
12388− goto op_fallback;
1238912568 case OP_div:
12390− if (!is_bigint_mode(ctx)) {
12569+ if (!is_math_mode(ctx)) {
1239112570 bf_t rem_s, *rem = &rem_s;
1239212571 bf_init(ctx->bf_ctx, rem);
1239312572 ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ,
1239412573 BF_RNDZ);
1239512574 bf_delete(rem);
1239612575 } else {
12397− bf_div(r, a, b, 53, bf_set_exp_bits(11) |
12398− BF_RNDN | BF_FLAG_SUBNORMAL);
12399− goto float64_result;
12576+ goto math_mode_div_pow;
1240012577 }
1240112578 break;
1240212579 case OP_math_mod:
1240312580 /* Euclidian remainder */
12404− rnd_mode = BF_DIVREM_EUCLIDIAN;
12405− goto do_int_mod;
12581+ ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
12582+ BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP;
12583+ break;
1240612584 case OP_mod:
12407− rnd_mode = BF_RNDZ;
12408− do_int_mod:
12409− {
12410− bf_t q_s, *q = &q_s;
12411− bf_init(ctx->bf_ctx, q);
12412− ret = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ,
12413− rnd_mode) & BF_ST_INVALID_OP;
12414− bf_delete(q);
12415− }
12585+ ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
12586+ BF_RNDZ) & BF_ST_INVALID_OP;
1241612587 break;
1241712588 case OP_pow:
12418− case OP_math_pow:
1241912589 if (b->sign) {
12420− if (!is_bigint_mode(ctx)) {
12590+ if (!is_math_mode(ctx)) {
1242112591 ret = BF_ST_INVALID_OP;
12422− } else if (op == OP_math_pow) {
12423− op_fallback:
12424− bf_delete(r);
12592+ } else {
12593+ math_mode_div_pow:
12594+ JS_FreeValue(ctx, res);
12595+ ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op);
12596+ if (ret != 0) {
12597+ JS_FreeBigInt(ctx, a, &a_s);
12598+ JS_FreeBigInt(ctx, b, &b_s);
12599+ JS_FreeValue(ctx, op1);
12600+ JS_FreeValue(ctx, op2);
12601+ if (ret < 0) {
12602+ return -1;
12603+ } else {
12604+ *pres = res;
12605+ return 0;
12606+ }
12607+ }
12608+ /* if no BigInt power operator defined, return a
12609+ bigfloat */
12610+ res = JS_NewBigFloat(ctx);
12611+ if (JS_IsException(res)) {
12612+ JS_FreeBigInt(ctx, a, &a_s);
12613+ JS_FreeBigInt(ctx, b, &b_s);
12614+ goto fail;
12615+ }
12616+ r = JS_GetBigFloat(res);
12617+ if (op == OP_div) {
12618+ ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR;
12619+ } else {
12620+ ret = bf_pow(r, a, b, ctx->fp_env.prec,
12621+ ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR;
12622+ }
1242512623 JS_FreeBigInt(ctx, a, &a_s);
1242612624 JS_FreeBigInt(ctx, b, &b_s);
12427− ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op);
1242812625 JS_FreeValue(ctx, op1);
1242912626 JS_FreeValue(ctx, op2);
12430− if (ret < 0) {
12431− return -1;
12432− } else if (ret == 0) {
12433− JS_ThrowTypeError(ctx, "operator must be defined for exact division or power");
12627+ if (unlikely(ret)) {
12628+ JS_FreeValue(ctx, res);
12629+ throw_bf_exception(ctx, ret);
1243412630 return -1;
1243512631 }
1243612632 *pres = res;
1243712633 return 0;
12438− } else {
12439− double dr;
12440− bf_pow(r, a, b, 53, bf_set_exp_bits(11) |
12441− BF_RNDN | BF_FLAG_SUBNORMAL);
12442− float64_result:
12443− bf_get_float64(r, &dr, BF_RNDN);
12444− bf_delete(r);
12445− JS_FreeBigInt(ctx, a, &a_s);
12446− JS_FreeBigInt(ctx, b, &b_s);
12447− JS_FreeValue(ctx, op1);
12448− JS_FreeValue(ctx, op2);
12449− *pres = __JS_NewFloat64(ctx, dr);
12450− return 0;
1245112634 }
1245212635 } else {
12453− ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUICKS);
12636+ ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
1245412637 }
1245512638 break;
1245612639
@@ -12494,13 +12677,14 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, · 37 unmodified lines
1249412677 JS_FreeValue(ctx, op1);
1249512678 JS_FreeValue(ctx, op2);
1249612679 if (unlikely(ret)) {
12497− bf_delete(r);
12680+ JS_FreeValue(ctx, res);
1249812681 throw_bf_exception(ctx, ret);
1249912682 return -1;
1250012683 }
12501− *pres = JS_NewBigInt(ctx, r);
12684+ *pres = JS_CompactBigInt(ctx, res);
1250212685 return 0;
1250312686 fail:
12687+ JS_FreeValue(ctx, res);
1250412688 JS_FreeValue(ctx, op1);
1250512689 JS_FreeValue(ctx, op2);
1250612690 return -1;
@@ -12536,18 +12720,21 @@ static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b) · 29 unmodified lines
1253612720 static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
1253712721 JSValue *pres, JSValue op1, JSValue op2)
1253812722 {
12539− bfdec_t r_s, *r, *a, *b;
12540− int ret, rnd_mode;
12541−
12542− /* big decimal result */
12723+ bfdec_t *r, *a, *b;
12724+ int ret;
12725+ JSValue res;
12726+
12727+ res = JS_NewBigDecimal(ctx);
12728+ if (JS_IsException(res))
12729+ goto fail;
12730+ r = JS_GetBigDecimal(res);
12731+
1254312732 a = JS_ToBigDecimal(ctx, op1);
1254412733 if (!a)
1254512734 goto fail;
1254612735 b = JS_ToBigDecimal(ctx, op2);
1254712736 if (!b)
1254812737 goto fail;
12549− r = &r_s;
12550− bfdec_init(ctx->bf_ctx, r);
1255112738 switch(op) {
1255212739 case OP_add:
1255312740 ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);
@@ -12558,26 +12745,17 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op, · 4 unmodified lines
1255812745 case OP_mul:
1255912746 ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
1256012747 break;
12561− case OP_math_div:
1256212748 case OP_div:
1256312749 ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);
1256412750 break;
1256512751 case OP_math_mod:
1256612752 /* Euclidian remainder */
12567− rnd_mode = BF_DIVREM_EUCLIDIAN;
12568− goto do_mod_dec;
12753+ ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN);
12754+ break;
1256912755 case OP_mod:
12570− rnd_mode = BF_RNDZ;
12571− do_mod_dec:
12572− {
12573− bfdec_t q_s, *q = &q_s;
12574− bfdec_init(ctx->bf_ctx, q);
12575− ret = bfdec_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, rnd_mode);
12576− bfdec_delete(q);
12577− }
12756+ ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
1257812757 break;
1257912758 case OP_pow:
12580− case OP_math_pow:
1258112759 ret = js_bfdec_pow(r, a, b);
1258212760 break;
1258312761 default:
@@ -12586,13 +12764,14 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op, · 2 unmodified lines
1258612764 JS_FreeValue(ctx, op1);
1258712765 JS_FreeValue(ctx, op2);
1258812766 if (unlikely(ret)) {
12589− bfdec_delete(r);
12767+ JS_FreeValue(ctx, res);
1259012768 throw_bf_exception(ctx, ret);
1259112769 return -1;
1259212770 }
12593− *pres = JS_NewBigDecimal(ctx, r);
12771+ *pres = res;
1259412772 return 0;
1259512773 fail:
12774+ JS_FreeValue(ctx, res);
1259612775 JS_FreeValue(ctx, op1);
1259712776 JS_FreeValue(ctx, op2);
1259812777 return -1;
@@ -12602,7 +12781,6 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 3 unmodified lines
1260212781 OPCodeEnum op)
1260312782 {
1260412783 JSValue op1, op2, res;
12605− BOOL is_legacy;
1260612784 uint32_t tag1, tag2;
1260712785 int ret;
1260812786 double d1, d2;
@@ -12619,12 +12797,11 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 10 unmodified lines
1261912797 }
1262012798
1262112799 /* try to call an overloaded operator */
12622− if (((tag1 == JS_TAG_OBJECT &&
12623− (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
12624− (tag2 == JS_TAG_OBJECT &&
12625− (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&
12626− ctx->bignum_ext) {
12627− ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op);
12800+ if ((tag1 == JS_TAG_OBJECT &&
12801+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
12802+ (tag2 == JS_TAG_OBJECT &&
12803+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
12804+ ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
1262812805 if (ret != 0) {
1262912806 JS_FreeValue(ctx, op1);
1263012807 JS_FreeValue(ctx, op2);
@@ -12655,23 +12832,23 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 24 unmodified lines
1265512832 int64_t v;
1265612833 v1 = JS_VALUE_GET_INT(op1);
1265712834 v2 = JS_VALUE_GET_INT(op2);
12658− is_legacy = is_bigint_mode(ctx) ^ 1;
1265912835 switch(op) {
1266012836 case OP_sub:
1266112837 v = (int64_t)v1 - (int64_t)v2;
1266212838 break;
1266312839 case OP_mul:
1266412840 v = (int64_t)v1 * (int64_t)v2;
12665− if (is_legacy && v == 0 && (v1 | v2) < 0) {
12841+ if (is_math_mode(ctx) &&
12842+ (v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER))
12843+ goto handle_bigint;
12844+ if (v == 0 && (v1 | v2) < 0) {
1266612845 sp[-2] = __JS_NewFloat64(ctx, -0.0);
1266712846 return 0;
1266812847 }
1266912848 break;
12670− case OP_math_div:
12671− if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
12672− goto exception;
12673− return 0;
1267412849 case OP_div:
12850+ if (is_math_mode(ctx))
12851+ goto handle_bigint;
1267512852 sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2);
1267612853 return 0;
1267712854 case OP_math_mod:
@@ -12688,26 +12865,19 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 10 unmodified lines
1268812865 }
1268912866 break;
1269012867 case OP_mod:
12691− if (is_legacy && (v1 < 0 || v2 <= 0)) {
12868+ if (v1 < 0 || v2 <= 0) {
1269212869 sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
1269312870 return 0;
1269412871 } else {
12695− if (unlikely(v2 == 0)) {
12696− throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO);
12697− goto exception;
12698− }
1269912872 v = (int64_t)v1 % (int64_t)v2;
1270012873 }
1270112874 break;
1270212875 case OP_pow:
12703− case OP_math_pow:
12704− if (is_legacy) {
12876+ if (!is_math_mode(ctx)) {
1270512877 sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
1270612878 return 0;
1270712879 } else {
12708− if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
12709− goto exception;
12710− return 0;
12880+ goto handle_bigint;
1271112881 }
1271212882 break;
1271312883 default:
@@ -12720,6 +12890,10 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 6 unmodified lines
1272012890 } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
1272112891 if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2))
1272212892 goto exception;
12893+ } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
12894+ handle_bigint:
12895+ if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
12896+ goto exception;
1272312897 } else if (tag1 == JS_TAG_FLOAT64 || tag2 == JS_TAG_FLOAT64) {
1272412898 double dr;
1272512899 /* float64 result */
@@ -12730,6 +12904,8 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 4 unmodified lines
1273012904 if (JS_ToFloat64Free(ctx, &d2, op2))
1273112905 goto exception;
1273212906 handle_float64:
12907+ if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
12908+ goto handle_bigint;
1273312909 switch(op) {
1273412910 case OP_sub:
1273512911 dr = d1 - d2;
@@ -12738,7 +12914,6 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 2 unmodified lines
1273812914 dr = d1 * d2;
1273912915 break;
1274012916 case OP_div:
12741− case OP_math_div:
1274212917 dr = d1 / d2;
1274312918 break;
1274412919 case OP_mod:
@@ -12752,16 +12927,12 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s · 7 unmodified lines
1275212927 dr += d2;
1275312928 break;
1275412929 case OP_pow:
12755− case OP_math_pow:
1275612930 dr = js_pow(d1, d2);
1275712931 break;
1275812932 default:
1275912933 abort();
1276012934 }
1276112935 sp[-2] = __JS_NewFloat64(ctx, dr);
12762− } else {
12763− if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
12764− goto exception;
1276512936 }
1276612937 return 0;
1276712938 exception:
@@ -12792,12 +12963,14 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) · 24 unmodified lines
1279212963
1279312964 if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
1279412965 /* try to call an overloaded operator */
12795− if (((tag1 == JS_TAG_OBJECT &&
12796− (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
12797− (tag2 == JS_TAG_OBJECT &&
12798− (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&
12799− ctx->bignum_ext) {
12800− ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add);
12966+ if ((tag1 == JS_TAG_OBJECT &&
12967+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED &&
12968+ tag2 != JS_TAG_STRING)) ||
12969+ (tag2 == JS_TAG_OBJECT &&
12970+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED &&
12971+ tag1 != JS_TAG_STRING))) {
12972+ ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add,
12973+ FALSE, HINT_NONE);
1280112974 if (ret != 0) {
1280212975 JS_FreeValue(ctx, op1);
1280312976 JS_FreeValue(ctx, op2);
@@ -12886,6 +13059,7 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, · 82 unmodified lines
1288613059 JSValue op1, op2, res;
1288713060 int ret;
1288813061 uint32_t tag1, tag2;
13062+ uint32_t v1, v2, r;
1288913063
1289013064 op1 = sp[-2];
1289113065 op2 = sp[-1];
@@ -12893,12 +13067,11 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, · 1 unmodified line
1289313067 tag2 = JS_VALUE_GET_NORM_TAG(op2);
1289413068
1289513069 /* try to call an overloaded operator */
12896− if (((tag1 == JS_TAG_OBJECT &&
12897− (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
12898− (tag2 == JS_TAG_OBJECT &&
12899− (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&
12900− ctx->bignum_ext) {
12901− ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op);
13070+ if ((tag1 == JS_TAG_OBJECT &&
13071+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13072+ (tag2 == JS_TAG_OBJECT &&
13073+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13074+ ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
1290213075 if (ret != 0) {
1290313076 JS_FreeValue(ctx, op1);
1290413077 JS_FreeValue(ctx, op2);
@@ -12911,63 +13084,60 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, · 6 unmodified lines
1291113084 }
1291213085 }
1291313086
12914− op1 = JS_ToNumberHintFree(ctx, op1, TON_FLAG_INTEGER);
13087+ op1 = JS_ToNumericFree(ctx, op1);
1291513088 if (JS_IsException(op1)) {
1291613089 JS_FreeValue(ctx, op2);
1291713090 goto exception;
1291813091 }
12919− op2 = JS_ToNumberHintFree(ctx, op2, TON_FLAG_INTEGER);
13092+ op2 = JS_ToNumericFree(ctx, op2);
1292013093 if (JS_IsException(op2)) {
1292113094 JS_FreeValue(ctx, op1);
1292213095 goto exception;
1292313096 }
1292413097
12925− if (!is_bigint_mode(ctx)) {
12926− uint32_t v1, v2, r;
13098+ if (is_math_mode(ctx))
13099+ goto bigint_op;
1292713100
12928− tag1 = JS_VALUE_GET_TAG(op1);
12929− tag2 = JS_VALUE_GET_TAG(op2);
12930− if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
12931− if (tag1 != tag2) {
12932− JS_FreeValue(ctx, op1);
12933− JS_FreeValue(ctx, op2);
12934− JS_ThrowTypeError(ctx, "both operands must be bigint");
12935− goto exception;
12936− } else {
12937− goto bigint_op;
12938− }
13101+ tag1 = JS_VALUE_GET_TAG(op1);
13102+ tag2 = JS_VALUE_GET_TAG(op2);
13103+ if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
13104+ if (tag1 != tag2) {
13105+ JS_FreeValue(ctx, op1);
13106+ JS_FreeValue(ctx, op2);
13107+ JS_ThrowTypeError(ctx, "both operands must be bigint");
13108+ goto exception;
1293913109 } else {
12940− if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
12941− JS_FreeValue(ctx, op2);
12942− goto exception;
12943− }
12944− if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
13110+ bigint_op:
13111+ if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
1294513112 goto exception;
12946− switch(op) {
12947− case OP_shl:
12948− r = v1 << (v2 & 0x1f);
12949− break;
12950− case OP_sar:
12951− r = (int)v1 >> (v2 & 0x1f);
12952− break;
12953− case OP_and:
12954− r = v1 & v2;
12955− break;
12956− case OP_or:
12957− r = v1 | v2;
12958− break;
12959− case OP_xor:
12960− r = v1 ^ v2;
12961− break;
12962− default:
12963− abort();
12964− }
12965− sp[-2] = JS_NewInt32(ctx, r);
1296613113 }
1296713114 } else {
12968− bigint_op:
12969− if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
13115+ if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
13116+ JS_FreeValue(ctx, op2);
13117+ goto exception;
13118+ }
13119+ if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
1297013120 goto exception;
13121+ switch(op) {
13122+ case OP_shl:
13123+ r = v1 << (v2 & 0x1f);
13124+ break;
13125+ case OP_sar:
13126+ r = (int)v1 >> (v2 & 0x1f);
13127+ break;
13128+ case OP_and:
13129+ r = v1 & v2;
13130+ break;
13131+ case OP_or:
13132+ r = v1 | v2;
13133+ break;
13134+ case OP_xor:
13135+ r = v1 ^ v2;
13136+ break;
13137+ default:
13138+ abort();
13139+ }
13140+ sp[-2] = JS_NewInt32(ctx, r);
1297113141 }
1297213142 return 0;
1297313143 exception:
@@ -13081,12 +13251,12 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, · 107 unmodified lines
1308113251 tag1 = JS_VALUE_GET_NORM_TAG(op1);
1308213252 tag2 = JS_VALUE_GET_NORM_TAG(op2);
1308313253 /* try to call an overloaded operator */
13084− if (((tag1 == JS_TAG_OBJECT &&
13085− (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13086− (tag2 == JS_TAG_OBJECT &&
13087− (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&
13088− ctx->bignum_ext) {
13089− res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op);
13254+ if ((tag1 == JS_TAG_OBJECT &&
13255+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
13256+ (tag2 == JS_TAG_OBJECT &&
13257+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
13258+ res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op,
13259+ FALSE, HINT_NUMBER);
1309013260 if (res != 0) {
1309113261 JS_FreeValue(ctx, op1);
1309213262 JS_FreeValue(ctx, op2);
@@ -13165,7 +13335,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, · 72 unmodified lines
1316513335 } else {
1316613336 if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) ||
1316713337 (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) &&
13168− !is_bigint_mode(ctx)) {
13338+ !is_math_mode(ctx)) {
1316913339 if (tag1 == JS_TAG_STRING) {
1317013340 op1 = JS_StringToBigInt(ctx, op1);
1317113341 if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
@@ -13271,10 +13441,11 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, · 99 unmodified lines
1327113441 goto exception;
1327213442 }
1327313443 } else if (tag1 == tag2) {
13274− if (tag1 == JS_TAG_OBJECT && ctx->bignum_ext) {
13444+ if (tag1 == JS_TAG_OBJECT) {
1327513445 /* try the fallback operator */
1327613446 res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
13277− is_neq ? OP_neq : OP_eq);
13447+ is_neq ? OP_neq : OP_eq,
13448+ FALSE, HINT_NONE);
1327813449 if (res != 0) {
1327913450 JS_FreeValue(ctx, op1);
1328013451 JS_FreeValue(ctx, op2);
@@ -13294,7 +13465,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, · 13 unmodified lines
1329413465 (tag2 == JS_TAG_STRING && tag_is_number(tag1))) {
1329513466
1329613467 if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&
13297− !is_bigint_mode(ctx)) {
13468+ !is_math_mode(ctx)) {
1329813469 if (tag1 == JS_TAG_STRING) {
1329913470 op1 = JS_StringToBigInt(ctx, op1);
1330013471 if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
@@ -13336,7 +13507,8 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, · 35 unmodified lines
1333613507
1333713508 /* try the fallback operator */
1333813509 res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
13339− is_neq ? OP_neq : OP_eq);
13510+ is_neq ? OP_neq : OP_eq,
13511+ FALSE, HINT_NONE);
1334013512 if (res != 0) {
1334113513 JS_FreeValue(ctx, op1);
1334213514 JS_FreeValue(ctx, op2);
@@ -13391,7 +13563,7 @@ static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) · 48 unmodified lines
1339113563 goto exception;
1339213564 }
1339313565 /* XXX: could forbid >>> in bignum mode */
13394− if (!is_bigint_mode(ctx) &&
13566+ if (!is_math_mode(ctx) &&
1339513567 (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
1339613568 JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT)) {
1339713569 JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");
@@ -13433,34 +13605,38 @@ static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a, · 35 unmodified lines
1343313605
1343413606 static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
1343513607 {
13436− bf_t a_s, *a, r_s, *r = &r_s;
13437− JSValue op1, op2;
13438− slimb_t e;
13608+ bf_t a_s, *a, *r;
13609+ JSValue op1, op2, res;
13610+ int64_t e;
1343913611 int ret;
1344013612
13613+ res = JS_NewBigFloat(ctx);
13614+ if (JS_IsException(res))
13615+ return -1;
13616+ r = JS_GetBigFloat(res);
1344113617 op1 = sp[-2];
1344213618 op2 = sp[-1];
1344313619 a = JS_ToBigFloat(ctx, &a_s, op1);
1344413620 if (!a)
1344513621 return -1;
13446−#if LIMB_BITS == 32
13447− ret = JS_ToInt32(ctx, &e, op2);
13448−#else
13449− ret = JS_ToInt64(ctx, &e, op2);
13450−#endif
13622+ if (JS_IsBigInt(ctx, op2)) {
13623+ ret = JS_ToBigInt64(ctx, &e, op2);
13624+ } else {
13625+ ret = JS_ToInt64(ctx, &e, op2);
13626+ }
1345113627 if (ret) {
1345213628 if (a == &a_s)
1345313629 bf_delete(a);
13630+ JS_FreeValue(ctx, res);
1345413631 return -1;
1345513632 }
1345613633
13457− bf_init(ctx->bf_ctx, r);
1345813634 bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags);
1345913635 if (a == &a_s)
1346013636 bf_delete(a);
1346113637 JS_FreeValue(ctx, op1);
1346213638 JS_FreeValue(ctx, op2);
13463− sp[-2] = JS_NewBigFloat(ctx, r);
13639+ sp[-2] = res;
1346413640 return 0;
1346513641 }
1346613642
@@ -13882,22 +14058,9 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, · 415 unmodified lines
1388214058 d2 = JS_VALUE_GET_INT(op2);
1388314059 goto number_test;
1388414060 } else if (tag2 == JS_TAG_FLOAT64) {
13885−#ifdef CONFIG_BIGNUM
13886− if (is_bigint_mode(ctx)) {
13887− res = FALSE;
13888− } else
13889−#endif
13890− {
13891− d2 = JS_VALUE_GET_FLOAT64(op2);
13892− goto number_test;
13893− }
13894− } else
13895−#ifdef CONFIG_BIGNUM
13896− if (tag2 == JS_TAG_BIG_INT && is_bigint_mode(ctx)) {
13897− goto bigint_test;
13898− } else
13899−#endif
13900− {
14061+ d2 = JS_VALUE_GET_FLOAT64(op2);
14062+ goto number_test;
14063+ } else {
1390114064 res = FALSE;
1390214065 }
1390314066 break;
@@ -13905,11 +14068,7 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, · 1 unmodified line
1390514068 d1 = JS_VALUE_GET_FLOAT64(op1);
1390614069 if (tag2 == JS_TAG_FLOAT64) {
1390714070 d2 = JS_VALUE_GET_FLOAT64(op2);
13908− } else if (tag2 == JS_TAG_INT
13909−#ifdef CONFIG_BIGNUM
13910− && !is_bigint_mode(ctx)
13911−#endif
13912− ) {
14071+ } else if (tag2 == JS_TAG_INT) {
1391314072 d2 = JS_VALUE_GET_INT(op2);
1391414073 } else {
1391514074 res = FALSE;
@@ -13936,15 +14095,10 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, · 20 unmodified lines
1393614095 case JS_TAG_BIG_INT:
1393714096 {
1393814097 bf_t a_s, *a, b_s, *b;
13939− if (tag1 == tag2) {
13940− /* OK */
13941− } else if (tag2 == JS_TAG_INT && is_bigint_mode(ctx)) {
13942− /* OK */
13943− } else {
14098+ if (tag1 != tag2) {
1394414099 res = FALSE;
1394514100 break;
1394614101 }
13947− bigint_test:
1394814102 a = JS_ToBigFloat(ctx, &a_s, op1);
1394914103 b = JS_ToBigFloat(ctx, &b_s, op2);
1395014104 res = bf_cmp_eq(a, b);
@@ -14100,30 +14254,20 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValue op1) · 149 unmodified lines
1410014254 tag = JS_VALUE_GET_NORM_TAG(op1);
1410114255 switch(tag) {
1410214256 #ifdef CONFIG_BIGNUM
14103− case JS_TAG_INT:
14104− if (is_bigint_mode(ctx))
14105− atom = JS_ATOM_bigint;
14106− else
14107− atom = JS_ATOM_number;
14108− break;
1410914257 case JS_TAG_BIG_INT:
1411014258 atom = JS_ATOM_bigint;
1411114259 break;
14112− case JS_TAG_FLOAT64:
14113− atom = JS_ATOM_number;
14114− break;
1411514260 case JS_TAG_BIG_FLOAT:
1411614261 atom = JS_ATOM_bigfloat;
1411714262 break;
1411814263 case JS_TAG_BIG_DECIMAL:
1411914264 atom = JS_ATOM_bigdecimal;
1412014265 break;
14121−#else
14266+#endif
1412214267 case JS_TAG_INT:
1412314268 case JS_TAG_FLOAT64:
1412414269 atom = JS_ATOM_number;
1412514270 break;
14126−#endif
1412714271 case JS_TAG_UNDEFINED:
1412814272 atom = JS_ATOM_undefined;
1412914273 break;
@@ -15288,7 +15432,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, · 1158 unmodified lines
1528815432 /* we only propagate the bignum mode as some runtime functions
1528915433 test it */
1529015434 if (prev_sf)
15291− sf->js_mode = prev_sf->js_mode & JS_MODE_BIGINT;
15435+ sf->js_mode = prev_sf->js_mode & JS_MODE_MATH;
1529215436 else
1529315437 sf->js_mode = 0;
1529415438 #else
@@ -17315,11 +17459,12 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 2020 unmodified lines
1731517459 v1 = JS_VALUE_GET_INT(op1);
1731617460 v2 = JS_VALUE_GET_INT(op2);
1731717461 r = (int64_t)v1 * v2;
17318−#ifdef CONFIG_BIGNUM
17319− if (unlikely((int)r != r) || (r == 0 && !is_bigint_mode(ctx)))
17320− goto binary_arith_slow;
17321−#else
1732217462 if (unlikely((int)r != r)) {
17463+#ifdef CONFIG_BIGNUM
17464+ if (unlikely(sf->js_mode & JS_MODE_MATH) &&
17465+ (r < -MAX_SAFE_INTEGER || r > MAX_SAFE_INTEGER))
17466+ goto binary_arith_slow;
17467+#endif
1732317468 d = (double)r;
1732417469 goto mul_fp_res;
1732517470 }
@@ -17328,14 +17473,15 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 2 unmodified lines
1732817473 d = -0.0;
1732917474 goto mul_fp_res;
1733017475 }
17331−#endif
1733217476 sp[-2] = JS_NewInt32(ctx, r);
1733317477 sp--;
1733417478 } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
17479+#ifdef CONFIG_BIGNUM
17480+ if (unlikely(sf->js_mode & JS_MODE_MATH))
17481+ goto binary_arith_slow;
17482+#endif
1733517483 d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
17336−#ifndef CONFIG_BIGNUM
1733717484 mul_fp_res:
17338−#endif
1733917485 sp[-2] = __JS_NewFloat64(ctx, d);
1734017486 sp--;
1734117487 } else {
@@ -17343,11 +17489,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 1 unmodified line
1734317489 }
1734417490 }
1734517491 BREAK;
17346−#ifdef CONFIG_BIGNUM
17347− CASE(OP_math_div):
17348− CASE(OP_div):
17349− goto binary_arith_slow;
17350−#else
1735117492 CASE(OP_div):
1735217493 {
1735317494 JSValue op1, op2;
@@ -17355,6 +17496,8 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 1 unmodified line
1735517496 op2 = sp[-1];
1735617497 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
1735717498 int v1, v2;
17499+ if (unlikely(sf->js_mode & JS_MODE_MATH))
17500+ goto binary_arith_slow;
1735817501 v1 = JS_VALUE_GET_INT(op1);
1735917502 v2 = JS_VALUE_GET_INT(op2);
1736017503 sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
@@ -17364,7 +17507,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 3 unmodified lines
1736417507 }
1736517508 }
1736617509 BREAK;
17367−#endif
1736817510 CASE(OP_mod):
1736917511 #ifdef CONFIG_BIGNUM
1737017512 CASE(OP_math_mod):
@@ -17390,9 +17532,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 19 unmodified lines
1739017532 }
1739117533 BREAK;
1739217534 CASE(OP_pow):
17393−#ifdef CONFIG_BIGNUM
17394− CASE(OP_math_pow):
17395−#endif
1739617535 binary_arith_slow:
1739717536 if (js_binary_arith_slow(ctx, sp, opcode))
1739817537 goto exception;
@@ -17422,11 +17561,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 23 unmodified lines
1742217561 tag = JS_VALUE_GET_TAG(op1);
1742317562 if (tag == JS_TAG_INT) {
1742417563 val = JS_VALUE_GET_INT(op1);
17425−#ifdef CONFIG_BIGNUM
17426− if (unlikely(val == INT32_MIN) ||
17427− (val == 0 && !is_bigint_mode(ctx)))
17428− goto slow_neg;
17429−#else
1743017564 /* Note: -0 cannot be expressed as integer */
1743117565 if (unlikely(val == 0)) {
1743217566 d = -0.0;
@@ -17436,18 +17570,12 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 3 unmodified lines
1743617570 d = -(double)val;
1743717571 goto neg_fp_res;
1743817572 }
17439−#endif
1744017573 sp[-1] = JS_NewInt32(ctx, -val);
1744117574 } else if (JS_TAG_IS_FLOAT64(tag)) {
1744217575 d = -JS_VALUE_GET_FLOAT64(op1);
17443−#ifndef CONFIG_BIGNUM
1744417576 neg_fp_res:
17445−#endif
1744617577 sp[-1] = __JS_NewFloat64(ctx, d);
1744717578 } else {
17448−#ifdef CONFIG_BIGNUM
17449− slow_neg:
17450−#endif
1745117579 if (js_unary_arith_slow(ctx, sp, opcode))
1745217580 goto exception;
1745317581 }
@@ -17560,7 +17688,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 106 unmodified lines
1756017688 #ifdef CONFIG_BIGNUM
1756117689 {
1756217690 int64_t r;
17563− if (is_bigint_mode(ctx)) {
17691+ if (unlikely(sf->js_mode & JS_MODE_MATH)) {
1756417692 if (v2 > 0x1f)
1756517693 goto shl_slow;
1756617694 r = (int64_t)v1 << v2;
@@ -17616,7 +17744,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, · 49 unmodified lines
1761617744 v2 = JS_VALUE_GET_INT(op2);
1761717745 #ifdef CONFIG_BIGNUM
1761817746 if (unlikely(v2 > 0x1f)) {
17619− if (is_bigint_mode(ctx))
17747+ if (unlikely(sf->js_mode & JS_MODE_MATH))
1762017748 goto sar_slow;
1762117749 else
1762217750 v2 &= 0x1f;
@@ -20182,7 +20310,7 @@ static __exception int next_token(JSParseState *s) · 2559 unmodified lines
2018220310 ATOD_ACCEPT_UNDERSCORES;
2018320311 #ifdef CONFIG_BIGNUM
2018420312 flags |= ATOD_ACCEPT_SUFFIX;
20185− if (s->cur_func->js_mode & JS_MODE_BIGINT) {
20313+ if (s->cur_func->js_mode & JS_MODE_MATH) {
2018620314 flags |= ATOD_MODE_BIGINT;
2018720315 if (s->cur_func->js_mode & JS_MODE_MATH)
2018820316 flags |= ATOD_TYPE_BIG_FLOAT;
@@ -23312,7 +23440,6 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen · 3123 unmodified lines
2331223440 } else
2331323441 #ifdef CONFIG_BIGNUM
2331423442 if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
23315− bf_t r_s, *r = &r_s;
2331623443 slimb_t e;
2331723444 int ret;
2331823445
@@ -23326,9 +23453,9 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen · 7 unmodified lines
2332623453 emit_op(s, OP_push_i32);
2332723454 emit_u32(s, e);
2332823455 } else {
23329− bf_init(s->ctx->bf_ctx, r);
23330− bf_set_si(r, e);
23331− val = JS_NewBigInt(s->ctx, r);
23456+ val = JS_NewBigInt64_1(s->ctx, e);
23457+ if (JS_IsException(val))
23458+ return -1;
2333223459 ret = emit_push_const(s, val, 0);
2333323460 JS_FreeValue(s->ctx, val);
2333423461 if (ret < 0)
@@ -24105,10 +24232,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) · 770 unmodified lines
2410524232 return -1;
2410624233 if (js_parse_unary(s, 1))
2410724234 return -1;
24108− if (s->cur_func->js_mode & JS_MODE_MATH)
24109− emit_op(s, OP_math_pow);
24110− else
24111− emit_op(s, OP_pow);
24235+ emit_op(s, OP_pow);
2411224236 }
2411324237 #else
2411424238 if (s->token.val == TOK_POW) {
@@ -24151,12 +24275,7 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level, · 36 unmodified lines
2415124275 opcode = OP_mul;
2415224276 break;
2415324277 case '/':
24154−#ifdef CONFIG_BIGNUM
24155− if (s->cur_func->js_mode & JS_MODE_MATH)
24156− opcode = OP_math_div;
24157− else
24158−#endif
24159− opcode = OP_div;
24278+ opcode = OP_div;
2416024279 break;
2416124280 case '%':
2416224281 #ifdef CONFIG_BIGNUM
@@ -24549,12 +24668,8 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) · 386 unmodified lines
2454924668 op = assign_opcodes[op - TOK_MUL_ASSIGN];
2455024669 #ifdef CONFIG_BIGNUM
2455124670 if (s->cur_func->js_mode & JS_MODE_MATH) {
24552− if (op == OP_div)
24553− op = OP_math_div;
24554− else if (op == OP_mod)
24671+ if (op == OP_mod)
2455524672 op = OP_math_mod;
24556− else if (op == OP_pow)
24557− op = OP_math_pow;
2455824673 }
2455924674 #endif
2456024675 emit_op(s, op);
@@ -30149,20 +30264,6 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) · 5588 unmodified lines
3014930264 len = opcode_info[op].size;
3015030265 pos_next = pos + len;
3015130266 switch(op) {
30152− case OP_close_var_object:
30153− {
30154− if (s->var_object_idx >= 0) {
30155− /* close the var object and create a new one */
30156− add_pc2line_info(s, bc_out.size, line_num);
30157− dbuf_putc(&bc_out, OP_close_loc);
30158− dbuf_put_u16(&bc_out, s->var_object_idx);
30159− dbuf_putc(&bc_out, OP_special_object);
30160− dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
30161− put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
30162− }
30163− }
30164− break;
30165−
3016630267 case OP_line_num:
3016730268 /* line number info (for debug). We put it in a separate
3016830269 compressed table to reduce memory usage and get better
@@ -31508,11 +31609,8 @@ static __exception int js_parse_directives(JSParseState *s) · 1339 unmodified lines
3150831609 }
3150931610 #endif
3151031611 #ifdef CONFIG_BIGNUM
31511− else if (s->ctx->bignum_ext && !strcmp(str, "use bigint")) {
31512− s->cur_func->js_mode |= JS_MODE_BIGINT;
31513− }
3151431612 else if (s->ctx->bignum_ext && !strcmp(str, "use math")) {
31515− s->cur_func->js_mode |= JS_MODE_BIGINT | JS_MODE_MATH;
31613+ s->cur_func->js_mode |= JS_MODE_MATH;
3151631614 }
3151731615 #endif
3151831616 }
@@ -31804,13 +31902,6 @@ static __exception int js_parse_function_decl2(JSParseState *s, · 285 unmodified lines
3180431902 }
3180531903 if (js_parse_destructing_element(s, TOK_VAR, 1, TRUE, -1, TRUE))
3180631904 goto fail;
31807− /* Close var object: necessary if direct eval call
31808− occurred in the assignment expression or if any
31809− variable was captured and a later direct eval call
31810− may instantiate it in the var object.
31811− The next pass will generate the capture if required.
31812− */
31813− emit_op(s, OP_close_var_object);
3181431905 } else if (s->token.val == TOK_IDENT) {
3181531906 if (s->token.u.ident.is_reserved) {
3181631907 js_parse_error_reserved_identifier(s);
@@ -31889,8 +31980,6 @@ static __exception int js_parse_function_decl2(JSParseState *s, · 72 unmodified lines
3188931980 set_object_name(s, name);
3189031981 emit_op(s, OP_put_arg);
3189131982 emit_u16(s, idx);
31892− /* Close var object: see above comment. */
31893− emit_op(s, OP_close_var_object);
3189431983 emit_label(s, label);
3189531984 }
3189631985 } else if (!has_opt_arg) {
@@ -34399,30 +34488,20 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val) · 2502 unmodified lines
3439934488 case JS_TAG_EXCEPTION:
3440034489 return JS_DupValue(ctx, val);
3440134490 #ifdef CONFIG_BIGNUM
34402− case JS_TAG_INT:
34403− if (is_bigint_mode(ctx))
34404− obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
34405− else
34406− obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
34407− goto set_value;
3440834491 case JS_TAG_BIG_INT:
3440934492 obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
3441034493 goto set_value;
34411− case JS_TAG_FLOAT64:
34412− obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
34413− goto set_value;
3441434494 case JS_TAG_BIG_FLOAT:
3441534495 obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT);
3441634496 goto set_value;
3441734497 case JS_TAG_BIG_DECIMAL:
3441834498 obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL);
3441934499 goto set_value;
34420−#else
34500+#endif
3442134501 case JS_TAG_INT:
3442234502 case JS_TAG_FLOAT64:
3442334503 obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
3442434504 goto set_value;
34425−#endif
3442634505 case JS_TAG_STRING:
3442734506 /* XXX: should call the string constructor */
3442834507 {
@@ -34995,10 +35074,13 @@ static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val · 566 unmodified lines
3499535074 ret = JS_PreventExtensions(ctx, obj);
3499635075 if (ret < 0)
3499735076 return JS_EXCEPTION;
34998− if (reflect)
35077+ if (reflect) {
3499935078 return JS_NewBool(ctx, ret);
35000− else
35079+ } else {
35080+ if (!ret)
35081+ return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
3500135082 return JS_DupValue(ctx, obj);
35083+ }
3500235084 }
3500335085
3500435086 static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
@@ -35166,7 +35248,7 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val, · 161 unmodified lines
3516635248 goto exception;
3516735249 }
3516835250 js_free_prop_enum(ctx, props, len);
35169− return JS_TRUE;
35251+ return JS_DupValue(ctx, obj);
3517035252
3517135253 exception:
3517235254 js_free_prop_enum(ctx, props, len);
@@ -37690,17 +37772,14 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target, · 2517 unmodified lines
3769037772 int argc, JSValueConst *argv)
3769137773 {
3769237774 JSValue val, obj;
37693−#ifdef CONFIG_BIGNUM
3769437775 if (argc == 0) {
37695− if (is_bigint_mode(ctx))
37696− val = __JS_NewFloat64(ctx, 0);
37697− else
37698− val = JS_NewInt32(ctx, 0);
37776+ val = JS_NewInt32(ctx, 0);
3769937777 } else {
3770037778 val = JS_ToNumeric(ctx, argv[0]);
3770137779 if (JS_IsException(val))
3770237780 return val;
3770337781 switch(JS_VALUE_GET_TAG(val)) {
37782+#ifdef CONFIG_BIGNUM
3770437783 case JS_TAG_BIG_INT:
3770537784 case JS_TAG_BIG_FLOAT:
3770637785 {
@@ -37711,25 +37790,19 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target, · 4 unmodified lines
3771137790 val = __JS_NewFloat64(ctx, d);
3771237791 }
3771337792 break;
37714− case JS_TAG_INT:
37715− if (is_bigint_mode(ctx)) {
37716− /* always return a number in bignum mode */
37717− val = __JS_NewFloat64(ctx, JS_VALUE_GET_INT(val));
37718− }
37793+ case JS_TAG_BIG_DECIMAL:
37794+ val = JS_ToStringFree(ctx, val);
37795+ if (JS_IsException(val))
37796+ return val;
37797+ val = JS_ToNumberFree(ctx, val);
37798+ if (JS_IsException(val))
37799+ return val;
3771937800 break;
37801+#endif
3772037802 default:
3772137803 break;
3772237804 }
3772337805 }
37724−#else
37725− if (argc == 0) {
37726− val = JS_NewInt32(ctx, 0);
37727− } else {
37728− val = JS_ToNumber(ctx, argv[0]);
37729− if (JS_IsException(val))
37730− return val;
37731− }
37732−#endif
3773337806 if (!JS_IsUndefined(new_target)) {
3773437807 obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
3773537808 if (!JS_IsException(obj))
@@ -37760,7 +37833,6 @@ static JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val, · 24 unmodified lines
3776037833 static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
3776137834 int argc, JSValueConst *argv)
3776237835 {
37763− /* XXX: should just check for float and big_float */
3776437836 if (!JS_IsNumber(argv[0]))
3776537837 return JS_FALSE;
3776637838 return js_global_isNaN(ctx, this_val, argc, argv);
@@ -37793,8 +37865,7 @@ static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val, · 26 unmodified lines
3779337865 return JS_FALSE;
3779437866 if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
3779537867 return JS_EXCEPTION;
37796− return JS_NewBool(ctx, isfinite(d) && floor(d) == d &&
37797− fabs(d) <= (double)MAX_SAFE_INTEGER);
37868+ return JS_NewBool(ctx, is_safe_integer(d));
3779837869 }
3779937870
3780037871 static const JSCFunctionListEntry js_number_funcs[] = {
@@ -37838,6 +37909,18 @@ static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val, · 37 unmodified lines
3783837909 return js_thisNumberValue(ctx, this_val);
3783937910 }
3784037911
37912+static int js_get_radix(JSContext *ctx, JSValueConst val)
37913+{
37914+ int radix;
37915+ if (JS_ToInt32Sat(ctx, &radix, val))
37916+ return -1;
37917+ if (radix < 2 || radix > 36) {
37918+ JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
37919+ return -1;
37920+ }
37921+ return radix;
37922+}
37923+
3784137924 static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
3784237925 int argc, JSValueConst *argv, int magic)
3784337926 {
@@ -37851,12 +37934,9 @@ static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val, · 7 unmodified lines
3785137934 if (magic || JS_IsUndefined(argv[0])) {
3785237935 base = 10;
3785337936 } else {
37854− if (JS_ToInt32Sat(ctx, &base, argv[0]))
37855− goto fail;
37856− if (base < 2 || base > 36) {
37857− JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
37937+ base = js_get_radix(ctx, argv[0]);
37938+ if (base < 0)
3785837939 goto fail;
37859− }
3786037940 }
3786137941 if (JS_ToFloat64Free(ctx, &d, val))
3786237942 return JS_EXCEPTION;
@@ -37972,10 +38052,6 @@ static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val, · 109 unmodified lines
3797238052 p = str;
3797338053 p += skip_spaces(p);
3797438054 flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;
37975−#ifdef CONFIG_BIGNUM
37976− if (is_bigint_mode(ctx))
37977− flags |= ATOD_MODE_BIGINT;
37978−#endif
3797938055 ret = js_atof(ctx, p, NULL, radix, flags);
3798038056 }
3798138057 JS_FreeCString(ctx, str);
@@ -39738,348 +39814,6 @@ static double js_fmax(double a, double b) · 1756 unmodified lines
3973839814 }
3973939815 }
3974039816
39741−#ifdef CONFIG_BIGNUM
39742−
39743−enum {
39744− MATH_OP_ABS,
39745− MATH_OP_FLOOR,
39746− MATH_OP_CEIL,
39747− MATH_OP_ROUND,
39748− MATH_OP_TRUNC,
39749− MATH_OP_SQRT,
39750− MATH_OP_FPROUND,
39751− MATH_OP_ACOS,
39752− MATH_OP_ASIN,
39753− MATH_OP_ATAN,
39754− MATH_OP_ATAN2,
39755− MATH_OP_COS,
39756− MATH_OP_EXP,
39757− MATH_OP_LOG,
39758− MATH_OP_POW,
39759− MATH_OP_SIN,
39760− MATH_OP_TAN,
39761− MATH_OP_FMOD,
39762− MATH_OP_REM,
39763− MATH_OP_SIGN,
39764−
39765− MATH_OP_ADD,
39766− MATH_OP_SUB,
39767− MATH_OP_MUL,
39768− MATH_OP_DIV,
39769−};
39770−
39771−static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
39772− int argc, JSValueConst *argv, int magic)
39773−{
39774− bf_t a_s, *a, r_s, *r = &r_s;
39775− JSFloatEnv *fe;
39776− int rnd_mode;
39777− JSValue op1;
39778−
39779− op1 = JS_ToNumber(ctx, argv[0]);
39780− if (JS_IsException(op1))
39781− return op1;
39782− a = JS_ToBigFloat(ctx, &a_s, op1);
39783− fe = &ctx->fp_env;
39784− if (argc > 1) {
39785− fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
39786− if (!fe) {
39787− if (a == &a_s)
39788− bf_delete(a);
39789− JS_FreeValue(ctx, op1);
39790− return JS_EXCEPTION;
39791− }
39792− }
39793−
39794− bf_init(ctx->bf_ctx, r);
39795− switch (magic) {
39796− case MATH_OP_ABS:
39797− bf_set(r, a);
39798− r->sign = 0;
39799− break;
39800− case MATH_OP_FLOOR:
39801− rnd_mode = BF_RNDD;
39802− goto rint;
39803− case MATH_OP_CEIL:
39804− rnd_mode = BF_RNDU;
39805− goto rint;
39806− case MATH_OP_ROUND:
39807− rnd_mode = BF_RNDNU;
39808− goto rint;
39809− case MATH_OP_TRUNC:
39810− rnd_mode = BF_RNDZ;
39811− rint:
39812− bf_set(r, a);
39813− fe->status |= bf_rint(r, rnd_mode);
39814− break;
39815− case MATH_OP_SQRT:
39816− fe->status |= bf_sqrt(r, a, fe->prec, fe->flags);
39817− break;
39818− case MATH_OP_FPROUND:
39819− bf_set(r, a);
39820− fe->status |= bf_round(r, fe->prec, fe->flags);
39821− break;
39822− case MATH_OP_ACOS:
39823− fe->status |= bf_acos(r, a, fe->prec, fe->flags);
39824− break;
39825− case MATH_OP_ASIN:
39826− fe->status |= bf_asin(r, a, fe->prec, fe->flags);
39827− break;
39828− case MATH_OP_ATAN:
39829− fe->status |= bf_atan(r, a, fe->prec, fe->flags);
39830− break;
39831− case MATH_OP_COS:
39832− fe->status |= bf_cos(r, a, fe->prec, fe->flags);
39833− break;
39834− case MATH_OP_EXP:
39835− fe->status |= bf_exp(r, a, fe->prec, fe->flags);
39836− break;
39837− case MATH_OP_LOG:
39838− fe->status |= bf_log(r, a, fe->prec, fe->flags);
39839− break;
39840− case MATH_OP_SIN:
39841− fe->status |= bf_sin(r, a, fe->prec, fe->flags);
39842− break;
39843− case MATH_OP_TAN:
39844− fe->status |= bf_tan(r, a, fe->prec, fe->flags);
39845− break;
39846− case MATH_OP_SIGN:
39847− if (bf_is_nan(a) || bf_is_zero(a)) {
39848− bf_set(r, a);
39849− } else {
39850− bf_set_si(r, 1 - 2 * a->sign);
39851− }
39852− break;
39853− default:
39854− abort();
39855− }
39856− if (a == &a_s)
39857− bf_delete(a);
39858− JS_FreeValue(ctx, op1);
39859− return JS_NewBigFloat(ctx, r);
39860−}
39861−
39862−static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
39863− int argc, JSValueConst *argv, int magic)
39864−{
39865− bf_t a_s, *a, b_s, *b, r_s, *r = &r_s;
39866− JSFloatEnv *fe;
39867− JSValue op1, op2;
39868−
39869− op1 = JS_ToNumber(ctx, argv[0]);
39870− if (JS_IsException(op1))
39871− return op1;
39872− op2 = JS_ToNumber(ctx, argv[1]);
39873− if (JS_IsException(op2)) {
39874− JS_FreeValue(ctx, op1);
39875− return op2;
39876− }
39877− a = JS_ToBigFloat(ctx, &a_s, op1);
39878− b = JS_ToBigFloat(ctx, &b_s, op2);
39879− fe = &ctx->fp_env;
39880− if (argc > 2) {
39881− fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
39882− if (!fe) {
39883− if (a == &a_s)
39884− bf_delete(a);
39885− if (b == &b_s)
39886− bf_delete(b);
39887− JS_FreeValue(ctx, op1);
39888− JS_FreeValue(ctx, op2);
39889− return JS_EXCEPTION;
39890− }
39891− }
39892−
39893− bf_init(ctx->bf_ctx, r);
39894− switch (magic) {
39895− case MATH_OP_ATAN2:
39896− fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags);
39897− break;
39898− case MATH_OP_POW:
39899− fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUICKS);
39900− break;
39901− case MATH_OP_FMOD:
39902− fe->status |= bf_fmod(r, a, b, fe->prec, fe->flags);
39903− break;
39904− case MATH_OP_REM:
39905− fe->status |= bf_remainder(r, a, b, fe->prec, fe->flags);
39906− break;
39907− case MATH_OP_ADD:
39908− fe->status |= bf_add(r, a, b, fe->prec, fe->flags);
39909− break;
39910− case MATH_OP_SUB:
39911− fe->status |= bf_sub(r, a, b, fe->prec, fe->flags);
39912− break;
39913− case MATH_OP_MUL:
39914− fe->status |= bf_mul(r, a, b, fe->prec, fe->flags);
39915− break;
39916− case MATH_OP_DIV:
39917− fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
39918− break;
39919− default:
39920− abort();
39921− }
39922− if (a == &a_s)
39923− bf_delete(a);
39924− if (b == &b_s)
39925− bf_delete(b);
39926− JS_FreeValue(ctx, op1);
39927− JS_FreeValue(ctx, op2);
39928− return JS_NewBigFloat(ctx, r);
39929−}
39930−
39931−static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
39932− int argc, JSValueConst *argv, int magic)
39933−{
39934− BOOL is_max = magic;
39935− JSValue val, ret;
39936− int i;
39937− uint32_t tag;
39938−
39939− if (unlikely(argc == 0)) {
39940− return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
39941− }
39942−
39943− tag = JS_VALUE_GET_TAG(argv[0]);
39944− if (tag == JS_TAG_INT) {
39945− int a1, r1 = JS_VALUE_GET_INT(argv[0]);
39946− for(i = 1; i < argc; i++) {
39947− tag = JS_VALUE_GET_TAG(argv[i]);
39948− if (tag != JS_TAG_INT) {
39949− ret = JS_NewInt32(ctx, r1);
39950− goto generic_case;
39951− }
39952− a1 = JS_VALUE_GET_INT(argv[i]);
39953− if (is_max)
39954− r1 = max_int(r1, a1);
39955− else
39956− r1 = min_int(r1, a1);
39957− }
39958− ret = JS_NewInt32(ctx, r1);
39959− } else {
39960− ret = JS_ToNumber(ctx, argv[0]);
39961− if (JS_IsException(ret))
39962− return ret;
39963− i = 1;
39964− generic_case:
39965− for(; i < argc; i++) {
39966− val = JS_ToNumber(ctx, argv[i]);
39967− if (JS_IsException(val)) {
39968− JS_FreeValue(ctx, ret);
39969− return val;
39970− }
39971− if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(ret)) &&
39972− JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(val))) {
39973− double r, a;
39974− r = JS_VALUE_GET_FLOAT64(ret);
39975− a = JS_VALUE_GET_FLOAT64(val);
39976− if (!isnan(r)) {
39977− if (isnan(a)) {
39978− r = a;
39979− } else {
39980− if (is_max)
39981− r = js_fmax(r, a);
39982− else
39983− r = js_fmin(r, a);
39984− }
39985− ret = __JS_NewFloat64(ctx, r);
39986− }
39987− } else {
39988− bf_t a_s, *a, r_s, *r;
39989− int res;
39990−
39991− r = JS_ToBigFloat(ctx, &r_s, ret);
39992− if (!bf_is_nan(r)) {
39993− a = JS_ToBigFloat(ctx, &a_s, val);
39994− res = bf_cmp_full(a, r);
39995− if (is_max)
39996− res = -res;
39997− if (bf_is_nan(a) || res < 0) {
39998− JS_FreeValue(ctx, ret);
39999− ret = JS_DupValue(ctx, val);
40000− }
40001− if (a == &a_s)
40002− bf_delete(a);
40003− }
40004− if (r == &r_s)
40005− bf_delete(r);
40006− JS_FreeValue(ctx, val);
40007− }
40008− }
40009− }
40010− return ret;
40011−}
40012−
40013−static JSValue js_math_abs(JSContext *ctx, JSValueConst this_val,
40014− int argc, JSValueConst *argv)
40015−{
40016− JSValue val;
40017− uint32_t tag;
40018−
40019− val = JS_ToNumeric(ctx, argv[0]);
40020− tag = JS_VALUE_GET_NORM_TAG(val);
40021− switch(tag) {
40022− case JS_TAG_INT:
40023− if (JS_VALUE_GET_INT(val) < 0)
40024− val = JS_NewInt64(ctx, -(int64_t)JS_VALUE_GET_INT(val));
40025− break;
40026− case JS_TAG_FLOAT64:
40027− val = __JS_NewFloat64(ctx, fabs(JS_VALUE_GET_FLOAT64(val)));
40028− break;
40029− case JS_TAG_BIG_FLOAT:
40030− case JS_TAG_BIG_INT:
40031− {
40032− JSBigFloat *p = JS_VALUE_GET_PTR(val);
40033− bf_t r_s, *r = &r_s;
40034− bf_init(ctx->bf_ctx, r);
40035− bf_set(r, &p->num);
40036− r->sign = 0;
40037− JS_FreeValue(ctx, val);
40038− if (tag == JS_TAG_BIG_FLOAT)
40039− val = JS_NewBigFloat(ctx, r);
40040− else
40041− val = JS_NewBigInt2(ctx, r, TRUE);
40042− }
40043− break;
40044− default:
40045− break;
40046− }
40047− return val;
40048−}
40049−
40050−#if 0
40051−/* XXX: should give exact rounding */
40052−/* XXX: correct NaN/Infinity handling */
40053−static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
40054− int argc, JSValueConst *argv)
40055−{
40056− bf_t a_s, *a, r_s, *r = &r_s, r2_s, *r2 = &r2_s;
40057− JSValue val;
40058− int i;
40059− BOOL is_float;
40060−
40061− bf_init(ctx->bf_ctx, r);
40062− bf_set_si(r, 0);
40063− for(i = 0; i < argc; i++) {
40064− val = JS_ToNumber(ctx, argv[i]);
40065− if (JS_IsException(val)) {
40066− bf_delete(r);
40067− return val;
40068− }
40069− a = JS_ToBigFloat(ctx, &is_float, &a_s, val);
40070− bf_add(r, r, a, ctx->fp_env.prec, ctx->fp_env.flags);
40071− if (a == &a_s)
40072− bf_delete(a);
40073− }
40074− bf_init(ctx->bf_ctx, r2);
40075− bf_sqrt(r2, r, ctx->fp_env.prec, ctx->fp_env.flags);
40076− bf_delete(r);
40077− return JS_NewBigFloat(ctx, r2);
40078−}
40079−#endif
40080−
40081−#else
40082−
4008339817 static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
4008439818 int argc, JSValueConst *argv, int magic)
4008539819 {
@@ -40133,8 +39867,6 @@ static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val, · 47 unmodified lines
4013339867 }
4013439868 }
4013539869
40136−#endif /* !CONFIG_BIGNUM */
40137−
4013839870 static double js_math_sign(double a)
4013939871 {
4014039872 if (isnan(a) || a == 0.0)
@@ -40267,11 +39999,7 @@ static JSValue js_math_random(JSContext *ctx, JSValueConst this_val, · 126 unmodified lines
4026739999 static const JSCFunctionListEntry js_math_funcs[] = {
4026840000 JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
4026940001 JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
40270−#ifdef CONFIG_BIGNUM
40271− JS_CFUNC_DEF("abs", 1, js_math_abs ),
40272−#else
4027340002 JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
40274−#endif
4027540003 JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
4027640004 JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
4027740005 JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
@@ -41959,46 +41687,12 @@ static JSValue json_parse_value(JSParseState *s) · 1681 unmodified lines
4195941687 }
4196041688 is_neg = 1;
4196141689 number:
41962−#ifdef CONFIG_BIGNUM
41963− val = JS_DupValue(ctx, s->token.u.num.val);
41964− if (is_neg) {
41965− switch(JS_VALUE_GET_NORM_TAG(val)) {
41966− case JS_TAG_BIG_INT:
41967− case JS_TAG_BIG_FLOAT:
41968− {
41969− JSBigFloat *p;
41970− p = JS_VALUE_GET_PTR(val);
41971− bf_neg(&p->num);
41972− }
41973− break;
41974− case JS_TAG_FLOAT64:
41975− {
41976− double d;
41977− d = JS_VALUE_GET_FLOAT64(val);
41978− val = __JS_NewFloat64(ctx, -d);
41979− }
41980− break;
41981− default:
41982− case JS_TAG_INT:
41983− {
41984− int v;
41985− v = JS_VALUE_GET_INT(val);
41986− if (v == 0 && !is_bigint_mode(s->ctx))
41987− val = __JS_NewFloat64(ctx, -0.0);
41988− else
41989− val = JS_NewInt64(ctx, -(int64_t)v);
41990− }
41991− break;
41992− }
41993− }
41994−#else
4199541690 val = s->token.u.num.val;
4199641691 if (is_neg) {
4199741692 double d;
4199841693 JS_ToFloat64(ctx, &d, val); /* no exception possible */
4199941694 val = JS_NewFloat64(ctx, -d);
4200041695 }
42001−#endif
4200241696 if (next_token(s))
4200341697 goto fail;
4200441698 break;
@@ -42168,10 +41862,6 @@ static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) { · 163 unmodified lines
4216841862 return r;
4216941863 }
4217041864
42171−#ifdef CONFIG_BIGNUM
42172−static inline BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v);
42173−#endif
42174−
4217541865 static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
4217641866 JSValueConst holder, JSValue val, JSValueConst key)
4217741867 {
@@ -46764,7 +46454,8 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, · 4586 unmodified lines
4676446454 double d;
4676546455 int p, i, c, sgn;
4676646456 JSString *sp;
46767−
46457+ BOOL is_local;
46458+
4676846459 rv = JS_NAN;
4676946460
4677046461 s = JS_ToString(ctx, argv[0]);
@@ -46780,11 +46471,15 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, · 9 unmodified lines
4678046471 if (string_get_signed_field(sp, &p, &fields[0]))
4678146472 goto done;
4678246473
46474+ is_local = TRUE;
4678346475 for (i = 1; i < 6; i++) {
4678446476 if (string_get_field(sp, &p, &fields[i]))
4678546477 break;
4678646478 }
46787− if (i == 6 && p < sp->len && string_get(sp, p) == '.') {
46479+ if (i <= 3) {
46480+ /* no time: UTC by default */
46481+ is_local = FALSE;
46482+ } else if (i == 6 && p < sp->len && string_get(sp, p) == '.') {
4678846483 /* parse milliseconds as a fractional part, round to nearest */
4678946484 /* XXX: the spec does not indicate which rounding should be used */
4679046485 int mul = 1000, ms = 0;
@@ -46802,14 +46497,20 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, · 11 unmodified lines
4680246497
4680346498 /* parse the time zone offset if present: [+-]HH:mm */
4680446499 tz = 0;
46805− if (p < sp->len && ((sgn = string_get(sp, p)) == '+' || sgn == '-')) {
46806− if (string_get_field(sp, &p, &hh))
46807− goto done;
46808− if (string_get_field(sp, &p, &mm))
46809− goto done;
46810− tz = hh * 60 + mm;
46811− if (sgn == '-')
46812− tz = -tz;
46500+ if (p < sp->len) {
46501+ sgn = string_get(sp, p);
46502+ if (sgn == '+' || sgn == '-') {
46503+ if (string_get_field(sp, &p, &hh))
46504+ goto done;
46505+ if (string_get_field(sp, &p, &mm))
46506+ goto done;
46507+ tz = hh * 60 + mm;
46508+ if (sgn == '-')
46509+ tz = -tz;
46510+ is_local = FALSE;
46511+ } else if (sgn == 'Z') {
46512+ is_local = FALSE;
46513+ }
4681346514 }
4681446515 } else {
4681546516 /* toString or toUTCString format */
@@ -46844,6 +46545,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, · 28 unmodified lines
4684446545 // XXX: parse optional milliseconds?
4684546546
4684646547 /* parse the time zone offset if present: [+-]HHmm */
46548+ is_local = FALSE;
4684746549 tz = 0;
4684846550 for (tz = 0; p < sp->len; p++) {
4684946551 sgn = string_get(sp, p);
@@ -46860,7 +46562,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, · 10 unmodified lines
4686046562 }
4686146563 }
4686246564 }
46863− d = set_date_fields(fields, 0) - tz * 60000;
46565+ d = set_date_fields(fields, is_local) - tz * 60000;
4686446566 rv = __JS_NewFloat64(ctx, d);
4686546567
4686646568 done:
@@ -47080,61 +46782,364 @@ void JS_AddIntrinsicEval(JSContext *ctx) · 213 unmodified lines
4708046782
4708146783 #ifdef CONFIG_BIGNUM
4708246784
46785+/* Operators */
46786+
46787+static void js_operator_set_finalizer(JSRuntime *rt, JSValue val)
46788+{
46789+ JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
46790+ int i, j;
46791+ JSBinaryOperatorDefEntry *ent;
46792+
46793+ if (opset) {
46794+ for(i = 0; i < JS_OVOP_COUNT; i++) {
46795+ if (opset->self_ops[i])
46796+ JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]));
46797+ }
46798+ for(j = 0; j < opset->left.count; j++) {
46799+ ent = &opset->left.tab[j];
46800+ for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
46801+ if (ent->ops[i])
46802+ JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
46803+ }
46804+ }
46805+ js_free_rt(rt, opset->left.tab);
46806+ for(j = 0; j < opset->right.count; j++) {
46807+ ent = &opset->right.tab[j];
46808+ for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
46809+ if (ent->ops[i])
46810+ JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
46811+ }
46812+ }
46813+ js_free_rt(rt, opset->right.tab);
46814+ js_free_rt(rt, opset);
46815+ }
46816+}
46817+
46818+static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
46819+ JS_MarkFunc *mark_func)
46820+{
46821+ JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
46822+ int i, j;
46823+ JSBinaryOperatorDefEntry *ent;
46824+
46825+ if (opset) {
46826+ for(i = 0; i < JS_OVOP_COUNT; i++) {
46827+ if (opset->self_ops[i])
46828+ JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]),
46829+ mark_func);
46830+ }
46831+ for(j = 0; j < opset->left.count; j++) {
46832+ ent = &opset->left.tab[j];
46833+ for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
46834+ if (ent->ops[i])
46835+ JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
46836+ mark_func);
46837+ }
46838+ }
46839+ for(j = 0; j < opset->right.count; j++) {
46840+ ent = &opset->right.tab[j];
46841+ for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
46842+ if (ent->ops[i])
46843+ JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
46844+ mark_func);
46845+ }
46846+ }
46847+ }
46848+}
46849+
46850+
46851+/* create an OperatorSet object */
46852+static JSValue js_operators_create_internal(JSContext *ctx,
46853+ int argc, JSValueConst *argv,
46854+ BOOL is_primitive)
46855+{
46856+ JSValue opset_obj, prop, obj;
46857+ JSOperatorSetData *opset, *opset1;
46858+ JSBinaryOperatorDef *def;
46859+ JSValueConst arg;
46860+ int i, j;
46861+ JSBinaryOperatorDefEntry *new_tab;
46862+ JSBinaryOperatorDefEntry *ent;
46863+ uint32_t op_count;
46864+
46865+ if (ctx->rt->operator_count == UINT32_MAX) {
46866+ return JS_ThrowTypeError(ctx, "too many operators");
46867+ }
46868+ opset_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OPERATOR_SET);
46869+ if (JS_IsException(opset_obj))
46870+ goto fail;
46871+ opset = js_mallocz(ctx, sizeof(*opset));
46872+ if (!opset)
46873+ goto fail;
46874+ JS_SetOpaque(opset_obj, opset);
46875+ if (argc >= 1) {
46876+ arg = argv[0];
46877+ /* self operators */
46878+ for(i = 0; i < JS_OVOP_COUNT; i++) {
46879+ prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]);
46880+ if (JS_IsException(prop))
46881+ goto fail;
46882+ if (!JS_IsUndefined(prop)) {
46883+ if (check_function(ctx, prop)) {
46884+ JS_FreeValue(ctx, prop);
46885+ goto fail;
46886+ }
46887+ opset->self_ops[i] = JS_VALUE_GET_OBJ(prop);
46888+ }
46889+ }
46890+ }
46891+ /* left & right operators */
46892+ for(j = 1; j < argc; j++) {
46893+ arg = argv[j];
46894+ prop = JS_GetPropertyStr(ctx, arg, "left");
46895+ if (JS_IsException(prop))
46896+ goto fail;
46897+ def = &opset->right;
46898+ if (JS_IsUndefined(prop)) {
46899+ prop = JS_GetPropertyStr(ctx, arg, "right");
46900+ if (JS_IsException(prop))
46901+ goto fail;
46902+ if (JS_IsUndefined(prop)) {
46903+ JS_ThrowTypeError(ctx, "left or right property must be present");
46904+ goto fail;
46905+ }
46906+ def = &opset->left;
46907+ }
46908+ /* get the operator set */
46909+ obj = JS_GetProperty(ctx, prop, JS_ATOM_prototype);
46910+ JS_FreeValue(ctx, prop);
46911+ if (JS_IsException(obj))
46912+ goto fail;
46913+ prop = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
46914+ JS_FreeValue(ctx, obj);
46915+ if (JS_IsException(prop))
46916+ goto fail;
46917+ opset1 = JS_GetOpaque2(ctx, prop, JS_CLASS_OPERATOR_SET);
46918+ if (!opset1) {
46919+ JS_FreeValue(ctx, prop);
46920+ goto fail;
46921+ }
46922+ op_count = opset1->operator_counter;
46923+ JS_FreeValue(ctx, prop);
46924+
46925+ /* we assume there are few entries */
46926+ new_tab = js_realloc(ctx, def->tab,
46927+ (def->count + 1) * sizeof(def->tab[0]));
46928+ if (!new_tab)
46929+ goto fail;
46930+ def->tab = new_tab;
46931+ def->count++;
46932+ ent = def->tab + def->count - 1;
46933+ memset(ent, 0, sizeof(def->tab[0]));
46934+ ent->operator_index = op_count;
46935+
46936+ for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
46937+ prop = JS_GetPropertyStr(ctx, arg,
46938+ js_overloadable_operator_names[i]);
46939+ if (JS_IsException(prop))
46940+ goto fail;
46941+ if (!JS_IsUndefined(prop)) {
46942+ if (check_function(ctx, prop)) {
46943+ JS_FreeValue(ctx, prop);
46944+ goto fail;
46945+ }
46946+ ent->ops[i] = JS_VALUE_GET_OBJ(prop);
46947+ }
46948+ }
46949+ }
46950+ opset->is_primitive = is_primitive;
46951+ opset->operator_counter = ctx->rt->operator_count++;
46952+ return opset_obj;
46953+ fail:
46954+ JS_FreeValue(ctx, opset_obj);
46955+ return JS_EXCEPTION;
46956+}
46957+
46958+static JSValue js_operators_create(JSContext *ctx, JSValueConst this_val,
46959+ int argc, JSValueConst *argv)
46960+{
46961+ return js_operators_create_internal(ctx, argc, argv, FALSE);
46962+}
46963+
46964+static JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst this_val,
46965+ int argc, JSValueConst *argv)
46966+{
46967+ JSValue opset_obj, prop;
46968+ JSOperatorSetData *opset;
46969+ const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW };
46970+ JSOverloadableOperatorEnum op;
46971+ int i;
46972+
46973+ opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
46974+ JS_ATOM_Symbol_operatorSet);
46975+ if (JS_IsException(opset_obj))
46976+ goto fail;
46977+ opset = JS_GetOpaque2(ctx, opset_obj, JS_CLASS_OPERATOR_SET);
46978+ if (!opset)
46979+ goto fail;
46980+ for(i = 0; i < countof(ops); i++) {
46981+ op = ops[i];
46982+ prop = JS_GetPropertyStr(ctx, argv[0],
46983+ js_overloadable_operator_names[op]);
46984+ if (JS_IsException(prop))
46985+ goto fail;
46986+ if (!JS_IsUndefined(prop)) {
46987+ if (!JS_IsNull(prop) && check_function(ctx, prop)) {
46988+ JS_FreeValue(ctx, prop);
46989+ goto fail;
46990+ }
46991+ if (opset->self_ops[op])
46992+ JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[op]));
46993+ if (JS_IsNull(prop)) {
46994+ opset->self_ops[op] = NULL;
46995+ } else {
46996+ opset->self_ops[op] = JS_VALUE_GET_PTR(prop);
46997+ }
46998+ }
46999+ }
47000+ JS_FreeValue(ctx, opset_obj);
47001+ return JS_UNDEFINED;
47002+ fail:
47003+ JS_FreeValue(ctx, opset_obj);
47004+ return JS_EXCEPTION;
47005+}
47006+
47007+static int js_operators_set_default(JSContext *ctx, JSValueConst obj)
47008+{
47009+ JSValue opset_obj;
47010+
47011+ if (!JS_IsObject(obj)) /* in case the prototype is not defined */
47012+ return 0;
47013+ opset_obj = js_operators_create_internal(ctx, 0, NULL, TRUE);
47014+ if (JS_IsException(opset_obj))
47015+ return -1;
47016+ /* cannot be modified by the user */
47017+ JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_operatorSet,
47018+ opset_obj, 0);
47019+ return 0;
47020+}
47021+
47022+static JSValue js_dummy_operators_ctor(JSContext *ctx, JSValueConst new_target,
47023+ int argc, JSValueConst *argv)
47024+{
47025+ return js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
47026+}
47027+
47028+static JSValue js_global_operators(JSContext *ctx, JSValueConst this_val,
47029+ int argc, JSValueConst *argv)
47030+{
47031+ JSValue func_obj, proto, opset_obj;
47032+
47033+ func_obj = JS_UNDEFINED;
47034+ proto = JS_NewObject(ctx);
47035+ if (JS_IsException(proto))
47036+ return JS_EXCEPTION;
47037+ opset_obj = js_operators_create_internal(ctx, argc, argv, FALSE);
47038+ if (JS_IsException(opset_obj))
47039+ goto fail;
47040+ JS_DefinePropertyValue(ctx, proto, JS_ATOM_Symbol_operatorSet,
47041+ opset_obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
47042+ func_obj = JS_NewCFunction2(ctx, js_dummy_operators_ctor, "Operators",
47043+ 0, JS_CFUNC_constructor, 0);
47044+ if (JS_IsException(func_obj))
47045+ goto fail;
47046+ JS_SetConstructor2(ctx, func_obj, proto,
47047+ 0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
47048+ JS_FreeValue(ctx, proto);
47049+ return func_obj;
47050+ fail:
47051+ JS_FreeValue(ctx, proto);
47052+ JS_FreeValue(ctx, func_obj);
47053+ return JS_EXCEPTION;
47054+}
47055+
47056+static const JSCFunctionListEntry js_operators_funcs[] = {
47057+ JS_CFUNC_DEF("create", 1, js_operators_create ),
47058+ JS_CFUNC_DEF("updateBigIntOperators", 2, js_operators_updateBigIntOperators ),
47059+};
47060+
47061+/* must be called after all overloadable base types are initialized */
47062+void JS_AddIntrinsicOperators(JSContext *ctx)
47063+{
47064+ JSValue obj;
47065+
47066+ ctx->allow_operator_overloading = TRUE;
47067+ obj = JS_NewCFunction(ctx, js_global_operators, "Operators", 1);
47068+ JS_SetPropertyFunctionList(ctx, obj,
47069+ js_operators_funcs,
47070+ countof(js_operators_funcs));
47071+ JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Operators,
47072+ obj,
47073+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
47074+ /* add default operatorSets */
47075+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BOOLEAN]);
47076+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_NUMBER]);
47077+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_STRING]);
47078+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_INT]);
47079+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]);
47080+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
47081+}
47082+
4708347083 /* BigInt */
4708447084
4708547085 static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
4708647086 {
4708747087 uint32_t tag;
47088− BOOL is_legacy;
47089− int ret;
4709047088
47091− is_legacy = is_bigint_mode(ctx) ^ 1;
4709247089 redo:
4709347090 tag = JS_VALUE_GET_NORM_TAG(val);
4709447091 switch(tag) {
4709547092 case JS_TAG_INT:
4709647093 case JS_TAG_BOOL:
47097− if (is_legacy) {
47098− bf_t r_s, *r = &r_s;
47099− bf_init(ctx->bf_ctx, r);
47100− bf_set_si(r, JS_VALUE_GET_INT(val));
47101− val = JS_NewBigInt2(ctx, r, TRUE);
47102− } else {
47103− val = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
47104− }
47094+ val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
4710547095 break;
4710647096 case JS_TAG_BIG_INT:
4710747097 break;
4710847098 case JS_TAG_FLOAT64:
4710947099 case JS_TAG_BIG_FLOAT:
4711047100 {
47111− bf_t *a, a_s, r_s, *r = &r_s;
47101+ bf_t *a, a_s;
47102+
4711247103 a = JS_ToBigFloat(ctx, &a_s, val);
47113− bf_init(ctx->bf_ctx, r);
4711447104 if (!bf_is_finite(a)) {
4711547105 JS_FreeValue(ctx, val);
4711647106 val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint");
4711747107 } else {
47118− bf_set(r, a);
47119− ret = bf_rint(r, BF_RNDZ);
47108+ JSValue val1 = JS_NewBigInt(ctx);
47109+ bf_t *r;
47110+ int ret;
47111+ if (JS_IsException(val1)) {
47112+ JS_FreeValue(ctx, val);
47113+ return JS_EXCEPTION;
47114+ }
47115+ r = JS_GetBigInt(val1);
47116+ ret = bf_set(r, a);
47117+ ret |= bf_rint(r, BF_RNDZ);
4712047118 JS_FreeValue(ctx, val);
47121− if (is_legacy && (ret & BF_ST_INEXACT)) {
47122− bf_delete(r);
47119+ if (ret & BF_ST_MEM_ERROR) {
47120+ JS_FreeValue(ctx, val1);
47121+ val = JS_ThrowOutOfMemory(ctx);
47122+ } else if (ret & BF_ST_INEXACT) {
47123+ JS_FreeValue(ctx, val1);
4712347124 val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer");
4712447125 } else {
47125− val = JS_NewBigInt2(ctx, r, is_legacy);
47126+ val = JS_CompactBigInt(ctx, val1);
4712647127 }
4712747128 }
4712847129 if (a == &a_s)
4712947130 bf_delete(a);
4713047131 }
4713147132 break;
47133+ case JS_TAG_BIG_DECIMAL:
47134+ val = JS_ToStringFree(ctx, val);
47135+ if (JS_IsException(val))
47136+ break;
47137+ goto redo;
4713247138 case JS_TAG_STRING:
4713347139 val = JS_StringToBigIntErr(ctx, val);
4713447140 break;
4713547141 case JS_TAG_OBJECT:
47136− val = JS_ToPrimitiveFree(ctx, val,
47137− is_legacy ? HINT_NUMBER : HINT_INTEGER);
47142+ val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
4713847143 if (JS_IsException(val))
4713947144 break;
4714047145 goto redo;
@@ -47154,17 +47159,6 @@ static JSValue js_bigint_constructor(JSContext *ctx, · 13 unmodified lines
4715447159 return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
4715547160 }
4715647161
47157−static inline BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)
47158−{
47159− int tag = JS_VALUE_GET_TAG(v);
47160− if (tag == JS_TAG_BIG_INT)
47161− return TRUE;
47162− if (is_bigint_mode(ctx))
47163− return tag == JS_TAG_INT;
47164− else
47165− return FALSE;
47166−}
47167−
4716847162 static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
4716947163 {
4717047164 if (JS_IsBigInt(ctx, this_val))
@@ -47173,8 +47167,6 @@ static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val) · 2 unmodified lines
4717347167 if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
4717447168 JSObject *p = JS_VALUE_GET_OBJ(this_val);
4717547169 if (p->class_id == JS_CLASS_BIG_INT) {
47176− /* XXX: may relax the check in case the object comes from
47177− bignum mode */
4717847170 if (JS_IsBigInt(ctx, p->u.object_data))
4717947171 return JS_DupValue(ctx, p->u.object_data);
4718047172 }
@@ -47195,12 +47187,9 @@ static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val, · 14 unmodified lines
4719547187 if (argc == 0 || JS_IsUndefined(argv[0])) {
4719647188 base = 10;
4719747189 } else {
47198− if (JS_ToInt32Sat(ctx, &base, argv[0]))
47190+ base = js_get_radix(ctx, argv[0]);
47191+ if (base < 0)
4719947192 goto fail;
47200− if (base < 2 || base > 36) {
47201− JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
47202− goto fail;
47203− }
4720447193 }
4720547194 ret = js_bigint_to_string1(ctx, val, base);
4720647195 JS_FreeValue(ctx, val);
@@ -47220,72 +47209,96 @@ static JSValue js_bigint_div(JSContext *ctx, · 13 unmodified lines
4722047209 JSValueConst this_val,
4722147210 int argc, JSValueConst *argv, int magic)
4722247211 {
47223− bf_t a_s, b_s, *a, *b, r_s, *r = &r_s, q_s, *q = &q_s;
47212+ bf_t a_s, b_s, *a, *b, *r, *q;
4722447213 int status;
47225−
47214+ JSValue q_val, r_val;
47215+
47216+ q_val = JS_NewBigInt(ctx);
47217+ if (JS_IsException(q_val))
47218+ return JS_EXCEPTION;
47219+ r_val = JS_NewBigInt(ctx);
47220+ if (JS_IsException(r_val))
47221+ goto fail;
4722647222 b = NULL;
4722747223 a = JS_ToBigInt(ctx, &a_s, argv[0]);
4722847224 if (!a)
47229− return JS_EXCEPTION;
47225+ goto fail;
4723047226 b = JS_ToBigInt(ctx, &b_s, argv[1]);
4723147227 if (!b) {
4723247228 JS_FreeBigInt(ctx, a, &a_s);
47233− return JS_EXCEPTION;
47229+ goto fail;
4723447230 }
47235− bf_init(ctx->bf_ctx, q);
47236− bf_init(ctx->bf_ctx, r);
47231+ q = JS_GetBigInt(q_val);
47232+ r = JS_GetBigInt(r_val);
4723747233 status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf);
4723847234 JS_FreeBigInt(ctx, a, &a_s);
4723947235 JS_FreeBigInt(ctx, b, &b_s);
4724047236 if (unlikely(status)) {
47241− bf_delete(q);
47242− bf_delete(r);
4724347237 throw_bf_exception(ctx, status);
47244− return JS_EXCEPTION;
47238+ goto fail;
4724547239 }
47240+ q_val = JS_CompactBigInt(ctx, q_val);
4724647241 if (magic & 0x10) {
4724747242 JSValue ret;
47248− /* XXX: handle exceptions */
4724947243 ret = JS_NewArray(ctx);
47250− JS_SetPropertyUint32(ctx, ret, 0, JS_NewBigInt(ctx, q));
47251− JS_SetPropertyUint32(ctx, ret, 1, JS_NewBigInt(ctx, r));
47244+ if (JS_IsException(ret))
47245+ goto fail;
47246+ JS_SetPropertyUint32(ctx, ret, 0, q_val);
47247+ JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, r_val));
4725247248 return ret;
4725347249 } else {
47254− bf_delete(r);
47255− return JS_NewBigInt(ctx, q);
47250+ JS_FreeValue(ctx, r_val);
47251+ return q_val;
4725647252 }
47253+ fail:
47254+ JS_FreeValue(ctx, q_val);
47255+ JS_FreeValue(ctx, r_val);
47256+ return JS_EXCEPTION;
4725747257 }
4725847258
4725947259 static JSValue js_bigint_sqrt(JSContext *ctx,
4726047260 JSValueConst this_val,
4726147261 int argc, JSValueConst *argv, int magic)
4726247262 {
47263− bf_t a_s, *a, r_s, *r = &r_s, rem_s, *rem = &rem_s;
47263+ bf_t a_s, *a, *r, *rem;
4726447264 int status;
47265+ JSValue r_val, rem_val;
47266+
47267+ r_val = JS_NewBigInt(ctx);
47268+ if (JS_IsException(r_val))
47269+ return JS_EXCEPTION;
47270+ rem_val = JS_NewBigInt(ctx);
47271+ if (JS_IsException(rem_val))
47272+ return JS_EXCEPTION;
47273+ r = JS_GetBigInt(r_val);
47274+ rem = JS_GetBigInt(rem_val);
4726547275
4726647276 a = JS_ToBigInt(ctx, &a_s, argv[0]);
4726747277 if (!a)
47268− return JS_EXCEPTION;
47269− bf_init(ctx->bf_ctx, r);
47270− bf_init(ctx->bf_ctx, rem);
47278+ goto fail;
4727147279 status = bf_sqrtrem(r, rem, a);
4727247280 JS_FreeBigInt(ctx, a, &a_s);
4727347281 if (unlikely(status & ~BF_ST_INEXACT)) {
47274− bf_delete(r);
47275− bf_delete(rem);
47276− return throw_bf_exception(ctx, status);
47282+ throw_bf_exception(ctx, status);
47283+ goto fail;
4727747284 }
47285+ r_val = JS_CompactBigInt(ctx, r_val);
4727847286 if (magic) {
4727947287 JSValue ret;
47280− /* XXX: handle exceptions */
4728147288 ret = JS_NewArray(ctx);
47282− JS_SetPropertyUint32(ctx, ret, 0, JS_NewBigInt(ctx, r));
47283− JS_SetPropertyUint32(ctx, ret, 1, JS_NewBigInt(ctx, rem));
47289+ if (JS_IsException(ret))
47290+ goto fail;
47291+ JS_SetPropertyUint32(ctx, ret, 0, r_val);
47292+ JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, rem_val));
4728447293 return ret;
4728547294 } else {
47286− bf_delete(rem);
47287− return JS_NewBigInt(ctx, r);
47295+ JS_FreeValue(ctx, rem_val);
47296+ return r_val;
4728847297 }
47298+ fail:
47299+ JS_FreeValue(ctx, r_val);
47300+ JS_FreeValue(ctx, rem_val);
47301+ return JS_EXCEPTION;
4728947302 }
4729047303
4729147304 static JSValue js_bigint_op1(JSContext *ctx,
@@ -47326,15 +47339,22 @@ static JSValue js_bigint_asUintN(JSContext *ctx, · 34 unmodified lines
4732647339 int argc, JSValueConst *argv, int asIntN)
4732747340 {
4732847341 uint64_t bits;
47329− bf_t a_s, *a = &a_s, r_s, *r = &r_s, mask_s, *mask = &mask_s;
47330−
47342+ bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s;
47343+ JSValue res;
47344+
4733147345 if (JS_ToIndex(ctx, &bits, argv[0]))
4733247346 return JS_EXCEPTION;
47347+ res = JS_NewBigInt(ctx);
47348+ if (JS_IsException(res))
47349+ return JS_EXCEPTION;
47350+ r = JS_GetBigInt(res);
4733347351 a = JS_ToBigInt(ctx, &a_s, argv[1]);
47334− if (!a)
47352+ if (!a) {
47353+ JS_FreeValue(ctx, res);
4733547354 return JS_EXCEPTION;
47355+ }
4733647356 /* XXX: optimize */
47337− bf_init(ctx->bf_ctx, r);
47357+ r = JS_GetBigInt(res);
4733847358 bf_init(ctx->bf_ctx, mask);
4733947359 bf_set_ui(mask, 1);
4734047360 bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
@@ -47351,7 +47371,7 @@ static JSValue js_bigint_asUintN(JSContext *ctx, · 10 unmodified lines
4735147371 }
4735247372 bf_delete(mask);
4735347373 JS_FreeBigInt(ctx, a, &a_s);
47354− return JS_NewBigInt(ctx, r);
47374+ return JS_CompactBigInt(ctx, res);
4735547375 }
4735647376
4735747377 static const JSCFunctionListEntry js_bigint_funcs[] = {
@@ -47430,12 +47450,9 @@ static JSValue js_bigfloat_toString(JSContext *ctx, JSValueConst this_val, · 72 unmodified lines
4743047450 if (argc == 0 || JS_IsUndefined(argv[0])) {
4743147451 base = 10;
4743247452 } else {
47433− if (JS_ToInt32Sat(ctx, &base, argv[0]))
47434− goto fail;
47435− if (base < 2 || base > 36) {
47436− JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
47453+ base = js_get_radix(ctx, argv[0]);
47454+ if (base < 0)
4743747455 goto fail;
47438− }
4743947456 }
4744047457 ret = js_ftoa(ctx, val, base, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
4744147458 JS_FreeValue(ctx, val);
@@ -47451,7 +47468,7 @@ static JSValue js_bigfloat_valueOf(JSContext *ctx, JSValueConst this_val, · 9 unmodified lines
4745147468 return js_thisBigFloatValue(ctx, this_val);
4745247469 }
4745347470
47454−static int get_rnd_mode(JSContext *ctx, JSValueConst val)
47471+static int bigfloat_get_rnd_mode(JSContext *ctx, JSValueConst val)
4745547472 {
4745647473 int rnd_mode;
4745747474 if (JS_ToInt32Sat(ctx, &rnd_mode, val))
@@ -47468,8 +47485,7 @@ static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val, · 10 unmodified lines
4746847485 {
4746947486 JSValue val, ret;
4747047487 int64_t f;
47471− int res, rnd_mode;
47472− bf_t a_s, *a, b;
47488+ int rnd_mode, radix;
4747347489
4747447490 val = js_thisBigFloatValue(ctx, this_val);
4747547491 if (JS_IsException(val))
@@ -47481,26 +47497,19 @@ static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val, · 5 unmodified lines
4748147497 goto fail;
4748247498 }
4748347499 rnd_mode = BF_RNDNA;
47500+ radix = 10;
47501+ /* XXX: swap parameter order for rounding mode and radix */
4748447502 if (argc > 1) {
47485− rnd_mode = get_rnd_mode(ctx, argv[1]);
47503+ rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
4748647504 if (rnd_mode < 0)
4748747505 goto fail;
4748847506 }
47489−
47490− a = JS_ToBigFloat(ctx, &a_s, val);
47491− if (!a)
47492− goto fail;
47493− bf_init(ctx->bf_ctx, &b);
47494− bf_set_float64(&b, 1e21);
47495− res = bf_cmpu(a, &b);
47496− bf_delete(&b);
47497− if (a == &a_s)
47498− bf_delete(a);
47499− if (res >= 0) {
47500− ret = JS_ToString(ctx, val);
47501− } else {
47502− ret = js_ftoa(ctx, val, 10, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
47507+ if (argc > 2) {
47508+ radix = js_get_radix(ctx, argv[2]);
47509+ if (radix < 0)
47510+ goto fail;
4750347511 }
47512+ ret = js_ftoa(ctx, val, radix, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
4750447513 JS_FreeValue(ctx, val);
4750547514 return ret;
4750647515 fail:
@@ -47533,7 +47542,7 @@ static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val, · 26 unmodified lines
4753347542 {
4753447543 JSValue val, ret;
4753547544 int64_t f;
47536− int rnd_mode;
47545+ int rnd_mode, radix;
4753747546
4753847547 val = js_thisBigFloatValue(ctx, this_val);
4753947548 if (JS_IsException(val))
@@ -47551,12 +47560,18 @@ static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val, · 11 unmodified lines
4755147560 goto fail;
4755247561 }
4755347562 rnd_mode = BF_RNDNA;
47563+ radix = 10;
4755447564 if (argc > 1) {
47555− rnd_mode = get_rnd_mode(ctx, argv[1]);
47565+ rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
4755647566 if (rnd_mode < 0)
4755747567 goto fail;
4755847568 }
47559− ret = js_ftoa(ctx, val, 10, f + 1,
47569+ if (argc > 2) {
47570+ radix = js_get_radix(ctx, argv[2]);
47571+ if (radix < 0)
47572+ goto fail;
47573+ }
47574+ ret = js_ftoa(ctx, val, radix, f + 1,
4756047575 rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
4756147576 }
4756247577 JS_FreeValue(ctx, val);
@@ -47571,7 +47586,7 @@ static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val, · 8 unmodified lines
4757147586 {
4757247587 JSValue val, ret;
4757347588 int64_t p;
47574− int rnd_mode;
47589+ int rnd_mode, radix;
4757547590
4757647591 val = js_thisBigFloatValue(ctx, this_val);
4757747592 if (JS_IsException(val))
@@ -47589,12 +47604,18 @@ static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val, · 11 unmodified lines
4758947604 goto fail;
4759047605 }
4759147606 rnd_mode = BF_RNDNA;
47607+ radix = 10;
4759247608 if (argc > 1) {
47593− rnd_mode = get_rnd_mode(ctx, argv[1]);
47609+ rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
4759447610 if (rnd_mode < 0)
4759547611 goto fail;
4759647612 }
47597− ret = js_ftoa(ctx, val, 10, p, rnd_mode | BF_FTOA_FORMAT_FIXED);
47613+ if (argc > 2) {
47614+ radix = js_get_radix(ctx, argv[2]);
47615+ if (radix < 0)
47616+ goto fail;
47617+ }
47618+ ret = js_ftoa(ctx, val, radix, p, rnd_mode | BF_FTOA_FORMAT_FIXED);
4759847619 }
4759947620 JS_FreeValue(ctx, val);
4760047621 return ret;
@@ -47617,10 +47638,12 @@ static JSValue js_bigfloat_constructor(JSContext *ctx, · 16 unmodified lines
4761747638 {
4761847639 JSValue val;
4761947640 if (argc == 0) {
47620− bf_t r_s, *r = &r_s;
47621− bf_init(ctx->bf_ctx, r);
47641+ bf_t *r;
47642+ val = JS_NewBigFloat(ctx);
47643+ if (JS_IsException(val))
47644+ return val;
47645+ r = JS_GetBigFloat(val);
4762247646 bf_set_zero(r, 0);
47623− val = JS_NewBigFloat(ctx, r);
4762447647 } else {
4762547648 val = JS_DupValue(ctx, argv[0]);
4762647649 redo:
@@ -47629,18 +47652,26 @@ static JSValue js_bigfloat_constructor(JSContext *ctx, · 2 unmodified lines
4762947652 break;
4763047653 case JS_TAG_FLOAT64:
4763147654 {
47632− bf_t r_s, *r = &r_s;
47633− bf_init(ctx->bf_ctx, r);
47634− bf_set_float64(r, JS_VALUE_GET_FLOAT64(val));
47635− val = JS_NewBigFloat(ctx, r);
47655+ bf_t *r;
47656+ double d = JS_VALUE_GET_FLOAT64(val);
47657+ val = JS_NewBigFloat(ctx);
47658+ if (JS_IsException(val))
47659+ break;
47660+ r = JS_GetBigFloat(val);
47661+ if (bf_set_float64(r, d))
47662+ goto fail;
4763647663 }
4763747664 break;
4763847665 case JS_TAG_INT:
4763947666 {
47640− bf_t r_s, *r = &r_s;
47641− bf_init(ctx->bf_ctx, r);
47642− bf_set_si(r, JS_VALUE_GET_INT(val));
47643− val = JS_NewBigFloat(ctx, r);
47667+ bf_t *r;
47668+ int32_t v = JS_VALUE_GET_INT(val);
47669+ val = JS_NewBigFloat(ctx);
47670+ if (JS_IsException(val))
47671+ break;
47672+ r = JS_GetBigFloat(val);
47673+ if (bf_set_si(r, v))
47674+ goto fail;
4764447675 }
4764547676 break;
4764647677 case JS_TAG_BIG_INT:
@@ -47650,6 +47681,11 @@ static JSValue js_bigfloat_constructor(JSContext *ctx, · 3 unmodified lines
4765047681 val = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
4765147682 }
4765247683 break;
47684+ case JS_TAG_BIG_DECIMAL:
47685+ val = JS_ToStringFree(ctx, val);
47686+ if (JS_IsException(val))
47687+ break;
47688+ goto redo;
4765347689 case JS_TAG_STRING:
4765447690 {
4765547691 const char *str, *p;
@@ -47663,10 +47699,12 @@ static JSValue js_bigfloat_constructor(JSContext *ctx, · 7 unmodified lines
4766347699 p = str;
4766447700 p += skip_spaces(p);
4766547701 if ((p - str) == len) {
47666− bf_t r_s, *r = &r_s;
47667− bf_init(ctx->bf_ctx, r);
47668− bf_set_si(r, 0);
47669− val = JS_NewBigFloat(ctx, r);
47702+ bf_t *r;
47703+ val = JS_NewBigFloat(ctx);
47704+ if (JS_IsException(val))
47705+ break;
47706+ r = JS_GetBigFloat(val);
47707+ bf_set_zero(r, 0);
4767047708 err = 0;
4767147709 } else {
4767247710 val = js_atof(ctx, p, &p, 0, ATOD_ACCEPT_BIN_OCT |
@@ -47699,13 +47737,20 @@ static JSValue js_bigfloat_constructor(JSContext *ctx, · 26 unmodified lines
4769947737 }
4770047738 }
4770147739 return val;
47740+ fail:
47741+ JS_FreeValue(ctx, val);
47742+ return JS_EXCEPTION;
4770247743 }
4770347744
4770447745 static JSValue js_bigfloat_get_const(JSContext *ctx,
47705− JSValueConst this_val, int magic)
47746+ JSValueConst this_val, int magic)
4770647747 {
47707− bf_t r_s, *r = &r_s;
47708− bf_init(ctx->bf_ctx, r);
47748+ bf_t *r;
47749+ JSValue val;
47750+ val = JS_NewBigFloat(ctx);
47751+ if (JS_IsException(val))
47752+ return val;
47753+ r = JS_GetBigFloat(val);
4770947754 switch(magic) {
4771047755 case 0: /* PI */
4771147756 bf_const_pi(r, ctx->fp_env.prec, ctx->fp_env.flags);
@@ -47741,13 +47786,13 @@ static JSValue js_bigfloat_get_const(JSContext *ctx, · 29 unmodified lines
4774147786 default:
4774247787 abort();
4774347788 }
47744− return JS_NewBigFloat(ctx, r);
47789+ return val;
4774547790 }
4774647791
4774747792 static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val,
4774847793 int argc, JSValueConst *argv)
4774947794 {
47750− bf_t a_s, *a = &a_s;
47795+ bf_t *a;
4775147796 const char *str;
4775247797 JSValue ret;
4775347798 int radix;
@@ -47771,10 +47816,13 @@ static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val, · 17 unmodified lines
4777147816 if (!fe)
4777247817 goto fail;
4777347818 }
47774− bf_init(ctx->bf_ctx, a);
47819+ ret = JS_NewBigFloat(ctx);
47820+ if (JS_IsException(ret))
47821+ goto done;
47822+ a = JS_GetBigFloat(ret);
4777547823 /* XXX: use js_atof() */
4777647824 bf_atof(a, str, NULL, radix, fe->prec, fe->flags);
47777− ret = JS_NewBigFloat(ctx, a);
47825+ done:
4777847826 JS_FreeCString(ctx, str);
4777947827 return ret;
4778047828 }
@@ -47800,7 +47848,201 @@ static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val, · 19 unmodified lines
4780047848 if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
4780147849 return JS_FALSE;
4780247850 p = JS_VALUE_GET_PTR(val);
47803− return JS_NewBool(ctx, bf_is_finite(&p->num));
47851+ return JS_NewBool(ctx, bf_is_nan(&p->num));
47852+}
47853+
47854+enum {
47855+ MATH_OP_ABS,
47856+ MATH_OP_FLOOR,
47857+ MATH_OP_CEIL,
47858+ MATH_OP_ROUND,
47859+ MATH_OP_TRUNC,
47860+ MATH_OP_SQRT,
47861+ MATH_OP_FPROUND,
47862+ MATH_OP_ACOS,
47863+ MATH_OP_ASIN,
47864+ MATH_OP_ATAN,
47865+ MATH_OP_ATAN2,
47866+ MATH_OP_COS,
47867+ MATH_OP_EXP,
47868+ MATH_OP_LOG,
47869+ MATH_OP_POW,
47870+ MATH_OP_SIN,
47871+ MATH_OP_TAN,
47872+ MATH_OP_FMOD,
47873+ MATH_OP_REM,
47874+ MATH_OP_SIGN,
47875+
47876+ MATH_OP_ADD,
47877+ MATH_OP_SUB,
47878+ MATH_OP_MUL,
47879+ MATH_OP_DIV,
47880+};
47881+
47882+static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
47883+ int argc, JSValueConst *argv, int magic)
47884+{
47885+ bf_t a_s, *a, *r;
47886+ JSFloatEnv *fe;
47887+ int rnd_mode;
47888+ JSValue op1, res;
47889+
47890+ op1 = JS_ToNumeric(ctx, argv[0]);
47891+ if (JS_IsException(op1))
47892+ return op1;
47893+ a = JS_ToBigFloat(ctx, &a_s, op1);
47894+ fe = &ctx->fp_env;
47895+ if (argc > 1) {
47896+ fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
47897+ if (!fe)
47898+ goto fail;
47899+ }
47900+ res = JS_NewBigFloat(ctx);
47901+ if (JS_IsException(res)) {
47902+ fail:
47903+ if (a == &a_s)
47904+ bf_delete(a);
47905+ JS_FreeValue(ctx, op1);
47906+ return JS_EXCEPTION;
47907+ }
47908+ r = JS_GetBigFloat(res);
47909+ switch (magic) {
47910+ case MATH_OP_ABS:
47911+ bf_set(r, a);
47912+ r->sign = 0;
47913+ break;
47914+ case MATH_OP_FLOOR:
47915+ rnd_mode = BF_RNDD;
47916+ goto rint;
47917+ case MATH_OP_CEIL:
47918+ rnd_mode = BF_RNDU;
47919+ goto rint;
47920+ case MATH_OP_ROUND:
47921+ rnd_mode = BF_RNDNA;
47922+ goto rint;
47923+ case MATH_OP_TRUNC:
47924+ rnd_mode = BF_RNDZ;
47925+ rint:
47926+ bf_set(r, a);
47927+ fe->status |= bf_rint(r, rnd_mode);
47928+ break;
47929+ case MATH_OP_SQRT:
47930+ fe->status |= bf_sqrt(r, a, fe->prec, fe->flags);
47931+ break;
47932+ case MATH_OP_FPROUND:
47933+ bf_set(r, a);
47934+ fe->status |= bf_round(r, fe->prec, fe->flags);
47935+ break;
47936+ case MATH_OP_ACOS:
47937+ fe->status |= bf_acos(r, a, fe->prec, fe->flags);
47938+ break;
47939+ case MATH_OP_ASIN:
47940+ fe->status |= bf_asin(r, a, fe->prec, fe->flags);
47941+ break;
47942+ case MATH_OP_ATAN:
47943+ fe->status |= bf_atan(r, a, fe->prec, fe->flags);
47944+ break;
47945+ case MATH_OP_COS:
47946+ fe->status |= bf_cos(r, a, fe->prec, fe->flags);
47947+ break;
47948+ case MATH_OP_EXP:
47949+ fe->status |= bf_exp(r, a, fe->prec, fe->flags);
47950+ break;
47951+ case MATH_OP_LOG:
47952+ fe->status |= bf_log(r, a, fe->prec, fe->flags);
47953+ break;
47954+ case MATH_OP_SIN:
47955+ fe->status |= bf_sin(r, a, fe->prec, fe->flags);
47956+ break;
47957+ case MATH_OP_TAN:
47958+ fe->status |= bf_tan(r, a, fe->prec, fe->flags);
47959+ break;
47960+ case MATH_OP_SIGN:
47961+ if (bf_is_nan(a) || bf_is_zero(a)) {
47962+ bf_set(r, a);
47963+ } else {
47964+ bf_set_si(r, 1 - 2 * a->sign);
47965+ }
47966+ break;
47967+ default:
47968+ abort();
47969+ }
47970+ if (a == &a_s)
47971+ bf_delete(a);
47972+ JS_FreeValue(ctx, op1);
47973+ return res;
47974+}
47975+
47976+static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
47977+ int argc, JSValueConst *argv, int magic)
47978+{
47979+ bf_t a_s, *a, b_s, *b, r_s, *r = &r_s;
47980+ JSFloatEnv *fe;
47981+ JSValue op1, op2, res;
47982+
47983+ op1 = JS_ToNumeric(ctx, argv[0]);
47984+ if (JS_IsException(op1))
47985+ return op1;
47986+ op2 = JS_ToNumeric(ctx, argv[1]);
47987+ if (JS_IsException(op2)) {
47988+ JS_FreeValue(ctx, op1);
47989+ return op2;
47990+ }
47991+ a = JS_ToBigFloat(ctx, &a_s, op1);
47992+ b = JS_ToBigFloat(ctx, &b_s, op2);
47993+ fe = &ctx->fp_env;
47994+ if (argc > 2) {
47995+ fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
47996+ if (!fe)
47997+ goto fail;
47998+ }
47999+ res = JS_NewBigFloat(ctx);
48000+ if (JS_IsException(res)) {
48001+ fail:
48002+ if (a == &a_s)
48003+ bf_delete(a);
48004+ if (b == &b_s)
48005+ bf_delete(b);
48006+ JS_FreeValue(ctx, op1);
48007+ JS_FreeValue(ctx, op2);
48008+ return JS_EXCEPTION;
48009+ }
48010+ r = JS_GetBigFloat(res);
48011+ switch (magic) {
48012+ case MATH_OP_ATAN2:
48013+ fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags);
48014+ break;
48015+ case MATH_OP_POW:
48016+ fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUIRKS);
48017+ break;
48018+ case MATH_OP_FMOD:
48019+ fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
48020+ break;
48021+ case MATH_OP_REM:
48022+ fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDN);
48023+ break;
48024+ case MATH_OP_ADD:
48025+ fe->status |= bf_add(r, a, b, fe->prec, fe->flags);
48026+ break;
48027+ case MATH_OP_SUB:
48028+ fe->status |= bf_sub(r, a, b, fe->prec, fe->flags);
48029+ break;
48030+ case MATH_OP_MUL:
48031+ fe->status |= bf_mul(r, a, b, fe->prec, fe->flags);
48032+ break;
48033+ case MATH_OP_DIV:
48034+ fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
48035+ break;
48036+ default:
48037+ abort();
48038+ }
48039+ if (a == &a_s)
48040+ bf_delete(a);
48041+ if (b == &b_s)
48042+ bf_delete(b);
48043+ JS_FreeValue(ctx, op1);
48044+ JS_FreeValue(ctx, op2);
48045+ return res;
4780448046 }
4780548047
4780648048 static const JSCFunctionListEntry js_bigfloat_funcs[] = {
@@ -47895,9 +48137,6 @@ static JSValue js_float_env_get_expBits(JSContext *ctx, JSValueConst this_val) · 88 unmodified lines
4789548137 return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags));
4789648138 }
4789748139
47898−/* temporary fix for string conversion overflows */
47899−#define BF_EXP_BITS_MAX1 (BF_EXP_BITS_MAX - 1)
47900−
4790148140 static JSValue js_float_env_setPrec(JSContext *ctx,
4790248141 JSValueConst this_val,
4790348142 int argc, JSValueConst *argv)
@@ -47913,18 +48152,16 @@ static JSValue js_float_env_setPrec(JSContext *ctx, · 9 unmodified lines
4791348152 return JS_EXCEPTION;
4791448153 if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
4791548154 return JS_ThrowRangeError(ctx, "invalid precision");
47916− exp_bits = BF_EXP_BITS_MAX1;
48155+ exp_bits = BF_EXP_BITS_MAX;
4791748156
4791848157 if (argc > 2 && !JS_IsUndefined(argv[2])) {
4791948158 if (JS_ToInt32Sat(ctx, &exp_bits, argv[2]))
4792048159 return JS_EXCEPTION;
47921− if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX1)
48160+ if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX)
4792248161 return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
4792348162 }
4792448163
47925− flags = BF_RNDN | bf_set_exp_bits(exp_bits);
47926− if (exp_bits != BF_EXP_BITS_MAX1)
47927− flags |= BF_FLAG_SUBNORMAL;
48164+ flags = BF_RNDN | BF_FLAG_SUBNORMAL | bf_set_exp_bits(exp_bits);
4792848165
4792948166 saved_prec = ctx->fp_env.prec;
4793048167 saved_flags = ctx->fp_env.flags;
@@ -47984,24 +48221,20 @@ static JSValue js_float_env_proto_set_status(JSContext *ctx, JSValueConst this_v · 53 unmodified lines
4798448221 case FE_EXP:
4798548222 if (JS_ToInt32Sat(ctx, &b, val))
4798648223 return JS_EXCEPTION;
47987− if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX1)
48224+ if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX)
4798848225 return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
47989− if (b == BF_EXP_BITS_MAX1)
47990− fe->flags &= ~BF_FLAG_SUBNORMAL;
4799148226 fe->flags = (fe->flags & ~(BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)) |
4799248227 bf_set_exp_bits(b);
4799348228 break;
4799448229 case FE_RNDMODE:
47995− b = get_rnd_mode(ctx, val);
48230+ b = bigfloat_get_rnd_mode(ctx, val);
4799648231 if (b < 0)
4799748232 return JS_EXCEPTION;
4799848233 fe->flags = (fe->flags & ~BF_RND_MASK) | b;
4799948234 break;
4800048235 case FE_SUBNORMAL:
4800148236 b = JS_ToBool(ctx, val);
48002− if (bf_get_exp_bits(fe->flags) != BF_EXP_BITS_MAX1) {
48003− fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0);
48004− }
48237+ fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0);
4800548238 break;
4800648239 default:
4800748240 b = JS_ToBool(ctx, val);
@@ -48031,12 +48264,12 @@ static const JSCFunctionListEntry js_float_env_funcs[] = { · 23 unmodified lines
4803148264 JS_PROP_INT32_DEF("RNDU", BF_RNDU, 0 ),
4803248265 JS_PROP_INT32_DEF("RNDD", BF_RNDD, 0 ),
4803348266 JS_PROP_INT32_DEF("RNDNA", BF_RNDNA, 0 ),
48034− JS_PROP_INT32_DEF("RNDNU", BF_RNDNU, 0 ),
48267+ JS_PROP_INT32_DEF("RNDA", BF_RNDA, 0 ),
4803548268 JS_PROP_INT32_DEF("RNDF", BF_RNDF, 0 ),
4803648269 JS_PROP_INT32_DEF("precMin", BF_PREC_MIN, 0 ),
4803748270 JS_PROP_INT64_DEF("precMax", BF_PREC_MAX, 0 ),
4803848271 JS_PROP_INT32_DEF("expBitsMin", BF_EXP_BITS_MIN, 0 ),
48039− JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX1, 0 ),
48272+ JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX, 0 ),
4804048273 };
4804148274
4804248275 static const JSCFunctionListEntry js_float_env_proto_funcs[] = {
@@ -48112,10 +48345,18 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, · 69 unmodified lines
4811248345 case JS_TAG_BOOL:
4811348346 case JS_TAG_INT:
4811448347 {
48115− bfdec_t r_s, *r = &r_s;
48116− bfdec_init(ctx->bf_ctx, r);
48117− bfdec_set_si(r, JS_VALUE_GET_INT(val));
48118− val = JS_NewBigDecimal(ctx, r);
48348+ bfdec_t *r;
48349+ int32_t v = JS_VALUE_GET_INT(val);
48350+
48351+ val = JS_NewBigDecimal(ctx);
48352+ if (JS_IsException(val))
48353+ break;
48354+ r = JS_GetBigDecimal(val);
48355+ if (bfdec_set_si(r, v)) {
48356+ JS_FreeValue(ctx, val);
48357+ val = JS_EXCEPTION;
48358+ break;
48359+ }
4811948360 }
4812048361 break;
4812148362 case JS_TAG_FLOAT64:
@@ -48138,10 +48379,12 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, · 16 unmodified lines
4813848379 p = str;
4813948380 p += skip_spaces(p);
4814048381 if ((p - str) == len) {
48141− bfdec_t r_s, *r = &r_s;
48142− bfdec_init(ctx->bf_ctx, r);
48382+ bfdec_t *r;
48383+ val = JS_NewBigDecimal(ctx);
48384+ if (JS_IsException(val))
48385+ break;
48386+ r = JS_GetBigDecimal(val);
4814348387 bfdec_set_zero(r, 0);
48144− val = JS_NewBigDecimal(ctx, r);
4814548388 err = 0;
4814648389 } else {
4814748390 val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL);
@@ -48166,12 +48409,14 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, · 18 unmodified lines
4816648409 goto redo;
4816748410 case JS_TAG_UNDEFINED:
4816848411 {
48169− bfdec_t r_s, *r = &r_s;
48412+ bfdec_t *r;
4817048413 if (!allow_null_or_undefined)
4817148414 goto fail;
48172− bfdec_init(ctx->bf_ctx, r);
48415+ val = JS_NewBigDecimal(ctx);
48416+ if (JS_IsException(val))
48417+ break;
48418+ r = JS_GetBigDecimal(val);
4817348419 bfdec_set_nan(r);
48174− val = JS_NewBigDecimal(ctx, r);
4817548420 }
4817648421 break;
4817748422 default:
@@ -48188,10 +48433,12 @@ static JSValue js_bigdecimal_constructor(JSContext *ctx, · 10 unmodified lines
4818848433 {
4818948434 JSValue val;
4819048435 if (argc == 0) {
48191− bfdec_t r_s, *r = &r_s;
48192− bfdec_init(ctx->bf_ctx, r);
48436+ bfdec_t *r;
48437+ val = JS_NewBigDecimal(ctx);
48438+ if (JS_IsException(val))
48439+ return val;
48440+ r = JS_GetBigDecimal(val);
4819348441 bfdec_set_zero(r, 0);
48194− val = JS_NewBigDecimal(ctx, r);
4819548442 } else {
4819648443 val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE);
4819748444 }
@@ -48230,6 +48477,39 @@ static JSValue js_bigdecimal_valueOf(JSContext *ctx, JSValueConst this_val, · 32 unmodified lines
4823048477 return js_thisBigDecimalValue(ctx, this_val);
4823148478 }
4823248479
48480+static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj)
48481+{
48482+ const char *str;
48483+ size_t size;
48484+ int rnd_mode;
48485+
48486+ str = JS_ToCStringLen(ctx, &size, obj);
48487+ if (!str)
48488+ return -1;
48489+ if (strlen(str) != size)
48490+ goto invalid_rounding_mode;
48491+ if (!strcmp(str, "floor")) {
48492+ rnd_mode = BF_RNDD;
48493+ } else if (!strcmp(str, "ceiling")) {
48494+ rnd_mode = BF_RNDU;
48495+ } else if (!strcmp(str, "down")) {
48496+ rnd_mode = BF_RNDZ;
48497+ } else if (!strcmp(str, "up")) {
48498+ rnd_mode = BF_RNDA;
48499+ } else if (!strcmp(str, "half-even")) {
48500+ rnd_mode = BF_RNDN;
48501+ } else if (!strcmp(str, "half-up")) {
48502+ rnd_mode = BF_RNDNA;
48503+ } else {
48504+ invalid_rounding_mode:
48505+ JS_FreeCString(ctx, str);
48506+ JS_ThrowTypeError(ctx, "invalid rounding mode");
48507+ return -1;
48508+ }
48509+ JS_FreeCString(ctx, str);
48510+ return rnd_mode;
48511+}
48512+
4823348513 typedef struct {
4823448514 int64_t prec;
4823548515 bf_flags_t flags;
@@ -48239,10 +48519,9 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, · 3 unmodified lines
4823948519 JSValueConst obj)
4824048520 {
4824148521 JSValue prop;
48242− const char *str;
48243− size_t size;
4824448522 int64_t val;
4824548523 BOOL has_prec;
48524+ int rnd_mode;
4824648525
4824748526 if (!JS_IsObject(obj)) {
4824848527 JS_ThrowTypeErrorNotAnObject(ctx);
@@ -48251,29 +48530,11 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, · 2 unmodified lines
4825148530 prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode);
4825248531 if (JS_IsException(prop))
4825348532 return -1;
48254− str = JS_ToCStringLen(ctx, &size, prop);
48533+ rnd_mode = js_bigdecimal_get_rnd_mode(ctx, prop);
4825548534 JS_FreeValue(ctx, prop);
48256− if (!str)
48257− return -1;
48258− if (strlen(str) != size)
48259− goto invalid_rounding_mode;
48260− if (!strcmp(str, "floor")) {
48261− fe->flags = BF_RNDD;
48262− } else if (!strcmp(str, "ceiling")) {
48263− fe->flags = BF_RNDU;
48264− } else if (!strcmp(str, "down")) {
48265− fe->flags = BF_RNDZ;
48266− } else if (!strcmp(str, "half-even")) {
48267− fe->flags = BF_RNDN;
48268− } else if (!strcmp(str, "half-up")) {
48269− fe->flags = BF_RNDNA;
48270− } else {
48271− invalid_rounding_mode:
48272− JS_FreeCString(ctx, str);
48273− JS_ThrowTypeError(ctx, "invalid rounding mode");
48535+ if (rnd_mode < 0)
4827448536 return -1;
48275− }
48276− JS_FreeCString(ctx, str);
48537+ fe->flags = rnd_mode;
4827748538
4827848539 prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits);
4827948540 if (JS_IsException(prop))
@@ -48282,7 +48543,7 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, · 2 unmodified lines
4828248543 if (!JS_IsUndefined(prop)) {
4828348544 if (JS_ToInt64SatFree(ctx, &val, prop))
4828448545 return -1;
48285− if (val < 0 || val > BF_PREC_MAX)
48546+ if (val < 1 || val > BF_PREC_MAX)
4828648547 goto invalid_precision;
4828748548 fe->prec = val;
4828848549 has_prec = TRUE;
@@ -48320,7 +48581,7 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, · 31 unmodified lines
4832048581 int argc, JSValueConst *argv, int magic)
4832148582 {
4832248583 bfdec_t *a, *b, r_s, *r = &r_s;
48323− JSValue op1, op2;
48584+ JSValue op1, op2, res;
4832448585 BigDecimalEnv fe_s, *fe = &fe_s;
4832548586 int op_count, ret;
4832648587
@@ -48354,21 +48615,18 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, · 27 unmodified lines
4835448615 fe->flags = BF_RNDZ;
4835548616 fe->prec = BF_PREC_INF;
4835648617 if (op_count < argc) {
48357− if (js_bigdecimal_get_env(ctx, fe, argv[op_count])) {
48358− fail:
48359− JS_FreeValue(ctx, op1);
48360− JS_FreeValue(ctx, op2);
48361− return JS_EXCEPTION;
48362− }
48363− if ((fe->flags & BF_FLAG_RADPNT_PREC) &&
48364− magic != MATH_OP_DIV &&
48365− magic != MATH_OP_ROUND) {
48366− JS_ThrowTypeError(ctx, "maximumFractionDigits is not supported for this operation");
48618+ if (js_bigdecimal_get_env(ctx, fe, argv[op_count]))
4836748619 goto fail;
48368− }
4836948620 }
4837048621
48371− bfdec_init(ctx->bf_ctx, r);
48622+ res = JS_NewBigDecimal(ctx);
48623+ if (JS_IsException(res)) {
48624+ fail:
48625+ JS_FreeValue(ctx, op1);
48626+ JS_FreeValue(ctx, op2);
48627+ return JS_EXCEPTION;
48628+ }
48629+ r = JS_GetBigDecimal(res);
4837248630 switch (magic) {
4837348631 case MATH_OP_ADD:
4837448632 ret = bfdec_add(r, a, b, fe->prec, fe->flags);
@@ -48382,6 +48640,9 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, · 7 unmodified lines
4838248640 case MATH_OP_DIV:
4838348641 ret = bfdec_div(r, a, b, fe->prec, fe->flags);
4838448642 break;
48643+ case MATH_OP_FMOD:
48644+ ret = bfdec_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
48645+ break;
4838548646 case MATH_OP_SQRT:
4838648647 ret = bfdec_sqrt(r, a, fe->prec, fe->flags);
4838748648 break;
@@ -48398,16 +48659,119 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, · 10 unmodified lines
4839848659 ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP |
4839948660 BF_ST_OVERFLOW;
4840048661 if (ret != 0) {
48401− bfdec_delete(r);
48662+ JS_FreeValue(ctx, res);
4840248663 return throw_bf_exception(ctx, ret);
4840348664 } else {
48404− return JS_NewBigDecimal(ctx, r);
48665+ return res;
48666+ }
48667+}
48668+
48669+static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val,
48670+ int argc, JSValueConst *argv)
48671+{
48672+ JSValue val, ret;
48673+ int64_t f;
48674+ int rnd_mode;
48675+
48676+ val = js_thisBigDecimalValue(ctx, this_val);
48677+ if (JS_IsException(val))
48678+ return val;
48679+ if (JS_ToInt64Sat(ctx, &f, argv[0]))
48680+ goto fail;
48681+ if (f < 0 || f > BF_PREC_MAX) {
48682+ JS_ThrowRangeError(ctx, "invalid number of digits");
48683+ goto fail;
48684+ }
48685+ rnd_mode = BF_RNDNA;
48686+ if (argc > 1) {
48687+ rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
48688+ if (rnd_mode < 0)
48689+ goto fail;
48690+ }
48691+ ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
48692+ JS_FreeValue(ctx, val);
48693+ return ret;
48694+ fail:
48695+ JS_FreeValue(ctx, val);
48696+ return JS_EXCEPTION;
48697+}
48698+
48699+static JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val,
48700+ int argc, JSValueConst *argv)
48701+{
48702+ JSValue val, ret;
48703+ int64_t f;
48704+ int rnd_mode;
48705+
48706+ val = js_thisBigDecimalValue(ctx, this_val);
48707+ if (JS_IsException(val))
48708+ return val;
48709+ if (JS_ToInt64Sat(ctx, &f, argv[0]))
48710+ goto fail;
48711+ if (JS_IsUndefined(argv[0])) {
48712+ ret = js_bigdecimal_to_string1(ctx, val, 0,
48713+ BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
48714+ } else {
48715+ if (f < 0 || f > BF_PREC_MAX) {
48716+ JS_ThrowRangeError(ctx, "invalid number of digits");
48717+ goto fail;
48718+ }
48719+ rnd_mode = BF_RNDNA;
48720+ if (argc > 1) {
48721+ rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
48722+ if (rnd_mode < 0)
48723+ goto fail;
48724+ }
48725+ ret = js_bigdecimal_to_string1(ctx, val, f + 1,
48726+ rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
48727+ }
48728+ JS_FreeValue(ctx, val);
48729+ return ret;
48730+ fail:
48731+ JS_FreeValue(ctx, val);
48732+ return JS_EXCEPTION;
48733+}
48734+
48735+static JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val,
48736+ int argc, JSValueConst *argv)
48737+{
48738+ JSValue val, ret;
48739+ int64_t p;
48740+ int rnd_mode;
48741+
48742+ val = js_thisBigDecimalValue(ctx, this_val);
48743+ if (JS_IsException(val))
48744+ return val;
48745+ if (JS_IsUndefined(argv[0])) {
48746+ return JS_ToStringFree(ctx, val);
48747+ }
48748+ if (JS_ToInt64Sat(ctx, &p, argv[0]))
48749+ goto fail;
48750+ if (p < 1 || p > BF_PREC_MAX) {
48751+ JS_ThrowRangeError(ctx, "invalid number of digits");
48752+ goto fail;
48753+ }
48754+ rnd_mode = BF_RNDNA;
48755+ if (argc > 1) {
48756+ rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
48757+ if (rnd_mode < 0)
48758+ goto fail;
4840548759 }
48760+ ret = js_bigdecimal_to_string1(ctx, val, p,
48761+ rnd_mode | BF_FTOA_FORMAT_FIXED);
48762+ JS_FreeValue(ctx, val);
48763+ return ret;
48764+ fail:
48765+ JS_FreeValue(ctx, val);
48766+ return JS_EXCEPTION;
4840648767 }
4840748768
4840848769 static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = {
4840948770 JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ),
4841048771 JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ),
48772+ JS_CFUNC_DEF("toPrecision", 1, js_bigdecimal_toPrecision ),
48773+ JS_CFUNC_DEF("toFixed", 1, js_bigdecimal_toFixed ),
48774+ JS_CFUNC_DEF("toExponential", 1, js_bigdecimal_toExponential ),
4841148775 };
4841248776
4841348777 static const JSCFunctionListEntry js_bigdecimal_funcs[] = {
@@ -48415,6 +48779,7 @@ static const JSCFunctionListEntry js_bigdecimal_funcs[] = { · 1 unmodified line
4841548779 JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ),
4841648780 JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ),
4841748781 JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ),
48782+ JS_CFUNC_MAGIC_DEF("mod", 2, js_bigdecimal_fop, MATH_OP_FMOD ),
4841848783 JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ),
4841948784 JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ),
4842048785 };
@@ -49512,6 +49877,8 @@ static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val, · 1091 unmodified lines
4951249877 count = min_int(final - from, len - to);
4951349878 if (count > 0) {
4951449879 p = JS_VALUE_GET_OBJ(this_val);
49880+ if (typed_array_is_detached(ctx, p))
49881+ return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
4951549882 shift = typed_array_size_log2(p->class_id);
4951649883 memmove(p->u.array.u.uint8_ptr + (to << shift),
4951749884 p->u.array.u.uint8_ptr + (from << shift),
@@ -49579,6 +49946,9 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, · 61 unmodified lines
4957949946 return JS_EXCEPTION;
4958049947 }
4958149948
49949+ if (typed_array_is_detached(ctx, p))
49950+ return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
49951+
4958249952 shift = typed_array_size_log2(p->class_id);
4958349953 switch(shift) {
4958449954 case 0:
quickjs.h+11−5
@@ -53,7 +53,7 @@ typedef struct JSClass JSClass; · 52 unmodified lines
5353 typedef uint32_t JSClassID;
5454 typedef uint32_t JSAtom;
5555
56−#if defined(__x86_64__) || defined(__aarch64__)
56+#if INTPTR_MAX >= INT64_MAX
5757 #define JS_PTR64
5858 #define JS_PTR64_DEF(a) a
5959 #else
@@ -366,7 +366,9 @@ void JS_AddIntrinsicPromise(JSContext *ctx); · 306 unmodified lines
366366 void JS_AddIntrinsicBigInt(JSContext *ctx);
367367 void JS_AddIntrinsicBigFloat(JSContext *ctx);
368368 void JS_AddIntrinsicBigDecimal(JSContext *ctx);
369−/* enable "use bigint", "use math" and operator overloading */
369+/* enable operator overloading */
370+void JS_AddIntrinsicOperators(JSContext *ctx);
371+/* enable "use math" */
370372 void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable);
371373
372374 JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
@@ -531,12 +533,16 @@ static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d) · 158 unmodified lines
531533 return v;
532534 }
533535
534−JS_BOOL JS_IsNumber(JSValueConst v);
536+static inline JS_BOOL JS_IsNumber(JSValueConst v)
537+{
538+ int tag = JS_VALUE_GET_TAG(v);
539+ return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);
540+}
535541
536−static inline JS_BOOL JS_IsInteger(JSValueConst v)
542+static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)
537543 {
538544 int tag = JS_VALUE_GET_TAG(v);
539− return tag == JS_TAG_INT || tag == JS_TAG_BIG_INT;
545+ return tag == JS_TAG_BIG_INT;
540546 }
541547
542548 static inline JS_BOOL JS_IsBigFloat(JSValueConst v)
repl.js+6−28
@@ -1,8 +1,8 @@
11 /*
22 * QuickJS Read Eval Print Loop
33 *
4− * Copyright (c) 2017-2019 Fabrice Bellard
5− * Copyright (c) 2017-2019 Charlie Gordon
4+ * Copyright (c) 2017-2020 Fabrice Bellard
5+ * Copyright (c) 2017-2020 Charlie Gordon
66 *
77 * Permission is hereby granted, free of charge, to any person obtaining a copy
88 * of this software and associated documentation files (the "Software"), to deal
@@ -860,18 +860,6 @@ import * as os from "os"; · 851 unmodified lines
860860 var hex_mode = false;
861861 var eval_mode = "std";
862862
863− function bignum_typeof(a) {
864− "use bigint";
865− return typeof a;
866− }
867−
868− function eval_mode_typeof(a) {
869− if (eval_mode === "std")
870− return typeof a;
871− else
872− return bignum_typeof(a);
873− }
874−
875863 function number_to_string(a, radix) {
876864 var s;
877865 if (!isFinite(a)) {
@@ -897,13 +885,6 @@ import * as os from "os"; · 19 unmodified lines
897885 s = a.toString();
898886 }
899887 }
900− if (eval_mode !== "std" && s.indexOf(".") < 0 &&
901− ((radix == 16 && s.indexOf("p") < 0) ||
902− (radix == 10 && s.indexOf("e") < 0))) {
903− /* add a decimal point so that the floating point type
904− is visible */
905− s += ".0";
906− }
907888 return s;
908889 }
909890 }
@@ -975,7 +956,7 @@ import * as os from "os"; · 65 unmodified lines
975956 function print_rec(a) {
976957 var n, i, keys, key, type, s;
977958
978− type = eval_mode_typeof(a);
959+ type = typeof(a);
979960 if (type === "object") {
980961 if (a === null) {
981962 std.puts(a);
@@ -1037,7 +1018,7 @@ import * as os from "os"; · 55 unmodified lines
10371018 } else if (type === "bigfloat") {
10381019 std.puts(bigfloat_to_string(a, hex_mode ? 16 : 10));
10391020 } else if (type === "bigdecimal") {
1040− std.puts(a.toString() + "d");
1021+ std.puts(a.toString() + "m");
10411022 } else if (type === "symbol") {
10421023 std.puts(String(a));
10431024 } else if (type === "function") {
@@ -1133,8 +1114,7 @@ import * as os from "os"; · 89 unmodified lines
11331114 param = expr.substring(cmd.length + 1).trim();
11341115 if (param === "") {
11351116 std.puts("Running mode=" + eval_mode + "\n");
1136− } else if (param === "std" || param === "math" ||
1137− param === "bigint") {
1117+ } else if (param === "std" || param === "math") {
11381118 eval_mode = param;
11391119 } else {
11401120 std.puts("Invalid mode\n");
@@ -1192,7 +1172,7 @@ import * as os from "os"; · 51 unmodified lines
11921172 std.puts("\\p [m [e]] set the BigFloat precision to 'm' bits\n" +
11931173 "\\digits n set the BigFloat precision to 'ceil(n*log2(10))' bits\n");
11941174 if (!has_jscalc) {
1195− std.puts("\\mode [std|bigint|math] change the running mode (current = " + eval_mode + ")\n");
1175+ std.puts("\\mode [std|math] change the running mode (current = " + eval_mode + ")\n");
11961176 }
11971177 }
11981178 if (!config_numcalc) {
@@ -1206,8 +1186,6 @@ import * as os from "os"; · 7 unmodified lines
12061186 try {
12071187 if (eval_mode === "math")
12081188 expr = '"use math"; void 0;' + expr;
1209− else if (eval_mode === "bigint")
1210− expr = '"use bigint"; void 0;' + expr;
12111189 var now = (new Date).getTime();
12121190 /* eval as a script */
12131191 result = std.evalScript(expr, { backtrace_barrier: true });
test262_errors.txt+13−0
@@ -1,4 +1,17 @@
1+test262/test/language/expressions/arrow-function/eval-var-scope-syntax-err.js:47: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
2+test262/test/language/expressions/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
3+test262/test/language/expressions/async-generator/named-eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
4+test262/test/language/expressions/class/super-evaluation-order.js:26: Test262Error: via ArgumentListEvaluation Expected SameValue(«0», «123») to be true
5+test262/test/language/expressions/class/super-evaluation-order.js:26: strict mode: Test262Error: via ArgumentListEvaluation Expected SameValue(«0», «123») to be true
16 test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
27 test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
8+test262/test/language/expressions/function/eval-var-scope-syntax-err.js:48: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
9+test262/test/language/expressions/generators/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
10+test262/test/language/expressions/object/method-definition/async-gen-meth-eval-var-scope-syntax-err.js:32: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
11+test262/test/language/expressions/object/method-definition/gen-meth-eval-var-scope-syntax-err.js:54: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
12+test262/test/language/expressions/object/method-definition/meth-eval-var-scope-syntax-err.js:50: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
313 test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: value has no property
414 test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: value has no property
15+test262/test/language/statements/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
16+test262/test/language/statements/function/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
17+test262/test/language/statements/generators/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
tests/test_bignum.js+125−40
@@ -171,67 +171,152 @@ function test_bigfloat() · 170 unmodified lines
171171 e = new BigFloatEnv(128);
172172 assert(e.prec == 128);
173173 a = BigFloat.sqrt(2l, e);
174− assert(a == BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));
174+ assert(a === BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));
175175 assert(e.inexact === true);
176176 assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcc908b2fb1366ea95l);
177177
178178 b = BigFloatEnv.setPrec(BigFloat.sqrt.bind(null, 2), 128);
179− assert(a == b);
179+ assert(a === b);
180+
181+ assert(BigFloat.isNaN(BigFloat(NaN)));
182+ assert(BigFloat.isFinite(1l));
183+ assert(!BigFloat.isFinite(1l/0l));
184+
185+ assert(BigFloat.abs(-3l) === 3l);
186+ assert(BigFloat.sign(-3l) === -1l);
187+
188+ assert(BigFloat.exp(0.2l) === 1.2214027581601698339210719946396742l);
189+ assert(BigFloat.log(3l) === 1.0986122886681096913952452369225256l);
190+ assert(BigFloat.pow(2.1l, 1.6l) === 3.277561666451861947162828744873745l);
191+
192+ assert(BigFloat.sin(-1l) === -0.841470984807896506652502321630299l);
193+ assert(BigFloat.cos(1l) === 0.5403023058681397174009366074429766l);
194+ assert(BigFloat.tan(0.1l) === 0.10033467208545054505808004578111154l);
195+
196+ assert(BigFloat.asin(0.3l) === 0.30469265401539750797200296122752915l);
197+ assert(BigFloat.acos(0.4l) === 1.1592794807274085998465837940224159l);
198+ assert(BigFloat.atan(0.7l) === 0.610725964389208616543758876490236l);
199+ assert(BigFloat.atan2(7.1l, -5.1l) === 2.1937053809751415549388104628759813l);
200+
201+ assert(BigFloat.floor(2.5l) === 2l);
202+ assert(BigFloat.ceil(2.5l) === 3l);
203+ assert(BigFloat.trunc(-2.5l) === -2l);
204+ assert(BigFloat.round(2.5l) === 3l);
205+
206+ assert(BigFloat.fmod(3l,2l) === 1l);
207+ assert(BigFloat.remainder(3l,2l) === -1l);
208+
209+ /* string conversion */
210+ assert((1234.125l).toString(), "1234.125");
211+ assert((1234.125l).toFixed(2), "1234.13");
212+ assert((1234.125l).toFixed(2, "down"), "1234.12");
213+ assert((1234.125l).toExponential(), "1.234125e+3");
214+ assert((1234.125l).toExponential(5), "1.23413e+3");
215+ assert((1234.125l).toExponential(5, BigFloatEnv.RNDZ), "1.23412e+3");
216+ assert((1234.125l).toPrecision(6), "1234.13");
217+ assert((1234.125l).toPrecision(6, BigFloatEnv.RNDZ), "1234.12");
218+
219+ /* string conversion with binary base */
220+ assert((0x123.438l).toString(16), "123.438");
221+ assert((0x323.438l).toString(16), "323.438");
222+ assert((0x723.438l).toString(16), "723.438");
223+ assert((0xf23.438l).toString(16), "f23.438");
224+ assert((0x123.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "123.44");
225+ assert((0x323.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "323.44");
226+ assert((0x723.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "723.44");
227+ assert((0xf23.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "f23.44");
228+ assert((0x0.0000438l).toFixed(6, BigFloatEnv.RNDNA, 16), "0.000044");
229+ assert((0x1230000000l).toFixed(1, BigFloatEnv.RNDNA, 16), "1230000000.0");
230+ assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "123.44");
231+ assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDZ, 16), "123.43");
232+ assert((0x323.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "323.44");
233+ assert((0x723.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "723.44");
234+ assert((-0xf23.438l).toPrecision(5, BigFloatEnv.RNDD, 16), "-f23.44");
235+ assert((0x123.438l).toExponential(4, BigFloatEnv.RNDNA, 16), "1.2344p+8");
180236 }
181237
182238 function test_bigdecimal()
183239 {
184− assert(1d === 1d);
185− assert(1d !== 2d);
186− test_less(1d, 2d);
187− test_eq(2d, 2d);
240+ assert(1m === 1m);
241+ assert(1m !== 2m);
242+ test_less(1m, 2m);
243+ test_eq(2m, 2m);
188244
189− test_less(1, 2d);
190− test_eq(2, 2d);
245+ test_less(1, 2m);
246+ test_eq(2, 2m);
191247
192− test_less(1.1, 2d);
193− test_eq(Math.sqrt(4), 2d);
248+ test_less(1.1, 2m);
249+ test_eq(Math.sqrt(4), 2m);
194250
195− test_less(2n, 3d);
196− test_eq(3n, 3d);
251+ test_less(2n, 3m);
252+ test_eq(3n, 3m);
197253
198− assert(BigDecimal("1234.1") === 1234.1d);
199− assert(BigDecimal(" 1234.1") === 1234.1d);
200− assert(BigDecimal(" 1234.1 ") === 1234.1d);
201−
202− assert(BigDecimal(0.1) === 0.1d);
203− assert(BigDecimal(123) === 123d);
204− assert(BigDecimal(true) === 1d);
254+ assert(BigDecimal("1234.1") === 1234.1m);
255+ assert(BigDecimal(" 1234.1") === 1234.1m);
256+ assert(BigDecimal(" 1234.1 ") === 1234.1m);
205257
206− assert(123d + 1d === 124d);
207− assert(123d - 1d === 122d);
258+ assert(BigDecimal(0.1) === 0.1m);
259+ assert(BigDecimal(123) === 123m);
260+ assert(BigDecimal(true) === 1m);
208261
209− assert(3.2d * 3d === 9.6d);
210− assert(10d / 2d === 5d);
211− assertThrows(RangeError, () => { 10d / 3d } );
212− assert(BigDecimal.div(20d, 3d,
213− { roundingMode: "half-even",
214− maximumSignificantDigits: 3 }) === 6.67d);
215− assert(BigDecimal.div(20d, 3d,
216− { roundingMode: "half-even",
217− maximumFractionDigits: 3 }) === 6.667d);
262+ assert(123m + 1m === 124m);
263+ assert(123m - 1m === 122m);
218264
219− assert(10d % 3d === 1d);
220− assert(-10d % 3d === -1d);
265+ assert(3.2m * 3m === 9.6m);
266+ assert(10m / 2m === 5m);
267+ assertThrows(RangeError, () => { 10m / 3m } );
221268
222− assert(-10d % 3d === -1d);
269+ assert(10m % 3m === 1m);
270+ assert(-10m % 3m === -1m);
223271
224− assert(1234.5d ** 3d === 1881365963.625d);
225− assertThrows(RangeError, () => { 2d ** 3.1d } );
226− assertThrows(RangeError, () => { 2d ** -3d } );
272+ assert(1234.5m ** 3m === 1881365963.625m);
273+ assertThrows(RangeError, () => { 2m ** 3.1m } );
274+ assertThrows(RangeError, () => { 2m ** -3m } );
227275
228− assert(BigDecimal.sqrt(2d,
276+ assert(BigDecimal.sqrt(2m,
277+ { roundingMode: "half-even",
278+ maximumSignificantDigits: 4 }) === 1.414m);
279+ assert(BigDecimal.sqrt(101m,
229280 { roundingMode: "half-even",
230− maximumSignificantDigits: 4 }) === 1.414d);
281+ maximumFractionDigits: 3 }) === 10.050m);
282+ assert(BigDecimal.sqrt(0.002m,
283+ { roundingMode: "half-even",
284+ maximumFractionDigits: 3 }) === 0.045m);
231285
232− assert(BigDecimal.round(3.14159d,
286+ assert(BigDecimal.round(3.14159m,
287+ { roundingMode: "half-even",
288+ maximumFractionDigits: 3 }) === 3.142m);
289+
290+ assert(BigDecimal.add(3.14159m, 0.31212m,
291+ { roundingMode: "half-even",
292+ maximumFractionDigits: 2 }) === 3.45m);
293+ assert(BigDecimal.sub(3.14159m, 0.31212m,
294+ { roundingMode: "down",
295+ maximumFractionDigits: 2 }) === 2.82m);
296+ assert(BigDecimal.mul(3.14159m, 0.31212m,
297+ { roundingMode: "half-even",
298+ maximumFractionDigits: 3 }) === 0.981m);
299+ assert(BigDecimal.mod(3.14159m, 0.31211m,
300+ { roundingMode: "half-even",
301+ maximumFractionDigits: 4 }) === 0.0205m);
302+ assert(BigDecimal.div(20m, 3m,
303+ { roundingMode: "half-even",
304+ maximumSignificantDigits: 3 }) === 6.67m);
305+ assert(BigDecimal.div(20m, 3m,
233306 { roundingMode: "half-even",
234− maximumFractionDigits: 3 }) === 3.142d);
307+ maximumFractionDigits: 50 }) ===
308+ 6.66666666666666666666666666666666666666666666666667m);
309+
310+ /* string conversion */
311+ assert((1234.125m).toString(), "1234.125");
312+ assert((1234.125m).toFixed(2), "1234.13");
313+ assert((1234.125m).toFixed(2, "down"), "1234.12");
314+ assert((1234.125m).toExponential(), "1.234125e+3");
315+ assert((1234.125m).toExponential(5), "1.23413e+3");
316+ assert((1234.125m).toExponential(5, "down"), "1.23412e+3");
317+ assert((1234.125m).toPrecision(6), "1234.13");
318+ assert((1234.125m).toPrecision(6, "down"), "1234.12");
319+ assert((-1234.125m).toPrecision(6, "floor"), "-1234.13");
235320 }
236321
237322 test_bigint1();
tests/test_op_overloading.js+207−0
@@ -0,0 +1,207 @@
1+"use strict";
2+
3+function assert(actual, expected, message) {
4+ if (arguments.length == 1)
5+ expected = true;
6+
7+ if (actual === expected)
8+ return;
9+
10+ if (actual !== null && expected !== null
11+ && typeof actual == 'object' && typeof expected == 'object'
12+ && actual.toString() === expected.toString())
13+ return;
14+
15+ throw Error("assertion failed: got |" + actual + "|" +
16+ ", expected |" + expected + "|" +
17+ (message ? " (" + message + ")" : ""));
18+}
19+
20+/* operators overloading with Operators.create() */
21+function test_operators_create() {
22+ class Vec2
23+ {
24+ constructor(x, y) {
25+ this.x = x;
26+ this.y = y;
27+ }
28+ static mul_scalar(p1, a) {
29+ var r = new Vec2();
30+ r.x = p1.x * a;
31+ r.y = p1.y * a;
32+ return r;
33+ }
34+ toString() {
35+ return "Vec2(" + this.x + "," + this.y + ")";
36+ }
37+ }
38+
39+ Vec2.prototype[Symbol.operatorSet] = Operators.create(
40+ {
41+ "+"(p1, p2) {
42+ var r = new Vec2();
43+ r.x = p1.x + p2.x;
44+ r.y = p1.y + p2.y;
45+ return r;
46+ },
47+ "-"(p1, p2) {
48+ var r = new Vec2();
49+ r.x = p1.x - p2.x;
50+ r.y = p1.y - p2.y;
51+ return r;
52+ },
53+ "=="(a, b) {
54+ return a.x == b.x && a.y == b.y;
55+ },
56+ "<"(a, b) {
57+ var r;
58+ /* lexicographic order */
59+ if (a.x == b.x)
60+ r = (a.y < b.y);
61+ else
62+ r = (a.x < b.x);
63+ return r;
64+ },
65+ "++"(a) {
66+ var r = new Vec2();
67+ r.x = a.x + 1;
68+ r.y = a.y + 1;
69+ return r;
70+ }
71+ },
72+ {
73+ left: Number,
74+ "*"(a, b) {
75+ return Vec2.mul_scalar(b, a);
76+ }
77+ },
78+ {
79+ right: Number,
80+ "*"(a, b) {
81+ return Vec2.mul_scalar(a, b);
82+ }
83+ });
84+
85+ var a = new Vec2(1, 2);
86+ var b = new Vec2(3, 4);
87+ var r;
88+
89+ r = a * 2 + 3 * b;
90+ assert(r.x === 11 && r.y === 16);
91+ assert(a == a, true);
92+ assert(a == b, false);
93+ assert(a != a, false);
94+ assert(a < b, true);
95+ assert(a <= b, true);
96+ assert(b < a, false);
97+ assert(b <= a, false);
98+ assert(a <= a, true);
99+ assert(a >= a, true);
100+ a++;
101+ assert(a.x === 2 && a.y === 3);
102+ r = ++a;
103+ assert(a.x === 3 && a.y === 4);
104+ assert(r === a);
105+}
106+
107+/* operators overloading thru inheritance */
108+function test_operators()
109+{
110+ var Vec2;
111+
112+ function mul_scalar(p1, a) {
113+ var r = new Vec2();
114+ r.x = p1.x * a;
115+ r.y = p1.y * a;
116+ return r;
117+ }
118+
119+ var vec2_ops = Operators({
120+ "+"(p1, p2) {
121+ var r = new Vec2();
122+ r.x = p1.x + p2.x;
123+ r.y = p1.y + p2.y;
124+ return r;
125+ },
126+ "-"(p1, p2) {
127+ var r = new Vec2();
128+ r.x = p1.x - p2.x;
129+ r.y = p1.y - p2.y;
130+ return r;
131+ },
132+ "=="(a, b) {
133+ return a.x == b.x && a.y == b.y;
134+ },
135+ "<"(a, b) {
136+ var r;
137+ /* lexicographic order */
138+ if (a.x == b.x)
139+ r = (a.y < b.y);
140+ else
141+ r = (a.x < b.x);
142+ return r;
143+ },
144+ "++"(a) {
145+ var r = new Vec2();
146+ r.x = a.x + 1;
147+ r.y = a.y + 1;
148+ return r;
149+ }
150+ },
151+ {
152+ left: Number,
153+ "*"(a, b) {
154+ return mul_scalar(b, a);
155+ }
156+ },
157+ {
158+ right: Number,
159+ "*"(a, b) {
160+ return mul_scalar(a, b);
161+ }
162+ });
163+
164+ Vec2 = class Vec2 extends vec2_ops
165+ {
166+ constructor(x, y) {
167+ super();
168+ this.x = x;
169+ this.y = y;
170+ }
171+ toString() {
172+ return "Vec2(" + this.x + "," + this.y + ")";
173+ }
174+ }
175+
176+ var a = new Vec2(1, 2);
177+ var b = new Vec2(3, 4);
178+ var r;
179+
180+ r = a * 2 + 3 * b;
181+ assert(r.x === 11 && r.y === 16);
182+ assert(a == a, true);
183+ assert(a == b, false);
184+ assert(a != a, false);
185+ assert(a < b, true);
186+ assert(a <= b, true);
187+ assert(b < a, false);
188+ assert(b <= a, false);
189+ assert(a <= a, true);
190+ assert(a >= a, true);
191+ a++;
192+ assert(a.x === 2 && a.y === 3);
193+ r = ++a;
194+ assert(a.x === 3 && a.y === 4);
195+ assert(r === a);
196+}
197+
198+function test_default_op()
199+{
200+ assert(Object(1) + 2, 3);
201+ assert(Object(1) + true, 2);
202+ assert(-Object(1), -1);
203+}
204+
205+test_operators_create();
206+test_operators();
207+test_default_op();
tests/test_qjscalc.js+15−3
@@ -66,13 +66,14 @@ function test_integer() · 65 unmodified lines
6666
6767 r = (1 << 31) < 0;
6868 assert(r, false, "(1 << 31) < 0 === false");
69+
70+ assert(typeof 1 === "number");
71+ assert(typeof 9007199254740991 === "number");
72+ assert(typeof 9007199254740992 === "bigint");
6973 }
7074
7175 function test_float()
7276 {
73− var e, a, b, sqrt2;
74−
75− assert(typeof 1 === "bigint");
7677 assert(typeof 1.0 === "bigfloat");
7778 assert(1 == 1.0);
7879 assert(1 !== 1.0);
@@ -101,6 +102,16 @@ function test_modulo() · 22 unmodified lines
101102 assert(a == [ 2,2,2,11,13,13,1009,618970019642690137449562111 ]);
102103 }
103104
105+function test_fraction()
106+{
107+ assert((1/3 + 1).toString(), "4/3")
108+ assert((2/3)^30, 1073741824/205891132094649);
109+ assert(1/3 < 2/3);
110+ assert(1/3 < 1);
111+ assert(1/3 == 1.0/3);
112+ assert(1.0/3 < 2/3);
113+}
114+
104115 function test_mod()
105116 {
106117 var a, b, p;
@@ -235,6 +246,7 @@ test_integer(); · 128 unmodified lines
235246 test_float();
236247
237248 test_modulo();
249+test_fraction();
238250 test_mod();
239251 test_polynomial();
240252 test_poly_mod();

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t