2020-03-16 release

This commit is contained in:
bellard 2020-09-06 19:02:03 +02:00
parent 0e8fffd4de
commit 383e2b06c8
26 changed files with 2352 additions and 2020 deletions

View file

@ -1,3 +1,14 @@
2020-03-16:
- reworked error handling in std and os libraries: suppressed I/O
exceptions in std FILE functions and return a positive errno value
when it is explicit
- output exception messages to stderr
- added std.loadFile(), std.strerror(), std.FILE.prototype.tello()
- added JS_GetRuntimeOpaque(), JS_SetRuntimeOpaque(), JS_NewUint32()
- updated to Unicode 13.0.0
- misc bug fixes
2020-01-19: 2020-01-19:
- keep CONFIG_BIGNUM in the makefile - keep CONFIG_BIGNUM in the makefile

5
TODO
View file

@ -73,5 +73,6 @@ REPL:
Test262o: 0/11262 errors, 463 excluded Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch) Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
Test262: 17/69942 errors, 855 excluded, 581 skipped Test262: 22/70040 errors, 860 excluded, 581 skipped
test262 commit: 28b4fcca4b1b1d278dfe0cc0e69c7d9d59b31aab test262 commit: 25c9e334d301944537215caba1d7f44319f3e0da

View file

@ -1 +1 @@
2020-01-19 2020-03-16

View file

@ -1,8 +1,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html> <html>
<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ --> <!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Javascript Bignum Extensions</title> <title>Javascript Bignum Extensions</title>
<meta name="description" content="Javascript Bignum Extensions"> <meta name="description" content="Javascript Bignum Extensions">
@ -10,6 +9,7 @@
<meta name="resource-type" content="document"> <meta name="resource-type" content="document">
<meta name="distribution" content="global"> <meta name="distribution" content="global">
<meta name="Generator" content="makeinfo"> <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"> <link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css"> <style type="text/css">
<!-- <!--
@ -121,7 +121,7 @@ changes were done in order to simplify the implementation.
<ul> <ul>
<li> <code>with operators from</code> is not supported. Operator overloading is always enabled. <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 the of the <code>Symbol.operatorSet</code> property is done. This property is typically added in the prototype of each object. </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>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.
@ -194,7 +194,7 @@ raised if <em>a &lt; 0</em>.
<h3 class="section">4.1 Introduction</h3> <h3 class="section">4.1 Introduction</h3>
<p>This extension adds the <code>BigFloat</code> primitive type. The <p>This extension adds the <code>BigFloat</code> primitive type. The
<code>BigFloat</code> type represents floating point numbers are in base 2 <code>BigFloat</code> type represents floating point numbers in base 2
with the IEEE 754 semantics. A floating with the IEEE 754 semantics. A floating
point number is represented as a sign, mantissa and exponent. The 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> special values <code>NaN</code>, <code>+/-Infinity</code>, <code>+0</code> and <code>-0</code>
@ -216,15 +216,13 @@ point environment is used.
<code>RNDN</code> (&ldquo;round to nearest with ties to even&rdquo;)<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>. The status flags of the global environment cannot be <code>RNDN</code> (&ldquo;round to nearest with ties to even&rdquo;)<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>. The status flags of the global environment cannot be
read<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>. The precision of the global environment is 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 <code>BigFloatEnv.prec</code>. The number of exponent bits of the global
environment is <code>BigFloatEnv.expBits</code>. If <code>BigFloatEnv.expBits</code> is environment is <code>BigFloatEnv.expBits</code>. The global environment
strictly smaller than the maximum allowed number of exponent bits subnormal flag is set to <code>true</code>.
(<code>BigFloatEnv.expBitsMax</code>), then the global environment subnormal
flag is set to <code>true</code>. Otherwise it is set to <code>false</code>;
</p> </p>
<p>For example, <code>prec = 53</code> and <code> expBits = 11</code> give exactly <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. The 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 default precision is <code>prec = 113</code> and <code> expBits = 15</code> (IEEE
754 128 bit floating point). 754 128 bit floating point format).
</p> </p>
<p>The global floating point environment can only be modified temporarily <p>The global floating point environment can only be modified temporarily
when calling a function (see <code>BigFloatEnv.setPrec</code>). Hence a when calling a function (see <code>BigFloatEnv.setPrec</code>). Hence a
@ -433,9 +431,8 @@ environment. The initial value is <code>113</code>.
</dd> </dd>
<dt><code>expBits</code></dt> <dt><code>expBits</code></dt>
<dd><p>Getter. Return the exponent size in bits of the global floating point <dd><p>Getter. Return the exponent size in bits of the global floating point
environment assuming an IEEE 754 representation. If <code>expBits &lt; environment assuming an IEEE 754 representation. The initial value is
expBitsMax</code>, then subnormal numbers are supported. The initial value <code>15</code>.
is <code>15</code>.
</p> </p>
</dd> </dd>
<dt><code>setPrec(f, p[, e])</code></dt> <dt><code>setPrec(f, p[, e])</code></dt>
@ -608,7 +605,7 @@ Number value.
<p>It returns <code>0m</code> if no parameter is provided. Otherwise the first <p>It returns <code>0m</code> if no parameter is provided. Otherwise the first
parameter is converted to a bigdecimal by using ToString(). Hence parameter is converted to a bigdecimal by using ToString(). Hence
Number value are not converted to their exact numerical value as Number values are not converted to their exact numerical value as
BigDecimal. BigDecimal.
</p> </p>
<a name="Properties-of-the-BigDecimal-object"></a> <a name="Properties-of-the-BigDecimal-object"></a>
@ -702,12 +699,12 @@ always represented as BigFloat.
</li><li> The logical xor operator is still available with the <code>^^</code> operator. </li><li> The logical xor operator is still available with the <code>^^</code> operator.
</li><li> The integer division operator can be overloaded by modifying the corresponding operator in <code>BigInt.prototype.[[OperatorSet]]</code>.
</li><li> The integer power operator with a non zero negative exponent can be overloaded by modifying the corresponding operator in <code>BigInt.prototype.[[OperatorSet]]</code>.
</li><li> The modulo operator (<code>%</code>) returns the Euclidian remainder (always positive) instead of the truncated remainder. </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> </li></ul>
<div class="footnote"> <div class="footnote">

Binary file not shown.

View file

@ -57,7 +57,7 @@ More precisely, the following modifications were made:
@item @code{with operators from} is not supported. Operator overloading is always enabled. @item @code{with operators from} is not supported. Operator overloading is always enabled.
@item The dispatch is not based on a static @code{[[OperatorSet]]} field in all instances. Instead, a dynamic lookup the of the @code{Symbol.operatorSet} property is done. This property is typically added in the prototype of each object. @item The dispatch is not based on a static @code{[[OperatorSet]]} field in all instances. Instead, a dynamic lookup of the @code{Symbol.operatorSet} property is done. This property is typically added in the prototype of each object.
@item @code{Operators.create(...dictionaries)} is used to create a new OperatorSet object. The @code{Operators} function is supported as an helper to be closer to the TC39 proposal. @item @code{Operators.create(...dictionaries)} is used to create a new OperatorSet object. The @code{Operators} function is supported as an helper to be closer to the TC39 proposal.
@ -119,7 +119,7 @@ Return the number of trailing zeros in the two's complement binary representatio
@section Introduction @section Introduction
This extension adds the @code{BigFloat} primitive type. The This extension adds the @code{BigFloat} primitive type. The
@code{BigFloat} type represents floating point numbers are in base 2 @code{BigFloat} type represents floating point numbers in base 2
with the IEEE 754 semantics. A floating with the IEEE 754 semantics. A floating
point number is represented as a sign, mantissa and exponent. The point number is represented as a sign, mantissa and exponent. The
special values @code{NaN}, @code{+/-Infinity}, @code{+0} and @code{-0} special values @code{NaN}, @code{+/-Infinity}, @code{+0} and @code{-0}
@ -143,15 +143,13 @@ explicit.}. The status flags of the global environment cannot be
read@footnote{The rationale is to avoid side effects for the built-in read@footnote{The rationale is to avoid side effects for the built-in
operators.}. The precision of the global environment is operators.}. The precision of the global environment is
@code{BigFloatEnv.prec}. The number of exponent bits of the global @code{BigFloatEnv.prec}. The number of exponent bits of the global
environment is @code{BigFloatEnv.expBits}. If @code{BigFloatEnv.expBits} is environment is @code{BigFloatEnv.expBits}. The global environment
strictly smaller than the maximum allowed number of exponent bits subnormal flag is set to @code{true}.
(@code{BigFloatEnv.expBitsMax}), then the global environment subnormal
flag is set to @code{true}. Otherwise it is set to @code{false};
For example, @code{prec = 53} and @code{ expBits = 11} give exactly For example, @code{prec = 53} and @code{ expBits = 11} exactly give
the same precision as the IEEE 754 64 bit floating point. The the same precision as the IEEE 754 64 bit floating point format. The
default precision is @code{prec = 113} and @code{ expBits = 15} (IEEE default precision is @code{prec = 113} and @code{ expBits = 15} (IEEE
754 128 bit floating point). 754 128 bit floating point format).
The global floating point environment can only be modified temporarily The global floating point environment can only be modified temporarily
when calling a function (see @code{BigFloatEnv.setPrec}). Hence a when calling a function (see @code{BigFloatEnv.setPrec}). Hence a
@ -345,9 +343,8 @@ environment. The initial value is @code{113}.
@item expBits @item expBits
Getter. Return the exponent size in bits of the global floating point Getter. Return the exponent size in bits of the global floating point
environment assuming an IEEE 754 representation. If @code{expBits < environment assuming an IEEE 754 representation. The initial value is
expBitsMax}, then subnormal numbers are supported. The initial value @code{15}.
is @code{15}.
@item setPrec(f, p[, e]) @item setPrec(f, p[, e])
Set the precision of the global floating point environment to @code{p} Set the precision of the global floating point environment to @code{p}
@ -492,7 +489,7 @@ BigDecimal literals are decimal floating point numbers with a trailing
It returns @code{0m} if no parameter is provided. Otherwise the first It returns @code{0m} if no parameter is provided. Otherwise the first
parameter is converted to a bigdecimal by using ToString(). Hence parameter is converted to a bigdecimal by using ToString(). Hence
Number value are not converted to their exact numerical value as Number values are not converted to their exact numerical value as
BigDecimal. BigDecimal.
@subsection Properties of the @code{BigDecimal} object @subsection Properties of the @code{BigDecimal} object
@ -581,12 +578,12 @@ The following changes are made to the Javascript semantics:
@item The logical xor operator is still available with the @code{^^} operator. @item The logical xor operator is still available with the @code{^^} operator.
@item The integer division operator can be overloaded by modifying the corresponding operator in @code{BigInt.prototype.[[OperatorSet]]}.
@item The integer power operator with a non zero negative exponent can be overloaded by modifying the corresponding operator in @code{BigInt.prototype.[[OperatorSet]]}.
@item The modulo operator (@code{%}) returns the Euclidian remainder (always positive) instead of the truncated remainder. @item The modulo operator (@code{%}) returns the Euclidian remainder (always positive) instead of the truncated remainder.
@item The integer division operator can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
@item The integer power operator with a non zero negative exponent can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
@end itemize @end itemize
@bye @bye

View file

