quickjs-2024-01-13.tar.xz

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4765 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2024-01-13 13:04:19 +00:00
parent 10d438e723
commit 2b7077ca70
35 changed files with 3799 additions and 1453 deletions

View File

@ -1,3 +1,22 @@
2024-01-13:
- top-level-await support in modules
- allow 'await' in the REPL
- added Array.prototype.{with,toReversed,toSpliced,toSorted} and
TypedArray.prototype.{with,toReversed,toSorted}
- added String.prototype.isWellFormed and String.prototype.toWellFormed
- added Object.groupBy and Map.groupBy
- added Promise.withResolvers
- class static block
- 'in' operator support for private fields
- optional chaining fixes
- added RegExp 'd' flag
- fixed RegExp zero length match logic
- fixed RegExp case insensitive flag
- added os.getpid() and os.now()
- added cosmopolitan build
- misc bug fixes
2023-12-09:
- added Object.hasOwn, {String|Array|TypedArray}.prototype.at,

83
deps/quickjs/Makefile vendored
View File

@ -33,15 +33,11 @@ CONFIG_LTO=y
#CONFIG_WERROR=y
# force 32 bit build for some utilities
#CONFIG_M32=y
ifdef CONFIG_DARWIN
# use clang instead of gcc
CONFIG_CLANG=y
CONFIG_DEFAULT_AR=y
endif
# cosmopolitan build (see https://github.com/jart/cosmopolitan)
#CONFIG_COSMO=y
# installation directory
prefix=/usr/local
PREFIX?=/usr/local
# use the gprof profiler
#CONFIG_PROFILE=y
@ -52,21 +48,28 @@ CONFIG_BIGNUM=y
OBJDIR=.obj
ifdef CONFIG_DARWIN
# use clang instead of gcc
CONFIG_CLANG=y
CONFIG_DEFAULT_AR=y
endif
ifdef CONFIG_WIN32
ifdef CONFIG_M32
CROSS_PREFIX=i686-w64-mingw32-
CROSS_PREFIX?=i686-w64-mingw32-
else
CROSS_PREFIX=x86_64-w64-mingw32-
CROSS_PREFIX?=x86_64-w64-mingw32-
endif
EXE=.exe
else
CROSS_PREFIX=
CROSS_PREFIX?=
EXE=
endif
ifdef CONFIG_CLANG
HOST_CC=clang
CC=$(CROSS_PREFIX)clang
CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
CFLAGS += -Wextra
CFLAGS += -Wno-sign-compare
CFLAGS += -Wno-missing-field-initializers
@ -84,10 +87,18 @@ ifdef CONFIG_CLANG
AR=$(CROSS_PREFIX)ar
endif
endif
else ifdef CONFIG_COSMO
CONFIG_LTO=
HOST_CC=gcc
CC=cosmocc
# cosmocc does not correct support -MF
CFLAGS=-g -Wall #-MMD -MF $(OBJDIR)/$(@F).d
CFLAGS += -Wno-array-bounds -Wno-format-truncation
AR=cosmoar
else
HOST_CC=gcc
CC=$(CROSS_PREFIX)gcc
CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
CFLAGS += -Wno-array-bounds -Wno-format-truncation
ifdef CONFIG_LTO
AR=$(CROSS_PREFIX)gcc-ar
@ -96,6 +107,7 @@ else
endif
endif
STRIP=$(CROSS_PREFIX)strip
CFLAGS+=-fwrapv # ensure that signed overflows behave as expected
ifdef CONFIG_WERROR
CFLAGS+=-Werror
endif
@ -112,7 +124,11 @@ CFLAGS_DEBUG=$(CFLAGS) -O0
CFLAGS_SMALL=$(CFLAGS) -Os
CFLAGS_OPT=$(CFLAGS) -O2
CFLAGS_NOLTO:=$(CFLAGS_OPT)
LDFLAGS=-g
ifdef CONFIG_COSMO
LDFLAGS+=-s # better to strip by default
else
LDFLAGS+=-g
endif
ifdef CONFIG_LTO
CFLAGS_SMALL+=-flto
CFLAGS_OPT+=-flto
@ -132,6 +148,12 @@ else
LDEXPORT=-rdynamic
endif
ifndef CONFIG_COSMO
ifndef CONFIG_DARWIN
CONFIG_SHARED_LIBS=y # building shared libraries is supported
endif
endif
PROGS=qjs$(EXE) qjsc$(EXE) run-test262
ifneq ($(CROSS_PREFIX),)
QJSC_CC=gcc
@ -154,13 +176,12 @@ endif
# examples
ifeq ($(CROSS_PREFIX),)
ifdef CONFIG_ASAN
PROGS+=
else
PROGS+=examples/hello examples/hello_module examples/test_fib
ifndef CONFIG_DARWIN
PROGS+=examples/fib.so examples/point.so
PROGS+=examples/hello
ifndef CONFIG_ASAN
PROGS+=examples/hello_module
endif
ifdef CONFIG_SHARED_LIBS
PROGS+=examples/test_fib examples/fib.so examples/point.so
endif
endif
@ -200,11 +221,11 @@ $(QJSC): $(OBJDIR)/qjsc.host.o \
endif #CROSS_PREFIX
QJSC_DEFINES:=-DCONFIG_CC=\"$(QJSC_CC)\" -DCONFIG_PREFIX=\"$(prefix)\"
QJSC_DEFINES:=-DCONFIG_CC=\"$(QJSC_CC)\" -DCONFIG_PREFIX=\"$(PREFIX)\"
ifdef CONFIG_LTO
QJSC_DEFINES+=-DCONFIG_LTO
endif
QJSC_HOST_DEFINES:=-DCONFIG_CC=\"$(HOST_CC)\" -DCONFIG_PREFIX=\"$(prefix)\"
QJSC_HOST_DEFINES:=-DCONFIG_CC=\"$(HOST_CC)\" -DCONFIG_PREFIX=\"$(PREFIX)\"
$(OBJDIR)/qjsc.o: CFLAGS+=$(QJSC_DEFINES)
$(OBJDIR)/qjsc.host.o: CFLAGS+=$(QJSC_HOST_DEFINES)
@ -297,17 +318,17 @@ clean:
rm -rf run-test262-debug run-test262-32
install: all
mkdir -p "$(DESTDIR)$(prefix)/bin"
mkdir -p "$(DESTDIR)$(PREFIX)/bin"
$(STRIP) qjs qjsc
install -m755 qjs qjsc "$(DESTDIR)$(prefix)/bin"
ln -sf qjs "$(DESTDIR)$(prefix)/bin/qjscalc"
mkdir -p "$(DESTDIR)$(prefix)/lib/quickjs"
install -m644 libquickjs.a "$(DESTDIR)$(prefix)/lib/quickjs"
install -m755 qjs qjsc "$(DESTDIR)$(PREFIX)/bin"
ln -sf qjs "$(DESTDIR)$(PREFIX)/bin/qjscalc"
mkdir -p "$(DESTDIR)$(PREFIX)/lib/quickjs"
install -m644 libquickjs.a "$(DESTDIR)$(PREFIX)/lib/quickjs"
ifdef CONFIG_LTO
install -m644 libquickjs.lto.a "$(DESTDIR)$(prefix)/lib/quickjs"
install -m644 libquickjs.lto.a "$(DESTDIR)$(PREFIX)/lib/quickjs"
endif
mkdir -p "$(DESTDIR)$(prefix)/include/quickjs"
install -m644 quickjs.h quickjs-libc.h "$(DESTDIR)$(prefix)/include/quickjs"
mkdir -p "$(DESTDIR)$(PREFIX)/include/quickjs"
install -m644 quickjs.h quickjs-libc.h "$(DESTDIR)$(PREFIX)/include/quickjs"
###############################################################################
# examples
@ -373,7 +394,7 @@ doc/%.html: doc/%.html.pre
###############################################################################
# tests
ifndef CONFIG_DARWIN
ifdef CONFIG_SHARED_LIBS
test: tests/bjson.so examples/point.so
endif
ifdef CONFIG_M32
@ -387,7 +408,7 @@ test: qjs
./qjs tests/test_loop.js
./qjs tests/test_std.js
./qjs tests/test_worker.js
ifndef CONFIG_DARWIN
ifdef CONFIG_SHARED_LIBS
ifdef CONFIG_BIGNUM
./qjs --bignum tests/test_bjson.js
else

5
deps/quickjs/TODO vendored
View File

@ -1,6 +1,3 @@
Bugs:
- modules: better error handling with cyclic module references
Misc ideas:
- use custom printf to avoid compatibility issues with floating point numbers
- consistent naming for preprocessor defines
@ -66,5 +63,5 @@ Optimization ideas:
Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
Result: 41/76133 errors, 1497 excluded, 8650 skipped
Result: 10/76947 errors, 1497 excluded, 8117 skipped
Test262 commit: 6cbb6da9473c56d95358d8e679c5a6d2b4574efb

View File

@ -1 +1 @@
2023-12-09
2024-01-13

View File

@ -49,6 +49,9 @@
#define countof(x) (sizeof(x) / sizeof((x)[0]))
#endif
/* return the pointer of type 'type *' containing 'ptr' as field 'member' */
#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
typedef int BOOL;
#ifndef FALSE

View File

