mirror of
https://github.com/bellard/quickjs.git
synced 2024-11-25 07:08:12 +08:00
2020-11-08 release
This commit is contained in:
parent
7c312df422
commit
b1f67dfc1a
@ -1,3 +1,10 @@
|
||||
2020-11-08:
|
||||
|
||||
- improved function parameter initializers
|
||||
- added std.setenv(), std.unsetenv() and std.getenviron()
|
||||
- added JS_EvalThis()
|
||||
- misc bug fixes
|
||||
|
||||
2020-09-06:
|
||||
|
||||
- added logical assignment operators
|
||||
|
15
Makefile
15
Makefile
@ -28,9 +28,9 @@ endif
|
||||
# Windows cross compilation from Linux
|
||||
#CONFIG_WIN32=y
|
||||
# use link time optimization (smaller and faster executables but slower build)
|
||||
CONFIG_LTO=y
|
||||
#CONFIG_LTO=y
|
||||
# consider warnings as errors (for development)
|
||||
#CONFIG_WERROR=y
|
||||
CONFIG_WERROR=y
|
||||
# force 32 bit build for some utilities
|
||||
#CONFIG_M32=y
|
||||
|
||||
@ -53,7 +53,11 @@ CONFIG_BIGNUM=y
|
||||
OBJDIR=.obj
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
CROSS_PREFIX=i686-w64-mingw32-
|
||||
ifdef CONFIG_M32
|
||||
CROSS_PREFIX=i686-w64-mingw32-
|
||||
else
|
||||
CROSS_PREFIX=x86_64-w64-mingw32-
|
||||
endif
|
||||
EXE=.exe
|
||||
else
|
||||
CROSS_PREFIX=
|
||||
@ -281,15 +285,12 @@ $(OBJDIR)/%.check.o: %.c | $(OBJDIR)
|
||||
regexp_test: libregexp.c libunicode.c cutils.c
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -DTEST -o $@ libregexp.c libunicode.c cutils.c $(LIBS)
|
||||
|
||||
jscompress: jscompress.c
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ jscompress.c
|
||||
|
||||
unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c unicode_gen_def.h
|
||||
$(HOST_CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o
|
||||
|
||||
clean:
|
||||
rm -f repl.c qjscalc.c out.c
|
||||
rm -f *.a *.o *.d *~ jscompress unicode_gen regexp_test $(PROGS)
|
||||
rm -f *.a *.o *.d *~ unicode_gen regexp_test $(PROGS)
|
||||
rm -f hello.c test_fib.c
|
||||
rm -f examples/*.so tests/*.so
|
||||
rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug
|
||||
|
82
TODO
82
TODO
@ -1,13 +1,11 @@
|
||||
Misc:
|
||||
- use realpath in module name normalizer and put it in quickjs-libc
|
||||
- use custom printf to avoid C library compatibility issues
|
||||
- rename CONFIG_ALL_UNICODE, CONFIG_BIGNUM, CONFIG_ATOMICS, CONFIG_CHECK_JSVALUE ?
|
||||
Bugs:
|
||||
- modules: better error handling with cyclic module references
|
||||
|
||||
Misc ideas:
|
||||
- use custom printf to avoid compatibility issues with floating point numbers
|
||||
- consistent naming for preprocessor defines
|
||||
- unify coding style and naming conventions
|
||||
- use names from the ECMA spec in library implementation
|
||||
- modules: if no ".", use a well known module loading path ?
|
||||
- use JSHoistedDef only for global variables (JSHoistedDef.var_name != JS_ATOM_NULL)
|
||||
- add index in JSVarDef and is_arg flag to merge args and vars in JSFunctionDef
|
||||
- replace most JSVarDef flags with var_type enumeration
|
||||
- use byte code emitters with typed arguments (for clarity)
|
||||
- use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing
|
||||
and use the same wrappers in all phases
|
||||
@ -15,48 +13,18 @@ Misc:
|
||||
- use custom timezone support to avoid C library compatibility issues
|
||||
|
||||
Memory:
|
||||
- use memory pools for objects, etc?
|
||||
- test border cases for max number of atoms, object properties, string length
|
||||
- add emergency malloc mode for out of memory exceptions.
|
||||
- test all DynBuf memory errors
|
||||
- test all js_realloc memory errors
|
||||
- bignum: handle memory errors
|
||||
- use memory pools for objects, etc?
|
||||
- improve JS_ComputeMemoryUsage() with more info
|
||||
|
||||
Optimizations:
|
||||
- 64-bit atoms in 64-bit mode ?
|
||||
- use auto-init properties for more global objects
|
||||
- reuse stack slots for disjoint scopes, if strip
|
||||
- optimize `for of` iterator for built-in array objects
|
||||
- add heuristic to avoid some cycles in closures
|
||||
- small String (0-2 charcodes) with immediate storage
|
||||
- perform static string concatenation at compile time
|
||||
- optimize string concatenation with ropes or miniropes?
|
||||
- add implicit numeric strings for Uint32 numbers?
|
||||
- optimize `s += a + b`, `s += a.b` and similar simple expressions
|
||||
- ensure string canonical representation and optimise comparisons and hashes?
|
||||
- remove JSObject.first_weak_ref, use bit+context based hashed array for weak references
|
||||
- optimize function storage with length and name accessors?
|
||||
- property access optimization on the global object, functions,
|
||||
prototypes and special non extensible objects.
|
||||
- create object literals with the correct length by backpatching length argument
|
||||
- remove redundant set_loc_uninitialized/check_uninitialized opcodes
|
||||
- peephole optim: push_atom_value, to_propkey -> push_atom_value
|
||||
- peephole optim: put_loc x, get_loc_check x -> set_loc x
|
||||
- comparative performance benchmark
|
||||
- use variable name when throwing uninitialized exception if available
|
||||
- convert slow array to fast array when all properties != length are numeric
|
||||
- optimize destructuring assignments for global and local variables
|
||||
- implement some form of tail-call-optimization
|
||||
- optimize OP_apply
|
||||
- optimize f(...b)
|
||||
|
||||
Extensions:
|
||||
- support more features in [features] section
|
||||
- add built-in preprocessor in compiler, get rid of jscompress
|
||||
handle #if, #ifdef, #line, limited support for #define
|
||||
- get rid of __loadScript, use more common name
|
||||
Built-in standard library:
|
||||
- BSD sockets
|
||||
- modules: use realpath in module name normalizer and put it in quickjs-libc
|
||||
- modules: if no ".", use a well known module loading path ?
|
||||
- get rid of __loadScript, use more common name
|
||||
|
||||
REPL:
|
||||
- debugger
|
||||
@ -71,8 +39,32 @@ REPL:
|
||||
- save history
|
||||
- close all predefined methods in repl.js and jscalc.js
|
||||
|
||||
Optimization ideas:
|
||||
- 64-bit atoms in 64-bit mode ?
|
||||
- 64-bit small bigint in 64-bit mode ?
|
||||
- reuse stack slots for disjoint scopes, if strip
|
||||
- add heuristic to avoid some cycles in closures
|
||||
- small String (0-2 charcodes) with immediate storage
|
||||
- perform static string concatenation at compile time
|
||||
- optimize string concatenation with ropes or miniropes?
|
||||
- add implicit numeric strings for Uint32 numbers?
|
||||
- optimize `s += a + b`, `s += a.b` and similar simple expressions
|
||||
- ensure string canonical representation and optimise comparisons and hashes?
|
||||
- remove JSObject.first_weak_ref, use bit+context based hashed array for weak references
|
||||
- property access optimization on the global object, functions,
|
||||
prototypes and special non extensible objects.
|
||||
- create object literals with the correct length by backpatching length argument
|
||||
- remove redundant set_loc_uninitialized/check_uninitialized opcodes
|
||||
- peephole optim: push_atom_value, to_propkey -> push_atom_value
|
||||
- peephole optim: put_loc x, get_loc_check x -> set_loc x
|
||||
- convert slow array to fast array when all properties != length are numeric
|
||||
- optimize destructuring assignments for global and local variables
|
||||
- implement some form of tail-call-optimization
|
||||
- optimize OP_apply
|
||||
- optimize f(...b)
|
||||
|
||||
Test262o: 0/11262 errors, 463 excluded
|
||||
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
|
||||
|
||||
Test262: 30/71748 errors, 868 excluded, 474 skipped
|
||||
Test262 commit: 24c67328062383079ada85f4d253eb0526fd209b
|
||||
Result: 51/75119 errors, 899 excluded, 570 skipped
|
||||
Test262 commit: 1c33fdb0ca60fb9d7392403be769ed0d26209132
|
||||
|
@ -1,734 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
|
||||
<head>
|
||||
<title>Javascript Bignum Extensions</title>
|
||||
|
||||
<meta name="description" content="Javascript Bignum Extensions">
|
||||
<meta name="keywords" content="Javascript Bignum Extensions">
|
||||
<meta name="resource-type" content="document">
|
||||
<meta name="distribution" content="global">
|
||||
<meta name="Generator" content="makeinfo">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
|
||||
<style type="text/css">
|
||||
<!--
|
||||
a.summary-letter {text-decoration: none}
|
||||
blockquote.indentedblock {margin-right: 0em}
|
||||
blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
|
||||
blockquote.smallquotation {font-size: smaller}
|
||||
div.display {margin-left: 3.2em}
|
||||
div.example {margin-left: 3.2em}
|
||||
div.lisp {margin-left: 3.2em}
|
||||
div.smalldisplay {margin-left: 3.2em}
|
||||
div.smallexample {margin-left: 3.2em}
|
||||
div.smalllisp {margin-left: 3.2em}
|
||||
kbd {font-style: oblique}
|
||||
pre.display {font-family: inherit}
|
||||
pre.format {font-family: inherit}
|
||||
pre.menu-comment {font-family: serif}
|
||||
pre.menu-preformatted {font-family: serif}
|
||||
pre.smalldisplay {font-family: inherit; font-size: smaller}
|
||||
pre.smallexample {font-size: smaller}
|
||||
pre.smallformat {font-family: inherit; font-size: smaller}
|
||||
pre.smalllisp {font-size: smaller}
|
||||
span.nolinebreak {white-space: nowrap}
|
||||
span.roman {font-family: initial; font-weight: normal}
|
||||
span.sansserif {font-family: sans-serif; font-weight: normal}
|
||||
ul.no-bullet {list-style: none}
|
||||
-->
|
||||
</style>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body lang="en">
|
||||
<h1 class="settitle" align="center">Javascript Bignum Extensions</h1>
|
||||
|
||||
<a name="SEC_Contents"></a>
|
||||
<h2 class="contents-heading">Table of Contents</h2>
|
||||
|
||||
<div class="contents">
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-Introduction" href="#Introduction">1 Introduction</a></li>
|
||||
<li><a name="toc-Operator-overloading" href="#Operator-overloading">2 Operator overloading</a></li>
|
||||
<li><a name="toc-BigInt-extensions" href="#BigInt-extensions">3 BigInt extensions</a></li>
|
||||
<li><a name="toc-BigFloat" href="#BigFloat">4 BigFloat</a>
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-Introduction-1" href="#Introduction-1">4.1 Introduction</a></li>
|
||||
<li><a name="toc-Floating-point-rounding" href="#Floating-point-rounding">4.2 Floating point rounding</a></li>
|
||||
<li><a name="toc-Operators" href="#Operators">4.3 Operators</a></li>
|
||||
<li><a name="toc-BigFloat-literals" href="#BigFloat-literals">4.4 BigFloat literals</a></li>
|
||||
<li><a name="toc-Builtin-Object-changes" href="#Builtin-Object-changes">4.5 Builtin Object changes</a>
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-BigFloat-function" href="#BigFloat-function">4.5.1 <code>BigFloat</code> function</a></li>
|
||||
<li><a name="toc-BigFloat_002eprototype" href="#BigFloat_002eprototype">4.5.2 <code>BigFloat.prototype</code></a></li>
|
||||
<li><a name="toc-BigFloatEnv-constructor" href="#BigFloatEnv-constructor">4.5.3 <code>BigFloatEnv</code> constructor</a></li>
|
||||
</ul></li>
|
||||
</ul></li>
|
||||
<li><a name="toc-BigDecimal" href="#BigDecimal">5 BigDecimal</a>
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-Operators-1" href="#Operators-1">5.1 Operators</a></li>
|
||||
<li><a name="toc-BigDecimal-literals" href="#BigDecimal-literals">5.2 BigDecimal literals</a></li>
|
||||
<li><a name="toc-Builtin-Object-changes-1" href="#Builtin-Object-changes-1">5.3 Builtin Object changes</a>
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-The-BigDecimal-function_002e" href="#The-BigDecimal-function_002e">5.3.1 The <code>BigDecimal</code> function.</a></li>
|
||||
<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>
|
||||
<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>
|
||||
</ul></li>
|
||||
</ul></li>
|
||||
<li><a name="toc-Math-mode" href="#Math-mode">6 Math mode</a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<a name="Introduction"></a>
|
||||
<h2 class="chapter">1 Introduction</h2>
|
||||
|
||||
<p>The Bignum extensions add the following features to the Javascript
|
||||
language while being 100% backward compatible:
|
||||
</p>
|
||||
<ul>
|
||||
<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>.
|
||||
|
||||
</li><li> Arbitrarily large floating point numbers (<code>BigFloat</code>) in base 2 using the IEEE 754 semantics.
|
||||
|
||||
</li><li> Arbitrarily large floating point numbers (<code>BigDecimal</code>) in base 10 based on the proposal available at
|
||||
<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
|
||||
|
||||
</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
|
||||
remainder. <code>^</code> is an alias to the power operator
|
||||
(<code>**</code>). <code>^^</code> is used as the exclusive or operator.
|
||||
|
||||
</li></ul>
|
||||
|
||||
<p>The extensions are independent from each other except the <code>math</code>
|
||||
mode which relies on BigFloat and operator overloading.
|
||||
</p>
|
||||
<a name="Operator-overloading"></a>
|
||||
<h2 class="chapter">2 Operator overloading</h2>
|
||||
|
||||
<p>Operator overloading is inspired from the proposal available at
|
||||
<a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>. It
|
||||
implements the same dispatch logic but finds the operator sets by
|
||||
looking at the <code>Symbol.operatorSet</code> property in the objects. The
|
||||
changes were done in order to simplify the implementation.
|
||||
</p>
|
||||
<p>More precisely, the following modifications were made:
|
||||
</p>
|
||||
<ul>
|
||||
<li> <code>with operators from</code> is not supported. Operator overloading is always enabled.
|
||||
|
||||
</li><li> The dispatch is not based on a static <code>[[OperatorSet]]</code> field in all instances. Instead, a dynamic lookup of the <code>Symbol.operatorSet</code> property is done. This property is typically added in the prototype of each object.
|
||||
|
||||
</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.
|
||||
|
||||
</li><li> <code>[]</code> cannot be overloaded.
|
||||
|
||||
</li><li> In math mode, the BigInt division and power operators can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
|
||||
|
||||
</li></ul>
|
||||
|
||||
<a name="BigInt-extensions"></a>
|
||||
<h2 class="chapter">3 BigInt extensions</h2>
|
||||
|
||||
<p>A few properties are added to the BigInt object:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>tdiv(a, b)</code></dt>
|
||||
<dd><p>Return <em>trunc(a/b)</em>. <code>b = 0</code> raises a RangeError
|
||||
exception.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>fdiv(a, b)</code></dt>
|
||||
<dd><p>Return <em>\lfloor a/b \rfloor</em>. <code>b = 0</code> raises a RangeError
|
||||
exception.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>cdiv(a, b)</code></dt>
|
||||
<dd><p>Return <em>\lceil a/b \rceil</em>. <code>b = 0</code> raises a RangeError
|
||||
exception.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>ediv(a, b)</code></dt>
|
||||
<dd><p>Return <em>sgn(b) \lfloor a/{|b|} \rfloor</em> (Euclidian
|
||||
division). <code>b = 0</code> raises a RangeError exception.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>tdivrem(a, b)</code></dt>
|
||||
<dt><code>fdivrem(a, b)</code></dt>
|
||||
<dt><code>cdivrem(a, b)</code></dt>
|
||||
<dt><code>edivrem(a, b)</code></dt>
|
||||
<dd><p>Return an array of two elements. The first element is the quotient,
|
||||
the second is the remainder. The same rounding is done as the
|
||||
corresponding division operation.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>sqrt(a)</code></dt>
|
||||
<dd><p>Return <em>\lfloor \sqrt(a) \rfloor</em>. A RangeError exception is
|
||||
raised if <em>a < 0</em>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>sqrtrem(a)</code></dt>
|
||||
<dd><p>Return an array of two elements. The first element is <em>\lfloor
|
||||
\sqrt{a} \rfloor</em>. The second element is <em>a-\lfloor \sqrt{a}
|
||||
\rfloor^2</em>. A RangeError exception is raised if <em>a < 0</em>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>floorLog2(a)</code></dt>
|
||||
<dd><p>Return -1 if <em>a \leq 0</em> otherwise return <em>\lfloor \log2(a) \rfloor</em>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>ctz(a)</code></dt>
|
||||
<dd><p>Return the number of trailing zeros in the two’s complement binary representation of a. Return -1 if <em>a=0</em>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="BigFloat"></a>
|
||||
<h2 class="chapter">4 BigFloat</h2>
|
||||
|
||||
<a name="Introduction-1"></a>
|
||||
<h3 class="section">4.1 Introduction</h3>
|
||||
|
||||
<p>This extension adds the <code>BigFloat</code> primitive type. The
|
||||
<code>BigFloat</code> type represents floating point numbers in base 2
|
||||
with the IEEE 754 semantics. A floating
|
||||
point number is represented as a sign, mantissa and exponent. The
|
||||
special values <code>NaN</code>, <code>+/-Infinity</code>, <code>+0</code> and <code>-0</code>
|
||||
are supported. The mantissa and exponent can have any bit length with
|
||||
an implementation specific minimum and maximum.
|
||||
</p>
|
||||
<a name="Floating-point-rounding"></a>
|
||||
<h3 class="section">4.2 Floating point rounding</h3>
|
||||
|
||||
<p>Each floating point operation operates with infinite precision and
|
||||
then rounds the result according to the specified floating point
|
||||
environment (<code>BigFloatEnv</code> object). The status flags of the
|
||||
environment are also set according to the result of the operation.
|
||||
</p>
|
||||
<p>If no floating point environment is provided, the global floating
|
||||
point environment is used.
|
||||
</p>
|
||||
<p>The rounding mode of the global floating point environment is always
|
||||
<code>RNDN</code> (“round to nearest with ties to even”)<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>. The status flags of the global environment cannot be
|
||||
read<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>. The precision of the global environment is
|
||||
<code>BigFloatEnv.prec</code>. The number of exponent bits of the global
|
||||
environment is <code>BigFloatEnv.expBits</code>. The global environment
|
||||
subnormal flag is set to <code>true</code>.
|
||||
</p>
|
||||
<p>For example, <code>prec = 53</code> and <code> expBits = 11</code> exactly give
|
||||
the same precision as the IEEE 754 64 bit floating point format. The
|
||||
default precision is <code>prec = 113</code> and <code> expBits = 15</code> (IEEE
|
||||
754 128 bit floating point format).
|
||||
</p>
|
||||
<p>The global floating point environment can only be modified temporarily
|
||||
when calling a function (see <code>BigFloatEnv.setPrec</code>). Hence a
|
||||
function can change the global floating point environment for its
|
||||
callees but not for its caller.
|
||||
</p>
|
||||
<a name="Operators"></a>
|
||||
<h3 class="section">4.3 Operators</h3>
|
||||
|
||||
<p>The builtin operators are extended so that a BigFloat is returned if
|
||||
at least one operand is a BigFloat. The computations are always done
|
||||
with infinite precision and rounded according to the global floating
|
||||
point environment.
|
||||
</p>
|
||||
<p><code>typeof</code> applied on a <code>BigFloat</code> returns <code>bigfloat</code>.
|
||||
</p>
|
||||
<p>BigFloat can be compared with all the other numeric types and the
|
||||
result follows the expected mathematical relations.
|
||||
</p>
|
||||
<p>However, since BigFloat and Number are different types they are never
|
||||
equal when using the strict comparison operators (e.g. <code>0.0 ===
|
||||
0.0l</code> is false).
|
||||
</p>
|
||||
<a name="BigFloat-literals"></a>
|
||||
<h3 class="section">4.4 BigFloat literals</h3>
|
||||
|
||||
<p>BigFloat literals are floating point numbers with a trailing <code>l</code>
|
||||
suffix. BigFloat literals have an infinite precision. They are rounded
|
||||
according to the global floating point environment when they are
|
||||
evaluated.<a name="DOCF3" href="#FOOT3"><sup>3</sup></a>
|
||||
</p>
|
||||
<a name="Builtin-Object-changes"></a>
|
||||
<h3 class="section">4.5 Builtin Object changes</h3>
|
||||
|
||||
<a name="BigFloat-function"></a>
|
||||
<h4 class="subsection">4.5.1 <code>BigFloat</code> function</h4>
|
||||
|
||||
<p>The <code>BigFloat</code> function cannot be invoked as a constructor. When
|
||||
invoked as a function: the parameter is converted to a primitive
|
||||
type. If the result is a numeric type, it is converted to BigFloat
|
||||
without rounding. If the result is a string, it is converted to
|
||||
BigFloat using the precision of the global floating point environment.
|
||||
</p>
|
||||
<p><code>BigFloat</code> properties:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>LN2</code></dt>
|
||||
<dt><code>PI</code></dt>
|
||||
<dd><p>Getter. Return the value of the corresponding mathematical constant
|
||||
rounded to nearest, ties to even with the current global
|
||||
precision. The constant values are cached for small precisions.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>MIN_VALUE</code></dt>
|
||||
<dt><code>MAX_VALUE</code></dt>
|
||||
<dt><code>EPSILON</code></dt>
|
||||
<dd><p>Getter. Return the minimum, maximum and epsilon <code>BigFloat</code> values
|
||||
(same definition as the corresponding <code>Number</code> constants).
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>fpRound(a[, e])</code></dt>
|
||||
<dd><p>Round the floating point number <code>a</code> according to the floating
|
||||
point environment <code>e</code> or the global environment if <code>e</code> is
|
||||
undefined.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>parseFloat(a[, radix[, e]])</code></dt>
|
||||
<dd><p>Parse the string <code>a</code> as a floating point number in radix
|
||||
<code>radix</code>. The radix is 0 (default) or from 2 to 36. The radix 0
|
||||
means radix 10 unless there is a hexadecimal or binary prefix. The
|
||||
result is rounded according to the floating point environment <code>e</code>
|
||||
or the global environment if <code>e</code> is undefined.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>isFinite(a)</code></dt>
|
||||
<dd><p>Return true if <code>a</code> is a finite bigfloat.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>isNaN(a)</code></dt>
|
||||
<dd><p>Return true if <code>a</code> is a NaN bigfloat.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>add(a, b[, e])</code></dt>
|
||||
<dt><code>sub(a, b[, e])</code></dt>
|
||||
<dt><code>mul(a, b[, e])</code></dt>
|
||||
<dt><code>div(a, b[, e])</code></dt>
|
||||
<dd><p>Perform the specified floating point operation and round the floating
|
||||
point number <code>a</code> according to the floating point environment
|
||||
<code>e</code> or the global environment if <code>e</code> is undefined. If
|
||||
<code>e</code> is specified, the floating point status flags are updated.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>floor(x)</code></dt>
|
||||
<dt><code>ceil(x)</code></dt>
|
||||
<dt><code>round(x)</code></dt>
|
||||
<dt><code>trunc(x)</code></dt>
|
||||
<dd><p>Round to an integer. No additional rounding is performed.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>abs(x)</code></dt>
|
||||
<dd><p>Return the absolute value of x. No additional rounding is performed.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>fmod(x, y[, e])</code></dt>
|
||||
<dt><code>remainder(x, y[, e])</code></dt>
|
||||
<dd><p>Floating point remainder. The quotient is truncated to zero (fmod) or
|
||||
to the nearest integer with ties to even (remainder). <code>e</code> is an
|
||||
optional floating point environment.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>sqrt(x[, e])</code></dt>
|
||||
<dd><p>Square root. Return a rounded floating point number. <code>e</code> is an
|
||||
optional floating point environment.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>sin(x[, e])</code></dt>
|
||||
<dt><code>cos(x[, e])</code></dt>
|
||||
<dt><code>tan(x[, e])</code></dt>
|
||||
<dt><code>asin(x[, e])</code></dt>
|
||||
<dt><code>acos(x[, e])</code></dt>
|
||||
<dt><code>atan(x[, e])</code></dt>
|
||||
<dt><code>atan2(x, y[, e])</code></dt>
|
||||
<dt><code>exp(x[, e])</code></dt>
|
||||
<dt><code>log(x[, e])</code></dt>
|
||||
<dt><code>pow(x, y[, e])</code></dt>
|
||||
<dd><p>Transcendental operations. Return a rounded floating point
|
||||
number. <code>e</code> is an optional floating point environment.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="BigFloat_002eprototype"></a>
|
||||
<h4 class="subsection">4.5.2 <code>BigFloat.prototype</code></h4>
|
||||
|
||||
<p>The following properties are modified:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>valueOf()</code></dt>
|
||||
<dd><p>Return the bigfloat primitive value corresponding to <code>this</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>toString(radix)</code></dt>
|
||||
<dd>
|
||||
<p>For floating point numbers:
|
||||
</p>
|
||||
<ul>
|
||||
<li> If the radix is a power of two, the conversion is done with infinite
|
||||
precision.
|
||||
</li><li> Otherwise, the number is rounded to nearest with ties to even using
|
||||
the global precision. It is then converted to string using the minimum
|
||||
number of digits so that its conversion back to a floating point using
|
||||
the global precision and round to nearest gives the same number.
|
||||
|
||||
</li></ul>
|
||||
|
||||
<p>The exponent letter is <code>e</code> for base 10, <code>p</code> for bases 2, 8,
|
||||
16 with a binary exponent and <code>@</code> for the other bases.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
|
||||
<dt><code>toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
|
||||
<dt><code>toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
|
||||
<dd><p>Same semantics as the corresponding <code>Number</code> functions with
|
||||
BigFloats. There is no limit on the accepted precision <code>p</code>. The
|
||||
rounding mode and radix can be optionally specified. The radix must be
|
||||
between 2 and 36.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="BigFloatEnv-constructor"></a>
|
||||
<h4 class="subsection">4.5.3 <code>BigFloatEnv</code> constructor</h4>
|
||||
|
||||
<p>The <code>BigFloatEnv([p, [,rndMode]]</code> constructor cannot be invoked as a
|
||||
function. The floating point environment contains:
|
||||
</p>
|
||||
<ul>
|
||||
<li> the mantissa precision in bits
|
||||
|
||||
</li><li> the exponent size in bits assuming an IEEE 754 representation;
|
||||
|
||||
</li><li> the subnormal flag (if true, subnormal floating point numbers can
|
||||
be generated by the floating point operations).
|
||||
|
||||
</li><li> the rounding mode
|
||||
|
||||
</li><li> the floating point status. The status flags can only be set by the floating point operations. They can be reset with <code>BigFloatEnv.prototype.clearStatus()</code> or with the various status flag setters.
|
||||
|
||||
</li></ul>
|
||||
|
||||
<p><code>new BigFloatEnv([p, [,rndMode]]</code> creates a new floating point
|
||||
environment. The status flags are reset. If no parameter is given the
|
||||
precision, exponent bits and subnormal flags are copied from the
|
||||
global floating point environment. Otherwise, the precision is set to
|
||||
<code>p</code>, the number of exponent bits is set to <code>expBitsMax</code> and the
|
||||
subnormal flags is set to <code>false</code>. If <code>rndMode</code> is
|
||||
<code>undefined</code>, the rounding mode is set to <code>RNDN</code>.
|
||||
</p>
|
||||
<p><code>BigFloatEnv</code> properties:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>prec</code></dt>
|
||||
<dd><p>Getter. Return the precision in bits of the global floating point
|
||||
environment. The initial value is <code>113</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>expBits</code></dt>
|
||||
<dd><p>Getter. Return the exponent size in bits of the global floating point
|
||||
environment assuming an IEEE 754 representation. The initial value is
|
||||
<code>15</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>setPrec(f, p[, e])</code></dt>
|
||||
<dd><p>Set the precision of the global floating point environment to <code>p</code>
|
||||
and the exponent size to <code>e</code> then call the function
|
||||
<code>f</code>. Then the Float precision and exponent size are reset to
|
||||
their precious value and the return value of <code>f</code> is returned (or
|
||||
an exception is raised if <code>f</code> raised an exception). If <code>e</code>
|
||||
is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>precMin</code></dt>
|
||||
<dd><p>Read-only integer. Return the minimum allowed precision. Must be at least 2.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>precMax</code></dt>
|
||||
<dd><p>Read-only integer. Return the maximum allowed precision. Must be at least 113.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>expBitsMin</code></dt>
|
||||
<dd><p>Read-only integer. Return the minimum allowed exponent size in
|
||||
bits. Must be at least 3.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>expBitsMax</code></dt>
|
||||
<dd><p>Read-only integer. Return the maximum allowed exponent size in
|
||||
bits. Must be at least 15.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDN</code></dt>
|
||||
<dd><p>Read-only integer. Round to nearest, with ties to even rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDZ</code></dt>
|
||||
<dd><p>Read-only integer. Round to zero rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDD</code></dt>
|
||||
<dd><p>Read-only integer. Round to -Infinity rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDU</code></dt>
|
||||
<dd><p>Read-only integer. Round to +Infinity rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDNA</code></dt>
|
||||
<dd><p>Read-only integer. Round to nearest, with ties away from zero rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDA</code></dt>
|
||||
<dd><p>Read-only integer. Round away from zero rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDF<a name="DOCF4" href="#FOOT4"><sup>4</sup></a></code></dt>
|
||||
<dd><p>Read-only integer. Faithful rounding mode. The result is
|
||||
non-deterministically rounded to -Infinity or +Infinity. This rounding
|
||||
mode usually gives a faster and deterministic running time for the
|
||||
floating point operations.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<p><code>BigFloatEnv.prototype</code> properties:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>prec</code></dt>
|
||||
<dd><p>Getter and setter (Integer). Return or set the precision in bits.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>expBits</code></dt>
|
||||
<dd><p>Getter and setter (Integer). Return or set the exponent size in bits
|
||||
assuming an IEEE 754 representation.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>rndMode</code></dt>
|
||||
<dd><p>Getter and setter (Integer). Return or set the rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>subnormal</code></dt>
|
||||
<dd><p>Getter and setter (Boolean). subnormal flag. It is false when
|
||||
<code>expBits = expBitsMax</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>clearStatus()</code></dt>
|
||||
<dd><p>Clear the status flags.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>invalidOperation</code></dt>
|
||||
<dt><code>divideByZero</code></dt>
|
||||
<dt><code>overflow</code></dt>
|
||||
<dt><code>underflow</code></dt>
|
||||
<dt><code>inexact</code></dt>
|
||||
<dd><p>Getter and setter (Boolean). Status flags.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="BigDecimal"></a>
|
||||
<h2 class="chapter">5 BigDecimal</h2>
|
||||
|
||||
<p>This extension adds the <code>BigDecimal</code> primitive type. The
|
||||
<code>BigDecimal</code> type represents floating point numbers in base
|
||||
10. It is inspired from the proposal available at
|
||||
<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
|
||||
</p>
|
||||
<p>The <code>BigDecimal</code> floating point numbers are always normalized and
|
||||
finite. There is no concept of <code>-0</code>, <code>Infinity</code> or
|
||||
<code>NaN</code>. By default, all the computations are done with infinite
|
||||
precision.
|
||||
</p>
|
||||
<a name="Operators-1"></a>
|
||||
<h3 class="section">5.1 Operators</h3>
|
||||
|
||||
<p>The following builtin operators support BigDecimal:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>+</code></dt>
|
||||
<dt><code>-</code></dt>
|
||||
<dt><code>*</code></dt>
|
||||
<dd><p>Both operands must be BigDecimal. The result is computed with infinite
|
||||
precision.
|
||||
</p></dd>
|
||||
<dt><code>%</code></dt>
|
||||
<dd><p>Both operands must be BigDecimal. The result is computed with infinite
|
||||
precision. A range error is throws in case of division by zero.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>/</code></dt>
|
||||
<dd><p>Both operands must be BigDecimal. A range error is throws in case of
|
||||
division by zero or if the result cannot be represented with infinite
|
||||
precision (use <code>BigDecimal.div</code> to specify the rounding).
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>**</code></dt>
|
||||
<dd><p>Both operands must be BigDecimal. The exponent must be a positive
|
||||
integer. The result is computed with infinite precision.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>===</code></dt>
|
||||
<dd><p>When one of the operand is a BigDecimal, return true if both operands
|
||||
are a BigDecimal and if they are equal.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>==</code></dt>
|
||||
<dt><code>!=</code></dt>
|
||||
<dt><code><=</code></dt>
|
||||
<dt><code>>=</code></dt>
|
||||
<dt><code><</code></dt>
|
||||
<dt><code>></code></dt>
|
||||
<dd>
|
||||
<p>Numerical comparison. When one of the operand is not a BigDecimal, it is
|
||||
converted to BigDecimal by using ToString(). Hence comparisons between
|
||||
Number and BigDecimal do not use the exact mathematical value of the
|
||||
Number value.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="BigDecimal-literals"></a>
|
||||
<h3 class="section">5.2 BigDecimal literals</h3>
|
||||
|
||||
<p>BigDecimal literals are decimal floating point numbers with a trailing
|
||||
<code>m</code> suffix.
|
||||
</p>
|
||||
<a name="Builtin-Object-changes-1"></a>
|
||||
<h3 class="section">5.3 Builtin Object changes</h3>
|
||||
|
||||
<a name="The-BigDecimal-function_002e"></a>
|
||||
<h4 class="subsection">5.3.1 The <code>BigDecimal</code> function.</h4>
|
||||
|
||||
<p>It returns <code>0m</code> if no parameter is provided. Otherwise the first
|
||||
parameter is converted to a bigdecimal by using ToString(). Hence
|
||||
Number values are not converted to their exact numerical value as
|
||||
BigDecimal.
|
||||
</p>
|
||||
<a name="Properties-of-the-BigDecimal-object"></a>
|
||||
<h4 class="subsection">5.3.2 Properties of the <code>BigDecimal</code> object</h4>
|
||||
|
||||
<dl compact="compact">
|
||||
<dt><code>add(a, b[, e])</code></dt>
|
||||
<dt><code>sub(a, b[, e])</code></dt>
|
||||
<dt><code>mul(a, b[, e])</code></dt>
|
||||
<dt><code>div(a, b[, e])</code></dt>
|
||||
<dt><code>mod(a, b[, e])</code></dt>
|
||||
<dt><code>sqrt(a, e)</code></dt>
|
||||
<dt><code>round(a, e)</code></dt>
|
||||
<dd><p>Perform the specified floating point operation and round the floating
|
||||
point result according to the rounding object <code>e</code>. If the
|
||||
rounding object is not present, the operation is executed with
|
||||
infinite precision.
|
||||
</p>
|
||||
<p>For <code>div</code>, a <code>RangeError</code> exception is thrown in case of
|
||||
division by zero or if the result cannot be represented with infinite
|
||||
precision if no rounding object is present.
|
||||
</p>
|
||||
<p>For <code>sqrt</code>, a range error is thrown if <code>a</code> is less than
|
||||
zero.
|
||||
</p>
|
||||
<p>The rounding object must contain the following properties:
|
||||
<code>roundingMode</code> is a string specifying the rounding mode
|
||||
(<code>"floor"</code>, <code>"ceiling"</code>, <code>"down"</code>, <code>"up"</code>,
|
||||
<code>"half-even"</code>, <code>"half-up"</code>). Either
|
||||
<code>maximumSignificantDigits</code> or <code>maximumFractionDigits</code> must
|
||||
be present to specify respectively the number of significant digits
|
||||
(must be >= 1) or the number of digits after the decimal point (must
|
||||
be >= 0).
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="Properties-of-the-BigDecimal_002eprototype-object"></a>
|
||||
<h4 class="subsection">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</h4>
|
||||
|
||||
<dl compact="compact">
|
||||
<dt><code>valueOf()</code></dt>
|
||||
<dd><p>Return the bigdecimal primitive value corresponding to <code>this</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>toString()</code></dt>
|
||||
<dd><p>Convert <code>this</code> to a string with infinite precision in base 10.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>toPrecision(p, rnd_mode = "half-up")</code></dt>
|
||||
<dt><code>toFixed(p, rnd_mode = "half-up")</code></dt>
|
||||
<dt><code>toExponential(p, rnd_mode = "half-up")</code></dt>
|
||||
<dd><p>Convert the BigDecimal <code>this</code> to string with the specified
|
||||
precision <code>p</code>. There is no limit on the accepted precision
|
||||
<code>p</code>. The rounding mode can be optionally
|
||||
specified. <code>toPrecision</code> outputs either in decimal fixed notation
|
||||
or in decimal exponential notation with a <code>p</code> digits of
|
||||
precision. <code>toExponential</code> outputs in decimal exponential
|
||||
notation with <code>p</code> digits after the decimal point. <code>toFixed</code>
|
||||
outputs in decimal notation with <code>p</code> digits after the decimal
|
||||
point.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="Math-mode"></a>
|
||||
<h2 class="chapter">6 Math mode</h2>
|
||||
|
||||
<p>A new <em>math mode</em> is enabled with the <code>"use math"</code>
|
||||
directive. It propagates the same way as the <em>strict mode</em>. It is
|
||||
designed so that arbitrarily large integers and floating point numbers
|
||||
are available by default. In order to minimize the number of changes
|
||||
in the Javascript semantics, integers are represented either as Number
|
||||
or BigInt depending on their magnitude. Floating point numbers are
|
||||
always represented as BigFloat.
|
||||
</p>
|
||||
<p>The following changes are made to the Javascript semantics:
|
||||
</p>
|
||||
<ul>
|
||||
<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 === "bigfloat"</code>.
|
||||
|
||||
</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 === "number "</code>, <code>typeof 1n === "number"</code> but <code>typeof 9007199254740992 === "bigint" </code>.
|
||||
|
||||
</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.
|
||||
|
||||
</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.
|
||||
|
||||
</li><li> The <code>^</code> operator is an alias to the power operator (<code>**</code>).
|
||||
|
||||
</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>.
|
||||
|
||||
</li><li> The logical xor operator is still available with the <code>^^</code> operator.
|
||||
|
||||
</li><li> The modulo operator (<code>%</code>) returns the Euclidian remainder (always positive) instead of the truncated remainder.
|
||||
|
||||
</li><li> The integer division operator can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
|
||||
|
||||
</li><li> The integer power operator with a non zero negative exponent can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
|
||||
|
||||
</li></ul>
|
||||
|
||||
<div class="footnote">
|
||||
<hr>
|
||||
<h4 class="footnotes-heading">Footnotes</h4>
|
||||
|
||||
<h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>
|
||||
<p>The
|
||||
rationale is that the rounding mode changes must always be
|
||||
explicit.</p>
|
||||
<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
|
||||
<p>The rationale is to avoid side effects for the built-in
|
||||
operators.</p>
|
||||
<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
|
||||
<p>Base 10 floating point literals cannot usually be
|
||||
exactly represented as base 2 floating point number. In order to
|
||||
ensure that the literal is represented accurately with the current
|
||||
precision, it must be evaluated at runtime.</p>
|
||||
<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
|
||||
<p>Could be removed in case a deterministic behavior for floating point operations is required.</p>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
BIN
doc/jsbignum.pdf
BIN
doc/jsbignum.pdf
Binary file not shown.
1369
doc/quickjs.html
1369
doc/quickjs.html
File diff suppressed because it is too large
Load Diff
BIN
doc/quickjs.pdf
BIN
doc/quickjs.pdf
Binary file not shown.
@ -452,6 +452,16 @@ useful in case of specific memory constraints or for testing.
|
||||
Return the value of the environment variable @code{name} or
|
||||
@code{undefined} if it is not defined.
|
||||
|
||||
@item setenv(name, value)
|
||||
Set the value of the environment variable @code{name} to the string
|
||||
@code{value}.
|
||||
|
||||
@item unsetenv(name)
|
||||
Delete the environment variable @code{name}.
|
||||
|
||||
@item getenviron()
|
||||
Return an object containing the environment variables as key-value pairs.
|
||||
|
||||
@item urlGet(url, options = undefined)
|
||||
|
||||
Download @code{url} using the @file{curl} command line
|
||||
@ -532,7 +542,7 @@ position @code{position} (wrapper to the libc @code{fread}).
|
||||
|
||||
@item write(buffer, position, length)
|
||||
Write @code{length} bytes to the file from the ArrayBuffer @code{buffer} at byte
|
||||
position @code{position} (wrapper to the libc @code{fread}).
|
||||
position @code{position} (wrapper to the libc @code{fwrite}).
|
||||
|
||||
@item getline()
|
||||
Return the next line from the file, assuming UTF-8 encoding, excluding
|
||||
|
918
jscompress.c
918
jscompress.c
@ -1,918 +0,0 @@
|
||||
/*
|
||||
* Javascript Compressor
|
||||
*
|
||||
* Copyright (c) 2008-2018 Fabrice Bellard
|
||||
* Copyright (c) 2017-2018 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cutils.h"
|
||||
|
||||
typedef struct JSToken {
|
||||
int tok;
|
||||
char buf[20];
|
||||
char *str;
|
||||
int len;
|
||||
int size;
|
||||
int line_num; /* line number for start of token */
|
||||
int lines; /* number of embedded linefeeds in token */
|
||||
} JSToken;
|
||||
|
||||
enum {
|
||||
TOK_EOF = 256,
|
||||
TOK_IDENT,
|
||||
TOK_STR1,
|
||||
TOK_STR2,
|
||||
TOK_STR3,
|
||||
TOK_NUM,
|
||||
TOK_COM,
|
||||
TOK_LCOM,
|
||||
};
|
||||
|
||||
void tok_reset(JSToken *tt)
|
||||
{
|
||||
if (tt->str != tt->buf) {
|
||||
free(tt->str);
|
||||
tt->str = tt->buf;
|
||||
tt->size = sizeof(tt->buf);
|
||||
}
|
||||
tt->len = 0;
|
||||
}
|
||||
|
||||
void tok_add_ch(JSToken *tt, int c)
|
||||
{
|
||||
if (tt->len + 1 > tt->size) {
|
||||
tt->size *= 2;
|
||||
if (tt->str == tt->buf) {
|
||||
tt->str = malloc(tt->size);
|
||||
memcpy(tt->str, tt->buf, tt->len);
|
||||
} else {
|
||||
tt->str = realloc(tt->str, tt->size);
|
||||
}
|
||||
}
|
||||
tt->str[tt->len++] = c;
|
||||
}
|
||||
|
||||
FILE *infile;
|
||||
const char *filename;
|
||||
int output_line_num;
|
||||
int line_num;
|
||||
int ch;
|
||||
JSToken tokc;
|
||||
|
||||
int skip_mask;
|
||||
#define DEFINE_MAX 20
|
||||
char *define_tab[DEFINE_MAX];
|
||||
int define_len;
|
||||
|
||||
void error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
if (filename) {
|
||||
fprintf(stderr, "%s:%d: ", filename, line_num);
|
||||
} else {
|
||||
fprintf(stderr, "jscompress: ");
|
||||
}
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void define_symbol(const char *def)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < define_len; i++) {
|
||||
if (!strcmp(tokc.str, define_tab[i]))
|
||||
return;
|
||||
}
|
||||
if (define_len >= DEFINE_MAX)
|
||||
error("too many defines");
|
||||
define_tab[define_len++] = strdup(def);
|
||||
}
|
||||
|
||||
void undefine_symbol(const char *def)
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 0; i < define_len; i++) {
|
||||
if (!strcmp(tokc.str, define_tab[i])) {
|
||||
free(define_tab[i]);
|
||||
} else {
|
||||
define_tab[j++] = define_tab[i];
|
||||
}
|
||||
}
|
||||
define_len = j;
|
||||
}
|
||||
|
||||
const char *find_symbol(const char *def)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < define_len; i++) {
|
||||
if (!strcmp(tokc.str, define_tab[i]))
|
||||
return "1";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void next(void);
|
||||
|
||||
void nextch(void)
|
||||
{
|
||||
ch = fgetc(infile);
|
||||
if (ch == '\n')
|
||||
line_num++;
|
||||
}
|
||||
|
||||
int skip_blanks(void)
|
||||
{
|
||||
for (;;) {
|
||||
next();
|
||||
if (tokc.tok != ' ' && tokc.tok != '\t' &&
|
||||
tokc.tok != TOK_COM && tokc.tok != TOK_LCOM)
|
||||
return tokc.tok;
|
||||
}
|
||||
}
|
||||
|
||||
void parse_directive(void)
|
||||
{
|
||||
int ifdef, mask = skip_mask;
|
||||
/* simplistic preprocessor:
|
||||
#define / #undef / #ifdef / #ifndef / #else / #endif
|
||||
no symbol substitution.
|
||||
*/
|
||||
skip_mask = 0; /* disable skipping to parse preprocessor line */
|
||||
nextch();
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected preprocessing directive after #");
|
||||
|
||||
if (!strcmp(tokc.str, "define")) {
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected identifier after #define");
|
||||
define_symbol(tokc.str);
|
||||
} else if (!strcmp(tokc.str, "undef")) {
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected identifier after #undef");
|
||||
undefine_symbol(tokc.str);
|
||||
} else if ((ifdef = 1, !strcmp(tokc.str, "ifdef")) ||
|
||||
(ifdef = 0, !strcmp(tokc.str, "ifndef"))) {
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected identifier after #ifdef/#ifndef");
|
||||
mask = (mask << 2) | 2 | ifdef;
|
||||
if (find_symbol(tokc.str))
|
||||
mask ^= 1;
|
||||
} else if (!strcmp(tokc.str, "else")) {
|
||||
if (!(mask & 2))
|
||||
error("#else without a #if");
|
||||
mask ^= 1;
|
||||
} else if (!strcmp(tokc.str, "endif")) {
|
||||
if (!(mask & 2))
|
||||
error("#endif without a #if");
|
||||
mask >>= 2;
|
||||
} else {
|
||||
error("unsupported preprocessing directive");
|
||||
}
|
||||
if (skip_blanks() != '\n')
|
||||
error("extra characters on preprocessing line");
|
||||
skip_mask = mask;
|
||||
}
|
||||
|
||||
/* return -1 if invalid char */
|
||||
static int hex_to_num(int ch)
|
||||
{
|
||||
if (ch >= 'a' && ch <= 'f')
|
||||
return ch - 'a' + 10;
|
||||
else if (ch >= 'A' && ch <= 'F')
|
||||
return ch - 'A' + 10;
|
||||
else if (ch >= '0' && ch <= '9')
|
||||
return ch - '0';
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
void next(void)
|
||||
{
|
||||
again:
|
||||
tok_reset(&tokc);
|
||||
tokc.line_num = line_num;
|
||||
tokc.lines = 0;
|
||||
switch(ch) {
|
||||
case EOF:
|
||||
tokc.tok = TOK_EOF;
|
||||
if (skip_mask)
|
||||
error("missing #endif");
|
||||
break;
|
||||
case 'a' ... 'z':
|
||||
case 'A' ... 'Z':
|
||||
case '_':
|
||||
case '$':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
while ((ch >= 'a' && ch <= 'z') ||
|
||||
(ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9') ||
|
||||
(ch == '_' || ch == '$')) {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_IDENT;
|
||||
break;
|
||||
case '.':
|
||||
nextch();
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, '.');
|
||||
goto has_dot;
|
||||
}
|
||||
tokc.tok = '.';
|
||||
break;
|
||||
case '0':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
if (ch == 'x' || ch == 'X') {
|
||||
/* hexa */
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
while ((ch >= 'a' && ch <= 'f') ||
|
||||
(ch >= 'A' && ch <= 'F') ||
|
||||
(ch >= '0' && ch <= '9')) {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_NUM;
|
||||
break;
|
||||
}
|
||||
goto has_digit;
|
||||
|
||||
case '1' ... '9':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
has_digit:
|
||||
/* decimal */
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
if (ch == '.') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
has_dot:
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
if (ch == 'e' || ch == 'E') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
if (ch == '+' || ch == '-') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_NUM;
|
||||
break;
|
||||
case '`':
|
||||
{
|
||||
nextch();
|
||||
while (ch != '`' && ch != EOF) {
|
||||
if (ch == '\\') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
if (ch == EOF) {
|
||||
error("unexpected char after '\\'");
|
||||
}
|
||||
tok_add_ch(&tokc, ch);
|
||||
} else {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
nextch();
|
||||
tok_add_ch(&tokc, 0);
|
||||
tokc.tok = TOK_STR3;
|
||||
}
|
||||
break;
|
||||
case '\"':
|
||||
case '\'':
|
||||
{
|
||||
int n, i, c, hex_digit_count;
|
||||
int quote_ch;
|
||||
quote_ch = ch;
|
||||
nextch();
|
||||
while (ch != quote_ch && ch != EOF) {
|
||||
if (ch == '\\') {
|
||||
nextch();
|
||||
switch(ch) {
|
||||
case 'n':
|
||||
tok_add_ch(&tokc, '\n');
|
||||
nextch();
|
||||
break;
|
||||
case 'r':
|
||||
tok_add_ch(&tokc, '\r');
|
||||
nextch();
|
||||
break;
|
||||
case 't':
|
||||
tok_add_ch(&tokc, '\t');
|
||||
nextch();
|
||||
break;
|
||||
case 'v':
|
||||
tok_add_ch(&tokc, '\v');
|
||||
nextch();
|
||||
break;
|
||||
case '\"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
break;
|
||||
case '0' ... '7':
|
||||
n = 0;
|
||||
while (ch >= '0' && ch <= '7') {
|
||||
n = n * 8 + (ch - '0');
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, n);
|
||||
break;
|
||||
case 'x':
|
||||
case 'u':
|
||||
if (ch == 'x')
|
||||
hex_digit_count = 2;
|
||||
else
|
||||
hex_digit_count = 4;
|
||||
nextch();
|
||||
n = 0;
|
||||
for(i = 0; i < hex_digit_count; i++) {
|
||||
c = hex_to_num(ch);
|
||||
if (c < 0)
|
||||
error("unexpected char after '\\x'");
|
||||
n = n * 16 + c;
|
||||
nextch();
|
||||
}
|
||||
if (n >= 256)
|
||||
error("unicode is currently unsupported");
|
||||
tok_add_ch(&tokc, n);
|
||||
break;
|
||||
|
||||
default:
|
||||
error("unexpected char after '\\'");
|
||||
}
|
||||
} else {
|
||||
/* XXX: should refuse embedded newlines */
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
nextch();
|
||||
tok_add_ch(&tokc, 0);
|
||||
if (quote_ch == '\'')
|
||||
tokc.tok = TOK_STR1;
|
||||
else
|
||||
tokc.tok = TOK_STR2;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
nextch();
|
||||
if (ch == '/') {
|
||||
tok_add_ch(&tokc, '/');
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
while (ch != '\n' && ch != EOF) {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_LCOM;
|
||||
} else if (ch == '*') {
|
||||
int last;
|
||||
tok_add_ch(&tokc, '/');
|
||||
tok_add_ch(&tokc, ch);
|
||||
last = 0;
|
||||
for(;;) {
|
||||
nextch();
|
||||
if (ch == EOF)
|
||||
error("unterminated comment");
|
||||
if (ch == '\n')
|
||||
tokc.lines++;
|
||||
tok_add_ch(&tokc, ch);
|
||||
if (last == '*' && ch == '/')
|
||||
break;
|
||||
last = ch;
|
||||
}
|
||||
nextch();
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_COM;
|
||||
} else {
|
||||
tokc.tok = '/';
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
parse_directive();
|
||||
goto again;
|
||||
case '\n':
|
||||
/* adjust line number */
|
||||
tokc.line_num--;
|
||||
tokc.lines++;
|
||||
/* fall thru */
|
||||
default:
|
||||
tokc.tok = ch;
|
||||
nextch();
|
||||
break;
|
||||
}
|
||||
if (skip_mask & 1)
|
||||
goto again;
|
||||
}
|
||||
|
||||
void print_tok(FILE *f, JSToken *tt)
|
||||
{
|
||||
/* keep output lines in sync with input lines */
|
||||
while (output_line_num < tt->line_num) {
|
||||
putc('\n', f);
|
||||
output_line_num++;
|
||||
}
|
||||
|
||||
switch(tt->tok) {
|
||||
case TOK_IDENT:
|
||||
case TOK_COM:
|
||||
case TOK_LCOM:
|
||||
fprintf(f, "%s", tt->str);
|
||||
break;
|
||||
case TOK_NUM:
|
||||
{
|
||||
unsigned long a;
|
||||
char *p;
|
||||
a = strtoul(tt->str, &p, 0);
|
||||
if (*p == '\0' && a <= 0x7fffffff) {
|
||||
/* must be an integer */
|
||||
fprintf(f, "%d", (int)a);
|
||||
} else {
|
||||
fprintf(f, "%s", tt->str);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TOK_STR3:
|
||||
fprintf(f, "`%s`", tt->str);
|
||||
break;
|
||||
case TOK_STR1:
|
||||
case TOK_STR2:
|
||||
{
|
||||
int i, c, quote_ch;
|
||||
if (tt->tok == TOK_STR1)
|
||||
quote_ch = '\'';
|
||||
else
|
||||
quote_ch = '\"';
|
||||
fprintf(f, "%c", quote_ch);
|
||||
for(i = 0; i < tt->len - 1; i++) {
|
||||
c = (uint8_t)tt->str[i];
|
||||
switch(c) {
|
||||
case '\r':
|
||||
fprintf(f, "\\r");
|
||||
break;
|
||||
case '\n':
|
||||
fprintf(f, "\\n");
|
||||
break;
|
||||
case '\t':
|
||||
fprintf(f, "\\t");
|
||||
break;
|
||||
case '\v':
|
||||
fprintf(f, "\\v");
|
||||
break;
|
||||
case '\"':
|
||||
case '\'':
|
||||
if (c == quote_ch)
|
||||
fprintf(f, "\\%c", c);
|
||||
else
|
||||
fprintf(f, "%c", c);
|
||||
break;
|
||||
case '\\':
|
||||
fprintf(f, "\\\\");
|
||||
break;
|
||||
default:
|
||||
/* XXX: no utf-8 support! */
|
||||
if (c >= 32 && c <= 255) {
|
||||
fprintf(f, "%c", c);
|
||||
} else if (c <= 255)
|
||||
fprintf(f, "\\x%02x", c);
|
||||
else
|
||||
fprintf(f, "\\u%04x", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(f, "%c", quote_ch);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (tokc.tok >= 256)
|
||||
error("unsupported token in print_tok: %d", tt->tok);
|
||||
fprintf(f, "%c", tt->tok);
|
||||
break;
|
||||
}
|
||||
output_line_num += tt->lines;
|
||||
}
|
||||
|
||||
/* check if token pasting could occur */
|
||||
static BOOL compat_token(int c1, int c2)
|
||||
{
|
||||
if ((c1 == TOK_IDENT || c1 == TOK_NUM) &&
|
||||
(c2 == TOK_IDENT || c2 == TOK_NUM))
|
||||
return FALSE;
|
||||
|
||||
if ((c1 == c2 && strchr("+-<>&|=*/.", c1))
|
||||
|| (c2 == '=' && strchr("+-<>&|!*/^%", c1))
|
||||
|| (c1 == '=' && c2 == '>')
|
||||
|| (c1 == '/' && c2 == '*')
|
||||
|| (c1 == '.' && c2 == TOK_NUM)
|
||||
|| (c1 == TOK_NUM && c2 == '.'))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void js_compress(const char *filename, const char *outfilename,
|
||||
BOOL do_strip, BOOL keep_header)
|
||||
{
|
||||
FILE *outfile;
|
||||
int ltok, seen_space;
|
||||
|
||||
line_num = 1;
|
||||
infile = fopen(filename, "rb");
|
||||
if (!infile) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
output_line_num = 1;
|
||||
outfile = fopen(outfilename, "wb");
|
||||
if (!outfile) {
|
||||
perror(outfilename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
nextch();
|
||||
next();
|
||||
ltok = 0;
|
||||
seen_space = 0;
|
||||
if (do_strip) {
|
||||
if (keep_header) {
|
||||
while (tokc.tok == ' ' ||
|
||||
tokc.tok == '\n' ||
|
||||
tokc.tok == '\t' ||
|
||||
tokc.tok == '\v' ||
|
||||
tokc.tok == '\b' ||
|
||||
tokc.tok == '\f') {
|
||||
seen_space = 1;
|
||||
next();
|
||||
}
|
||||
if (tokc.tok == TOK_COM) {
|
||||
print_tok(outfile, &tokc);
|
||||
//fprintf(outfile, "\n");
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
if (tokc.tok == TOK_EOF)
|
||||
break;
|
||||
if (tokc.tok == ' ' ||
|
||||
tokc.tok == '\r' ||
|
||||
tokc.tok == '\t' ||
|
||||
tokc.tok == '\v' ||
|
||||
tokc.tok == '\b' ||
|
||||
tokc.tok == '\f' ||
|
||||
tokc.tok == TOK_LCOM ||
|
||||
tokc.tok == TOK_COM) {
|
||||
/* don't print spaces or comments */
|
||||
seen_space = 1;
|
||||
} else if (tokc.tok == TOK_STR3) {
|
||||
print_tok(outfile, &tokc);
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
} else if (tokc.tok == TOK_STR1 || tokc.tok == TOK_STR2) {
|
||||
int count, i;
|
||||
/* find the optimal quote char */
|
||||
count = 0;
|
||||
for(i = 0; i < tokc.len; i++) {
|
||||
if (tokc.str[i] == '\'')
|
||||
count++;
|
||||
else if (tokc.str[i] == '\"')
|
||||
count--;
|
||||
}
|
||||
if (count > 0)
|
||||
tokc.tok = TOK_STR2;
|
||||
else if (count < 0)
|
||||
tokc.tok = TOK_STR1;
|
||||
print_tok(outfile, &tokc);
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
} else {
|
||||
if (seen_space && !compat_token(ltok, tokc.tok)) {
|
||||
fprintf(outfile, " ");
|
||||
}
|
||||
print_tok(outfile, &tokc);
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
}
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
/* just handle preprocessing */
|
||||
while (tokc.tok != TOK_EOF) {
|
||||
print_tok(outfile, &tokc);
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
fclose(outfile);
|
||||
fclose(infile);
|
||||
}
|
||||
|
||||
#define HASH_SIZE 30011
|
||||
#define MATCH_LEN_MIN 3
|
||||
#define MATCH_LEN_MAX (4 + 63)
|
||||
#define DIST_MAX 65535
|
||||
|
||||
static int find_longest_match(int *pdist, const uint8_t *src, int src_len,
|
||||
const int *hash_next, int cur_pos)
|
||||
{
|
||||
int pos, i, match_len, match_pos, pos_min, len_max;
|
||||
|
||||
len_max = min_int(src_len - cur_pos, MATCH_LEN_MAX);
|
||||
match_len = 0;
|
||||
match_pos = 0;
|
||||
pos_min = max_int(cur_pos - DIST_MAX - 1, 0);
|
||||
pos = hash_next[cur_pos];
|
||||
while (pos >= pos_min) {
|
||||
for(i = 0; i < len_max; i++) {
|
||||
if (src[cur_pos + i] != src[pos + i])
|
||||
break;
|
||||
}
|
||||
if (i > match_len) {
|
||||
match_len = i;
|
||||
match_pos = pos;
|
||||
}
|
||||
pos = hash_next[pos];
|
||||
}
|
||||
*pdist = cur_pos - match_pos - 1;
|
||||
return match_len;
|
||||
}
|
||||
|
||||
int lz_compress(uint8_t **pdst, const uint8_t *src, int src_len)
|
||||
{
|
||||
int *hash_table, *hash_next;
|
||||
uint32_t h, v;
|
||||
int i, dist, len, len1, dist1;
|
||||
uint8_t *dst, *q;
|
||||
|
||||
/* build the hash table */
|
||||
|
||||
hash_table = malloc(sizeof(hash_table[0]) * HASH_SIZE);
|
||||
for(i = 0; i < HASH_SIZE; i++)
|
||||
hash_table[i] = -1;
|
||||
hash_next = malloc(sizeof(hash_next[0]) * src_len);
|
||||
for(i = 0; i < src_len; i++)
|
||||
hash_next[i] = -1;
|
||||
|
||||
for(i = 0; i < src_len - MATCH_LEN_MIN + 1; i++) {
|
||||
h = ((src[i] << 16) | (src[i + 1] << 8) | src[i + 2]) % HASH_SIZE;
|
||||
hash_next[i] = hash_table[h];
|
||||
hash_table[h] = i;
|
||||
}
|
||||
for(;i < src_len; i++) {
|
||||
hash_next[i] = -1;
|
||||
}
|
||||
free(hash_table);
|
||||
|
||||
dst = malloc(src_len + 4); /* never larger than the source */
|
||||
q = dst;
|
||||
*q++ = src_len >> 24;
|
||||
*q++ = src_len >> 16;
|
||||
*q++ = src_len >> 8;
|
||||
*q++ = src_len >> 0;
|
||||
/* compress */
|
||||
i = 0;
|
||||
while (i < src_len) {
|
||||
if (src[i] >= 128)
|
||||
return -1;
|
||||
len = find_longest_match(&dist, src, src_len, hash_next, i);
|
||||
if (len >= MATCH_LEN_MIN) {
|
||||
/* heuristic: see if better length just after */
|
||||
len1 = find_longest_match(&dist1, src, src_len, hash_next, i + 1);
|
||||
if (len1 > len)
|
||||
goto no_match;
|
||||
}
|
||||
if (len < MATCH_LEN_MIN) {
|
||||
no_match:
|
||||
*q++ = src[i];
|
||||
i++;
|
||||
} else if (len <= (3 + 15) && dist < (1 << 10)) {
|
||||
v = 0x8000 | ((len - 3) << 10) | dist;
|
||||
*q++ = v >> 8;
|
||||
*q++ = v;
|
||||
i += len;
|
||||
} else if (len >= 4 && len <= (4 + 63) && dist < (1 << 16)) {
|
||||
v = 0xc00000 | ((len - 4) << 16) | dist;
|
||||
*q++ = v >> 16;
|
||||
*q++ = v >> 8;
|
||||
*q++ = v;
|
||||
i += len;
|
||||
} else {
|
||||
goto no_match;
|
||||
}
|
||||
}
|
||||
free(hash_next);
|
||||
*pdst = dst;
|
||||
return q - dst;
|
||||
}
|
||||
|
||||
static int load_file(uint8_t **pbuf, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
uint8_t *buf;
|
||||
int buf_len;
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
buf_len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
buf = malloc(buf_len + 1);
|
||||
fread(buf, 1, buf_len, f);
|
||||
buf[buf_len] = '\0';
|
||||
fclose(f);
|
||||
*pbuf = buf;
|
||||
return buf_len;
|
||||
}
|
||||
|
||||
static void save_file(const char *filename, const uint8_t *buf, int buf_len)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
fwrite(buf, 1, buf_len, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void save_c_source(const char *filename, const uint8_t *buf, int buf_len,
|
||||
const char *var_name)
|
||||
{
|
||||
FILE *f;
|
||||
int i;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(f, "/* This file is automatically generated - do not edit */\n\n");
|
||||
fprintf(f, "const uint8_t %s[] = {\n", var_name);
|
||||
for(i = 0; i < buf_len; i++) {
|
||||
fprintf(f, " 0x%02x,", buf[i]);
|
||||
if ((i % 8) == 7 || (i == buf_len - 1))
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fprintf(f, "};\n");
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#define DEFAULT_OUTPUT_FILENAME "out.js"
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("jscompress version 1.0 Copyright (c) 2008-2018 Fabrice Bellard\n"
|
||||
"usage: jscompress [options] filename\n"
|
||||
"Javascript compressor\n"
|
||||
"\n"
|
||||
"-h print this help\n"
|
||||
"-n do not compress spaces\n"
|
||||
"-H keep the first comment\n"
|
||||
"-c compress to file\n"
|
||||
"-C name compress to C source ('name' is the variable name)\n"
|
||||
"-D symbol define preprocessor symbol\n"
|
||||
"-U symbol undefine preprocessor symbol\n"
|
||||
"-o outfile set the output filename (default=%s)\n",
|
||||
DEFAULT_OUTPUT_FILENAME);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c, do_strip, keep_header, compress;
|
||||
const char *out_filename, *c_var, *fname;
|
||||
char tmpfilename[1024];
|
||||
|
||||
do_strip = 1;
|
||||
keep_header = 0;
|
||||
out_filename = DEFAULT_OUTPUT_FILENAME;
|
||||
compress = 0;
|
||||
c_var = NULL;
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "hno:HcC:D:U:");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'h':
|
||||
help();
|
||||
break;
|
||||
case 'n':
|
||||
do_strip = 0;
|
||||
break;
|
||||
case 'o':
|
||||
out_filename = optarg;
|
||||
break;
|
||||
case 'H':
|
||||
keep_header = 1;
|
||||
break;
|
||||
case 'c':
|
||||
compress = 1;
|
||||
break;
|
||||
case 'C':
|
||||
c_var = optarg;
|
||||
compress = 1;
|
||||
break;
|
||||
case 'D':
|
||||
define_symbol(optarg);
|
||||
break;
|
||||
case 'U':
|
||||
undefine_symbol(optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (optind >= argc)
|
||||
help();
|
||||
|
||||
filename = argv[optind++];
|
||||
|
||||
if (compress) {
|
||||
#if defined(__ANDROID__)
|
||||
/* XXX: use another directory ? */
|
||||
snprintf(tmpfilename, sizeof(tmpfilename), "out.%d", getpid());
|
||||
#else
|
||||
snprintf(tmpfilename, sizeof(tmpfilename), "/tmp/out.%d", getpid());
|
||||
#endif
|
||||
fname = tmpfilename;
|
||||
} else {
|
||||
fname = out_filename;
|
||||
}
|
||||
js_compress(filename, fname, do_strip, keep_header);
|
||||
|
||||
if (compress) {
|
||||
uint8_t *buf1, *buf2;
|
||||
int buf1_len, buf2_len;
|
||||
|
||||
buf1_len = load_file(&buf1, fname);
|
||||
unlink(fname);
|
||||
buf2_len = lz_compress(&buf2, buf1, buf1_len);
|
||||
if (buf2_len < 0) {
|
||||
fprintf(stderr, "Could not compress file (UTF8 chars are forbidden)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (c_var) {
|
||||
save_c_source(out_filename, buf2, buf2_len, c_var);
|
||||
} else {
|
||||
save_file(out_filename, buf2, buf2_len);
|
||||
}
|
||||
free(buf1);
|
||||
free(buf2);
|
||||
}
|
||||
return 0;
|
||||
}
|
2
libbf.h
2
libbf.h
@ -27,7 +27,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#if INTPTR_MAX >= INT64_MAX
|
||||
#define LIMB_LOG2_BITS 6
|
||||
#else
|
||||
#define LIMB_LOG2_BITS 5
|
||||
|
26
libregexp.c
26
libregexp.c
@ -75,7 +75,7 @@ typedef struct {
|
||||
int capture_count;
|
||||
int total_capture_count; /* -1 = not computed yet */
|
||||
int has_named_captures; /* -1 = don't know, 0 = no, 1 = yes */
|
||||
void *mem_opaque;
|
||||
void *opaque;
|
||||
DynBuf group_names;
|
||||
union {
|
||||
char error_msg[TMP_BUF_SIZE];
|
||||
@ -230,7 +230,7 @@ static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c)
|
||||
invert = c & 1;
|
||||
c_pt = char_range_table[c >> 1];
|
||||
len = *c_pt++;
|
||||
cr_init(cr, s->mem_opaque, lre_realloc);
|
||||
cr_init(cr, s->opaque, lre_realloc);
|
||||
for(i = 0; i < len * 2; i++) {
|
||||
if (cr_add_point(cr, c_pt[i]))
|
||||
goto fail;
|
||||
@ -625,7 +625,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
||||
p++;
|
||||
q = name;
|
||||
while (is_unicode_char(*p)) {
|
||||
if ((q - name) > sizeof(name) - 1)
|
||||
if ((q - name) >= sizeof(name) - 1)
|
||||
goto unknown_property_name;
|
||||
*q++ = *p++;
|
||||
}
|
||||
@ -634,7 +634,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
||||
if (*p == '=') {
|
||||
p++;
|
||||
while (is_unicode_char(*p)) {
|
||||
if ((q - value) > sizeof(value) - 1)
|
||||
if ((q - value) >= sizeof(value) - 1)
|
||||
return re_parse_error(s, "unknown unicode property value");
|
||||
*q++ = *p++;
|
||||
}
|
||||
@ -651,7 +651,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
||||
} else if (!strcmp(name, "Script_Extensions") || !strcmp(name, "scx")) {
|
||||
script_ext = TRUE;
|
||||
do_script:
|
||||
cr_init(cr, s->mem_opaque, lre_realloc);
|
||||
cr_init(cr, s->opaque, lre_realloc);
|
||||
ret = unicode_script(cr, value, script_ext);
|
||||
if (ret) {
|
||||
cr_free(cr);
|
||||
@ -661,7 +661,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
||||
goto out_of_memory;
|
||||
}
|
||||
} else if (!strcmp(name, "General_Category") || !strcmp(name, "gc")) {
|
||||
cr_init(cr, s->mem_opaque, lre_realloc);
|
||||
cr_init(cr, s->opaque, lre_realloc);
|
||||
ret = unicode_general_category(cr, value);
|
||||
if (ret) {
|
||||
cr_free(cr);
|
||||
@ -671,7 +671,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
||||
goto out_of_memory;
|
||||
}
|
||||
} else if (value[0] == '\0') {
|
||||
cr_init(cr, s->mem_opaque, lre_realloc);
|
||||
cr_init(cr, s->opaque, lre_realloc);
|
||||
ret = unicode_general_category(cr, name);
|
||||
if (ret == -1) {
|
||||
cr_free(cr);
|
||||
@ -864,7 +864,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
|
||||
CharRange cr1_s, *cr1 = &cr1_s;
|
||||
BOOL invert;
|
||||
|
||||
cr_init(cr, s->mem_opaque, lre_realloc);
|
||||
cr_init(cr, s->opaque, lre_realloc);
|
||||
p = *pp;
|
||||
p++; /* skip '[' */
|
||||
invert = FALSE;
|
||||
@ -1147,9 +1147,13 @@ static int re_parse_captures(REParseState *s, int *phas_named_captures,
|
||||
}
|
||||
}
|
||||
capture_index++;
|
||||
if (capture_index >= CAPTURE_COUNT_MAX)
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
capture_index++;
|
||||
if (capture_index >= CAPTURE_COUNT_MAX)
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
@ -1163,6 +1167,7 @@ static int re_parse_captures(REParseState *s, int *phas_named_captures,
|
||||
break;
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (capture_name)
|
||||
return -1;
|
||||
else
|
||||
@ -1734,6 +1739,9 @@ static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir)
|
||||
{
|
||||
int start, len, pos;
|
||||
|
||||
if (lre_check_stack_overflow(s->opaque, 0))
|
||||
return re_parse_error(s, "stack overflow");
|
||||
|
||||
start = s->byte_code.size;
|
||||
if (re_parse_alternative(s, is_backward_dir))
|
||||
return -1;
|
||||
@ -1819,7 +1827,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
||||
BOOL is_sticky;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->mem_opaque = opaque;
|
||||
s->opaque = opaque;
|
||||
s->buf_ptr = (const uint8_t *)buf;
|
||||
s->buf_end = s->buf_ptr + buf_len;
|
||||
s->buf_start = s->buf_ptr;
|
||||
|
11
qjscalc.js
11
qjscalc.js
@ -2625,6 +2625,17 @@ function atanh(a)
|
||||
return 0.5 * log((1 + x) / (1 - x));
|
||||
}
|
||||
|
||||
function sigmoid(x)
|
||||
{
|
||||
x = Float(x);
|
||||
return 1 / (1 + exp(-x));
|
||||
}
|
||||
|
||||
function lerp(a, b, t)
|
||||
{
|
||||
return a + (b - a) * t;
|
||||
}
|
||||
|
||||
var idn = Matrix.idn;
|
||||
var diag = Matrix.diag;
|
||||
var trans = Matrix.trans;
|
||||
|
@ -113,6 +113,7 @@ DEF(caller, "caller")
|
||||
DEF(_eval_, "<eval>")
|
||||
DEF(_ret_, "<ret>")
|
||||
DEF(_var_, "<var>")
|
||||
DEF(_arg_var_, "<arg_var>")
|
||||
DEF(_with_, "<with>")
|
||||
DEF(lastIndex, "lastIndex")
|
||||
DEF(target, "target")
|
||||
|
@ -623,6 +623,97 @@ static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_NewString(ctx, str);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
static void setenv(const char *name, const char *value, int overwrite)
|
||||
{
|
||||
char *str;
|
||||
size_t name_len, value_len;
|
||||
name_len = strlen(name);
|
||||
value_len = strlen(value);
|
||||
str = malloc(name_len + 1 + value_len + 1);
|
||||
memcpy(str, name, name_len);
|
||||
str[name_len] = '=';
|
||||
memcpy(str + name_len + 1, value, value_len);
|
||||
str[name_len + 1 + value_len] = '\0';
|
||||
_putenv(str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
static void unsetenv(const char *name)
|
||||
{
|
||||
setenv(name, "", TRUE);
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
const char *name, *value;
|
||||
name = JS_ToCString(ctx, argv[0]);
|
||||
if (!name)
|
||||
return JS_EXCEPTION;
|
||||
value = JS_ToCString(ctx, argv[1]);
|
||||
if (!value) {
|
||||
JS_FreeCString(ctx, name);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
setenv(name, value, TRUE);
|
||||
JS_FreeCString(ctx, name);
|
||||
JS_FreeCString(ctx, value);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
const char *name;
|
||||
name = JS_ToCString(ctx, argv[0]);
|
||||
if (!name)
|
||||
return JS_EXCEPTION;
|
||||
unsetenv(name);
|
||||
JS_FreeCString(ctx, name);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
/* return an object containing the list of the available environment
|
||||
variables. */
|
||||
static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
char **envp;
|
||||
const char *name, *p, *value;
|
||||
JSValue obj;
|
||||
uint32_t idx;
|
||||
size_t name_len;
|
||||
JSAtom atom;
|
||||
int ret;
|
||||
|
||||
obj = JS_NewObject(ctx);
|
||||
if (JS_IsException(obj))
|
||||
return JS_EXCEPTION;
|
||||
envp = environ;
|
||||
for(idx = 0; envp[idx] != NULL; idx++) {
|
||||
name = envp[idx];
|
||||
p = strchr(name, '=');
|
||||
name_len = p - name;
|
||||
if (!p)
|
||||
continue;
|
||||
value = p + 1;
|
||||
atom = JS_NewAtomLen(ctx, name, name_len);
|
||||
if (atom == JS_ATOM_NULL)
|
||||
goto fail;
|
||||
ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value),
|
||||
JS_PROP_C_W_E);
|
||||
JS_FreeAtom(ctx, atom);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
return obj;
|
||||
fail:
|
||||
JS_FreeValue(ctx, obj);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
@ -1395,6 +1486,9 @@ static const JSCFunctionListEntry js_std_funcs[] = {
|
||||
JS_CFUNC_DEF("evalScript", 1, js_evalScript ),
|
||||
JS_CFUNC_DEF("loadScript", 1, js_loadScript ),
|
||||
JS_CFUNC_DEF("getenv", 1, js_std_getenv ),
|
||||
JS_CFUNC_DEF("setenv", 1, js_std_setenv ),
|
||||
JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ),
|
||||
JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ),
|
||||
JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
|
||||
JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
|
||||
JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
|
||||
@ -1412,7 +1506,6 @@ static const JSCFunctionListEntry js_std_funcs[] = {
|
||||
JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ),
|
||||
JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ),
|
||||
JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE),
|
||||
/* setenv, ... */
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_std_file_proto_funcs[] = {
|
||||
|
@ -114,7 +114,7 @@ DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
|
||||
DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
|
||||
DEF( return_async, 1, 1, 0, none)
|
||||
DEF( throw, 1, 1, 0, none)
|
||||
DEF( throw_var, 6, 0, 0, atom_u8)
|
||||
DEF( throw_error, 6, 0, 0, atom_u8)
|
||||
DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
|
||||
DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
|
||||
DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
|
||||
@ -205,16 +205,15 @@ DEF( for_of_start, 1, 1, 3, none)
|
||||
DEF(for_await_of_start, 1, 1, 3, none)
|
||||
DEF( for_in_next, 1, 1, 3, none)
|
||||
DEF( for_of_next, 2, 3, 5, u8)
|
||||
DEF(for_await_of_next, 1, 3, 4, none)
|
||||
DEF(iterator_check_object, 1, 1, 1, none)
|
||||
DEF(iterator_get_value_done, 1, 1, 2, none)
|
||||
DEF( iterator_close, 1, 3, 0, none)
|
||||
DEF(iterator_close_return, 1, 4, 4, none)
|
||||
DEF(async_iterator_close, 1, 3, 2, none)
|
||||
DEF(async_iterator_next, 1, 4, 4, none)
|
||||
DEF(async_iterator_get, 2, 4, 5, u8)
|
||||
DEF( iterator_next, 1, 4, 4, none)
|
||||
DEF( iterator_call, 2, 4, 5, u8)
|
||||
DEF( initial_yield, 1, 0, 0, none)
|
||||
DEF( yield, 1, 1, 2, none)
|
||||
DEF( yield_star, 1, 2, 2, none)
|
||||
DEF( yield_star, 1, 1, 2, none)
|
||||
DEF(async_yield_star, 1, 1, 2, none)
|
||||
DEF( await, 1, 1, 1, none)
|
||||
|
||||
@ -266,8 +265,6 @@ DEF( nop, 1, 0, 0, none)
|
||||
|
||||
/* temporary opcodes: never emitted in the final bytecode */
|
||||
|
||||
def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */
|
||||
|
||||
def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
|
||||
|
||||
|
@ -776,7 +776,10 @@ JS_BOOL JS_DetectModule(const char *input, size_t input_len);
|
||||
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
|
||||
JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
|
||||
const char *filename, int eval_flags);
|
||||
JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj);
|
||||
/* same as JS_Eval() but with an explicit 'this_obj' parameter */
|
||||
JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
|
||||
const char *input, size_t input_len,
|
||||
const char *filename, int eval_flags);
|
||||
JSValue JS_GetGlobalObject(JSContext *ctx);
|
||||
int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj);
|
||||
int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
|
||||
@ -885,7 +888,9 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
|
||||
#define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */
|
||||
JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
||||
int flags);
|
||||
|
||||
/* instantiate and evaluate a bytecode function. Only used when
|
||||
reading a script or module with JS_ReadObject() */
|
||||
JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj);
|
||||
/* load the dependencies of the module 'obj'. Useful when JS_ReadObject()
|
||||
returns a module. */
|
||||
int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
|
||||
|
77
release.sh
77
release.sh
@ -6,30 +6,23 @@ set -e
|
||||
version=`cat VERSION`
|
||||
|
||||
if [ "$1" = "-h" ] ; then
|
||||
echo "release.sh [all]"
|
||||
echo "release.sh [release_list]"
|
||||
echo ""
|
||||
echo "all: build all the archives. Otherwise only build the quickjs source archive."
|
||||
echo "release_list: extras binary win_binary quickjs"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
extras="no"
|
||||
binary="no"
|
||||
quickjs="no"
|
||||
release_list="extras binary win_binary quickjs"
|
||||
|
||||
if [ "$1" = "all" ] ; then
|
||||
extras="yes"
|
||||
binary="yes"
|
||||
quickjs="yes"
|
||||
elif [ "$1" = "binary" ] ; then
|
||||
binary="yes"
|
||||
else
|
||||
quickjs="yes"
|
||||
if [ "$1" != "" ] ; then
|
||||
release_list="$1"
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# extras
|
||||
|
||||
if [ "$extras" = "yes" ] ; then
|
||||
if echo $release_list | grep -w -q extras ; then
|
||||
|
||||
d="quickjs-${version}"
|
||||
name="quickjs-extras-${version}"
|
||||
@ -46,10 +39,58 @@ cp -a tests/bench-v8 $outdir/tests
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# binary release
|
||||
# Windows binary release
|
||||
|
||||
if [ "$binary" = "yes" ] ; then
|
||||
if echo $release_list | grep -w -q win_binary ; then
|
||||
|
||||
# win64
|
||||
|
||||
dlldir=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
|
||||
cross_prefix="x86_64-w64-mingw32-"
|
||||
d="quickjs-win-x86_64-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
make CONFIG_WIN32=y qjs.exe
|
||||
cp qjs.exe $outdir
|
||||
${cross_prefix}strip $outdir/qjs.exe
|
||||
cp $dlldir/libwinpthread-1.dll $outdir
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
make CONFIG_WIN32=y clean
|
||||
|
||||
# win32
|
||||
|
||||
dlldir=/usr/i686-w64-mingw32/sys-root/mingw/bin
|
||||
cross_prefix="i686-w64-mingw32-"
|
||||
d="quickjs-win-i686-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
make clean
|
||||
make CONFIG_WIN32=y clean
|
||||
|
||||
make CONFIG_WIN32=y CONFIG_M32=y qjs.exe
|
||||
cp qjs.exe $outdir
|
||||
${cross_prefix}strip $outdir/qjs.exe
|
||||
cp $dlldir/libwinpthread-1.dll $outdir
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# Linux binary release
|
||||
|
||||
if echo $release_list | grep -w -q binary ; then
|
||||
|
||||
make clean
|
||||
make CONFIG_WIN32=y clean
|
||||
make -j4 qjs run-test262
|
||||
make -j4 CONFIG_M32=y qjs32 run-test262-32
|
||||
strip qjs run-test262 qjs32 run-test262-32
|
||||
@ -80,7 +121,7 @@ fi
|
||||
#################################################"
|
||||
# quickjs
|
||||
|
||||
if [ "$quickjs" = "yes" ] ; then
|
||||
if echo $release_list | grep -w -q quickjs ; then
|
||||
|
||||
make build_doc
|
||||
|
||||
@ -98,7 +139,7 @@ cp Makefile VERSION TODO Changelog readme.txt release.sh unicode_download.sh \
|
||||
libregexp.c libregexp.h libregexp-opcode.h \
|
||||
libunicode.c libunicode.h libunicode-table.h \
|
||||
libbf.c libbf.h \
|
||||
jscompress.c unicode_gen.c unicode_gen_def.h \
|
||||
unicode_gen.c unicode_gen_def.h \
|
||||
run-test262.c test262o.conf test262.conf \
|
||||
test262o_errors.txt test262_errors.txt \
|
||||
$outdir
|
||||
|
17
test262.conf
17
test262.conf
@ -49,9 +49,12 @@ testdir=test262/test
|
||||
# skipped features are tagged as such to avoid warnings
|
||||
|
||||
AggregateError
|
||||
align-detached-buffer-semantics-with-web-reality
|
||||
arbitrary-module-namespace-names=skip
|
||||
Array.prototype.flat
|
||||
Array.prototype.flatMap
|
||||
Array.prototype.flatten
|
||||
Array.prototype.item=skip
|
||||
Array.prototype.values
|
||||
ArrayBuffer
|
||||
arrow-function
|
||||
@ -82,7 +85,6 @@ DataView.prototype.getInt8
|
||||
DataView.prototype.getUint16
|
||||
DataView.prototype.getUint32
|
||||
DataView.prototype.setUint8
|
||||
default-arg
|
||||
default-parameters
|
||||
destructuring-assignment
|
||||
destructuring-binding
|
||||
@ -90,6 +92,7 @@ dynamic-import
|
||||
export-star-as-namespace-from-module
|
||||
FinalizationGroup=skip
|
||||
FinalizationRegistry=skip
|
||||
FinalizationRegistry.prototype.cleanupSome=skip
|
||||
Float32Array
|
||||
Float64Array
|
||||
for-in-order
|
||||
@ -99,10 +102,12 @@ globalThis
|
||||
hashbang
|
||||
host-gc-required=skip
|
||||
import.meta
|
||||
Int16Array
|
||||
Int32Array
|
||||
Int8Array
|
||||
IsHTMLDDA
|
||||
json-superset
|
||||
legacy-regexp=skip
|
||||
let
|
||||
logical-assignment-operators
|
||||
Map
|
||||
@ -114,6 +119,7 @@ Object.fromEntries
|
||||
Object.is
|
||||
optional-catch-binding
|
||||
optional-chaining
|
||||
Promise
|
||||
Promise.allSettled
|
||||
Promise.any
|
||||
Promise.prototype.finally
|
||||
@ -135,6 +141,7 @@ string-trimming
|
||||
String.fromCodePoint
|
||||
String.prototype.endsWith
|
||||
String.prototype.includes
|
||||
String.prototype.item=skip
|
||||
String.prototype.matchAll
|
||||
String.prototype.replaceAll
|
||||
String.prototype.trimEnd
|
||||
@ -159,14 +166,19 @@ tail-call-optimization=skip
|
||||
template
|
||||
top-level-await=skip
|
||||
TypedArray
|
||||
TypedArray.prototype.item=skip
|
||||
u180e
|
||||
Uint16Array
|
||||
Uint32Array
|
||||
Uint8Array
|
||||
Uint8ClampedArray
|
||||
WeakMap
|
||||
WeakRef=skip
|
||||
WeakSet
|
||||
well-formed-json-stringify
|
||||
__getter__
|
||||
__proto__
|
||||
__setter__
|
||||
|
||||
[exclude]
|
||||
# list excluded tests and directories here
|
||||
@ -183,8 +195,5 @@ test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
|
||||
#test262/test/built-ins/RegExp/CharacterClassEscapes/
|
||||
#test262/test/built-ins/RegExp/property-escapes/
|
||||
|
||||
# invalid tests
|
||||
test262/test/language/module-code/verify-dfs.js
|
||||
|
||||
[tests]
|
||||
# list test files or use config.testdir
|
||||
|
@ -1,30 +1,51 @@
|
||||
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: Test262Error: Expected a ReferenceError but got a ReferenceError
|
||||
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError
|
||||
test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
|
||||
test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: strict mode: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
|
||||
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name
|
||||
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name
|
||||
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
|
||||
test262/test/language/expressions/async-arrow-function/eval-var-scope-syntax-err.js:49: TypeError: $DONE() not called
|
||||
test262/test/language/expressions/async-function/named-eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
|
||||
test262/test/language/expressions/async-function/nameless-eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
|
||||
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
|
||||
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
|
||||
test262/test/language/expressions/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name
|
||||
test262/test/language/expressions/class/elements/grammar-private-field-optional-chaining.js:26: strict mode: SyntaxError: expecting field name
|
||||
test262/test/built-ins/TypedArray/prototype/every/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/every/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/every/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/every/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/filter/BigInt/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/filter/BigInt/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/filter/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/filter/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/findIndex/BigInt/predicate-may-detach-buffer.js:36: Test262Error: throws a TypeError getting a value from the detached buffer Expected a TypeError to be thrown but no exception was thrown at all (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/findIndex/BigInt/predicate-may-detach-buffer.js:36: strict mode: Test262Error: throws a TypeError getting a value from the detached buffer Expected a TypeError to be thrown but no exception was thrown at all (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/forEach/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/forEach/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/forEach/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/forEach/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/map/BigInt/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/map/BigInt/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/map/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/map/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduce/BigInt/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduce/BigInt/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduce/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduce/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduceRight/BigInt/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduceRight/BigInt/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduceRight/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduceRight/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/some/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/some/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/some/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/some/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:37: Test262Error: (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:37: strict mode: Test262Error: (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:38: Test262Error: (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:38: strict mode: Test262Error: (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/BigInt/index-prop-desc.js:21: Test262Error: Expected SameValue(«43», «42») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/BigInt/index-prop-desc.js:21: strict mode: Test262Error: Expected SameValue(«43», «42») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/index-prop-desc.js:22: Test262Error: Expected SameValue(«43», «42») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/index-prop-desc.js:22: strict mode: Test262Error: Expected SameValue(«43», «42») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:36: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:34: TypeError: cannot convert bigint to number (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:36: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
|
||||
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
|
||||
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
|
||||
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
|
||||
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
|
||||
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
|
||||
test262/test/language/expressions/object/method-definition/async-meth-eval-var-scope-syntax-err.js:36: TypeError: $DONE() not called
|
||||
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
|
||||
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
|
||||
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined
|
||||
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined
|
||||
test262/test/language/statements/async-function/eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
|
||||
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
|
||||
test262/test/language/statements/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name
|
||||
test262/test/language/statements/class/elements/grammar-private-field-optional-chaining.js:26: strict mode: SyntaxError: expecting field name
|
||||
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
|
||||
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
|
||||
|
@ -17,6 +17,22 @@ function assert(actual, expected, message) {
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function assert_throws(expected_error, func)
|
||||
{
|
||||
var err = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
err = true;
|
||||
if (!(e instanceof expected_error)) {
|
||||
throw Error("unexpected exception type");
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
throw Error("expected exception");
|
||||
}
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
@ -48,6 +64,13 @@ function test_function()
|
||||
r = my_func.apply(null, [1, 2]);
|
||||
assert(r, 3, "apply");
|
||||
|
||||
r = (function () { return 1; }).apply(null, undefined);
|
||||
assert(r, 1);
|
||||
|
||||
assert_throws(TypeError, (function() {
|
||||
Reflect.apply((function () { return 1; }), null, undefined);
|
||||
}));
|
||||
|
||||
r = new Function("a", "b", "return a + b;");
|
||||
assert(r(2,3), 5, "function");
|
||||
|
||||
|
@ -15,6 +15,22 @@ function assert(actual, expected, message) {
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function assert_throws(expected_error, func)
|
||||
{
|
||||
var err = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
err = true;
|
||||
if (!(e instanceof expected_error)) {
|
||||
throw Error("unexpected exception type");
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
throw Error("expected exception");
|
||||
}
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
@ -233,8 +249,13 @@ function test_delete()
|
||||
|
||||
function test_prototype()
|
||||
{
|
||||
function f() { }
|
||||
var f = function f() { };
|
||||
assert(f.prototype.constructor, f, "prototype");
|
||||
|
||||
var g = function g() { };
|
||||
/* QuickJS bug */
|
||||
Object.defineProperty(g, "prototype", { writable: false });
|
||||
assert(g.prototype.constructor, g, "prototype");
|
||||
}
|
||||
|
||||
function test_arguments()
|
||||
@ -376,6 +397,135 @@ function test_spread()
|
||||
assert(Object.getOwnPropertyNames(x).toString(), "0,length");
|
||||
}
|
||||
|
||||
function test_function_length()
|
||||
{
|
||||
assert( ((a, b = 1, c) => {}).length, 1);
|
||||
assert( (([a,b]) => {}).length, 1);
|
||||
assert( (({a,b}) => {}).length, 1);
|
||||
assert( ((c, [a,b] = 1, d) => {}).length, 1);
|
||||
}
|
||||
|
||||
function test_argument_scope()
|
||||
{
|
||||
var f;
|
||||
var c = "global";
|
||||
|
||||
f = function(a = eval("var arguments")) {};
|
||||
assert_throws(SyntaxError, f);
|
||||
|
||||
f = function(a = eval("1"), b = arguments[0]) { return b; };
|
||||
assert(f(12), 12);
|
||||
|
||||
f = function(a, b = arguments[0]) { return b; };
|
||||
assert(f(12), 12);
|
||||
|
||||
f = function(a, b = () => arguments) { return b; };
|
||||
assert(f(12)()[0], 12);
|
||||
|
||||
f = function(a = eval("1"), b = () => arguments) { return b; };
|
||||
assert(f(12)()[0], 12);
|
||||
|
||||
(function() {
|
||||
"use strict";
|
||||
f = function(a = this) { return a; };
|
||||
assert(f.call(123), 123);
|
||||
|
||||
f = function f(a = f) { return a; };
|
||||
assert(f(), f);
|
||||
|
||||
f = function f(a = eval("f")) { return a; };
|
||||
assert(f(), f);
|
||||
})();
|
||||
|
||||
f = (a = eval("var c = 1"), probe = () => c) => {
|
||||
var c = 2;
|
||||
assert(c, 2);
|
||||
assert(probe(), 1);
|
||||
}
|
||||
f();
|
||||
|
||||
f = (a = eval("var arguments = 1"), probe = () => arguments) => {
|
||||
var arguments = 2;
|
||||
assert(arguments, 2);
|
||||
assert(probe(), 1);
|
||||
}
|
||||
f();
|
||||
|
||||
f = function f(a = eval("var c = 1"), b = c, probe = () => c) {
|
||||
assert(b, 1);
|
||||
assert(c, 1);
|
||||
assert(probe(), 1)
|
||||
}
|
||||
f();
|
||||
|
||||
assert(c, "global");
|
||||
f = function f(a, b = c, probe = () => c) {
|
||||
eval("var c = 1");
|
||||
assert(c, 1);
|
||||
assert(b, "global");
|
||||
assert(probe(), "global")
|
||||
}
|
||||
f();
|
||||
assert(c, "global");
|
||||
|
||||
f = function f(a = eval("var c = 1"), probe = (d = eval("c")) => d) {
|
||||
assert(probe(), 1)
|
||||
}
|
||||
f();
|
||||
}
|
||||
|
||||
function test_function_expr_name()
|
||||
{
|
||||
var f;
|
||||
|
||||
/* non strict mode test : assignment to the function name silently
|
||||
fails */
|
||||
|
||||
f = function myfunc() {
|
||||
myfunc = 1;
|
||||
return myfunc;
|
||||
};
|
||||
assert(f(), f);
|
||||
|
||||
f = function myfunc() {
|
||||
myfunc = 1;
|
||||
(() => {
|
||||
myfunc = 1;
|
||||
})();
|
||||
return myfunc;
|
||||
};
|
||||
assert(f(), f);
|
||||
|
||||
f = function myfunc() {
|
||||
eval("myfunc = 1");
|
||||
return myfunc;
|
||||
};
|
||||
assert(f(), f);
|
||||
|
||||
/* strict mode test : assignment to the function name raises a
|
||||
TypeError exception */
|
||||
|
||||
f = function myfunc() {
|
||||
"use strict";
|
||||
myfunc = 1;
|
||||
};
|
||||
assert_throws(TypeError, f);
|
||||
|
||||
f = function myfunc() {
|
||||
"use strict";
|
||||
(() => {
|
||||
myfunc = 1;
|
||||
})();
|
||||
};
|
||||
assert_throws(TypeError, f);
|
||||
|
||||
f = function myfunc() {
|
||||
"use strict";
|
||||
eval("myfunc = 1");
|
||||
};
|
||||
assert_throws(TypeError, f);
|
||||
}
|
||||
|
||||
test_op1();
|
||||
test_cvt();
|
||||
test_eq();
|
||||
@ -392,3 +542,6 @@ test_regexp_skip();
|
||||
test_labels();
|
||||
test_destructuring();
|
||||
test_spread();
|
||||
test_function_length();
|
||||
test_argument_scope();
|
||||
test_function_expr_name();
|
||||
|
Loading…
Reference in New Issue
Block a user