@ -1,8 +1,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html> <html>
<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ --> <!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>QuickJS Javascript Engine</title> <title>QuickJS Javascript Engine</title>
<meta name="description" content="QuickJS Javascript Engine"> <meta name="description" content="QuickJS Javascript Engine">
@ -10,6 +9,7 @@
<meta name="resource-type" content="document"> <meta name="resource-type" content="document">
<meta name="distribution" content="global"> <meta name="distribution" content="global">
<meta name="Generator" content="makeinfo"> <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"> <link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css"> <style type="text/css">
<!-- <!--
@ -519,50 +519,39 @@ optional properties:
<dd><p>Evaluate the file <code>filename</code> as a script (global eval). <dd><p>Evaluate the file <code>filename</code> as a script (global eval).
</p> </p>
</dd> </dd>
<dt><code>Error(errno)</code></dt> <dt><code>loadFile(filename)</code></dt>
<dd> <dd><p>Load the file <code>filename</code> and return it as a string assuming UTF-8
<p><code>std.Error</code> constructor. Error instances contain the field encoding. Return <code>null</code> in case of I/O error.
<code>errno</code> (error code) and <code>message</code> (result of
<code>std.Error.strerror(errno)</code>).
</p>
<p>The constructor contains the following fields:
</p>
<dl compact="compact">
<dt><code>EINVAL</code></dt>
<dt><code>EIO</code></dt>
<dt><code>EACCES</code></dt>
<dt><code>EEXIST</code></dt>
<dt><code>ENOSPC</code></dt>
<dt><code>ENOSYS</code></dt>
<dt><code>EBUSY</code></dt>
<dt><code>ENOENT</code></dt>
<dt><code>EPERM</code></dt>
<dt><code>EPIPE</code></dt>
<dd><p>Integer value of common errors (additional error codes may be defined).
</p></dd>
<dt><code>strerror(errno)</code></dt>
<dd><p>Return a string that describes the error <code>errno</code>.
</p></dd>
</dl>
</dd>
<dt><code>open(filename, flags)</code></dt>
<dd><p>Open a file (wrapper to the libc <code>fopen()</code>). Throws
<code>std.Error</code> in case of I/O error.
</p> </p>
</dd> </dd>
<dt><code>popen(command, flags)</code></dt> <dt><code>open(filename, flags, errorObj = undefined)</code></dt>
<dd><p>Open a process by creating a pipe (wrapper to the libc <code>popen()</code>). Throws <dd><p>Open a file (wrapper to the libc <code>fopen()</code>). Return the FILE
<code>std.Error</code> in case of I/O error. object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
undefined, set its <code>errno</code> property to the error code or to 0 if
no error occured.
</p> </p>
</dd> </dd>
<dt><code>fdopen(fd, flags)</code></dt> <dt><code>popen(command, flags, errorObj = undefined)</code></dt>
<dd><p>Open a process by creating a pipe (wrapper to the libc
<code>popen()</code>). Return the FILE
object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
undefined, set its <code>errno</code> property to the error code or to 0 if
no error occured.
</p>
</dd>
<dt><code>fdopen(fd, flags, errorObj = undefined)</code></dt>
<dd><p>Open a file from a file handle (wrapper to the libc <dd><p>Open a file from a file handle (wrapper to the libc
<code>fdopen()</code>). Throws <code>std.Error</code> in case of I/O error. <code>fdopen()</code>). Return the FILE
object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
undefined, set its <code>errno</code> property to the error code or to 0 if
no error occured.
</p> </p>
</dd> </dd>
<dt><code>tmpfile()</code></dt> <dt><code>tmpfile(errorObj = undefined)</code></dt>
<dd><p>Open a temporary file. Throws <code>std.Error</code> in case of I/O error. <dd><p>Open a temporary file. Return the FILE
object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
undefined, set its <code>errno</code> property to the error code or to 0 if
no error occured.
</p> </p>
</dd> </dd>
<dt><code>puts(str)</code></dt> <dt><code>puts(str)</code></dt>
@ -589,6 +578,29 @@ optional properties:
<dd><p>Constants for seek(). <dd><p>Constants for seek().
</p> </p>
</dd> </dd>
<dt><code>Error</code></dt>
<dd>
<p>Enumeration object containing the integer value of common errors
(additional error codes may be defined):
</p>
<dl compact="compact">
<dt><code>EINVAL</code></dt>
<dt><code>EIO</code></dt>
<dt><code>EACCES</code></dt>
<dt><code>EEXIST</code></dt>
<dt><code>ENOSPC</code></dt>
<dt><code>ENOSYS</code></dt>
<dt><code>EBUSY</code></dt>
<dt><code>ENOENT</code></dt>
<dt><code>EPERM</code></dt>
<dt><code>EPIPE</code></dt>
</dl>
</dd>
<dt><code>strerror(errno)</code></dt>
<dd><p>Return a string that describes the error <code>errno</code>.
</p>
</dd>
<dt><code>gc()</code></dt> <dt><code>gc()</code></dt>
<dd><p>Manually invoke the cycle removal algorithm. The cycle removal <dd><p>Manually invoke the cycle removal algorithm. The cycle removal
algorithm is automatically started when needed, so this function is algorithm is automatically started when needed, so this function is
@ -614,12 +626,14 @@ optional properties:
</p> </p>
</dd> </dd>
<dt><code>full</code></dt> <dt><code>full</code></dt>
<dd><p>Boolean (default = false). If true, return the an object contains <dd>
<p>Boolean (default = false). If true, return the an object contains
the properties <code>response</code> (response content), the properties <code>response</code> (response content),
<code>responseHeaders</code> (headers separated by CRLF), <code>status</code> <code>responseHeaders</code> (headers separated by CRLF), <code>status</code>
(status code). If <code>full</code> is false, only the response is (status code). <code>response</code> is <code>null</code> is case of protocol or
returned if the status is between 200 and 299. Otherwise an network error. If <code>full</code> is false, only the response is
<code>std.Error</code> exception is raised. returned if the status is between 200 and 299. Otherwise <code>null</code>
is returned.
</p> </p>
</dd> </dd>
</dl> </dl>
@ -631,7 +645,7 @@ optional properties:
</p> </p>
<dl compact="compact"> <dl compact="compact">
<dt><code>close()</code></dt> <dt><code>close()</code></dt>
<dd><p>Close the file. <dd><p>Close the file. Return 0 if OK or <code>-errno</code> in case of I/O error.
</p></dd> </p></dd>
<dt><code>puts(str)</code></dt> <dt><code>puts(str)</code></dt>
<dd><p>Outputs the string with the UTF-8 encoding. <dd><p>Outputs the string with the UTF-8 encoding.
@ -643,17 +657,27 @@ optional properties:
<dd><p>Flush the buffered file. <dd><p>Flush the buffered file.
</p></dd> </p></dd>
<dt><code>seek(offset, whence)</code></dt> <dt><code>seek(offset, whence)</code></dt>
<dd><p>Seek to a give file position (whence is <code>std.SEEK_*</code>). Throws a <dd><p>Seek to a give file position (whence is
<code>std.Error</code> in case of I/O error. <code>std.SEEK_*</code>). <code>offset</code> can be a number or a bigint. Return
0 if OK or <code>-errno</code> in case of I/O error.
</p></dd> </p></dd>
<dt><code>tell()</code></dt> <dt><code>tell()</code></dt>
<dd><p>Return the current file position. <dd><p>Return the current file position.
</p></dd> </p></dd>
<dt><code>tello()</code></dt>
<dd><p>Return the current file position as a bigint.
</p></dd>
<dt><code>eof()</code></dt> <dt><code>eof()</code></dt>
<dd><p>Return true if end of file. <dd><p>Return true if end of file.
</p></dd> </p></dd>
<dt><code>fileno()</code></dt> <dt><code>fileno()</code></dt>
<dd><p>Return the associated OS handle. <dd><p>Return the associated OS handle.
</p></dd>
<dt><code>error()</code></dt>
<dd><p>Return true if there was an error.
</p></dd>
<dt><code>clearerr()</code></dt>
<dd><p>Clear the error indication.
</p> </p>
</dd> </dd>
<dt><code>read(buffer, position, length)</code></dt> <dt><code>read(buffer, position, length)</code></dt>
@ -727,7 +751,9 @@ error code.
</p> </p>
</dd> </dd>
<dt><code>seek(fd, offset, whence)</code></dt> <dt><code>seek(fd, offset, whence)</code></dt>
<dd><p>Seek in the file. Use <code>std.SEEK_*</code> for <code>whence</code>. <dd><p>Seek in the file. Use <code>std.SEEK_*</code> for
<code>whence</code>. <code>offset</code> is either a number or a bigint. If
<code>offset</code> is a bigint, a bigint is returned too.
</p> </p>
</dd> </dd>
<dt><code>read(fd, buffer, offset, length)</code></dt> <dt><code>read(fd, buffer, offset, length)</code></dt>
@ -755,11 +781,11 @@ Return the number of written bytes or &lt; 0 if error.
</p> </p>
</dd> </dd>
<dt><code>remove(filename)</code></dt> <dt><code>remove(filename)</code></dt>
<dd><p>Remove a file. Return 0 if OK or &lt; 0 if error. <dd><p>Remove a file. Return 0 if OK or <code>-errno</code>.
</p> </p>
</dd> </dd>
<dt><code>rename(oldname, newname)</code></dt> <dt><code>rename(oldname, newname)</code></dt>
<dd><p>Rename a file. Return 0 if OK or &lt; 0 if error. <dd><p>Rename a file. Return 0 if OK or <code>-errno</code>.
</p> </p>
</dd> </dd>
<dt><code>realpath(path)</code></dt> <dt><code>realpath(path)</code></dt>
@ -773,11 +799,11 @@ and <code>err</code> the error code.
</p> </p>
</dd> </dd>
<dt><code>chdir(path)</code></dt> <dt><code>chdir(path)</code></dt>
<dd><p>Change the current directory. Return the error code. <dd><p>Change the current directory. Return 0 if OK or <code>-errno</code>.
</p> </p>
</dd> </dd>
<dt><code>mkdir(path, mode = 0o777)</code></dt> <dt><code>mkdir(path, mode = 0o777)</code></dt>
<dd><p>Create a directory at <code>path</code>. Return the error code. <dd><p>Create a directory at <code>path</code>. Return 0 if OK or <code>-errno</code>.
</p> </p>
</dd> </dd>
<dt><code>stat(path)</code></dt> <dt><code>stat(path)</code></dt>
@ -809,11 +835,11 @@ itself.
</dd> </dd>
<dt><code>utimes(path, atime, mtime)</code></dt> <dt><code>utimes(path, atime, mtime)</code></dt>
<dd><p>Change the access and modification times of the file <code>path</code>. The <dd><p>Change the access and modification times of the file <code>path</code>. The
times are specified in milliseconds since 1970. times are specified in milliseconds since 1970. Return 0 if OK or <code>-errno</code>.
</p> </p>
</dd> </dd>
<dt><code>symlink(target, linkpath)</code></dt> <dt><code>symlink(target, linkpath)</code></dt>
<dd><p>Create a link at <code>linkpath</code> containing the string <code>target</code>. <dd><p>Create a link at <code>linkpath</code> containing the string <code>target</code>. Return 0 if OK or <code>-errno</code>.
</p> </p>
</dd> </dd>
<dt><code>readlink(path)</code></dt> <dt><code>readlink(path)</code></dt>
@ -896,7 +922,8 @@ object containing optional parameters:
</dd> </dd>
<dt><code>waitpid(pid, options)</code></dt> <dt><code>waitpid(pid, options)</code></dt>
<dd><p><code>waitpid</code> Unix system call. Return the array <code>[ret, status]</code>. <dd><p><code>waitpid</code> Unix system call. Return the array <code>[ret,
status]</code>. <code>ret</code> contains <code>-errno</code> in case of error.
</p> </p>
</dd> </dd>
<dt><code>WNOHANG</code></dt> <dt><code>WNOHANG</code></dt>

Binary file not shown.

View file