@ -72,7 +72,7 @@ ul.no-bullet {list-style: none}
<ul class="no-bullet">
<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-ES2023-support" href="#ES2023-support">3.1.1 ES2023 support</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>
@ -128,8 +128,8 @@ ul.no-bullet {list-style: none}
<a name="Introduction"></a>
<h2 class="chapter">1 Introduction</h2>
<p>QuickJS is a small and embeddable Javascript engine. It supports the
ES2020 specification
<p>QuickJS is a small and embeddable Javascript engine. It supports most of the
ES2023 specification
<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>
including modules, asynchronous generators, proxies and BigInt.
</p>
@ -143,14 +143,14 @@ and operator overloading.
<ul>
<li> Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple &ldquo;hello world&rdquo; program.
</li><li> Fast interpreter with very low startup time: runs the 69000 tests of the ECMAScript Test Suite<a name="DOCF2" href="#FOOT2"><sup>2</sup></a> in about 95 seconds on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds.
</li><li> Fast interpreter with very low startup time: runs the 77000 tests of the ECMAScript Test Suite<a name="DOCF2" href="#FOOT2"><sup>2</sup></a> in less than 2 minutes on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds.
</li><li> Almost complete ES2020 support including modules, asynchronous
generators and full Annex B support (legacy web compatibility). Many
features from the upcoming ES2021 specification
</li><li> Almost complete ES2023 support including modules, asynchronous
generators and full Annex B support (legacy web compatibility). Some
features from the upcoming ES2024 specification
<a name="DOCF3" href="#FOOT3"><sup>3</sup></a> are also supported.
</li><li> Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2020 features.
</li><li> Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2023 features.
</li><li> Compile Javascript sources to executables with no external dependency.
@ -180,6 +180,11 @@ options then run <code>make</code>.
<p>You can type <code>make install</code> as root if you wish to install the binaries and support files to
<code>/usr/local</code> (this is not necessary to use QuickJS).
</p>
<p>Note: On some OSes atomic operations are not available or need a
specific library. If you get related errors, you should either add
<code>-latomics</code> in the Makefile <code>LIBS</code> variable or disable
<code>CONFIG_ATOMICS</code> in <samp>quickjs.c</samp>.
</p>
<a name="Quick-start"></a>
<h3 class="section">2.2 Quick start</h3>
@ -400,10 +405,10 @@ about 100 seconds).
<a name="Language-support"></a>
<h3 class="section">3.1 Language support</h3>
<a name="ES2020-support"></a>
<h4 class="subsection">3.1.1 ES2020 support</h4>
<a name="ES2023-support"></a>
<h4 class="subsection">3.1.1 ES2023 support</h4>
<p>The ES2020 specification is almost fully supported including the Annex
<p>The ES2023 specification is almost fully supported including the Annex
B (legacy web compatibility) and the Unicode related features.
</p>
<p>The following features are not supported yet:
@ -411,6 +416,10 @@ B (legacy web compatibility) and the Unicode related features.
<ul>
<li> Tail calls<a name="DOCF6" href="#FOOT6"><sup>6</sup></a>
</li><li> WeakRef and FinalizationRegistry objects
</li><li> Symbols as WeakMap keys
</li></ul>
<a name="ECMA402"></a>
@ -511,6 +520,10 @@ optional properties:
<dd><p>Boolean (default = false). If true, error backtraces do not list the
stack frames below the evalScript.
</p></dd>
<dt><code>async</code></dt>
<dd><p>Boolean (default = false). If true, <code>await</code> is accepted in the
script and a promise is returned.
</p></dd>
</dl>
</dd>
@ -968,6 +981,10 @@ object containing optional parameters:
</dd>
</dl>
</dd>
<dt><code>getpid()</code></dt>
<dd><p>Return the current process ID.
</p>
</dd>
<dt><code>waitpid(pid, options)</code></dt>
<dd><p><code>waitpid</code> Unix system call. Return the array <code>[ret,
@ -995,6 +1012,19 @@ write_fd]</code> or null in case of error.
<dd><p>Sleep during <code>delay_ms</code> milliseconds.
</p>
</dd>
<dt><code>sleepAsync(delay_ms)</code></dt>
<dd><p>Asynchronouse sleep during <code>delay_ms</code> milliseconds. Returns a promise. Example:
</p><div class="example">
<pre class="example">await os.sleepAsync(500);
</pre></div>
</dd>
<dt><code>now()</code></dt>
<dd><p>Return a timestamp in milliseconds with more precision than
<code>Date.now()</code>. The time origin is unspecified and is normally not
impacted by system clock adjustments.
</p>
</dd>
<dt><code>setTimeout(func, delay)</code></dt>
<dd><p>Call the function <code>func</code> after <code>delay</code> ms. Return a handle
to the timer.
@ -1310,7 +1340,7 @@ stack holds the Javascript parameters and local variables.
<h3 class="section">4.4 RegExp</h3>
<p>A specific regular expression engine was developed. It is both small
and efficient and supports all the ES2020 features including the
and efficient and supports all the ES2023 features including the
Unicode properties. As the Javascript compiler, it directly generates
bytecode without a parse tree.
</p>
@ -1318,9 +1348,6 @@ bytecode without a parse tree.
recursion on the system stack. Simple quantifiers are specifically
optimized to avoid recursions.
</p>
<p>Infinite recursions coming from quantifiers with empty terms are
avoided.
</p>
<p>The full regexp library weights about 15 KiB (x86 code), excluding the
Unicode library.
</p>
@ -1359,11 +1386,11 @@ Bellard and Charlie Gordon.
<h4 class="footnotes-heading">Footnotes</h4>
<h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>
<p><a href="https://tc39.es/ecma262/">https://tc39.es/ecma262/</a></p>
<p><a href="https://tc39.es/ecma262/2023">https://tc39.es/ecma262/2023</a></p>
<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
<p><a href="https://github.com/tc39/test262">https://github.com/tc39/test262</a></p>
<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
<p><a href="https://tc39.github.io/ecma262/">https://tc39.github.io/ecma262/</a></p>
<p><a href="https://tc39.es/ecma262/">https://tc39.es/ecma262/</a></p>
<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
<p>The old
ES5.1 tests can be extracted with <code>git clone --single-branch

Binary file not shown.

View File

@ -19,9 +19,9 @@
@chapter Introduction
QuickJS is a small and embeddable Javascript engine. It supports the
ES2020 specification
@footnote{@url{https://tc39.es/ecma262/}}
QuickJS is a small and embeddable Javascript engine. It supports most of the
ES2023 specification
@footnote{@url{https://tc39.es/ecma262/2023 }}
including modules, asynchronous generators, proxies and BigInt.
It supports mathematical extensions such as big decimal float float
@ -34,14 +34,14 @@ and operator overloading.
@item Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple ``hello world'' program.
@item Fast interpreter with very low startup time: runs the 69000 tests of the ECMAScript Test Suite@footnote{@url{https://github.com/tc39/test262}} in about 95 seconds on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds.
@item Fast interpreter with very low startup time: runs the 77000 tests of the ECMAScript Test Suite@footnote{@url{https://github.com/tc39/test262}} in less than 2 minutes on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds.
@item Almost complete ES2020 support including modules, asynchronous
generators and full Annex B support (legacy web compatibility). Many
features from the upcoming ES2021 specification
@footnote{@url{https://tc39.github.io/ecma262/}} are also supported.
@item Almost complete ES2023 support including modules, asynchronous
generators and full Annex B support (legacy web compatibility). Some
features from the upcoming ES2024 specification
@footnote{@url{https://tc39.es/ecma262/}} are also supported.
@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2020 features.
@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2023 features.
@item Compile Javascript sources to executables with no external dependency.
@ -69,6 +69,11 @@ options then run @code{make}.
You can type @code{make install} as root if you wish to install the binaries and support files to
@code{/usr/local} (this is not necessary to use QuickJS).
Note: On some OSes atomic operations are not available or need a
specific library. If you get related errors, you should either add
@code{-latomics} in the Makefile @code{LIBS} variable or disable
@code{CONFIG_ATOMICS} in @file{quickjs.c}.
@section Quick start
@code{qjs} is the command line interpreter (Read-Eval-Print Loop). You can pass
@ -265,9 +270,9 @@ about 100 seconds).
@section Language support
@subsection ES2020 support
@subsection ES2023 support
The ES2020 specification is almost fully supported including the Annex
The ES2023 specification is almost fully supported including the Annex
B (legacy web compatibility) and the Unicode related features.
The following features are not supported yet:
@ -276,6 +281,10 @@ The following features are not supported yet:
@item Tail calls@footnote{We believe the current specification of tails calls is too complicated and presents limited practical interests.}
@item WeakRef and FinalizationRegistry objects
@item Symbols as WeakMap keys
@end itemize
@subsection ECMA402
@ -368,6 +377,9 @@ optional properties:
@item backtrace_barrier
Boolean (default = false). If true, error backtraces do not list the
stack frames below the evalScript.
@item async
Boolean (default = false). If true, @code{await} is accepted in the
script and a promise is returned.
@end table
@item loadScript(filename)
@ -749,6 +761,9 @@ object containing optional parameters:
@end table
@item getpid()
Return the current process ID.
@item waitpid(pid, options)
@code{waitpid} Unix system call. Return the array @code{[ret,
status]}. @code{ret} contains @code{-errno} in case of error.
@ -769,6 +784,17 @@ write_fd]} or null in case of error.
@item sleep(delay_ms)
Sleep during @code{delay_ms} milliseconds.
@item sleepAsync(delay_ms)
Asynchronouse sleep during @code{delay_ms} milliseconds. Returns a promise. Example:
@example
await os.sleepAsync(500);
@end example
@item now()
Return a timestamp in milliseconds with more precision than
@code{Date.now()}. The time origin is unspecified and is normally not
impacted by system clock adjustments.
@item setTimeout(func, delay)
Call the function @code{func} after @code{delay} ms. Return a handle
to the timer.
@ -1053,7 +1079,7 @@ stack holds the Javascript parameters and local variables.
@section RegExp
A specific regular expression engine was developed. It is both small
and efficient and supports all the ES2020 features including the
and efficient and supports all the ES2023 features including the
Unicode properties. As the Javascript compiler, it directly generates
bytecode without a parse tree.
@ -1061,9 +1087,6 @@ Backtracking with an explicit stack is used so that there is no
recursion on the system stack. Simple quantifiers are specifically
optimized to avoid recursions.
Infinite recursions coming from quantifiers with empty terms are
avoided.
The full regexp library weights about 15 KiB (x86 code), excluding the
Unicode library.

View File

@ -27,7 +27,7 @@
#include <stddef.h>
#include <stdint.h>
#if INTPTR_MAX >= INT64_MAX
#if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX)
#define LIMB_LOG2_BITS 6
#else
#define LIMB_LOG2_BITS 5

View File

@ -50,8 +50,7 @@ DEF(range32, 3) /* variable length */
DEF(lookahead, 5)
DEF(negative_lookahead, 5)
DEF(push_char_pos, 1) /* push the character position on the stack */
DEF(bne_char_pos, 5) /* pop one stack element and jump if equal to the character
position */
DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */
DEF(prev, 1) /* go to the previous char */
DEF(simple_greedy_quant, 17)

View File

@ -34,9 +34,6 @@
/*
TODO:
- Add full unicode canonicalize rules for character ranges (not
really useful but needed for exact "ignorecase" compatibility).
- Add a lock step execution mode (=linear time execution guaranteed)
when the regular expression is "simple" i.e. no backreference nor
complicated lookahead. The opcodes are designed for this execution
@ -120,33 +117,6 @@ static int dbuf_insert(DynBuf *s, int pos, int len)
return 0;
}
/* canonicalize with the specific JS regexp rules */
static uint32_t lre_canonicalize(uint32_t c, BOOL is_utf16)
{
uint32_t res[LRE_CC_RES_LEN_MAX];
int len;
if (is_utf16) {
if (likely(c < 128)) {
if (c >= 'A' && c <= 'Z')
c = c - 'A' + 'a';
} else {
lre_case_conv(res, c, 2);
c = res[0];
}
} else {
if (likely(c < 128)) {
if (c >= 'a' && c <= 'z')
c = c - 'a' + 'A';
} else {
/* legacy regexp: to upper case if single char >= 128 */
len = lre_case_conv(res, c, FALSE);
if (len == 1 && res[0] >= 128)
c = res[0];
}
}
return c;
}
static const uint16_t char_range_d[] = {
1,
0x0030, 0x0039 + 1,
@ -245,31 +215,6 @@ static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c)
return -1;
}
static int cr_canonicalize(CharRange *cr)
{
CharRange a;
uint32_t pt[2];
int i, ret;
cr_init(&a, cr->mem_opaque, lre_realloc);
pt[0] = 'a';
pt[1] = 'z' + 1;
ret = cr_op(&a, cr->points, cr->len, pt, 2, CR_OP_INTER);
if (ret)
goto fail;
/* convert to upper case */
/* XXX: the generic unicode case would be much more complicated
and not really useful */
for(i = 0; i < a.len; i++) {
a.points[i] += 'A' - 'a';
}
/* Note: for simplicity we keep the lower case ranges */
ret = cr_union1(cr, a.points, a.len);
fail:
cr_free(&a);
return ret;
}
#ifdef DUMP_REOP
static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
int buf_len)
@ -335,7 +280,6 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
case REOP_loop:
case REOP_lookahead:
case REOP_negative_lookahead:
case REOP_bne_char_pos:
val = get_u32(buf + pos + 1);
val += (pos + 5);
printf(" %u", val);
@ -922,7 +866,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
}
}
if (s->ignore_case) {
if (cr_canonicalize(cr))
if (cr_regexp_canonicalize(cr, s->is_utf16))
goto memory_error;
}
if (invert) {
@ -943,22 +887,17 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
}
/* Return:
1 if the opcodes in bc_buf[] always advance the character pointer.
0 if the character pointer may not be advanced.
-1 if the code may depend on side effects of its previous execution (backreference)
- true if the opcodes may not advance the char pointer
- false if the opcodes always advance the char pointer
*/
static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len)
static BOOL re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len)
{
int pos, opcode, ret, len, i;
uint32_t val, last;
BOOL has_back_reference;
uint8_t capture_bitmap[CAPTURE_COUNT_MAX];
int pos, opcode, len;
uint32_t val;
BOOL ret;
ret = -2; /* not known yet */
ret = TRUE;
pos = 0;
has_back_reference = FALSE;
memset(capture_bitmap, 0, sizeof(capture_bitmap));
while (pos < bc_buf_len) {
opcode = bc_buf[pos];
len = reopcode_info[opcode].size;
@ -976,8 +915,7 @@ static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len)
case REOP_dot:
case REOP_any:
simple_char:
if (ret == -2)
ret = 1;
ret = FALSE;
break;
case REOP_line_start:
case REOP_line_end:
@ -991,41 +929,16 @@ static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len)
break;
case REOP_save_start:
case REOP_save_end:
val = bc_buf[pos + 1];
capture_bitmap[val] |= 1;
break;
case REOP_save_reset:
{
val = bc_buf[pos + 1];
last = bc_buf[pos + 2];
while (val < last)
capture_bitmap[val++] |= 1;
}
break;
case REOP_back_reference:
case REOP_backward_back_reference:
val = bc_buf[pos + 1];
capture_bitmap[val] |= 2;
has_back_reference = TRUE;
break;
default:
/* safe behvior: we cannot predict the outcome */
if (ret == -2)
ret = 0;
break;
return TRUE;
}
pos += len;
}
if (has_back_reference) {
/* check if there is back reference which references a capture
made in the some code */
for(i = 0; i < CAPTURE_COUNT_MAX; i++) {
if (capture_bitmap[i] == 3)
return -1;
}
}
if (ret == -2)
ret = 0;
return ret;
}
@ -1596,8 +1509,12 @@ 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);
/* the spec tells that if there is no advance when
running the atom after the first quant_min times,
then there is no match. We remove this test when we
are sure the atom always advances the position. */
add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start,
s->byte_code.size - last_atom_start);
} else {
add_zero_advance_check = FALSE;
}
@ -1617,38 +1534,34 @@ 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) {
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) {
} else if (quant_max == 1 || quant_max == INT32_MAX) {
BOOL has_goto = (quant_max == INT32_MAX);
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,
len + 5 + add_zero_advance_check);
len + 5 * has_goto + add_zero_advance_check * 2);
if (add_zero_advance_check) {
/* avoid infinite loop by stoping the
recursion if no advance was made in the
atom (only works if the atom has no
side effect) */
s->byte_code.buf[last_atom_start + 1 + 4] = REOP_push_char_pos;
re_emit_goto(s, REOP_bne_char_pos, last_atom_start);
} else {
re_emit_goto(s, REOP_goto, last_atom_start);
re_emit_op(s, REOP_check_advance);
}
if (has_goto)
re_emit_goto(s, REOP_goto, last_atom_start);
} else {
if (dbuf_insert(&s->byte_code, last_atom_start, 10))
if (dbuf_insert(&s->byte_code, last_atom_start, 10 + add_zero_advance_check))
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);
pos += 4;
s->byte_code.buf[pos++] = REOP_split_goto_first + greedy;
put_u32(s->byte_code.buf + pos, len + 5);
put_u32(s->byte_code.buf + pos, len + 5 + add_zero_advance_check * 2);
pos += 4;
if (add_zero_advance_check) {
s->byte_code.buf[pos++] = REOP_push_char_pos;
re_emit_op(s, REOP_check_advance);
}
re_emit_goto(s, REOP_loop, last_atom_start + 5);
re_emit_op(s, REOP_drop);
}
@ -1672,22 +1585,25 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
if (quant_max == INT32_MAX) {
pos = s->byte_code.size;
re_emit_op_u32(s, REOP_split_goto_first + greedy,
len + 5 + add_zero_advance_check);
len + 5 + add_zero_advance_check * 2);
if (add_zero_advance_check)
re_emit_op(s, REOP_push_char_pos);
/* copy the atom */
dbuf_put_self(&s->byte_code, last_atom_start, len);
if (add_zero_advance_check)
re_emit_goto(s, REOP_bne_char_pos, pos);
else
re_emit_goto(s, REOP_goto, pos);
re_emit_op(s, REOP_check_advance);
re_emit_goto(s, REOP_goto, pos);
} else if (quant_max > quant_min) {
re_emit_op_u32(s, REOP_push_i32, quant_max - quant_min);
pos = s->byte_code.size;
re_emit_op_u32(s, REOP_split_goto_first + greedy, len + 5);
re_emit_op_u32(s, REOP_split_goto_first + greedy,
len + 5 + add_zero_advance_check * 2);
if (add_zero_advance_check)
re_emit_op(s, REOP_push_char_pos);
/* copy the atom */
dbuf_put_self(&s->byte_code, last_atom_start, len);
if (add_zero_advance_check)
re_emit_op(s, REOP_check_advance);
re_emit_goto(s, REOP_loop, pos);
re_emit_op(s, REOP_drop);
}
@ -1801,7 +1717,7 @@ static int compute_stack_size(const uint8_t *bc_buf, int bc_buf_len)
}
break;
case REOP_drop:
case REOP_bne_char_pos:
case REOP_check_advance:
assert(stack_size > 0);
stack_size--;
break;
@ -2297,11 +2213,9 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
case REOP_push_char_pos:
stack[stack_len++] = (uintptr_t)cptr;
break;
case REOP_bne_char_pos:
val = get_u32(pc);
pc += 4;
if (stack[--stack_len] != (uintptr_t)cptr)
pc += (int)val;
case REOP_check_advance:
if (stack[--stack_len] == (uintptr_t)cptr)
goto no_match;
break;
case REOP_word_boundary:
case REOP_not_word_boundary:

