2020-07-05 release

This commit is contained in:
bellard 2020-09-06 19:07:30 +02:00
parent 1722758717
commit 8900766099
30 changed files with 3775 additions and 1729 deletions

View file

@ -1,3 +1,12 @@
2020-07-05:
- modified JS_GetPrototype() to return a live value
- REPL: support unicode characters larger than 16 bits
- added os.Worker
- improved object serialization
- added std.parseExtJSON
- misc bug fixes
2020-04-12: 2020-04-12:
- added cross realm support - added cross realm support

View file

@ -99,6 +99,10 @@ DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
ifdef CONFIG_BIGNUM ifdef CONFIG_BIGNUM
DEFINES+=-DCONFIG_BIGNUM DEFINES+=-DCONFIG_BIGNUM
endif endif
ifdef CONFIG_WIN32
DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior
endif
CFLAGS+=$(DEFINES) CFLAGS+=$(DEFINES)
CFLAGS_DEBUG=$(CFLAGS) -O0 CFLAGS_DEBUG=$(CFLAGS) -O0
CFLAGS_SMALL=$(CFLAGS) -Os CFLAGS_SMALL=$(CFLAGS) -Os
@ -115,8 +119,8 @@ CFLAGS+=-p
LDFLAGS+=-p LDFLAGS+=-p
endif endif
ifdef CONFIG_ASAN ifdef CONFIG_ASAN
CFLAGS+=-fsanitize=address CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
LDFLAGS+=-fsanitize=address LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer
endif endif
ifdef CONFIG_WIN32 ifdef CONFIG_WIN32
LDEXPORT= LDEXPORT=
@ -166,9 +170,10 @@ QJS_LIB_OBJS+=$(OBJDIR)/libbf.o
QJS_OBJS+=$(OBJDIR)/qjscalc.o QJS_OBJS+=$(OBJDIR)/qjscalc.o
endif endif
HOST_LIBS=-lm -ldl -lpthread
LIBS=-lm LIBS=-lm
ifndef CONFIG_WIN32 ifndef CONFIG_WIN32
LIBS+=-ldl LIBS+=-ldl -lpthread
endif endif
$(OBJDIR): $(OBJDIR):
@ -187,7 +192,7 @@ ifneq ($(CROSS_PREFIX),)
$(QJSC): $(OBJDIR)/qjsc.host.o \ $(QJSC): $(OBJDIR)/qjsc.host.o \
$(patsubst %.o, %.host.o, $(QJS_LIB_OBJS)) $(patsubst %.o, %.host.o, $(QJS_LIB_OBJS))
$(HOST_CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(HOST_CC) $(LDFLAGS) -o $@ $^ $(HOST_LIBS)
endif #CROSS_PREFIX endif #CROSS_PREFIX
@ -239,13 +244,13 @@ libunicode-table.h: unicode_gen
endif endif
run-test262: $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS) run-test262: $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
run-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)) run-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
run-test262-32: $(patsubst %.o, %.m32.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)) run-test262-32: $(patsubst %.o, %.m32.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread $(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
# object suffix order: nolto, [m32|m32s] # object suffix order: nolto, [m32|m32s]
@ -285,7 +290,7 @@ unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c u
clean: clean:
rm -f repl.c qjscalc.c out.c rm -f repl.c qjscalc.c out.c
rm -f *.a *.o *.d *~ jscompress unicode_gen regexp_test $(PROGS) rm -f *.a *.o *.d *~ jscompress unicode_gen regexp_test $(PROGS)
rm -f hello.c hello_module.c test_fib.c rm -f hello.c test_fib.c
rm -f examples/*.so tests/*.so rm -f examples/*.so tests/*.so
rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug
rm -rf run-test262-debug run-test262-32 rm -rf run-test262-debug run-test262-32
@ -379,10 +384,11 @@ endif
test: qjs test: qjs
./qjs tests/test_closure.js ./qjs tests/test_closure.js
./qjs tests/test_op.js ./qjs tests/test_language.js
./qjs tests/test_builtin.js ./qjs tests/test_builtin.js
./qjs tests/test_loop.js ./qjs tests/test_loop.js
./qjs tests/test_std.js ./qjs tests/test_std.js
./qjs tests/test_worker.js
ifndef CONFIG_DARWIN ifndef CONFIG_DARWIN
ifdef CONFIG_BIGNUM ifdef CONFIG_BIGNUM
./qjs --bignum tests/test_bjson.js ./qjs --bignum tests/test_bjson.js
@ -398,10 +404,11 @@ ifdef CONFIG_BIGNUM
endif endif
ifdef CONFIG_M32 ifdef CONFIG_M32
./qjs32 tests/test_closure.js ./qjs32 tests/test_closure.js
./qjs32 tests/test_op.js ./qjs32 tests/test_language.js
./qjs32 tests/test_builtin.js ./qjs32 tests/test_builtin.js
./qjs32 tests/test_loop.js ./qjs32 tests/test_loop.js
./qjs32 tests/test_std.js ./qjs32 tests/test_std.js
./qjs32 tests/test_worker.js
ifdef CONFIG_BIGNUM ifdef CONFIG_BIGNUM
./qjs32 --bignum tests/test_op_overloading.js ./qjs32 --bignum tests/test_op_overloading.js
./qjs32 --bignum tests/test_bignum.js ./qjs32 --bignum tests/test_bignum.js

8
TODO
View file

@ -1,4 +1,5 @@
Misc: Misc:
- use realpath in module name normalizer and put it in quickjs-libc
- use custom printf to avoid C library compatibility issues - use custom printf to avoid C library compatibility issues
- rename CONFIG_ALL_UNICODE, CONFIG_BIGNUM, CONFIG_ATOMICS, CONFIG_CHECK_JSVALUE ? - rename CONFIG_ALL_UNICODE, CONFIG_BIGNUM, CONFIG_ATOMICS, CONFIG_CHECK_JSVALUE ?
- unify coding style and naming conventions - unify coding style and naming conventions
@ -56,12 +57,12 @@ Extensions:
handle #if, #ifdef, #line, limited support for #define handle #if, #ifdef, #line, limited support for #define
- get rid of __loadScript, use more common name - get rid of __loadScript, use more common name
- BSD sockets - BSD sockets
- Workers
REPL: REPL:
- debugger - debugger
- readline: support MS Windows terminal - readline: support MS Windows terminal
- readline: handle dynamic terminal resizing - readline: handle dynamic terminal resizing
- readline: handle double width unicode characters
- multiline editing - multiline editing
- runtime object and function inspectors - runtime object and function inspectors
- interactive object browser - interactive object browser
@ -73,6 +74,5 @@ 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: 28/70829 errors, 877 excluded, 425 skipped Test262: 30/71095 errors, 870 excluded, 549 skipped
Test262 commit: 4a8e49b3ca7f9f74a4cafe6621ff9ba548ccc353 Test262 commit: 281eb10b2844929a7c0ac04527f5b42ce56509fd

View file

@ -1 +1 @@
2020-04-12 2020-07-05

View file

@ -268,6 +268,10 @@ void dbuf_free(DynBuf *s);
static inline BOOL dbuf_error(DynBuf *s) { static inline BOOL dbuf_error(DynBuf *s) {
return s->error; return s->error;
} }
static inline void dbuf_set_error(DynBuf *s)
{
s->error = TRUE;
}
#define UTF8_CHAR_LEN_MAX 6 #define UTF8_CHAR_LEN_MAX 6

View file

@ -1,7 +1,8 @@
<!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.1, http://www.gnu.org/software/texinfo/ --> <!-- Created by GNU Texinfo 6.5, 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">
@ -9,7 +10,6 @@
<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">
<!-- <!--

Binary file not shown.

View file

@ -1,7 +1,8 @@
<!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.1, http://www.gnu.org/software/texinfo/ --> <!-- Created by GNU Texinfo 6.5, 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">
@ -9,7 +10,6 @@
<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">
<!-- <!--
@ -73,10 +73,9 @@ ul.no-bullet {list-style: none}
<li><a name="toc-Language-support" href="#Language-support">3.1 Language support</a> <li><a name="toc-Language-support" href="#Language-support">3.1 Language support</a>
<ul class="no-bullet"> <ul class="no-bullet">
<li><a name="toc-ES2020-support" href="#ES2020-support">3.1.1 ES2020 support</a></li> <li><a name="toc-ES2020-support" href="#ES2020-support">3.1.1 ES2020 support</a></li>
<li><a name="toc-JSON" href="#JSON">3.1.2 JSON</a></li> <li><a name="toc-ECMA402" href="#ECMA402">3.1.2 ECMA402</a></li>
<li><a name="toc-ECMA402" href="#ECMA402">3.1.3 ECMA402</a></li> <li><a name="toc-Extensions" href="#Extensions">3.1.3 Extensions</a></li>
<li><a name="toc-Extensions" href="#Extensions">3.1.4 Extensions</a></li> <li><a name="toc-Mathematical-extensions" href="#Mathematical-extensions">3.1.4 Mathematical extensions</a></li>
<li><a name="toc-Mathematical-extensions" href="#Mathematical-extensions">3.1.5 Mathematical extensions</a></li>
</ul></li> </ul></li>
<li><a name="toc-Modules" href="#Modules">3.2 Modules</a></li> <li><a name="toc-Modules" href="#Modules">3.2 Modules</a></li>
<li><a name="toc-Standard-library" href="#Standard-library">3.3 Standard library</a> <li><a name="toc-Standard-library" href="#Standard-library">3.3 Standard library</a>
@ -407,18 +406,13 @@ B (legacy web compatibility) and the Unicode related features.
</li></ul> </li></ul>
<a name="JSON"></a>
<h4 class="subsection">3.1.2 JSON</h4>
<p>The JSON parser is currently more tolerant than the specification.
</p>
<a name="ECMA402"></a> <a name="ECMA402"></a>
<h4 class="subsection">3.1.3 ECMA402</h4> <h4 class="subsection">3.1.2 ECMA402</h4>
<p>ECMA402 (Internationalization API) is not supported. <p>ECMA402 (Internationalization API) is not supported.
</p> </p>
<a name="Extensions"></a> <a name="Extensions"></a>
<h4 class="subsection">3.1.4 Extensions</h4> <h4 class="subsection">3.1.3 Extensions</h4>
<ul> <ul>
<li> The directive <code>&quot;use strip&quot;</code> indicates that the debug information (including the source code of the functions) should not be retained to save memory. As <code>&quot;use strict&quot;</code>, the directive can be global to a script or local to a function. <li> The directive <code>&quot;use strip&quot;</code> indicates that the debug information (including the source code of the functions) should not be retained to save memory. As <code>&quot;use strict&quot;</code>, the directive can be global to a script or local to a function.
@ -428,7 +422,7 @@ B (legacy web compatibility) and the Unicode related features.
</li></ul> </li></ul>
<a name="Mathematical-extensions"></a> <a name="Mathematical-extensions"></a>
<h4 class="subsection">3.1.5 Mathematical extensions</h4> <h4 class="subsection">3.1.4 Mathematical extensions</h4>
<p>The mathematical extensions are fully backward compatible with <p>The mathematical extensions are fully backward compatible with
standard Javascript. See <code>jsbignum.pdf</code> for more information. standard Javascript. See <code>jsbignum.pdf</code> for more information.
@ -557,7 +551,7 @@ no error occured.
</p> </p>
</dd> </dd>
<dt><code>printf(fmt, ...args)</code></dt> <dt><code>printf(fmt, ...args)</code></dt>
<dd><p>Equivalent to <code>std.out.printf(fmt, ...args)</code> <dd><p>Equivalent to <code>std.out.printf(fmt, ...args)</code>.
</p> </p>
</dd> </dd>
<dt><code>sprintf(fmt, ...args)</code></dt> <dt><code>sprintf(fmt, ...args)</code></dt>
@ -636,6 +630,21 @@ optional properties:
</dd> </dd>
</dl> </dl>
</dd>
<dt><code>parseExtJSON(str)</code></dt>
<dd>
<p>Parse <code>str</code> using a superset of <code>JSON.parse</code>. The
following extensions are accepted:
</p>
<ul>
<li> Single line and multiline comments
</li><li> unquoted properties (ASCII-only Javascript identifiers)
</li><li> trailing comma in array and object definitions
</li><li> single quoted strings
</li><li> <code>\f</code> and <code>\v</code> are accepted as space characters
</li><li> leading plus in numbers
</li><li> octal (<code>0o</code> prefix) and hexadecimal (<code>0x</code> prefix) numbers
</li></ul>
</dd> </dd>
</dl> </dl>
@ -649,8 +658,14 @@ optional properties:
<dd><p>Outputs the string with the UTF-8 encoding. <dd><p>Outputs the string with the UTF-8 encoding.
</p></dd> </p></dd>
<dt><code>printf(fmt, ...args)</code></dt> <dt><code>printf(fmt, ...args)</code></dt>
<dd><p>Formatted printf, same formats as the libc printf. <dd><p>Formatted printf.
</p></dd> </p>
<p>The same formats as the standard C library <code>printf</code> are
supported. Integer format types (e.g. <code>%d</code>) truncate the Numbers
or BigInts to 32 bits. Use the <code>l</code> modifier (e.g. <code>%ld</code>) to
truncate to 64 bits.
</p>
</dd>
<dt><code>flush()</code></dt> <dt><code>flush()</code></dt>
<dd><p>Flush the buffered file. <dd><p>Flush the buffered file.
</p></dd> </p></dd>
@ -718,6 +733,7 @@ is read up its end.
</li><li> signals </li><li> signals
</li><li> timers </li><li> timers
</li><li> asynchronous I/O </li><li> asynchronous I/O
</li><li> workers (threads)
</li></ul> </li></ul>
<p>The OS functions usually return 0 if OK or an OS specific negative <p>The OS functions usually return 0 if OK or an OS specific negative
@ -869,7 +885,7 @@ the handler.
<dd><p>Call the function <code>func</code> when the signal <code>signal</code> <dd><p>Call the function <code>func</code> when the signal <code>signal</code>
happens. Only a single handler per signal number is supported. Use happens. Only a single handler per signal number is supported. Use
<code>null</code> to set the default handler or <code>undefined</code> to ignore <code>null</code> to set the default handler or <code>undefined</code> to ignore
the signal. the signal. Signal handlers can only be defined in the main thread.
</p> </p>
</dd> </dd>
<dt><code>SIGINT</code></dt> <dt><code>SIGINT</code></dt>
@ -972,6 +988,49 @@ to the timer.
<dd><p>Return a string representing the platform: <code>&quot;linux&quot;</code>, <code>&quot;darwin&quot;</code>, <dd><p>Return a string representing the platform: <code>&quot;linux&quot;</code>, <code>&quot;darwin&quot;</code>,
<code>&quot;win32&quot;</code> or <code>&quot;js&quot;</code>. <code>&quot;win32&quot;</code> or <code>&quot;js&quot;</code>.
</p> </p>
</dd>
<dt><code>Worker(source)</code></dt>
<dd><p>Constructor to create a new thread (worker) with an API close to the
<code>WebWorkers</code>. <code>source</code> is a string containing the module
source which is executed in the newly created thread. Threads normally
don&rsquo;t share any data and communicate between each other with
messages. Nested workers are not supported. An example is available in
<samp>tests/test_worker.js</samp>.
</p>
<p>The worker class has the following static properties:
</p>
<dl compact="compact">
<dt><code>parent</code></dt>
<dd><p>In the created worker, <code>Worker.parent</code> represents the parent
worker and is used to send or receive messages.
</p></dd>
</dl>
<p>The worker instances have the following properties:
</p>
<dl compact="compact">
<dt><code>postMessage(msg)</code></dt>
<dd>
<p>Send a message to the corresponding worker. <code>msg</code> is cloned in
the destination worker using an algorithm similar to the <code>HTML</code>
structured clone algorithm. <code>SharedArrayBuffer</code> are shared
between workers.
</p>
<p>Current limitations: <code>Map</code> and <code>Set</code> are not supported
yet.
</p>
</dd>
<dt><code>onmessage</code></dt>
<dd>
<p>Getter and setter. Set a function which is called each time a
message is received. The function is called with a single
argument. It is an object with a <code>data</code> property containing the
received message. The thread is not terminated if there is at least
one non <code>null</code> <code>onmessage</code> handler.
</p>
</dd>
</dl>
</dd> </dd>
</dl> </dl>

Binary file not shown.

View file

@ -272,10 +272,6 @@ The following features are not supported yet:
@end itemize @end itemize
@subsection JSON
The JSON parser is currently more tolerant than the specification.
@subsection ECMA402 @subsection ECMA402
ECMA402 (Internationalization API) is not supported. ECMA402 (Internationalization API) is not supported.
@ -405,7 +401,7 @@ no error occured.
Equivalent to @code{std.out.puts(str)}. Equivalent to @code{std.out.puts(str)}.
@item printf(fmt, ...args) @item printf(fmt, ...args)
Equivalent to @code{std.out.printf(fmt, ...args)} Equivalent to @code{std.out.printf(fmt, ...args)}.
@item sprintf(fmt, ...args) @item sprintf(fmt, ...args)
Equivalent to the libc sprintf(). Equivalent to the libc sprintf().
@ -474,6 +470,20 @@ optional properties:
@end table @end table
@item parseExtJSON(str)
Parse @code{str} using a superset of @code{JSON.parse}. The
following extensions are accepted:
@itemize
@item Single line and multiline comments
@item unquoted properties (ASCII-only Javascript identifiers)
@item trailing comma in array and object definitions
@item single quoted strings
@item @code{\f} and @code{\v} are accepted as space characters
@item leading plus in numbers
@item octal (@code{0o} prefix) and hexadecimal (@code{0x} prefix) numbers
@end itemize
@end table @end table
FILE prototype: FILE prototype:
@ -484,7 +494,13 @@ 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)
Formatted printf, same formats as the libc printf. Formatted printf.
The same formats as the standard C library @code{printf} are
supported. Integer format types (e.g. @code{%d}) truncate the Numbers
or BigInts to 32 bits. Use the @code{l} modifier (e.g. @code{%ld}) to
truncate to 64 bits.
@item flush() @item flush()
Flush the buffered file. Flush the buffered file.
@item seek(offset, whence) @item seek(offset, whence)
@ -537,6 +553,7 @@ The @code{os} module provides Operating System specific functions:
@item signals @item signals
@item timers @item timers
@item asynchronous I/O @item asynchronous I/O
@item workers (threads)
@end itemize @end itemize
The OS functions usually return 0 if OK or an OS specific negative The OS functions usually return 0 if OK or an OS specific negative
@ -664,7 +681,7 @@ the handler.
Call the function @code{func} when the signal @code{signal} Call the function @code{func} when the signal @code{signal}
happens. Only a single handler per signal number is supported. Use happens. Only a single handler per signal number is supported. Use
@code{null} to set the default handler or @code{undefined} to ignore @code{null} to set the default handler or @code{undefined} to ignore
the signal. the signal. Signal handlers can only be defined in the main thread.
@item SIGINT @item SIGINT
@item SIGABRT @item SIGABRT
@ -747,6 +764,45 @@ Cancel a timer.
Return a string representing the platform: @code{"linux"}, @code{"darwin"}, Return a string representing the platform: @code{"linux"}, @code{"darwin"},
@code{"win32"} or @code{"js"}. @code{"win32"} or @code{"js"}.
@item Worker(source)
Constructor to create a new thread (worker) with an API close to the
@code{WebWorkers}. @code{source} is a string containing the module
source which is executed in the newly created thread. Threads normally
don't share any data and communicate between each other with
messages. Nested workers are not supported. An example is available in
@file{tests/test_worker.js}.
The worker class has the following static properties:
@table @code
@item parent
In the created worker, @code{Worker.parent} represents the parent
worker and is used to send or receive messages.
@end table
The worker instances have the following properties:
@table @code
@item postMessage(msg)
Send a message to the corresponding worker. @code{msg} is cloned in
the destination worker using an algorithm similar to the @code{HTML}
structured clone algorithm. @code{SharedArrayBuffer} are shared
between workers.
Current limitations: @code{Map} and @code{Set} are not supported
yet.
@item onmessage
Getter and setter. Set a function which is called each time a
message is received. The function is called with a single
argument. It is an object with a @code{data} property containing the
received message. The thread is not terminated if there is at least
one non @code{null} @code{onmessage} handler.
@end table
@end table @end table
@section QuickJS C API @section QuickJS C API

View file

@ -130,11 +130,11 @@ static int js_point_init(JSContext *ctx, JSModuleDef *m)
point_proto = JS_NewObject(ctx); point_proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs)); JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs));
JS_SetClassProto(ctx, js_point_class_id, point_proto);
point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0); point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0);
/* set proto.constructor and ctor.prototype */ /* set proto.constructor and ctor.prototype */
JS_SetConstructor(ctx, point_class, point_proto); JS_SetConstructor(ctx, point_class, point_proto);
JS_SetClassProto(ctx, js_point_class_id, point_proto);
JS_SetModuleExport(ctx, m, "Point", point_class); JS_SetModuleExport(ctx, m, "Point", point_class);
return 0; return 0;

75
libbf.c
View file

@ -3370,12 +3370,14 @@ slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,
} }
/* 'n' is the number of output limbs */ /* 'n' is the number of output limbs */
static void bf_integer_to_radix_rec(bf_t *pow_tab, static int bf_integer_to_radix_rec(bf_t *pow_tab,
limb_t *out, const bf_t *a, limb_t n, limb_t *out, const bf_t *a, limb_t n,
int level, limb_t n0, limb_t radixl, int level, limb_t n0, limb_t radixl,
unsigned int radixl_bits) unsigned int radixl_bits)
{ {
limb_t n1, n2, q_prec; limb_t n1, n2, q_prec;
int ret;
assert(n >= 1); assert(n >= 1);
if (n == 1) { if (n == 1) {
out[0] = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn); out[0] = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn);
@ -3402,63 +3404,81 @@ static void bf_integer_to_radix_rec(bf_t *pow_tab,
n1 = n - n2; n1 = n - n2;
B = &pow_tab[2 * level]; B = &pow_tab[2 * level];
B_inv = &pow_tab[2 * level + 1]; B_inv = &pow_tab[2 * level + 1];
ret = 0;
if (B->len == 0) { if (B->len == 0) {
/* compute BASE^n2 */ /* compute BASE^n2 */
bf_pow_ui_ui(B, radixl, n2, BF_PREC_INF, BF_RNDZ); ret |= bf_pow_ui_ui(B, radixl, n2, BF_PREC_INF, BF_RNDZ);
/* we use enough bits for the maximum possible 'n1' value, /* we use enough bits for the maximum possible 'n1' value,
i.e. n2 + 1 */ i.e. n2 + 1 */
bf_set_ui(&R, 1); ret |= bf_set_ui(&R, 1);
bf_div(B_inv, &R, B, (n2 + 1) * radixl_bits + 2, BF_RNDN); ret |= bf_div(B_inv, &R, B, (n2 + 1) * radixl_bits + 2, BF_RNDN);
} }
// printf("%d: n1=% " PRId64 " n2=%" PRId64 "\n", level, n1, n2); // printf("%d: n1=% " PRId64 " n2=%" PRId64 "\n", level, n1, n2);
q_prec = n1 * radixl_bits; q_prec = n1 * radixl_bits;
bf_mul(&Q, a, B_inv, q_prec, BF_RNDN); ret |= bf_mul(&Q, a, B_inv, q_prec, BF_RNDN);
bf_rint(&Q, BF_RNDZ); ret |= bf_rint(&Q, BF_RNDZ);
bf_mul(&R, &Q, B, BF_PREC_INF, BF_RNDZ); ret |= bf_mul(&R, &Q, B, BF_PREC_INF, BF_RNDZ);
bf_sub(&R, a, &R, BF_PREC_INF, BF_RNDZ); ret |= bf_sub(&R, a, &R, BF_PREC_INF, BF_RNDZ);
if (ret & BF_ST_MEM_ERROR)
goto fail;
/* adjust if necessary */ /* adjust if necessary */
q_add = 0; q_add = 0;
while (R.sign && R.len != 0) { while (R.sign && R.len != 0) {
bf_add(&R, &R, B, BF_PREC_INF, BF_RNDZ); if (bf_add(&R, &R, B, BF_PREC_INF, BF_RNDZ))
goto fail;
q_add--; q_add--;
} }
while (bf_cmpu(&R, B) >= 0) { while (bf_cmpu(&R, B) >= 0) {
bf_sub(&R, &R, B, BF_PREC_INF, BF_RNDZ); if (bf_sub(&R, &R, B, BF_PREC_INF, BF_RNDZ))
goto fail;
q_add++; q_add++;
} }
if (q_add != 0) { if (q_add != 0) {
bf_add_si(&Q, &Q, q_add, BF_PREC_INF, BF_RNDZ); if (bf_add_si(&Q, &Q, q_add, BF_PREC_INF, BF_RNDZ))
goto fail;
}
if (bf_integer_to_radix_rec(pow_tab, out + n2, &Q, n1, level + 1, n0,
radixl, radixl_bits))
goto fail;
if (bf_integer_to_radix_rec(pow_tab, out, &R, n2, level + 1, n0,
radixl, radixl_bits)) {
fail:
bf_delete(&Q);
bf_delete(&R);
return -1;
} }
bf_integer_to_radix_rec(pow_tab, out + n2, &Q, n1, level + 1, n0,
radixl, radixl_bits);
bf_integer_to_radix_rec(pow_tab, out, &R, n2, level + 1, n0,
radixl, radixl_bits);
bf_delete(&Q); bf_delete(&Q);
bf_delete(&R); bf_delete(&R);
} }
return 0;
} }
static void bf_integer_to_radix(bf_t *r, const bf_t *a, limb_t radixl) /* return 0 if OK != 0 if memory error */
static int bf_integer_to_radix(bf_t *r, const bf_t *a, limb_t radixl)
{ {
bf_context_t *s = r->ctx; bf_context_t *s = r->ctx;
limb_t r_len; limb_t r_len;
bf_t *pow_tab; bf_t *pow_tab;
int i, pow_tab_len; int i, pow_tab_len, ret;
r_len = r->len; r_len = r->len;
pow_tab_len = (ceil_log2(r_len) + 2) * 2; /* XXX: check */ pow_tab_len = (ceil_log2(r_len) + 2) * 2; /* XXX: check */
pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len); pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len);
if (!pow_tab)
return -1;
for(i = 0; i < pow_tab_len; i++) for(i = 0; i < pow_tab_len; i++)
bf_init(r->ctx, &pow_tab[i]); bf_init(r->ctx, &pow_tab[i]);
bf_integer_to_radix_rec(pow_tab, r->tab, a, r_len, 0, r_len, radixl, ret = bf_integer_to_radix_rec(pow_tab, r->tab, a, r_len, 0, r_len, radixl,
ceil_log2(radixl)); ceil_log2(radixl));
for(i = 0; i < pow_tab_len; i++) { for(i = 0; i < pow_tab_len; i++) {
bf_delete(&pow_tab[i]); bf_delete(&pow_tab[i]);
} }
bf_free(s, pow_tab); bf_free(s, pow_tab);
return ret;
} }
/* a must be >= 0. 'P' is the wanted number of digits in radix /* a must be >= 0. 'P' is the wanted number of digits in radix
@ -3625,8 +3645,14 @@ static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits,
a = &a_s; a = &a_s;
bf_init(a1->ctx, a); bf_init(a1->ctx, a);
n = (n_digits + digits_per_limb - 1) / digits_per_limb; n = (n_digits + digits_per_limb - 1) / digits_per_limb;
bf_resize(a, n); if (bf_resize(a, n)) {
bf_integer_to_radix(a, a1, radixl); dbuf_set_error(s);
goto done;
}
if (bf_integer_to_radix(a, a1, radixl)) {
dbuf_set_error(s);
goto done;
}
radix_bits = 0; radix_bits = 0;
pos = n; pos = n;
pos_incr = 1; pos_incr = 1;
@ -3659,6 +3685,7 @@ static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits,
buf_pos += l; buf_pos += l;
i += l; i += l;
} }
done:
if (a != a1) if (a != a1)
bf_delete(a); bf_delete(a);
} }

View file

@ -110,12 +110,14 @@ static inline int is_digit(int c) {
return c >= '0' && c <= '9'; return c >= '0' && c <= '9';
} }
/* insert 'len' bytes at position 'pos' */ /* insert 'len' bytes at position 'pos'. Return < 0 if error. */
static void dbuf_insert(DynBuf *s, int pos, int len) static int dbuf_insert(DynBuf *s, int pos, int len)
{ {
dbuf_realloc(s, s->size + len); if (dbuf_realloc(s, s->size + len))
return -1;
memmove(s->buf + pos + len, s->buf + pos, s->size - pos); memmove(s->buf + pos + len, s->buf + pos, s->size - pos);
s->size += len; s->size += len;
return 0;
} }
/* canonicalize with the specific JS regexp rules */ /* canonicalize with the specific JS regexp rules */
@ -434,6 +436,11 @@ static int __attribute__((format(printf, 2, 3))) re_parse_error(REParseState *s,
return -1; return -1;
} }
static int re_parse_out_of_memory(REParseState *s)
{
return re_parse_error(s, "out of memory");
}
/* If allow_overflow is false, return -1 in case of /* If allow_overflow is false, return -1 in case of
overflow. Otherwise return INT32_MAX. */ overflow. Otherwise return INT32_MAX. */
static int parse_digits(const uint8_t **pp, BOOL allow_overflow) static int parse_digits(const uint8_t **pp, BOOL allow_overflow)
@ -693,7 +700,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
*pp = p; *pp = p;
return 0; return 0;
out_of_memory: out_of_memory:
return re_parse_error(s, "out of memory"); return re_parse_out_of_memory(s);
} }
#endif /* CONFIG_ALL_UNICODE */ #endif /* CONFIG_ALL_UNICODE */
@ -928,7 +935,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
*pp = p; *pp = p;
return 0; return 0;
memory_error: memory_error:
re_parse_error(s, "out of memory"); re_parse_out_of_memory(s);
fail: fail:
cr_free(cr); cr_free(cr);
return -1; return -1;
@ -1295,6 +1302,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
return -1; return -1;
re_emit_op(s, REOP_match); re_emit_op(s, REOP_match);
/* jump after the 'match' after the lookahead is successful */ /* jump after the 'match' after the lookahead is successful */
if (dbuf_error(&s->byte_code))
return -1;
put_u32(s->byte_code.buf + pos, s->byte_code.size - (pos + 4)); put_u32(s->byte_code.buf + pos, s->byte_code.size - (pos + 4));
} else if (p[2] == '<') { } else if (p[2] == '<') {
p += 3; p += 3;
@ -1548,12 +1557,15 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
if (quant_max > 0) { if (quant_max > 0) {
/* specific optimization for simple quantifiers */ /* specific optimization for simple quantifiers */
if (dbuf_error(&s->byte_code))
goto out_of_memory;
len = re_is_simple_quantifier(s->byte_code.buf + last_atom_start, len = re_is_simple_quantifier(s->byte_code.buf + last_atom_start,
s->byte_code.size - last_atom_start); s->byte_code.size - last_atom_start);
if (len > 0) { if (len > 0) {
re_emit_op(s, REOP_match); re_emit_op(s, REOP_match);
dbuf_insert(&s->byte_code, last_atom_start, 17); if (dbuf_insert(&s->byte_code, last_atom_start, 17))
goto out_of_memory;
pos = last_atom_start; pos = last_atom_start;
s->byte_code.buf[pos++] = REOP_simple_greedy_quant; s->byte_code.buf[pos++] = REOP_simple_greedy_quant;
put_u32(&s->byte_code.buf[pos], put_u32(&s->byte_code.buf[pos],
@ -1569,6 +1581,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
} }
} }
if (dbuf_error(&s->byte_code))
goto out_of_memory;
add_zero_advance_check = (re_check_advance(s->byte_code.buf + last_atom_start, add_zero_advance_check = (re_check_advance(s->byte_code.buf + last_atom_start,
s->byte_code.size - last_atom_start) == 0); s->byte_code.size - last_atom_start) == 0);
} else { } else {
@ -1582,7 +1596,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
/* need to reset the capture in case the atom is /* need to reset the capture in case the atom is
not executed */ not executed */
if (last_capture_count != s->capture_count) { if (last_capture_count != s->capture_count) {
dbuf_insert(&s->byte_code, last_atom_start, 3); if (dbuf_insert(&s->byte_code, last_atom_start, 3))
goto out_of_memory;
s->byte_code.buf[last_atom_start++] = REOP_save_reset; s->byte_code.buf[last_atom_start++] = REOP_save_reset;
s->byte_code.buf[last_atom_start++] = last_capture_count; s->byte_code.buf[last_atom_start++] = last_capture_count;
s->byte_code.buf[last_atom_start++] = s->capture_count - 1; s->byte_code.buf[last_atom_start++] = s->capture_count - 1;
@ -1590,12 +1605,14 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
if (quant_max == 0) { if (quant_max == 0) {
s->byte_code.size = last_atom_start; s->byte_code.size = last_atom_start;
} else if (quant_max == 1) { } else if (quant_max == 1) {
dbuf_insert(&s->byte_code, last_atom_start, 5); if (dbuf_insert(&s->byte_code, last_atom_start, 5))
goto out_of_memory;
s->byte_code.buf[last_atom_start] = REOP_split_goto_first + s->byte_code.buf[last_atom_start] = REOP_split_goto_first +
greedy; greedy;
put_u32(s->byte_code.buf + last_atom_start + 1, len); put_u32(s->byte_code.buf + last_atom_start + 1, len);
} else if (quant_max == INT32_MAX) { } else if (quant_max == INT32_MAX) {
dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check); if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check))
goto out_of_memory;
s->byte_code.buf[last_atom_start] = REOP_split_goto_first + s->byte_code.buf[last_atom_start] = REOP_split_goto_first +
greedy; greedy;
put_u32(s->byte_code.buf + last_atom_start + 1, put_u32(s->byte_code.buf + last_atom_start + 1,
@ -1611,7 +1628,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
re_emit_goto(s, REOP_goto, last_atom_start); re_emit_goto(s, REOP_goto, last_atom_start);
} }
} else { } else {
dbuf_insert(&s->byte_code, last_atom_start, 10); if (dbuf_insert(&s->byte_code, last_atom_start, 10))
goto out_of_memory;
pos = last_atom_start; pos = last_atom_start;
s->byte_code.buf[pos++] = REOP_push_i32; s->byte_code.buf[pos++] = REOP_push_i32;
put_u32(s->byte_code.buf + pos, quant_max); put_u32(s->byte_code.buf + pos, quant_max);
@ -1629,7 +1647,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
if (quant_min == 1) { if (quant_min == 1) {
/* nothing to add */ /* nothing to add */
} else { } else {
dbuf_insert(&s->byte_code, last_atom_start, 5); if (dbuf_insert(&s->byte_code, last_atom_start, 5))
goto out_of_memory;
s->byte_code.buf[last_atom_start] = REOP_push_i32; s->byte_code.buf[last_atom_start] = REOP_push_i32;
put_u32(s->byte_code.buf + last_atom_start + 1, put_u32(s->byte_code.buf + last_atom_start + 1,
quant_min); quant_min);
@ -1670,6 +1689,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
done: done:
s->buf_ptr = p; s->buf_ptr = p;
return 0; return 0;
out_of_memory:
return re_parse_out_of_memory(s);
} }
static int re_parse_alternative(REParseState *s, BOOL is_backward_dir) static int re_parse_alternative(REParseState *s, BOOL is_backward_dir)
@ -1719,7 +1740,9 @@ static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir)
len = s->byte_code.size - start; len = s->byte_code.size - start;
/* insert a split before the first alternative */ /* insert a split before the first alternative */
dbuf_insert(&s->byte_code, start, 5); if (dbuf_insert(&s->byte_code, start, 5)) {
return re_parse_out_of_memory(s);
}
s->byte_code.buf[start] = REOP_split_next_first; s->byte_code.buf[start] = REOP_split_next_first;
put_u32(s->byte_code.buf + start + 1, len + 5); put_u32(s->byte_code.buf + start + 1, len + 5);
@ -1844,7 +1867,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
} }
if (dbuf_error(&s->byte_code)) { if (dbuf_error(&s->byte_code)) {
re_parse_error(s, "out of memory"); re_parse_out_of_memory(s);
goto error; goto error;
} }

13
qjs.c
View file

@ -270,6 +270,7 @@ void help(void)
"-T --trace trace memory allocation\n" "-T --trace trace memory allocation\n"
"-d --dump dump the memory usage stats\n" "-d --dump dump the memory usage stats\n"
" --memory-limit n limit the memory usage to 'n' bytes\n" " --memory-limit n limit the memory usage to 'n' bytes\n"
" --stack-size n limit the stack size to 'n' bytes\n"
" --unhandled-rejection dump unhandled promise rejections\n" " --unhandled-rejection dump unhandled promise rejections\n"
"-q --quit just instantiate the interpreter and quit\n"); "-q --quit just instantiate the interpreter and quit\n");
exit(1); exit(1);
@ -295,6 +296,7 @@ int main(int argc, char **argv)
#ifdef CONFIG_BIGNUM #ifdef CONFIG_BIGNUM
int load_jscalc, bignum_ext = 0; int load_jscalc, bignum_ext = 0;
#endif #endif
size_t stack_size = 0;
#ifdef CONFIG_BIGNUM #ifdef CONFIG_BIGNUM
/* load jscalc runtime if invoked as 'qjscalc' */ /* load jscalc runtime if invoked as 'qjscalc' */
@ -407,6 +409,14 @@ int main(int argc, char **argv)
memory_limit = (size_t)strtod(argv[optind++], NULL); memory_limit = (size_t)strtod(argv[optind++], NULL);
continue; continue;
} }
if (!strcmp(longopt, "stack-size")) {
if (optind >= argc) {
fprintf(stderr, "expecting stack size");
exit(1);
}
stack_size = (size_t)strtod(argv[optind++], NULL);
continue;
}
if (opt) { if (opt) {
fprintf(stderr, "qjs: unknown option '-%c'\n", opt); fprintf(stderr, "qjs: unknown option '-%c'\n", opt);
} else { } else {
@ -428,6 +438,9 @@ int main(int argc, char **argv)
} }
if (memory_limit != 0) if (memory_limit != 0)
JS_SetMemoryLimit(rt, memory_limit); JS_SetMemoryLimit(rt, memory_limit);
if (stack_size != 0)
JS_SetMaxStackSize(rt, stack_size);
js_std_init_handlers(rt);
ctx = JS_NewContext(rt); ctx = JS_NewContext(rt);
if (!ctx) { if (!ctx) {
fprintf(stderr, "qjs: cannot allocate JS context\n"); fprintf(stderr, "qjs: cannot allocate JS context\n");

17
qjsc.c
View file

@ -326,6 +326,7 @@ static const char main_c_template1[] =
" JSRuntime *rt;\n" " JSRuntime *rt;\n"
" JSContext *ctx;\n" " JSContext *ctx;\n"
" rt = JS_NewRuntime();\n" " rt = JS_NewRuntime();\n"
" js_std_init_handlers(rt);\n"
; ;
static const char main_c_template2[] = static const char main_c_template2[] =
@ -351,7 +352,8 @@ void help(void)
"-M module_name[,cname] add initialization code for an external C module\n" "-M module_name[,cname] add initialization code for an external C module\n"
"-x byte swapped output\n" "-x byte swapped output\n"
"-p prefix set the prefix of the generated C names\n" "-p prefix set the prefix of the generated C names\n"
); "-S n set the maximum stack size to 'n' bytes (default=%d)\n",
JS_DEFAULT_STACK_SIZE);
#ifdef CONFIG_LTO #ifdef CONFIG_LTO
{ {
int i; int i;
@ -447,6 +449,7 @@ static int output_executable(const char *out_filename, const char *cfilename,
*arg++ = libjsname; *arg++ = libjsname;
*arg++ = "-lm"; *arg++ = "-lm";
*arg++ = "-ldl"; *arg++ = "-ldl";
*arg++ = "-lpthread";
*arg = NULL; *arg = NULL;
if (verbose) { if (verbose) {
@ -487,6 +490,7 @@ int main(int argc, char **argv)
BOOL use_lto; BOOL use_lto;
int module; int module;
OutputTypeEnum output_type; OutputTypeEnum output_type;
size_t stack_size;
#ifdef CONFIG_BIGNUM #ifdef CONFIG_BIGNUM
BOOL bignum_ext = FALSE; BOOL bignum_ext = FALSE;
#endif #endif
@ -499,13 +503,14 @@ int main(int argc, char **argv)
byte_swap = FALSE; byte_swap = FALSE;
verbose = 0; verbose = 0;
use_lto = FALSE; use_lto = FALSE;
stack_size = 0;
/* add system modules */ /* add system modules */
namelist_add(&cmodule_list, "std", "std", 0); namelist_add(&cmodule_list, "std", "std", 0);
namelist_add(&cmodule_list, "os", "os", 0); namelist_add(&cmodule_list, "os", "os", 0);
for(;;) { for(;;) {
c = getopt(argc, argv, "ho:cN:f:mxevM:p:"); c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:");
if (c == -1) if (c == -1)
break; break;
switch(c) { switch(c) {
@ -580,6 +585,9 @@ int main(int argc, char **argv)
case 'p': case 'p':
c_ident_prefix = optarg; c_ident_prefix = optarg;
break; break;
case 'S':
stack_size = (size_t)strtod(optarg, NULL);
break;
default: default:
break; break;
} }
@ -652,6 +660,11 @@ int main(int argc, char **argv)
fputs(main_c_template1, fo); fputs(main_c_template1, fo);
fprintf(fo, " ctx = JS_NewContextRaw(rt);\n"); fprintf(fo, " ctx = JS_NewContextRaw(rt);\n");
if (stack_size != 0) {
fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n",
(unsigned int)stack_size);
}
/* add the module loader if necessary */ /* add the module loader if necessary */
if (feature_bitmap & (1 << FE_MODULE_LOADER)) { if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n"); fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");

View file

@ -82,6 +82,7 @@ DEF(length, "length")
DEF(fileName, "fileName") DEF(fileName, "fileName")
DEF(lineNumber, "lineNumber") DEF(lineNumber, "lineNumber")
DEF(message, "message") DEF(message, "message")
DEF(errors, "errors")
DEF(stack, "stack") DEF(stack, "stack")
DEF(name, "name") DEF(name, "name")
DEF(toString, "toString") DEF(toString, "toString")

File diff suppressed because it is too large Load diff

View file

@ -29,10 +29,15 @@
#include "quickjs.h" #include "quickjs.h"
#ifdef __cplusplus
extern "C" {
#endif
JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
void js_std_add_helpers(JSContext *ctx, int argc, char **argv); void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
void js_std_loop(JSContext *ctx); void js_std_loop(JSContext *ctx);
void js_std_init_handlers(JSRuntime *rt);
void js_std_free_handlers(JSRuntime *rt); void js_std_free_handlers(JSRuntime *rt);
void js_std_dump_error(JSContext *ctx); void js_std_dump_error(JSContext *ctx);
uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename); uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
@ -46,4 +51,8 @@ void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
JSValueConst reason, JSValueConst reason,
JS_BOOL is_handled, void *opaque); JS_BOOL is_handled, void *opaque);
#ifdef __cplusplus
} /* extern "C" { */
#endif
#endif /* QUICKJS_LIBC_H */ #endif /* QUICKJS_LIBC_H */

3315
quickjs.c

File diff suppressed because it is too large Load diff

View file

@ -498,7 +498,7 @@ int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);
static js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val) static js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val)
{ {
return JS_MKVAL(JS_TAG_BOOL, val); return JS_MKVAL(JS_TAG_BOOL, (val != 0));
} }
static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val) static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val)
@ -746,7 +746,7 @@ int JS_IsExtensible(JSContext *ctx, JSValueConst obj);
int JS_PreventExtensions(JSContext *ctx, JSValueConst obj); int JS_PreventExtensions(JSContext *ctx, JSValueConst obj);
int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags); int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags);
int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val); int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val);
JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val); JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val);
#define JS_GPN_STRING_MASK (1 << 0) #define JS_GPN_STRING_MASK (1 << 0)
#define JS_GPN_SYMBOL_MASK (1 << 1) #define JS_GPN_SYMBOL_MASK (1 << 1)
@ -796,6 +796,9 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id);
/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */ /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
const char *filename); const char *filename);
#define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */
JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
const char *filename, int flags);
JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
JSValueConst replacer, JSValueConst space0); JSValueConst replacer, JSValueConst space0);
@ -810,6 +813,14 @@ JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
size_t *pbyte_offset, size_t *pbyte_offset,
size_t *pbyte_length, size_t *pbyte_length,
size_t *pbytes_per_element); size_t *pbytes_per_element);
typedef struct {
void *(*sab_alloc)(void *opaque, size_t size);
void (*sab_free)(void *opaque, void *ptr);
void (*sab_dup)(void *opaque, void *ptr);
void *sab_opaque;
} JSSharedArrayBufferFunctions;
void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
const JSSharedArrayBufferFunctions *sf);
JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
@ -853,14 +864,24 @@ JS_BOOL JS_IsJobPending(JSRuntime *rt);
int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx); int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);
/* Object Writer/Reader (currently only used to handle precompiled code) */ /* Object Writer/Reader (currently only used to handle precompiled code) */
#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */ #define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */ #define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */
#define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to
encode arbitrary object
graph */
uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
int flags); int flags);
uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
int flags, uint8_t ***psab_tab, size_t *psab_tab_len);
#define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */ #define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */
#define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */ #define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */
#define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
#define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */
JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
int flags); int flags);
/* load the dependencies of the module 'obj'. Useful when JS_ReadObject() /* load the dependencies of the module 'obj'. Useful when JS_ReadObject()
returns a module. */ returns a module. */
int JS_ResolveModule(JSContext *ctx, JSValueConst obj); int JS_ResolveModule(JSContext *ctx, JSValueConst obj);