@ -373,44 +373,35 @@ optional properties:
@item loadScript(filename) @item loadScript(filename)
Evaluate the file @code{filename} as a script (global eval). Evaluate the file @code{filename} as a script (global eval).
@item Error(errno) @item loadFile(filename)
Load the file @code{filename} and return it as a string assuming UTF-8
encoding. Return @code{null} in case of I/O error.
@code{std.Error} constructor. Error instances contain the field @item open(filename, flags, errorObj = undefined)
@code{errno} (error code) and @code{message} (result of Open a file (wrapper to the libc @code{fopen()}). Return the FILE
@code{std.Error.strerror(errno)}). object or @code{null} in case of I/O error. If @code{errorObj} is not
undefined, set its @code{errno} property to the error code or to 0 if
no error occured.
The constructor contains the following fields: @item popen(command, flags, errorObj = undefined)
Open a process by creating a pipe (wrapper to the libc
@code{popen()}). Return the FILE
object or @code{null} in case of I/O error. If @code{errorObj} is not
undefined, set its @code{errno} property to the error code or to 0 if
no error occured.
@table @code @item fdopen(fd, flags, errorObj = undefined)
@item EINVAL
@item EIO
@item EACCES
@item EEXIST
@item ENOSPC
@item ENOSYS
@item EBUSY
@item ENOENT
@item EPERM
@item EPIPE
Integer value of common errors (additional error codes may be defined).
@item strerror(errno)
Return a string that describes the error @code{errno}.
@end table
@item open(filename, flags)
Open a file (wrapper to the libc @code{fopen()}). Throws
@code{std.Error} in case of I/O error.
@item popen(command, flags)
Open a process by creating a pipe (wrapper to the libc @code{popen()}). Throws
@code{std.Error} in case of I/O error.
@item fdopen(fd, flags)
Open a file from a file handle (wrapper to the libc Open a file from a file handle (wrapper to the libc
@code{fdopen()}). Throws @code{std.Error} in case of I/O error. @code{fdopen()}). Return the FILE
object or @code{null} in case of I/O error. If @code{errorObj} is not
undefined, set its @code{errno} property to the error code or to 0 if
no error occured.
@item tmpfile() @item tmpfile(errorObj = undefined)
Open a temporary file. Throws @code{std.Error} in case of I/O error. Open a temporary file. Return the FILE
object or @code{null} in case of I/O error. If @code{errorObj} is not
undefined, set its @code{errno} property to the error code or to 0 if
no error occured.
@item puts(str) @item puts(str)
Equivalent to @code{std.out.puts(str)}. Equivalent to @code{std.out.puts(str)}.
@ -431,6 +422,27 @@ Wrappers to the libc file @code{stdin}, @code{stdout}, @code{stderr}.
@item SEEK_END @item SEEK_END
Constants for seek(). Constants for seek().
@item Error
Enumeration object containing the integer value of common errors
(additional error codes may be defined):
@table @code
@item EINVAL
@item EIO
@item EACCES
@item EEXIST
@item ENOSPC
@item ENOSYS
@item EBUSY
@item ENOENT
@item EPERM
@item EPIPE
@end table
@item strerror(errno)
Return a string that describes the error @code{errno}.
@item gc() @item gc()
Manually invoke the cycle removal algorithm. The cycle removal Manually invoke the cycle removal algorithm. The cycle removal
algorithm is automatically started when needed, so this function is algorithm is automatically started when needed, so this function is
@ -453,12 +465,14 @@ optional properties:
to be UTF-8 encoded. to be UTF-8 encoded.
@item full @item full
Boolean (default = false). If true, return the an object contains Boolean (default = false). If true, return the an object contains
the properties @code{response} (response content), the properties @code{response} (response content),
@code{responseHeaders} (headers separated by CRLF), @code{status} @code{responseHeaders} (headers separated by CRLF), @code{status}
(status code). If @code{full} is false, only the response is (status code). @code{response} is @code{null} is case of protocol or
returned if the status is between 200 and 299. Otherwise an network error. If @code{full} is false, only the response is
@code{std.Error} exception is raised. returned if the status is between 200 and 299. Otherwise @code{null}
is returned.
@end table @end table
@ -468,7 +482,7 @@ FILE prototype:
@table @code @table @code
@item close() @item close()
Close the file. Close the file. Return 0 if OK or @code{-errno} in case of I/O error.
@item puts(str) @item puts(str)
Outputs the string with the UTF-8 encoding. Outputs the string with the UTF-8 encoding.
@item printf(fmt, ...args) @item printf(fmt, ...args)
@ -476,14 +490,21 @@ Formatted printf, same formats as the libc printf.
@item flush() @item flush()
Flush the buffered file. Flush the buffered file.
@item seek(offset, whence) @item seek(offset, whence)
Seek to a give file position (whence is @code{std.SEEK_*}). Throws a Seek to a give file position (whence is
@code{std.Error} in case of I/O error. @code{std.SEEK_*}). @code{offset} can be a number or a bigint. Return
0 if OK or @code{-errno} in case of I/O error.
@item tell() @item tell()
Return the current file position. Return the current file position.
@item tello()
Return the current file position as a bigint.
@item eof() @item eof()
Return true if end of file. Return true if end of file.
@item fileno() @item fileno()
Return the associated OS handle. Return the associated OS handle.
@item error()
Return true if there was an error.
@item clearerr()
Clear the error indication.
@item read(buffer, position, length) @item read(buffer, position, length)
Read @code{length} bytes from the file to the ArrayBuffer @code{buffer} at byte Read @code{length} bytes from the file to the ArrayBuffer @code{buffer} at byte
@ -545,7 +566,9 @@ POSIX open flags.
Close the file handle @code{fd}. Close the file handle @code{fd}.
@item seek(fd, offset, whence) @item seek(fd, offset, whence)
Seek in the file. Use @code{std.SEEK_*} for @code{whence}. Seek in the file. Use @code{std.SEEK_*} for
@code{whence}. @code{offset} is either a number or a bigint. If
@code{offset} is a bigint, a bigint is returned too.
@item read(fd, buffer, offset, length) @item read(fd, buffer, offset, length)
Read @code{length} bytes from the file handle @code{fd} to the Read @code{length} bytes from the file handle @code{fd} to the
@ -567,10 +590,10 @@ Return the TTY size as @code{[width, height]} or @code{null} if not available.
Set the TTY in raw mode. Set the TTY in raw mode.
@item remove(filename) @item remove(filename)
Remove a file. Return 0 if OK or < 0 if error. Remove a file. Return 0 if OK or @code{-errno}.
@item rename(oldname, newname) @item rename(oldname, newname)
Rename a file. Return 0 if OK or < 0 if error. Rename a file. Return 0 if OK or @code{-errno}.
@item realpath(path) @item realpath(path)
Return @code{[str, err]} where @code{str} is the canonicalized absolute Return @code{[str, err]} where @code{str} is the canonicalized absolute
@ -581,10 +604,10 @@ Return @code{[str, err]} where @code{str} is the current working directory
and @code{err} the error code. and @code{err} the error code.
@item chdir(path) @item chdir(path)
Change the current directory. Return the error code. Change the current directory. Return 0 if OK or @code{-errno}.
@item mkdir(path, mode = 0o777) @item mkdir(path, mode = 0o777)
Create a directory at @code{path}. Return the error code. Create a directory at @code{path}. Return 0 if OK or @code{-errno}.
@item stat(path) @item stat(path)
@item lstat(path) @item lstat(path)
@ -613,10 +636,10 @@ Constants to interpret the @code{mode} property returned by
@item utimes(path, atime, mtime) @item utimes(path, atime, mtime)
Change the access and modification times of the file @code{path}. The Change the access and modification times of the file @code{path}. The
times are specified in milliseconds since 1970. times are specified in milliseconds since 1970. Return 0 if OK or @code{-errno}.
@item symlink(target, linkpath) @item symlink(target, linkpath)
Create a link at @code{linkpath} containing the string @code{target}. Create a link at @code{linkpath} containing the string @code{target}. Return 0 if OK or @code{-errno}.
@item readlink(path) @item readlink(path)
Return @code{[str, err]} where @code{str} is the link target and @code{err} Return @code{[str, err]} where @code{str} is the link target and @code{err}
@ -685,7 +708,8 @@ object containing optional parameters:
@end table @end table
@item waitpid(pid, options) @item waitpid(pid, options)
@code{waitpid} Unix system call. Return the array @code{[ret, status]}. @code{waitpid} Unix system call. Return the array @code{[ret,
status]}. @code{ret} contains @code{-errno} in case of error.
@item WNOHANG @item WNOHANG
Constant for the @code{options} argument of @code{waitpid}. Constant for the @code{options} argument of @code{waitpid}.

47
libbf.c
View file