View File

@ -36,6 +36,7 @@
#define LRE_FLAG_DOTALL (1 << 3)
#define LRE_FLAG_UTF16 (1 << 4)
#define LRE_FLAG_STICKY (1 << 5)
#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */
#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */

View File

@ -3779,72 +3779,70 @@ static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = {
0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80,
};
static const uint8_t unicode_prop_Changes_When_Casefolded1_table[33] = {
0x40, 0xde, 0x80, 0xcf, 0x80, 0x97, 0x80, 0x44,
0x3c, 0x80, 0x59, 0x11, 0x80, 0x40, 0xe4, 0x3f,
0x3f, 0x87, 0x89, 0x11, 0x05, 0x02, 0x11, 0x80,
0xa9, 0x11, 0x80, 0x60, 0xdb, 0x07, 0x86, 0x8b,
0x84,
static const uint8_t unicode_prop_Changes_When_Casefolded1_table[29] = {
0x41, 0xef, 0x80, 0x41, 0x9e, 0x80, 0x9e, 0x80,
0x5a, 0xe4, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00,
0x80, 0xde, 0x06, 0x06, 0x80, 0x8a, 0x09, 0x81,
0x89, 0x10, 0x81, 0x8d, 0x80,
};
static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[451] = {
static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[447] = {
0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12,
0x10, 0x82, 0x9f, 0x80, 0xcf, 0x01, 0x80, 0x8b,
0x07, 0x80, 0xfb, 0x01, 0x01, 0x80, 0xa5, 0x80,
0x40, 0xbb, 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08,
0x81, 0x89, 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08,
0x80, 0xc9, 0x82, 0x9c, 0x80, 0x41, 0x93, 0x80,
0x40, 0x93, 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87,
0xfb, 0x08, 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11,
0x80, 0x40, 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe,
0x80, 0xa7, 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88,
0x03, 0x03, 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00,
0x26, 0x80, 0x90, 0x80, 0x88, 0x03, 0x03, 0x03,
0x80, 0x8b, 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81,
0x46, 0x52, 0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10,
0x8a, 0x80, 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1,
0xa4, 0x40, 0xd9, 0x80, 0x40, 0xd5, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x3f, 0x87,
0x89, 0x11, 0x04, 0x00, 0x29, 0x04, 0x12, 0x80,
0x88, 0x12, 0x80, 0x88, 0x11, 0x11, 0x04, 0x08,
0x8f, 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b,
0x00, 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a,
0x80, 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a,
0x01, 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06,
0x05, 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80,
0x40, 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41,
0x34, 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6,
0x82, 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0,
0x80, 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40,
0xd5, 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09,
0x80, 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf,
0x9e, 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f,
0x60, 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40,
0x80, 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80,
0x60, 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81,
0x89, 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9,
0xa5, 0x86, 0x8b, 0x24, 0x00, 0x97, 0x04, 0x00,
0x01, 0x01, 0x80, 0xeb, 0xa0, 0x41, 0x6a, 0x91,
0xbf, 0x81, 0xb5, 0xa7, 0x8c, 0x82, 0x99, 0x95,
0x94, 0x81, 0x8b, 0x80, 0x92, 0x03, 0x1a, 0x00,
0x80, 0x40, 0x86, 0x08, 0x80, 0x9f, 0x99, 0x40,
0x83, 0x15, 0x0d, 0x0d, 0x0a, 0x16, 0x06, 0x80,
0x88, 0x47, 0x87, 0x20, 0xa9, 0x80, 0x88, 0x60,
0xb4, 0xe4, 0x83, 0x54, 0xb9, 0x86, 0x8d, 0x87,
0xbf, 0x85, 0x42, 0x3e, 0xd4, 0x80, 0xc6, 0x01,
0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80,
0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04,
0x00, 0x16, 0x80, 0x41, 0x53, 0x81, 0x41, 0x23,
0x81, 0xb1, 0x48, 0x2f, 0xbd, 0x4d, 0x91, 0x18,
0x9a, 0x01, 0x00, 0x08, 0x80, 0x89, 0x03, 0x00,
0x00, 0x28, 0x18, 0x00, 0x00, 0x02, 0x01, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b,
0x06, 0x03, 0x03, 0x00, 0x80, 0x89, 0x80, 0x90,
0x22, 0x04, 0x80, 0x90, 0x42, 0x43, 0x8a, 0x84,
0x9e, 0x80, 0x9f, 0x99, 0x82, 0xa2, 0x80, 0xee,
0x82, 0x8c, 0xab, 0x83, 0x88, 0x31, 0x49, 0x9d,
0x89, 0x60, 0xfc, 0x05, 0x42, 0x1d, 0x6b, 0x05,
0xe1, 0x4f, 0xff,
0x10, 0x82, 0xf3, 0x80, 0x8b, 0x80, 0x40, 0x84,
0x01, 0x01, 0x80, 0xa2, 0x01, 0x80, 0x40, 0xbb,
0x88, 0x9e, 0x29, 0x84, 0xda, 0x08, 0x81, 0x89,
0x80, 0xa3, 0x04, 0x02, 0x04, 0x08, 0x07, 0x80,
0x9e, 0x80, 0xa0, 0x82, 0x9c, 0x80, 0x42, 0x28,
0x80, 0xd7, 0x83, 0x42, 0xde, 0x87, 0xfb, 0x08,
0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11, 0x80, 0x40,
0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe, 0x80, 0xa7,
0x81, 0xad, 0x80, 0xb5, 0x80, 0x88, 0x03, 0x03,
0x03, 0x80, 0x8b, 0x80, 0x88, 0x00, 0x26, 0x80,
0x90, 0x80, 0x88, 0x03, 0x03, 0x03, 0x80, 0x8b,
0x80, 0x41, 0x41, 0x80, 0xe1, 0x81, 0x46, 0x52,
0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10, 0x8a, 0x80,
0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1, 0xa4, 0x40,
0xd5, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, 0x80,
0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xb7, 0x05, 0x00, 0x13, 0x05, 0x11, 0x02, 0x0c,
0x11, 0x00, 0x00, 0x0c, 0x15, 0x05, 0x08, 0x8f,
0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b, 0x00,
0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a, 0x80,
0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a, 0x01,
0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06, 0x05,
0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80, 0x40,
0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41, 0x34,
0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6, 0x82,
0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0, 0x80,
0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40, 0xd5,
0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09, 0x80,
0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf, 0x9e,
0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f, 0x60,
0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x80,
0x12, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60,
0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89,
0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xc2,
0x00, 0x97, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb,
0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7,
0x8c, 0x82, 0x99, 0x95, 0x94, 0x81, 0x8b, 0x80,
0x92, 0x03, 0x1a, 0x00, 0x80, 0x40, 0x86, 0x08,
0x80, 0x9f, 0x99, 0x40, 0x83, 0x15, 0x0d, 0x0d,
0x0a, 0x16, 0x06, 0x80, 0x88, 0x47, 0x87, 0x20,
0xa9, 0x80, 0x88, 0x60, 0xb4, 0xe4, 0x83, 0x54,
0xb9, 0x86, 0x8d, 0x87, 0xbf, 0x85, 0x42, 0x3e,
0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80,
0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06,
0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, 0x41,
0x53, 0x81, 0x41, 0x23, 0x81, 0xb1, 0x48, 0x2f,
0xbd, 0x4d, 0x91, 0x18, 0x9a, 0x01, 0x00, 0x08,
0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00,
0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00,
0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90,
0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80, 0x9f, 0x99,
0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c, 0xab, 0x83,
0x88, 0x31, 0x49, 0x9d, 0x89, 0x60, 0xfc, 0x05,
0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f, 0xff,
};
static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = {

View File

@ -43,11 +43,111 @@ enum {
RUN_TYPE_UF_D1_EXT,
RUN_TYPE_U_EXT,
RUN_TYPE_LF_EXT,
RUN_TYPE_U_EXT2,
RUN_TYPE_L_EXT2,
RUN_TYPE_U_EXT3,
RUN_TYPE_UF_EXT2,
RUN_TYPE_LF_EXT2,
RUN_TYPE_UF_EXT3,
};
static int lre_case_conv1(uint32_t c, int conv_type)
{
uint32_t res[LRE_CC_RES_LEN_MAX];
lre_case_conv(res, c, conv_type);
return res[0];
}
/* case conversion using the table entry 'idx' with value 'v' */
static int lre_case_conv_entry(uint32_t *res, uint32_t c, int conv_type, uint32_t idx, uint32_t v)
{
uint32_t code, data, type, a, is_lower;
is_lower = (conv_type != 0);
type = (v >> (32 - 17 - 7 - 4)) & 0xf;
data = ((v & 0xf) << 8) | case_conv_table2[idx];
code = v >> (32 - 17);
switch(type) {
case RUN_TYPE_U:
case RUN_TYPE_L:
case RUN_TYPE_UF:
case RUN_TYPE_LF:
if (conv_type == (type & 1) ||
(type >= RUN_TYPE_UF && conv_type == 2)) {
c = c - code + (case_conv_table1[data] >> (32 - 17));
}
break;
case RUN_TYPE_UL:
a = c - code;
if ((a & 1) != (1 - is_lower))
break;
c = (a ^ 1) + code;
break;
case RUN_TYPE_LSU:
a = c - code;
if (a == 1) {
c += 2 * is_lower - 1;
} else if (a == (1 - is_lower) * 2) {
c += (2 * is_lower - 1) * 2;
}
break;
case RUN_TYPE_U2L_399_EXT2:
if (!is_lower) {
res[0] = c - code + case_conv_ext[data >> 6];
res[1] = 0x399;
return 2;
} else {
c = c - code + case_conv_ext[data & 0x3f];
}
break;
case RUN_TYPE_UF_D20:
if (conv_type == 1)
break;
c = data + (conv_type == 2) * 0x20;
break;
case RUN_TYPE_UF_D1_EXT:
if (conv_type == 1)
break;
c = case_conv_ext[data] + (conv_type == 2);
break;
case RUN_TYPE_U_EXT:
case RUN_TYPE_LF_EXT:
if (is_lower != (type - RUN_TYPE_U_EXT))
break;
c = case_conv_ext[data];
break;
case RUN_TYPE_LF_EXT2:
if (!is_lower)
break;
res[0] = c - code + case_conv_ext[data >> 6];
res[1] = case_conv_ext[data & 0x3f];
return 2;
case RUN_TYPE_UF_EXT2:
if (conv_type == 1)
break;
res[0] = c - code + case_conv_ext[data >> 6];
res[1] = case_conv_ext[data & 0x3f];
if (conv_type == 2) {
/* convert to lower */
res[0] = lre_case_conv1(res[0], 1);
res[1] = lre_case_conv1(res[1], 1);
}
return 2;
default:
case RUN_TYPE_UF_EXT3:
if (conv_type == 1)
break;
res[0] = case_conv_ext[data >> 8];
res[1] = case_conv_ext[(data >> 4) & 0xf];
res[2] = case_conv_ext[data & 0xf];
if (conv_type == 2) {
/* convert to lower */
res[0] = lre_case_conv1(res[0], 1);
res[1] = lre_case_conv1(res[1], 1);
res[2] = lre_case_conv1(res[2], 1);
}
return 3;
}
res[0] = c;
return 1;
}
/* conv_type:
0 = to upper
1 = to lower
@ -66,10 +166,9 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
}
}
} else {
uint32_t v, code, data, type, len, a, is_lower;
uint32_t v, code, len;
int idx, idx_min, idx_max;
is_lower = (conv_type != 0);
idx_min = 0;
idx_max = countof(case_conv_table1) - 1;
while (idx_min <= idx_max) {
@ -82,74 +181,7 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
} else if (c >= code + len) {
idx_min = idx + 1;
} else {
type = (v >> (32 - 17 - 7 - 4)) & 0xf;
data = ((v & 0xf) << 8) | case_conv_table2[idx];
switch(type) {
case RUN_TYPE_U:
case RUN_TYPE_L:
case RUN_TYPE_UF:
case RUN_TYPE_LF:
if (conv_type == (type & 1) ||
(type >= RUN_TYPE_UF && conv_type == 2)) {
c = c - code + (case_conv_table1[data] >> (32 - 17));
}
break;
case RUN_TYPE_UL:
a = c - code;
if ((a & 1) != (1 - is_lower))
break;
c = (a ^ 1) + code;
break;
case RUN_TYPE_LSU:
a = c - code;
if (a == 1) {
c += 2 * is_lower - 1;
} else if (a == (1 - is_lower) * 2) {
c += (2 * is_lower - 1) * 2;
}
break;
case RUN_TYPE_U2L_399_EXT2:
if (!is_lower) {
res[0] = c - code + case_conv_ext[data >> 6];
res[1] = 0x399;
return 2;
} else {
c = c - code + case_conv_ext[data & 0x3f];
}
break;
case RUN_TYPE_UF_D20:
if (conv_type == 1)
break;
c = data + (conv_type == 2) * 0x20;
break;
case RUN_TYPE_UF_D1_EXT:
if (conv_type == 1)
break;
c = case_conv_ext[data] + (conv_type == 2);
break;
case RUN_TYPE_U_EXT:
case RUN_TYPE_LF_EXT:
if (is_lower != (type - RUN_TYPE_U_EXT))
break;
c = case_conv_ext[data];
break;
case RUN_TYPE_U_EXT2:
case RUN_TYPE_L_EXT2:
if (conv_type != (type - RUN_TYPE_U_EXT2))
break;
res[0] = c - code + case_conv_ext[data >> 6];
res[1] = case_conv_ext[data & 0x3f];
return 2;
default:
case RUN_TYPE_U_EXT3:
if (conv_type != 0)
break;
res[0] = case_conv_ext[data >> 8];
res[1] = case_conv_ext[(data >> 4) & 0xf];
res[2] = case_conv_ext[data & 0xf];
return 3;
}
break;
return lre_case_conv_entry(res, c, conv_type, idx, v);
}
}
}
@ -157,6 +189,77 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
return 1;
}
static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, BOOL is_unicode)
{
uint32_t res[LRE_CC_RES_LEN_MAX];
int len;
if (is_unicode) {
len = lre_case_conv_entry(res, c, 2, idx, v);
if (len == 1) {
c = res[0];
} else {
/* handle the few specific multi-character cases (see
unicode_gen.c:dump_case_folding_special_cases()) */
if (c == 0xfb06) {
c = 0xfb05;
} else if (c == 0x01fd3) {
c = 0x390;
} else if (c == 0x01fe3) {
c = 0x3b0;
}
}
} else {
if (likely(c < 128)) {
if (c >= 'a' && c <= 'z')
c = c - 'a' + 'A';
} else {
/* legacy regexp: to upper case if single char >= 128 */
len = lre_case_conv_entry(res, c, FALSE, idx, v);
if (len == 1 && res[0] >= 128)
c = res[0];
}
}
return c;
}
/* JS regexp specific rules for case folding */
int lre_canonicalize(uint32_t c, BOOL is_unicode)
{
if (c < 128) {
/* fast case */
if (is_unicode) {
if (c >= 'A' && c <= 'Z') {
c = c - 'A' + 'a';
}
} else {
if (c >= 'a' && c <= 'z') {
c = c - 'a' + 'A';
}
}
} else {
uint32_t v, code, len;
int idx, idx_min, idx_max;
idx_min = 0;
idx_max = countof(case_conv_table1) - 1;
while (idx_min <= idx_max) {
idx = (unsigned)(idx_max + idx_min) / 2;
v = case_conv_table1[idx];
code = v >> (32 - 17);
len = (v >> (32 - 17 - 7)) & 0x7f;
if (c < code) {
idx_max = idx - 1;
} else if (c >= code + len) {
idx_min = idx + 1;
} else {
return lre_case_folding_entry(c, idx, v, is_unicode);
}
}
}
return c;
}
static uint32_t get_le24(const uint8_t *ptr)
{
#if defined(__x86__) || defined(__x86_64__)
@ -1179,11 +1282,11 @@ static int unicode_case1(CharRange *cr, int case_mask)
#define MR(x) (1 << RUN_TYPE_ ## x)
const uint32_t tab_run_mask[3] = {
MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) |
MR(UF_D1_EXT) | MR(U_EXT) | MR(U_EXT2) | MR(U_EXT3),
MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(L_EXT2),
MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2),
MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT),
MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
};
#undef MR
uint32_t mask, v, code, type, len, i, idx;
@ -1236,7 +1339,136 @@ static int unicode_case1(CharRange *cr, int case_mask)
}
return 0;
}
static int point_cmp(const void *p1, const void *p2, void *arg)
{
uint32_t v1 = *(uint32_t *)p1;
uint32_t v2 = *(uint32_t *)p2;
return (v1 > v2) - (v1 < v2);
}
static void cr_sort_and_remove_overlap(CharRange *cr)
{
uint32_t start, end, start1, end1, i, j;
/* the resulting ranges are not necessarily sorted and may overlap */
rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL);
j = 0;
for(i = 0; i < cr->len; ) {
start = cr->points[i];
end = cr->points[i + 1];
i += 2;
while (i < cr->len) {
start1 = cr->points[i];
end1 = cr->points[i + 1];
if (start1 > end) {
/* |------|
* |-------| */
break;
} else if (end1 <= end) {
/* |------|
* |--| */
i += 2;
} else {
/* |------|
* |-------| */
end = end1;
i += 2;
}
}
cr->points[j] = start;
cr->points[j + 1] = end;
j += 2;
}
cr->len = j;
}
/* canonicalize a character set using the JS regex case folding rules
(see lre_canonicalize()) */
int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode)
{
CharRange cr_inter, cr_mask, cr_result, cr_sub;
uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d;
cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func);
cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func);
cr_init(&cr_result, cr->mem_opaque, cr->realloc_func);
cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func);
if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U))
goto fail;
if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
goto fail;
if (cr_invert(&cr_mask))
goto fail;
if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
goto fail;
/* cr_inter = cr & cr_mask */
/* cr_sub = cr & ~cr_mask */
/* use the case conversion table to compute the result */
d_start = -1;
d_end = -1;
idx = 0;
v = case_conv_table1[idx];
code = v >> (32 - 17);
len = (v >> (32 - 17 - 7)) & 0x7f;
for(i = 0; i < cr_inter.len; i += 2) {
start = cr_inter.points[i];
end = cr_inter.points[i + 1];
for(c = start; c < end; c++) {
for(;;) {
if (c >= code && c < code + len)
break;
idx++;
assert(idx < countof(case_conv_table1));
v = case_conv_table1[idx];
code = v >> (32 - 17);
len = (v >> (32 - 17 - 7)) & 0x7f;
}
d = lre_case_folding_entry(c, idx, v, is_unicode);
/* try to merge with the current interval */
if (d_start == -1) {
d_start = d;
d_end = d + 1;
} else if (d_end == d) {
d_end++;
} else {
cr_add_interval(&cr_result, d_start, d_end);
d_start = d;
d_end = d + 1;
}
}
}
if (d_start != -1) {
if (cr_add_interval(&cr_result, d_start, d_end))
goto fail;
}
/* the resulting ranges are not necessarily sorted and may overlap */
cr_sort_and_remove_overlap(&cr_result);
/* or with the character not affected by the case folding */
cr->len = 0;
if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION))
goto fail;
cr_free(&cr_inter);
cr_free(&cr_mask);
cr_free(&cr_result);
cr_free(&cr_sub);
return 0;
fail:
cr_free(&cr_inter);
cr_free(&cr_mask);
cr_free(&cr_result);
cr_free(&cr_sub);
return -1;
}
typedef enum {
POP_GC,
POP_PROP,

View File

@ -41,6 +41,7 @@ typedef enum {
} UnicodeNormalizationEnum;
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
int lre_canonicalize(uint32_t c, BOOL is_unicode);
LRE_BOOL lre_is_cased(uint32_t c);
LRE_BOOL lre_is_case_ignorable(uint32_t c);
@ -101,6 +102,8 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
int cr_invert(CharRange *cr);
int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode);
#ifdef CONFIG_ALL_UNICODE
LRE_BOOL lre_is_id_start(uint32_t c);