72
repl.js
View file

@ -209,6 +209,29 @@ import * as os from "os";
(is_alpha(c) || is_digit(c) || c == '_' || c == '$'); (is_alpha(c) || is_digit(c) || c == '_' || c == '$');
} }
function ucs_length(str) {
var len, c, i, str_len = str.length;
len = 0;
/* we never count the trailing surrogate to have the
following property: ucs_length(str) =
ucs_length(str.substring(0, a)) + ucs_length(str.substring(a,
str.length)) for 0 <= a <= str.length */
for(i = 0; i < str_len; i++) {
c = str.charCodeAt(i);
if (c < 0xdc00 || c >= 0xe000)
len++;
}
return len;
}
function is_trailing_surrogate(c) {
var d;
if (typeof c !== "string")
return false;
d = c.codePointAt(0); /* can be NaN if empty string */
return d >= 0xdc00 && d < 0xe000;
}
function is_balanced(a, b) { function is_balanced(a, b) {
switch (a + b) { switch (a + b) {
case "()": case "()":
@ -235,6 +258,7 @@ import * as os from "os";
std.puts("\x1b[" + ((n != 1) ? n : "") + code); std.puts("\x1b[" + ((n != 1) ? n : "") + code);
} }
/* XXX: handle double-width characters */
function move_cursor(delta) { function move_cursor(delta) {
var i, l; var i, l;
if (delta > 0) { if (delta > 0) {
@ -269,15 +293,16 @@ import * as os from "os";
} }
function update() { function update() {
var i; var i, cmd_len;
/* cursor_pos is the position in 16 bit characters inside the
UTF-16 string 'cmd' */
if (cmd != last_cmd) { if (cmd != last_cmd) {
if (!show_colors && last_cmd.substring(0, last_cursor_pos) == cmd.substring(0, last_cursor_pos)) { if (!show_colors && last_cmd.substring(0, last_cursor_pos) == cmd.substring(0, last_cursor_pos)) {
/* optimize common case */ /* optimize common case */
std.puts(cmd.substring(last_cursor_pos)); std.puts(cmd.substring(last_cursor_pos));
} else { } else {
/* goto the start of the line */ /* goto the start of the line */
move_cursor(-last_cursor_pos); move_cursor(-ucs_length(last_cmd.substring(0, last_cursor_pos)));
if (show_colors) { if (show_colors) {
var str = mexpr ? mexpr + '\n' + cmd : cmd; var str = mexpr ? mexpr + '\n' + cmd : cmd;
var start = str.length - cmd.length; var start = str.length - cmd.length;
@ -287,8 +312,7 @@ import * as os from "os";
std.puts(cmd); std.puts(cmd);
} }
} }
/* Note: assuming no surrogate pairs */ term_cursor_x = (term_cursor_x + ucs_length(cmd)) % term_width;
term_cursor_x = (term_cursor_x + cmd.length) % term_width;
if (term_cursor_x == 0) { if (term_cursor_x == 0) {
/* show the cursor on the next line */ /* show the cursor on the next line */
std.puts(" \x08"); std.puts(" \x08");
@ -298,7 +322,11 @@ import * as os from "os";
last_cmd = cmd; last_cmd = cmd;
last_cursor_pos = cmd.length; last_cursor_pos = cmd.length;
} }
move_cursor(cursor_pos - last_cursor_pos); if (cursor_pos > last_cursor_pos) {
move_cursor(ucs_length(cmd.substring(last_cursor_pos, cursor_pos)));
} else if (cursor_pos < last_cursor_pos) {
move_cursor(-ucs_length(cmd.substring(cursor_pos, last_cursor_pos)));
}
last_cursor_pos = cursor_pos; last_cursor_pos = cursor_pos;
std.out.flush(); std.out.flush();
} }
@ -333,13 +361,19 @@ import * as os from "os";
} }
function forward_char() { function forward_char() {
if (cursor_pos < cmd.length) if (cursor_pos < cmd.length) {
cursor_pos++; cursor_pos++;
while (is_trailing_surrogate(cmd.charAt(cursor_pos)))
cursor_pos++;
}
} }
function backward_char() { function backward_char() {
if (cursor_pos > 0) if (cursor_pos > 0) {
cursor_pos--; cursor_pos--;
while (is_trailing_surrogate(cmd.charAt(cursor_pos)))
cursor_pos--;
}
} }
function skip_word_forward(pos) { function skip_word_forward(pos) {
@ -419,8 +453,18 @@ import * as os from "os";
} }
function delete_char_dir(dir) { function delete_char_dir(dir) {
var start = cursor_pos - (dir < 0); var start, end;
var end = start + 1;
start = cursor_pos;
if (dir < 0) {
start--;
while (is_trailing_surrogate(cmd.charAt(start)))
start--;
}
end = start + 1;
while (is_trailing_surrogate(cmd.charAt(end)))
end++;
if (start >= 0 && start < cmd.length) { if (start >= 0 && start < cmd.length) {
if (last_fun === kill_region) { if (last_fun === kill_region) {
kill_region(start, end, dir); kill_region(start, end, dir);
@ -752,7 +796,7 @@ import * as os from "os";
function readline_print_prompt() function readline_print_prompt()
{ {
std.puts(prompt); std.puts(prompt);
term_cursor_x = prompt.length % term_width; term_cursor_x = ucs_length(prompt) % term_width;
last_cmd = ""; last_cmd = "";
last_cursor_pos = 0; last_cursor_pos = 0;
} }
@ -785,7 +829,7 @@ import * as os from "os";
function handle_char(c1) { function handle_char(c1) {
var c; var c;
c = String.fromCharCode(c1); c = String.fromCodePoint(c1);
switch(readline_state) { switch(readline_state) {
case 0: case 0:
if (c == '\x1b') { /* '^[' - ESC */ if (c == '\x1b') { /* '^[' - ESC */
@ -825,7 +869,7 @@ import * as os from "os";
var fun; var fun;
if (quote_flag) { if (quote_flag) {
if (keys.length === 1) if (ucs_length(keys) === 1)
insert(keys); insert(keys);
quote_flag = false; quote_flag = false;
} else if (fun = commands[keys]) { } else if (fun = commands[keys]) {
@ -845,7 +889,7 @@ import * as os from "os";
return; return;
} }
last_fun = this_fun; last_fun = this_fun;
} else if (keys.length === 1 && keys >= ' ') { } else if (ucs_length(keys) === 1 && keys >= ' ') {
insert(keys); insert(keys);
last_fun = insert; last_fun = insert;
} else { } else {

View file

@ -58,6 +58,7 @@ arrow-function
async-functions async-functions
async-iteration async-iteration
Atomics Atomics
Atomics.waitAsync=skip
BigInt BigInt
caller caller
class class

View file

@ -2,6 +2,8 @@ test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-r
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError
test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents. test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: strict mode: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents. test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: strict mode: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name
test262/test/language/expressions/arrow-function/eval-var-scope-syntax-err.js:47: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all test262/test/language/expressions/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-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/named-eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
@ -18,8 +20,8 @@ test262/test/language/expressions/object/method-definition/async-gen-meth-eval-v
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/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: cannot read property 'c' of undefined
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: cannot read property '_b' of undefined
test262/test/language/statements/async-function/eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called test262/test/language/statements/async-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/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name test262/test/language/statements/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name

View file

@ -31,6 +31,7 @@ static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
uint64_t pos, len; uint64_t pos, len;
JSValue obj; JSValue obj;
size_t size; size_t size;
int flags;
if (JS_ToIndex(ctx, &pos, argv[1])) if (JS_ToIndex(ctx, &pos, argv[1]))
return JS_EXCEPTION; return JS_EXCEPTION;
@ -41,7 +42,10 @@ static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION; return JS_EXCEPTION;
if (pos + len > size) if (pos + len > size)
return JS_ThrowRangeError(ctx, "array buffer overflow"); return JS_ThrowRangeError(ctx, "array buffer overflow");
obj = JS_ReadObject(ctx, buf + pos, len, 0); flags = 0;
if (JS_ToBool(ctx, argv[3]))
flags |= JS_READ_OBJ_REFERENCE;
obj = JS_ReadObject(ctx, buf + pos, len, flags);
return obj; return obj;
} }
@ -51,8 +55,12 @@ static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
size_t len; size_t len;
uint8_t *buf; uint8_t *buf;
JSValue array; JSValue array;
int flags;
buf = JS_WriteObject(ctx, &len, argv[0], 0); flags = 0;
if (JS_ToBool(ctx, argv[1]))
flags |= JS_WRITE_OBJ_REFERENCE;
buf = JS_WriteObject(ctx, &len, argv[0], flags);
if (!buf) if (!buf)
return JS_EXCEPTION; return JS_EXCEPTION;
array = JS_NewArrayBufferCopy(ctx, buf, len); array = JS_NewArrayBufferCopy(ctx, buf, len);
@ -61,8 +69,8 @@ static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
} }
static const JSCFunctionListEntry js_bjson_funcs[] = { static const JSCFunctionListEntry js_bjson_funcs[] = {
JS_CFUNC_DEF("read", 3, js_bjson_read ), JS_CFUNC_DEF("read", 4, js_bjson_read ),
JS_CFUNC_DEF("write", 1, js_bjson_write ), JS_CFUNC_DEF("write", 2, js_bjson_write ),
}; };
static int js_bjson_init(JSContext *ctx, JSModuleDef *m) static int js_bjson_init(JSContext *ctx, JSModuleDef *m)

View file

@ -228,6 +228,19 @@ function prop_create(n)
return n * 4; return n * 4;
} }
function prop_delete(n)
{
var obj, j;
obj = {};
for(j = 0; j < n; j++) {
obj[j] = 1;
}
for(j = 0; j < n; j++) {
delete obj[j];
}
return n;
}
function array_read(n) function array_read(n)
{ {
var tab, len, sum, i, j; var tab, len, sum, i, j;
@ -945,6 +958,7 @@ function main(argc, argv, g)
prop_read, prop_read,
prop_write, prop_write,
prop_create, prop_create,
prop_delete,
array_read, array_read,
array_write, array_write,
array_prop_create, array_prop_create,

View file

@ -1,12 +1,20 @@
import * as bjson from "./bjson.so"; import * as bjson from "./bjson.so";
function assert(b, str) function assert(actual, expected, message) {
{ if (arguments.length == 1)
if (b) { expected = true;
if (actual === expected)
return; return;
} else {
throw Error("assertion failed: " + str); if (actual !== null && expected !== null
} && typeof actual == 'object' && typeof expected == 'object'
&& actual.toString() === expected.toString())
return;
throw Error("assertion failed: got |" + actual + "|" +
", expected |" + expected + "|" +
(message ? " (" + message + ")" : ""));
} }
function toHex(a) function toHex(a)
@ -24,6 +32,20 @@ function toHex(a)
return s; return s;
} }
function isArrayLike(a)
{
return Array.isArray(a) ||
(a instanceof Uint8ClampedArray) ||
(a instanceof Uint8Array) ||
(a instanceof Uint16Array) ||
(a instanceof Uint32Array) ||
(a instanceof Int8Array) ||
(a instanceof Int16Array) ||
(a instanceof Int32Array) ||
(a instanceof Float32Array) ||
(a instanceof Float64Array);
}
function toStr(a) function toStr(a)
{ {
var s, i, props, prop; var s, i, props, prop;
@ -32,7 +54,15 @@ function toStr(a)
case "object": case "object":
if (a === null) if (a === null)
return "null"; return "null";
if (Array.isArray(a)) { if (a instanceof Date) {
s = "Date(" + toStr(a.valueOf()) + ")";
} else if (a instanceof Number) {
s = "Number(" + toStr(a.valueOf()) + ")";
} else if (a instanceof String) {
s = "String(" + toStr(a.valueOf()) + ")";
} else if (a instanceof Boolean) {
s = "Boolean(" + toStr(a.valueOf()) + ")";
} else if (isArrayLike(a)) {
s = "["; s = "[";
for(i = 0; i < a.length; i++) { for(i = 0; i < a.length; i++) {
if (i != 0) if (i != 0)
@ -85,6 +115,35 @@ function bjson_test(a)
} }
} }
/* test multiple references to an object including circular
references */
function bjson_test_reference()
{
var array, buf, i, n, array_buffer;
n = 16;
array = [];
for(i = 0; i < n; i++)
array[i] = {};
array_buffer = new ArrayBuffer(n);
for(i = 0; i < n; i++) {
array[i].next = array[(i + 1) % n];
array[i].idx = i;
array[i].typed_array = new Uint8Array(array_buffer, i, 1);
}
buf = bjson.write(array, true);
array = bjson.read(buf, 0, buf.byteLength, true);
/* check the result */
for(i = 0; i < n; i++) {
assert(array[i].next, array[(i + 1) % n]);
assert(array[i].idx, i);
assert(array[i].typed_array.buffer, array_buffer);
assert(array[i].typed_array.length, 1);
assert(array[i].typed_array.byteOffset, i);
}
}
function bjson_test_all() function bjson_test_all()
{ {
var obj; var obj;
@ -111,6 +170,11 @@ function bjson_test_all()
BigDecimal("1.233e-1000")]); BigDecimal("1.233e-1000")]);
} }
bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]);
bjson_test(new Int32Array([123123, 222111, -32222]));
bjson_test(new Float64Array([123123, 222111.5]));
/* tested with a circular reference */ /* tested with a circular reference */
obj = {}; obj = {};
obj.x = obj; obj.x = obj;
@ -120,6 +184,8 @@ function bjson_test_all()
} catch(e) { } catch(e) {
assert(e instanceof TypeError); assert(e instanceof TypeError);
} }
bjson_test_reference();
} }
bjson_test_all(); bjson_test_all();

View file

@ -287,6 +287,10 @@ function test_math()
assert(Math.ceil(a), 2); assert(Math.ceil(a), 2);
assert(Math.imul(0x12345678, 123), -1088058456); assert(Math.imul(0x12345678, 123), -1088058456);
assert(Math.fround(0.1), 0.10000000149011612); assert(Math.fround(0.1), 0.10000000149011612);
assert(Math.hypot() == 0);
assert(Math.hypot(-2) == 2);
assert(Math.hypot(3, 4) == 5);
assert(Math.abs(Math.hypot(3, 4, 5) - 7.0710678118654755) <= 1e-15);
} }
function test_number() function test_number()