@ -2526,19 +2526,18 @@ fail:
return BF_ST_MEM_ERROR; return BF_ST_MEM_ERROR;
} }
/* The rounding mode is always BF_RNDZ. Return BF_ST_OVERFLOW if there /* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there
is an overflow and 0 otherwise. */ is an overflow and 0 otherwise. */
int bf_get_int32(int *pres, const bf_t *a, int flags) int bf_get_int32(int *pres, const bf_t *a, int flags)
{ {
uint32_t v; uint32_t v;
int ret; int ret;
if (a->expn >= BF_EXP_INF) { if (a->expn >= BF_EXP_INF) {
ret = 0; ret = BF_ST_INVALID_OP;
if (flags & BF_GET_INT_MOD) { if (flags & BF_GET_INT_MOD) {
v = 0; v = 0;
} else if (a->expn == BF_EXP_INF) { } else if (a->expn == BF_EXP_INF) {
v = (uint32_t)INT32_MAX + a->sign; v = (uint32_t)INT32_MAX + a->sign;
/* XXX: return overflow ? */
} else { } else {
v = INT32_MAX; v = INT32_MAX;
} }
@ -2551,7 +2550,7 @@ int bf_get_int32(int *pres, const bf_t *a, int flags)
v = -v; v = -v;
ret = 0; ret = 0;
} else if (!(flags & BF_GET_INT_MOD)) { } else if (!(flags & BF_GET_INT_MOD)) {
ret = BF_ST_OVERFLOW; ret = BF_ST_INVALID_OP;
if (a->sign) { if (a->sign) {
v = (uint32_t)INT32_MAX + 1; v = (uint32_t)INT32_MAX + 1;
if (a->expn == 32 && if (a->expn == 32 &&
@ -2571,14 +2570,14 @@ int bf_get_int32(int *pres, const bf_t *a, int flags)
return ret; return ret;
} }
/* The rounding mode is always BF_RNDZ. Return BF_ST_OVERFLOW if there /* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there
is an overflow and 0 otherwise. */ is an overflow and 0 otherwise. */
int bf_get_int64(int64_t *pres, const bf_t *a, int flags) int bf_get_int64(int64_t *pres, const bf_t *a, int flags)
{ {
uint64_t v; uint64_t v;
int ret; int ret;
if (a->expn >= BF_EXP_INF) { if (a->expn >= BF_EXP_INF) {
ret = 0; ret = BF_ST_INVALID_OP;
if (flags & BF_GET_INT_MOD) { if (flags & BF_GET_INT_MOD) {
v = 0; v = 0;
} else if (a->expn == BF_EXP_INF) { } else if (a->expn == BF_EXP_INF) {
@ -2603,7 +2602,7 @@ int bf_get_int64(int64_t *pres, const bf_t *a, int flags)
v = -v; v = -v;
ret = 0; ret = 0;
} else if (!(flags & BF_GET_INT_MOD)) { } else if (!(flags & BF_GET_INT_MOD)) {
ret = BF_ST_OVERFLOW; ret = BF_ST_INVALID_OP;
if (a->sign) { if (a->sign) {
uint64_t v1; uint64_t v1;
v = (uint64_t)INT64_MAX + 1; v = (uint64_t)INT64_MAX + 1;
@ -2632,6 +2631,40 @@ int bf_get_int64(int64_t *pres, const bf_t *a, int flags)
return ret; return ret;
} }
/* The rounding mode is always BF_RNDZ. Return BF_ST_INVALID_OP if there
is an overflow and 0 otherwise. */
int bf_get_uint64(uint64_t *pres, const bf_t *a)
{
uint64_t v;
int ret;
if (a->expn == BF_EXP_NAN) {
goto overflow;
} else if (a->expn <= 0) {
v = 0;
ret = 0;
} else if (a->sign) {
v = 0;
ret = BF_ST_INVALID_OP;
} else if (a->expn <= 64) {
#if LIMB_BITS == 32
if (a->expn <= 32)
v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
else
v = (((uint64_t)a->tab[a->len - 1] << 32) |
get_limbz(a, a->len - 2)) >> (64 - a->expn);
#else
v = a->tab[a->len - 1] >> (LIMB_BITS - a->expn);
#endif
ret = 0;
} else {
overflow:
v = UINT64_MAX;
ret = BF_ST_INVALID_OP;
}
*pres = v;
return ret;
}
/* base conversion from radix */ /* base conversion from radix */
static const uint8_t digits_per_limb_table[BF_RADIX_MAX - 1] = { static const uint8_t digits_per_limb_table[BF_RADIX_MAX - 1] = {

View file

@ -376,6 +376,7 @@ char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,
#define BF_GET_INT_MOD (1 << 0) #define BF_GET_INT_MOD (1 << 0)
int bf_get_int32(int *pres, const bf_t *a, int flags); int bf_get_int32(int *pres, const bf_t *a, int flags);
int bf_get_int64(int64_t *pres, const bf_t *a, int flags); int bf_get_int64(int64_t *pres, const bf_t *a, int flags);
int bf_get_uint64(uint64_t *pres, const bf_t *a);
/* the following functions are exported for testing only. */ /* the following functions are exported for testing only. */
void mp_print_str(const char *str, const limb_t *tab, limb_t n); void mp_print_str(const char *str, const limb_t *tab, limb_t n);

View file

@ -434,8 +434,9 @@ static int __attribute__((format(printf, 2, 3))) re_parse_error(REParseState *s,
return -1; return -1;
} }
/* Return -1 in case of overflow */ /* If allow_overflow is false, return -1 in case of
static int parse_digits(const uint8_t **pp) overflow. Otherwise return INT32_MAX. */
static int parse_digits(const uint8_t **pp, BOOL allow_overflow)
{ {
const uint8_t *p; const uint8_t *p;
uint64_t v; uint64_t v;
@ -448,8 +449,12 @@ static int parse_digits(const uint8_t **pp)
if (c < '0' || c > '9') if (c < '0' || c > '9')
break; break;
v = v * 10 + c - '0'; v = v * 10 + c - '0';
if (v >= INT32_MAX) if (v >= INT32_MAX) {
return -1; if (allow_overflow)
v = INT32_MAX;
else
return -1;
}
p++; p++;
} }
*pp = p; *pp = p;
@ -1225,14 +1230,27 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
re_emit_op(s, REOP_prev); re_emit_op(s, REOP_prev);
break; break;
case '{': case '{':
/* As an extension (see ES6 annex B), we accept '{' not if (s->is_utf16) {
followed by digits as a normal atom */ return re_parse_error(s, "syntax error");
if (!is_digit(p[1])) { } else if (!is_digit(p[1])) {
if (s->is_utf16) /* Annex B: we accept '{' not followed by digits as a
goto invalid_quant_count; normal atom */
goto parse_class_atom; goto parse_class_atom;
} else {
const uint8_t *p1 = p + 1;
/* Annex B: error if it is like a repetition count */
parse_digits(&p1, TRUE);
if (*p1 == ',') {
p1++;
if (is_digit(*p1)) {
parse_digits(&p1, TRUE);
}
}
if (*p1 != '}') {
goto parse_class_atom;
}
} }
/* fall tru */ /* fall thru */
case '*': case '*':
case '+': case '+':
case '?': case '?':
@ -1387,7 +1405,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
{ {
const uint8_t *q = ++p; const uint8_t *q = ++p;
c = parse_digits(&p); c = parse_digits(&p, FALSE);
if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) { if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) {
if (!s->is_utf16) { if (!s->is_utf16) {
/* Annex B.1.4: accept legacy octal */ /* Annex B.1.4: accept legacy octal */
@ -1484,32 +1502,38 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
quant_max = 1; quant_max = 1;
goto quantifier; goto quantifier;
case '{': case '{':
/* As an extension (see ES6 annex B), we accept '{' not {
followed by digits as a normal atom */ const uint8_t *p1 = p;
if (!is_digit(p[1])) { /* As an extension (see ES6 annex B), we accept '{' not
if (s->is_utf16) followed by digits as a normal atom */
goto invalid_quant_count; if (!is_digit(p[1])) {
break; if (s->is_utf16)
}
p++;
quant_min = parse_digits(&p);
if (quant_min < 0) {
invalid_quant_count:
return re_parse_error(s, "invalid repetition count");
}
quant_max = quant_min;
if (*p == ',') {
p++;
if (is_digit(*p)) {
quant_max = parse_digits(&p);
if (quant_max < 0 || quant_max < quant_min)
goto invalid_quant_count; goto invalid_quant_count;
} else { break;
quant_max = INT32_MAX; /* infinity */
} }
p++;
quant_min = parse_digits(&p, TRUE);
quant_max = quant_min;
if (*p == ',') {
p++;
if (is_digit(*p)) {
quant_max = parse_digits(&p, TRUE);
if (quant_max < quant_min) {
invalid_quant_count:
return re_parse_error(s, "invalid repetition count");
}
} else {
quant_max = INT32_MAX; /* infinity */
}
}
if (*p != '}' && !s->is_utf16) {
/* Annex B: normal atom if invalid '{' syntax */
p = p1;
break;
}
if (re_parse_expect(s, &p, '}'))
return -1;
} }
if (re_parse_expect(s, &p, '}'))
return -1;
quantifier: quantifier:
greedy = TRUE; greedy = TRUE;
if (*p == '?') { if (*p == '?') {

File diff suppressed because it is too large Load diff

View file

@ -224,17 +224,15 @@ static JSValue js_printf_internal(JSContext *ctx,
case 'X': case 'X':
if (i >= argc) if (i >= argc)
goto missing; goto missing;
if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
goto fail;
if (modsize > 0) { if (modsize > 0) {
if (JS_ToInt64(ctx, &int64_arg, argv[i++]))
goto fail;
q[1] = q[-1]; q[1] = q[-1];
q[-1] = q[0] = 'l'; q[-1] = q[0] = 'l';
q[2] = '\0'; q[2] = '\0';
dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg); dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg);
} else { } else {
if (JS_ToInt32(ctx, &int32_arg, argv[i++])) dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg);
goto fail;
dbuf_printf_fun(&dbuf, fmtbuf, int32_arg);
} }
break; break;
@ -369,6 +367,27 @@ static JSValue js_loadScript(JSContext *ctx, JSValueConst this_val,
return ret; return ret;
} }
/* load a file as a UTF-8 encoded string */
static JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
uint8_t *buf;
const char *filename;
JSValue ret;
size_t buf_len;
filename = JS_ToCString(ctx, argv[0]);
if (!filename)
return JS_EXCEPTION;
buf = js_load_file(ctx, &buf_len, filename);
JS_FreeCString(ctx, filename);
if (!buf)
return JS_NULL;
ret = JS_NewStringLen(ctx, (char *)buf, buf_len);
js_free(ctx, buf);
return ret;
}
typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx, typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,
const char *module_name); const char *module_name);
@ -633,30 +652,14 @@ static void js_std_file_finalizer(JSRuntime *rt, JSValue val)
} }
} }
static JSValue js_new_std_error(JSContext *ctx, int err) static ssize_t js_get_errno(ssize_t ret)
{ {
JSValue obj; if (ret == -1)
/* XXX: could add a specific Error prototype */ ret = -errno;
obj = JS_NewError(ctx); return ret;
JS_DefinePropertyValueStr(ctx, obj, "message",
JS_NewString(ctx, strerror(err)),
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
JS_DefinePropertyValueStr(ctx, obj, "errno",
JS_NewInt32(ctx, err),
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
return obj;
} }
static JSValue js_std_error_constructor(JSContext *ctx, JSValueConst new_target, static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
int err;
if (JS_ToInt32(ctx, &err, argv[0]))
return JS_EXCEPTION;
return js_new_std_error(ctx, err);
}
static JSValue js_std_error_strerror(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) int argc, JSValueConst *argv)
{ {
int err; int err;
@ -665,15 +668,6 @@ static JSValue js_std_error_strerror(JSContext *ctx, JSValueConst this_val,
return JS_NewString(ctx, strerror(err)); return JS_NewString(ctx, strerror(err));
} }
static JSValue js_std_throw_errno(JSContext *ctx, int err)
{
JSValue obj;
obj = js_new_std_error(ctx, err);
if (JS_IsException(obj))
obj = JS_NULL;
return JS_Throw(ctx, obj);
}
static JSValue js_new_std_file(JSContext *ctx, FILE *f, static JSValue js_new_std_file(JSContext *ctx, FILE *f,
BOOL close_in_finalizer, BOOL close_in_finalizer,
BOOL is_popen) BOOL is_popen)
@ -695,12 +689,20 @@ static JSValue js_new_std_file(JSContext *ctx, FILE *f,
return obj; return obj;
} }
static void js_set_error_object(JSContext *ctx, JSValue obj, int err)
{
if (!JS_IsUndefined(obj)) {
JS_SetPropertyStr(ctx, obj, "errno", JS_NewInt32(ctx, err));
}
}
static JSValue js_std_open(JSContext *ctx, JSValueConst this_val, static JSValue js_std_open(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) int argc, JSValueConst *argv)
{ {
const char *filename, *mode = NULL; const char *filename, *mode = NULL;
FILE *f; FILE *f;
int err;
filename = JS_ToCString(ctx, argv[0]); filename = JS_ToCString(ctx, argv[0]);
if (!filename) if (!filename)
goto fail; goto fail;
@ -708,15 +710,21 @@ static JSValue js_std_open(JSContext *ctx, JSValueConst this_val,
if (!mode) if (!mode)
goto fail; goto fail;
if (mode[strspn(mode, "rwa+b")] != '\0') { if (mode[strspn(mode, "rwa+b")] != '\0') {
js_std_throw_errno(ctx, EINVAL); JS_ThrowTypeError(ctx, "invalid file mode");
goto fail; goto fail;
} }
f = fopen(filename, mode); f = fopen(filename, mode);
if (!f)
err = errno;
else
err = 0;
if (argc >= 3)
js_set_error_object(ctx, argv[2], err);
JS_FreeCString(ctx, filename); JS_FreeCString(ctx, filename);
JS_FreeCString(ctx, mode); JS_FreeCString(ctx, mode);
if (!f) if (!f)
return js_std_throw_errno(ctx, errno); return JS_NULL;
return js_new_std_file(ctx, f, TRUE, FALSE); return js_new_std_file(ctx, f, TRUE, FALSE);
fail: fail:
JS_FreeCString(ctx, filename); JS_FreeCString(ctx, filename);
@ -729,7 +737,8 @@ static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val,
{ {
const char *filename, *mode = NULL; const char *filename, *mode = NULL;
FILE *f; FILE *f;
int err;
filename = JS_ToCString(ctx, argv[0]); filename = JS_ToCString(ctx, argv[0]);
if (!filename) if (!filename)
goto fail; goto fail;
@ -737,15 +746,21 @@ static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val,
if (!mode) if (!mode)
goto fail; goto fail;
if (mode[strspn(mode, "rw")] != '\0') { if (mode[strspn(mode, "rw")] != '\0') {
js_std_throw_errno(ctx, EINVAL); JS_ThrowTypeError(ctx, "invalid file mode");
goto fail; goto fail;
} }
f = popen(filename, mode); f = popen(filename, mode);
if (!f)
err = errno;
else
err = 0;
if (argc >= 3)
js_set_error_object(ctx, argv[2], err);
JS_FreeCString(ctx, filename); JS_FreeCString(ctx, filename);
JS_FreeCString(ctx, mode); JS_FreeCString(ctx, mode);
if (!f) if (!f)
return js_std_throw_errno(ctx, errno); return JS_NULL;
return js_new_std_file(ctx, f, TRUE, TRUE); return js_new_std_file(ctx, f, TRUE, TRUE);
fail: fail:
JS_FreeCString(ctx, filename); JS_FreeCString(ctx, filename);
@ -758,7 +773,7 @@ static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val,
{ {
const char *mode; const char *mode;
FILE *f; FILE *f;
int fd; int fd, err;
if (JS_ToInt32(ctx, &fd, argv[0])) if (JS_ToInt32(ctx, &fd, argv[0]))
return JS_EXCEPTION; return JS_EXCEPTION;
@ -766,14 +781,20 @@ static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val,
if (!mode) if (!mode)
goto fail; goto fail;
if (mode[strspn(mode, "rwa+")] != '\0') { if (mode[strspn(mode, "rwa+")] != '\0') {
js_std_throw_errno(ctx, EINVAL); JS_ThrowTypeError(ctx, "invalid file mode");
goto fail; goto fail;
} }
f = fdopen(fd, mode); f = fdopen(fd, mode);
if (!f)
err = errno;
else
err = 0;
if (argc >= 3)
js_set_error_object(ctx, argv[2], err);
JS_FreeCString(ctx, mode); JS_FreeCString(ctx, mode);
if (!f) if (!f)
return js_std_throw_errno(ctx, errno); return JS_NULL;
return js_new_std_file(ctx, f, TRUE, FALSE); return js_new_std_file(ctx, f, TRUE, FALSE);
fail: fail:
JS_FreeCString(ctx, mode); JS_FreeCString(ctx, mode);
@ -785,8 +806,10 @@ static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val,
{ {
FILE *f; FILE *f;
f = tmpfile(); f = tmpfile();
if (argc >= 1)
js_set_error_object(ctx, argv[0], f ? 0 : errno);
if (!f) if (!f)
return js_std_throw_errno(ctx, errno); return JS_NULL;
return js_new_std_file(ctx, f, TRUE, FALSE); return js_new_std_file(ctx, f, TRUE, FALSE);
} }
@ -808,7 +831,7 @@ static FILE *js_std_file_get(JSContext *ctx, JSValueConst obj)
if (!s) if (!s)
return NULL; return NULL;
if (!s->f) { if (!s->f) {
js_std_throw_errno(ctx, EBADF); JS_ThrowTypeError(ctx, "invalid file handle");
return NULL; return NULL;
} }
return s->f; return s->f;
@ -843,17 +866,17 @@ static JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) int argc, JSValueConst *argv)
{ {
JSSTDFile *s = JS_GetOpaque2(ctx, this_val, js_std_file_class_id); JSSTDFile *s = JS_GetOpaque2(ctx, this_val, js_std_file_class_id);
int err;
if (!s) if (!s)
return JS_EXCEPTION; return JS_EXCEPTION;
if (!s->f) if (!s->f)
return js_std_throw_errno(ctx, EBADF); return JS_ThrowTypeError(ctx, "invalid file handle");
/* XXX: could return exit code */
if (s->is_popen) if (s->is_popen)
pclose(s->f); err = js_get_errno(pclose(s->f));
else else
fclose(s->f); err = js_get_errno(fclose(s->f));
s->f = NULL; s->f = NULL;
return JS_UNDEFINED; return JS_NewInt32(ctx, err);
} }
static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val, static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val,
@ -876,7 +899,7 @@ static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val,
} }
static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val, static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) int argc, JSValueConst *argv, int is_bigint)
{ {
FILE *f = js_std_file_get(ctx, this_val); FILE *f = js_std_file_get(ctx, this_val);
int64_t pos; int64_t pos;
@ -887,7 +910,10 @@ static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val,
#else #else
pos = ftell(f); pos = ftell(f);
#endif #endif
return JS_NewInt64(ctx, pos); if (is_bigint)
return JS_NewBigInt64(ctx, pos);
else
return JS_NewInt64(ctx, pos);
} }
static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val, static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val,
@ -898,7 +924,7 @@ static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val,
int whence, ret; int whence, ret;
if (!f) if (!f)
return JS_EXCEPTION; return JS_EXCEPTION;
if (JS_ToInt64(ctx, &pos, argv[0])) if (JS_ToInt64Ext(ctx, &pos, argv[0]))
return JS_EXCEPTION; return JS_EXCEPTION;
if (JS_ToInt32(ctx, &whence, argv[1])) if (JS_ToInt32(ctx, &whence, argv[1]))
return JS_EXCEPTION; return JS_EXCEPTION;
@ -908,8 +934,8 @@ static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val,
ret = fseek(f, pos, whence); ret = fseek(f, pos, whence);
#endif #endif
if (ret < 0) if (ret < 0)
return js_std_throw_errno(ctx, EBADF); ret = -errno;
return JS_UNDEFINED; return JS_NewInt32(ctx, ret);
} }
static JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val, static JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val,
@ -921,6 +947,25 @@ static JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val,
return JS_NewBool(ctx, feof(f)); return JS_NewBool(ctx, feof(f));
} }
static JSValue js_std_file_error(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
FILE *f = js_std_file_get(ctx, this_val);
if (!f)
return JS_EXCEPTION;
return JS_NewBool(ctx, ferror(f));
}
static JSValue js_std_file_clearerr(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
FILE *f = js_std_file_get(ctx, this_val);
if (!f)
return JS_EXCEPTION;
clearerr(f);
return JS_UNDEFINED;
}
static JSValue js_std_file_fileno(JSContext *ctx, JSValueConst this_val, static JSValue js_std_file_fileno(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) int argc, JSValueConst *argv)
{ {
@ -1151,7 +1196,7 @@ static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
f = popen((char *)cmd_buf.buf, "r"); f = popen((char *)cmd_buf.buf, "r");
dbuf_free(&cmd_buf); dbuf_free(&cmd_buf);
if (!f) { if (!f) {
return js_std_throw_errno(ctx, errno); return JS_ThrowTypeError(ctx, "could not start curl");
} }
js_std_dbuf_init(ctx, data_buf); js_std_dbuf_init(ctx, data_buf);
@ -1162,20 +1207,21 @@ static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
goto fail; goto fail;
/* get the HTTP status */ /* get the HTTP status */
if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, NULL) < 0) if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, NULL) < 0) {
status = 0;
goto bad_header; goto bad_header;
}
status = http_get_status(buf); status = http_get_status(buf);
if (!full_flag && !(status >= 200 && status <= 299)) { if (!full_flag && !(status >= 200 && status <= 299)) {
js_std_throw_errno(ctx, ENOENT); goto bad_header;
goto fail;
} }
/* wait until there is an empty line */ /* wait until there is an empty line */
for(;;) { for(;;) {
if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, header_buf) < 0) { if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, header_buf) < 0) {
bad_header: bad_header:
js_std_throw_errno(ctx, EINVAL); response = JS_NULL;
goto fail; goto done;
} }
if (!strcmp(buf, "\r\n")) if (!strcmp(buf, "\r\n"))
break; break;
@ -1191,11 +1237,6 @@ static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
break; break;
dbuf_put(data_buf, (uint8_t *)buf, len); dbuf_put(data_buf, (uint8_t *)buf, len);
} }
js_free(ctx, buf);
buf = NULL;
pclose(f);
f = NULL;
if (dbuf_error(data_buf)) if (dbuf_error(data_buf))
goto fail; goto fail;
if (binary_flag) { if (binary_flag) {
@ -1204,10 +1245,15 @@ static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
} else { } else {
response = JS_NewStringLen(ctx, (char *)data_buf->buf, data_buf->size); response = JS_NewStringLen(ctx, (char *)data_buf->buf, data_buf->size);
} }
dbuf_free(data_buf);
data_buf = NULL;
if (JS_IsException(response)) if (JS_IsException(response))
goto fail; goto fail;
done:
js_free(ctx, buf);
buf = NULL;
pclose(f);
f = NULL;
dbuf_free(data_buf);
data_buf = NULL;
if (full_flag) { if (full_flag) {
ret_obj = JS_NewObject(ctx); ret_obj = JS_NewObject(ctx);
@ -1216,13 +1262,15 @@ static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
JS_DefinePropertyValueStr(ctx, ret_obj, "response", JS_DefinePropertyValueStr(ctx, ret_obj, "response",
response, response,
JS_PROP_C_W_E); JS_PROP_C_W_E);
JS_DefinePropertyValueStr(ctx, ret_obj, "responseHeaders", if (!JS_IsNull(response)) {
JS_NewStringLen(ctx, (char *)header_buf->buf, JS_DefinePropertyValueStr(ctx, ret_obj, "responseHeaders",
header_buf->size), JS_NewStringLen(ctx, (char *)header_buf->buf,
JS_PROP_C_W_E); header_buf->size),
JS_DefinePropertyValueStr(ctx, ret_obj, "status", JS_PROP_C_W_E);
JS_NewInt32(ctx, status), JS_DefinePropertyValueStr(ctx, ret_obj, "status",
JS_PROP_C_W_E); JS_NewInt32(ctx, status),
JS_PROP_C_W_E);
}
} else { } else {
ret_obj = response; ret_obj = response;
} }
@ -1245,31 +1293,7 @@ static JSClassDef js_std_file_class = {
.finalizer = js_std_file_finalizer, .finalizer = js_std_file_finalizer,
}; };
static const JSCFunctionListEntry js_std_funcs[] = { static const JSCFunctionListEntry js_std_error_props[] = {
JS_CFUNC_DEF("exit", 1, js_std_exit ),
JS_CFUNC_DEF("gc", 0, js_std_gc ),
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("urlGet", 1, js_std_urlGet ),
/* FILE I/O */
JS_CFUNC_DEF("open", 2, js_std_open ),
JS_CFUNC_DEF("popen", 2, js_std_popen ),
JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ),
JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ),
JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ),
JS_CFUNC_DEF("printf", 1, js_std_printf ),
JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ),
JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE ),
JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ),
JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ),
/* setenv, ... */
};
static const JSCFunctionListEntry js_std_error_funcs[] = {
JS_CFUNC_DEF("strerror", 1, js_std_error_strerror ),
/* various errno values */ /* various errno values */
#define DEF(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE ) #define DEF(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE )
DEF(EINVAL), DEF(EINVAL),
@ -1286,27 +1310,55 @@ static const JSCFunctionListEntry js_std_error_funcs[] = {
#undef DEF #undef DEF
}; };
static const JSCFunctionListEntry js_std_funcs[] = {
JS_CFUNC_DEF("exit", 1, js_std_exit ),
JS_CFUNC_DEF("gc", 0, js_std_gc ),
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("urlGet", 1, js_std_urlGet ),
JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
/* FILE I/O */
JS_CFUNC_DEF("open", 2, js_std_open ),
JS_CFUNC_DEF("popen", 2, js_std_popen ),
JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ),
JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ),
JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ),
JS_CFUNC_DEF("printf", 1, js_std_printf ),
JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ),
JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE ),
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[] = { static const JSCFunctionListEntry js_std_file_proto_funcs[] = {
JS_CFUNC_DEF("close", 0, js_std_file_close ), JS_CFUNC_DEF("close", 0, js_std_file_close ),
JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 1 ), JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 1 ),
JS_CFUNC_DEF("printf", 1, js_std_file_printf ), JS_CFUNC_DEF("printf", 1, js_std_file_printf ),
JS_CFUNC_DEF("flush", 0, js_std_file_flush ), JS_CFUNC_DEF("flush", 0, js_std_file_flush ),
JS_CFUNC_DEF("tell", 0, js_std_file_tell ), JS_CFUNC_MAGIC_DEF("tell", 0, js_std_file_tell, 0 ),
JS_CFUNC_MAGIC_DEF("tello", 0, js_std_file_tell, 1 ),
JS_CFUNC_DEF("seek", 2, js_std_file_seek ), JS_CFUNC_DEF("seek", 2, js_std_file_seek ),
JS_CFUNC_DEF("eof", 0, js_std_file_eof ), JS_CFUNC_DEF("eof", 0, js_std_file_eof ),
JS_CFUNC_DEF("fileno", 0, js_std_file_fileno ), JS_CFUNC_DEF("fileno", 0, js_std_file_fileno ),
JS_CFUNC_DEF("error", 0, js_std_file_error ),
JS_CFUNC_DEF("clearerr", 0, js_std_file_clearerr ),
JS_CFUNC_MAGIC_DEF("read", 3, js_std_file_read_write, 0 ), JS_CFUNC_MAGIC_DEF("read", 3, js_std_file_read_write, 0 ),
JS_CFUNC_MAGIC_DEF("write", 3, js_std_file_read_write, 1 ), JS_CFUNC_MAGIC_DEF("write", 3, js_std_file_read_write, 1 ),
JS_CFUNC_DEF("getline", 0, js_std_file_getline ), JS_CFUNC_DEF("getline", 0, js_std_file_getline ),
JS_CFUNC_DEF("readAsString", 0, js_std_file_readAsString ), JS_CFUNC_DEF("readAsString", 0, js_std_file_readAsString ),
JS_CFUNC_DEF("getByte", 0, js_std_file_getByte ), JS_CFUNC_DEF("getByte", 0, js_std_file_getByte ),
JS_CFUNC_DEF("putByte", 1, js_std_file_putByte ), JS_CFUNC_DEF("putByte", 1, js_std_file_putByte ),
/* setvbuf, ferror, clearerr, ... */ /* setvbuf, ... */
}; };
static int js_std_init(JSContext *ctx, JSModuleDef *m) static int js_std_init(JSContext *ctx, JSModuleDef *m)
{ {
JSValue proto, obj; JSValue proto;
/* FILE class */ /* FILE class */
/* the class ID is created once */ /* the class ID is created once */
@ -1323,13 +1375,6 @@ static int js_std_init(JSContext *ctx, JSModuleDef *m)
JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, FALSE, FALSE)); JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, FALSE, FALSE));
JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, FALSE, FALSE)); JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, FALSE, FALSE));
JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, FALSE, FALSE)); JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, FALSE, FALSE));
obj = JS_NewCFunction2(ctx, js_std_error_constructor,
"Error", 1, JS_CFUNC_constructor, 0);
JS_SetPropertyFunctionList(ctx, obj, js_std_error_funcs,
countof(js_std_error_funcs));
JS_SetModuleExport(ctx, m, "Error", obj);
return 0; return 0;
} }
@ -1343,20 +1388,12 @@ JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name)
JS_AddModuleExport(ctx, m, "in"); JS_AddModuleExport(ctx, m, "in");
JS_AddModuleExport(ctx, m, "out"); JS_AddModuleExport(ctx, m, "out");
JS_AddModuleExport(ctx, m, "err"); JS_AddModuleExport(ctx, m, "err");
JS_AddModuleExport(ctx, m, "Error");
return m; return m;
} }
/**********************************************************/ /**********************************************************/
/* 'os' object */ /* 'os' object */
static JSValue js_os_return(JSContext *ctx, ssize_t ret)
{
if (ret < 0)
ret = -errno;
return JS_NewInt64(ctx, ret);
}
static JSValue js_os_open(JSContext *ctx, JSValueConst this_val, static JSValue js_os_open(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) int argc, JSValueConst *argv)
{ {
@ -1382,9 +1419,9 @@ static JSValue js_os_open(JSContext *ctx, JSValueConst this_val,
if (!(flags & O_TEXT)) if (!(flags & O_TEXT))
flags |= O_BINARY; flags |= O_BINARY;
#endif #endif
ret = open(filename, flags, mode); ret = js_get_errno(open(filename, flags, mode));
JS_FreeCString(ctx, filename); JS_FreeCString(ctx, filename);
return js_os_return(ctx, ret); return JS_NewInt32(ctx, ret);
} }
static JSValue js_os_close(JSContext *ctx, JSValueConst this_val, static JSValue js_os_close(JSContext *ctx, JSValueConst this_val,
@ -1393,24 +1430,31 @@ static JSValue js_os_close(JSContext *ctx, JSValueConst this_val,
int fd, ret; int fd, ret;
if (JS_ToInt32(ctx, &fd, argv[0])) if (JS_ToInt32(ctx, &fd, argv[0]))
return JS_EXCEPTION; return JS_EXCEPTION;
ret = close(fd); ret = js_get_errno(close(fd));
return js_os_return(ctx, ret); return JS_NewInt32(ctx, ret);
} }
static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val, static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) int argc, JSValueConst *argv)
{ {
int fd, whence, ret; int fd, whence;
int64_t pos; int64_t pos, ret;
BOOL is_bigint;
if (JS_ToInt32(ctx, &fd, argv[0])) if (JS_ToInt32(ctx, &fd, argv[0]))
return JS_EXCEPTION; return JS_EXCEPTION;
if (JS_ToInt64(ctx, &pos, argv[1])) is_bigint = JS_IsBigInt(ctx, argv[1]);
if (JS_ToInt64Ext(ctx, &pos, argv[1]))
return JS_EXCEPTION; return JS_EXCEPTION;
if (JS_ToInt32(ctx, &whence, argv[2])) if (JS_ToInt32(ctx, &whence, argv[2]))
return JS_EXCEPTION; return JS_EXCEPTION;
ret = lseek(fd, pos, whence); ret = lseek(fd, pos, whence);
return js_os_return(ctx, ret); if (ret == -1)
ret = -errno;
if (is_bigint)
return JS_NewBigInt64(ctx, ret);
else
return JS_NewInt64(ctx, ret);
} }
static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val, static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val,
@ -1434,10 +1478,10 @@ static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val,
if (pos + len > size) if (pos + len > size)
return JS_ThrowRangeError(ctx, "read/write array buffer overflow"); return JS_ThrowRangeError(ctx, "read/write array buffer overflow");
if (magic) if (magic)
ret = write(fd, buf + pos, len); ret = js_get_errno(write(fd, buf + pos, len));
else else
ret = read(fd, buf + pos, len); ret = js_get_errno(read(fd, buf + pos, len));
return js_os_return(ctx, ret); return JS_NewInt64(ctx, ret);
} }
static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val, static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val,
@ -1555,9 +1599,9 @@ static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val,
filename = JS_ToCString(ctx, argv[0]); filename = JS_ToCString(ctx, argv[0]);
if (!filename) if (!filename)
return JS_EXCEPTION; return JS_EXCEPTION;
ret = remove(filename); ret = js_get_errno(remove(filename));
JS_FreeCString(ctx, filename); JS_FreeCString(ctx, filename);
return js_os_return(ctx, ret); return JS_NewInt32(ctx, ret);
} }
static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val, static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val,
@ -1574,10 +1618,10 @@ static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val,
JS_FreeCString(ctx, oldpath); JS_FreeCString(ctx, oldpath);
return JS_EXCEPTION; return JS_EXCEPTION;
} }
ret = rename(oldpath, newpath); ret = js_get_errno(rename(oldpath, newpath));
JS_FreeCString(ctx, oldpath); JS_FreeCString(ctx, oldpath);
JS_FreeCString(ctx, newpath); JS_FreeCString(ctx, newpath);
return js_os_return(ctx, ret); return JS_NewInt32(ctx, ret);
} }
static JSOSRWHandler *find_rh(int fd) static JSOSRWHandler *find_rh(int fd)
@ -2018,7 +2062,7 @@ static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val,
if (!getcwd(buf, sizeof(buf))) { if (!getcwd(buf, sizeof(buf))) {
buf[0] = '\0'; buf[0] = '\0';
err = -errno; err = errno;
} else { } else {
err = 0; err = 0;
} }
@ -2036,9 +2080,9 @@ static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val,
target = JS_ToCString(ctx, argv[0]); target = JS_ToCString(ctx, argv[0]);
if (!target) if (!target)
return JS_EXCEPTION; return JS_EXCEPTION;
err = chdir(target); err = js_get_errno(chdir(target));
JS_FreeCString(ctx, target); JS_FreeCString(ctx, target);
return js_os_return(ctx, err); return JS_NewInt32(ctx, err);
} }
/* return [path, errorcode] */ /* return [path, errorcode] */
@ -2056,7 +2100,7 @@ static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
JS_FreeCString(ctx, path); JS_FreeCString(ctx, path);
if (!res) { if (!res) {
buf[0] = '\0'; buf[0] = '\0';
err = -errno; err = errno;
} else { } else {
err = 0; err = 0;
} }
@ -2078,9 +2122,9 @@ static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val,
path = JS_ToCString(ctx, argv[0]); path = JS_ToCString(ctx, argv[0]);
if (!path) if (!path)
return JS_EXCEPTION; return JS_EXCEPTION;
ret = mkdir(path, mode); ret = js_get_errno(mkdir(path, mode));
JS_FreeCString(ctx, path); JS_FreeCString(ctx, path);
return js_os_return(ctx, ret); return JS_NewInt32(ctx, ret);
} }
static int64_t timespec_to_ms(const struct timespec *tv) static int64_t timespec_to_ms(const struct timespec *tv)
@ -2106,7 +2150,7 @@ static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val,
res = stat(path, &st); res = stat(path, &st);
JS_FreeCString(ctx, path); JS_FreeCString(ctx, path);
if (res < 0) { if (res < 0) {
err = -errno; err = errno;
obj = JS_NULL; obj = JS_NULL;
} else { } else {
err = 0; err = 0;
@ -2179,10 +2223,10 @@ static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val,
JS_FreeCString(ctx, target); JS_FreeCString(ctx, target);
return JS_EXCEPTION; return JS_EXCEPTION;
} }
err = symlink(target, linkpath); err = js_get_errno(symlink(target, linkpath));
JS_FreeCString(ctx, target); JS_FreeCString(ctx, target);
JS_FreeCString(ctx, linkpath); JS_FreeCString(ctx, linkpath);
return js_os_return(ctx, err); return JS_NewInt32(ctx, err);
} }
/* return [path, errorcode] */ /* return [path, errorcode] */
@ -2198,14 +2242,14 @@ static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val,
if (!path) if (!path)
return JS_EXCEPTION; return JS_EXCEPTION;
res = readlink(path, buf, sizeof(buf) - 1); res = readlink(path, buf, sizeof(buf) - 1);
JS_FreeCString(ctx, path);
if (res < 0) { if (res < 0) {
buf[0] = '\0'; buf[0] = '\0';
err = -errno; err = errno;
} else { } else {
buf[res] = '\0'; buf[res] = '\0';
err = 0; err = 0;
} }
JS_FreeCString(ctx, path);
return make_string_error(ctx, buf, err); return make_string_error(ctx, buf, err);
} }
@ -2229,18 +2273,19 @@ static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION; return JS_EXCEPTION;
} }
f = opendir(path); f = opendir(path);
if (!f)
err = errno;
else
err = 0;
JS_FreeCString(ctx, path); JS_FreeCString(ctx, path);
err = 0; if (!f)
if (!f) {
err = -errno;
goto done; goto done;
}
len = 0; len = 0;
for(;;) { for(;;) {
errno = 0; errno = 0;
d = readdir(f); d = readdir(f);
if (!d) { if (!d) {
err = -errno; err = errno;
break; break;
} }
JS_DefinePropertyValueUint32(ctx, obj, len++, JS_DefinePropertyValueUint32(ctx, obj, len++,
@ -2275,9 +2320,9 @@ static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION; return JS_EXCEPTION;
ms_to_timeval(&times[0], atime); ms_to_timeval(&times[0], atime);
ms_to_timeval(&times[1], mtime); ms_to_timeval(&times[1], mtime);
ret = utimes(path, times); ret = js_get_errno(utimes(path, times));
JS_FreeCString(ctx, path); JS_FreeCString(ctx, path);
return js_os_return(ctx, ret); return JS_NewInt32(ctx, ret);
} }
/* exec(args[, options]) -> exitcode */ /* exec(args[, options]) -> exitcode */
@ -2486,8 +2531,8 @@ static JSValue js_os_kill(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION; return JS_EXCEPTION;
if (JS_ToInt32(ctx, &sig, argv[1])) if (JS_ToInt32(ctx, &sig, argv[1]))
return JS_EXCEPTION; return JS_EXCEPTION;
ret = kill(pid, sig); ret = js_get_errno(kill(pid, sig));
return js_os_return(ctx, ret); return JS_NewInt32(ctx, ret);
} }
/* sleep(delay_ms) */ /* sleep(delay_ms) */
@ -2502,8 +2547,8 @@ static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION; return JS_EXCEPTION;
ts.tv_sec = delay / 1000; ts.tv_sec = delay / 1000;
ts.tv_nsec = (delay % 1000) * 1000000; ts.tv_nsec = (delay % 1000) * 1000000;
ret = nanosleep(&ts, NULL); ret = js_get_errno(nanosleep(&ts, NULL));
return js_os_return(ctx, ret); return JS_NewInt32(ctx, ret);
} }
/* dup(fd) */ /* dup(fd) */
@ -2514,8 +2559,8 @@ static JSValue js_os_dup(JSContext *ctx, JSValueConst this_val,
if (JS_ToInt32(ctx, &fd, argv[0])) if (JS_ToInt32(ctx, &fd, argv[0]))
return JS_EXCEPTION; return JS_EXCEPTION;
ret = dup(fd); ret = js_get_errno(dup(fd));
return js_os_return(ctx, ret); return JS_NewInt32(ctx, ret);
} }
/* dup2(fd) */ /* dup2(fd) */
@ -2528,8 +2573,8 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION; return JS_EXCEPTION;
if (JS_ToInt32(ctx, &fd2, argv[1])) if (JS_ToInt32(ctx, &fd2, argv[1]))
return JS_EXCEPTION; return JS_EXCEPTION;
ret = dup2(fd, fd2); ret = js_get_errno(dup2(fd, fd2));
return js_os_return(ctx, ret); return JS_NewInt32(ctx, ret);
} }
#endif /* !_WIN32 */ #endif /* !_WIN32 */
@ -2725,23 +2770,30 @@ void js_std_free_handlers(JSRuntime *rt)
} }
} }
static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val, static void js_dump_obj(JSContext *ctx, FILE *f, JSValueConst val)
BOOL is_throw) {
const char *str;
str = JS_ToCString(ctx, val);
if (str) {
fprintf(f, "%s\n", str);
JS_FreeCString(ctx, str);
} else {
fprintf(f, "[exception]\n");
}
}
static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val)
{ {
JSValue val; JSValue val;
const char *stack;
BOOL is_error; BOOL is_error;
is_error = JS_IsError(ctx, exception_val); is_error = JS_IsError(ctx, exception_val);
if (is_throw && !is_error) js_dump_obj(ctx, stderr, exception_val);
printf("Throw: ");
js_print(ctx, JS_NULL, 1, (JSValueConst *)&exception_val);
if (is_error) { if (is_error) {
val = JS_GetPropertyStr(ctx, exception_val, "stack"); val = JS_GetPropertyStr(ctx, exception_val, "stack");
if (!JS_IsUndefined(val)) { if (!JS_IsUndefined(val)) {
stack = JS_ToCString(ctx, val); js_dump_obj(ctx, stderr, val);
printf("%s\n", stack);
JS_FreeCString(ctx, stack);
} }
JS_FreeValue(ctx, val); JS_FreeValue(ctx, val);
} }
@ -2752,7 +2804,7 @@ void js_std_dump_error(JSContext *ctx)
JSValue exception_val; JSValue exception_val;
exception_val = JS_GetException(ctx); exception_val = JS_GetException(ctx);
js_std_dump_error1(ctx, exception_val, TRUE); js_std_dump_error1(ctx, exception_val);
JS_FreeValue(ctx, exception_val); JS_FreeValue(ctx, exception_val);
} }
@ -2761,8 +2813,8 @@ void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
BOOL is_handled, void *opaque) BOOL is_handled, void *opaque)
{ {
if (!is_handled) { if (!is_handled) {
printf("Possibly unhandled promise rejection: "); fprintf(stderr, "Possibly unhandled promise rejection: ");
js_std_dump_error1(ctx, reason, FALSE); js_std_dump_error1(ctx, reason);
} }
} }