3
deps/quickjs/list.h vendored
View File

@ -36,8 +36,7 @@ struct list_head {
#define LIST_HEAD_INIT(el) { &(el), &(el) }
/* return the pointer of type 'type *' containing 'el' as field 'member' */
#define list_entry(el, type, member) \
((type *)((uint8_t *)(el) - offsetof(type, member)))
#define list_entry(el, type, member) container_of(el, type, member)
static inline void init_list_head(struct list_head *head)
{

21
deps/quickjs/qjs.c vendored
View File

@ -140,19 +140,19 @@ static inline unsigned long long js_trace_malloc_ptr_offset(uint8_t *ptr,
}
/* default memory allocation functions with memory limitation */
static inline size_t js_trace_malloc_usable_size(void *ptr)
static size_t js_trace_malloc_usable_size(const void *ptr)
{
#if defined(__APPLE__)
return malloc_size(ptr);
#elif defined(_WIN32)
return _msize(ptr);
return _msize((void *)ptr);
#elif defined(EMSCRIPTEN)
return 0;
#elif defined(__linux__)
return malloc_usable_size(ptr);
return malloc_usable_size((void *)ptr);
#else
/* change this to `return 0;` if compilation fails */
return malloc_usable_size(ptr);
return malloc_usable_size((void *)ptr);
#endif
}
@ -264,18 +264,7 @@ static const JSMallocFunctions trace_mf = {
js_trace_malloc,
js_trace_free,
js_trace_realloc,
#if defined(__APPLE__)
malloc_size,
#elif defined(_WIN32)
(size_t (*)(const void *))_msize,
#elif defined(EMSCRIPTEN)
NULL,
#elif defined(__linux__)
(size_t (*)(const void *))malloc_usable_size,
#else
/* change this to `NULL,` if compilation fails */
malloc_usable_size,
#endif
js_trace_malloc_usable_size,
};
#define PROG_NAME "qjs"

5
deps/quickjs/qjsc.c vendored
View File

@ -330,6 +330,7 @@ static const char main_c_template1[] =
static const char main_c_template2[] =
" js_std_loop(ctx);\n"
" js_std_free_handlers(rt);\n"
" JS_FreeContext(ctx);\n"
" JS_FreeRuntime(rt);\n"
" return 0;\n"
@ -343,8 +344,8 @@ void help(void)
"usage: " PROG_NAME " [options] [files]\n"
"\n"
"options are:\n"
"-c only output bytecode in a C file\n"
"-e output main() and bytecode in a C file (default = executable output)\n"
"-c only output bytecode to a C file\n"
"-e output main() and bytecode to a C file (default = executable output)\n"
"-o output set the output filename\n"
"-N cname set the C name of the generated data\n"
"-m compile as Javascript module (default=autodetect)\n"

View File

@ -82,6 +82,7 @@ DEF(length, "length")
DEF(fileName, "fileName")
DEF(lineNumber, "lineNumber")
DEF(message, "message")
DEF(cause, "cause")
DEF(errors, "errors")
DEF(stack, "stack")
DEF(name, "name")
@ -166,6 +167,7 @@ DEF(revoke, "revoke")
DEF(async, "async")
DEF(exec, "exec")
DEF(groups, "groups")
DEF(indices, "indices")
DEF(status, "status")
DEF(reason, "reason")
DEF(globalThis, "globalThis")
@ -177,11 +179,11 @@ DEF(roundingMode, "roundingMode")
DEF(maximumSignificantDigits, "maximumSignificantDigits")
DEF(maximumFractionDigits, "maximumFractionDigits")
#endif
#ifdef CONFIG_ATOMICS
/* the following 3 atoms are only used with CONFIG_ATOMICS */
DEF(not_equal, "not-equal")
DEF(timed_out, "timed-out")
DEF(ok, "ok")
#endif
/* */
DEF(toJSON, "toJSON")
/* class names */
DEF(Object, "Object")

View File

@ -751,6 +751,7 @@ static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
JSValue ret;
JSValueConst options_obj;
BOOL backtrace_barrier = FALSE;
BOOL is_async = FALSE;
int flags;
if (argc >= 2) {
@ -758,6 +759,9 @@ static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
if (get_bool_option(ctx, &backtrace_barrier, options_obj,
"backtrace_barrier"))
return JS_EXCEPTION;
if (get_bool_option(ctx, &is_async, options_obj,
"async"))
return JS_EXCEPTION;
}
str = JS_ToCStringLen(ctx, &len, argv[0]);
@ -770,6 +774,8 @@ static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
flags = JS_EVAL_TYPE_GLOBAL;
if (backtrace_barrier)
flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER;
if (is_async)
flags |= JS_EVAL_FLAG_ASYNC;
ret = JS_Eval(ctx, str, len, "<evalScript>", flags);
JS_FreeCString(ctx, str);
if (!ts->recv_pipe && --ts->eval_script_recurse == 0) {
@ -1970,6 +1976,13 @@ static int64_t get_time_ms(void)
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000);
}
static int64_t get_time_ns(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
}
#else
/* more portable, but does not work if the date is updated */
static int64_t get_time_ms(void)
@ -1978,8 +1991,21 @@ static int64_t get_time_ms(void)
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
}
static int64_t get_time_ns(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_sec * 1000000000 + (tv.tv_usec * 1000);
}
#endif
static JSValue js_os_now(JSContext *ctx, JSValue this_val,
int argc, JSValue *argv)
{
return JS_NewFloat64(ctx, (double)get_time_ns() / 1e6);
}
static void unlink_timer(JSRuntime *rt, JSOSTimer *th)
{
if (th->link.prev) {
@ -2062,6 +2088,38 @@ static JSClassDef js_os_timer_class = {
.gc_mark = js_os_timer_mark,
};
/* return a promise */
static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSRuntime *rt = JS_GetRuntime(ctx);
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
int64_t delay;
JSOSTimer *th;
JSValue promise, resolving_funcs[2];
if (JS_ToInt64(ctx, &delay, argv[0]))
return JS_EXCEPTION;
promise = JS_NewPromiseCapability(ctx, resolving_funcs);
if (JS_IsException(promise))
return JS_EXCEPTION;
th = js_mallocz(ctx, sizeof(*th));
if (!th) {
JS_FreeValue(ctx, promise);
JS_FreeValue(ctx, resolving_funcs[0]);
JS_FreeValue(ctx, resolving_funcs[1]);
return JS_EXCEPTION;
}
th->has_object = FALSE;
th->timeout = get_time_ms() + delay;
th->func = JS_DupValue(ctx, resolving_funcs[0]);
list_add_tail(&th->link, &ts->os_timers);
JS_FreeValue(ctx, resolving_funcs[0]);
JS_FreeValue(ctx, resolving_funcs[1]);
return promise;
}
static void call_handler(JSContext *ctx, JSValueConst func)
{
JSValue ret, func1;
@ -3030,6 +3088,13 @@ static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
goto done;
}
/* getpid() -> pid */
static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
return JS_NewInt32(ctx, getpid());
}
/* waitpid(pid, block) -> [pid, status] */
static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@ -3274,6 +3339,7 @@ static void *worker_func(void *opaque)
JSRuntime *rt;
JSThreadState *ts;
JSContext *ctx;
JSValue promise;
rt = JS_NewRuntime();
if (rt == NULL) {
@ -3300,8 +3366,11 @@ static void *worker_func(void *opaque)
js_std_add_helpers(ctx, -1, NULL);
if (!JS_RunModule(ctx, args->basename, args->filename))
promise = JS_LoadModule(ctx, args->basename, args->filename);
if (JS_IsException(promise))
js_std_dump_error(ctx);
/* XXX: check */
JS_FreeValue(ctx, promise);
free(args->filename);
free(args->basename);
free(args);
@ -3621,8 +3690,10 @@ static const JSCFunctionListEntry js_os_funcs[] = {
OS_FLAG(SIGTTIN),
OS_FLAG(SIGTTOU),
#endif
JS_CFUNC_DEF("now", 0, js_os_now ),
JS_CFUNC_DEF("setTimeout", 2, js_os_setTimeout ),
JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ),
JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ),
JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
@ -3650,6 +3721,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
JS_CFUNC_DEF("symlink", 2, js_os_symlink ),
JS_CFUNC_DEF("readlink", 1, js_os_readlink ),
JS_CFUNC_DEF("exec", 1, js_os_exec ),
JS_CFUNC_DEF("getpid", 0, js_os_getpid ),
JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ),
OS_FLAG(WNOHANG),
JS_CFUNC_DEF("pipe", 0, js_os_pipe ),