View file

@ -311,10 +311,21 @@ function test_template()
var a, b; var a, b;
b = 123; b = 123;
a = `abc${b}d`; a = `abc${b}d`;
assert(a === "abc123d"); assert(a, "abc123d");
a = String.raw `abc${b}d`; a = String.raw `abc${b}d`;
assert(a === "abc123d"); assert(a, "abc123d");
a = "aaa";
b = "bbb";
assert(`aaa${a, b}ccc`, "aaabbbccc");
}
function test_template_skip()
{
var a = "Bar";
var { b = `${a + `a${a}` }baz` } = {};
assert(b, "BaraBarbaz");
} }
function test_object_literal() function test_object_literal()
@ -358,6 +369,7 @@ test_prototype();
test_arguments(); test_arguments();
test_class(); test_class();
test_template(); test_template();
test_template_skip();
test_object_literal(); test_object_literal();
test_regexp_skip(); test_regexp_skip();
test_labels(); test_labels();

View file

@ -26,6 +26,12 @@ try { std.loadScript("test_assert.js"); } catch(e) {}
function test_printf() function test_printf()
{ {
assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc"); assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc");
assert(std.sprintf("%010d", 123), "0000000123");
assert(std.sprintf("%x", -2), "fffffffe");
assert(std.sprintf("%lx", -2), "fffffffffffffffe");
assert(std.sprintf("%10.1f", 2.1), " 2.1");
assert(std.sprintf("%*.*f", 10, 2, -2.13), " -2.13");
assert(std.sprintf("%#lx", 0x7fffffffffffffffn), "0x7fffffffffffffff");
} }
function test_file1() function test_file1()
@ -119,6 +125,20 @@ function test_popen()
os.remove(fname); os.remove(fname);
} }
function test_ext_json()
{
var expected, input, obj;
expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"s":"str"}';
input = `{ "x":false, /*comments are allowed */
"y":true, // also a comment
z2:null, // unquoted property names
"a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal
"s":"str",} // trailing comma in objects and arrays
`;
obj = std.parseExtJSON(input);
assert(JSON.stringify(obj), expected);
}
function test_os() function test_os()
{ {
var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path; var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
@ -258,3 +278,4 @@ test_popen();
test_os(); test_os();
test_os_exec(); test_os_exec();
test_timer(); test_timer();
test_ext_json();

93
tests/test_worker.js Normal file
View file

@ -0,0 +1,93 @@
/* os.Worker API test */
import * as std from "std";
import * as os from "os";
function assert(actual, expected, message) {
if (arguments.length == 1)
expected = true;
if (actual === expected)
return;
if (actual !== null && expected !== null
&& typeof actual == 'object' && typeof expected == 'object'
&& actual.toString() === expected.toString())
return;
throw Error("assertion failed: got |" + actual + "|" +
", expected |" + expected + "|" +
(message ? " (" + message + ")" : ""));
}
var worker;
function test_worker()
{
var counter;
/* Note: can use std.loadFile() to read from a file */
worker = new os.Worker(`
import * as std from "std";
import * as os from "os";
var parent = os.Worker.parent;
function handle_msg(e) {
var ev = e.data;
// print("child_recv", JSON.stringify(ev));
switch(ev.type) {
case "abort":
parent.postMessage({ type: "done" });
break;
case "sab":
/* modify the SharedArrayBuffer */
ev.buf[2] = 10;
parent.postMessage({ type: "sab_done", buf: ev.buf });
break;
}
}
function worker_main() {
var i;
parent.onmessage = handle_msg;
for(i = 0; i < 10; i++) {
parent.postMessage({ type: "num", num: i });
}
}
worker_main();
`);
counter = 0;
worker.onmessage = function (e) {
var ev = e.data;
// print("recv", JSON.stringify(ev));
switch(ev.type) {
case "num":
assert(ev.num, counter);
counter++;
if (counter == 10) {
/* test SharedArrayBuffer modification */
let sab = new SharedArrayBuffer(10);
let buf = new Uint8Array(sab);
worker.postMessage({ type: "sab", buf: buf });
}
break;
case "sab_done":
{
let buf = ev.buf;
/* check that the SharedArrayBuffer was modified */
assert(buf[2], 10);
worker.postMessage({ type: "abort" });
}
break;
case "done":
/* terminate */
worker.onmessage = null;
break;
}
};
}
test_worker();