View file

@ -119,7 +119,6 @@ DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */ 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 DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
bytecode string */ bytecode string */
DEF( get_super_ctor, 1, 1, 1, none)
DEF( get_super, 1, 1, 1, none) DEF( get_super, 1, 1, 1, none)
DEF( import, 1, 1, 1, none) /* dynamic module import */ DEF( import, 1, 1, 1, none) /* dynamic module import */

204
quickjs.c
View file

@ -284,6 +284,7 @@ struct JSRuntime {
JSNumericOperations bigdecimal_ops; JSNumericOperations bigdecimal_ops;
uint32_t operator_count; uint32_t operator_count;
#endif #endif
void *user_opaque;
}; };
struct JSClass { struct JSClass {
@ -1537,6 +1538,16 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
return NULL; return NULL;
} }
void *JS_GetRuntimeOpaque(JSRuntime *rt)
{
return rt->user_opaque;
}
void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
{
rt->user_opaque = opaque;
}
/* default memory allocation functions with memory limitation */ /* default memory allocation functions with memory limitation */
static inline size_t js_def_malloc_usable_size(void *ptr) static inline size_t js_def_malloc_usable_size(void *ptr)
{ {
@ -2198,26 +2209,6 @@ static inline BOOL is_math_mode(JSContext *ctx)
} }
#endif #endif
JSValue JS_NewInt64(JSContext *ctx, int64_t v)
{
if (v == (int32_t)v) {
return JS_NewInt32(ctx, v);
} else {
return __JS_NewFloat64(ctx, (double)v);
}
}
static force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
{
JSValue v;
if (val <= 0x7fffffff) {
v = JS_MKVAL(JS_TAG_INT, val);
} else {
v = __JS_NewFloat64(ctx, val);
}
return v;
}
/* JSAtom support */ /* JSAtom support */
#define JS_ATOM_TAG_INT (1U << 31) #define JS_ATOM_TAG_INT (1U << 31)
@ -9794,6 +9785,8 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) { if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
is_float = TRUE; is_float = TRUE;
p++; p++;
if (*p == sep)
goto fail;
while (to_digit((uint8_t)*p) < radix || while (to_digit((uint8_t)*p) < radix ||
(*p == sep && to_digit((uint8_t)p[1]) < radix)) (*p == sep && to_digit((uint8_t)p[1]) < radix))
p++; p++;
@ -10129,7 +10122,6 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
ret = JS_NewInt32(ctx, 0); ret = JS_NewInt32(ctx, 0);
} else { } else {
/* convert -0 to +0 */ /* convert -0 to +0 */
/* XXX: should not be done here ? */
d = trunc(d) + 0.0; d = trunc(d) + 0.0;
ret = JS_NewFloat64(ctx, d); ret = JS_NewFloat64(ctx, d);
} }
@ -10385,6 +10377,14 @@ int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val)); return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));
} }
int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)
{
if (JS_IsBigInt(ctx, val))
return JS_ToBigInt64(ctx, pres, val);
else
return JS_ToInt64(ctx, pres, val);
}
/* return (<0, 0) in case of exception */ /* return (<0, 0) in case of exception */
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val) static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
{ {
@ -11840,7 +11840,8 @@ static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
} }
/* must be kept in sync with JSOverloadableOperatorEnum */ /* must be kept in sync with JSOverloadableOperatorEnum */
static const char *js_overloadable_operator_names[JS_OVOP_COUNT] = { /* XXX: use atoms ? */
static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = {
"+", "+",
"-", "-",
"*", "*",
@ -12894,7 +12895,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
handle_bigint: handle_bigint:
if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2)) if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
goto exception; goto exception;
} else if (tag1 == JS_TAG_FLOAT64 || tag2 == JS_TAG_FLOAT64) { } else {
double dr; double dr;
/* float64 result */ /* float64 result */
if (JS_ToFloat64Free(ctx, &d1, op1)) { if (JS_ToFloat64Free(ctx, &d1, op1)) {
@ -13031,7 +13032,11 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
} else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
goto exception; goto exception;
} else if (tag1 == JS_TAG_FLOAT64 || tag2 == JS_TAG_FLOAT64) { } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
handle_bigint:
if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
goto exception;
} else {
double d1, d2; double d1, d2;
/* float64 result */ /* float64 result */
if (JS_ToFloat64Free(ctx, &d1, op1)) { if (JS_ToFloat64Free(ctx, &d1, op1)) {
@ -13040,10 +13045,9 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
} }
if (JS_ToFloat64Free(ctx, &d2, op2)) if (JS_ToFloat64Free(ctx, &d2, op2))
goto exception; goto exception;
if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
goto handle_bigint;
sp[-2] = __JS_NewFloat64(ctx, d1 + d2); sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
} else {
if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
goto exception;
} }
return 0; return 0;
exception: exception:
@ -13642,6 +13646,28 @@ static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
#else /* !CONFIG_BIGNUM */ #else /* !CONFIG_BIGNUM */
static JSValue JS_ThrowUnsupportedBigint(JSContext *ctx)
{
return JS_ThrowTypeError(ctx, "bigint is not supported");
}
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
{
return JS_ThrowUnsupportedBigint(ctx);
}
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
{
return JS_ThrowUnsupportedBigint(ctx);
}
int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
{
JS_ThrowUnsupportedBigint(ctx);
*pres = 0;
return -1;
}
static no_inline __exception int js_unary_arith_slow(JSContext *ctx, static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
JSValue *sp, JSValue *sp,
OPCodeEnum op) OPCodeEnum op)
@ -16280,22 +16306,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
} }
BREAK; BREAK;
CASE(OP_get_super_ctor):
{
JSValue proto;
proto = JS_DupValue(ctx, JS_GetPrototype(ctx, sp[-1]));
if (JS_IsException(proto))
goto exception;
if (!JS_IsConstructor(ctx, proto)) {
JS_FreeValue(ctx, proto);
JS_ThrowTypeError(ctx, "not a constructor");
goto exception;
}
JS_FreeValue(ctx, sp[-1]);
sp[-1] = proto;
}
BREAK;
CASE(OP_get_super): CASE(OP_get_super):
{ {
JSValue proto; JSValue proto;
@ -23821,7 +23831,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
emit_atom(s, JS_ATOM_this_active_func); emit_atom(s, JS_ATOM_this_active_func);
emit_u16(s, 0); emit_u16(s, 0);
emit_op(s, OP_get_super_ctor); emit_op(s, OP_get_super);
emit_op(s, OP_scope_get_var); emit_op(s, OP_scope_get_var);
emit_atom(s, JS_ATOM_new_target); emit_atom(s, JS_ATOM_new_target);
@ -31993,10 +32003,10 @@ static __exception int js_parse_function_decl2(JSParseState *s,
js_parse_expect(s, ')'); js_parse_expect(s, ')');
goto fail; goto fail;
} }
if (s->token.val == ',') { if (s->token.val == ')')
if (next_token(s)) break;
goto fail; if (js_parse_expect(s, ','))
} goto fail;
} }
if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) || if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||
(func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) { (func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {
@ -34381,6 +34391,10 @@ int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
case JS_DEF_PROP_DOUBLE: case JS_DEF_PROP_DOUBLE:
val = __JS_NewFloat64(ctx, e->u.f64); val = __JS_NewFloat64(ctx, e->u.f64);
break; break;
case JS_DEF_OBJECT:
val = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
break;
default: default:
abort(); abort();
} }
@ -37357,7 +37371,8 @@ static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
JS_ThrowTypeError(ctx, "Array too long"); JS_ThrowTypeError(ctx, "Array too long");
goto fail; goto fail;
} }
if (JS_SetPropertyInt64(ctx, target, targetIndex, element) < 0) if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element,
JS_PROP_C_W_E | JS_PROP_THROW) < 0)
return -1; return -1;
targetIndex++; targetIndex++;
} }
@ -37754,7 +37769,6 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = {
JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ), JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ),
JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ), JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ),
JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ), JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ),
JS_CFUNC_MAGIC_DEF("flatten", 0, js_array_flatten, 0 ),
JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ), JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ),
JS_ALIAS_DEF("[Symbol.iterator]", "values" ), JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ), JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ),
@ -39918,14 +39932,36 @@ static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
if (JS_ToFloat64(ctx, &b, argv[1])) if (JS_ToFloat64(ctx, &b, argv[1]))
return JS_EXCEPTION; return JS_EXCEPTION;
r = hypot(a, b); r = hypot(a, b);
} else { } else if (argc == 0) {
r = 0; r = 0;
} else {
double *tab, a_max;
tab = js_malloc(ctx, sizeof(tab[0]) * argc);
if (!tab)
return JS_EXCEPTION;
/* avoid overflow by taking the maximum */
a_max = 0;
for(i = 0; i < argc; i++) { for(i = 0; i < argc; i++) {
if (JS_ToFloat64(ctx, &a, argv[i])) if (JS_ToFloat64(ctx, &a, argv[i])) {
js_free(ctx, tab);
return JS_EXCEPTION; return JS_EXCEPTION;
r += a; }
a = fabs(a);
tab[i] = a;
if (a > a_max)
a_max = a;
} }
r = sqrt(r); if (a_max == 0 || !isfinite(a_max)) {
r = a_max;
} else {
r = 0;
for(i = 0; i < argc; i++) {
a = tab[i] / a_max;
r += a * a;
}
r = a_max * sqrt(r);
}
js_free(ctx, tab);
} }
return JS_NewFloat64(ctx, r); return JS_NewFloat64(ctx, r);
} }
@ -45234,10 +45270,10 @@ static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_va
} }
JS_FreeValue(ctx, ret); JS_FreeValue(ctx, ret);
if (magic == 0) { if (magic == 0) {
then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 1, then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
0, 1, argv); 0, 1, argv);
} else { } else {
then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 1, then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0,
0, 1, argv); 0, 1, argv);
} }
if (JS_IsException(then_func)) { if (JS_IsException(then_func)) {
@ -50037,7 +50073,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int special) int argc, JSValueConst *argv, int special)
{ {
JSObject *p; JSObject *p;
int len, tag, is_int, is_big, k, stop, inc, res = -1; int len, tag, is_int, is_bigint, k, stop, inc, res = -1;
int64_t v64; int64_t v64;
double d; double d;
float f; float f;
@ -50080,7 +50116,11 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
inc = 1; inc = 1;
} }
is_big = 0; if (validate_typed_array(ctx, this_val))
goto exception;
p = JS_VALUE_GET_OBJ(this_val);
is_bigint = 0;
is_int = 0; /* avoid warning */ is_int = 0; /* avoid warning */
v64 = 0; /* avoid warning */ v64 = 0; /* avoid warning */
tag = JS_VALUE_GET_NORM_TAG(argv[0]); tag = JS_VALUE_GET_NORM_TAG(argv[0]);
@ -50095,10 +50135,20 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
is_int = (v64 == d); is_int = (v64 == d);
} else } else
#ifdef CONFIG_BIGNUM #ifdef CONFIG_BIGNUM
if (tag == JS_TAG_BIG_INT || tag == JS_TAG_BIG_FLOAT) { if (tag == JS_TAG_BIG_INT) {
/* will a generic loop for bigint and bigfloat */ JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]);
/* XXX: should use the generic loop in math_mode? */
is_big = 1; if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
if (bf_get_int64(&v64, &p1->num, 0) != 0)
goto done;
} else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
if (bf_get_uint64((uint64_t *)&v64, &p1->num) != 0)
goto done;
} else {
goto done;
}
d = 0;
is_bigint = 1;
} else } else
#endif #endif
{ {
@ -50172,7 +50222,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
} }
break; break;
case JS_CLASS_FLOAT32_ARRAY: case JS_CLASS_FLOAT32_ARRAY:
if (is_big) if (is_bigint)
break; break;
if (isnan(d)) { if (isnan(d)) {
const float *pv = p->u.array.u.float_ptr; const float *pv = p->u.array.u.float_ptr;
@ -50196,7 +50246,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
} }
break; break;
case JS_CLASS_FLOAT64_ARRAY: case JS_CLASS_FLOAT64_ARRAY:
if (is_big) if (is_bigint)
break; break;
if (isnan(d)) { if (isnan(d)) {
const double *pv = p->u.array.u.double_ptr; const double *pv = p->u.array.u.double_ptr;
@ -50221,20 +50271,22 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
break; break;
#ifdef CONFIG_BIGNUM #ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_INT64_ARRAY:
if (is_bigint || (is_math_mode(ctx) && is_int &&
v64 >= -MAX_SAFE_INTEGER &&
v64 <= MAX_SAFE_INTEGER)) {
goto scan64;
}
break;
case JS_CLASS_BIG_UINT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY:
if (is_big || is_strict_mode(ctx)) { if (is_bigint || (is_math_mode(ctx) && is_int &&
/* generic loop for bignums, argv[0] is a bignum != NaN */ v64 >= 0 && v64 <= MAX_SAFE_INTEGER)) {
/* XXX: optimize with explicit values */ const uint64_t *pv;
uint64_t v;
scan64:
pv = p->u.array.u.uint64_ptr;
v = v64;
for (; k != stop; k += inc) { for (; k != stop; k += inc) {
JSValue v = JS_GetPropertyUint32(ctx, this_val, k); if (pv[k] == v) {
int ret;
if (JS_IsException(v))
goto exception;
ret = js_same_value_zero(ctx, v, argv[0]);
JS_FreeValue(ctx, v);
if (ret) {
if (ret < 0)
goto exception;
res = k; res = k;
break; break;
} }

View file

@ -335,6 +335,8 @@ void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque); JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque);
void JS_FreeRuntime(JSRuntime *rt); void JS_FreeRuntime(JSRuntime *rt);
void *JS_GetRuntimeOpaque(JSRuntime *rt);
void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque);
typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp); typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp);
void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
void JS_RunGC(JSRuntime *rt); void JS_RunGC(JSRuntime *rt);
@ -508,7 +510,28 @@ static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val)
return JS_MKVAL(JS_TAG_CATCH_OFFSET, val); return JS_MKVAL(JS_TAG_CATCH_OFFSET, val);
} }
JSValue JS_NewInt64(JSContext *ctx, int64_t v); static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val)
{
JSValue v;
if (val == (int32_t)val) {
v = JS_NewInt32(ctx, val);
} else {
v = __JS_NewFloat64(ctx, val);
}
return v;
}
static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
{
JSValue v;
if (val <= 0x7fffffff) {
v = JS_NewInt32(ctx, val);
} else {
v = __JS_NewFloat64(ctx, val);
}
return v;
}
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v); JSValue JS_NewBigInt64(JSContext *ctx, int64_t v);
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v); JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);
@ -657,7 +680,10 @@ static int inline JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val); int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val); int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val);
int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val); int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val);
/* return an exception if 'val' is a Number */
int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val); int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
/* same as JS_ToInt64() but allow BigInt */
int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val);
JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1); JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1);
JSValue JS_NewString(JSContext *ctx, const char *str); JSValue JS_NewString(JSContext *ctx, const char *str);