View File

@ -172,6 +172,7 @@ DEF(set_loc_uninitialized, 3, 0, 0, loc)
DEF( get_loc_check, 3, 0, 1, loc)
DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */
DEF( put_loc_check_init, 3, 1, 0, loc)
DEF(get_loc_checkthis, 3, 0, 1, loc)
DEF(get_var_ref_check, 3, 0, 1, var_ref)
DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */
DEF(put_var_ref_check_init, 3, 1, 0, var_ref)
@ -182,6 +183,7 @@ DEF( goto, 5, 0, 0, label) /* must come after if_true */
DEF( catch, 5, 0, 1, label)
DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
DEF( to_object, 1, 1, 1, none)
//DEF( to_string, 1, 1, 1, none)
@ -208,7 +210,6 @@ DEF( for_of_next, 2, 3, 5, u8)
DEF(iterator_check_object, 1, 1, 1, none)
DEF(iterator_get_value_done, 1, 1, 2, none)
DEF( iterator_close, 1, 3, 0, none)
DEF(iterator_close_return, 1, 4, 4, none)
DEF( iterator_next, 1, 4, 4, none)
DEF( iterator_call, 2, 4, 5, u8)
DEF( initial_yield, 1, 0, 0, none)
@ -256,6 +257,7 @@ DEF( and, 1, 2, 1, none)
DEF( xor, 1, 2, 1, none)
DEF( or, 1, 2, 1, none)
DEF(is_undefined_or_null, 1, 1, 1, none)
DEF( private_in, 1, 2, 1, none)
#ifdef CONFIG_BIGNUM
DEF( mul_pow10, 1, 2, 1, none)
DEF( math_mod, 1, 2, 1, none)
@ -270,6 +272,8 @@ def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */
/* the following opcodes must be in the same order as the 'with_x' and
get_var_undef, get_var and put_var opcodes */
def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */
@ -277,10 +281,13 @@ def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase
def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
def(scope_get_var_checkthis, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */
def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */
def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */

3578
deps/quickjs/quickjs.c vendored

File diff suppressed because it is too large Load Diff

View File

@ -307,6 +307,9 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5)
/* don't include the stack frames before this eval in the Error() backtraces */
#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)
/* allow top-level await in normal script. JS_Eval() returns a
promise. Only allowed with JS_EVAL_TYPE_GLOBAL */
#define JS_EVAL_FLAG_ASYNC (1 << 7)
typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
@ -831,7 +834,15 @@ typedef struct {
void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
const JSSharedArrayBufferFunctions *sf);
typedef enum JSPromiseStateEnum {
JS_PROMISE_PENDING,
JS_PROMISE_FULFILLED,
JS_PROMISE_REJECTED,
} JSPromiseStateEnum;
JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise);
JSValue JS_PromiseResult(JSContext *ctx, JSValue promise);
/* is_handled = TRUE means that the rejection is handled */
typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise,
@ -902,8 +913,8 @@ int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
/* only exported for os.Worker() */
JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
/* only exported for os.Worker() */
JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
const char *filename);
JSValue JS_LoadModule(JSContext *ctx, const char *basename,
const char *filename);
/* C function definition */
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */

