mirror of
https://github.com/bellard/quickjs.git
synced 2024-11-22 05:38:11 +08:00
2020-07-05 release
This commit is contained in:
parent
1722758717
commit
8900766099
@ -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:
|
||||
|
||||
- added cross realm support
|
||||
|
27
Makefile
27
Makefile
@ -99,6 +99,10 @@ DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
|
||||
ifdef CONFIG_BIGNUM
|
||||
DEFINES+=-DCONFIG_BIGNUM
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior
|
||||
endif
|
||||
|
||||
CFLAGS+=$(DEFINES)
|
||||
CFLAGS_DEBUG=$(CFLAGS) -O0
|
||||
CFLAGS_SMALL=$(CFLAGS) -Os
|
||||
@ -115,8 +119,8 @@ CFLAGS+=-p
|
||||
LDFLAGS+=-p
|
||||
endif
|
||||
ifdef CONFIG_ASAN
|
||||
CFLAGS+=-fsanitize=address
|
||||
LDFLAGS+=-fsanitize=address
|
||||
CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
LDEXPORT=
|
||||
@ -166,9 +170,10 @@ QJS_LIB_OBJS+=$(OBJDIR)/libbf.o
|
||||
QJS_OBJS+=$(OBJDIR)/qjscalc.o
|
||||
endif
|
||||
|
||||
HOST_LIBS=-lm -ldl -lpthread
|
||||
LIBS=-lm
|
||||
ifndef CONFIG_WIN32
|
||||
LIBS+=-ldl
|
||||
LIBS+=-ldl -lpthread
|
||||
endif
|
||||
|
||||
$(OBJDIR):
|
||||
@ -187,7 +192,7 @@ ifneq ($(CROSS_PREFIX),)
|
||||
|
||||
$(QJSC): $(OBJDIR)/qjsc.host.o \
|
||||
$(patsubst %.o, %.host.o, $(QJS_LIB_OBJS))
|
||||
$(HOST_CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(HOST_CC) $(LDFLAGS) -o $@ $^ $(HOST_LIBS)
|
||||
|
||||
endif #CROSS_PREFIX
|
||||
|
||||
@ -239,13 +244,13 @@ libunicode-table.h: unicode_gen
|
||||
endif
|
||||
|
||||
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))
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
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]
|
||||
|
||||
@ -285,7 +290,7 @@ unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c u
|
||||
clean:
|
||||
rm -f repl.c qjscalc.c out.c
|
||||
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 -rf $(OBJDIR)/ *.dSYM/ qjs-debug
|
||||
rm -rf run-test262-debug run-test262-32
|
||||
@ -379,10 +384,11 @@ endif
|
||||
|
||||
test: qjs
|
||||
./qjs tests/test_closure.js
|
||||
./qjs tests/test_op.js
|
||||
./qjs tests/test_language.js
|
||||
./qjs tests/test_builtin.js
|
||||
./qjs tests/test_loop.js
|
||||
./qjs tests/test_std.js
|
||||
./qjs tests/test_worker.js
|
||||
ifndef CONFIG_DARWIN
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs --bignum tests/test_bjson.js
|
||||
@ -398,10 +404,11 @@ ifdef CONFIG_BIGNUM
|
||||
endif
|
||||
ifdef CONFIG_M32
|
||||
./qjs32 tests/test_closure.js
|
||||
./qjs32 tests/test_op.js
|
||||
./qjs32 tests/test_language.js
|
||||
./qjs32 tests/test_builtin.js
|
||||
./qjs32 tests/test_loop.js
|
||||
./qjs32 tests/test_std.js
|
||||
./qjs32 tests/test_worker.js
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs32 --bignum tests/test_op_overloading.js
|
||||
./qjs32 --bignum tests/test_bignum.js
|
||||
|
8
TODO
8
TODO
@ -1,4 +1,5 @@
|
||||
Misc:
|
||||
- use realpath in module name normalizer and put it in quickjs-libc
|
||||
- use custom printf to avoid C library compatibility issues
|
||||
- rename CONFIG_ALL_UNICODE, CONFIG_BIGNUM, CONFIG_ATOMICS, CONFIG_CHECK_JSVALUE ?
|
||||
- unify coding style and naming conventions
|
||||
@ -56,12 +57,12 @@ Extensions:
|
||||
handle #if, #ifdef, #line, limited support for #define
|
||||
- get rid of __loadScript, use more common name
|
||||
- BSD sockets
|
||||
- Workers
|
||||
|
||||
REPL:
|
||||
- debugger
|
||||
- readline: support MS Windows terminal
|
||||
- readline: handle dynamic terminal resizing
|
||||
- readline: handle double width unicode characters
|
||||
- multiline editing
|
||||
- runtime object and function inspectors
|
||||
- interactive object browser
|
||||
@ -73,6 +74,5 @@ REPL:
|
||||
Test262o: 0/11262 errors, 463 excluded
|
||||
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
|
||||
|
||||
Test262: 28/70829 errors, 877 excluded, 425 skipped
|
||||
Test262 commit: 4a8e49b3ca7f9f74a4cafe6621ff9ba548ccc353
|
||||
|
||||
Test262: 30/71095 errors, 870 excluded, 549 skipped
|
||||
Test262 commit: 281eb10b2844929a7c0ac04527f5b42ce56509fd
|
||||
|
4
cutils.h
4
cutils.h
@ -268,6 +268,10 @@ void dbuf_free(DynBuf *s);
|
||||
static inline BOOL dbuf_error(DynBuf *s) {
|
||||
return s->error;
|
||||
}
|
||||
static inline void dbuf_set_error(DynBuf *s)
|
||||
{
|
||||
s->error = TRUE;
|
||||
}
|
||||
|
||||
#define UTF8_CHAR_LEN_MAX 6
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
|
||||
<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Javascript Bignum Extensions</title>
|
||||
|
||||
<meta name="description" content="Javascript Bignum Extensions">
|
||||
@ -9,7 +10,6 @@
|
||||
<meta name="resource-type" content="document">
|
||||
<meta name="distribution" content="global">
|
||||
<meta name="Generator" content="makeinfo">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
|
||||
<style type="text/css">
|
||||
<!--
|
||||
|
BIN
doc/jsbignum.pdf
BIN
doc/jsbignum.pdf
Binary file not shown.
@ -1,7 +1,8 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
|
||||
<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>QuickJS Javascript Engine</title>
|
||||
|
||||
<meta name="description" content="QuickJS Javascript Engine">
|
||||
@ -9,7 +10,6 @@
|
||||
<meta name="resource-type" content="document">
|
||||
<meta name="distribution" content="global">
|
||||
<meta name="Generator" content="makeinfo">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
|
||||
<style type="text/css">
|
||||
<!--
|
||||
@ -73,10 +73,9 @@ ul.no-bullet {list-style: none}
|
||||
<li><a name="toc-Language-support" href="#Language-support">3.1 Language support</a>
|
||||
<ul class="no-bullet">
|
||||
<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.3 ECMA402</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.5 Mathematical extensions</a></li>
|
||||
<li><a name="toc-ECMA402" href="#ECMA402">3.1.2 ECMA402</a></li>
|
||||
<li><a name="toc-Extensions" href="#Extensions">3.1.3 Extensions</a></li>
|
||||
<li><a name="toc-Mathematical-extensions" href="#Mathematical-extensions">3.1.4 Mathematical extensions</a></li>
|
||||
</ul></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>
|
||||
@ -407,18 +406,13 @@ B (legacy web compatibility) and the Unicode related features.
|
||||
|
||||
</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>
|
||||
<h4 class="subsection">3.1.3 ECMA402</h4>
|
||||
<h4 class="subsection">3.1.2 ECMA402</h4>
|
||||
|
||||
<p>ECMA402 (Internationalization API) is not supported.
|
||||
</p>
|
||||
<a name="Extensions"></a>
|
||||
<h4 class="subsection">3.1.4 Extensions</h4>
|
||||
<h4 class="subsection">3.1.3 Extensions</h4>
|
||||
|
||||
<ul>
|
||||
<li> The directive <code>"use strip"</code> indicates that the debug information (including the source code of the functions) should not be retained to save memory. As <code>"use strict"</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>
|
||||
|
||||
<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
|
||||
standard Javascript. See <code>jsbignum.pdf</code> for more information.
|
||||
@ -557,7 +551,7 @@ no error occured.
|
||||
</p>
|
||||
</dd>
|
||||
<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>
|
||||
</dd>
|
||||
<dt><code>sprintf(fmt, ...args)</code></dt>
|
||||
@ -636,6 +630,21 @@ optional properties:
|
||||
</dd>
|
||||
</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>
|
||||
</dl>
|
||||
|
||||
@ -649,8 +658,14 @@ optional properties:
|
||||
<dd><p>Outputs the string with the UTF-8 encoding.
|
||||
</p></dd>
|
||||
<dt><code>printf(fmt, ...args)</code></dt>
|
||||
<dd><p>Formatted printf, same formats as the libc printf.
|
||||
</p></dd>
|
||||
<dd><p>Formatted printf.
|
||||
</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>
|
||||
<dd><p>Flush the buffered file.
|
||||
</p></dd>
|
||||
@ -718,6 +733,7 @@ is read up its end.
|
||||
</li><li> signals
|
||||
</li><li> timers
|
||||
</li><li> asynchronous I/O
|
||||
</li><li> workers (threads)
|
||||
</li></ul>
|
||||
|
||||
<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>
|
||||
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
|
||||
the signal.
|
||||
the signal. Signal handlers can only be defined in the main thread.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>SIGINT</code></dt>
|
||||
@ -972,6 +988,49 @@ to the timer.
|
||||
<dd><p>Return a string representing the platform: <code>"linux"</code>, <code>"darwin"</code>,
|
||||
<code>"win32"</code> or <code>"js"</code>.
|
||||
</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’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>
|
||||
</dl>
|
||||
|
||||
|
BIN
doc/quickjs.pdf
BIN
doc/quickjs.pdf
Binary file not shown.
@ -272,10 +272,6 @@ The following features are not supported yet:
|
||||
|
||||
@end itemize
|
||||
|
||||
@subsection JSON
|
||||
|
||||
The JSON parser is currently more tolerant than the specification.
|
||||
|
||||
@subsection ECMA402
|
||||
|
||||
ECMA402 (Internationalization API) is not supported.
|
||||
@ -405,7 +401,7 @@ no error occured.
|
||||
Equivalent to @code{std.out.puts(str)}.
|
||||
|
||||
@item printf(fmt, ...args)
|
||||
Equivalent to @code{std.out.printf(fmt, ...args)}
|
||||
Equivalent to @code{std.out.printf(fmt, ...args)}.
|
||||
|
||||
@item sprintf(fmt, ...args)
|
||||
Equivalent to the libc sprintf().
|
||||
@ -474,6 +470,20 @@ optional properties:
|
||||
|
||||
@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
|
||||
|
||||
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)
|
||||
Outputs the string with the UTF-8 encoding.
|
||||
@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()
|
||||
Flush the buffered file.
|
||||
@item seek(offset, whence)
|
||||
@ -537,6 +553,7 @@ The @code{os} module provides Operating System specific functions:
|
||||
@item signals
|
||||
@item timers
|
||||
@item asynchronous I/O
|
||||
@item workers (threads)
|
||||
@end itemize
|
||||
|
||||
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}
|
||||
happens. Only a single handler per signal number is supported. Use
|
||||
@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 SIGABRT
|
||||
@ -747,6 +764,45 @@ Cancel a timer.
|
||||
Return a string representing the platform: @code{"linux"}, @code{"darwin"},
|
||||
@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
|
||||
|
||||
@section QuickJS C API
|
||||
|
@ -130,11 +130,11 @@ static int js_point_init(JSContext *ctx, JSModuleDef *m)
|
||||
|
||||
point_proto = JS_NewObject(ctx);
|
||||
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);
|
||||
/* set proto.constructor and ctor.prototype */
|
||||
JS_SetConstructor(ctx, point_class, point_proto);
|
||||
JS_SetClassProto(ctx, js_point_class_id, point_proto);
|
||||
|
||||
JS_SetModuleExport(ctx, m, "Point", point_class);
|
||||
return 0;
|
||||
|
75
libbf.c
75
libbf.c
@ -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 */
|
||||
static void bf_integer_to_radix_rec(bf_t *pow_tab,
|
||||
limb_t *out, const bf_t *a, limb_t n,
|
||||
int level, limb_t n0, limb_t radixl,
|
||||
unsigned int radixl_bits)
|
||||
static int bf_integer_to_radix_rec(bf_t *pow_tab,
|
||||
limb_t *out, const bf_t *a, limb_t n,
|
||||
int level, limb_t n0, limb_t radixl,
|
||||
unsigned int radixl_bits)
|
||||
{
|
||||
limb_t n1, n2, q_prec;
|
||||
int ret;
|
||||
|
||||
assert(n >= 1);
|
||||
if (n == 1) {
|
||||
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;
|
||||
B = &pow_tab[2 * level];
|
||||
B_inv = &pow_tab[2 * level + 1];
|
||||
ret = 0;
|
||||
if (B->len == 0) {
|
||||
/* 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,
|
||||
i.e. n2 + 1 */
|
||||
bf_set_ui(&R, 1);
|
||||
bf_div(B_inv, &R, B, (n2 + 1) * radixl_bits + 2, BF_RNDN);
|
||||
ret |= bf_set_ui(&R, 1);
|
||||
ret |= bf_div(B_inv, &R, B, (n2 + 1) * radixl_bits + 2, BF_RNDN);
|
||||
}
|
||||
// printf("%d: n1=% " PRId64 " n2=%" PRId64 "\n", level, n1, n2);
|
||||
q_prec = n1 * radixl_bits;
|
||||
bf_mul(&Q, a, B_inv, q_prec, BF_RNDN);
|
||||
bf_rint(&Q, BF_RNDZ);
|
||||
ret |= bf_mul(&Q, a, B_inv, q_prec, BF_RNDN);
|
||||
ret |= bf_rint(&Q, BF_RNDZ);
|
||||
|
||||
bf_mul(&R, &Q, B, BF_PREC_INF, BF_RNDZ);
|
||||
bf_sub(&R, a, &R, BF_PREC_INF, BF_RNDZ);
|
||||
ret |= bf_mul(&R, &Q, B, 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 */
|
||||
q_add = 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--;
|
||||
}
|
||||
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++;
|
||||
}
|
||||
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(&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;
|
||||
limb_t r_len;
|
||||
bf_t *pow_tab;
|
||||
int i, pow_tab_len;
|
||||
int i, pow_tab_len, ret;
|
||||
|
||||
r_len = r->len;
|
||||
pow_tab_len = (ceil_log2(r_len) + 2) * 2; /* XXX: check */
|
||||
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++)
|
||||
bf_init(r->ctx, &pow_tab[i]);
|
||||
|
||||
bf_integer_to_radix_rec(pow_tab, r->tab, a, r_len, 0, r_len, radixl,
|
||||
ceil_log2(radixl));
|
||||
ret = bf_integer_to_radix_rec(pow_tab, r->tab, a, r_len, 0, r_len, radixl,
|
||||
ceil_log2(radixl));
|
||||
|
||||
for(i = 0; i < pow_tab_len; i++) {
|
||||
bf_delete(&pow_tab[i]);
|
||||
}
|
||||
bf_free(s, pow_tab);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
bf_init(a1->ctx, a);
|
||||
n = (n_digits + digits_per_limb - 1) / digits_per_limb;
|
||||
bf_resize(a, n);
|
||||
bf_integer_to_radix(a, a1, radixl);
|
||||
if (bf_resize(a, n)) {
|
||||
dbuf_set_error(s);
|
||||
goto done;
|
||||
}
|
||||
if (bf_integer_to_radix(a, a1, radixl)) {
|
||||
dbuf_set_error(s);
|
||||
goto done;
|
||||
}
|
||||
radix_bits = 0;
|
||||
pos = n;
|
||||
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;
|
||||
i += l;
|
||||
}
|
||||
done:
|
||||
if (a != a1)
|
||||
bf_delete(a);
|
||||
}
|
||||
|
49
libregexp.c
49
libregexp.c
@ -110,12 +110,14 @@ static inline int is_digit(int c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
/* insert 'len' bytes at position 'pos' */
|
||||
static void dbuf_insert(DynBuf *s, int pos, int len)
|
||||
/* insert 'len' bytes at position 'pos'. Return < 0 if error. */
|
||||
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);
|
||||
s->size += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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
|
||||
overflow. Otherwise return INT32_MAX. */
|
||||
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;
|
||||
return 0;
|
||||
out_of_memory:
|
||||
return re_parse_error(s, "out of memory");
|
||||
return re_parse_out_of_memory(s);
|
||||
}
|
||||
#endif /* CONFIG_ALL_UNICODE */
|
||||
|
||||
@ -928,7 +935,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
|
||||
*pp = p;
|
||||
return 0;
|
||||
memory_error:
|
||||
re_parse_error(s, "out of memory");
|
||||
re_parse_out_of_memory(s);
|
||||
fail:
|
||||
cr_free(cr);
|
||||
return -1;
|
||||
@ -1295,6 +1302,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
return -1;
|
||||
re_emit_op(s, REOP_match);
|
||||
/* 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));
|
||||
} else if (p[2] == '<') {
|
||||
p += 3;
|
||||
@ -1548,12 +1557,15 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
|
||||
if (quant_max > 0) {
|
||||
/* 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,
|
||||
s->byte_code.size - last_atom_start);
|
||||
if (len > 0) {
|
||||
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;
|
||||
s->byte_code.buf[pos++] = REOP_simple_greedy_quant;
|
||||
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,
|
||||
s->byte_code.size - last_atom_start) == 0);
|
||||
} 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
|
||||
not executed */
|
||||
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++] = last_capture_count;
|
||||
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) {
|
||||
s->byte_code.size = last_atom_start;
|
||||
} 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 +
|
||||
greedy;
|
||||
put_u32(s->byte_code.buf + last_atom_start + 1, len);
|
||||
} 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 +
|
||||
greedy;
|
||||
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);
|
||||
}
|
||||
} 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;
|
||||
s->byte_code.buf[pos++] = REOP_push_i32;
|
||||
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) {
|
||||
/* nothing to add */
|
||||
} 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;
|
||||
put_u32(s->byte_code.buf + last_atom_start + 1,
|
||||
quant_min);
|
||||
@ -1670,6 +1689,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
done:
|
||||
s->buf_ptr = p;
|
||||
return 0;
|
||||
out_of_memory:
|
||||
return re_parse_out_of_memory(s);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
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)) {
|
||||
re_parse_error(s, "out of memory");
|
||||
re_parse_out_of_memory(s);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
15
qjs.c
15
qjs.c
@ -270,6 +270,7 @@ void help(void)
|
||||
"-T --trace trace memory allocation\n"
|
||||
"-d --dump dump the memory usage stats\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"
|
||||
"-q --quit just instantiate the interpreter and quit\n");
|
||||
exit(1);
|
||||
@ -295,7 +296,8 @@ int main(int argc, char **argv)
|
||||
#ifdef CONFIG_BIGNUM
|
||||
int load_jscalc, bignum_ext = 0;
|
||||
#endif
|
||||
|
||||
size_t stack_size = 0;
|
||||
|
||||
#ifdef CONFIG_BIGNUM
|
||||
/* 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);
|
||||
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) {
|
||||
fprintf(stderr, "qjs: unknown option '-%c'\n", opt);
|
||||
} else {
|
||||
@ -428,6 +438,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
if (memory_limit != 0)
|
||||
JS_SetMemoryLimit(rt, memory_limit);
|
||||
if (stack_size != 0)
|
||||
JS_SetMaxStackSize(rt, stack_size);
|
||||
js_std_init_handlers(rt);
|
||||
ctx = JS_NewContext(rt);
|
||||
if (!ctx) {
|
||||
fprintf(stderr, "qjs: cannot allocate JS context\n");
|
||||
|
17
qjsc.c
17
qjsc.c
@ -326,6 +326,7 @@ static const char main_c_template1[] =
|
||||
" JSRuntime *rt;\n"
|
||||
" JSContext *ctx;\n"
|
||||
" rt = JS_NewRuntime();\n"
|
||||
" js_std_init_handlers(rt);\n"
|
||||
;
|
||||
|
||||
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"
|
||||
"-x byte swapped output\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
|
||||
{
|
||||
int i;
|
||||
@ -447,6 +449,7 @@ static int output_executable(const char *out_filename, const char *cfilename,
|
||||
*arg++ = libjsname;
|
||||
*arg++ = "-lm";
|
||||
*arg++ = "-ldl";
|
||||
*arg++ = "-lpthread";
|
||||
*arg = NULL;
|
||||
|
||||
if (verbose) {
|
||||
@ -487,6 +490,7 @@ int main(int argc, char **argv)
|
||||
BOOL use_lto;
|
||||
int module;
|
||||
OutputTypeEnum output_type;
|
||||
size_t stack_size;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
BOOL bignum_ext = FALSE;
|
||||
#endif
|
||||
@ -499,13 +503,14 @@ int main(int argc, char **argv)
|
||||
byte_swap = FALSE;
|
||||
verbose = 0;
|
||||
use_lto = FALSE;
|
||||
stack_size = 0;
|
||||
|
||||
/* add system modules */
|
||||
namelist_add(&cmodule_list, "std", "std", 0);
|
||||
namelist_add(&cmodule_list, "os", "os", 0);
|
||||
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "ho:cN:f:mxevM:p:");
|
||||
c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
@ -580,6 +585,9 @@ int main(int argc, char **argv)
|
||||
case 'p':
|
||||
c_ident_prefix = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
stack_size = (size_t)strtod(optarg, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -652,6 +660,11 @@ int main(int argc, char **argv)
|
||||
fputs(main_c_template1, fo);
|
||||
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 */
|
||||
if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
|
||||
fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
|
||||
|
@ -82,6 +82,7 @@ DEF(length, "length")
|
||||
DEF(fileName, "fileName")
|
||||
DEF(lineNumber, "lineNumber")
|
||||
DEF(message, "message")
|
||||
DEF(errors, "errors")
|
||||
DEF(stack, "stack")
|
||||
DEF(name, "name")
|
||||
DEF(toString, "toString")
|
||||
|
1438
quickjs-libc.c
1438
quickjs-libc.c
File diff suppressed because it is too large
Load Diff
@ -29,10 +29,15 @@
|
||||
|
||||
#include "quickjs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
JSModuleDef *js_init_module_std(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_loop(JSContext *ctx);
|
||||
void js_std_init_handlers(JSRuntime *rt);
|
||||
void js_std_free_handlers(JSRuntime *rt);
|
||||
void js_std_dump_error(JSContext *ctx);
|
||||
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,
|
||||
JS_BOOL is_handled, void *opaque);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" { */
|
||||
#endif
|
||||
|
||||
#endif /* QUICKJS_LIBC_H */
|
||||
|
29
quickjs.h
29
quickjs.h
@ -498,7 +498,7 @@ int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);
|
||||
|
||||
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)
|
||||
@ -746,7 +746,7 @@ int JS_IsExtensible(JSContext *ctx, JSValueConst obj);
|
||||
int JS_PreventExtensions(JSContext *ctx, JSValueConst obj);
|
||||
int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags);
|
||||
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_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'. */
|
||||
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
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,
|
||||
JSValueConst replacer, JSValueConst space0);
|
||||
|
||||
@ -810,6 +813,14 @@ JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
|
||||
size_t *pbyte_offset,
|
||||
size_t *pbyte_length,
|
||||
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);
|
||||
|
||||
@ -853,14 +864,24 @@ JS_BOOL JS_IsJobPending(JSRuntime *rt);
|
||||
int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);
|
||||
|
||||
/* Object Writer/Reader (currently only used to handle precompiled code) */
|
||||
#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
|
||||
#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */
|
||||
#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
|
||||
#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,
|
||||
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_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,
|
||||
int flags);
|
||||
|
||||
/* load the dependencies of the module 'obj'. Useful when JS_ReadObject()
|
||||
returns a module. */
|
||||
int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
|
||||
|
72
repl.js
72
repl.js
@ -209,6 +209,29 @@ import * as os from "os";
|
||||
(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) {
|
||||
switch (a + b) {
|
||||
case "()":
|
||||
@ -235,6 +258,7 @@ import * as os from "os";
|
||||
std.puts("\x1b[" + ((n != 1) ? n : "") + code);
|
||||
}
|
||||
|
||||
/* XXX: handle double-width characters */
|
||||
function move_cursor(delta) {
|
||||
var i, l;
|
||||
if (delta > 0) {
|
||||
@ -269,15 +293,16 @@ import * as os from "os";
|
||||
}
|
||||
|
||||
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 (!show_colors && last_cmd.substring(0, last_cursor_pos) == cmd.substring(0, last_cursor_pos)) {
|
||||
/* optimize common case */
|
||||
std.puts(cmd.substring(last_cursor_pos));
|
||||
} else {
|
||||
/* 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) {
|
||||
var str = mexpr ? mexpr + '\n' + cmd : cmd;
|
||||
var start = str.length - cmd.length;
|
||||
@ -287,8 +312,7 @@ import * as os from "os";
|
||||
std.puts(cmd);
|
||||
}
|
||||
}
|
||||
/* Note: assuming no surrogate pairs */
|
||||
term_cursor_x = (term_cursor_x + cmd.length) % term_width;
|
||||
term_cursor_x = (term_cursor_x + ucs_length(cmd)) % term_width;
|
||||
if (term_cursor_x == 0) {
|
||||
/* show the cursor on the next line */
|
||||
std.puts(" \x08");
|
||||
@ -298,7 +322,11 @@ import * as os from "os";
|
||||
last_cmd = cmd;
|
||||
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;
|
||||
std.out.flush();
|
||||
}
|
||||
@ -333,13 +361,19 @@ import * as os from "os";
|
||||
}
|
||||
|
||||
function forward_char() {
|
||||
if (cursor_pos < cmd.length)
|
||||
if (cursor_pos < cmd.length) {
|
||||
cursor_pos++;
|
||||
while (is_trailing_surrogate(cmd.charAt(cursor_pos)))
|
||||
cursor_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
function backward_char() {
|
||||
if (cursor_pos > 0)
|
||||
if (cursor_pos > 0) {
|
||||
cursor_pos--;
|
||||
while (is_trailing_surrogate(cmd.charAt(cursor_pos)))
|
||||
cursor_pos--;
|
||||
}
|
||||
}
|
||||
|
||||
function skip_word_forward(pos) {
|
||||
@ -419,8 +453,18 @@ import * as os from "os";
|
||||
}
|
||||
|
||||
function delete_char_dir(dir) {
|
||||
var start = cursor_pos - (dir < 0);
|
||||
var end = start + 1;
|
||||
var start, end;
|
||||
|
||||
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 (last_fun === kill_region) {
|
||||
kill_region(start, end, dir);
|
||||
@ -752,7 +796,7 @@ import * as os from "os";
|
||||
function readline_print_prompt()
|
||||
{
|
||||
std.puts(prompt);
|
||||
term_cursor_x = prompt.length % term_width;
|
||||
term_cursor_x = ucs_length(prompt) % term_width;
|
||||
last_cmd = "";
|
||||
last_cursor_pos = 0;
|
||||
}
|
||||
@ -785,7 +829,7 @@ import * as os from "os";
|
||||
|
||||
function handle_char(c1) {
|
||||
var c;
|
||||
c = String.fromCharCode(c1);
|
||||
c = String.fromCodePoint(c1);
|
||||
switch(readline_state) {
|
||||
case 0:
|
||||
if (c == '\x1b') { /* '^[' - ESC */
|
||||
@ -825,7 +869,7 @@ import * as os from "os";
|
||||
var fun;
|
||||
|
||||
if (quote_flag) {
|
||||
if (keys.length === 1)
|
||||
if (ucs_length(keys) === 1)
|
||||
insert(keys);
|
||||
quote_flag = false;
|
||||
} else if (fun = commands[keys]) {
|
||||
@ -845,7 +889,7 @@ import * as os from "os";
|
||||
return;
|
||||
}
|
||||
last_fun = this_fun;
|
||||
} else if (keys.length === 1 && keys >= ' ') {
|
||||
} else if (ucs_length(keys) === 1 && keys >= ' ') {
|
||||
insert(keys);
|
||||
last_fun = insert;
|
||||
} else {
|
||||
|
@ -58,6 +58,7 @@ arrow-function
|
||||
async-functions
|
||||
async-iteration
|
||||
Atomics
|
||||
Atomics.waitAsync=skip
|
||||
BigInt
|
||||
caller
|
||||
class
|
||||
|
@ -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/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
|
||||
test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: strict mode: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
|
||||
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name
|
||||
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name
|
||||
test262/test/language/expressions/arrow-function/eval-var-scope-syntax-err.js:47: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
|
||||
test262/test/language/expressions/async-arrow-function/eval-var-scope-syntax-err.js:49: TypeError: $DONE() not called
|
||||
test262/test/language/expressions/async-function/named-eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
|
||||
@ -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/gen-meth-eval-var-scope-syntax-err.js:54: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
|
||||
test262/test/language/expressions/object/method-definition/meth-eval-var-scope-syntax-err.js:50: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
|
||||
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: 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:21: TypeError: cannot read property 'c' of undefined
|
||||
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined
|
||||
test262/test/language/statements/async-function/eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
|
||||
test262/test/language/statements/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
|
||||
test262/test/language/statements/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name
|
||||
|
@ -31,6 +31,7 @@ static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
|
||||
uint64_t pos, len;
|
||||
JSValue obj;
|
||||
size_t size;
|
||||
int flags;
|
||||
|
||||
if (JS_ToIndex(ctx, &pos, argv[1]))
|
||||
return JS_EXCEPTION;
|
||||
@ -41,7 +42,10 @@ static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_EXCEPTION;
|
||||
if (pos + len > size)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -51,8 +55,12 @@ static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
|
||||
size_t len;
|
||||
uint8_t *buf;
|
||||
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)
|
||||
return JS_EXCEPTION;
|
||||
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[] = {
|
||||
JS_CFUNC_DEF("read", 3, js_bjson_read ),
|
||||
JS_CFUNC_DEF("write", 1, js_bjson_write ),
|
||||
JS_CFUNC_DEF("read", 4, js_bjson_read ),
|
||||
JS_CFUNC_DEF("write", 2, js_bjson_write ),
|
||||
};
|
||||
|
||||
static int js_bjson_init(JSContext *ctx, JSModuleDef *m)
|
||||
|
@ -228,6 +228,19 @@ function prop_create(n)
|
||||
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)
|
||||
{
|
||||
var tab, len, sum, i, j;
|
||||
@ -945,6 +958,7 @@ function main(argc, argv, g)
|
||||
prop_read,
|
||||
prop_write,
|
||||
prop_create,
|
||||
prop_delete,
|
||||
array_read,
|
||||
array_write,
|
||||
array_prop_create,
|
||||
|
@ -1,12 +1,20 @@
|
||||
import * as bjson from "./bjson.so";
|
||||
|
||||
function assert(b, str)
|
||||
{
|
||||
if (b) {
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
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)
|
||||
@ -24,6 +32,20 @@ function toHex(a)
|
||||
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)
|
||||
{
|
||||
var s, i, props, prop;
|
||||
@ -32,7 +54,15 @@ function toStr(a)
|
||||
case "object":
|
||||
if (a === 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 = "[";
|
||||
for(i = 0; i < a.length; i++) {
|
||||
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()
|
||||
{
|
||||
var obj;
|
||||
@ -111,6 +170,11 @@ function bjson_test_all()
|
||||
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 */
|
||||
obj = {};
|
||||
obj.x = obj;
|
||||
@ -120,6 +184,8 @@ function bjson_test_all()
|
||||
} catch(e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
|
||||
bjson_test_reference();
|
||||
}
|
||||
|
||||
bjson_test_all();
|
||||
|
@ -287,6 +287,10 @@ function test_math()
|
||||
assert(Math.ceil(a), 2);
|
||||
assert(Math.imul(0x12345678, 123), -1088058456);
|
||||
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()
|
||||
|
@ -311,10 +311,21 @@ function test_template()
|
||||
var a, b;
|
||||
b = 123;
|
||||
a = `abc${b}d`;
|
||||
assert(a === "abc123d");
|
||||
assert(a, "abc123d");
|
||||
|
||||
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()
|
||||
@ -358,6 +369,7 @@ test_prototype();
|
||||
test_arguments();
|
||||
test_class();
|
||||
test_template();
|
||||
test_template_skip();
|
||||
test_object_literal();
|
||||
test_regexp_skip();
|
||||
test_labels();
|
@ -26,6 +26,12 @@ try { std.loadScript("test_assert.js"); } catch(e) {}
|
||||
function test_printf()
|
||||
{
|
||||
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()
|
||||
@ -119,6 +125,20 @@ function test_popen()
|
||||
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()
|
||||
{
|
||||
var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
|
||||
@ -258,3 +278,4 @@ test_popen();
|
||||
test_os();
|
||||
test_os_exec();
|
||||
test_timer();
|
||||
test_ext_json();
|
||||
|
93
tests/test_worker.js
Normal file
93
tests/test_worker.js
Normal 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();
|
Loading…
Reference in New Issue
Block a user