View file

@ -50,21 +50,30 @@ fi
if [ "$binary" = "yes" ] ; then if [ "$binary" = "yes" ] ; then
make -j4 qjs run-test262
make -j4 CONFIG_M32=y qjs32 run-test262-32
strip qjs run-test262 qjs32 run-test262-32
d="quickjs-linux-x86_64-${version}" d="quickjs-linux-x86_64-${version}"
name="quickjs-linux-x86_64-${version}"
outdir="/tmp/${d}" outdir="/tmp/${d}"
rm -rf $outdir rm -rf $outdir
mkdir -p $outdir mkdir -p $outdir
files="qjs run-test262" cp qjs run-test262 $outdir
make -j4 $files ( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
strip $files d="quickjs-linux-i686-${version}"
cp $files $outdir outdir="/tmp/${d}"
( cd /tmp/$d && rm -f ../${name}.zip && zip -r ../${name}.zip . ) rm -rf $outdir
mkdir -p $outdir
cp qjs32 $outdir/qjs
cp run-test262-32 $outdir/run-test262
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
fi fi

View file

@ -385,8 +385,11 @@ static JSValue js_print(JSContext *ctx, JSValueConst this_val,
str = JS_ToCString(ctx, argv[i]); str = JS_ToCString(ctx, argv[i]);
if (!str) if (!str)
return JS_EXCEPTION; return JS_EXCEPTION;
if (!strcmp(str, "Test262:AsyncTestComplete")) if (!strcmp(str, "Test262:AsyncTestComplete")) {
async_done++; async_done++;
} else if (strstart(str, "Test262:AsyncTestFailure", NULL)) {
async_done = 2; /* force an error */
}
fputs(str, outfile); fputs(str, outfile);
JS_FreeCString(ctx, str); JS_FreeCString(ctx, str);
} }