View File

@ -8,12 +8,12 @@ version=`cat VERSION`
if [ "$1" = "-h" ] ; then
echo "release.sh [release_list]"
echo ""
echo "release_list: extras binary win_binary quickjs"
echo "release_list: extras binary win_binary cosmo_binary quickjs"
exit 1
fi
release_list="extras binary win_binary quickjs"
release_list="extras binary win_binary cosmo_binary quickjs"
if [ "$1" != "" ] ; then
release_list="$1"
@ -84,6 +84,28 @@ cp $dlldir/libwinpthread-1.dll $outdir
fi
#################################################"
# Cosmopolitan binary release
if echo $release_list | grep -w -q cosmo_binary ; then
export PATH=$PATH:$HOME/cosmocc/bin
d="quickjs-cosmo-${version}"
outdir="/tmp/${d}"
rm -rf $outdir
mkdir -p $outdir
make clean
make CONFIG_COSMO=y -j4 qjs run-test262
cp qjs run-test262 $outdir
cp readme-cosmo.txt $outdir/readme.txt
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
fi
#################################################"
# Linux binary release

116
deps/quickjs/repl.js vendored
View File

@ -118,6 +118,7 @@ import * as os from "os";
var utf8 = true;
var show_time = false;
var show_colors = true;
var eval_start_time;
var eval_time = 0;
var mexpr = "";
@ -814,10 +815,8 @@ import * as os from "os";
prompt += ps2;
} else {
if (show_time) {
var t = Math.round(eval_time) + " ";
eval_time = 0;
t = dupstr("0", 5 - t.length) + t;
prompt += t.substring(0, t.length - 4) + "." + t.substring(t.length - 4);
var t = eval_time / 1000;
prompt += t.toFixed(6) + " ";
}
plen = prompt.length;
prompt += ps1;
@ -1224,37 +1223,6 @@ import * as os from "os";
}
}
function eval_and_print(expr) {
var result;
try {
if (eval_mode === "math")
expr = '"use math"; void 0;' + expr;
var now = (new Date).getTime();
/* eval as a script */
result = std.evalScript(expr, { backtrace_barrier: true });
eval_time = (new Date).getTime() - now;
std.puts(colors[styles.result]);
print(result);
std.puts("\n");
std.puts(colors.none);
/* set the last result */
g._ = result;
} catch (error) {
std.puts(colors[styles.error_msg]);
if (error instanceof Error) {
console.log(error);
if (error.stack) {
std.puts(error.stack);
}
} else {
std.puts("Throw: ");
console.log(error);
}
std.puts(colors.none);
}
}
function cmd_start() {
if (!config_numcalc) {
if (has_jscalc)
@ -1281,29 +1249,32 @@ import * as os from "os";
}
function readline_handle_cmd(expr) {
handle_cmd(expr);
cmd_readline_start();
if (!handle_cmd(expr)) {
cmd_readline_start();
}
}
/* return true if async termination */
function handle_cmd(expr) {
var colorstate, cmd;
if (expr === null) {
expr = "";
return;
return false;
}
if (expr === "?") {
help();
return;
return false;
}
cmd = extract_directive(expr);
if (cmd.length > 0) {
if (!handle_directive(cmd, expr))
return;
if (!handle_directive(cmd, expr)) {
return false;
}
expr = expr.substring(cmd.length + 1);
}
if (expr === "")
return;
return false;
if (mexpr)
expr = mexpr + '\n' + expr;
@ -1312,20 +1283,73 @@ import * as os from "os";
level = colorstate[1];
if (pstate) {
mexpr = expr;
return;
return false;
}
mexpr = "";
if (has_bignum) {
BigFloatEnv.setPrec(eval_and_print.bind(null, expr),
/* XXX: async is not supported in this case */
BigFloatEnv.setPrec(eval_and_print_start.bind(null, expr, false),
prec, expBits);
} else {
eval_and_print(expr);
eval_and_print_start(expr, true);
}
level = 0;
return true;
}
function eval_and_print_start(expr, is_async) {
var result;
try {
if (eval_mode === "math")
expr = '"use math"; void 0;' + expr;
eval_start_time = os.now();
/* eval as a script */
result = std.evalScript(expr, { backtrace_barrier: true, async: is_async });
if (is_async) {
/* result is a promise */
result.then(print_eval_result, print_eval_error);
} else {
print_eval_result(result);
}
} catch (error) {
print_eval_error(error);
}
}
function print_eval_result(result) {
eval_time = os.now() - eval_start_time;
std.puts(colors[styles.result]);
print(result);
std.puts("\n");
std.puts(colors.none);
/* set the last result */
g._ = result;
handle_cmd_end();
}
function print_eval_error(error) {
std.puts(colors[styles.error_msg]);
if (error instanceof Error) {
console.log(error);
if (error.stack) {
std.puts(error.stack);
}
} else {
std.puts("Throw: ");
console.log(error);
}
std.puts(colors.none);
handle_cmd_end();
}
function handle_cmd_end() {
level = 0;
/* run the garbage collector after each command */
std.gc();
cmd_readline_start();
}
function colorize_js(str) {

View File

@ -1174,7 +1174,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
{
JSValue res_val, exception_val;
int ret, error_line, pos, pos_line;
BOOL is_error, has_error_line;
BOOL is_error, has_error_line, ret_promise;
const char *error_name;
pos = skip_comments(buf, 1, &pos_line);
@ -1183,12 +1183,19 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
exception_val = JS_UNDEFINED;
error_name = NULL;
/* a module evaluation returns a promise */
ret_promise = ((eval_flags & JS_EVAL_TYPE_MODULE) != 0);
async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */
res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
if (is_async && !JS_IsException(res_val)) {
JS_FreeValue(ctx, res_val);
if ((is_async || ret_promise) && !JS_IsException(res_val)) {
JSValue promise = JS_UNDEFINED;
if (ret_promise) {
promise = res_val;
} else {
JS_FreeValue(ctx, res_val);
}
for(;;) {
JSContext *ctx1;
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
@ -1196,15 +1203,27 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
res_val = JS_EXCEPTION;
break;
} else if (ret == 0) {
/* test if the test called $DONE() once */
if (async_done != 1) {
res_val = JS_ThrowTypeError(ctx, "$DONE() not called");
if (is_async) {
/* test if the test called $DONE() once */
if (async_done != 1) {
res_val = JS_ThrowTypeError(ctx, "$DONE() not called");
} else {
res_val = JS_UNDEFINED;
}
} else {
res_val = JS_UNDEFINED;
/* check that the returned promise is fulfilled */
JSPromiseStateEnum state = JS_PromiseState(ctx, promise);
if (state == JS_PROMISE_FULFILLED)
res_val = JS_UNDEFINED;
else if (state == JS_PROMISE_REJECTED)
res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise));
else
res_val = JS_ThrowTypeError(ctx, "promise is pending");
}
break;
}
}
JS_FreeValue(ctx, promise);
}
if (JS_IsException(res_val)) {
@ -1498,7 +1517,7 @@ void update_stats(JSRuntime *rt, const char *filename) {
#undef update
}
int run_test_buf(const char *filename, char *harness, namelist_t *ip,
int run_test_buf(const char *filename, const char *harness, namelist_t *ip,
char *buf, size_t buf_len, const char* error_type,
int eval_flags, BOOL is_negative, BOOL is_async,
BOOL can_block)
@ -1582,6 +1601,8 @@ int run_test(const char *filename, int index)
if (p) {
snprintf(harnessbuf, sizeof(harnessbuf), "%.*s%s",
(int)(p - filename), filename, "harness");
} else {
pstrcpy(harnessbuf, sizeof(harnessbuf), "");
}
harness = harnessbuf;
}
@ -1669,6 +1690,8 @@ int run_test(const char *filename, int index)
if (p) {
snprintf(harnessbuf, sizeof(harnessbuf), "%.*s%s",
(int)(p - filename), filename, "test/harness");
} else {
pstrcpy(harnessbuf, sizeof(harnessbuf), "");
}
harness = harnessbuf;
}
@ -1835,17 +1858,32 @@ int run_test262_harness_test(const char *filename, BOOL is_module)
js_std_dump_error(ctx);
ret_code = 1;
} else {
JS_FreeValue(ctx, res_val);
JSValue promise = JS_UNDEFINED;
if (is_module) {
promise = res_val;
} else {
JS_FreeValue(ctx, res_val);
}
for(;;) {
JSContext *ctx1;
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
if (ret < 0) {
js_std_dump_error(ctx1);
ret_code = 1;
js_std_dump_error(ctx1);
ret_code = 1;
} else if (ret == 0) {
break;
break;
}
}
/* dump the error if the module returned an error. */
if (is_module) {
JSPromiseStateEnum state = JS_PromiseState(ctx, promise);
if (state == JS_PROMISE_REJECTED) {
JS_Throw(ctx, JS_PromiseResult(ctx, promise));
js_std_dump_error(ctx);
ret_code = 1;
}
}
JS_FreeValue(ctx, promise);
}
free(buf);
#ifdef CONFIG_AGENT

View File

@ -56,7 +56,7 @@ AggregateError
align-detached-buffer-semantics-with-web-reality
arbitrary-module-namespace-names=skip
array-find-from-last
array-grouping=skip
array-grouping
Array.fromAsync=skip
Array.prototype.at
Array.prototype.flat
@ -73,13 +73,13 @@ Atomics
Atomics.waitAsync=skip
BigInt
caller
change-array-by-copy=skip
change-array-by-copy
class
class-fields-private
class-fields-private-in=skip
class-fields-private-in
class-fields-public
class-methods-private
class-static-block=skip
class-static-block
class-static-fields-private
class-static-fields-public
class-static-methods-private
@ -102,7 +102,7 @@ default-parameters
destructuring-assignment
destructuring-binding
dynamic-import
error-cause=skip
error-cause
exponentiation
export-star-as-namespace-from-module
FinalizationGroup=skip
@ -141,7 +141,7 @@ Object.is
optional-catch-binding
optional-chaining
Promise
promise-with-resolvers=skip
promise-with-resolvers
Promise.allSettled
Promise.any
Promise.prototype.finally
@ -154,7 +154,7 @@ Reflect.setPrototypeOf
regexp-dotall
regexp-duplicate-named-groups=skip
regexp-lookbehind
regexp-match-indices=skip
regexp-match-indices
regexp-named-groups
regexp-unicode-property-escapes
regexp-v-flag=skip
@ -169,10 +169,10 @@ String.fromCodePoint
String.prototype.at
String.prototype.endsWith
String.prototype.includes
String.prototype.isWellFormed=skip
String.prototype.isWellFormed
String.prototype.matchAll
String.prototype.replaceAll
String.prototype.toWellFormed=skip
String.prototype.toWellFormed
String.prototype.trimEnd
String.prototype.trimStart
super
@ -195,7 +195,7 @@ symbols-as-weakmap-keys=skip
tail-call-optimization=skip
template
Temporal=skip
top-level-await=skip
top-level-await
TypedArray
TypedArray.prototype.at
u180e

View File

@ -1,41 +1,8 @@
test262/test/annexB/language/eval-code/direct/script-decl-lex-collision-in-sloppy-mode.js:13: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/built-ins/AsyncGeneratorPrototype/return/return-state-completed-broken-promise.js:53: TypeError: $DONE() not called
test262/test/built-ins/AsyncGeneratorPrototype/return/return-state-completed-broken-promise.js:53: strict mode: TypeError: $DONE() not called
test262/test/built-ins/AsyncGeneratorPrototype/return/return-suspendedStart-broken-promise.js:34: TypeError: $DONE() not called
test262/test/built-ins/AsyncGeneratorPrototype/return/return-suspendedStart-broken-promise.js:34: strict mode: TypeError: $DONE() not called
test262/test/built-ins/AsyncGeneratorPrototype/return/return-suspendedYield-broken-promise-try-catch.js:39: TypeError: $DONE() not called
test262/test/built-ins/AsyncGeneratorPrototype/return/return-suspendedYield-broken-promise-try-catch.js:39: strict mode: TypeError: $DONE() not called
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: Test262Error: Expected a ReferenceError but got a different error constructor with the same name
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a different error constructor with the same name
test262/test/built-ins/RegExp/lookahead-quantifier-match-groups.js:27: Test262Error: Expected [a, abc] and [a, undefined] to have the same contents. ? quantifier
test262/test/built-ins/RegExp/lookahead-quantifier-match-groups.js:27: strict mode: Test262Error: Expected [a, abc] and [a, undefined] to have the same contents. ? quantifier
test262/test/built-ins/RegExp/unicode_full_case_folding.js:20: Test262Error: \u0390 does not match \u1fd3
test262/test/built-ins/RegExp/unicode_full_case_folding.js:20: strict mode: Test262Error: \u0390 does not match \u1fd3
test262/test/built-ins/String/prototype/localeCompare/15.5.4.9_CE.js:62: Test262Error: String.prototype.localeCompare considers ö (\u006f\u0308) ≠ ö (\u00f6).
test262/test/built-ins/String/prototype/localeCompare/15.5.4.9_CE.js:62: strict mode: Test262Error: String.prototype.localeCompare considers ö (\u006f\u0308) ≠ ö (\u00f6).
test262/test/built-ins/TypedArray/prototype/sort/sort-tonumber.js:30: TypeError: ArrayBuffer is detached (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/sort/sort-tonumber.js:30: strict mode: TypeError: ArrayBuffer is detached (Testing with Float64Array.)
test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: Test262Error: Expected a DummyError but got a TypeError
test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError
test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: Test262Error: Expected a DummyError but got a TypeError
test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
test262/test/language/expressions/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/expressions/in/private-field-invalid-assignment-target.js:23: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/expressions/in/private-field-invalid-assignment-target.js:23: strict mode: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/global-code/script-decl-lex-var-declared-via-eval-sloppy.js:13: Test262Error: variable Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/module-code/namespace/internals/define-own-property.js:30: Test262Error: Object.freeze: 1 Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/async-generator/yield-star-promise-not-unwrapped.js:25: TypeError: $DONE() not called
test262/test/language/statements/async-generator/yield-star-promise-not-unwrapped.js:25: strict mode: TypeError: $DONE() not called
test262/test/language/statements/async-generator/yield-star-return-then-getter-ticks.js:131: TypeError: $DONE() not called
test262/test/language/statements/async-generator/yield-star-return-then-getter-ticks.js:131: strict mode: TypeError: $DONE() not called
test262/test/language/statements/class/elements/private-method-double-initialisation-get-and-set.js:33: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation-get-and-set.js:33: strict mode: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation-get.js:32: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation-get.js:32: strict mode: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation-set.js:32: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation-set.js:32: strict mode: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation.js:32: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation.js:32: strict mode: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: strict mode: unexpected error type: Test262: This statement should not be evaluated.

View File

@ -23,6 +23,7 @@
* THE SOFTWARE.
*/
import * as std from "std";
import * as os from "os";
function pad(str, n) {
str += "";
@ -93,21 +94,12 @@ function log_line() {
console.log(s);
}
var clocks_per_sec = 1000000;
var max_iterations = 100;
var clock_threshold = 2000; /* favoring short measuring spans */
var clocks_per_sec = 1000;
var max_iterations = 10;
var clock_threshold = 100; /* favoring short measuring spans */
var min_n_argument = 1;
var get_clock;
if (typeof globalThis.__date_clock != "function") {
console.log("using fallback millisecond clock");
clocks_per_sec = 1000;
max_iterations = 10;
clock_threshold = 100;
get_clock = Date.now;
} else {
get_clock = globalThis.__date_clock;
}
//var get_clock = Date.now;
var get_clock = os.now;
function log_one(text, n, ti) {
var ref;

View File

@ -538,7 +538,17 @@ function test_regexp()
assert(/{1a}/.toString(), "/{1a}/");
a = /a{1+/.exec("a{11");
assert(a, ["a{11"] );
assert(a, ["a{11"]);
/* test zero length matches */
a = /(?:(?=(abc)))a/.exec("abc");
assert(a, ["a", "abc"]);
a = /(?:(?=(abc)))?a/.exec("abc");
assert(a, ["a", undefined]);
a = /(?:(?=(abc))){0,2}a/.exec("abc");
assert(a, ["a", undefined]);
a = /(?:|[\w])+([0-9])/.exec("123a23");
assert(a, ["123a23", "3"]);
}
function test_symbol()
@ -645,6 +655,18 @@ function test_generator()
assert(ret, "ret_val");
return 3;
}
function *f3() {
var ret;
/* test stack consistency with nip_n to handle yield return +
* finally clause */
try {
ret = 2 + (yield 1);
} catch(e) {
} finally {
ret++;
}
return ret;
}
var g, v;
g = f();
v = g.next();
@ -665,6 +687,12 @@ function test_generator()
assert(v.value === 3 && v.done === true);
v = g.next();
assert(v.value === undefined && v.done === true);
g = f3();
v = g.next();
assert(v.value === 1 && v.done === false);
v = g.next(3);
assert(v.value === 6 && v.done === true);
}
test();

View File

@ -120,6 +120,7 @@ function test_cvt()
assert((Infinity >>> 0) === 0);
assert(((-Infinity) >>> 0) === 0);
assert(((4294967296 * 3 - 4) >>> 0) === (4294967296 - 4));
assert((19686109595169230000).toString() === "19686109595169230000");
}
function test_eq()
@ -325,6 +326,15 @@ function test_class()
/* test class name scope */
var E1 = class E { static F() { return E; } };
assert(E1 === E1.F());
class S {
static x = 42;
static y = S.x;
static z = this.x;
}
assert(S.x === 42);
assert(S.y === 42);
assert(S.z === 42);
};
function test_template()
@ -526,6 +536,53 @@ function test_function_expr_name()
assert_throws(TypeError, f);
}
function test_parse_semicolon()
{
/* 'yield' or 'await' may not be considered as a token if the
previous ';' is missing */
function *f()
{
function func() {
}
yield 1;
var h = x => x + 1
yield 2;
}
async function g()
{
function func() {
}
await 1;
var h = x => x + 1
await 2;
}
}
/* optional chaining tests not present in test262 */
function test_optional_chaining()
{
var a, z;
z = null;
a = { b: { c: 2 } };
assert(delete z?.b.c, true);
assert(delete a?.b.c, true);
assert(JSON.stringify(a), '{"b":{}}', "optional chaining delete");
a = { b: { c: 2 } };
assert(delete z?.b["c"], true);
assert(delete a?.b["c"], true);
assert(JSON.stringify(a), '{"b":{}}');
a = {
b() { return this._b; },
_b: { c: 42 }
};
assert((a?.b)().c, 42);
assert((a?.["b"])().c, 42);
}
test_op1();
test_cvt();
test_eq();
@ -545,3 +602,5 @@ test_spread();
test_function_length();
test_argument_scope();
test_function_expr_name();
test_parse_semicolon();
test_optional_chaining();