View file

@ -87,6 +87,7 @@ destructuring-binding
dynamic-import dynamic-import
export-star-as-namespace-from-module export-star-as-namespace-from-module
FinalizationGroup=skip FinalizationGroup=skip
FinalizationRegistry=skip
Float32Array Float32Array
Float64Array Float64Array
for-in-order for-in-order

View file

@ -1,17 +1,22 @@
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/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/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/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/super-evaluation-order.js:26: Test262Error: via ArgumentListEvaluation Expected SameValue(«0», «123») to be true
test262/test/language/expressions/class/super-evaluation-order.js:26: strict mode: Test262Error: via ArgumentListEvaluation Expected SameValue(«0», «123») to be true
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: 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/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/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/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-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/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/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: value has no property test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: value has no property
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: value has no property test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: value has no property
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/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/for-await-of/async-gen-decl-dstr-array-elem-iter-rtrn-close-null.js:81: TypeError: $DONE() not called
test262/test/language/statements/for-await-of/async-gen-decl-dstr-array-elem-iter-rtrn-close-null.js:81: strict mode: TypeError: $DONE() not called
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/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 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

View file

@ -917,11 +917,9 @@ function load_result(filename)
var f, str, res; var f, str, res;
if (typeof std === "undefined") if (typeof std === "undefined")
return null; return null;
try { f = std.open(filename, "r");
f = std.open(filename, "r"); if (!f)
} catch(e) {
return null; return null;
}
str = f.readAsString(); str = f.readAsString();
res = JSON.parse(str); res = JSON.parse(str);
f.close(); f.close();

View file

@ -501,6 +501,10 @@ function test_regexp()
a = eval("/\0a/"); a = eval("/\0a/");
assert(a.toString(), "/\0a/"); assert(a.toString(), "/\0a/");
assert(a.exec("\0a")[0], "\0a"); assert(a.exec("\0a")[0], "\0a");
assert(/{1a}/.toString(), "/{1a}/");
a = /a{1+/.exec("a{11");
assert(a, ["a{11"] );
} }
function test_symbol() function test_symbol()

View file

@ -106,6 +106,9 @@ function test_popen()
f.puts(content); f.puts(content);
f.close(); f.close();
/* test loadFile */
assert(std.loadFile(fname), content);
/* execute the 'cat' shell command */ /* execute the 'cat' shell command */
f = std.popen("cat " + fname, "r"); f = std.popen("cat " + fname, "r");
str = f.readAsString(); str = f.readAsString();
@ -142,13 +145,19 @@ function test_os()
buf[i] = i; buf[i] = i;
assert(os.write(fd, buf.buffer, 0, buf.length) === buf.length); assert(os.write(fd, buf.buffer, 0, buf.length) === buf.length);
assert(os.seek(fd, 0, os.SEEK_SET) === 0); assert(os.seek(fd, 0, std.SEEK_SET) === 0);
buf2 = new Uint8Array(buf.length); buf2 = new Uint8Array(buf.length);
assert(os.read(fd, buf2.buffer, 0, buf2.length) === buf2.length); assert(os.read(fd, buf2.buffer, 0, buf2.length) === buf2.length);
for(i = 0; i < buf.length; i++) for(i = 0; i < buf.length; i++)
assert(buf[i] == buf2[i]); assert(buf[i] == buf2[i]);
if (typeof BigInt !== "undefined") {
assert(os.seek(fd, BigInt(6), std.SEEK_SET), BigInt(6));
assert(os.read(fd, buf2.buffer, 0, 1) === 1);
assert(buf[6] == buf2[0]);
}
assert(os.close(fd) === 0); assert(os.close(fd) === 0);
[files, err] = os.readdir(fdir); [files, err] = os.readdir(fdir);

View file

@ -1,8 +1,8 @@
#!/bin/sh #!/bin/sh
set -e set -e
url="ftp://ftp.unicode.org/Public/12.1.0/ucd" url="ftp://ftp.unicode.org/Public/13.0.0/ucd"
emoji_url="ftp://ftp.unicode.org/Public/emoji/12.0/emoji-data.txt" emoji_url="${url}/emoji/emoji-data.txt"
files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \ files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \
SpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \ SpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \
@ -11,9 +11,9 @@ PropertyValueAliases.txt"
mkdir -p unicode mkdir -p unicode
for f in $files; do #for f in $files; do
g="${url}/${f}" # g="${url}/${f}"
wget $g -O unicode/$f # wget $g -O unicode/$f
done #done
wget $emoji_url -O unicode/emoji-data.txt wget $emoji_url -O unicode/emoji-data.txt

View file

@ -66,6 +66,7 @@ DEF(Caucasian_Albanian, "Aghb")
DEF(Chakma, "Cakm") DEF(Chakma, "Cakm")
DEF(Cham, "Cham") DEF(Cham, "Cham")
DEF(Cherokee, "Cher") DEF(Cherokee, "Cher")
DEF(Chorasmian, "Chrs")
DEF(Common, "Zyyy") DEF(Common, "Zyyy")
DEF(Coptic, "Copt,Qaac") DEF(Coptic, "Copt,Qaac")
DEF(Cuneiform, "Xsux") DEF(Cuneiform, "Xsux")
@ -73,6 +74,7 @@ DEF(Cypriot, "Cprt")
DEF(Cyrillic, "Cyrl") DEF(Cyrillic, "Cyrl")
DEF(Deseret, "Dsrt") DEF(Deseret, "Dsrt")
DEF(Devanagari, "Deva") DEF(Devanagari, "Deva")
DEF(Dives_Akuru, "Diak")
DEF(Dogra, "Dogr") DEF(Dogra, "Dogr")
DEF(Duployan, "Dupl") DEF(Duployan, "Dupl")
DEF(Egyptian_Hieroglyphs, "Egyp") DEF(Egyptian_Hieroglyphs, "Egyp")
@ -106,6 +108,7 @@ DEF(Kayah_Li, "Kali")
DEF(Kharoshthi, "Khar") DEF(Kharoshthi, "Khar")
DEF(Khmer, "Khmr") DEF(Khmer, "Khmr")
DEF(Khojki, "Khoj") DEF(Khojki, "Khoj")
DEF(Khitan_Small_Script, "Kits")
DEF(Khudawadi, "Sind") DEF(Khudawadi, "Sind")
DEF(Lao, "Laoo") DEF(Lao, "Laoo")
DEF(Latin, "Latn") DEF(Latin, "Latn")
@ -193,6 +196,7 @@ DEF(Ugaritic, "Ugar")
DEF(Vai, "Vaii") DEF(Vai, "Vaii")
DEF(Wancho, "Wcho") DEF(Wancho, "Wcho")
DEF(Warang_Citi, "Wara") DEF(Warang_Citi, "Wara")
DEF(Yezidi, "Yezi")
DEF(Yi, "Yiii") DEF(Yi, "Yiii")
DEF(Zanabazar_Square, "Zanb") DEF(Zanabazar_Square, "Zanb")
#endif #endif
@ -244,11 +248,11 @@ DEF(Variation_Selector, "VS")
DEF(White_Space, "space") DEF(White_Space, "space")
DEF(Bidi_Mirrored, "Bidi_M") DEF(Bidi_Mirrored, "Bidi_M")
DEF(Emoji, "") DEF(Emoji, "")
DEF(Emoji_Component, "") DEF(Emoji_Component, "EComp")
DEF(Emoji_Modifier, "") DEF(Emoji_Modifier, "EMod")
DEF(Emoji_Modifier_Base, "") DEF(Emoji_Modifier_Base, "EBase")
DEF(Emoji_Presentation, "") DEF(Emoji_Presentation, "EPres")
DEF(Extended_Pictographic, "") DEF(Extended_Pictographic, "ExtPict")
DEF(Default_Ignorable_Code_Point, "DI") DEF(Default_Ignorable_Code_Point, "DI")
DEF(ID_Start, "IDS") DEF(ID_Start, "IDS")
DEF(Case_Ignorable, "CI") DEF(Case_Ignorable, "CI")