View File

@ -167,6 +167,29 @@ function test_for_in2()
assert(tab.toString() == "x,y");
}
function test_for_in_proxy() {
let removed_key = "";
let target = {}
let proxy = new Proxy(target, {
ownKeys: function() {
return ["a", "b", "c"];
},
getOwnPropertyDescriptor: function(target, key) {
if (removed_key != "" && key == removed_key)
return undefined;
else
return { enumerable: true, configurable: true, value: this[key] };
}
});
let str = "";
for(let o in proxy) {
str += " " + o;
if (o == "a")
removed_key = "b";
}
assert(str == " a c");
}
function test_for_break()
{
var i, c;
@ -357,6 +380,7 @@ test_switch1();
test_switch2();
test_for_in();
test_for_in2();
test_for_in_proxy();
test_try_catch1();
test_try_catch2();

View File

@ -1,3 +1,4 @@
#! (shebang test)
import * as std from "std";
import * as os from "os";
@ -270,6 +271,26 @@ function test_timer()
os.clearTimeout(th[i]);
}
/* test closure variable handling when freeing asynchronous
function */
function test_async_gc()
{
(async function run () {
let obj = {}
let done = () => {
obj
std.gc();
}
Promise.resolve().then(done)
const p = new Promise(() => {})
await p
})();
}
test_printf();
test_file1();
test_file2();
@ -279,3 +300,5 @@ test_os();
test_os_exec();
test_timer();
test_ext_json();
test_async_gc();

View File

@ -10,6 +10,7 @@ function handle_msg(e) {
switch(ev.type) {
case "abort":
parent.postMessage({ type: "done" });
parent.onMessage = null; /* terminate the worker */
break;
case "sab":
/* modify the SharedArrayBuffer */

View File

@ -42,6 +42,7 @@
//#define DUMP_TABLE_SIZE
//#define DUMP_CC_TABLE
//#define DUMP_DECOMP_TABLE
//#define DUMP_CASE_FOLDING_SPECIAL_CASES
/* Ideas:
- Generalize run length encoding + index for all tables
@ -217,15 +218,16 @@ static const char *unicode_prop_short_name[] = {
#undef DEF
};
#undef UNICODE_SPROP_LIST
#undef UNICODE_PROP_LIST
typedef struct {
/* case conv */
uint8_t u_len;
uint8_t l_len;
int u_data[CC_LEN_MAX];
int l_data[CC_LEN_MAX];
int f_code;
uint8_t f_len;
int u_data[CC_LEN_MAX]; /* to upper case */
int l_data[CC_LEN_MAX]; /* to lower case */
int f_data[CC_LEN_MAX]; /* to case folding */
uint8_t combining_class;
uint8_t is_compat:1;
@ -499,7 +501,7 @@ void parse_case_folding(CCInfo *tab, const char *filename)
FILE *f;
char line[1024];
const char *p;
int code;
int code, status;
CCInfo *ci;
f = fopen(filename, "rb");
@ -530,14 +532,28 @@ void parse_case_folding(CCInfo *tab, const char *filename)
/* locale dependent casing */
while (isspace(*p))
p++;
if (*p != 'C' && *p != 'S')
status = *p;
if (status != 'C' && status != 'S' && status != 'F')
continue;
p = get_field(line, 2);
assert(p != 0);
assert(ci->f_code == 0);
ci->f_code = strtoul(p, NULL, 16);
assert(ci->f_code != 0 && ci->f_code != code);
assert(p != NULL);
if (status == 'S') {
/* we always select the simple case folding and assume it
* comes after the full case folding case */
assert(ci->f_len >= 2);
ci->f_len = 0;
} else {
assert(ci->f_len == 0);
}
for(;;) {
while (isspace(*p))
p++;
if (*p == ';')
break;
assert(ci->l_len < CC_LEN_MAX);
ci->f_data[ci->f_len++] = strtoul(p, (char **)&p, 16);
}
}
fclose(f);
@ -864,19 +880,21 @@ void dump_cc_info(CCInfo *ci, int i)
for(j = 0; j < ci->l_len; j++)
printf(" %05x", ci->l_data[j]);
}
if (ci->f_code != 0) {
printf(" F: %05x", ci->f_code);
if (ci->f_len != 0) {
printf(" F:");
for(j = 0; j < ci->f_len; j++)
printf(" %05x", ci->f_data[j]);
}
printf("\n");
}
void dump_data(CCInfo *tab)
void dump_unicode_data(CCInfo *tab)
{
int i;
CCInfo *ci;
for(i = 0; i <= CHARCODE_MAX; i++) {
ci = &tab[i];
if (ci->u_len != 0 || ci->l_len != 0 || ci->f_code != 0) {
if (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0) {
dump_cc_info(ci, i);
}
}
@ -886,8 +904,8 @@ BOOL is_complicated_case(const CCInfo *ci)
{
return (ci->u_len > 1 || ci->l_len > 1 ||
(ci->u_len > 0 && ci->l_len > 0) ||
(ci->f_code != 0) != ci->l_len ||
(ci->f_code != 0 && ci->l_data[0] != ci->f_code));
(ci->f_len != ci->l_len) ||
(memcmp(ci->f_data, ci->l_data, ci->f_len * sizeof(ci->f_data[0])) != 0));
}
#ifndef USE_TEST
@ -903,9 +921,9 @@ enum {
RUN_TYPE_UF_D1_EXT,
RUN_TYPE_U_EXT,
RUN_TYPE_LF_EXT,
RUN_TYPE_U_EXT2,
RUN_TYPE_L_EXT2,
RUN_TYPE_U_EXT3,
RUN_TYPE_UF_EXT2,
RUN_TYPE_LF_EXT2,
RUN_TYPE_UF_EXT3,
};
#endif
@ -921,9 +939,9 @@ const char *run_type_str[] = {
"UF_D1_EXT",
"U_EXT",
"LF_EXT",
"U_EXT2",
"L_EXT2",
"U_EXT3",
"UF_EXT2",
"LF_EXT2",
"UF_EXT3",
};
typedef struct {
@ -936,6 +954,13 @@ typedef struct {
int data_index; /* 'data' coming from the table */
} TableEntry;
static int simple_to_lower(CCInfo *tab, int c)
{
if (tab[c].l_len != 1)
return c;
return tab[c].l_data[0];
}
/* code (17), len (7), type (4) */
void find_run_type(TableEntry *te, CCInfo *tab, int code)
@ -949,15 +974,15 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code)
te->code = code;
if (ci->l_len == 1 && ci->l_data[0] == code + 2 &&
ci->f_code == ci->l_data[0] &&
ci->f_len == 1 && ci->f_data[0] == ci->l_data[0] &&
ci->u_len == 0 &&
ci1->l_len == 1 && ci1->l_data[0] == code + 2 &&
ci1->f_code == ci1->l_data[0] &&
ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0] &&
ci1->u_len == 1 && ci1->u_data[0] == code &&
ci2->l_len == 0 &&
ci2->f_code == 0 &&
ci2->f_len == 0 &&
ci2->u_len == 1 && ci2->u_data[0] == code) {
te->len = 3;
te->data = 0;
@ -972,7 +997,7 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code)
if (ci1->u_len != 1 ||
ci1->u_data[0] != ci->u_data[0] + len ||
ci1->l_len != 0 ||
ci1->f_code != ci1->u_data[0])
ci1->f_len != 1 || ci1->f_data[0] != ci1->u_data[0])
break;
len++;
}
@ -983,21 +1008,25 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code)
return;
}
if (ci->u_len == 2 && ci->u_data[1] == 0x399 &&
ci->f_code == 0 && ci->l_len == 0) {
if (ci->l_len == 0 &&
ci->u_len == 2 && ci->u_data[1] == 0x399 &&
ci->f_len == 2 && ci->f_data[1] == 0x3B9 &&
ci->f_data[0] == simple_to_lower(tab, ci->u_data[0])) {
len = 1;
while (code + len <= CHARCODE_MAX) {
ci1 = &tab[code + len];
if (!(ci1->u_len == 2 &&
ci1->u_data[1] == 0x399 &&
ci1->u_data[1] == ci->u_data[1] &&
ci1->u_data[0] == ci->u_data[0] + len &&
ci1->f_code == 0 &&
ci1->f_len == 2 &&
ci1->f_data[1] == ci->f_data[1] &&
ci1->f_data[0] == ci->f_data[0] + len &&
ci1->l_len == 0))
break;
len++;
}
te->len = len;
te->type = RUN_TYPE_U_EXT2;
te->type = RUN_TYPE_UF_EXT2;
te->ext_data[0] = ci->u_data[0];
te->ext_data[1] = ci->u_data[1];
te->ext_len = 2;
@ -1005,7 +1034,8 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code)
}
if (ci->u_len == 2 && ci->u_data[1] == 0x399 &&
ci->l_len == 1 && ci->f_code == ci->l_data[0]) {
ci->l_len == 1 &&
ci->f_len == 1 && ci->f_data[0] == ci->l_data[0]) {
len = 1;
while (code + len <= CHARCODE_MAX) {
ci1 = &tab[code + len];
@ -1014,7 +1044,7 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code)
ci1->u_data[0] == ci->u_data[0] + len &&
ci1->l_len == 1 &&
ci1->l_data[0] == ci->l_data[0] + len &&
ci1->f_code == ci1->l_data[0]))
ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0]))
break;
len++;
}
@ -1026,13 +1056,13 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code)
return;
}
if (ci->l_len == 1 && ci->u_len == 0 && ci->f_code == 0) {
if (ci->l_len == 1 && ci->u_len == 0 && ci->f_len == 0) {
len = 1;
while (code + len <= CHARCODE_MAX) {
ci1 = &tab[code + len];
if (!(ci1->l_len == 1 &&
ci1->l_data[0] == ci->l_data[0] + len &&
ci1->u_len == 0 && ci1->f_code == 0))
ci1->u_len == 0 && ci1->f_len == 0))
break;
len++;
}
@ -1045,32 +1075,39 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code)
if (ci->l_len == 0 &&
ci->u_len == 1 &&
ci->u_data[0] < 0x1000 &&
ci->f_code == ci->u_data[0] + 0x20) {
ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 0x20) {
te->len = 1;
te->type = RUN_TYPE_UF_D20;
te->data = ci->u_data[0];
} else if (ci->l_len == 0 &&
ci->u_len == 1 &&
ci->f_code == ci->u_data[0] + 1) {
ci->u_len == 1 &&
ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 1) {
te->len = 1;
te->type = RUN_TYPE_UF_D1_EXT;
te->ext_data[0] = ci->u_data[0];
te->ext_len = 1;
} else if (ci->l_len == 2 && ci->u_len == 0 && ci->f_code == 0) {
} else if (ci->l_len == 2 && ci->u_len == 0 && ci->f_len == 2 &&
ci->l_data[0] == ci->f_data[0] &&
ci->l_data[1] == ci->f_data[1]) {
te->len = 1;
te->type = RUN_TYPE_L_EXT2;
te->type = RUN_TYPE_LF_EXT2;
te->ext_data[0] = ci->l_data[0];
te->ext_data[1] = ci->l_data[1];
te->ext_len = 2;
} else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_code == 0) {
} else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_len == 2 &&
ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) &&
ci->f_data[1] == simple_to_lower(tab, ci->u_data[1])) {
te->len = 1;
te->type = RUN_TYPE_U_EXT2;
te->type = RUN_TYPE_UF_EXT2;
te->ext_data[0] = ci->u_data[0];
te->ext_data[1] = ci->u_data[1];
te->ext_len = 2;
} else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_code == 0) {
} else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_len == 3 &&
ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) &&
ci->f_data[1] == simple_to_lower(tab, ci->u_data[1]) &&
ci->f_data[2] == simple_to_lower(tab, ci->u_data[2])) {
te->len = 1;
te->type = RUN_TYPE_U_EXT3;
te->type = RUN_TYPE_UF_EXT3;
te->ext_data[0] = ci->u_data[0];
te->ext_data[1] = ci->u_data[1];
te->ext_data[2] = ci->u_data[2];
@ -1188,7 +1225,7 @@ void build_conv_table(CCInfo *tab)
te = conv_table;
for(code = 0; code <= CHARCODE_MAX; code++) {
ci = &tab[code];
if (ci->u_len == 0 && ci->l_len == 0 && ci->f_code == 0)
if (ci->u_len == 0 && ci->l_len == 0 && ci->f_len == 0)
continue;
assert(te - conv_table < countof(conv_table));
find_run_type(te, tab, code);
@ -1244,7 +1281,7 @@ void build_conv_table(CCInfo *tab)
/* find the data index for ext_data */
for(i = 0; i < conv_table_len; i++) {
te = &conv_table[i];
if (te->type == RUN_TYPE_U_EXT3) {
if (te->type == RUN_TYPE_UF_EXT3) {
int p, v;
v = 0;
for(j = 0; j < 3; j++) {
@ -1258,8 +1295,8 @@ void build_conv_table(CCInfo *tab)
for(i = 0; i < conv_table_len; i++) {
te = &conv_table[i];
if (te->type == RUN_TYPE_L_EXT2 ||
te->type == RUN_TYPE_U_EXT2 ||
if (te->type == RUN_TYPE_LF_EXT2 ||
te->type == RUN_TYPE_UF_EXT2 ||
te->type == RUN_TYPE_U2L_399_EXT2) {
int p, v;
v = 0;
@ -1322,6 +1359,54 @@ void dump_case_conv_table(FILE *f)
fprintf(f, "\n};\n\n");
}
static CCInfo *global_tab;
static int sp_cc_cmp(const void *p1, const void *p2)
{
CCInfo *c1 = &global_tab[*(const int *)p1];
CCInfo *c2 = &global_tab[*(const int *)p2];
if (c1->f_len < c2->f_len) {
return -1;
} else if (c2->f_len < c1->f_len) {
return 1;
} else {
return memcmp(c1->f_data, c2->f_data, sizeof(c1->f_data[0]) * c1->f_len);
}
}
/* dump the case special cases (multi character results which are
identical and need specific handling in lre_canonicalize() */
void dump_case_folding_special_cases(CCInfo *tab)
{
int i, len, j;
int *perm;
perm = malloc(sizeof(perm[0]) * (CHARCODE_MAX + 1));
for(i = 0; i <= CHARCODE_MAX; i++)
perm[i] = i;
global_tab = tab;
qsort(perm, CHARCODE_MAX + 1, sizeof(perm[0]), sp_cc_cmp);
for(i = 0; i <= CHARCODE_MAX;) {
if (tab[perm[i]].f_len <= 1) {
i++;
} else {
len = 1;
while ((i + len) <= CHARCODE_MAX && !sp_cc_cmp(&perm[i], &perm[i + len]))
len++;
if (len > 1) {
for(j = i; j < i + len; j++)
dump_cc_info(&tab[perm[j]], perm[j]);
}
i += len;
}
}
free(perm);
global_tab = NULL;
}
int tabcmp(const int *tab1, const int *tab2, int n)
{
int i;
@ -1348,7 +1433,7 @@ void compute_internal_props(void)
for(i = 0; i <= CHARCODE_MAX; i++) {
CCInfo *ci = &unicode_db[i];
has_ul = (ci->u_len != 0 || ci->l_len != 0 || ci->f_code != 0);
has_ul = (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0);
if (has_ul) {
assert(get_prop(i, PROP_Cased));
} else {
@ -1363,10 +1448,10 @@ void compute_internal_props(void)
set_prop(i, PROP_Changes_When_Titlecased1,
get_prop(i, PROP_Changes_When_Titlecased) ^ (ci->u_len != 0));
set_prop(i, PROP_Changes_When_Casefolded1,
get_prop(i, PROP_Changes_When_Casefolded) ^ (ci->f_code != 0));
get_prop(i, PROP_Changes_When_Casefolded) ^ (ci->f_len != 0));
/* XXX: reduce table size (438 bytes) */
set_prop(i, PROP_Changes_When_NFKC_Casefolded1,
get_prop(i, PROP_Changes_When_NFKC_Casefolded) ^ (ci->f_code != 0));
get_prop(i, PROP_Changes_When_NFKC_Casefolded) ^ (ci->f_len != 0));
#if 0
/* TEST */
#define M(x) (1U << GCAT_ ## x)
@ -1797,8 +1882,10 @@ void check_case_conv(void)
ci->u_len = 1;
ci->u_data[0] = code;
}
if (ci->f_code == 0)
ci->f_code = code;
if (ci->f_len == 0) {
ci->f_len = 1;
ci->f_data[0] = code;
}
error = 0;
l = check_conv(res, code, 0);
@ -1812,7 +1899,7 @@ void check_case_conv(void)
error++;
}
l = check_conv(res, code, 2);
if (l != 1 || res[0] != ci->f_code) {
if (l != ci->f_len || tabcmp((int *)res, ci->f_data, l)) {
printf("ERROR: F\n");
error++;
}
@ -3007,11 +3094,12 @@ int main(int argc, char **argv)
unicode_db_path);
parse_prop_list(filename);
// dump_data(unicode_db);
// dump_unicode_data(unicode_db);
build_conv_table(unicode_db);
// dump_table();
#ifdef DUMP_CASE_FOLDING_SPECIAL_CASES
dump_case_folding_special_cases(unicode_db);
#endif
if (!outfilename) {
#ifdef USE_TEST