Retire third_party/quickjs/

QuickJS cosmocc binaries are now being distributed on
https://bellard.org/quickjs/
This commit is contained in:
Justine Tunney 2024-01-17 12:32:49 -08:00
parent 08793aa143
commit 1ef63eb206
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
111 changed files with 0 additions and 98553 deletions

View file

@ -319,7 +319,6 @@ include third_party/argon2/BUILD.mk
include third_party/smallz4/BUILD.mk
include third_party/sqlite3/BUILD.mk
include third_party/mbedtls/test/BUILD.mk
include third_party/quickjs/BUILD.mk
include third_party/lz4cli/BUILD.mk
include third_party/zip/BUILD.mk
include third_party/xxhash/BUILD.mk

View file

@ -85,7 +85,6 @@ EXAMPLES_DIRECTDEPS = \
THIRD_PARTY_MUSL \
THIRD_PARTY_NSYNC \
THIRD_PARTY_NSYNC_MEM \
THIRD_PARTY_QUICKJS \
THIRD_PARTY_SED \
THIRD_PARTY_STB \
THIRD_PARTY_TR \

View file

@ -59,7 +59,6 @@
#include "third_party/mbedtls/sha256.h"
#include "third_party/mbedtls/sha512.h"
#include "third_party/mbedtls/x509.h"
#include "third_party/quickjs/libbf.h"
#include "third_party/zlib/zlib.h"
uint64_t rng[12];

View file

@ -31,7 +31,6 @@ o/$(MODE)/third_party: \
o/$(MODE)/third_party/pcre \
o/$(MODE)/third_party/puff \
o/$(MODE)/third_party/python \
o/$(MODE)/third_party/quickjs \
o/$(MODE)/third_party/readline \
o/$(MODE)/third_party/regex \
o/$(MODE)/third_party/sed \

View file

@ -30,7 +30,6 @@
#include "third_party/python/Include/structmember.h"
#include "third_party/python/Include/sysmodule.h"
#include "third_party/python/Include/yoink.h"
#include "third_party/quickjs/internal.h"
PYTHON_PROVIDE("_pickle");
PYTHON_PROVIDE("_pickle.PickleError");

View file

@ -11,7 +11,6 @@
#include "third_party/python/Include/objimpl.h"
#include "third_party/python/Include/structmember.h"
#include "third_party/python/Include/weakrefobject.h"
#include "third_party/quickjs/quickjs.h"
#define GET_WEAKREFS_LISTPTR(o) \
((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))

View file

@ -20,7 +20,6 @@
#include "third_party/python/Include/tupleobject.h"
#include "third_party/python/Include/unicodeobject.h"
#include "third_party/python/Python/wordcode_helpers.inc"
#include "third_party/quickjs/internal.h"
/* Peephole optimizations for bytecode compiler. */

View file

@ -1,216 +0,0 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
PKGS += THIRD_PARTY_QUICKJS
THIRD_PARTY_QUICKJS_ARTIFACTS += THIRD_PARTY_QUICKJS_A
THIRD_PARTY_QUICKJS_BINS = $(THIRD_PARTY_QUICKJS_COMS) $(THIRD_PARTY_QUICKJS_COMS:%=%.dbg)
THIRD_PARTY_QUICKJS = $(THIRD_PARTY_QUICKJS_A_DEPS) $(THIRD_PARTY_QUICKJS_A)
THIRD_PARTY_QUICKJS_A = o/$(MODE)/third_party/quickjs/quickjs.a
THIRD_PARTY_QUICKJS_HDRS = $(foreach x,$(THIRD_PARTY_QUICKJS_ARTIFACTS),$($(x)_HDRS))
THIRD_PARTY_QUICKJS_INCS = $(foreach x,$(THIRD_PARTY_QUICKJS_ARTIFACTS),$($(x)_INCS))
THIRD_PARTY_QUICKJS_A_SRCS = \
third_party/quickjs/array.c \
third_party/quickjs/atof.c \
third_party/quickjs/atom.c \
third_party/quickjs/atomics.c \
third_party/quickjs/bigdecimal.c \
third_party/quickjs/bigint.c \
third_party/quickjs/byte.c \
third_party/quickjs/call.c \
third_party/quickjs/cutils.c \
third_party/quickjs/date.c \
third_party/quickjs/dbuf.c \
third_party/quickjs/dbuf.c \
third_party/quickjs/diglet.c \
third_party/quickjs/eq.c \
third_party/quickjs/err.c \
third_party/quickjs/float.c \
third_party/quickjs/gc.c \
third_party/quickjs/gen.c \
third_party/quickjs/iter.c \
third_party/quickjs/json.c \
third_party/quickjs/leb128.c \
third_party/quickjs/libbf.c \
third_party/quickjs/libregexp.c \
third_party/quickjs/libunicode.c \
third_party/quickjs/map.c \
third_party/quickjs/math.c \
third_party/quickjs/mem.c \
third_party/quickjs/object.c \
third_party/quickjs/parse.c \
third_party/quickjs/prim.c \
third_party/quickjs/promise.c \
third_party/quickjs/proxy.c \
third_party/quickjs/quickjs-libc.c \
third_party/quickjs/quickjs.c \
third_party/quickjs/reflect.c \
third_party/quickjs/regexp.c \
third_party/quickjs/shape.c \
third_party/quickjs/str.c \
third_party/quickjs/strbuf.c \
third_party/quickjs/tok.c \
third_party/quickjs/typedarray.c \
third_party/quickjs/uri.c \
third_party/quickjs/usage.c
THIRD_PARTY_QUICKJS_A_HDRS = \
third_party/quickjs/cutils.h \
third_party/quickjs/diglet.h \
third_party/quickjs/internal.h \
third_party/quickjs/leb128.h \
third_party/quickjs/libbf.h \
third_party/quickjs/libregexp.h \
third_party/quickjs/libunicode.h \
third_party/quickjs/list.h \
third_party/quickjs/quickjs-libc.h \
third_party/quickjs/quickjs.h
THIRD_PARTY_QUICKJS_A_INCS = \
third_party/quickjs/libregexp-opcode.inc \
third_party/quickjs/libunicode-table.inc \
third_party/quickjs/quickjs-atom.inc \
third_party/quickjs/quickjs-opcode.inc \
third_party/quickjs/unicode_gen_def.inc
THIRD_PARTY_QUICKJS_A_OBJS = \
$(THIRD_PARTY_QUICKJS_A_SRCS:%.c=o/$(MODE)/%.o)
THIRD_PARTY_QUICKJS_A_DIRECTDEPS = \
LIBC_CALLS \
LIBC_DLOPEN \
LIBC_FMT \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT_KERNEL32 \
LIBC_PROC \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
LIBC_STR \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_X \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_MUSL \
TOOL_ARGS
THIRD_PARTY_QUICKJS_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_QUICKJS_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_QUICKJS_A): \
third_party/quickjs/ \
$(THIRD_PARTY_QUICKJS_A).pkg \
$(THIRD_PARTY_QUICKJS_A_OBJS)
$(THIRD_PARTY_QUICKJS_A).pkg: \
$(THIRD_PARTY_QUICKJS_A_OBJS) \
$(foreach x,$(THIRD_PARTY_QUICKJS_A_DIRECTDEPS),$($(x)_A).pkg)
THIRD_PARTY_QUICKJS_SRCS = \
third_party/quickjs/qjs.c \
third_party/quickjs/qjsc.c \
third_party/quickjs/run-test262.c \
third_party/quickjs/unicode_gen.c \
$(foreach x,$(THIRD_PARTY_QUICKJS_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_QUICKJS_OBJS = \
o/$(MODE)/third_party/quickjs/qjs.o \
o/$(MODE)/third_party/quickjs/qjsc.o \
o/$(MODE)/third_party/quickjs/run-test262.o \
$(THIRD_PARTY_QUICKJS_A_OBJS)
THIRD_PARTY_QUICKJS_COMS = \
o/$(MODE)/third_party/quickjs/qjs.com \
o/$(MODE)/third_party/quickjs/qjsc.com \
o/$(MODE)/third_party/quickjs/run-test262.com \
o/$(MODE)/third_party/quickjs/unicode_gen.com
THIRD_PARTY_QUICKJS_CHECKS = \
$(THIRD_PARTY_QUICKJS_A).pkg \
$(THIRD_PARTY_QUICKJS_A_HDRS:%=o/$(MODE)/%.ok)
o/$(MODE)/third_party/quickjs/qjscalc.c: \
third_party/quickjs/qjscalc.js \
o/$(MODE)/third_party/quickjs/qjsc.com
@$(COMPILE) -wAQJSC o/$(MODE)/third_party/quickjs/qjsc.com -fbignum -o $@ -c $<
o/$(MODE)/third_party/quickjs/repl.c: \
third_party/quickjs/repl.js \
o/$(MODE)/third_party/quickjs/qjsc.com
@$(COMPILE) -wAQJSC o/$(MODE)/third_party/quickjs/qjsc.com -o $@ -m -c $<
o/$(MODE)/third_party/quickjs/qjs.com.dbg: \
$(THIRD_PARTY_QUICKJS) \
o/$(MODE)/third_party/quickjs/qjs.o \
o/$(MODE)/third_party/quickjs/repl.o \
o/$(MODE)/third_party/quickjs/qjscalc.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/third_party/quickjs/qjs.com: \
o/$(MODE)/third_party/quickjs/qjs.com.dbg \
o/$(MODE)/third_party/zip/zip.com \
o/$(MODE)/tool/build/symtab.com
@$(MAKE_OBJCOPY)
@$(MAKE_SYMTAB_CREATE)
@$(MAKE_SYMTAB_ZIP)
o/$(MODE)/third_party/quickjs/qjsc.com.dbg: \
$(THIRD_PARTY_QUICKJS) \
o/$(MODE)/third_party/quickjs/qjsc.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
# git clone git@github.com:tc39/test262 /opt/test262
# make -j8 MODE=dbg o/dbg/third_party/quickjs/run-test262.com
# o/dbg/third_party/quickjs/run-test262.com -m -c third_party/quickjs/test262.conf -a
o/$(MODE)/third_party/quickjs/run-test262.com.dbg: \
$(THIRD_PARTY_QUICKJS_A_DEPS) \
$(THIRD_PARTY_QUICKJS_A) \
$(THIRD_PARTY_QUICKJS_A).pkg \
o/$(MODE)/third_party/quickjs/run-test262.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/third_party/quickjs/unicode_gen.com.dbg: \
$(THIRD_PARTY_QUICKJS_A_DEPS) \
$(THIRD_PARTY_QUICKJS_A) \
$(THIRD_PARTY_QUICKJS_A).pkg \
o/$(MODE)/third_party/quickjs/unicode_gen.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
$(THIRD_PARTY_QUICKJS_OBJS): private \
CPPFLAGS += \
-DCONFIG_BIGNUM \
-DCONFIG_VERSION=\"2021-03-27\"
o/tiny/third_party/quickjs/call.o: private \
CFLAGS += \
-O2
# TODO(jart): Replace alloca() calls with malloc().
o/$(MODE)/third_party/quickjs/libregexp.o \
o/$(MODE)/third_party/quickjs/quickjs.o: private \
CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
o/$(MODE)/third_party/quickjs/call.o: private QUOTA = -M1024m -C32 -L180
o/$(MODE)/third_party/quickjs/quickjs.o: private QUOTA = -M512m -C32 -L180
.PHONY: o/$(MODE)/third_party/quickjs
o/$(MODE)/third_party/quickjs: \
$(THIRD_PARTY_QUICKJS_BINS) \
$(THIRD_PARTY_QUICKJS_CHECKS)

View file

@ -1,148 +0,0 @@
2021-03-27:
- faster Array.prototype.push and Array.prototype.unshift
- added JS_UpdateStackTop()
- fixed Windows console
- misc bug fixes
2020-11-08:
- improved function parameter initializers
- added std.setenv(), std.unsetenv() and std.getenviron()
- added JS_EvalThis()
- misc bug fixes
2020-09-06:
- added logical assignment operators
- added IsHTMLDDA support
- faster for-of loops
- os.Worker now takes a module filename as parameter
- qjsc: added -D option to compile dynamically loaded modules or workers
- misc bug fixes
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
- added AggregateError and Promise.any
- added env, uid and gid options in os.exec()
- misc bug fixes
2020-03-16:
- reworked error handling in std and os libraries: suppressed I/O
exceptions in std FILE functions and return a positive errno value
when it is explicit
- output exception messages to stderr
- added std.loadFile(), std.strerror(), std.FILE.prototype.tello()
- added JS_GetRuntimeOpaque(), JS_SetRuntimeOpaque(), JS_NewUint32()
- updated to Unicode 13.0.0
- misc bug fixes
2020-01-19:
- keep CONFIG_BIGNUM in the makefile
- added os.chdir()
- qjs: added -I option
- more memory checks in the bignum operations
- modified operator overloading semantics to be closer to the TC39
proposal
- suppressed "use bigint" mode. Simplified "use math" mode
- BigDecimal: changed suffix from 'd' to 'm'
- misc bug fixes
2020-01-05:
- always compile the bignum code. Added '--bignum' option to qjs.
- added BigDecimal
- added String.prototype.replaceAll
- misc bug fixes
2019-12-21:
- added nullish coalescing operator (ES2020)
- added optional chaining (ES2020)
- removed recursions in garbage collector
- test stack overflow in the parser
- improved backtrace logic
- added JS_SetHostPromiseRejectionTracker()
- allow exotic constructors
- improved c++ compatibility
- misc bug fixes
2019-10-27:
- added example of C class in a module (examples/test_point.js)
- added JS_GetTypedArrayBuffer()
- misc bug fixes
2019-09-18:
- added os.exec and other system calls
- exported JS_ValueToAtom()
- qjsc: added 'qjsc_' prefix to the generated C identifiers
- added cross-compilation support
- misc bug fixes
2019-09-01:
- added globalThis
- documented JS_EVAL_FLAG_COMPILE_ONLY
- added import.meta.url and import.meta.main
- added 'debugger' statement
- misc bug fixes
2019-08-18:
- added os.realpath, os.getcwd, os.mkdir, os.stat, os.lstat,
os.readlink, os.readdir, os.utimes, std.popen
- module autodetection
- added import.meta
- misc bug fixes
2019-08-10:
- added public class fields and private class fields, methods and
accessors (TC39 proposal)
- changed JS_ToCStringLen() prototype
- qjsc: handle '-' in module names and modules with the same filename
- added std.urlGet
- exported JS_GetOwnPropertyNames() and JS_GetOwnProperty()
- exported some bigint C functions
- added support for eshost in run-test262
- misc bug fixes
2019-07-28:
- added dynamic import
- added Promise.allSettled
- added String.prototype.matchAll
- added Object.fromEntries
- reduced number of ticks in await
- added BigInt support in Atomics
- exported JS_NewPromiseCapability()
- misc async function and async generator fixes
- enabled hashbang support by default
2019-07-21:
- updated test262 tests
- updated to Unicode version 12.1.0
- fixed missing Date object in qjsc
- fixed multi-context creation
- misc ES2020 related fixes
- simplified power and division operators in bignum extension
- fixed several crash conditions
2019-07-09:
- first public release

View file

@ -1,22 +0,0 @@
QuickJS Javascript Engine
Copyright (c) 2017-2021 Fabrice Bellard
Copyright (c) 2017-2021 Charlie Gordon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,16 +0,0 @@
LOCAL CHANGES
- Replace snprintf with xasprintf in find_unique_cname
- Squash uninitialized read of harnessbuf in run-test262.c
- Change run-test262.c to not rebase configured paths
- https://github.com/bellard/quickjs/pull/132
- https://github.com/bellard/quickjs/pull/171
- https://github.com/bellard/quickjs/pull/182
SYNCHRONIZATION POINT (`--date=format:"%a %b %d %H:%M:%S %Y %z"`)
commit 2788d71e823b522b178db3b3660ce93689534e6d
Author: bellard <6490144+bellard@users.noreply.github.com>
Date: Sun Mar 06 19:00:24 2022 +0100
updated to Unicode 14.0.0

View file

@ -1,70 +0,0 @@
Bugs:
- modules: better error handling with cyclic module references
Misc ideas:
- use custom printf to avoid compatibility issues with floating point numbers
- consistent naming for preprocessor defines
- unify coding style and naming conventions
- use names from the ECMA spec in library implementation
- use byte code emitters with typed arguments (for clarity)
- use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing
and use the same wrappers in all phases
- use more generic method for line numbers in resolve_variables and resolve_labels
- use custom timezone support to avoid C library compatibility issues
Memory:
- use memory pools for objects, etc?
- test border cases for max number of atoms, object properties, string length
- add emergency malloc mode for out of memory exceptions.
- test all DynBuf memory errors
- test all js_realloc memory errors
- improve JS_ComputeMemoryUsage() with more info
Built-in standard library:
- BSD sockets
- modules: use realpath in module name normalizer and put it in quickjs-libc
- modules: if no ".", use a well known module loading path ?
- get rid of __loadScript, use more common name
REPL:
- debugger
- 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
- use more generic approach to display evaluation results
- improve directive handling: dispatch, colorize, completion...
- save history
- close all predefined methods in repl.js and jscalc.js
Optimization ideas:
- 64-bit atoms in 64-bit mode ?
- 64-bit small bigint in 64-bit mode ?
- reuse stack slots for disjoint scopes, if strip
- add heuristic to avoid some cycles in closures
- small String (0-2 charcodes) with immediate storage
- perform static string concatenation at compile time
- optimize string concatenation with ropes or miniropes?
- add implicit numeric strings for Uint32 numbers?
- optimize `s += a + b`, `s += a.b` and similar simple expressions
- ensure string canonical representation and optimise comparisons and hashes?
- remove JSObject.first_weak_ref, use bit+context based hashed array for weak references
- property access optimization on the global object, functions,
prototypes and special non extensible objects.
- create object literals with the correct length by backpatching length argument
- remove redundant set_loc_uninitialized/check_uninitialized opcodes
- peephole optim: push_atom_value, to_propkey -> push_atom_value
- peephole optim: put_loc x, get_loc_check x -> set_loc x
- convert slow array to fast array when all properties != length are numeric
- optimize destructuring assignments for global and local variables
- implement some form of tail-call-optimization
- optimize OP_apply
- optimize f(...b)
Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
Result: 35/75280 errors, 909 excluded, 585 skipped
Test262 commit: 31126581e7290f9233c29cefd93f66c6ac78f1c9

File diff suppressed because it is too large Load diff

View file

@ -1,322 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/fmt/conv.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
/* XXX: remove */
static double js_strtod(const char *p, int radix, BOOL is_float)
{
double d;
int c;
if (!is_float || radix != 10) {
uint64_t n_max, n;
int int_exp, is_neg;
is_neg = 0;
if (*p == '-') {
is_neg = 1;
p++;
}
/* skip leading zeros */
while (*p == '0')
p++;
n = 0;
if (radix == 10)
n_max = ((uint64_t)-1 - 9) / 10; /* most common case */
else
n_max = ((uint64_t)-1 - (radix - 1)) / radix;
/* XXX: could be more precise */
int_exp = 0;
while (*p != '\0') {
c = to_digit((uint8_t)*p);
if (c >= radix)
break;
if (n <= n_max) {
n = n * radix + c;
} else {
int_exp++;
}
p++;
}
d = n;
if (int_exp != 0) {
d *= pow(radix, int_exp);
}
if (is_neg)
d = -d;
} else {
d = strtod(p, NULL);
}
return d;
}
/* return an exception in case of memory error. Return JS_NAN if
invalid syntax */
#ifdef CONFIG_BIGNUM
JSValue js_atof2(JSContext *ctx, const char *str, const char **pp, int radix, int flags, slimb_t *pexponent)
#else
JSValue js_atof(JSContext *ctx, const char *str, const char **pp, int radix, int flags)
#endif
{
const char *p, *p_start;
int sep, is_neg;
BOOL is_float, has_legacy_octal;
int atod_type = flags & ATOD_TYPE_MASK;
char buf1[64], *buf;
int i, j, len;
BOOL buf_allocated = FALSE;
JSValue val;
/* optional separator between digits */
sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
has_legacy_octal = FALSE;
p = str;
p_start = p;
is_neg = 0;
if (p[0] == '+') {
p++;
p_start++;
if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
goto no_radix_prefix;
} else if (p[0] == '-') {
p++;
p_start++;
is_neg = 1;
if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
goto no_radix_prefix;
}
if (p[0] == '0') {
if ((p[1] == 'x' || p[1] == 'X') &&
(radix == 0 || radix == 16)) {
p += 2;
radix = 16;
} else if ((p[1] == 'o' || p[1] == 'O') &&
radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
p += 2;
radix = 8;
} else if ((p[1] == 'b' || p[1] == 'B') &&
radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
p += 2;
radix = 2;
} else if ((p[1] >= '0' && p[1] <= '9') &&
radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) {
int i;
has_legacy_octal = TRUE;
sep = 256;
for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)
continue;
if (p[i] == '8' || p[i] == '9')
goto no_prefix;
p += 1;
radix = 8;
} else {
goto no_prefix;
}
/* there must be a digit after the prefix */
if (to_digit((uint8_t)*p) >= radix)
goto fail;
no_prefix: ;
} else {
no_radix_prefix:
if (!(flags & ATOD_INT_ONLY) &&
(atod_type == ATOD_TYPE_FLOAT64 ||
atod_type == ATOD_TYPE_BIG_FLOAT) &&
strstart(p, "Infinity", &p)) {
#ifdef CONFIG_BIGNUM
if (atod_type == ATOD_TYPE_BIG_FLOAT) {
bf_t *a;
val = JS_NewBigFloat(ctx);
if (JS_IsException(val))
goto done;
a = JS_GetBigFloat(val);
bf_set_inf(a, is_neg);
} else
#endif
{
double d = 1.0 / 0.0;
if (is_neg)
d = -d;
val = JS_NewFloat64(ctx, d);
}
goto done;
}
}
if (radix == 0)
radix = 10;
is_float = FALSE;
p_start = p;
while (to_digit((uint8_t)*p) < radix
|| (*p == sep && (radix != 10 ||
p != p_start + 1 || p[-1] != '0') &&
to_digit((uint8_t)p[1]) < radix)) {
p++;
}
if (!(flags & ATOD_INT_ONLY)) {
if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
is_float = TRUE;
p++;
if (*p == sep)
goto fail;
while (to_digit((uint8_t)*p) < radix ||
(*p == sep && to_digit((uint8_t)p[1]) < radix))
p++;
}
if (p > p_start &&
(((*p == 'e' || *p == 'E') && radix == 10) ||
((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {
const char *p1 = p + 1;
is_float = TRUE;
if (*p1 == '+') {
p1++;
} else if (*p1 == '-') {
p1++;
}
if (isdigit((uint8_t)*p1)) {
p = p1 + 1;
while (isdigit((uint8_t)*p) || (*p == sep && isdigit((uint8_t)p[1])))
p++;
}
}
}
if (p == p_start)
goto fail;
buf = buf1;
buf_allocated = FALSE;
len = p - p_start;
if (UNLIKELY((len + 2) > sizeof(buf1))) {
buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */
if (!buf)
goto mem_error;
buf_allocated = TRUE;
}
/* remove the separators and the radix prefixes */
j = 0;
if (is_neg)
buf[j++] = '-';
for (i = 0; i < len; i++) {
if (p_start[i] != '_')
buf[j++] = p_start[i];
}
buf[j] = '\0';
#ifdef CONFIG_BIGNUM
if (flags & ATOD_ACCEPT_SUFFIX) {
if (*p == 'n') {
p++;
atod_type = ATOD_TYPE_BIG_INT;
} else if (*p == 'l') {
p++;
atod_type = ATOD_TYPE_BIG_FLOAT;
} else if (*p == 'm') {
p++;
atod_type = ATOD_TYPE_BIG_DECIMAL;
} else {
if (flags & ATOD_MODE_BIGINT) {
if (!is_float)
atod_type = ATOD_TYPE_BIG_INT;
if (has_legacy_octal)
goto fail;
} else {
if (is_float && radix != 10)
goto fail;
}
}
} else {
if (atod_type == ATOD_TYPE_FLOAT64) {
if (flags & ATOD_MODE_BIGINT) {
if (!is_float)
atod_type = ATOD_TYPE_BIG_INT;
if (has_legacy_octal)
goto fail;
} else {
if (is_float && radix != 10)
goto fail;
}
}
}
switch(atod_type) {
case ATOD_TYPE_FLOAT64:
{
double d;
d = js_strtod(buf, radix, is_float);
/* return int or float64 */
val = JS_NewFloat64(ctx, d);
}
break;
case ATOD_TYPE_BIG_INT:
if (has_legacy_octal || is_float)
goto fail;
val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL);
break;
case ATOD_TYPE_BIG_FLOAT:
if (has_legacy_octal)
goto fail;
val = ctx->rt->bigfloat_ops.from_string(ctx, buf, radix, flags,
pexponent);
break;
case ATOD_TYPE_BIG_DECIMAL:
if (radix != 10)
goto fail;
val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL);
break;
default:
abort();
}
#else
{
double d;
(void)has_legacy_octal;
if (is_float && radix != 10)
goto fail;
d = js_strtod(buf, radix, is_float);
val = JS_NewFloat64(ctx, d);
}
#endif
done:
if (buf_allocated)
js_free_rt(ctx->rt, buf);
if (pp)
*pp = p;
return val;
fail:
val = JS_NAN;
goto done;
mem_error:
val = JS_ThrowOutOfMemory(ctx);
goto done;
}
#ifdef CONFIG_BIGNUM
JSValue js_atof(JSContext *ctx, const char *str, const char **pp, int radix, int flags)
{
return js_atof2(ctx, str, pp, radix, flags, NULL);
}
#endif

View file

@ -1,243 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/str/str.h"
#include "third_party/quickjs/internal.h"
#include "third_party/quickjs/libregexp.h"
#include "third_party/quickjs/quickjs.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
/* Should only be used for debug. */
const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size, JSAtom atom)
{
if (__JS_AtomIsTaggedInt(atom)) {
snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom));
} else {
JSAtomStruct *p;
assert(atom < rt->atom_size);
if (atom == JS_ATOM_NULL) {
snprintf(buf, buf_size, "<null>");
} else {
int i, c;
char *q;
JSString *str;
q = buf;
p = rt->atom_array[atom];
assert(!atom_is_free(p));
str = p;
if (str) {
if (!str->is_wide_char) {
/* special case ASCII strings */
c = 0;
for(i = 0; i < str->len; i++) {
c |= str->u.str8[i];
}
if (c < 0x80)
return (const char *)str->u.str8;
}
for(i = 0; i < str->len; i++) {
if (str->is_wide_char)
c = str->u.str16[i];
else
c = str->u.str8[i];
if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX)
break;
if (c < 128) {
*q++ = c;
} else {
q += unicode_to_utf8((uint8_t *)q, c);
}
}
}
*q = '\0';
}
}
return buf;
}
const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom)
{
return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);
}
static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string)
{
char buf[ATOM_GET_STR_BUF_SIZE];
if (__JS_AtomIsTaggedInt(atom)) {
snprintf(buf, sizeof(buf), "%u", __JS_AtomToUInt32(atom));
return JS_NewString(ctx, buf);
} else {
JSRuntime *rt = ctx->rt;
JSAtomStruct *p;
assert(atom < rt->atom_size);
p = rt->atom_array[atom];
if (p->atom_type == JS_ATOM_TYPE_STRING) {
goto ret_string;
} else if (force_string) {
if (p->len == 0 && p->is_wide_char != 0) {
/* no description string */
p = rt->atom_array[JS_ATOM_empty_string];
}
ret_string:
return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
} else {
return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p));
}
}
}
JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom)
{
return __JS_AtomToValue(ctx, atom, FALSE);
}
JSValue JS_AtomToString(JSContext *ctx, JSAtom atom)
{
return __JS_AtomToValue(ctx, atom, TRUE);
}
/* return TRUE if the atom is an array index (i.e. 0 <= index <=
2^32-2 and return its value */
BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)
{
if (__JS_AtomIsTaggedInt(atom)) {
*pval = __JS_AtomToUInt32(atom);
return TRUE;
} else {
JSRuntime *rt = ctx->rt;
JSAtomStruct *p;
uint32_t val;
assert(atom < rt->atom_size);
p = rt->atom_array[atom];
if (p->atom_type == JS_ATOM_TYPE_STRING &&
is_num_string(&val, p) && val != -1) {
*pval = val;
return TRUE;
} else {
*pval = 0;
return FALSE;
}
}
}
/* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */
BOOL is_num_string(uint32_t *pval, const JSString *p)
{
uint32_t n;
uint64_t n64;
int c, i, len;
len = p->len;
if (len == 0 || len > 10)
return FALSE;
if (p->is_wide_char)
c = p->u.str16[0];
else
c = p->u.str8[0];
if (isdigit(c)) {
if (c == '0') {
if (len != 1)
return FALSE;
n = 0;
} else {
n = c - '0';
for(i = 1; i < len; i++) {
if (p->is_wide_char)
c = p->u.str16[i];
else
c = p->u.str8[i];
if (!isdigit(c))
return FALSE;
n64 = (uint64_t)n * 10 + (c - '0');
if ((n64 >> 32) != 0)
return FALSE;
n = n64;
}
}
*pval = n;
return TRUE;
} else {
return FALSE;
}
}
JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p)
{
uint32_t i = p->hash_next; /* atom_index */
if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
JSAtomStruct *p1;
i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)];
p1 = rt->atom_array[i];
while (p1 != p) {
assert(i != 0);
i = p1->hash_next;
p1 = rt->atom_array[i];
}
}
return i;
}
/* val must be a symbol */
JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val)
{
JSAtomStruct *p = JS_VALUE_GET_PTR(val);
return js_get_atom_index(ctx->rt, p);
}
/* return a string atom containing name concatenated with str1 */
JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1)
{
JSValue str;
JSAtom atom;
const char *cstr;
char *cstr2;
size_t len, len1;
str = JS_AtomToString(ctx, name);
if (JS_IsException(str))
return JS_ATOM_NULL;
cstr = JS_ToCStringLen(ctx, &len, str);
if (!cstr)
goto fail;
len1 = strlen(str1);
cstr2 = js_malloc(ctx, len + len1 + 1);
if (!cstr2)
goto fail;
memcpy(cstr2, cstr, len);
memcpy(cstr2 + len, str1, len1);
cstr2[len + len1] = '\0';
atom = JS_NewAtomLen(ctx, cstr2, len + len1);
js_free(ctx, cstr2);
JS_FreeCString(ctx, cstr);
JS_FreeValue(ctx, str);
return atom;
fail:
JS_FreeCString(ctx, cstr);
JS_FreeValue(ctx, str);
return JS_ATOM_NULL;
}

View file

@ -1,520 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
#ifdef CONFIG_ATOMICS
typedef enum AtomicsOpEnum {
ATOMICS_OP_ADD,
ATOMICS_OP_AND,
ATOMICS_OP_OR,
ATOMICS_OP_SUB,
ATOMICS_OP_XOR,
ATOMICS_OP_EXCHANGE,
ATOMICS_OP_COMPARE_EXCHANGE,
ATOMICS_OP_LOAD,
} AtomicsOpEnum;
static void *js_atomics_get_ptr(JSContext *ctx,
JSArrayBuffer **pabuf,
int *psize_log2, JSClassID *pclass_id,
JSValueConst obj, JSValueConst idx_val,
int is_waitable)
{
JSObject *p;
JSTypedArray *ta;
JSArrayBuffer *abuf;
void *ptr;
uint64_t idx;
BOOL err;
int size_log2;
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
goto fail;
p = JS_VALUE_GET_OBJ(obj);
#ifdef CONFIG_BIGNUM
if (is_waitable)
err = (p->class_id != JS_CLASS_INT32_ARRAY &&
p->class_id != JS_CLASS_BIG_INT64_ARRAY);
else
err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
p->class_id <= JS_CLASS_BIG_UINT64_ARRAY);
#else
if (is_waitable)
err = (p->class_id != JS_CLASS_INT32_ARRAY);
else
err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
p->class_id <= JS_CLASS_UINT32_ARRAY);
#endif
if (err) {
fail:
JS_ThrowTypeError(ctx, "integer TypedArray expected");
return NULL;
}
ta = p->u.typed_array;
abuf = ta->buffer->u.array_buffer;
if (!abuf->shared) {
if (is_waitable == 2) {
JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray");
return NULL;
}
if (abuf->detached) {
JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
return NULL;
}
}
if (JS_ToIndex(ctx, &idx, idx_val)) {
return NULL;
}
/* if the array buffer is detached, p->u.array.count = 0 */
if (idx >= p->u.array.count) {
JS_ThrowRangeError(ctx, "out-of-bound access");
return NULL;
}
size_log2 = typed_array_size_log2(p->class_id);
ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
if (pabuf)
*pabuf = abuf;
if (psize_log2)
*psize_log2 = size_log2;
if (pclass_id)
*pclass_id = p->class_id;
return ptr;
}
static JSValue js_atomics_op(JSContext *ctx,
JSValueConst this_obj,
int argc, JSValueConst *argv, int op)
{
int size_log2;
#ifdef CONFIG_BIGNUM
uint64_t v, a, rep_val;
#else
uint32_t v, a, rep_val;
#endif
void *ptr;
JSValue ret;
JSClassID class_id;
JSArrayBuffer *abuf;
ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, &class_id,
argv[0], argv[1], 0);
if (!ptr)
return JS_EXCEPTION;
rep_val = 0;
if (op == ATOMICS_OP_LOAD) {
v = 0;
} else {
#ifdef CONFIG_BIGNUM
if (size_log2 == 3) {
int64_t v64;
if (JS_ToBigInt64(ctx, &v64, argv[2]))
return JS_EXCEPTION;
v = v64;
if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
if (JS_ToBigInt64(ctx, &v64, argv[3]))
return JS_EXCEPTION;
rep_val = v64;
}
} else
#endif
{
uint32_t v32;
if (JS_ToUint32(ctx, &v32, argv[2]))
return JS_EXCEPTION;
v = v32;
if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
if (JS_ToUint32(ctx, &v32, argv[3]))
return JS_EXCEPTION;
rep_val = v32;
}
}
if (abuf->detached)
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
}
switch(op | (size_log2 << 3)) {
#ifdef CONFIG_BIGNUM
#define OP(op_name, func_name) \
case ATOMICS_OP_ ## op_name | (0 << 3): \
a = func_name((_Atomic(uint8_t) *)ptr, v); \
break; \
case ATOMICS_OP_ ## op_name | (1 << 3): \
a = func_name((_Atomic(uint16_t) *)ptr, v); \
break; \
case ATOMICS_OP_ ## op_name | (2 << 3): \
a = func_name((_Atomic(uint32_t) *)ptr, v); \
break; \
case ATOMICS_OP_ ## op_name | (3 << 3): \
a = func_name((_Atomic(uint64_t) *)ptr, v); \
break;
#else
#define OP(op_name, func_name) \
case ATOMICS_OP_ ## op_name | (0 << 3): \
a = func_name((_Atomic(uint8_t) *)ptr, v); \
break; \
case ATOMICS_OP_ ## op_name | (1 << 3): \
a = func_name((_Atomic(uint16_t) *)ptr, v); \
break; \
case ATOMICS_OP_ ## op_name | (2 << 3): \
a = func_name((_Atomic(uint32_t) *)ptr, v); \
break;
#endif
OP(ADD, atomic_fetch_add)
OP(AND, atomic_fetch_and)
OP(OR, atomic_fetch_or)
OP(SUB, atomic_fetch_sub)
OP(XOR, atomic_fetch_xor)
OP(EXCHANGE, atomic_exchange)
#undef OP
case ATOMICS_OP_LOAD | (0 << 3):
a = atomic_load((_Atomic(uint8_t) *)ptr);
break;
case ATOMICS_OP_LOAD | (1 << 3):
a = atomic_load((_Atomic(uint16_t) *)ptr);
break;
case ATOMICS_OP_LOAD | (2 << 3):
a = atomic_load((_Atomic(uint32_t) *)ptr);
break;
#ifdef CONFIG_BIGNUM
case ATOMICS_OP_LOAD | (3 << 3):
a = atomic_load((_Atomic(uint64_t) *)ptr);
break;
#endif
case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):
{
uint8_t v1 = v;
atomic_compare_exchange_strong((_Atomic(uint8_t) *)ptr, &v1, rep_val);
a = v1;
}
break;
case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3):
{
uint16_t v1 = v;
atomic_compare_exchange_strong((_Atomic(uint16_t) *)ptr, &v1, rep_val);
a = v1;
}
break;
case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3):
{
uint32_t v1 = v;
atomic_compare_exchange_strong((_Atomic(uint32_t) *)ptr, &v1, rep_val);
a = v1;
}
break;
#ifdef CONFIG_BIGNUM
case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3):
{
uint64_t v1 = v;
atomic_compare_exchange_strong((_Atomic(uint64_t) *)ptr, &v1, rep_val);
a = v1;
}
break;
#endif
default:
abort();
}
switch(class_id) {
case JS_CLASS_INT8_ARRAY:
a = (int8_t)a;
goto done;
case JS_CLASS_UINT8_ARRAY:
a = (uint8_t)a;
goto done;
case JS_CLASS_INT16_ARRAY:
a = (int16_t)a;
goto done;
case JS_CLASS_UINT16_ARRAY:
a = (uint16_t)a;
goto done;
case JS_CLASS_INT32_ARRAY:
done:
ret = JS_NewInt32(ctx, a);
break;
case JS_CLASS_UINT32_ARRAY:
ret = JS_NewUint32(ctx, a);
break;
#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
ret = JS_NewBigInt64(ctx, a);
break;
case JS_CLASS_BIG_UINT64_ARRAY:
ret = JS_NewBigUint64(ctx, a);
break;
#endif
default:
abort();
}
return ret;
}
static JSValue js_atomics_store(JSContext *ctx,
JSValueConst this_obj,
int argc, JSValueConst *argv)
{
int size_log2;
void *ptr;
JSValue ret;
JSArrayBuffer *abuf;
ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, NULL,
argv[0], argv[1], 0);
if (!ptr)
return JS_EXCEPTION;
#ifdef CONFIG_BIGNUM
if (size_log2 == 3) {
int64_t v64;
ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2]));
if (JS_IsException(ret))
return ret;
if (JS_ToBigInt64(ctx, &v64, ret)) {
JS_FreeValue(ctx, ret);
return JS_EXCEPTION;
}
if (abuf->detached)
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
atomic_store((_Atomic(uint64_t) *)ptr, v64);
} else
#endif
{
uint32_t v;
/* XXX: spec, would be simpler to return the written value */
ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2]));
if (JS_IsException(ret))
return ret;
if (JS_ToUint32(ctx, &v, ret)) {
JS_FreeValue(ctx, ret);
return JS_EXCEPTION;
}
if (abuf->detached)
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
switch(size_log2) {
case 0:
atomic_store((_Atomic(uint8_t) *)ptr, v);
break;
case 1:
atomic_store((_Atomic(uint16_t) *)ptr, v);
break;
case 2:
atomic_store((_Atomic(uint32_t) *)ptr, v);
break;
default:
abort();
}
}
return ret;
}
static JSValue js_atomics_isLockFree(JSContext *ctx,
JSValueConst this_obj,
int argc, JSValueConst *argv)
{
int v, ret;
if (JS_ToInt32Sat(ctx, &v, argv[0]))
return JS_EXCEPTION;
ret = (v == 1 || v == 2 || v == 4
#ifdef CONFIG_BIGNUM
|| v == 8
#endif
);
return JS_NewBool(ctx, ret);
}
typedef struct JSAtomicsWaiter {
struct list_head link;
BOOL linked;
pthread_cond_t cond;
int32_t *ptr;
} JSAtomicsWaiter;
static pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct list_head js_atomics_waiter_list =
LIST_HEAD_INIT(js_atomics_waiter_list);
static JSValue js_atomics_wait(JSContext *ctx,
JSValueConst this_obj,
int argc, JSValueConst *argv)
{
int64_t v;
int32_t v32;
void *ptr;
int64_t timeout;
struct timespec ts;
JSAtomicsWaiter waiter_s, *waiter;
int ret, size_log2, res;
double d;
ptr = js_atomics_get_ptr(ctx, NULL, &size_log2, NULL,
argv[0], argv[1], 2);
if (!ptr)
return JS_EXCEPTION;
#ifdef CONFIG_BIGNUM
if (size_log2 == 3) {
if (JS_ToBigInt64(ctx, &v, argv[2]))
return JS_EXCEPTION;
} else
#endif
{
if (JS_ToInt32(ctx, &v32, argv[2]))
return JS_EXCEPTION;
v = v32;
}
if (JS_ToFloat64(ctx, &d, argv[3]))
return JS_EXCEPTION;
if (isnan(d) || d > INT64_MAX)
timeout = INT64_MAX;
else if (d < 0)
timeout = 0;
else
timeout = (int64_t)d;
if (!ctx->rt->can_block)
return JS_ThrowTypeError(ctx, "cannot block in this thread");
/* XXX: inefficient if large number of waiters, should hash on
'ptr' value */
/* XXX: use Linux futexes when available ? */
pthread_mutex_lock(&js_atomics_mutex);
if (size_log2 == 3) {
res = *(int64_t *)ptr != v;
} else {
res = *(int32_t *)ptr != v;
}
if (res) {
pthread_mutex_unlock(&js_atomics_mutex);
return JS_AtomToString(ctx, JS_ATOM_not_equal);
}
waiter = &waiter_s;
waiter->ptr = ptr;
pthread_cond_init(&waiter->cond, NULL);
waiter->linked = TRUE;
list_add_tail(&waiter->link, &js_atomics_waiter_list);
if (timeout == INT64_MAX) {
pthread_cond_wait(&waiter->cond, &js_atomics_mutex);
ret = 0;
} else {
/* XXX: use clock monotonic */
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += timeout / 1000;
ts.tv_nsec += (timeout % 1000) * 1000000;
if (ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
ts.tv_sec++;
}
ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex,
&ts);
}
if (waiter->linked)
list_del(&waiter->link);
pthread_mutex_unlock(&js_atomics_mutex);
pthread_cond_destroy(&waiter->cond);
if (ret == ETIMEDOUT) {
return JS_AtomToString(ctx, JS_ATOM_timed_out);
} else {
return JS_AtomToString(ctx, JS_ATOM_ok);
}
}
static JSValue js_atomics_notify(JSContext *ctx,
JSValueConst this_obj,
int argc, JSValueConst *argv)
{
struct list_head *el, *el1, waiter_list;
int32_t count, n;
void *ptr;
JSAtomicsWaiter *waiter;
JSArrayBuffer *abuf;
ptr = js_atomics_get_ptr(ctx, &abuf, NULL, NULL, argv[0], argv[1], 1);
if (!ptr)
return JS_EXCEPTION;
if (JS_IsUndefined(argv[2])) {
count = INT32_MAX;
} else {
if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0))
return JS_EXCEPTION;
}
if (abuf->detached)
return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
n = 0;
if (abuf->shared && count > 0) {
pthread_mutex_lock(&js_atomics_mutex);
init_list_head(&waiter_list);
list_for_each_safe(el, el1, &js_atomics_waiter_list) {
waiter = list_entry(el, JSAtomicsWaiter, link);
if (waiter->ptr == ptr) {
list_del(&waiter->link);
waiter->linked = FALSE;
list_add_tail(&waiter->link, &waiter_list);
n++;
if (n >= count)
break;
}
}
list_for_each(el, &waiter_list) {
waiter = list_entry(el, JSAtomicsWaiter, link);
pthread_cond_signal(&waiter->cond);
}
pthread_mutex_unlock(&js_atomics_mutex);
}
return JS_NewInt32(ctx, n);
}
static const JSCFunctionListEntry js_atomics_funcs[] = {
JS_CFUNC_MAGIC_DEF("add", 3, js_atomics_op, ATOMICS_OP_ADD ),
JS_CFUNC_MAGIC_DEF("and", 3, js_atomics_op, ATOMICS_OP_AND ),
JS_CFUNC_MAGIC_DEF("or", 3, js_atomics_op, ATOMICS_OP_OR ),
JS_CFUNC_MAGIC_DEF("sub", 3, js_atomics_op, ATOMICS_OP_SUB ),
JS_CFUNC_MAGIC_DEF("xor", 3, js_atomics_op, ATOMICS_OP_XOR ),
JS_CFUNC_MAGIC_DEF("exchange", 3, js_atomics_op, ATOMICS_OP_EXCHANGE ),
JS_CFUNC_MAGIC_DEF("compareExchange", 4, js_atomics_op, ATOMICS_OP_COMPARE_EXCHANGE ),
JS_CFUNC_MAGIC_DEF("load", 2, js_atomics_op, ATOMICS_OP_LOAD ),
JS_CFUNC_DEF("store", 3, js_atomics_store ),
JS_CFUNC_DEF("isLockFree", 1, js_atomics_isLockFree ),
JS_CFUNC_DEF("wait", 4, js_atomics_wait ),
JS_CFUNC_DEF("notify", 3, js_atomics_notify ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Atomics", JS_PROP_CONFIGURABLE ),
};
static const JSCFunctionListEntry js_atomics_obj[] = {
JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
};
void JS_AddIntrinsicAtomics(JSContext *ctx)
{
/* add Atomics as autoinit object */
JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj));
}
#endif /* CONFIG_ATOMICS */

View file

@ -1,724 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
JSValue JS_NewBigDecimal(JSContext *ctx)
{
JSBigDecimal *p;
p = js_malloc(ctx, sizeof(*p));
if (!p)
return JS_EXCEPTION;
p->header.ref_count = 1;
bfdec_init(ctx->bf_ctx, &p->num);
return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
}
/* return NULL if invalid type */
bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val)
{
uint32_t tag;
JSBigDecimal *p;
bfdec_t *r;
tag = JS_VALUE_GET_NORM_TAG(val);
switch(tag) {
case JS_TAG_BIG_DECIMAL:
p = JS_VALUE_GET_PTR(val);
r = &p->num;
break;
default:
JS_ThrowTypeError(ctx, "bigdecimal expected");
r = NULL;
break;
}
return r;
}
static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
BOOL allow_null_or_undefined)
{
redo:
switch(JS_VALUE_GET_NORM_TAG(val)) {
case JS_TAG_BIG_DECIMAL:
break;
case JS_TAG_NULL:
if (!allow_null_or_undefined)
goto fail;
/* fall thru */
case JS_TAG_BOOL:
case JS_TAG_INT:
{
bfdec_t *r;
int32_t v = JS_VALUE_GET_INT(val);
val = JS_NewBigDecimal(ctx);
if (JS_IsException(val))
break;
r = JS_GetBigDecimal(val);
if (bfdec_set_si(r, v)) {
JS_FreeValue(ctx, val);
val = JS_EXCEPTION;
break;
}
}
break;
case JS_TAG_FLOAT64:
case JS_TAG_BIG_INT:
case JS_TAG_BIG_FLOAT:
val = JS_ToStringFree(ctx, val);
if (JS_IsException(val))
break;
goto redo;
case JS_TAG_STRING:
{
const char *str, *p;
size_t len;
int err;
str = JS_ToCStringLen(ctx, &len, val);
JS_FreeValue(ctx, val);
if (!str)
return JS_EXCEPTION;
p = str;
p += skip_spaces(p);
if ((p - str) == len) {
bfdec_t *r;
val = JS_NewBigDecimal(ctx);
if (JS_IsException(val))
break;
r = JS_GetBigDecimal(val);
bfdec_set_zero(r, 0);
err = 0;
} else {
val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL);
if (JS_IsException(val)) {
JS_FreeCString(ctx, str);
return JS_EXCEPTION;
}
p += skip_spaces(p);
err = ((p - str) != len);
}
JS_FreeCString(ctx, str);
if (err) {
JS_FreeValue(ctx, val);
return JS_ThrowSyntaxError(ctx, "invalid bigdecimal literal");
}
}
break;
case JS_TAG_OBJECT:
val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
if (JS_IsException(val))
break;
goto redo;
case JS_TAG_UNDEFINED:
{
bfdec_t *r;
if (!allow_null_or_undefined)
goto fail;
val = JS_NewBigDecimal(ctx);
if (JS_IsException(val))
break;
r = JS_GetBigDecimal(val);
bfdec_set_nan(r);
}
break;
default:
fail:
JS_FreeValue(ctx, val);
return JS_ThrowTypeError(ctx, "cannot convert to bigdecimal");
}
return val;
}
static JSValue js_bigdecimal_constructor(JSContext *ctx,
JSValueConst new_target,
int argc, JSValueConst *argv)
{
JSValue val;
if (!JS_IsUndefined(new_target))
return JS_ThrowTypeError(ctx, "not a constructor");
if (argc == 0) {
bfdec_t *r;
val = JS_NewBigDecimal(ctx);
if (JS_IsException(val))
return val;
r = JS_GetBigDecimal(val);
bfdec_set_zero(r, 0);
} else {
val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE);
}
return val;
}
static JSValue js_thisBigDecimalValue(JSContext *ctx, JSValueConst this_val)
{
if (JS_IsBigDecimal(this_val))
return JS_DupValue(ctx, this_val);
if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
JSObject *p = JS_VALUE_GET_OBJ(this_val);
if (p->class_id == JS_CLASS_BIG_DECIMAL) {
if (JS_IsBigDecimal(p->u.object_data))
return JS_DupValue(ctx, p->u.object_data);
}
}
return JS_ThrowTypeError(ctx, "not a bigdecimal");
}
static JSValue js_bigdecimal_toString(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValue val;
val = js_thisBigDecimalValue(ctx, this_val);
if (JS_IsException(val))
return val;
return JS_ToStringFree(ctx, val);
}
static JSValue js_bigdecimal_valueOf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
return js_thisBigDecimalValue(ctx, this_val);
}
static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj)
{
const char *str;
size_t size;
int rnd_mode;
str = JS_ToCStringLen(ctx, &size, obj);
if (!str)
return -1;
if (strlen(str) != size)
goto invalid_rounding_mode;
if (!strcmp(str, "floor")) {
rnd_mode = BF_RNDD;
} else if (!strcmp(str, "ceiling")) {
rnd_mode = BF_RNDU;
} else if (!strcmp(str, "down")) {
rnd_mode = BF_RNDZ;
} else if (!strcmp(str, "up")) {
rnd_mode = BF_RNDA;
} else if (!strcmp(str, "half-even")) {
rnd_mode = BF_RNDN;
} else if (!strcmp(str, "half-up")) {
rnd_mode = BF_RNDNA;
} else {
invalid_rounding_mode:
JS_FreeCString(ctx, str);
JS_ThrowTypeError(ctx, "invalid rounding mode");
return -1;
}
JS_FreeCString(ctx, str);
return rnd_mode;
}
typedef struct {
int64_t prec;
bf_flags_t flags;
} BigDecimalEnv;
static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe,
JSValueConst obj)
{
JSValue prop;
int64_t val;
BOOL has_prec;
int rnd_mode;
if (!JS_IsObject(obj)) {
JS_ThrowTypeErrorNotAnObject(ctx);
return -1;
}
prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode);
if (JS_IsException(prop))
return -1;
rnd_mode = js_bigdecimal_get_rnd_mode(ctx, prop);
JS_FreeValue(ctx, prop);
if (rnd_mode < 0)
return -1;
fe->flags = rnd_mode;
prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits);
if (JS_IsException(prop))
return -1;
has_prec = FALSE;
if (!JS_IsUndefined(prop)) {
if (JS_ToInt64SatFree(ctx, &val, prop))
return -1;
if (val < 1 || val > BF_PREC_MAX)
goto invalid_precision;
fe->prec = val;
has_prec = TRUE;
}
prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumFractionDigits);
if (JS_IsException(prop))
return -1;
if (!JS_IsUndefined(prop)) {
if (has_prec) {
JS_FreeValue(ctx, prop);
JS_ThrowTypeError(ctx, "cannot provide both maximumSignificantDigits and maximumFractionDigits");
return -1;
}
if (JS_ToInt64SatFree(ctx, &val, prop))
return -1;
if (val < 0 || val > BF_PREC_MAX) {
invalid_precision:
JS_ThrowTypeError(ctx, "invalid precision");
return -1;
}
fe->prec = val;
fe->flags |= BF_FLAG_RADPNT_PREC;
has_prec = TRUE;
}
if (!has_prec) {
JS_ThrowTypeError(ctx, "precision must be present");
return -1;
}
return 0;
}
static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
bfdec_t *a, *b, r_s, *r = &r_s;
JSValue op1, op2, res;
BigDecimalEnv fe_s, *fe = &fe_s;
int op_count, ret;
if (magic == MATH_OP_SQRT ||
magic == MATH_OP_ROUND)
op_count = 1;
else
op_count = 2;
op1 = JS_ToNumeric(ctx, argv[0]);
if (JS_IsException(op1))
return op1;
a = JS_ToBigDecimal(ctx, op1);
if (!a) {
JS_FreeValue(ctx, op1);
return JS_EXCEPTION;
}
if (op_count >= 2) {
op2 = JS_ToNumeric(ctx, argv[1]);
if (JS_IsException(op2)) {
JS_FreeValue(ctx, op1);
return op2;
}
b = JS_ToBigDecimal(ctx, op2);
if (!b)
goto fail;
} else {
op2 = JS_UNDEFINED;
b = NULL;
}
fe->flags = BF_RNDZ;
fe->prec = BF_PREC_INF;
if (op_count < argc) {
if (js_bigdecimal_get_env(ctx, fe, argv[op_count]))
goto fail;
}
res = JS_NewBigDecimal(ctx);
if (JS_IsException(res)) {
fail:
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
return JS_EXCEPTION;
}
r = JS_GetBigDecimal(res);
switch (magic) {
case MATH_OP_ADD:
ret = bfdec_add(r, a, b, fe->prec, fe->flags);
break;
case MATH_OP_SUB:
ret = bfdec_sub(r, a, b, fe->prec, fe->flags);
break;
case MATH_OP_MUL:
ret = bfdec_mul(r, a, b, fe->prec, fe->flags);
break;
case MATH_OP_DIV:
ret = bfdec_div(r, a, b, fe->prec, fe->flags);
break;
case MATH_OP_FMOD:
ret = bfdec_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
break;
case MATH_OP_SQRT:
ret = bfdec_sqrt(r, a, fe->prec, fe->flags);
break;
case MATH_OP_ROUND:
ret = bfdec_set(r, a);
if (!(ret & BF_ST_MEM_ERROR))
ret = bfdec_round(r, fe->prec, fe->flags);
break;
default:
abort();
}
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP |
BF_ST_OVERFLOW;
if (ret != 0) {
JS_FreeValue(ctx, res);
return throw_bf_exception(ctx, ret);
} else {
return res;
}
}
static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValue val, ret;
int64_t f;
int rnd_mode;
val = js_thisBigDecimalValue(ctx, this_val);
if (JS_IsException(val))
return val;
if (JS_ToInt64Sat(ctx, &f, argv[0]))
goto fail;
if (f < 0 || f > BF_PREC_MAX) {
JS_ThrowRangeError(ctx, "invalid number of digits");
goto fail;
}
rnd_mode = BF_RNDNA;
if (argc > 1) {
rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
if (rnd_mode < 0)
goto fail;
}
ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
JS_FreeValue(ctx, val);
return ret;
fail:
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
static JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValue val, ret;
int64_t f;
int rnd_mode;
val = js_thisBigDecimalValue(ctx, this_val);
if (JS_IsException(val))
return val;
if (JS_ToInt64Sat(ctx, &f, argv[0]))
goto fail;
if (JS_IsUndefined(argv[0])) {
ret = js_bigdecimal_to_string1(ctx, val, 0,
BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
} else {
if (f < 0 || f > BF_PREC_MAX) {
JS_ThrowRangeError(ctx, "invalid number of digits");
goto fail;
}
rnd_mode = BF_RNDNA;
if (argc > 1) {
rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
if (rnd_mode < 0)
goto fail;
}
ret = js_bigdecimal_to_string1(ctx, val, f + 1,
rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
}
JS_FreeValue(ctx, val);
return ret;
fail:
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
static JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValue val, ret;
int64_t p;
int rnd_mode;
val = js_thisBigDecimalValue(ctx, this_val);
if (JS_IsException(val))
return val;
if (JS_IsUndefined(argv[0])) {
return JS_ToStringFree(ctx, val);
}
if (JS_ToInt64Sat(ctx, &p, argv[0]))
goto fail;
if (p < 1 || p > BF_PREC_MAX) {
JS_ThrowRangeError(ctx, "invalid number of digits");
goto fail;
}
rnd_mode = BF_RNDNA;
if (argc > 1) {
rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
if (rnd_mode < 0)
goto fail;
}
ret = js_bigdecimal_to_string1(ctx, val, p,
rnd_mode | BF_FTOA_FORMAT_FIXED);
JS_FreeValue(ctx, val);
return ret;
fail:
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = {
JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ),
JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ),
JS_CFUNC_DEF("toPrecision", 1, js_bigdecimal_toPrecision ),
JS_CFUNC_DEF("toFixed", 1, js_bigdecimal_toFixed ),
JS_CFUNC_DEF("toExponential", 1, js_bigdecimal_toExponential ),
};
static const JSCFunctionListEntry js_bigdecimal_funcs[] = {
JS_CFUNC_MAGIC_DEF("add", 2, js_bigdecimal_fop, MATH_OP_ADD ),
JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ),
JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ),
JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ),
JS_CFUNC_MAGIC_DEF("mod", 2, js_bigdecimal_fop, MATH_OP_FMOD ),
JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ),
JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ),
};
static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,
int radix, int flags, slimb_t *pexponent)
{
bfdec_t *a;
int ret;
JSValue val;
val = JS_NewBigDecimal(ctx);
if (JS_IsException(val))
return val;
a = JS_GetBigDecimal(val);
ret = bfdec_atof(a, buf, NULL, BF_PREC_INF,
BF_RNDZ | BF_ATOF_NO_NAN_INF);
if (ret & BF_ST_MEM_ERROR) {
JS_FreeValue(ctx, val);
return JS_ThrowOutOfMemory(ctx);
}
return val;
}
static int js_unary_arith_bigdecimal(JSContext *ctx,
JSValue *pres, OPCodeEnum op, JSValue op1)
{
bfdec_t *r, *a;
int ret, v;
JSValue res;
if (op == OP_plus && !is_math_mode(ctx)) {
JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
JS_FreeValue(ctx, op1);
return -1;
}
res = JS_NewBigDecimal(ctx);
if (JS_IsException(res)) {
JS_FreeValue(ctx, op1);
return -1;
}
r = JS_GetBigDecimal(res);
a = JS_ToBigDecimal(ctx, op1);
ret = 0;
switch(op) {
case OP_inc:
case OP_dec:
v = 2 * (op - OP_dec) - 1;
ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
break;
case OP_plus:
ret = bfdec_set(r, a);
break;
case OP_neg:
ret = bfdec_set(r, a);
bfdec_neg(r);
break;
default:
abort();
}
JS_FreeValue(ctx, op1);
if (UNLIKELY(ret)) {
JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
*pres = res;
return 0;
}
/* b must be a positive integer */
static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b)
{
bfdec_t b1;
int32_t b2;
int ret;
bfdec_init(b->ctx, &b1);
ret = bfdec_set(&b1, b);
if (ret) {
bfdec_delete(&b1);
return ret;
}
ret = bfdec_rint(&b1, BF_RNDZ);
if (ret) {
bfdec_delete(&b1);
return BF_ST_INVALID_OP; /* must be an integer */
}
ret = bfdec_get_int32(&b2, &b1);
bfdec_delete(&b1);
if (ret)
return ret; /* overflow */
if (b2 < 0)
return BF_ST_INVALID_OP; /* must be positive */
return bfdec_pow_ui(r, a, b2);
}
static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
JSValue op1, JSValue op2)
{
bfdec_t *a, *b;
int res;
/* Note: binary floats are converted to bigdecimal with
toString(). It is not mathematically correct but is consistent
with the BigDecimal() constructor behavior */
op1 = JS_ToBigDecimalFree(ctx, op1, TRUE);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
return -1;
}
op2 = JS_ToBigDecimalFree(ctx, op2, TRUE);
if (JS_IsException(op2)) {
JS_FreeValue(ctx, op1);
return -1;
}
a = JS_ToBigDecimal(ctx, op1);
b = JS_ToBigDecimal(ctx, op2);
switch(op) {
case OP_lt:
res = bfdec_cmp_lt(a, b); /* if NaN return false */
break;
case OP_lte:
res = bfdec_cmp_le(a, b); /* if NaN return false */
break;
case OP_gt:
res = bfdec_cmp_lt(b, a); /* if NaN return false */
break;
case OP_gte:
res = bfdec_cmp_le(b, a); /* if NaN return false */
break;
case OP_eq:
res = bfdec_cmp_eq(a, b); /* if NaN return false */
break;
default:
abort();
}
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
return res;
}
static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
JSValue *pres, JSValue op1, JSValue op2)
{
bfdec_t *r, *a, *b;
int ret;
JSValue res;
res = JS_NewBigDecimal(ctx);
if (JS_IsException(res))
goto fail;
r = JS_GetBigDecimal(res);
a = JS_ToBigDecimal(ctx, op1);
if (!a)
goto fail;
b = JS_ToBigDecimal(ctx, op2);
if (!b)
goto fail;
switch(op) {
case OP_add:
ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);
break;
case OP_sub:
ret = bfdec_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
break;
case OP_mul:
ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
break;
case OP_div:
ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);
break;
case OP_math_mod:
/* Euclidian remainder */
ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN);
break;
case OP_mod:
ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
break;
case OP_pow:
ret = js_bfdec_pow(r, a, b);
break;
default:
abort();
}
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
if (UNLIKELY(ret)) {
JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
*pres = res;
return 0;
fail:
JS_FreeValue(ctx, res);
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
return -1;
}
void JS_AddIntrinsicBigDecimal(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
JSValueConst obj1;
rt->bigdecimal_ops.to_string = js_bigdecimal_to_string;
rt->bigdecimal_ops.from_string = js_string_to_bigdecimal;
rt->bigdecimal_ops.unary_arith = js_unary_arith_bigdecimal;
rt->bigdecimal_ops.binary_arith = js_binary_arith_bigdecimal;
rt->bigdecimal_ops.compare = js_compare_bigdecimal;
ctx->class_proto[JS_CLASS_BIG_DECIMAL] = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL],
js_bigdecimal_proto_funcs,
countof(js_bigdecimal_proto_funcs));
obj1 = JS_NewGlobalCConstructor(ctx, "BigDecimal",
js_bigdecimal_constructor, 1,
ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
JS_SetPropertyFunctionList(ctx, obj1, js_bigdecimal_funcs,
countof(js_bigdecimal_funcs));
}
void JS_EnableBignumExt(JSContext *ctx, BOOL enable)
{
ctx->bignum_ext = enable;
}

View file

@ -1,851 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/runtime/runtime.h"
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
JSValue JS_NewBigInt(JSContext *ctx)
{
JSBigFloat *p;
p = js_malloc(ctx, sizeof(*p));
if (!p)
return JS_EXCEPTION;
p->header.ref_count = 1;
bf_init(ctx->bf_ctx, &p->num);
return JS_MKPTR(JS_TAG_BIG_INT, p);
}
static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
BOOL convert_to_safe_integer)
{
int64_t v;
bf_t *a;
if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
return val; /* fail safe */
a = JS_GetBigInt(val);
if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 &&
v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
JS_FreeValue(ctx, val);
return JS_NewInt64(ctx, v);
} else if (a->expn == BF_EXP_ZERO && a->sign) {
JSBigFloat *p = JS_VALUE_GET_PTR(val);
(void)p;
assert(p->header.ref_count == 1);
a->sign = 0;
}
return val;
}
/* Convert the big int to a safe integer if in math mode. normalize
the zero representation. Could also be used to convert the bigint
to a short bigint value. The reference count of the value must be
1. Cannot fail */
JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
{
return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
}
/* return NaN if bad bigint literal */
JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
{
const char *str, *p;
size_t len;
int flags;
str = JS_ToCStringLen(ctx, &len, val);
JS_FreeValue(ctx, val);
if (!str)
return JS_EXCEPTION;
p = str;
p += skip_spaces(p);
if ((p - str) == len) {
val = JS_NewBigInt64(ctx, 0);
} else {
flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
if (is_math_mode(ctx))
flags |= ATOD_MODE_BIGINT;
val = js_atof(ctx, p, &p, 0, flags);
p += skip_spaces(p);
if (!JS_IsException(val)) {
if ((p - str) != len) {
JS_FreeValue(ctx, val);
val = JS_NAN;
}
}
}
JS_FreeCString(ctx, str);
return val;
}
static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val)
{
val = JS_StringToBigInt(ctx, val);
if (JS_VALUE_IS_NAN(val))
return JS_ThrowSyntaxError(ctx, "invalid bigint literal");
return val;
}
static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
{
uint32_t tag;
redo:
tag = JS_VALUE_GET_NORM_TAG(val);
switch(tag) {
case JS_TAG_INT:
case JS_TAG_BOOL:
val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
break;
case JS_TAG_BIG_INT:
break;
case JS_TAG_FLOAT64:
case JS_TAG_BIG_FLOAT:
{
bf_t *a, a_s;
a = JS_ToBigFloat(ctx, &a_s, val);
if (!bf_is_finite(a)) {
JS_FreeValue(ctx, val);
val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint");
} else {
JSValue val1 = JS_NewBigInt(ctx);
bf_t *r;
int ret;
if (JS_IsException(val1)) {
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
r = JS_GetBigInt(val1);
ret = bf_set(r, a);
ret |= bf_rint(r, BF_RNDZ);
JS_FreeValue(ctx, val);
if (ret & BF_ST_MEM_ERROR) {
JS_FreeValue(ctx, val1);
val = JS_ThrowOutOfMemory(ctx);
} else if (ret & BF_ST_INEXACT) {
JS_FreeValue(ctx, val1);
val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer");
} else {
val = JS_CompactBigInt(ctx, val1);
}
}
if (a == &a_s)
bf_delete(a);
}
break;
case JS_TAG_BIG_DECIMAL:
val = JS_ToStringFree(ctx, val);
if (JS_IsException(val))
break;
goto redo;
case JS_TAG_STRING:
val = JS_StringToBigIntErr(ctx, val);
break;
case JS_TAG_OBJECT:
val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
if (JS_IsException(val))
break;
goto redo;
case JS_TAG_NULL:
case JS_TAG_UNDEFINED:
default:
JS_FreeValue(ctx, val);
return JS_ThrowTypeError(ctx, "cannot convert to bigint");
}
return val;
}
static JSValue js_bigint_constructor(JSContext *ctx,
JSValueConst new_target,
int argc, JSValueConst *argv)
{
if (!JS_IsUndefined(new_target))
return JS_ThrowTypeError(ctx, "not a constructor");
return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
}
static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
{
if (JS_IsBigInt(ctx, this_val))
return JS_DupValue(ctx, this_val);
if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
JSObject *p = JS_VALUE_GET_OBJ(this_val);
if (p->class_id == JS_CLASS_BIG_INT) {
if (JS_IsBigInt(ctx, p->u.object_data))
return JS_DupValue(ctx, p->u.object_data);
}
}
return JS_ThrowTypeError(ctx, "not a bigint");
}
static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValue val;
int base;
JSValue ret;
val = js_thisBigIntValue(ctx, this_val);
if (JS_IsException(val))
return val;
if (argc == 0 || JS_IsUndefined(argv[0])) {
base = 10;
} else {
base = js_get_radix(ctx, argv[0]);
if (base < 0)
goto fail;
}
ret = js_bigint_to_string1(ctx, val, base);
JS_FreeValue(ctx, val);
return ret;
fail:
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
return js_thisBigIntValue(ctx, this_val);
}
static JSValue js_bigint_div(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
bf_t a_s, b_s, *a, *b, *r, *q;
int status;
JSValue q_val, r_val;
q_val = JS_NewBigInt(ctx);
if (JS_IsException(q_val))
return JS_EXCEPTION;
r_val = JS_NewBigInt(ctx);
if (JS_IsException(r_val))
goto fail;
b = NULL;
a = JS_ToBigInt(ctx, &a_s, argv[0]);
if (!a)
goto fail;
b = JS_ToBigInt(ctx, &b_s, argv[1]);
if (!b) {
JS_FreeBigInt(ctx, a, &a_s);
goto fail;
}
q = JS_GetBigInt(q_val);
r = JS_GetBigInt(r_val);
status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf);
JS_FreeBigInt(ctx, a, &a_s);
JS_FreeBigInt(ctx, b, &b_s);
if (UNLIKELY(status)) {
throw_bf_exception(ctx, status);
goto fail;
}
q_val = JS_CompactBigInt(ctx, q_val);
if (magic & 0x10) {
JSValue ret;
ret = JS_NewArray(ctx);
if (JS_IsException(ret))
goto fail;
JS_SetPropertyUint32(ctx, ret, 0, q_val);
JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, r_val));
return ret;
} else {
JS_FreeValue(ctx, r_val);
return q_val;
}
fail:
JS_FreeValue(ctx, q_val);
JS_FreeValue(ctx, r_val);
return JS_EXCEPTION;
}
static JSValue js_bigint_sqrt(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
bf_t a_s, *a, *r, *rem;
int status;
JSValue r_val, rem_val;
r_val = JS_NewBigInt(ctx);
if (JS_IsException(r_val))
return JS_EXCEPTION;
rem_val = JS_NewBigInt(ctx);
if (JS_IsException(rem_val))
return JS_EXCEPTION;
r = JS_GetBigInt(r_val);
rem = JS_GetBigInt(rem_val);
a = JS_ToBigInt(ctx, &a_s, argv[0]);
if (!a)
goto fail;
status = bf_sqrtrem(r, rem, a);
JS_FreeBigInt(ctx, a, &a_s);
if (UNLIKELY(status & ~BF_ST_INEXACT)) {
throw_bf_exception(ctx, status);
goto fail;
}
r_val = JS_CompactBigInt(ctx, r_val);
if (magic) {
JSValue ret;
ret = JS_NewArray(ctx);
if (JS_IsException(ret))
goto fail;
JS_SetPropertyUint32(ctx, ret, 0, r_val);
JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, rem_val));
return ret;
} else {
JS_FreeValue(ctx, rem_val);
return r_val;
}
fail:
JS_FreeValue(ctx, r_val);
JS_FreeValue(ctx, rem_val);
return JS_EXCEPTION;
}
static JSValue js_bigint_op1(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv,
int magic)
{
bf_t a_s, *a;
int64_t res;
a = JS_ToBigInt(ctx, &a_s, argv[0]);
if (!a)
return JS_EXCEPTION;
switch(magic) {
case 0: /* floorLog2 */
if (a->sign || a->expn <= 0) {
res = -1;
} else {
res = a->expn - 1;
}
break;
case 1: /* ctz */
if (bf_is_zero(a)) {
res = -1;
} else {
res = bf_get_exp_min(a);
}
break;
default:
abort();
}
JS_FreeBigInt(ctx, a, &a_s);
return JS_NewBigInt64(ctx, res);
}
static JSValue js_bigint_asUintN(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv, int asIntN)
{
uint64_t bits;
bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s;
JSValue res;
if (JS_ToIndex(ctx, &bits, argv[0]))
return JS_EXCEPTION;
res = JS_NewBigInt(ctx);
if (JS_IsException(res))
return JS_EXCEPTION;
r = JS_GetBigInt(res);
a = JS_ToBigInt(ctx, &a_s, argv[1]);
if (!a) {
JS_FreeValue(ctx, res);
return JS_EXCEPTION;
}
/* XXX: optimize */
r = JS_GetBigInt(res);
bf_init(ctx->bf_ctx, mask);
bf_set_ui(mask, 1);
bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
bf_add_si(mask, mask, -1, BF_PREC_INF, BF_RNDZ);
bf_logic_and(r, a, mask);
if (asIntN && bits != 0) {
bf_set_ui(mask, 1);
bf_mul_2exp(mask, bits - 1, BF_PREC_INF, BF_RNDZ);
if (bf_cmpu(r, mask) >= 0) {
bf_set_ui(mask, 1);
bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
bf_sub(r, r, mask, BF_PREC_INF, BF_RNDZ);
}
}
bf_delete(mask);
JS_FreeBigInt(ctx, a, &a_s);
return JS_CompactBigInt(ctx, res);
}
static const JSCFunctionListEntry js_bigint_funcs[] = {
JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ),
JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ),
/* QuickJS extensions */
JS_CFUNC_MAGIC_DEF("tdiv", 2, js_bigint_div, BF_RNDZ ),
JS_CFUNC_MAGIC_DEF("fdiv", 2, js_bigint_div, BF_RNDD ),
JS_CFUNC_MAGIC_DEF("cdiv", 2, js_bigint_div, BF_RNDU ),
JS_CFUNC_MAGIC_DEF("ediv", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN ),
JS_CFUNC_MAGIC_DEF("tdivrem", 2, js_bigint_div, BF_RNDZ | 0x10 ),
JS_CFUNC_MAGIC_DEF("fdivrem", 2, js_bigint_div, BF_RNDD | 0x10 ),
JS_CFUNC_MAGIC_DEF("cdivrem", 2, js_bigint_div, BF_RNDU | 0x10 ),
JS_CFUNC_MAGIC_DEF("edivrem", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN | 0x10 ),
JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigint_sqrt, 0 ),
JS_CFUNC_MAGIC_DEF("sqrtrem", 1, js_bigint_sqrt, 1 ),
JS_CFUNC_MAGIC_DEF("floorLog2", 1, js_bigint_op1, 0 ),
JS_CFUNC_MAGIC_DEF("ctz", 1, js_bigint_op1, 1 ),
};
static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
JS_CFUNC_DEF("toString", 0, js_bigint_toString ),
JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ),
};
static JSValue js_string_to_bigint(JSContext *ctx, const char *buf,
int radix, int flags, slimb_t *pexponent)
{
bf_t a_s, *a = &a_s;
int ret;
JSValue val;
val = JS_NewBigInt(ctx);
if (JS_IsException(val))
return val;
a = JS_GetBigInt(val);
ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);
if (ret & BF_ST_MEM_ERROR) {
JS_FreeValue(ctx, val);
return JS_ThrowOutOfMemory(ctx);
}
val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0);
return val;
}
static int js_unary_arith_bigint(JSContext *ctx,
JSValue *pres, OPCodeEnum op, JSValue op1)
{
bf_t a_s, *r, *a;
int ret, v;
JSValue res;
if (op == OP_plus && !is_math_mode(ctx)) {
JS_ThrowTypeError(ctx, "bigint argument with unary +");
JS_FreeValue(ctx, op1);
return -1;
}
res = JS_NewBigInt(ctx);
if (JS_IsException(res)) {
JS_FreeValue(ctx, op1);
return -1;
}
r = JS_GetBigInt(res);
a = JS_ToBigInt(ctx, &a_s, op1);
ret = 0;
switch(op) {
case OP_inc:
case OP_dec:
v = 2 * (op - OP_dec) - 1;
ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
break;
case OP_plus:
ret = bf_set(r, a);
break;
case OP_neg:
ret = bf_set(r, a);
bf_neg(r);
break;
case OP_not:
ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ);
bf_neg(r);
break;
default:
abort();
}
JS_FreeBigInt(ctx, a, &a_s);
JS_FreeValue(ctx, op1);
if (UNLIKELY(ret)) {
JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
res = JS_CompactBigInt(ctx, res);
*pres = res;
return 0;
}
/* try to call the operation on the operatorSet field of 'obj'. Only
used for "/" and "**" on the BigInt prototype in math mode */
static __exception int js_call_binary_op_simple(JSContext *ctx,
JSValue *pret,
JSValueConst obj,
JSValueConst op1,
JSValueConst op2,
OPCodeEnum op)
{
JSValue opset1_obj, method, ret, new_op1, new_op2;
JSOperatorSetData *opset1;
JSOverloadableOperatorEnum ovop;
JSObject *p;
JSValueConst args[2];
opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
if (JS_IsException(opset1_obj))
goto exception;
if (JS_IsUndefined(opset1_obj))
return 0;
opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
if (!opset1)
goto exception;
ovop = get_ovop_from_opcode(op);
p = opset1->self_ops[ovop];
if (!p) {
JS_FreeValue(ctx, opset1_obj);
return 0;
}
new_op1 = JS_ToNumeric(ctx, op1);
if (JS_IsException(new_op1))
goto exception;
new_op2 = JS_ToNumeric(ctx, op2);
if (JS_IsException(new_op2)) {
JS_FreeValue(ctx, new_op1);
goto exception;
}
method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
args[0] = new_op1;
args[1] = new_op2;
ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
JS_FreeValue(ctx, new_op1);
JS_FreeValue(ctx, new_op2);
if (JS_IsException(ret))
goto exception;
JS_FreeValue(ctx, opset1_obj);
*pret = ret;
return 1;
exception:
JS_FreeValue(ctx, opset1_obj);
*pret = JS_UNDEFINED;
return -1;
}
static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
JSValue *pres, JSValue op1, JSValue op2)
{
bf_t a_s, b_s, *r, *a, *b;
int ret;
JSValue res;
res = JS_NewBigInt(ctx);
if (JS_IsException(res))
goto fail;
a = JS_ToBigInt(ctx, &a_s, op1);
if (!a)
goto fail;
b = JS_ToBigInt(ctx, &b_s, op2);
if (!b) {
JS_FreeBigInt(ctx, a, &a_s);
goto fail;
}
r = JS_GetBigInt(res);
ret = 0;
switch(op) {
case OP_add:
ret = bf_add(r, a, b, BF_PREC_INF, BF_RNDZ);
break;
case OP_sub:
ret = bf_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
break;
case OP_mul:
ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
break;
case OP_div:
if (!is_math_mode(ctx)) {
bf_t rem_s, *rem = &rem_s;
bf_init(ctx->bf_ctx, rem);
ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ,
BF_RNDZ);
bf_delete(rem);
} else {
goto math_mode_div_pow;
}
break;
case OP_math_mod:
/* Euclidian remainder */
ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP;
break;
case OP_mod:
ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
BF_RNDZ) & BF_ST_INVALID_OP;
break;
case OP_pow:
if (b->sign) {
if (!is_math_mode(ctx)) {
ret = BF_ST_INVALID_OP;
} else {
math_mode_div_pow:
JS_FreeValue(ctx, res);
ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op);
if (ret != 0) {
JS_FreeBigInt(ctx, a, &a_s);
JS_FreeBigInt(ctx, b, &b_s);
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
if (ret < 0) {
return -1;
} else {
*pres = res;
return 0;
}
}
/* if no BigInt power operator defined, return a
bigfloat */
res = JS_NewBigFloat(ctx);
if (JS_IsException(res)) {
JS_FreeBigInt(ctx, a, &a_s);
JS_FreeBigInt(ctx, b, &b_s);
goto fail;
}
r = JS_GetBigFloat(res);
if (op == OP_div) {
ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR;
} else {
ret = bf_pow(r, a, b, ctx->fp_env.prec,
ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR;
}
JS_FreeBigInt(ctx, a, &a_s);
JS_FreeBigInt(ctx, b, &b_s);
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
if (UNLIKELY(ret)) {
JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
*pres = res;
return 0;
}
} else {
ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
}
break;
/* logical operations */
case OP_shl:
case OP_sar:
{
slimb_t v2;
#if LIMB_BITS == 32
bf_get_int32(&v2, b, 0);
if (v2 == INT32_MIN)
v2 = INT32_MIN + 1;
#else
bf_get_int64(&v2, b, 0);
if (v2 == INT64_MIN)
v2 = INT64_MIN + 1;
#endif
if (op == OP_sar)
v2 = -v2;
ret = bf_set(r, a);
ret |= bf_mul_2exp(r, v2, BF_PREC_INF, BF_RNDZ);
if (v2 < 0) {
ret |= bf_rint(r, BF_RNDD) & (BF_ST_OVERFLOW | BF_ST_MEM_ERROR);
}
}
break;
case OP_and:
ret = bf_logic_and(r, a, b);
break;
case OP_or:
ret = bf_logic_or(r, a, b);
break;
case OP_xor:
ret = bf_logic_xor(r, a, b);
break;
default:
abort();
}
JS_FreeBigInt(ctx, a, &a_s);
JS_FreeBigInt(ctx, b, &b_s);
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
if (UNLIKELY(ret)) {
JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
*pres = JS_CompactBigInt(ctx, res);
return 0;
fail:
JS_FreeValue(ctx, res);
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
return -1;
}
void JS_AddIntrinsicBigInt(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
JSValueConst obj1;
rt->bigint_ops.to_string = js_bigint_to_string;
rt->bigint_ops.from_string = js_string_to_bigint;
rt->bigint_ops.unary_arith = js_unary_arith_bigint;
rt->bigint_ops.binary_arith = js_binary_arith_bigint;
rt->bigint_ops.compare = js_compare_bigfloat;
ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
js_bigint_proto_funcs,
countof(js_bigint_proto_funcs));
obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1,
ctx->class_proto[JS_CLASS_BIG_INT]);
JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs,
countof(js_bigint_funcs));
}
/* if the returned bigfloat is allocated it is equal to
'buf'. Otherwise it is a pointer to the bigfloat in 'val'. */
static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
{
uint32_t tag;
bf_t *r;
JSBigFloat *p;
redo:
tag = JS_VALUE_GET_NORM_TAG(val);
switch(tag) {
case JS_TAG_INT:
case JS_TAG_NULL:
case JS_TAG_UNDEFINED:
if (!is_math_mode(ctx))
goto fail;
/* fall tru */
case JS_TAG_BOOL:
r = buf;
bf_init(ctx->bf_ctx, r);
bf_set_si(r, JS_VALUE_GET_INT(val));
break;
case JS_TAG_FLOAT64:
{
double d = JS_VALUE_GET_FLOAT64(val);
if (!is_math_mode(ctx))
goto fail;
if (!isfinite(d))
goto fail;
r = buf;
bf_init(ctx->bf_ctx, r);
d = trunc(d);
bf_set_float64(r, d);
}
break;
case JS_TAG_BIG_INT:
p = JS_VALUE_GET_PTR(val);
r = &p->num;
break;
case JS_TAG_BIG_FLOAT:
if (!is_math_mode(ctx))
goto fail;
p = JS_VALUE_GET_PTR(val);
if (!bf_is_finite(&p->num))
goto fail;
r = buf;
bf_init(ctx->bf_ctx, r);
bf_set(r, &p->num);
bf_rint(r, BF_RNDZ);
JS_FreeValue(ctx, val);
break;
case JS_TAG_STRING:
val = JS_StringToBigIntErr(ctx, val);
if (JS_IsException(val))
return NULL;
goto redo;
case JS_TAG_OBJECT:
val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
if (JS_IsException(val))
return NULL;
goto redo;
default:
fail:
JS_FreeValue(ctx, val);
JS_ThrowTypeError(ctx, "cannot convert to bigint");
return NULL;
}
return r;
}
bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val)
{
return JS_ToBigIntFree(ctx, buf, JS_DupValue(ctx, val));
}
static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val)
{
if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
return val;
} else {
bf_t a_s, *a, *r;
int ret;
JSValue res;
res = JS_NewBigInt(ctx);
if (JS_IsException(res))
return JS_EXCEPTION;
a = JS_ToBigIntFree(ctx, &a_s, val);
if (!a) {
JS_FreeValue(ctx, res);
return JS_EXCEPTION;
}
r = JS_GetBigInt(res);
ret = bf_set(r, a);
JS_FreeBigInt(ctx, a, &a_s);
if (ret) {
JS_FreeValue(ctx, res);
return JS_ThrowOutOfMemory(ctx);
}
return JS_CompactBigInt(ctx, res);
}
}
/* free the bf_t allocated by JS_ToBigInt */
void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf)
{
if (a == buf) {
bf_delete(a);
} else {
JSBigFloat *p = (JSBigFloat *)((uint8_t *)a -
offsetof(JSBigFloat, num));
JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_FLOAT, p));
}
}
/* XXX: merge with JS_ToInt64Free with a specific flag */
int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
{
bf_t a_s, *a;
a = JS_ToBigIntFree(ctx, &a_s, val);
if (!a) {
*pres = 0;
return -1;
}
bf_get_int64(pres, a, BF_GET_INT_MOD);
JS_FreeBigInt(ctx, a, &a_s);
return 0;
}
int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
{
return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val));
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,515 +0,0 @@
/*
* C utilities
*
* Copyright (c) 2017 Fabrice Bellard
* Copyright (c) 2018 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "third_party/quickjs/cutils.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
void pstrcpy(char *buf, int buf_size, const char *str)
{
int c;
char *q = buf;
if (buf_size <= 0)
return;
for(;;) {
c = *str++;
if (c == 0 || q >= buf + buf_size - 1)
break;
*q++ = c;
}
*q = '\0';
}
/* strcat and truncate. */
char *pstrcat(char *buf, int buf_size, const char *s)
{
int len;
len = strlen(buf);
if (len < buf_size)
pstrcpy(buf + len, buf_size - len, s);
return buf;
}
int strstart(const char *str, const char *val, const char **ptr)
{
const char *p, *q;
p = str;
q = val;
while (*q != '\0') {
if (*p != *q)
return 0;
p++;
q++;
}
if (ptr)
*ptr = p;
return 1;
}
int has_suffix(const char *str, const char *suffix)
{
size_t len = strlen(str);
size_t slen = strlen(suffix);
return (len >= slen && !memcmp(str + len - slen, suffix, slen));
}
/* Dynamic buffer package */
/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes
are output. */
int unicode_to_utf8(uint8_t *buf, unsigned int c)
{
uint8_t *q = buf;
if (c < 0x80) {
*q++ = c;
} else {
if (c < 0x800) {
*q++ = (c >> 6) | 0xc0;
} else {
if (c < 0x10000) {
*q++ = (c >> 12) | 0xe0;
} else {
if (c < 0x00200000) {
*q++ = (c >> 18) | 0xf0;
} else {
if (c < 0x04000000) {
*q++ = (c >> 24) | 0xf8;
} else if (c < 0x80000000) {
*q++ = (c >> 30) | 0xfc;
*q++ = ((c >> 24) & 0x3f) | 0x80;
} else {
return 0;
}
*q++ = ((c >> 18) & 0x3f) | 0x80;
}
*q++ = ((c >> 12) & 0x3f) | 0x80;
}
*q++ = ((c >> 6) & 0x3f) | 0x80;
}
*q++ = (c & 0x3f) | 0x80;
}
return q - buf;
}
static const unsigned int utf8_min_code[5] = {
0x80, 0x800, 0x10000, 0x00200000, 0x04000000,
};
static const unsigned char utf8_first_code_mask[5] = {
0x1f, 0xf, 0x7, 0x3, 0x1,
};
/* return -1 if error. *pp is not updated in this case. max_len must
be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
{
int l, c, b, i;
c = *p++;
if (c < 0x80) {
*pp = p;
return c;
}
switch(c) {
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
case 0xc4: case 0xc5: case 0xc6: case 0xc7:
case 0xc8: case 0xc9: case 0xca: case 0xcb:
case 0xcc: case 0xcd: case 0xce: case 0xcf:
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
case 0xd4: case 0xd5: case 0xd6: case 0xd7:
case 0xd8: case 0xd9: case 0xda: case 0xdb:
case 0xdc: case 0xdd: case 0xde: case 0xdf:
l = 1;
break;
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
case 0xe8: case 0xe9: case 0xea: case 0xeb:
case 0xec: case 0xed: case 0xee: case 0xef:
l = 2;
break;
case 0xf0: case 0xf1: case 0xf2: case 0xf3:
case 0xf4: case 0xf5: case 0xf6: case 0xf7:
l = 3;
break;
case 0xf8: case 0xf9: case 0xfa: case 0xfb:
l = 4;
break;
case 0xfc: case 0xfd:
l = 5;
break;
default:
return -1;
}
/* check that we have enough characters */
if (l > (max_len - 1))
return -1;
c &= utf8_first_code_mask[l - 1];
for(i = 0; i < l; i++) {
b = *p++;
if (b < 0x80 || b >= 0xc0)
return -1;
c = (c << 6) | (b & 0x3f);
}
if (c < utf8_min_code[l - 1])
return -1;
*pp = p;
return c;
}
#if 0
#if defined(EMSCRIPTEN) || defined(__ANDROID__)
static void *rqsort_arg;
static int (*rqsort_cmp)(const void *, const void *, void *);
static int rqsort_cmp2(const void *p1, const void *p2)
{
return rqsort_cmp(p1, p2, rqsort_arg);
}
/* not reentrant, but not needed with emscripten */
void rqsort(void *base, size_t nmemb, size_t size,
int (*cmp)(const void *, const void *, void *),
void *arg)
{
rqsort_arg = arg;
rqsort_cmp = cmp;
qsort(base, nmemb, size, rqsort_cmp2);
}
#endif
#else
typedef void (*exchange_f)(void *a, void *b, size_t size);
typedef int (*cmp_f)(const void *, const void *, void *opaque);
static void exchange_bytes(void *a, void *b, size_t size) {
uint8_t *ap = (uint8_t *)a;
uint8_t *bp = (uint8_t *)b;
while (size-- != 0) {
uint8_t t = *ap;
*ap++ = *bp;
*bp++ = t;
}
}
static void exchange_one_byte(void *a, void *b, size_t size) {
uint8_t *ap = (uint8_t *)a;
uint8_t *bp = (uint8_t *)b;
uint8_t t = *ap;
*ap = *bp;
*bp = t;
}
static void exchange_int16s(void *a, void *b, size_t size) {
uint16_t *ap = (uint16_t *)a;
uint16_t *bp = (uint16_t *)b;
for (size /= sizeof(uint16_t); size-- != 0;) {
uint16_t t = *ap;
*ap++ = *bp;
*bp++ = t;
}
}
static void exchange_one_int16(void *a, void *b, size_t size) {
uint16_t *ap = (uint16_t *)a;
uint16_t *bp = (uint16_t *)b;
uint16_t t = *ap;
*ap = *bp;
*bp = t;
}
static void exchange_int32s(void *a, void *b, size_t size) {
uint32_t *ap = (uint32_t *)a;
uint32_t *bp = (uint32_t *)b;
for (size /= sizeof(uint32_t); size-- != 0;) {
uint32_t t = *ap;
*ap++ = *bp;
*bp++ = t;
}
}
static void exchange_one_int32(void *a, void *b, size_t size) {
uint32_t *ap = (uint32_t *)a;
uint32_t *bp = (uint32_t *)b;
uint32_t t = *ap;
*ap = *bp;
*bp = t;
}
static void exchange_int64s(void *a, void *b, size_t size) {
uint64_t *ap = (uint64_t *)a;
uint64_t *bp = (uint64_t *)b;
for (size /= sizeof(uint64_t); size-- != 0;) {
uint64_t t = *ap;
*ap++ = *bp;
*bp++ = t;
}
}
static void exchange_one_int64(void *a, void *b, size_t size) {
uint64_t *ap = (uint64_t *)a;
uint64_t *bp = (uint64_t *)b;
uint64_t t = *ap;
*ap = *bp;
*bp = t;
}
static void exchange_int128s(void *a, void *b, size_t size) {
uint64_t *ap = (uint64_t *)a;
uint64_t *bp = (uint64_t *)b;
for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) {
uint64_t t = ap[0];
uint64_t u = ap[1];
ap[0] = bp[0];
ap[1] = bp[1];
bp[0] = t;
bp[1] = u;
}
}
static void exchange_one_int128(void *a, void *b, size_t size) {
uint64_t *ap = (uint64_t *)a;
uint64_t *bp = (uint64_t *)b;
uint64_t t = ap[0];
uint64_t u = ap[1];
ap[0] = bp[0];
ap[1] = bp[1];
bp[0] = t;
bp[1] = u;
}
static inline exchange_f exchange_func(const void *base, size_t size) {
switch (((uintptr_t)base | (uintptr_t)size) & 15) {
case 0:
if (size == sizeof(uint64_t) * 2)
return exchange_one_int128;
else
return exchange_int128s;
case 8:
if (size == sizeof(uint64_t))
return exchange_one_int64;
else
return exchange_int64s;
case 4:
case 12:
if (size == sizeof(uint32_t))
return exchange_one_int32;
else
return exchange_int32s;
case 2:
case 6:
case 10:
case 14:
if (size == sizeof(uint16_t))
return exchange_one_int16;
else
return exchange_int16s;
default:
if (size == 1)
return exchange_one_byte;
else
return exchange_bytes;
}
}
static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
{
uint8_t *basep = (uint8_t *)base;
size_t i, n, c, r;
exchange_f swap = exchange_func(base, size);
if (nmemb > 1) {
i = (nmemb / 2) * size;
n = nmemb * size;
while (i > 0) {
i -= size;
for (r = i; (c = r * 2 + size) < n; r = c) {
if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0)
c += size;
if (cmp(basep + r, basep + c, opaque) > 0)
break;
swap(basep + r, basep + c, size);
}
}
for (i = n - size; i > 0; i -= size) {
swap(basep, basep + i, size);
for (r = 0; (c = r * 2 + size) < i; r = c) {
if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0)
c += size;
if (cmp(basep + r, basep + c, opaque) > 0)
break;
swap(basep + r, basep + c, size);
}
}
}
}
static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque)
{
return cmp(a, b, opaque) < 0 ?
(cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) :
(cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c ));
}
/* pointer based version with local stack and insertion sort threshhold */
void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
{
struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack;
uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m;
size_t m4, i, lt, gt, span, span2;
int c, depth;
exchange_f swap = exchange_func(base, size);
exchange_f swap_block = exchange_func(base, size | 128);
if (nmemb < 2 || size <= 0)
return;
sp->base = (uint8_t *)base;
sp->count = nmemb;
sp->depth = 0;
sp++;
while (sp > stack) {
sp--;
ptr = sp->base;
nmemb = sp->count;
depth = sp->depth;
while (nmemb > 6) {
if (++depth > 50) {
/* depth check to ensure worst case logarithmic time */
heapsortx(ptr, nmemb, size, cmp, opaque);
nmemb = 0;
break;
}
/* select median of 3 from 1/4, 1/2, 3/4 positions */
/* should use median of 5 or 9? */
m4 = (nmemb >> 2) * size;
m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque);
swap(ptr, m, size); /* move the pivot to the start or the array */
i = lt = 1;
pi = plt = ptr + size;
gt = nmemb;
pj = pgt = top = ptr + nmemb * size;
for (;;) {
while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) {
if (c == 0) {
swap(plt, pi, size);
lt++;
plt += size;
}
i++;
pi += size;
}
while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) {
if (c == 0) {
gt--;
pgt -= size;
swap(pgt, pj, size);
}
}
if (pi >= pj)
break;
swap(pi, pj, size);
i++;
pi += size;
}
/* array has 4 parts:
* from 0 to lt excluded: elements identical to pivot
* from lt to pi excluded: elements smaller than pivot
* from pi to gt excluded: elements greater than pivot
* from gt to n excluded: elements identical to pivot
*/
/* move elements identical to pivot in the middle of the array: */
/* swap values in ranges [0..lt[ and [i-lt..i[
swapping the smallest span between lt and i-lt is sufficient
*/
span = plt - ptr;
span2 = pi - plt;
lt = i - lt;
if (span > span2)
span = span2;
swap_block(ptr, pi - span, span);
/* swap values in ranges [gt..top[ and [i..top-(top-gt)[
swapping the smallest span between top-gt and gt-i is sufficient
*/
span = top - pgt;
span2 = pgt - pi;
pgt = top - span2;
gt = nmemb - (gt - i);
if (span > span2)
span = span2;
swap_block(pi, top - span, span);
/* now array has 3 parts:
* from 0 to lt excluded: elements smaller than pivot
* from lt to gt excluded: elements identical to pivot
* from gt to n excluded: elements greater than pivot
*/
/* stack the larger segment and keep processing the smaller one
to minimize stack use for pathological distributions */
if (lt > nmemb - gt) {
sp->base = ptr;
sp->count = lt;
sp->depth = depth;
sp++;
ptr = pgt;
nmemb -= gt;
} else {
sp->base = pgt;
sp->count = nmemb - gt;
sp->depth = depth;
sp++;
nmemb = lt;
}
}
/* Use insertion sort for small fragments */
for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) {
for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size)
swap(pj, pj - size, size);
}
}
}
#endif

View file

@ -1,259 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_CUTILS_H_
#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_CUTILS_H_
#include "libc/intrin/bswap.h"
COSMOPOLITAN_C_START_
/* set if CPU is big endian */
#undef WORDS_BIGENDIAN
#define __maybe_unused __attribute__((__unused__))
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#define stringify(s) tostring(s)
#define tostring(s) #s
#ifndef countof
#define countof(x) (sizeof(x) / sizeof((x)[0]))
#endif
typedef int BOOL;
#ifndef FALSE
enum {
FALSE = 0,
TRUE = 1,
};
#endif
void pstrcpy(char *, int, const char *);
char *pstrcat(char *, int, const char *);
int strstart(const char *, const char *, const char **);
int has_suffix(const char *, const char *);
static inline int max_int(int a, int b)
{
if (a > b)
return a;
else
return b;
}
static inline int min_int(int a, int b)
{
if (a < b)
return a;
else
return b;
}
static inline uint32_t max_uint32(uint32_t a, uint32_t b)
{
if (a > b)
return a;
else
return b;
}
static inline uint32_t min_uint32(uint32_t a, uint32_t b)
{
if (a < b)
return a;
else
return b;
}
static inline int64_t max_int64(int64_t a, int64_t b)
{
if (a > b)
return a;
else
return b;
}
static inline int64_t min_int64(int64_t a, int64_t b)
{
if (a < b)
return a;
else
return b;
}
/* WARNING: undefined if a = 0 */
forceinline int clz32(unsigned int a)
{
return __builtin_clz(a);
}
/* WARNING: undefined if a = 0 */
forceinline int clz64(uint64_t a)
{
return __builtin_clzll(a);
}
/* WARNING: undefined if a = 0 */
forceinline int ctz32(unsigned int a)
{
return __builtin_ctz(a);
}
/* WARNING: undefined if a = 0 */
forceinline int ctz64(uint64_t a)
{
return __builtin_ctzll(a);
}
struct thatispacked packed_u64 {
uint64_t v;
};
struct thatispacked packed_u32 {
uint32_t v;
};
struct thatispacked packed_u16 {
uint16_t v;
};
static inline uint64_t get_u64(const uint8_t *tab)
{
return ((const struct packed_u64 *)tab)->v;
}
static inline int64_t get_i64(const uint8_t *tab)
{
return (int64_t)((const struct packed_u64 *)tab)->v;
}
static inline void put_u64(uint8_t *tab, uint64_t val)
{
((struct packed_u64 *)tab)->v = val;
}
static inline uint32_t get_u32(const uint8_t *tab)
{
return ((const struct packed_u32 *)tab)->v;
}
static inline int32_t get_i32(const uint8_t *tab)
{
return (int32_t)((const struct packed_u32 *)tab)->v;
}
static inline void put_u32(uint8_t *tab, uint32_t val)
{
((struct packed_u32 *)tab)->v = val;
}
static inline uint32_t get_u16(const uint8_t *tab)
{
return ((const struct packed_u16 *)tab)->v;
}
static inline int32_t get_i16(const uint8_t *tab)
{
return (int16_t)((const struct packed_u16 *)tab)->v;
}
static inline void put_u16(uint8_t *tab, uint16_t val)
{
((struct packed_u16 *)tab)->v = val;
}
static inline uint32_t get_u8(const uint8_t *tab)
{
return *tab;
}
static inline int32_t get_i8(const uint8_t *tab)
{
return (int8_t)*tab;
}
static inline void put_u8(uint8_t *tab, uint8_t val)
{
*tab = val;
}
forceinline uint16_t bswap16(uint16_t x)
{
return bswap_16(x);
}
forceinline uint32_t bswap32(uint32_t v)
{
return bswap_32(v);
}
forceinline uint64_t bswap64(uint64_t v)
{
return bswap_64(v);
}
/* XXX: should take an extra argument to pass slack information to the caller */
typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
typedef struct DynBuf {
uint8_t *buf;
size_t size;
size_t allocated_size;
BOOL error; /* true if a memory allocation error occurred */
DynBufReallocFunc *realloc_func;
void *opaque; /* for realloc_func */
} DynBuf;
void dbuf_init(DynBuf *);
void dbuf_init2(DynBuf *, void *, DynBufReallocFunc *);
int dbuf_realloc(DynBuf *, size_t);
int dbuf_write(DynBuf *, size_t, const uint8_t *, size_t);
int dbuf_put(DynBuf *, const uint8_t *, size_t);
int dbuf_put_self(DynBuf *, size_t, size_t);
int dbuf_putc(DynBuf *, uint8_t);
int dbuf_putstr(DynBuf *, const char *);
int dbuf_printf(DynBuf *, const char *, ...) printfesque(2);
void dbuf_free(DynBuf *);
int unicode_to_utf8(uint8_t *buf, unsigned int c);
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
static inline int dbuf_put_u16(DynBuf *s, uint16_t val) {
return dbuf_put(s, (uint8_t *)&val, 2);
}
static inline int dbuf_put_u32(DynBuf *s, uint32_t val) {
return dbuf_put(s, (uint8_t *)&val, 4);
}
static inline int dbuf_put_u64(DynBuf *s, uint64_t val) {
return dbuf_put(s, (uint8_t *)&val, 8);
}
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
static inline int from_hex(int c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else
return -1;
}
void rqsort(void *base, size_t nmemb, size_t size,
int (*cmp)(const void *, const void *, void *),
void *arg);
/* clang-format on */
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_CUTILS_H_ */

File diff suppressed because it is too large Load diff

View file

@ -1,175 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "third_party/quickjs/internal.h"
#include "third_party/quickjs/libregexp.h"
#include "third_party/quickjs/quickjs.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size)
{
return realloc(ptr, size);
}
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)
{
bzero(s, sizeof(*s));
if (!realloc_func)
realloc_func = dbuf_default_realloc;
s->opaque = opaque;
s->realloc_func = realloc_func;
}
void dbuf_init(DynBuf *s)
{
dbuf_init2(s, NULL, NULL);
}
/* return < 0 if error */
int dbuf_realloc(DynBuf *s, size_t new_size)
{
size_t size;
uint8_t *new_buf;
if (new_size > s->allocated_size) {
if (s->error)
return -1;
size = s->allocated_size * 3 / 2;
if (size > new_size)
new_size = size;
new_buf = s->realloc_func(s->opaque, s->buf, new_size);
if (!new_buf) {
s->error = TRUE;
return -1;
}
s->buf = new_buf;
s->allocated_size = new_size;
}
return 0;
}
int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len)
{
size_t end;
end = offset + len;
if (dbuf_realloc(s, end))
return -1;
memcpy(s->buf + offset, data, len);
if (end > s->size)
s->size = end;
return 0;
}
int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)
{
if (UNLIKELY((s->size + len) > s->allocated_size)) {
if (dbuf_realloc(s, s->size + len))
return -1;
}
memcpy(s->buf + s->size, data, len);
s->size += len;
return 0;
}
int dbuf_put_self(DynBuf *s, size_t offset, size_t len)
{
if (UNLIKELY((s->size + len) > s->allocated_size)) {
if (dbuf_realloc(s, s->size + len))
return -1;
}
memcpy(s->buf + s->size, s->buf + offset, len);
s->size += len;
return 0;
}
int dbuf_putc(DynBuf *s, uint8_t c)
{
return dbuf_put(s, &c, 1);
}
int dbuf_putstr(DynBuf *s, const char *str)
{
return dbuf_put(s, (const uint8_t *)str, strlen(str));
}
int dbuf_printf(DynBuf *s, const char *fmt, ...)
{
va_list ap;
char buf[128];
int len;
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (len < sizeof(buf)) {
/* fast case */
return dbuf_put(s, (uint8_t *)buf, len);
} else {
if (dbuf_realloc(s, s->size + len + 1))
return -1;
va_start(ap, fmt);
vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size,
fmt, ap);
va_end(ap);
s->size += len;
}
return 0;
}
void dbuf_free(DynBuf *s)
{
/* we test s->buf as a fail safe to avoid crashing if dbuf_free()
is called twice */
if (s->buf) {
s->realloc_func(s->opaque, s->buf, 0);
}
bzero(s, sizeof(*s));
}
void dbuf_put_leb128(DynBuf *s, uint32_t v)
{
uint32_t a;
for(;;) {
a = v & 0x7f;
v >>= 7;
if (v != 0) {
dbuf_putc(s, a | 0x80);
} else {
dbuf_putc(s, a);
break;
}
}
}
void dbuf_put_sleb128(DynBuf *s, int32_t v1)
{
uint32_t v = v1;
dbuf_put_leb128(s, (2 * v) ^ -(v >> 31));
}

View file

@ -1,30 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "third_party/quickjs/diglet.h"
int to_digit(int c) {
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'A' && c <= 'Z')
return c - 'A' + 10;
else if (c >= 'a' && c <= 'z')
return c - 'a' + 10;
else
return 36;
}

View file

@ -1,8 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_DIGLET_H_
#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_DIGLET_H_
COSMOPOLITAN_C_START_
int to_digit(int);
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_DIGLET_H_ */

View file

@ -1,734 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
<head>
<title>Javascript Bignum Extensions</title>
<meta name="description" content="Javascript Bignum Extensions">
<meta name="keywords" content="Javascript Bignum Extensions">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
a.summary-letter {text-decoration: none}
blockquote.indentedblock {margin-right: 0em}
blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
blockquote.smallquotation {font-size: smaller}
div.display {margin-left: 3.2em}
div.example {margin-left: 3.2em}
div.lisp {margin-left: 3.2em}
div.smalldisplay {margin-left: 3.2em}
div.smallexample {margin-left: 3.2em}
div.smalllisp {margin-left: 3.2em}
kbd {font-style: oblique}
pre.display {font-family: inherit}
pre.format {font-family: inherit}
pre.menu-comment {font-family: serif}
pre.menu-preformatted {font-family: serif}
pre.smalldisplay {font-family: inherit; font-size: smaller}
pre.smallexample {font-size: smaller}
pre.smallformat {font-family: inherit; font-size: smaller}
pre.smalllisp {font-size: smaller}
span.nolinebreak {white-space: nowrap}
span.roman {font-family: initial; font-weight: normal}
span.sansserif {font-family: sans-serif; font-weight: normal}
ul.no-bullet {list-style: none}
-->
</style>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body lang="en">
<h1 class="settitle" align="center">Javascript Bignum Extensions</h1>
<a name="SEC_Contents"></a>
<h2 class="contents-heading">Table of Contents</h2>
<div class="contents">
<ul class="no-bullet">
<li><a name="toc-Introduction" href="#Introduction">1 Introduction</a></li>
<li><a name="toc-Operator-overloading" href="#Operator-overloading">2 Operator overloading</a></li>
<li><a name="toc-BigInt-extensions" href="#BigInt-extensions">3 BigInt extensions</a></li>
<li><a name="toc-BigFloat" href="#BigFloat">4 BigFloat</a>
<ul class="no-bullet">
<li><a name="toc-Introduction-1" href="#Introduction-1">4.1 Introduction</a></li>
<li><a name="toc-Floating-point-rounding" href="#Floating-point-rounding">4.2 Floating point rounding</a></li>
<li><a name="toc-Operators" href="#Operators">4.3 Operators</a></li>
<li><a name="toc-BigFloat-literals" href="#BigFloat-literals">4.4 BigFloat literals</a></li>
<li><a name="toc-Builtin-Object-changes" href="#Builtin-Object-changes">4.5 Builtin Object changes</a>
<ul class="no-bullet">
<li><a name="toc-BigFloat-function" href="#BigFloat-function">4.5.1 <code>BigFloat</code> function</a></li>
<li><a name="toc-BigFloat_002eprototype" href="#BigFloat_002eprototype">4.5.2 <code>BigFloat.prototype</code></a></li>
<li><a name="toc-BigFloatEnv-constructor" href="#BigFloatEnv-constructor">4.5.3 <code>BigFloatEnv</code> constructor</a></li>
</ul></li>
</ul></li>
<li><a name="toc-BigDecimal" href="#BigDecimal">5 BigDecimal</a>
<ul class="no-bullet">
<li><a name="toc-Operators-1" href="#Operators-1">5.1 Operators</a></li>
<li><a name="toc-BigDecimal-literals" href="#BigDecimal-literals">5.2 BigDecimal literals</a></li>
<li><a name="toc-Builtin-Object-changes-1" href="#Builtin-Object-changes-1">5.3 Builtin Object changes</a>
<ul class="no-bullet">
<li><a name="toc-The-BigDecimal-function_002e" href="#The-BigDecimal-function_002e">5.3.1 The <code>BigDecimal</code> function.</a></li>
<li><a name="toc-Properties-of-the-BigDecimal-object" href="#Properties-of-the-BigDecimal-object">5.3.2 Properties of the <code>BigDecimal</code> object</a></li>
<li><a name="toc-Properties-of-the-BigDecimal_002eprototype-object" href="#Properties-of-the-BigDecimal_002eprototype-object">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</a></li>
</ul></li>
</ul></li>
<li><a name="toc-Math-mode" href="#Math-mode">6 Math mode</a></li>
</ul>
</div>
<a name="Introduction"></a>
<h2 class="chapter">1 Introduction</h2>
<p>The Bignum extensions add the following features to the Javascript
language while being 100% backward compatible:
</p>
<ul>
<li> Operator overloading with a dispatch logic inspired from the proposal available at <a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>.
</li><li> Arbitrarily large floating point numbers (<code>BigFloat</code>) in base 2 using the IEEE 754 semantics.
</li><li> Arbitrarily large floating point numbers (<code>BigDecimal</code>) in base 10 based on the proposal available at
<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
</li><li> <code>math</code> mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (<code>%</code>) is defined as the Euclidian
remainder. <code>^</code> is an alias to the power operator
(<code>**</code>). <code>^^</code> is used as the exclusive or operator.
</li></ul>
<p>The extensions are independent from each other except the <code>math</code>
mode which relies on BigFloat and operator overloading.
</p>
<a name="Operator-overloading"></a>
<h2 class="chapter">2 Operator overloading</h2>
<p>Operator overloading is inspired from the proposal available at
<a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>. It
implements the same dispatch logic but finds the operator sets by
looking at the <code>Symbol.operatorSet</code> property in the objects. The
changes were done in order to simplify the implementation.
</p>
<p>More precisely, the following modifications were made:
</p>
<ul>
<li> <code>with operators from</code> is not supported. Operator overloading is always enabled.
</li><li> The dispatch is not based on a static <code>[[OperatorSet]]</code> field in all instances. Instead, a dynamic lookup of the <code>Symbol.operatorSet</code> property is done. This property is typically added in the prototype of each object.
</li><li> <code>Operators.create(...dictionaries)</code> is used to create a new OperatorSet object. The <code>Operators</code> function is supported as an helper to be closer to the TC39 proposal.
</li><li> <code>[]</code> cannot be overloaded.
</li><li> In math mode, the BigInt division and power operators can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
</li></ul>
<a name="BigInt-extensions"></a>
<h2 class="chapter">3 BigInt extensions</h2>
<p>A few properties are added to the BigInt object:
</p>
<dl compact="compact">
<dt><code>tdiv(a, b)</code></dt>
<dd><p>Return <em>trunc(a/b)</em>. <code>b = 0</code> raises a RangeError
exception.
</p>
</dd>
<dt><code>fdiv(a, b)</code></dt>
<dd><p>Return <em>\lfloor a/b \rfloor</em>. <code>b = 0</code> raises a RangeError
exception.
</p>
</dd>
<dt><code>cdiv(a, b)</code></dt>
<dd><p>Return <em>\lceil a/b \rceil</em>. <code>b = 0</code> raises a RangeError
exception.
</p>
</dd>
<dt><code>ediv(a, b)</code></dt>
<dd><p>Return <em>sgn(b) \lfloor a/{|b|} \rfloor</em> (Euclidian
division). <code>b = 0</code> raises a RangeError exception.
</p>
</dd>
<dt><code>tdivrem(a, b)</code></dt>
<dt><code>fdivrem(a, b)</code></dt>
<dt><code>cdivrem(a, b)</code></dt>
<dt><code>edivrem(a, b)</code></dt>
<dd><p>Return an array of two elements. The first element is the quotient,
the second is the remainder. The same rounding is done as the
corresponding division operation.
</p>
</dd>
<dt><code>sqrt(a)</code></dt>
<dd><p>Return <em>\lfloor \sqrt(a) \rfloor</em>. A RangeError exception is
raised if <em>a &lt; 0</em>.
</p>
</dd>
<dt><code>sqrtrem(a)</code></dt>
<dd><p>Return an array of two elements. The first element is <em>\lfloor
\sqrt{a} \rfloor</em>. The second element is <em>a-\lfloor \sqrt{a}
\rfloor^2</em>. A RangeError exception is raised if <em>a &lt; 0</em>.
</p>
</dd>
<dt><code>floorLog2(a)</code></dt>
<dd><p>Return -1 if <em>a \leq 0</em> otherwise return <em>\lfloor \log2(a) \rfloor</em>.
</p>
</dd>
<dt><code>ctz(a)</code></dt>
<dd><p>Return the number of trailing zeros in the two&rsquo;s complement binary representation of a. Return -1 if <em>a=0</em>.
</p>
</dd>
</dl>
<a name="BigFloat"></a>
<h2 class="chapter">4 BigFloat</h2>
<a name="Introduction-1"></a>
<h3 class="section">4.1 Introduction</h3>
<p>This extension adds the <code>BigFloat</code> primitive type. The
<code>BigFloat</code> type represents floating point numbers in base 2
with the IEEE 754 semantics. A floating
point number is represented as a sign, mantissa and exponent. The
special values <code>NaN</code>, <code>+/-Infinity</code>, <code>+0</code> and <code>-0</code>
are supported. The mantissa and exponent can have any bit length with
an implementation specific minimum and maximum.
</p>
<a name="Floating-point-rounding"></a>
<h3 class="section">4.2 Floating point rounding</h3>
<p>Each floating point operation operates with infinite precision and
then rounds the result according to the specified floating point
environment (<code>BigFloatEnv</code> object). The status flags of the
environment are also set according to the result of the operation.
</p>
<p>If no floating point environment is provided, the global floating
point environment is used.
</p>
<p>The rounding mode of the global floating point environment is always
<code>RNDN</code> (&ldquo;round to nearest with ties to even&rdquo;)<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>. The status flags of the global environment cannot be
read<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>. The precision of the global environment is
<code>BigFloatEnv.prec</code>. The number of exponent bits of the global
environment is <code>BigFloatEnv.expBits</code>. The global environment
subnormal flag is set to <code>true</code>.
</p>
<p>For example, <code>prec = 53</code> and <code> expBits = 11</code> exactly give
the same precision as the IEEE 754 64 bit floating point format. The
default precision is <code>prec = 113</code> and <code> expBits = 15</code> (IEEE
754 128 bit floating point format).
</p>
<p>The global floating point environment can only be modified temporarily
when calling a function (see <code>BigFloatEnv.setPrec</code>). Hence a
function can change the global floating point environment for its
callees but not for its caller.
</p>
<a name="Operators"></a>
<h3 class="section">4.3 Operators</h3>
<p>The builtin operators are extended so that a BigFloat is returned if
at least one operand is a BigFloat. The computations are always done
with infinite precision and rounded according to the global floating
point environment.
</p>
<p><code>typeof</code> applied on a <code>BigFloat</code> returns <code>bigfloat</code>.
</p>
<p>BigFloat can be compared with all the other numeric types and the
result follows the expected mathematical relations.
</p>
<p>However, since BigFloat and Number are different types they are never
equal when using the strict comparison operators (e.g. <code>0.0 ===
0.0l</code> is false).
</p>
<a name="BigFloat-literals"></a>
<h3 class="section">4.4 BigFloat literals</h3>
<p>BigFloat literals are floating point numbers with a trailing <code>l</code>
suffix. BigFloat literals have an infinite precision. They are rounded
according to the global floating point environment when they are
evaluated.<a name="DOCF3" href="#FOOT3"><sup>3</sup></a>
</p>
<a name="Builtin-Object-changes"></a>
<h3 class="section">4.5 Builtin Object changes</h3>
<a name="BigFloat-function"></a>
<h4 class="subsection">4.5.1 <code>BigFloat</code> function</h4>
<p>The <code>BigFloat</code> function cannot be invoked as a constructor. When
invoked as a function: the parameter is converted to a primitive
type. If the result is a numeric type, it is converted to BigFloat
without rounding. If the result is a string, it is converted to
BigFloat using the precision of the global floating point environment.
</p>
<p><code>BigFloat</code> properties:
</p>
<dl compact="compact">
<dt><code>LN2</code></dt>
<dt><code>PI</code></dt>
<dd><p>Getter. Return the value of the corresponding mathematical constant
rounded to nearest, ties to even with the current global
precision. The constant values are cached for small precisions.
</p>
</dd>
<dt><code>MIN_VALUE</code></dt>
<dt><code>MAX_VALUE</code></dt>
<dt><code>EPSILON</code></dt>
<dd><p>Getter. Return the minimum, maximum and epsilon <code>BigFloat</code> values
(same definition as the corresponding <code>Number</code> constants).
</p>
</dd>
<dt><code>fpRound(a[, e])</code></dt>
<dd><p>Round the floating point number <code>a</code> according to the floating
point environment <code>e</code> or the global environment if <code>e</code> is
undefined.
</p>
</dd>
<dt><code>parseFloat(a[, radix[, e]])</code></dt>
<dd><p>Parse the string <code>a</code> as a floating point number in radix
<code>radix</code>. The radix is 0 (default) or from 2 to 36. The radix 0
means radix 10 unless there is a hexadecimal or binary prefix. The
result is rounded according to the floating point environment <code>e</code>
or the global environment if <code>e</code> is undefined.
</p>
</dd>
<dt><code>isFinite(a)</code></dt>
<dd><p>Return true if <code>a</code> is a finite bigfloat.
</p>
</dd>
<dt><code>isNaN(a)</code></dt>
<dd><p>Return true if <code>a</code> is a NaN bigfloat.
</p>
</dd>
<dt><code>add(a, b[, e])</code></dt>
<dt><code>sub(a, b[, e])</code></dt>
<dt><code>mul(a, b[, e])</code></dt>
<dt><code>div(a, b[, e])</code></dt>
<dd><p>Perform the specified floating point operation and round the floating
point number <code>a</code> according to the floating point environment
<code>e</code> or the global environment if <code>e</code> is undefined. If
<code>e</code> is specified, the floating point status flags are updated.
</p>
</dd>
<dt><code>floor(x)</code></dt>
<dt><code>ceil(x)</code></dt>
<dt><code>round(x)</code></dt>
<dt><code>trunc(x)</code></dt>
<dd><p>Round to an integer. No additional rounding is performed.
</p>
</dd>
<dt><code>abs(x)</code></dt>
<dd><p>Return the absolute value of x. No additional rounding is performed.
</p>
</dd>
<dt><code>fmod(x, y[, e])</code></dt>
<dt><code>remainder(x, y[, e])</code></dt>
<dd><p>Floating point remainder. The quotient is truncated to zero (fmod) or
to the nearest integer with ties to even (remainder). <code>e</code> is an
optional floating point environment.
</p>
</dd>
<dt><code>sqrt(x[, e])</code></dt>
<dd><p>Square root. Return a rounded floating point number. <code>e</code> is an
optional floating point environment.
</p>
</dd>
<dt><code>sin(x[, e])</code></dt>
<dt><code>cos(x[, e])</code></dt>
<dt><code>tan(x[, e])</code></dt>
<dt><code>asin(x[, e])</code></dt>
<dt><code>acos(x[, e])</code></dt>
<dt><code>atan(x[, e])</code></dt>
<dt><code>atan2(x, y[, e])</code></dt>
<dt><code>exp(x[, e])</code></dt>
<dt><code>log(x[, e])</code></dt>
<dt><code>pow(x, y[, e])</code></dt>
<dd><p>Transcendental operations. Return a rounded floating point
number. <code>e</code> is an optional floating point environment.
</p>
</dd>
</dl>
<a name="BigFloat_002eprototype"></a>
<h4 class="subsection">4.5.2 <code>BigFloat.prototype</code></h4>
<p>The following properties are modified:
</p>
<dl compact="compact">
<dt><code>valueOf()</code></dt>
<dd><p>Return the bigfloat primitive value corresponding to <code>this</code>.
</p>
</dd>
<dt><code>toString(radix)</code></dt>
<dd>
<p>For floating point numbers:
</p>
<ul>
<li> If the radix is a power of two, the conversion is done with infinite
precision.
</li><li> Otherwise, the number is rounded to nearest with ties to even using
the global precision. It is then converted to string using the minimum
number of digits so that its conversion back to a floating point using
the global precision and round to nearest gives the same number.
</li></ul>
<p>The exponent letter is <code>e</code> for base 10, <code>p</code> for bases 2, 8,
16 with a binary exponent and <code>@</code> for the other bases.
</p>
</dd>
<dt><code>toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
<dt><code>toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
<dt><code>toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
<dd><p>Same semantics as the corresponding <code>Number</code> functions with
BigFloats. There is no limit on the accepted precision <code>p</code>. The
rounding mode and radix can be optionally specified. The radix must be
between 2 and 36.
</p>
</dd>
</dl>
<a name="BigFloatEnv-constructor"></a>
<h4 class="subsection">4.5.3 <code>BigFloatEnv</code> constructor</h4>
<p>The <code>BigFloatEnv([p, [,rndMode]]</code> constructor cannot be invoked as a
function. The floating point environment contains:
</p>
<ul>
<li> the mantissa precision in bits
</li><li> the exponent size in bits assuming an IEEE 754 representation;
</li><li> the subnormal flag (if true, subnormal floating point numbers can
be generated by the floating point operations).
</li><li> the rounding mode
</li><li> the floating point status. The status flags can only be set by the floating point operations. They can be reset with <code>BigFloatEnv.prototype.clearStatus()</code> or with the various status flag setters.
</li></ul>
<p><code>new BigFloatEnv([p, [,rndMode]]</code> creates a new floating point
environment. The status flags are reset. If no parameter is given the
precision, exponent bits and subnormal flags are copied from the
global floating point environment. Otherwise, the precision is set to
<code>p</code>, the number of exponent bits is set to <code>expBitsMax</code> and the
subnormal flags is set to <code>false</code>. If <code>rndMode</code> is
<code>undefined</code>, the rounding mode is set to <code>RNDN</code>.
</p>
<p><code>BigFloatEnv</code> properties:
</p>
<dl compact="compact">
<dt><code>prec</code></dt>
<dd><p>Getter. Return the precision in bits of the global floating point
environment. The initial value is <code>113</code>.
</p>
</dd>
<dt><code>expBits</code></dt>
<dd><p>Getter. Return the exponent size in bits of the global floating point
environment assuming an IEEE 754 representation. The initial value is
<code>15</code>.
</p>
</dd>
<dt><code>setPrec(f, p[, e])</code></dt>
<dd><p>Set the precision of the global floating point environment to <code>p</code>
and the exponent size to <code>e</code> then call the function
<code>f</code>. Then the Float precision and exponent size are reset to
their precious value and the return value of <code>f</code> is returned (or
an exception is raised if <code>f</code> raised an exception). If <code>e</code>
is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>.
</p>
</dd>
<dt><code>precMin</code></dt>
<dd><p>Read-only integer. Return the minimum allowed precision. Must be at least 2.
</p>
</dd>
<dt><code>precMax</code></dt>
<dd><p>Read-only integer. Return the maximum allowed precision. Must be at least 113.
</p>
</dd>
<dt><code>expBitsMin</code></dt>
<dd><p>Read-only integer. Return the minimum allowed exponent size in
bits. Must be at least 3.
</p>
</dd>
<dt><code>expBitsMax</code></dt>
<dd><p>Read-only integer. Return the maximum allowed exponent size in
bits. Must be at least 15.
</p>
</dd>
<dt><code>RNDN</code></dt>
<dd><p>Read-only integer. Round to nearest, with ties to even rounding mode.
</p>
</dd>
<dt><code>RNDZ</code></dt>
<dd><p>Read-only integer. Round to zero rounding mode.
</p>
</dd>
<dt><code>RNDD</code></dt>
<dd><p>Read-only integer. Round to -Infinity rounding mode.
</p>
</dd>
<dt><code>RNDU</code></dt>
<dd><p>Read-only integer. Round to +Infinity rounding mode.
</p>
</dd>
<dt><code>RNDNA</code></dt>
<dd><p>Read-only integer. Round to nearest, with ties away from zero rounding mode.
</p>
</dd>
<dt><code>RNDA</code></dt>
<dd><p>Read-only integer. Round away from zero rounding mode.
</p>
</dd>
<dt><code>RNDF<a name="DOCF4" href="#FOOT4"><sup>4</sup></a></code></dt>
<dd><p>Read-only integer. Faithful rounding mode. The result is
non-deterministically rounded to -Infinity or +Infinity. This rounding
mode usually gives a faster and deterministic running time for the
floating point operations.
</p>
</dd>
</dl>
<p><code>BigFloatEnv.prototype</code> properties:
</p>
<dl compact="compact">
<dt><code>prec</code></dt>
<dd><p>Getter and setter (Integer). Return or set the precision in bits.
</p>
</dd>
<dt><code>expBits</code></dt>
<dd><p>Getter and setter (Integer). Return or set the exponent size in bits
assuming an IEEE 754 representation.
</p>
</dd>
<dt><code>rndMode</code></dt>
<dd><p>Getter and setter (Integer). Return or set the rounding mode.
</p>
</dd>
<dt><code>subnormal</code></dt>
<dd><p>Getter and setter (Boolean). subnormal flag. It is false when
<code>expBits = expBitsMax</code>.
</p>
</dd>
<dt><code>clearStatus()</code></dt>
<dd><p>Clear the status flags.
</p>
</dd>
<dt><code>invalidOperation</code></dt>
<dt><code>divideByZero</code></dt>
<dt><code>overflow</code></dt>
<dt><code>underflow</code></dt>
<dt><code>inexact</code></dt>
<dd><p>Getter and setter (Boolean). Status flags.
</p>
</dd>
</dl>
<a name="BigDecimal"></a>
<h2 class="chapter">5 BigDecimal</h2>
<p>This extension adds the <code>BigDecimal</code> primitive type. The
<code>BigDecimal</code> type represents floating point numbers in base
10. It is inspired from the proposal available at
<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
</p>
<p>The <code>BigDecimal</code> floating point numbers are always normalized and
finite. There is no concept of <code>-0</code>, <code>Infinity</code> or
<code>NaN</code>. By default, all the computations are done with infinite
precision.
</p>
<a name="Operators-1"></a>
<h3 class="section">5.1 Operators</h3>
<p>The following builtin operators support BigDecimal:
</p>
<dl compact="compact">
<dt><code>+</code></dt>
<dt><code>-</code></dt>
<dt><code>*</code></dt>
<dd><p>Both operands must be BigDecimal. The result is computed with infinite
precision.
</p></dd>
<dt><code>%</code></dt>
<dd><p>Both operands must be BigDecimal. The result is computed with infinite
precision. A range error is throws in case of division by zero.
</p>
</dd>
<dt><code>/</code></dt>
<dd><p>Both operands must be BigDecimal. A range error is throws in case of
division by zero or if the result cannot be represented with infinite
precision (use <code>BigDecimal.div</code> to specify the rounding).
</p>
</dd>
<dt><code>**</code></dt>
<dd><p>Both operands must be BigDecimal. The exponent must be a positive
integer. The result is computed with infinite precision.
</p>
</dd>
<dt><code>===</code></dt>
<dd><p>When one of the operand is a BigDecimal, return true if both operands
are a BigDecimal and if they are equal.
</p>
</dd>
<dt><code>==</code></dt>
<dt><code>!=</code></dt>
<dt><code>&lt;=</code></dt>
<dt><code>&gt;=</code></dt>
<dt><code>&lt;</code></dt>
<dt><code>&gt;</code></dt>
<dd>
<p>Numerical comparison. When one of the operand is not a BigDecimal, it is
converted to BigDecimal by using ToString(). Hence comparisons between
Number and BigDecimal do not use the exact mathematical value of the
Number value.
</p>
</dd>
</dl>
<a name="BigDecimal-literals"></a>
<h3 class="section">5.2 BigDecimal literals</h3>
<p>BigDecimal literals are decimal floating point numbers with a trailing
<code>m</code> suffix.
</p>
<a name="Builtin-Object-changes-1"></a>
<h3 class="section">5.3 Builtin Object changes</h3>
<a name="The-BigDecimal-function_002e"></a>
<h4 class="subsection">5.3.1 The <code>BigDecimal</code> function.</h4>
<p>It returns <code>0m</code> if no parameter is provided. Otherwise the first
parameter is converted to a bigdecimal by using ToString(). Hence
Number values are not converted to their exact numerical value as
BigDecimal.
</p>
<a name="Properties-of-the-BigDecimal-object"></a>
<h4 class="subsection">5.3.2 Properties of the <code>BigDecimal</code> object</h4>
<dl compact="compact">
<dt><code>add(a, b[, e])</code></dt>
<dt><code>sub(a, b[, e])</code></dt>
<dt><code>mul(a, b[, e])</code></dt>
<dt><code>div(a, b[, e])</code></dt>
<dt><code>mod(a, b[, e])</code></dt>
<dt><code>sqrt(a, e)</code></dt>
<dt><code>round(a, e)</code></dt>
<dd><p>Perform the specified floating point operation and round the floating
point result according to the rounding object <code>e</code>. If the
rounding object is not present, the operation is executed with
infinite precision.
</p>
<p>For <code>div</code>, a <code>RangeError</code> exception is thrown in case of
division by zero or if the result cannot be represented with infinite
precision if no rounding object is present.
</p>
<p>For <code>sqrt</code>, a range error is thrown if <code>a</code> is less than
zero.
</p>
<p>The rounding object must contain the following properties:
<code>roundingMode</code> is a string specifying the rounding mode
(<code>&quot;floor&quot;</code>, <code>&quot;ceiling&quot;</code>, <code>&quot;down&quot;</code>, <code>&quot;up&quot;</code>,
<code>&quot;half-even&quot;</code>, <code>&quot;half-up&quot;</code>). Either
<code>maximumSignificantDigits</code> or <code>maximumFractionDigits</code> must
be present to specify respectively the number of significant digits
(must be &gt;= 1) or the number of digits after the decimal point (must
be &gt;= 0).
</p>
</dd>
</dl>
<a name="Properties-of-the-BigDecimal_002eprototype-object"></a>
<h4 class="subsection">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</h4>
<dl compact="compact">
<dt><code>valueOf()</code></dt>
<dd><p>Return the bigdecimal primitive value corresponding to <code>this</code>.
</p>
</dd>
<dt><code>toString()</code></dt>
<dd><p>Convert <code>this</code> to a string with infinite precision in base 10.
</p>
</dd>
<dt><code>toPrecision(p, rnd_mode = &quot;half-up&quot;)</code></dt>
<dt><code>toFixed(p, rnd_mode = &quot;half-up&quot;)</code></dt>
<dt><code>toExponential(p, rnd_mode = &quot;half-up&quot;)</code></dt>
<dd><p>Convert the BigDecimal <code>this</code> to string with the specified
precision <code>p</code>. There is no limit on the accepted precision
<code>p</code>. The rounding mode can be optionally
specified. <code>toPrecision</code> outputs either in decimal fixed notation
or in decimal exponential notation with a <code>p</code> digits of
precision. <code>toExponential</code> outputs in decimal exponential
notation with <code>p</code> digits after the decimal point. <code>toFixed</code>
outputs in decimal notation with <code>p</code> digits after the decimal
point.
</p>
</dd>
</dl>
<a name="Math-mode"></a>
<h2 class="chapter">6 Math mode</h2>
<p>A new <em>math mode</em> is enabled with the <code>&quot;use math&quot;</code>
directive. It propagates the same way as the <em>strict mode</em>. It is
designed so that arbitrarily large integers and floating point numbers
are available by default. In order to minimize the number of changes
in the Javascript semantics, integers are represented either as Number
or BigInt depending on their magnitude. Floating point numbers are
always represented as BigFloat.
</p>
<p>The following changes are made to the Javascript semantics:
</p>
<ul>
<li> Floating point literals (i.e. number with a decimal point or an exponent) are <code>BigFloat</code> by default (i.e. a <code>l</code> suffix is implied). Hence <code>typeof 1.0 === &quot;bigfloat&quot;</code>.
</li><li> Integer literals (i.e. numbers without a decimal point or an exponent) with or without the <code>n</code> suffix are <code>BigInt</code> if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to <code>2**53-1</code>. Hence <code>typeof 1 === &quot;number &quot;</code>, <code>typeof 1n === &quot;number&quot;</code> but <code>typeof 9007199254740992 === &quot;bigint&quot; </code>.
</li><li> All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt.
</li><li> The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result.
</li><li> The <code>^</code> operator is an alias to the power operator (<code>**</code>).
</li><li> The power operator (both <code>^</code> and <code>**</code>) grammar is modified so that <code>-2^2</code> is allowed and yields <code>-4</code>.
</li><li> The logical xor operator is still available with the <code>^^</code> operator.
</li><li> The modulo operator (<code>%</code>) returns the Euclidian remainder (always positive) instead of the truncated remainder.
</li><li> The integer division operator can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
</li><li> The integer power operator with a non zero negative exponent can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
</li></ul>
<div class="footnote">
<hr>
<h4 class="footnotes-heading">Footnotes</h4>
<h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>
<p>The
rationale is that the rounding mode changes must always be
explicit.</p>
<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
<p>The rationale is to avoid side effects for the built-in
operators.</p>
<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
<p>Base 10 floating point literals cannot usually be
exactly represented as base 2 floating point number. In order to
ensure that the literal is represented accurately with the current
precision, it must be evaluated at runtime.</p>
<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
<p>Could be removed in case a deterministic behavior for floating point operations is required.</p>
</div>
<hr>
</body>
</html>

Binary file not shown.

View file

@ -1,589 +0,0 @@
\input texinfo
@iftex
@afourpaper
@headings double
@end iftex
@titlepage
@afourpaper
@sp 7
@center @titlefont{Javascript Bignum Extensions}
@sp 3
@center Version 2020-01-11
@sp 3
@center Author: Fabrice Bellard
@end titlepage
@setfilename jsbignum.info
@settitle Javascript Bignum Extensions
@contents
@chapter Introduction
The Bignum extensions add the following features to the Javascript
language while being 100% backward compatible:
@itemize
@item Operator overloading with a dispatch logic inspired from the proposal available at @url{https://github.com/tc39/proposal-operator-overloading/}.
@item Arbitrarily large floating point numbers (@code{BigFloat}) in base 2 using the IEEE 754 semantics.
@item Arbitrarily large floating point numbers (@code{BigDecimal}) in base 10 based on the proposal available at
@url{https://github.com/littledan/proposal-bigdecimal}.
@item @code{math} mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (@code{%}) is defined as the Euclidian
remainder. @code{^} is an alias to the power operator
(@code{**}). @code{^^} is used as the exclusive or operator.
@end itemize
The extensions are independent from each other except the @code{math}
mode which relies on BigFloat and operator overloading.
@chapter Operator overloading
Operator overloading is inspired from the proposal available at
@url{https://github.com/tc39/proposal-operator-overloading/}. It
implements the same dispatch logic but finds the operator sets by
looking at the @code{Symbol.operatorSet} property in the objects. The
changes were done in order to simplify the implementation.
More precisely, the following modifications were made:
@itemize
@item @code{with operators from} is not supported. Operator overloading is always enabled.
@item The dispatch is not based on a static @code{[[OperatorSet]]} field in all instances. Instead, a dynamic lookup of the @code{Symbol.operatorSet} property is done. This property is typically added in the prototype of each object.
@item @code{Operators.create(...dictionaries)} is used to create a new OperatorSet object. The @code{Operators} function is supported as an helper to be closer to the TC39 proposal.
@item @code{[]} cannot be overloaded.
@item In math mode, the BigInt division and power operators can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
@end itemize
@chapter BigInt extensions
A few properties are added to the BigInt object:
@table @code
@item tdiv(a, b)
Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError
exception.
@item fdiv(a, b)
Return @math{\lfloor a/b \rfloor}. @code{b = 0} raises a RangeError
exception.
@item cdiv(a, b)
Return @math{\lceil a/b \rceil}. @code{b = 0} raises a RangeError
exception.
@item ediv(a, b)
Return @math{sgn(b) \lfloor a/{|b|} \rfloor} (Euclidian
division). @code{b = 0} raises a RangeError exception.
@item tdivrem(a, b)
@item fdivrem(a, b)
@item cdivrem(a, b)
@item edivrem(a, b)
Return an array of two elements. The first element is the quotient,
the second is the remainder. The same rounding is done as the
corresponding division operation.
@item sqrt(a)
Return @math{\lfloor \sqrt(a) \rfloor}. A RangeError exception is
raised if @math{a < 0}.
@item sqrtrem(a)
Return an array of two elements. The first element is @math{\lfloor
\sqrt{a} \rfloor}. The second element is @math{a-\lfloor \sqrt{a}
\rfloor^2}. A RangeError exception is raised if @math{a < 0}.
@item floorLog2(a)
Return -1 if @math{a \leq 0} otherwise return @math{\lfloor \log2(a) \rfloor}.
@item ctz(a)
Return the number of trailing zeros in the two's complement binary representation of a. Return -1 if @math{a=0}.
@end table
@chapter BigFloat
@section Introduction
This extension adds the @code{BigFloat} primitive type. The
@code{BigFloat} type represents floating point numbers in base 2
with the IEEE 754 semantics. A floating
point number is represented as a sign, mantissa and exponent. The
special values @code{NaN}, @code{+/-Infinity}, @code{+0} and @code{-0}
are supported. The mantissa and exponent can have any bit length with
an implementation specific minimum and maximum.
@section Floating point rounding
Each floating point operation operates with infinite precision and
then rounds the result according to the specified floating point
environment (@code{BigFloatEnv} object). The status flags of the
environment are also set according to the result of the operation.
If no floating point environment is provided, the global floating
point environment is used.
The rounding mode of the global floating point environment is always
@code{RNDN} (``round to nearest with ties to even'')@footnote{The
rationale is that the rounding mode changes must always be
explicit.}. The status flags of the global environment cannot be
read@footnote{The rationale is to avoid side effects for the built-in
operators.}. The precision of the global environment is
@code{BigFloatEnv.prec}. The number of exponent bits of the global
environment is @code{BigFloatEnv.expBits}. The global environment
subnormal flag is set to @code{true}.
For example, @code{prec = 53} and @code{ expBits = 11} exactly give
the same precision as the IEEE 754 64 bit floating point format. The
default precision is @code{prec = 113} and @code{ expBits = 15} (IEEE
754 128 bit floating point format).
The global floating point environment can only be modified temporarily
when calling a function (see @code{BigFloatEnv.setPrec}). Hence a
function can change the global floating point environment for its
callees but not for its caller.
@section Operators
The builtin operators are extended so that a BigFloat is returned if
at least one operand is a BigFloat. The computations are always done
with infinite precision and rounded according to the global floating
point environment.
@code{typeof} applied on a @code{BigFloat} returns @code{bigfloat}.
BigFloat can be compared with all the other numeric types and the
result follows the expected mathematical relations.
However, since BigFloat and Number are different types they are never
equal when using the strict comparison operators (e.g. @code{0.0 ===
0.0l} is false).
@section BigFloat literals
BigFloat literals are floating point numbers with a trailing @code{l}
suffix. BigFloat literals have an infinite precision. They are rounded
according to the global floating point environment when they are
evaluated.@footnote{Base 10 floating point literals cannot usually be
exactly represented as base 2 floating point number. In order to
ensure that the literal is represented accurately with the current
precision, it must be evaluated at runtime.}
@section Builtin Object changes
@subsection @code{BigFloat} function
The @code{BigFloat} function cannot be invoked as a constructor. When
invoked as a function: the parameter is converted to a primitive
type. If the result is a numeric type, it is converted to BigFloat
without rounding. If the result is a string, it is converted to
BigFloat using the precision of the global floating point environment.
@code{BigFloat} properties:
@table @code
@item LN2
@item PI
Getter. Return the value of the corresponding mathematical constant
rounded to nearest, ties to even with the current global
precision. The constant values are cached for small precisions.
@item MIN_VALUE
@item MAX_VALUE
@item EPSILON
Getter. Return the minimum, maximum and epsilon @code{BigFloat} values
(same definition as the corresponding @code{Number} constants).
@item fpRound(a[, e])
Round the floating point number @code{a} according to the floating
point environment @code{e} or the global environment if @code{e} is
undefined.
@item parseFloat(a[, radix[, e]])
Parse the string @code{a} as a floating point number in radix
@code{radix}. The radix is 0 (default) or from 2 to 36. The radix 0
means radix 10 unless there is a hexadecimal or binary prefix. The
result is rounded according to the floating point environment @code{e}
or the global environment if @code{e} is undefined.
@item isFinite(a)
Return true if @code{a} is a finite bigfloat.
@item isNaN(a)
Return true if @code{a} is a NaN bigfloat.
@item add(a, b[, e])
@item sub(a, b[, e])
@item mul(a, b[, e])
@item div(a, b[, e])
Perform the specified floating point operation and round the floating
point number @code{a} according to the floating point environment
@code{e} or the global environment if @code{e} is undefined. If
@code{e} is specified, the floating point status flags are updated.
@item floor(x)
@item ceil(x)
@item round(x)
@item trunc(x)
Round to an integer. No additional rounding is performed.
@item abs(x)
Return the absolute value of x. No additional rounding is performed.
@item fmod(x, y[, e])
@item remainder(x, y[, e])
Floating point remainder. The quotient is truncated to zero (fmod) or
to the nearest integer with ties to even (remainder). @code{e} is an
optional floating point environment.
@item sqrt(x[, e])
Square root. Return a rounded floating point number. @code{e} is an
optional floating point environment.
@item sin(x[, e])
@item cos(x[, e])
@item tan(x[, e])
@item asin(x[, e])
@item acos(x[, e])
@item atan(x[, e])
@item atan2(x, y[, e])
@item exp(x[, e])
@item log(x[, e])
@item pow(x, y[, e])
Transcendental operations. Return a rounded floating point
number. @code{e} is an optional floating point environment.
@end table
@subsection @code{BigFloat.prototype}
The following properties are modified:
@table @code
@item valueOf()
Return the bigfloat primitive value corresponding to @code{this}.
@item toString(radix)
For floating point numbers:
@itemize
@item
If the radix is a power of two, the conversion is done with infinite
precision.
@item
Otherwise, the number is rounded to nearest with ties to even using
the global precision. It is then converted to string using the minimum
number of digits so that its conversion back to a floating point using
the global precision and round to nearest gives the same number.
@end itemize
The exponent letter is @code{e} for base 10, @code{p} for bases 2, 8,
16 with a binary exponent and @code{@@} for the other bases.
@item toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
@item toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
@item toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
Same semantics as the corresponding @code{Number} functions with
BigFloats. There is no limit on the accepted precision @code{p}. The
rounding mode and radix can be optionally specified. The radix must be
between 2 and 36.
@end table
@subsection @code{BigFloatEnv} constructor
The @code{BigFloatEnv([p, [,rndMode]]} constructor cannot be invoked as a
function. The floating point environment contains:
@itemize
@item the mantissa precision in bits
@item the exponent size in bits assuming an IEEE 754 representation;
@item the subnormal flag (if true, subnormal floating point numbers can
be generated by the floating point operations).
@item the rounding mode
@item the floating point status. The status flags can only be set by the floating point operations. They can be reset with @code{BigFloatEnv.prototype.clearStatus()} or with the various status flag setters.
@end itemize
@code{new BigFloatEnv([p, [,rndMode]]} creates a new floating point
environment. The status flags are reset. If no parameter is given the
precision, exponent bits and subnormal flags are copied from the
global floating point environment. Otherwise, the precision is set to
@code{p}, the number of exponent bits is set to @code{expBitsMax} and the
subnormal flags is set to @code{false}. If @code{rndMode} is
@code{undefined}, the rounding mode is set to @code{RNDN}.
@code{BigFloatEnv} properties:
@table @code
@item prec
Getter. Return the precision in bits of the global floating point
environment. The initial value is @code{113}.
@item expBits
Getter. Return the exponent size in bits of the global floating point
environment assuming an IEEE 754 representation. The initial value is
@code{15}.
@item setPrec(f, p[, e])
Set the precision of the global floating point environment to @code{p}
and the exponent size to @code{e} then call the function
@code{f}. Then the Float precision and exponent size are reset to
their precious value and the return value of @code{f} is returned (or
an exception is raised if @code{f} raised an exception). If @code{e}
is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}.
@item precMin
Read-only integer. Return the minimum allowed precision. Must be at least 2.
@item precMax
Read-only integer. Return the maximum allowed precision. Must be at least 113.
@item expBitsMin
Read-only integer. Return the minimum allowed exponent size in
bits. Must be at least 3.
@item expBitsMax
Read-only integer. Return the maximum allowed exponent size in
bits. Must be at least 15.
@item RNDN
Read-only integer. Round to nearest, with ties to even rounding mode.
@item RNDZ
Read-only integer. Round to zero rounding mode.
@item RNDD
Read-only integer. Round to -Infinity rounding mode.
@item RNDU
Read-only integer. Round to +Infinity rounding mode.
@item RNDNA
Read-only integer. Round to nearest, with ties away from zero rounding mode.
@item RNDA
Read-only integer. Round away from zero rounding mode.
@item RNDF@footnote{Could be removed in case a deterministic behavior for floating point operations is required.}
Read-only integer. Faithful rounding mode. The result is
non-deterministically rounded to -Infinity or +Infinity. This rounding
mode usually gives a faster and deterministic running time for the
floating point operations.
@end table
@code{BigFloatEnv.prototype} properties:
@table @code
@item prec
Getter and setter (Integer). Return or set the precision in bits.
@item expBits
Getter and setter (Integer). Return or set the exponent size in bits
assuming an IEEE 754 representation.
@item rndMode
Getter and setter (Integer). Return or set the rounding mode.
@item subnormal
Getter and setter (Boolean). subnormal flag. It is false when
@code{expBits = expBitsMax}.
@item clearStatus()
Clear the status flags.
@item invalidOperation
@item divideByZero
@item overflow
@item underflow
@item inexact
Getter and setter (Boolean). Status flags.
@end table
@chapter BigDecimal
This extension adds the @code{BigDecimal} primitive type. The
@code{BigDecimal} type represents floating point numbers in base
10. It is inspired from the proposal available at
@url{https://github.com/littledan/proposal-bigdecimal}.
The @code{BigDecimal} floating point numbers are always normalized and
finite. There is no concept of @code{-0}, @code{Infinity} or
@code{NaN}. By default, all the computations are done with infinite
precision.
@section Operators
The following builtin operators support BigDecimal:
@table @code
@item +
@item -
@item *
Both operands must be BigDecimal. The result is computed with infinite
precision.
@item %
Both operands must be BigDecimal. The result is computed with infinite
precision. A range error is throws in case of division by zero.
@item /
Both operands must be BigDecimal. A range error is throws in case of
division by zero or if the result cannot be represented with infinite
precision (use @code{BigDecimal.div} to specify the rounding).
@item **
Both operands must be BigDecimal. The exponent must be a positive
integer. The result is computed with infinite precision.
@item ===
When one of the operand is a BigDecimal, return true if both operands
are a BigDecimal and if they are equal.
@item ==
@item !=
@item <=
@item >=
@item <
@item >
Numerical comparison. When one of the operand is not a BigDecimal, it is
converted to BigDecimal by using ToString(). Hence comparisons between
Number and BigDecimal do not use the exact mathematical value of the
Number value.
@end table
@section BigDecimal literals
BigDecimal literals are decimal floating point numbers with a trailing
@code{m} suffix.
@section Builtin Object changes
@subsection The @code{BigDecimal} function.
It returns @code{0m} if no parameter is provided. Otherwise the first
parameter is converted to a bigdecimal by using ToString(). Hence
Number values are not converted to their exact numerical value as
BigDecimal.
@subsection Properties of the @code{BigDecimal} object
@table @code
@item add(a, b[, e])
@item sub(a, b[, e])
@item mul(a, b[, e])
@item div(a, b[, e])
@item mod(a, b[, e])
@item sqrt(a, e)
@item round(a, e)
Perform the specified floating point operation and round the floating
point result according to the rounding object @code{e}. If the
rounding object is not present, the operation is executed with
infinite precision.
For @code{div}, a @code{RangeError} exception is thrown in case of
division by zero or if the result cannot be represented with infinite
precision if no rounding object is present.
For @code{sqrt}, a range error is thrown if @code{a} is less than
zero.
The rounding object must contain the following properties:
@code{roundingMode} is a string specifying the rounding mode
(@code{"floor"}, @code{"ceiling"}, @code{"down"}, @code{"up"},
@code{"half-even"}, @code{"half-up"}). Either
@code{maximumSignificantDigits} or @code{maximumFractionDigits} must
be present to specify respectively the number of significant digits
(must be >= 1) or the number of digits after the decimal point (must
be >= 0).
@end table
@subsection Properties of the @code{BigDecimal.prototype} object
@table @code
@item valueOf()
Return the bigdecimal primitive value corresponding to @code{this}.
@item toString()
Convert @code{this} to a string with infinite precision in base 10.
@item toPrecision(p, rnd_mode = "half-up")
@item toFixed(p, rnd_mode = "half-up")
@item toExponential(p, rnd_mode = "half-up")
Convert the BigDecimal @code{this} to string with the specified
precision @code{p}. There is no limit on the accepted precision
@code{p}. The rounding mode can be optionally
specified. @code{toPrecision} outputs either in decimal fixed notation
or in decimal exponential notation with a @code{p} digits of
precision. @code{toExponential} outputs in decimal exponential
notation with @code{p} digits after the decimal point. @code{toFixed}
outputs in decimal notation with @code{p} digits after the decimal
point.
@end table
@chapter Math mode
A new @emph{math mode} is enabled with the @code{"use math"}
directive. It propagates the same way as the @emph{strict mode}. It is
designed so that arbitrarily large integers and floating point numbers
are available by default. In order to minimize the number of changes
in the Javascript semantics, integers are represented either as Number
or BigInt depending on their magnitude. Floating point numbers are
always represented as BigFloat.
The following changes are made to the Javascript semantics:
@itemize
@item Floating point literals (i.e. number with a decimal point or an exponent) are @code{BigFloat} by default (i.e. a @code{l} suffix is implied). Hence @code{typeof 1.0 === "bigfloat"}.
@item Integer literals (i.e. numbers without a decimal point or an exponent) with or without the @code{n} suffix are @code{BigInt} if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to @code{2**53-1}. Hence @code{typeof 1 === "number "}, @code{typeof 1n === "number"} but @code{typeof 9007199254740992 === "bigint" }.
@item All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt.
@item The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result.
@item The @code{^} operator is an alias to the power operator (@code{**}).
@item The power operator (both @code{^} and @code{**}) grammar is modified so that @code{-2^2} is allowed and yields @code{-4}.
@item The logical xor operator is still available with the @code{^^} operator.
@item The modulo operator (@code{%}) returns the Euclidian remainder (always positive) instead of the truncated remainder.
@item The integer division operator can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
@item The integer power operator with a non zero negative exponent can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
@end itemize
@bye

File diff suppressed because it is too large Load diff

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -1,458 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "third_party/quickjs/internal.h"
#include "third_party/quickjs/libregexp.h"
#include "third_party/quickjs/quickjs.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
/* XXX: Should take JSValueConst arguments */
BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
JSStrictEqModeEnum eq_mode)
{
BOOL res;
int tag1, tag2;
double d1, d2;
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
switch(tag1) {
case JS_TAG_BOOL:
if (tag1 != tag2) {
res = FALSE;
} else {
res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
goto done_no_free;
}
break;
case JS_TAG_NULL:
case JS_TAG_UNDEFINED:
res = (tag1 == tag2);
break;
case JS_TAG_STRING:
{
JSString *p1, *p2;
if (tag1 != tag2) {
res = FALSE;
} else {
p1 = JS_VALUE_GET_STRING(op1);
p2 = JS_VALUE_GET_STRING(op2);
res = (js_string_compare(ctx, p1, p2) == 0);
}
}
break;
case JS_TAG_SYMBOL:
{
JSAtomStruct *p1, *p2;
if (tag1 != tag2) {
res = FALSE;
} else {
p1 = JS_VALUE_GET_PTR(op1);
p2 = JS_VALUE_GET_PTR(op2);
res = (p1 == p2);
}
}
break;
case JS_TAG_OBJECT:
if (tag1 != tag2)
res = FALSE;
else
res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2);
break;
case JS_TAG_INT:
d1 = JS_VALUE_GET_INT(op1);
if (tag2 == JS_TAG_INT) {
d2 = JS_VALUE_GET_INT(op2);
goto number_test;
} else if (tag2 == JS_TAG_FLOAT64) {
d2 = JS_VALUE_GET_FLOAT64(op2);
goto number_test;
} else {
res = FALSE;
}
break;
case JS_TAG_FLOAT64:
d1 = JS_VALUE_GET_FLOAT64(op1);
if (tag2 == JS_TAG_FLOAT64) {
d2 = JS_VALUE_GET_FLOAT64(op2);
} else if (tag2 == JS_TAG_INT) {
d2 = JS_VALUE_GET_INT(op2);
} else {
res = FALSE;
break;
}
number_test:
if (UNLIKELY(eq_mode >= JS_EQ_SAME_VALUE)) {
JSFloat64Union u1, u2;
/* NaN is not always normalized, so this test is necessary */
if (isnan(d1) || isnan(d2)) {
res = isnan(d1) == isnan(d2);
} else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) {
res = (d1 == d2); /* +0 == -0 */
} else {
u1.d = d1;
u2.d = d2;
res = (u1.u64 == u2.u64); /* +0 != -0 */
}
} else {
res = (d1 == d2); /* if NaN return false and +0 == -0 */
}
goto done_no_free;
#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
{
bf_t a_s, *a, b_s, *b;
if (tag1 != tag2) {
res = FALSE;
break;
}
a = JS_ToBigFloat(ctx, &a_s, op1);
b = JS_ToBigFloat(ctx, &b_s, op2);
res = bf_cmp_eq(a, b);
if (a == &a_s)
bf_delete(a);
if (b == &b_s)
bf_delete(b);
}
break;
case JS_TAG_BIG_FLOAT:
{
JSBigFloat *p1, *p2;
const bf_t *a, *b;
if (tag1 != tag2) {
res = FALSE;
break;
}
p1 = JS_VALUE_GET_PTR(op1);
p2 = JS_VALUE_GET_PTR(op2);
a = &p1->num;
b = &p2->num;
if (UNLIKELY(eq_mode >= JS_EQ_SAME_VALUE)) {
if (eq_mode == JS_EQ_SAME_VALUE_ZERO &&
a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO) {
res = TRUE;
} else {
res = (bf_cmp_full(a, b) == 0);
}
} else {
res = bf_cmp_eq(a, b);
}
}
break;
case JS_TAG_BIG_DECIMAL:
{
JSBigDecimal *p1, *p2;
const bfdec_t *a, *b;
if (tag1 != tag2) {
res = FALSE;
break;
}
p1 = JS_VALUE_GET_PTR(op1);
p2 = JS_VALUE_GET_PTR(op2);
a = &p1->num;
b = &p2->num;
res = bfdec_cmp_eq(a, b);
}
break;
#endif
default:
res = FALSE;
break;
}
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
done_no_free:
return res;
}
BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2)
{
return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
}
BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
{
return js_strict_eq2(ctx,
JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
JS_EQ_SAME_VALUE);
}
BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
{
return js_strict_eq2(ctx,
JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
JS_EQ_SAME_VALUE_ZERO);
}
int js_strict_eq_slow(JSContext *ctx, JSValue *sp, BOOL is_neq)
{
BOOL res;
res = js_strict_eq(ctx, sp[-2], sp[-1]);
sp[-2] = JS_NewBool(ctx, res ^ is_neq);
return 0;
}
static BOOL tag_is_number(uint32_t tag)
{
return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT ||
tag == JS_TAG_FLOAT64 || tag == JS_TAG_BIG_FLOAT ||
tag == JS_TAG_BIG_DECIMAL);
}
static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj)
{
JSObject *p;
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
return FALSE;
p = JS_VALUE_GET_OBJ(obj);
return p->is_HTMLDDA;
}
int js_eq_slow(JSContext *ctx, JSValue *sp, BOOL is_neq)
{
#ifdef CONFIG_BIGNUM
JSValue op1, op2, ret;
int res;
uint32_t tag1, tag2;
op1 = sp[-2];
op2 = sp[-1];
redo:
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
if (tag_is_number(tag1) && tag_is_number(tag2)) {
if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
} else if ((tag1 == JS_TAG_FLOAT64 &&
(tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) ||
(tag2 == JS_TAG_FLOAT64 &&
(tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) {
double d1, d2;
if (tag1 == JS_TAG_FLOAT64) {
d1 = JS_VALUE_GET_FLOAT64(op1);
} else {
d1 = JS_VALUE_GET_INT(op1);
}
if (tag2 == JS_TAG_FLOAT64) {
d2 = JS_VALUE_GET_FLOAT64(op2);
} else {
d2 = JS_VALUE_GET_INT(op2);
}
res = (d1 == d2);
} else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2);
if (res < 0)
goto exception;
} else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2);
if (res < 0)
goto exception;
} else {
res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2);
if (res < 0)
goto exception;
}
} else if (tag1 == tag2) {
if (tag1 == JS_TAG_OBJECT) {
/* try the fallback operator */
res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
is_neq ? OP_neq : OP_eq,
FALSE, HINT_NONE);
if (res != 0) {
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
if (res < 0) {
goto exception;
} else {
sp[-2] = ret;
return 0;
}
}
}
res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
} else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
(tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
res = TRUE;
} else if ((tag1 == JS_TAG_STRING && tag_is_number(tag2)) ||
(tag2 == JS_TAG_STRING && tag_is_number(tag1))) {
if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&
!is_math_mode(ctx)) {
if (tag1 == JS_TAG_STRING) {
op1 = JS_StringToBigInt(ctx, op1);
if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
goto invalid_bigint_string;
}
if (tag2 == JS_TAG_STRING) {
op2 = JS_StringToBigInt(ctx, op2);
if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
invalid_bigint_string:
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
res = FALSE;
goto done;
}
}
} else {
op1 = JS_ToNumericFree(ctx, op1);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
goto exception;
}
op2 = JS_ToNumericFree(ctx, op2);
if (JS_IsException(op2)) {
JS_FreeValue(ctx, op1);
goto exception;
}
}
res = js_strict_eq(ctx, op1, op2);
} else if (tag1 == JS_TAG_BOOL) {
op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
goto redo;
} else if (tag2 == JS_TAG_BOOL) {
op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
goto redo;
} else if ((tag1 == JS_TAG_OBJECT &&
(tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) ||
(tag2 == JS_TAG_OBJECT &&
(tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) {
/* try the fallback operator */
res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
is_neq ? OP_neq : OP_eq,
FALSE, HINT_NONE);
if (res != 0) {
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
if (res < 0) {
goto exception;
} else {
sp[-2] = ret;
return 0;
}
}
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
goto exception;
}
op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
if (JS_IsException(op2)) {
JS_FreeValue(ctx, op1);
goto exception;
}
goto redo;
} else {
/* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
if ((JS_IsHTMLDDA(ctx, op1) &&
(tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
(JS_IsHTMLDDA(ctx, op2) &&
(tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
res = TRUE;
} else {
res = FALSE;
}
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
}
done:
sp[-2] = JS_NewBool(ctx, res ^ is_neq);
return 0;
exception:
sp[-2] = JS_UNDEFINED;
sp[-1] = JS_UNDEFINED;
return -1;
#else /* CONFIG_BIGNUM */
JSValue op1, op2;
int tag1, tag2;
BOOL res;
op1 = sp[-2];
op2 = sp[-1];
redo:
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
if (tag1 == tag2 ||
(tag1 == JS_TAG_INT && tag2 == JS_TAG_FLOAT64) ||
(tag2 == JS_TAG_INT && tag1 == JS_TAG_FLOAT64)) {
res = js_strict_eq(ctx, op1, op2);
} else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
(tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
res = TRUE;
} else if ((tag1 == JS_TAG_STRING && (tag2 == JS_TAG_INT ||
tag2 == JS_TAG_FLOAT64)) ||
(tag2 == JS_TAG_STRING && (tag1 == JS_TAG_INT ||
tag1 == JS_TAG_FLOAT64))) {
double d1;
double d2;
if (JS_ToFloat64Free(ctx, &d1, op1)) {
JS_FreeValue(ctx, op2);
goto exception;
}
if (JS_ToFloat64Free(ctx, &d2, op2))
goto exception;
res = (d1 == d2);
} else if (tag1 == JS_TAG_BOOL) {
op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
goto redo;
} else if (tag2 == JS_TAG_BOOL) {
op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
goto redo;
} else if (tag1 == JS_TAG_OBJECT &&
(tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64 || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) {
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
goto exception;
}
goto redo;
} else if (tag2 == JS_TAG_OBJECT &&
(tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64 || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL)) {
op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
if (JS_IsException(op2)) {
JS_FreeValue(ctx, op1);
goto exception;
}
goto redo;
} else {
/* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
if ((JS_IsHTMLDDA(ctx, op1) &&
(tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
(JS_IsHTMLDDA(ctx, op2) &&
(tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
res = TRUE;
} else {
res = FALSE;
}
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
}
sp[-2] = JS_NewBool(ctx, res ^ is_neq);
return 0;
exception:
sp[-2] = JS_UNDEFINED;
sp[-1] = JS_UNDEFINED;
return -1;
#endif /* CONFIG_BIGNUM */
}

View file

@ -1,416 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "third_party/quickjs/internal.h"
#include "third_party/quickjs/leb128.h"
#include "third_party/quickjs/libregexp.h"
#include "third_party/quickjs/quickjs.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
int js_parse_error(JSParseState *s, const char *fmt, ...)
{
JSContext *ctx = s->ctx;
va_list ap;
int backtrace_flags;
va_start(ap, fmt);
JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
va_end(ap);
backtrace_flags = 0;
if (s->cur_func && s->cur_func->backtrace_barrier)
backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
build_backtrace(ctx, ctx->rt->current_exception, s->filename, s->line_num,
backtrace_flags);
return -1;
}
JSValue JS_NewError(JSContext *ctx)
{
return JS_NewObjectClass(ctx, JS_CLASS_ERROR);
}
JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num, const char *fmt, va_list ap, BOOL add_backtrace)
{
char buf[256];
JSValue obj, ret;
vsnprintf(buf, sizeof(buf), fmt, ap);
obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num],
JS_CLASS_ERROR);
if (UNLIKELY(JS_IsException(obj))) {
/* out of memory: throw JS_NULL to avoid recursing */
obj = JS_NULL;
} else {
JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
JS_NewString(ctx, buf),
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
}
if (add_backtrace) {
build_backtrace(ctx, obj, NULL, 0, 0);
}
ret = JS_Throw(ctx, obj);
return ret;
}
JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num, const char *fmt, va_list ap)
{
JSRuntime *rt = ctx->rt;
JSStackFrame *sf;
BOOL add_backtrace;
/* the backtrace is added later if called from a bytecode function */
sf = rt->current_stack_frame;
add_backtrace = !rt->in_out_of_memory &&
(!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);
}
JSValue JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)
{
JSValue val;
va_list ap;
va_start(ap, fmt);
val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap);
va_end(ap);
return val;
}
JSValue JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)
{
JSValue val;
va_list ap;
va_start(ap, fmt);
val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
va_end(ap);
return val;
}
int JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)
{
va_list ap;
if ((flags & JS_PROP_THROW) ||
((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
va_start(ap, fmt);
JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
va_end(ap);
return -1;
} else {
return FALSE;
}
}
/* never use it directly */
JSValue __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
{
char buf[ATOM_GET_STR_BUF_SIZE];
return JS_ThrowTypeError(ctx, fmt,
JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
}
/* never use it directly */
JSValue __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
{
char buf[ATOM_GET_STR_BUF_SIZE];
return JS_ThrowSyntaxError(ctx, fmt,
JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
}
int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
{
if ((flags & JS_PROP_THROW) ||
((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
return -1;
} else {
return FALSE;
}
}
JSValue JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)
{
JSValue val;
va_list ap;
va_start(ap, fmt);
val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap);
va_end(ap);
return val;
}
JSValue JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)
{
JSValue val;
va_list ap;
va_start(ap, fmt);
val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap);
va_end(ap);
return val;
}
JSValue JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)
{
JSValue val;
va_list ap;
va_start(ap, fmt);
val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap);
va_end(ap);
return val;
}
JSValue JS_ThrowOutOfMemory(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
if (!rt->in_out_of_memory) {
rt->in_out_of_memory = TRUE;
JS_ThrowInternalError(ctx, "out of memory");
rt->in_out_of_memory = FALSE;
}
return JS_EXCEPTION;
}
JSValue JS_ThrowStackOverflow(JSContext *ctx)
{
return JS_ThrowInternalError(ctx, "stack overflow");
}
JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx)
{
return JS_ThrowTypeError(ctx, "not an object");
}
JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx)
{
return JS_ThrowTypeError(ctx, "not a symbol");
}
int js_throw_URIError(JSContext *ctx, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap);
va_end(ap);
return -1;
}
JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name)
{
char buf[ATOM_GET_STR_BUF_SIZE];
return JS_ThrowReferenceError(ctx, "'%s' is not defined",
JS_AtomGetStr(ctx, buf, sizeof(buf), name));
}
JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)
{
char buf[ATOM_GET_STR_BUF_SIZE];
return JS_ThrowReferenceError(ctx, "%s is not initialized",
name == JS_ATOM_NULL ? "lexical variable" :
JS_AtomGetStr(ctx, buf, sizeof(buf), name));
}
JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,
JSFunctionBytecode *b,
int idx, BOOL is_ref)
{
JSAtom atom = JS_ATOM_NULL;
if (is_ref) {
atom = b->closure_var[idx].var_name;
} else {
/* not present if the function is stripped and contains no eval() */
if (b->vardefs)
atom = b->vardefs[b->arg_count + idx].var_name;
}
return JS_ThrowReferenceErrorUninitialized(ctx, atom);
}
JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop)
{
return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
}
JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)
{
return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist",
atom);
}
JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx)
{
return JS_ThrowTypeError(ctx, "ArrayBuffer is detached");
}
/* in order to avoid executing arbitrary code during the stack trace
generation, we only look at simple 'name' properties containing a
string. */
static const char *get_func_name(JSContext *ctx, JSValueConst func)
{
JSProperty *pr;
JSShapeProperty *prs;
JSValueConst val;
if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)
return NULL;
prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name);
if (!prs)
return NULL;
if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
return NULL;
val = pr->u.value;
if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
return NULL;
return JS_ToCString(ctx, val);
}
int find_line_num(JSContext *ctx, JSFunctionBytecode *b, uint32_t pc_value)
{
const uint8_t *p_end, *p;
int new_line_num, line_num, pc, v, ret;
unsigned int op;
if (!b->has_debug || !b->debug.pc2line_buf) {
/* function was stripped */
return -1;
}
p = b->debug.pc2line_buf;
p_end = p + b->debug.pc2line_len;
pc = 0;
line_num = b->debug.line_num;
while (p < p_end) {
op = *p++;
if (op == 0) {
uint32_t val;
ret = get_leb128(&val, p, p_end);
if (ret < 0)
goto fail;
pc += val;
p += ret;
ret = get_sleb128(&v, p, p_end);
if (ret < 0) {
fail:
/* should never happen */
return b->debug.line_num;
}
p += ret;
new_line_num = line_num + v;
} else {
op -= PC2LINE_OP_FIRST;
pc += (op / PC2LINE_RANGE);
new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;
}
if (pc_value < pc)
return line_num;
line_num = new_line_num;
}
return line_num;
}
/* if filename != NULL, an additional level is added with the filename
and line number information (used for parse error). */
void build_backtrace(JSContext *ctx, JSValueConst error_obj,
const char *filename, int line_num,
int backtrace_flags)
{
JSStackFrame *sf;
JSValue str;
DynBuf dbuf;
const char *func_name_str;
const char *str1;
JSObject *p;
BOOL backtrace_barrier;
js_dbuf_init(ctx, &dbuf);
if (filename) {
dbuf_printf(&dbuf, " at %s", filename);
if (line_num != -1)
dbuf_printf(&dbuf, ":%d", line_num);
dbuf_putc(&dbuf, '\n');
str = JS_NewString(ctx, filename);
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
if (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL)
goto done;
}
for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
continue;
}
func_name_str = get_func_name(ctx, sf->cur_func);
if (!func_name_str || func_name_str[0] == '\0')
str1 = "<anonymous>";
else
str1 = func_name_str;
dbuf_printf(&dbuf, " at %s", str1);
JS_FreeCString(ctx, func_name_str);
p = JS_VALUE_GET_OBJ(sf->cur_func);
backtrace_barrier = FALSE;
if (js_class_has_bytecode(p->class_id)) {
JSFunctionBytecode *b;
const char *atom_str;
int line_num1;
b = p->u.func.function_bytecode;
backtrace_barrier = b->backtrace_barrier;
if (b->has_debug) {
line_num1 = find_line_num(ctx, b,
sf->cur_pc - b->byte_code_buf - 1);
atom_str = JS_AtomToCString(ctx, b->debug.filename);
dbuf_printf(&dbuf, " (%s",
atom_str ? atom_str : "<null>");
JS_FreeCString(ctx, atom_str);
if (line_num1 != -1)
dbuf_printf(&dbuf, ":%d", line_num1);
dbuf_putc(&dbuf, ')');
}
} else {
dbuf_printf(&dbuf, " (native)");
}
dbuf_putc(&dbuf, '\n');
/* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */
if (backtrace_barrier)
break;
}
done:
dbuf_putc(&dbuf, '\0');
if (dbuf_error(&dbuf))
str = JS_NULL;
else
str = JS_NewString(ctx, (char *)dbuf.buf);
dbuf_free(&dbuf);
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
}
JSValue throw_bf_exception(JSContext *ctx, int status)
{
const char *str;
if (status & BF_ST_MEM_ERROR)
return JS_ThrowOutOfMemory(ctx);
if (status & BF_ST_DIVIDE_ZERO) {
str = "division by zero";
} else if (status & BF_ST_INVALID_OP) {
str = "invalid operation";
} else {
str = "integer overflow";
}
return JS_ThrowRangeError(ctx, "%s", str);
}

View file

@ -1,72 +0,0 @@
/*
* QuickJS: Example of C module
*
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "../quickjs.h"
#define countof(x) (sizeof(x) / sizeof((x)[0]))
static int fib(int n)
{
if (n <= 0)
return 0;
else if (n == 1)
return 1;
else
return fib(n - 1) + fib(n - 2);
}
static JSValue js_fib(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
int n, res;
if (JS_ToInt32(ctx, &n, argv[0]))
return JS_EXCEPTION;
res = fib(n);
return JS_NewInt32(ctx, res);
}
static const JSCFunctionListEntry js_fib_funcs[] = {
JS_CFUNC_DEF("fib", 1, js_fib ),
};
static int js_fib_init(JSContext *ctx, JSModuleDef *m)
{
return JS_SetModuleExportList(ctx, m, js_fib_funcs,
countof(js_fib_funcs));
}
#ifdef JS_SHARED_LIBRARY
#define JS_INIT_MODULE js_init_module
#else
#define JS_INIT_MODULE js_init_module_fib
#endif
JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
{
JSModuleDef *m;
m = JS_NewCModule(ctx, module_name, js_fib_init);
if (!m)
return NULL;
JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs));
return m;
}

View file

@ -1,10 +0,0 @@
/* fib module */
export function fib(n)
{
if (n <= 0)
return 0;
else if (n == 1)
return 1;
else
return fib(n - 1) + fib(n - 2);
}

View file

@ -1 +0,0 @@
console.log("Hello World");

View file

@ -1,6 +0,0 @@
/* example of JS module */
import { fib } from "./fib_module.js";
console.log("Hello World");
console.log("fib(10)=", fib(10));

View file

@ -1,68 +0,0 @@
/*
* PI computation in Javascript using the QuickJS bigdecimal type
* (decimal floating point)
*/
"use strict";
/* compute PI with a precision of 'prec' digits */
function calc_pi(prec) {
const CHUD_A = 13591409m;
const CHUD_B = 545140134m;
const CHUD_C = 640320m;
const CHUD_C3 = 10939058860032000m; /* C^3/24 */
const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */
/* return [P, Q, G] */
function chud_bs(a, b, need_G) {
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1;
if (a == (b - 1n)) {
b1 = BigDecimal(b);
G = (2m * b1 - 1m) * (6m * b1 - 1m) * (6m * b1 - 5m);
P = G * (CHUD_B * b1 + CHUD_A);
if (b & 1n)
P = -P;
G = G;
Q = b1 * b1 * b1 * CHUD_C3;
} else {
c = (a + b) >> 1n;
[P1, Q1, G1] = chud_bs(a, c, true);
[P2, Q2, G2] = chud_bs(c, b, need_G);
P = P1 * Q2 + P2 * G1;
Q = Q1 * Q2;
if (need_G)
G = G1 * G2;
else
G = 0m;
}
return [P, Q, G];
}
var n, P, Q, G;
/* number of serie terms */
n = BigInt(Math.ceil(prec / CHUD_DIGITS_PER_TERM)) + 10n;
[P, Q, G] = chud_bs(0n, n, false);
Q = BigDecimal.div(Q, (P + Q * CHUD_A),
{ roundingMode: "half-even",
maximumSignificantDigits: prec });
G = (CHUD_C / 12m) * BigDecimal.sqrt(CHUD_C,
{ roundingMode: "half-even",
maximumSignificantDigits: prec });
return Q * G;
}
(function() {
var r, n_digits, n_bits;
if (typeof scriptArgs != "undefined") {
if (scriptArgs.length < 2) {
print("usage: pi n_digits");
return;
}
n_digits = scriptArgs[1] | 0;
} else {
n_digits = 1000;
}
/* we add more digits to reduce the probability of bad rounding for
the last digits */
r = calc_pi(n_digits + 20);
print(r.toFixed(n_digits, "down"));
})();

View file

@ -1,66 +0,0 @@
/*
* PI computation in Javascript using the QuickJS bigfloat type
* (binary floating point)
*/
"use strict";
/* compute PI with a precision of 'prec' bits */
function calc_pi() {
const CHUD_A = 13591409n;
const CHUD_B = 545140134n;
const CHUD_C = 640320n;
const CHUD_C3 = 10939058860032000n; /* C^3/24 */
const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
/* return [P, Q, G] */
function chud_bs(a, b, need_G) {
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
if (a == (b - 1n)) {
G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
P = BigFloat(G * (CHUD_B * b + CHUD_A));
if (b & 1n)
P = -P;
G = BigFloat(G);
Q = BigFloat(b * b * b * CHUD_C3);
} else {
c = (a + b) >> 1n;
[P1, Q1, G1] = chud_bs(a, c, true);
[P2, Q2, G2] = chud_bs(c, b, need_G);
P = P1 * Q2 + P2 * G1;
Q = Q1 * Q2;
if (need_G)
G = G1 * G2;
else
G = 0l;
}
return [P, Q, G];
}
var n, P, Q, G;
/* number of serie terms */
n = BigInt(Math.ceil(BigFloatEnv.prec / CHUD_BITS_PER_TERM)) + 10n;
[P, Q, G] = chud_bs(0n, n, false);
Q = Q / (P + Q * BigFloat(CHUD_A));
G = BigFloat((CHUD_C / 12n)) * BigFloat.sqrt(BigFloat(CHUD_C));
return Q * G;
}
(function() {
var r, n_digits, n_bits;
if (typeof scriptArgs != "undefined") {
if (scriptArgs.length < 2) {
print("usage: pi n_digits");
return;
}
n_digits = scriptArgs[1];
} else {
n_digits = 1000;
}
n_bits = Math.ceil(n_digits * Math.log2(10));
/* we add more bits to reduce the probability of bad rounding for
the last digits */
BigFloatEnv.setPrec( () => {
r = calc_pi();
print(r.toFixed(n_digits, BigFloatEnv.RNDZ));
}, n_bits + 32);
})();

View file

@ -1,118 +0,0 @@
/*
* PI computation in Javascript using the BigInt type
*/
"use strict";
/* return floor(log2(a)) for a > 0 and 0 for a = 0 */
function floor_log2(a)
{
var k_max, a1, k, i;
k_max = 0n;
while ((a >> (2n ** k_max)) != 0n) {
k_max++;
}
k = 0n;
a1 = a;
for(i = k_max - 1n; i >= 0n; i--) {
a1 = a >> (2n ** i);
if (a1 != 0n) {
a = a1;
k |= (1n << i);
}
}
return k;
}
/* return ceil(log2(a)) for a > 0 */
function ceil_log2(a)
{
return floor_log2(a - 1n) + 1n;
}
/* return floor(sqrt(a)) (not efficient but simple) */
function int_sqrt(a)
{
var l, u, s;
if (a == 0n)
return a;
l = ceil_log2(a);
u = 1n << ((l + 1n) / 2n);
/* u >= floor(sqrt(a)) */
for(;;) {
s = u;
u = ((a / s) + s) / 2n;
if (u >= s)
break;
}
return s;
}
/* return pi * 2**prec */
function calc_pi(prec) {
const CHUD_A = 13591409n;
const CHUD_B = 545140134n;
const CHUD_C = 640320n;
const CHUD_C3 = 10939058860032000n; /* C^3/24 */
const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
/* return [P, Q, G] */
function chud_bs(a, b, need_G) {
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
if (a == (b - 1n)) {
G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
P = G * (CHUD_B * b + CHUD_A);
if (b & 1n)
P = -P;
Q = b * b * b * CHUD_C3;
} else {
c = (a + b) >> 1n;
[P1, Q1, G1] = chud_bs(a, c, true);
[P2, Q2, G2] = chud_bs(c, b, need_G);
P = P1 * Q2 + P2 * G1;
Q = Q1 * Q2;
if (need_G)
G = G1 * G2;
else
G = 0n;
}
return [P, Q, G];
}
var n, P, Q, G;
/* number of serie terms */
n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n;
[P, Q, G] = chud_bs(0n, n, false);
Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A);
G = int_sqrt(CHUD_C << (2n * prec));
return (Q * G) >> prec;
}
function main(args) {
var r, n_digits, n_bits, out;
if (args.length < 1) {
print("usage: pi n_digits");
return;
}
n_digits = args[0] | 0;
/* we add more bits to reduce the probability of bad rounding for
the last digits */
n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n;
r = calc_pi(n_bits);
r = ((10n ** BigInt(n_digits)) * r) >> n_bits;
out = r.toString();
print(out[0] + "." + out.slice(1));
}
var args;
if (typeof scriptArgs != "undefined") {
args = scriptArgs;
args.shift();
} else if (typeof arguments != "undefined") {
args = arguments;
} else {
/* default: 1000 digits */
args=[1000];
}
main(args);

View file

@ -1,151 +0,0 @@
/*
* QuickJS: Example of C module with a class
*
* Copyright (c) 2019 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "../quickjs.h"
#include <math.h>
#define countof(x) (sizeof(x) / sizeof((x)[0]))
/* Point Class */
typedef struct {
int x;
int y;
} JSPointData;
static JSClassID js_point_class_id;
static void js_point_finalizer(JSRuntime *rt, JSValue val)
{
JSPointData *s = JS_GetOpaque(val, js_point_class_id);
/* Note: 's' can be NULL in case JS_SetOpaque() was not called */
js_free_rt(rt, s);
}
static JSValue js_point_ctor(JSContext *ctx,
JSValueConst new_target,
int argc, JSValueConst *argv)
{
JSPointData *s;
JSValue obj = JS_UNDEFINED;
JSValue proto;
s = js_mallocz(ctx, sizeof(*s));
if (!s)
return JS_EXCEPTION;
if (JS_ToInt32(ctx, &s->x, argv[0]))
goto fail;
if (JS_ToInt32(ctx, &s->y, argv[1]))
goto fail;
/* using new_target to get the prototype is necessary when the
class is extended. */
proto = JS_GetPropertyStr(ctx, new_target, "prototype");
if (JS_IsException(proto))
goto fail;
obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id);
JS_FreeValue(ctx, proto);
if (JS_IsException(obj))
goto fail;
JS_SetOpaque(obj, s);
return obj;
fail:
js_free(ctx, s);
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic)
{
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
if (!s)
return JS_EXCEPTION;
if (magic == 0)
return JS_NewInt32(ctx, s->x);
else
return JS_NewInt32(ctx, s->y);
}
static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic)
{
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
int v;
if (!s)
return JS_EXCEPTION;
if (JS_ToInt32(ctx, &v, val))
return JS_EXCEPTION;
if (magic == 0)
s->x = v;
else
s->y = v;
return JS_UNDEFINED;
}
static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
if (!s)
return JS_EXCEPTION;
return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y));
}
static JSClassDef js_point_class = {
"Point",
.finalizer = js_point_finalizer,
};
static const JSCFunctionListEntry js_point_proto_funcs[] = {
JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0),
JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1),
JS_CFUNC_DEF("norm", 0, js_point_norm),
};
static int js_point_init(JSContext *ctx, JSModuleDef *m)
{
JSValue point_proto, point_class;
/* create the Point class */
JS_NewClassID(&js_point_class_id);
JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class);
point_proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs));
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;
}
JSModuleDef *js_init_module(JSContext *ctx, const char *module_name)
{
JSModuleDef *m;
m = JS_NewCModule(ctx, module_name, js_point_init);
if (!m)
return NULL;
JS_AddModuleExport(ctx, m, "Point");
return m;
}

View file

@ -1,6 +0,0 @@
/* example of JS module importing a C module */
import { fib } from "./fib.so";
console.log("Hello World");
console.log("fib(10)=", fib(10));

View file

@ -1,40 +0,0 @@
/* example of JS module importing a C module */
import { Point } from "./point.so";
function assert(b, str)
{
if (b) {
return;
} else {
throw Error("assertion failed: " + str);
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y);
this.color = color;
}
get_color() {
return this.color;
}
};
function main()
{
var pt, pt2;
pt = new Point(2, 3);
assert(pt.x === 2);
assert(pt.y === 3);
pt.x = 4;
assert(pt.x === 4);
assert(pt.norm() == 5);
pt2 = new ColorPoint(2, 3, 0xffffff);
assert(pt2.x === 2);
assert(pt2.color === 0xffffff);
assert(pt2.get_color() === 0xffffff);
}
main();

File diff suppressed because it is too large Load diff

View file

@ -1,495 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/runtime/runtime.h"
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
void js_trigger_gc(JSRuntime *rt, size_t size)
{
BOOL force_gc;
#ifdef FORCE_GC_AT_MALLOC
force_gc = TRUE;
#else
force_gc = ((rt->malloc_state.malloc_size + size) >
rt->malloc_gc_threshold);
#endif
if (force_gc) {
#ifdef DUMP_GC
printf("GC: size=%" PRIu64 "\n",
(uint64_t)rt->malloc_state.malloc_size);
#endif
JS_RunGC(rt);
rt->malloc_gc_threshold = rt->malloc_state.malloc_size +
(rt->malloc_state.malloc_size >> 1);
}
}
void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
{
if (JS_VALUE_HAS_REF_COUNT(val)) {
switch(JS_VALUE_GET_TAG(val)) {
case JS_TAG_OBJECT:
case JS_TAG_FUNCTION_BYTECODE:
mark_func(rt, JS_VALUE_GET_PTR(val));
break;
default:
break;
}
}
}
static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
JS_MarkFunc *mark_func)
{
int i;
for(i = 0; i < m->export_entries_count; i++) {
JSExportEntry *me = &m->export_entries[i];
if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
me->u.local.var_ref) {
mark_func(rt, &me->u.local.var_ref->header);
}
}
JS_MarkValue(rt, m->module_ns, mark_func);
JS_MarkValue(rt, m->func_obj, mark_func);
JS_MarkValue(rt, m->eval_exception, mark_func);
JS_MarkValue(rt, m->meta_obj, mark_func);
}
static void JS_MarkContext(JSRuntime *rt, JSContext *ctx, JS_MarkFunc *mark_func)
{
int i;
struct list_head *el;
/* modules are not seen by the GC, so we directly mark the objects
referenced by each module */
list_for_each(el, &ctx->loaded_modules) {
JSModuleDef *m = list_entry(el, JSModuleDef, link);
js_mark_module_def(rt, m, mark_func);
}
JS_MarkValue(rt, ctx->global_obj, mark_func);
JS_MarkValue(rt, ctx->global_var_obj, mark_func);
JS_MarkValue(rt, ctx->throw_type_error, mark_func);
JS_MarkValue(rt, ctx->eval_obj, mark_func);
JS_MarkValue(rt, ctx->array_proto_values, mark_func);
for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
}
for(i = 0; i < rt->class_count; i++) {
JS_MarkValue(rt, ctx->class_proto[i], mark_func);
}
JS_MarkValue(rt, ctx->iterator_proto, mark_func);
JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);
JS_MarkValue(rt, ctx->promise_ctor, mark_func);
JS_MarkValue(rt, ctx->array_ctor, mark_func);
JS_MarkValue(rt, ctx->regexp_ctor, mark_func);
JS_MarkValue(rt, ctx->function_ctor, mark_func);
JS_MarkValue(rt, ctx->function_proto, mark_func);
if (ctx->array_shape)
mark_func(rt, &ctx->array_shape->header);
}
static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
JS_MarkFunc *mark_func)
{
switch(gp->gc_obj_type) {
case JS_GC_OBJ_TYPE_JS_OBJECT:
{
JSObject *p = (JSObject *)gp;
JSShapeProperty *prs;
JSShape *sh;
int i;
sh = p->shape;
mark_func(rt, &sh->header);
/* mark all the fields */
prs = get_shape_prop(sh);
for(i = 0; i < sh->prop_count; i++) {
JSProperty *pr = &p->prop[i];
if (prs->atom != JS_ATOM_NULL) {
if (prs->flags & JS_PROP_TMASK) {
if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
if (pr->u.getset.getter)
mark_func(rt, &pr->u.getset.getter->header);
if (pr->u.getset.setter)
mark_func(rt, &pr->u.getset.setter->header);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
if (pr->u.var_ref->is_detached) {
/* Note: the tag does not matter
provided it is a GC object */
mark_func(rt, &pr->u.var_ref->header);
}
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
js_autoinit_mark(rt, pr, mark_func);
}
} else {
JS_MarkValue(rt, pr->u.value, mark_func);
}
}
prs++;
}
if (p->class_id != JS_CLASS_OBJECT) {
JSClassGCMark *gc_mark;
gc_mark = rt->class_array[p->class_id].gc_mark;
if (gc_mark)
gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func);
}
}
break;
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
/* the template objects can be part of a cycle */
{
JSFunctionBytecode *b = (JSFunctionBytecode *)gp;
int i;
for(i = 0; i < b->cpool_count; i++) {
JS_MarkValue(rt, b->cpool[i], mark_func);
}
if (b->realm)
mark_func(rt, &b->realm->header);
}
break;
case JS_GC_OBJ_TYPE_VAR_REF:
{
JSVarRef *var_ref = (JSVarRef *)gp;
/* only detached variable referenced are taken into account */
assert(var_ref->is_detached);
JS_MarkValue(rt, *var_ref->pvalue, mark_func);
}
break;
case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
{
JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp;
if (s->is_active)
async_func_mark(rt, &s->func_state, mark_func);
JS_MarkValue(rt, s->resolving_funcs[0], mark_func);
JS_MarkValue(rt, s->resolving_funcs[1], mark_func);
}
break;
case JS_GC_OBJ_TYPE_SHAPE:
{
JSShape *sh = (JSShape *)gp;
if (sh->proto != NULL) {
mark_func(rt, &sh->proto->header);
}
}
break;
case JS_GC_OBJ_TYPE_JS_CONTEXT:
{
JSContext *ctx = (JSContext *)gp;
JS_MarkContext(rt, ctx, mark_func);
}
break;
default:
abort();
}
}
static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p)
{
assert(p->ref_count > 0);
p->ref_count--;
if (p->ref_count == 0 && p->mark == 1) {
list_del(&p->link);
list_add_tail(&p->link, &rt->tmp_obj_list);
}
}
static void gc_decref(JSRuntime *rt)
{
struct list_head *el, *el1;
JSGCObjectHeader *p;
init_list_head(&rt->tmp_obj_list);
/* decrement the refcount of all the children of all the GC
objects and move the GC objects with zero refcount to
tmp_obj_list */
list_for_each_safe(el, el1, &rt->gc_obj_list) {
p = list_entry(el, JSGCObjectHeader, link);
assert(p->mark == 0);
mark_children(rt, p, gc_decref_child);
p->mark = 1;
if (p->ref_count == 0) {
list_del(&p->link);
list_add_tail(&p->link, &rt->tmp_obj_list);
}
}
}
static void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p)
{
p->ref_count++;
if (p->ref_count == 1) {
/* ref_count was 0: remove from tmp_obj_list and add at the
end of gc_obj_list */
list_del(&p->link);
list_add_tail(&p->link, &rt->gc_obj_list);
p->mark = 0; /* reset the mark for the next GC call */
}
}
static void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p)
{
p->ref_count++;
}
static void gc_scan(JSRuntime *rt)
{
struct list_head *el;
JSGCObjectHeader *p;
/* keep the objects with a refcount > 0 and their children. */
list_for_each(el, &rt->gc_obj_list) {
p = list_entry(el, JSGCObjectHeader, link);
assert(p->ref_count > 0);
p->mark = 0; /* reset the mark for the next GC call */
mark_children(rt, p, gc_scan_incref_child);
}
/* restore the refcount of the objects to be deleted. */
list_for_each(el, &rt->tmp_obj_list) {
p = list_entry(el, JSGCObjectHeader, link);
mark_children(rt, p, gc_scan_incref_child2);
}
}
static void free_object(JSRuntime *rt, JSObject *p)
{
int i;
JSClassFinalizer *finalizer;
JSShape *sh;
JSShapeProperty *pr;
p->free_mark = 1; /* used to tell the object is invalid when
freeing cycles */
/* free all the fields */
sh = p->shape;
pr = get_shape_prop(sh);
for(i = 0; i < sh->prop_count; i++) {
free_property(rt, &p->prop[i], pr->flags);
pr++;
}
js_free_rt(rt, p->prop);
/* as an optimization we destroy the shape immediately without
putting it in gc_zero_ref_count_list */
js_free_shape(rt, sh);
/* fail safe */
p->shape = NULL;
p->prop = NULL;
if (UNLIKELY(p->first_weak_ref)) {
reset_weak_ref(rt, p);
}
finalizer = rt->class_array[p->class_id].finalizer;
if (finalizer)
(*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p));
/* fail safe */
p->class_id = 0;
p->u.opaque = NULL;
p->u.func.var_refs = NULL;
p->u.func.home_object = NULL;
remove_gc_object(&p->header);
if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && p->header.ref_count != 0) {
list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);
} else {
js_free_rt(rt, p);
}
}
static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
{
switch(gp->gc_obj_type) {
case JS_GC_OBJ_TYPE_JS_OBJECT:
free_object(rt, (JSObject *)gp);
break;
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
free_function_bytecode(rt, (JSFunctionBytecode *)gp);
break;
default:
abort();
}
}
void free_zero_refcount(JSRuntime *rt)
{
struct list_head *el;
JSGCObjectHeader *p;
rt->gc_phase = JS_GC_PHASE_DECREF;
for(;;) {
el = rt->gc_zero_ref_count_list.next;
if (el == &rt->gc_zero_ref_count_list)
break;
p = list_entry(el, JSGCObjectHeader, link);
assert(p->ref_count == 0);
free_gc_object(rt, p);
}
rt->gc_phase = JS_GC_PHASE_NONE;
}
static void gc_free_cycles(JSRuntime *rt)
{
struct list_head *el, *el1;
JSGCObjectHeader *p;
#ifdef DUMP_GC_FREE
BOOL header_done = FALSE;
#endif
rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES;
for(;;) {
el = rt->tmp_obj_list.next;
if (el == &rt->tmp_obj_list)
break;
p = list_entry(el, JSGCObjectHeader, link);
/* Only need to free the GC object associated with JS
values. The rest will be automatically removed because they
must be referenced by them. */
switch(p->gc_obj_type) {
case JS_GC_OBJ_TYPE_JS_OBJECT:
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
#ifdef DUMP_GC_FREE
if (!header_done) {
printf("Freeing cycles:\n");
JS_DumpObjectHeader(rt);
header_done = TRUE;
}
JS_DumpGCObject(rt, p);
#endif
free_gc_object(rt, p);
break;
default:
list_del(&p->link);
list_add_tail(&p->link, &rt->gc_zero_ref_count_list);
break;
}
}
rt->gc_phase = JS_GC_PHASE_NONE;
list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) {
p = list_entry(el, JSGCObjectHeader, link);
assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||
p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
js_free_rt(rt, p);
}
init_list_head(&rt->gc_zero_ref_count_list);
}
void JS_RunGC(JSRuntime *rt)
{
/* decrement the reference of the children of each object. mark =
1 after this pass. */
gc_decref(rt);
/* keep the GC objects with a non zero refcount and their childs */
gc_scan(rt);
/* free the GC objects in a cycle */
gc_free_cycles(rt);
}
/* Return false if not an object or if the object has already been
freed (zombie objects are visible in finalizers when freeing
cycles). */
BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj)
{
JSObject *p;
if (!JS_IsObject(obj))
return FALSE;
p = JS_VALUE_GET_OBJ(obj);
return !p->free_mark;
}
/* called with the ref_count of 'v' reaches zero. */
void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
{
uint32_t tag = JS_VALUE_GET_TAG(v);
#ifdef DUMP_FREE
{
printf("Freeing ");
if (tag == JS_TAG_OBJECT) {
JS_DumpObject(rt, JS_VALUE_GET_OBJ(v));
} else {
JS_DumpValueShort(rt, v);
printf("\n");
}
}
#endif
switch(tag) {
case JS_TAG_STRING:
{
JSString *p = JS_VALUE_GET_STRING(v);
if (p->atom_type) {
JS_FreeAtomStruct(rt, p);
} else {
#ifdef DUMP_LEAKS
list_del(&p->link);
#endif
js_free_rt(rt, p);
}
}
break;
case JS_TAG_OBJECT:
case JS_TAG_FUNCTION_BYTECODE:
{
JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);
if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
list_del(&p->link);
list_add(&p->link, &rt->gc_zero_ref_count_list);
if (rt->gc_phase == JS_GC_PHASE_NONE) {
free_zero_refcount(rt);
}
}
}
break;
case JS_TAG_MODULE:
abort(); /* never freed here */
break;
#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
case JS_TAG_BIG_FLOAT:
{
JSBigFloat *bf = JS_VALUE_GET_PTR(v);
bf_delete(&bf->num);
js_free_rt(rt, bf);
}
break;
case JS_TAG_BIG_DECIMAL:
{
JSBigDecimal *bf = JS_VALUE_GET_PTR(v);
bfdec_delete(&bf->num);
js_free_rt(rt, bf);
}
break;
#endif
case JS_TAG_SYMBOL:
{
JSAtomStruct *p = JS_VALUE_GET_PTR(v);
JS_FreeAtomStruct(rt, p);
}
break;
default:
printf("__JS_FreeValue: unknown tag=%d\n", tag);
abort();
}
}
void __JS_FreeValue(JSContext *ctx, JSValue v)
{
__JS_FreeValueRT(ctx->rt, v);
}

View file

@ -1,509 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/runtime/runtime.h"
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
typedef enum JSGeneratorStateEnum {
JS_GENERATOR_STATE_SUSPENDED_START,
JS_GENERATOR_STATE_SUSPENDED_YIELD,
JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
JS_GENERATOR_STATE_EXECUTING,
JS_GENERATOR_STATE_COMPLETED,
} JSGeneratorStateEnum;
typedef struct JSGeneratorData {
JSGeneratorStateEnum state;
JSAsyncFunctionState func_state;
} JSGeneratorData;
static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s)
{
if (s->state == JS_GENERATOR_STATE_COMPLETED)
return;
async_func_free(rt, &s->func_state);
s->state = JS_GENERATOR_STATE_COMPLETED;
}
void js_generator_finalizer(JSRuntime *rt, JSValue obj)
{
JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR);
if (s) {
free_generator_stack_rt(rt, s);
js_free_rt(rt, s);
}
}
static void free_generator_stack(JSContext *ctx, JSGeneratorData *s)
{
free_generator_stack_rt(ctx->rt, s);
}
void js_generator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
JSGeneratorData *s = p->u.generator_data;
if (!s || s->state == JS_GENERATOR_STATE_COMPLETED)
return;
async_func_mark(rt, &s->func_state, mark_func);
}
static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv,
BOOL *pdone, int magic)
{
JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);
JSStackFrame *sf;
JSValue ret, func_ret;
*pdone = TRUE;
if (!s)
return JS_ThrowTypeError(ctx, "not a generator");
sf = &s->func_state.frame;
switch(s->state) {
default:
case JS_GENERATOR_STATE_SUSPENDED_START:
if (magic == GEN_MAGIC_NEXT) {
goto exec_no_arg;
} else {
free_generator_stack(ctx, s);
goto done;
}
break;
case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
case JS_GENERATOR_STATE_SUSPENDED_YIELD:
/* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
ret = JS_DupValue(ctx, argv[0]);
if (magic == GEN_MAGIC_THROW &&
s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
JS_Throw(ctx, ret);
s->func_state.throw_flag = TRUE;
} else {
sf->cur_sp[-1] = ret;
sf->cur_sp[0] = JS_NewInt32(ctx, magic);
sf->cur_sp++;
exec_no_arg:
s->func_state.throw_flag = FALSE;
}
s->state = JS_GENERATOR_STATE_EXECUTING;
func_ret = async_func_resume(ctx, &s->func_state);
s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD;
if (JS_IsException(func_ret)) {
/* finalize the execution in case of exception */
free_generator_stack(ctx, s);
return func_ret;
}
if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
/* get the returned yield value at the top of the stack */
ret = sf->cur_sp[-1];
sf->cur_sp[-1] = JS_UNDEFINED;
if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
/* return (value, done) object */
*pdone = 2;
} else {
*pdone = FALSE;
}
} else {
/* end of iterator */
ret = sf->cur_sp[-1];
sf->cur_sp[-1] = JS_UNDEFINED;
JS_FreeValue(ctx, func_ret);
free_generator_stack(ctx, s);
}
break;
case JS_GENERATOR_STATE_COMPLETED:
done:
/* execution is finished */
switch(magic) {
default:
case GEN_MAGIC_NEXT:
ret = JS_UNDEFINED;
break;
case GEN_MAGIC_RETURN:
ret = JS_DupValue(ctx, argv[0]);
break;
case GEN_MAGIC_THROW:
ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0]));
break;
}
break;
case JS_GENERATOR_STATE_EXECUTING:
ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator");
break;
}
return ret;
}
JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
JSValueConst this_obj, int argc,
JSValueConst *argv, int flags)
{
JSValue obj, func_ret;
JSGeneratorData *s;
s = js_mallocz(ctx, sizeof(*s));
if (!s)
return JS_EXCEPTION;
s->state = JS_GENERATOR_STATE_SUSPENDED_START;
if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
s->state = JS_GENERATOR_STATE_COMPLETED;
goto fail;
}
/* execute the function up to 'OP_initial_yield' */
func_ret = async_func_resume(ctx, &s->func_state);
if (JS_IsException(func_ret))
goto fail;
JS_FreeValue(ctx, func_ret);
obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR);
if (JS_IsException(obj))
goto fail;
JS_SetOpaque(obj, s);
return obj;
fail:
free_generator_stack_rt(ctx->rt, s);
js_free(ctx, s);
return JS_EXCEPTION;
}
static JSValue js_async_generator_resolve_function(JSContext *ctx,
JSValueConst this_obj,
int argc, JSValueConst *argv,
int magic, JSValue *func_data);
static int js_async_generator_resolve_function_create(JSContext *ctx,
JSValueConst generator,
JSValue *resolving_funcs,
BOOL is_resume_next)
{
int i;
JSValue func;
for(i = 0; i < 2; i++) {
func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1,
i + is_resume_next * 2, 1, &generator);
if (JS_IsException(func)) {
if (i == 1)
JS_FreeValue(ctx, resolving_funcs[0]);
return -1;
}
resolving_funcs[i] = func;
}
return 0;
}
static int js_async_generator_await(JSContext *ctx,
JSAsyncGeneratorData *s,
JSValueConst value)
{
JSValue promise, resolving_funcs[2], resolving_funcs1[2];
int i, res;
promise = js_promise_resolve(ctx, ctx->promise_ctor,
1, &value, 0);
if (JS_IsException(promise))
goto fail;
if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator),
resolving_funcs, FALSE)) {
JS_FreeValue(ctx, promise);
goto fail;
}
/* Note: no need to create 'thrownawayCapability' as in
the spec */
for(i = 0; i < 2; i++)
resolving_funcs1[i] = JS_UNDEFINED;
res = perform_promise_then(ctx, promise,
(JSValueConst *)resolving_funcs,
(JSValueConst *)resolving_funcs1);
JS_FreeValue(ctx, promise);
for(i = 0; i < 2; i++)
JS_FreeValue(ctx, resolving_funcs[i]);
if (res)
goto fail;
return 0;
fail:
return -1;
}
static void js_async_generator_resolve_or_reject(JSContext *ctx,
JSAsyncGeneratorData *s,
JSValueConst result,
int is_reject)
{
JSAsyncGeneratorRequest *next;
JSValue ret;
next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
list_del(&next->link);
ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1,
&result);
JS_FreeValue(ctx, ret);
JS_FreeValue(ctx, next->result);
JS_FreeValue(ctx, next->promise);
JS_FreeValue(ctx, next->resolving_funcs[0]);
JS_FreeValue(ctx, next->resolving_funcs[1]);
js_free(ctx, next);
}
static void js_async_generator_resolve(JSContext *ctx,
JSAsyncGeneratorData *s,
JSValueConst value,
BOOL done)
{
JSValue result;
result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done);
/* XXX: better exception handling ? */
js_async_generator_resolve_or_reject(ctx, s, result, 0);
JS_FreeValue(ctx, result);
}
static void js_async_generator_reject(JSContext *ctx,
JSAsyncGeneratorData *s,
JSValueConst exception)
{
js_async_generator_resolve_or_reject(ctx, s, exception, 1);
}
static void js_async_generator_complete(JSContext *ctx,
JSAsyncGeneratorData *s)
{
if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {
s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
async_func_free(ctx->rt, &s->func_state);
}
}
static int js_async_generator_completed_return(JSContext *ctx,
JSAsyncGeneratorData *s,
JSValueConst value)
{
JSValue promise, resolving_funcs[2], resolving_funcs1[2];
int res;
promise = js_promise_resolve(ctx, ctx->promise_ctor,
1, (JSValueConst *)&value, 0);
if (JS_IsException(promise))
return -1;
if (js_async_generator_resolve_function_create(ctx,
JS_MKPTR(JS_TAG_OBJECT, s->generator),
resolving_funcs1,
TRUE)) {
JS_FreeValue(ctx, promise);
return -1;
}
resolving_funcs[0] = JS_UNDEFINED;
resolving_funcs[1] = JS_UNDEFINED;
res = perform_promise_then(ctx, promise,
(JSValueConst *)resolving_funcs1,
(JSValueConst *)resolving_funcs);
JS_FreeValue(ctx, resolving_funcs1[0]);
JS_FreeValue(ctx, resolving_funcs1[1]);
JS_FreeValue(ctx, promise);
return res;
}
void js_async_generator_resume_next(JSContext *ctx, JSAsyncGeneratorData *s)
{
JSAsyncGeneratorRequest *next;
JSValue func_ret, value;
for(;;) {
if (list_empty(&s->queue))
break;
next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
switch(s->state) {
case JS_ASYNC_GENERATOR_STATE_EXECUTING:
/* only happens when restarting execution after await() */
goto resume_exec;
case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN:
goto done;
case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START:
if (next->completion_type == GEN_MAGIC_NEXT) {
goto exec_no_arg;
} else {
js_async_generator_complete(ctx, s);
}
break;
case JS_ASYNC_GENERATOR_STATE_COMPLETED:
if (next->completion_type == GEN_MAGIC_NEXT) {
js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE);
} else if (next->completion_type == GEN_MAGIC_RETURN) {
s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN;
js_async_generator_completed_return(ctx, s, next->result);
goto done;
} else {
js_async_generator_reject(ctx, s, next->result);
}
goto done;
case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD:
case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
value = JS_DupValue(ctx, next->result);
if (next->completion_type == GEN_MAGIC_THROW &&
s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) {
JS_Throw(ctx, value);
s->func_state.throw_flag = TRUE;
} else {
/* 'yield' returns a value. 'yield *' also returns a value
in case the 'throw' method is called */
s->func_state.frame.cur_sp[-1] = value;
s->func_state.frame.cur_sp[0] =
JS_NewInt32(ctx, next->completion_type);
s->func_state.frame.cur_sp++;
exec_no_arg:
s->func_state.throw_flag = FALSE;
}
s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING;
resume_exec:
func_ret = async_func_resume(ctx, &s->func_state);
if (JS_IsException(func_ret)) {
value = JS_GetException(ctx);
js_async_generator_complete(ctx, s);
js_async_generator_reject(ctx, s, value);
JS_FreeValue(ctx, value);
} else if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
int func_ret_code;
value = s->func_state.frame.cur_sp[-1];
s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
func_ret_code = JS_VALUE_GET_INT(func_ret);
switch(func_ret_code) {
case FUNC_RET_YIELD:
case FUNC_RET_YIELD_STAR:
if (func_ret_code == FUNC_RET_YIELD_STAR)
s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
else
s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD;
js_async_generator_resolve(ctx, s, value, FALSE);
JS_FreeValue(ctx, value);
break;
case FUNC_RET_AWAIT:
js_async_generator_await(ctx, s, value);
JS_FreeValue(ctx, value);
goto done;
default:
abort();
}
} else {
assert(JS_IsUndefined(func_ret));
/* end of function */
value = s->func_state.frame.cur_sp[-1];
s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
js_async_generator_complete(ctx, s);
js_async_generator_resolve(ctx, s, value, TRUE);
JS_FreeValue(ctx, value);
}
break;
default:
abort();
}
}
done: ;
}
static JSValue js_async_generator_resolve_function(JSContext *ctx,
JSValueConst this_obj,
int argc, JSValueConst *argv,
int magic, JSValue *func_data)
{
BOOL is_reject = magic & 1;
JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR);
JSValueConst arg = argv[0];
/* XXX: what if s == NULL */
if (magic >= 2) {
/* resume next case in AWAITING_RETURN state */
assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN ||
s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED);
s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
if (is_reject) {
js_async_generator_reject(ctx, s, arg);
} else {
js_async_generator_resolve(ctx, s, arg, TRUE);
}
} else {
/* restart function execution after await() */
assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING);
s->func_state.throw_flag = is_reject;
if (is_reject) {
JS_Throw(ctx, JS_DupValue(ctx, arg));
} else {
/* return value of await */
s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg);
}
js_async_generator_resume_next(ctx, s);
}
return JS_UNDEFINED;
}
void js_async_generator_free(JSRuntime *rt, JSAsyncGeneratorData *s)
{
struct list_head *el, *el1;
JSAsyncGeneratorRequest *req;
list_for_each_safe(el, el1, &s->queue) {
req = list_entry(el, JSAsyncGeneratorRequest, link);
JS_FreeValueRT(rt, req->result);
JS_FreeValueRT(rt, req->promise);
JS_FreeValueRT(rt, req->resolving_funcs[0]);
JS_FreeValueRT(rt, req->resolving_funcs[1]);
js_free_rt(rt, req);
}
if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
async_func_free(rt, &s->func_state);
}
js_free_rt(rt, s);
}
static const JSCFunctionListEntry js_generator_function_proto_funcs[] = {
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "GeneratorFunction", JS_PROP_CONFIGURABLE),
};
static const JSCFunctionListEntry js_generator_proto_funcs[] = {
JS_ITERATOR_NEXT_DEF("next", 1, js_generator_next, GEN_MAGIC_NEXT ),
JS_ITERATOR_NEXT_DEF("return", 1, js_generator_next, GEN_MAGIC_RETURN ),
JS_ITERATOR_NEXT_DEF("throw", 1, js_generator_next, GEN_MAGIC_THROW ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Generator", JS_PROP_CONFIGURABLE),
};
void JS_AddIntrinsicGenerator(JSContext *ctx)
{
JSValue obj1;
ctx->class_proto[JS_CLASS_GENERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_GENERATOR],
js_generator_proto_funcs,
countof(js_generator_proto_funcs));
ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
obj1 = JS_NewCFunctionMagic(ctx, js_function_constructor,
"GeneratorFunction", 1,
JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR);
JS_SetPropertyFunctionList(ctx,
ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
js_generator_function_proto_funcs,
countof(js_generator_function_proto_funcs));
JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
ctx->class_proto[JS_CLASS_GENERATOR],
JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
0, JS_PROP_CONFIGURABLE);
JS_FreeValue(ctx, obj1);
}

File diff suppressed because it is too large Load diff

View file

@ -1,47 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) {
return JS_DupValue(ctx, this_val);
}
static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator),
};
void JS_AddIteratorProto(JSContext *ctx) {
ctx->iterator_proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, ctx->iterator_proto,
js_iterator_proto_funcs,
countof(js_iterator_proto_funcs));
}

View file

@ -1,991 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/str/str.h"
#include "third_party/quickjs/internal.h"
#include "third_party/quickjs/libregexp.h"
#include "third_party/quickjs/quickjs.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
{
const uint8_t *p;
char ident_buf[128], *buf;
size_t ident_size, ident_pos;
JSAtom atom;
p = *pp;
buf = ident_buf;
ident_size = sizeof(ident_buf);
ident_pos = 0;
for(;;) {
buf[ident_pos++] = c;
c = *p;
if (c >= 128 ||
!((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1))
break;
p++;
if (UNLIKELY(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
atom = JS_ATOM_NULL;
goto done;
}
}
}
atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
done:
if (UNLIKELY(buf != ident_buf))
js_free(s->ctx, buf);
*pp = p;
return atom;
}
static __exception int json_next_token(JSParseState *s)
{
const uint8_t *p;
int c;
JSAtom atom;
if (js_check_stack_overflow(s->ctx->rt, 0)) {
return js_parse_error(s, "stack overflow");
}
free_token(s, &s->token);
p = s->last_ptr = s->buf_ptr;
s->last_line_num = s->token.line_num;
redo:
s->token.line_num = s->line_num;
s->token.ptr = p;
c = *p;
switch(c) {
case 0:
if (p >= s->buf_end) {
s->token.val = TOK_EOF;
} else {
goto def_token;
}
break;
case '\'':
if (!s->ext_json) {
/* JSON does not accept single quoted strings */
goto def_token;
}
/* fall through */
case '\"':
if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
goto fail;
break;
case '\r': /* accept DOS and MAC newline sequences */
if (p[1] == '\n') {
p++;
}
/* fall thru */
case '\n':
p++;
s->line_num++;
goto redo;
case '\f':
case '\v':
if (!s->ext_json) {
/* JSONWhitespace does not match <VT>, nor <FF> */
goto def_token;
}
/* fall through */
case ' ':
case '\t':
p++;
goto redo;
case '/':
if (!s->ext_json) {
/* JSON does not accept comments */
goto def_token;
}
if (p[1] == '*') {
/* comment */
p += 2;
for(;;) {
if (*p == '\0' && p >= s->buf_end) {
js_parse_error(s, "unexpected end of comment");
goto fail;
}
if (p[0] == '*' && p[1] == '/') {
p += 2;
break;
}
if (*p == '\n') {
s->line_num++;
p++;
} else if (*p == '\r') {
p++;
} else if (*p >= 0x80) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
if (c == -1) {
p++; /* skip invalid UTF-8 */
}
} else {
p++;
}
}
goto redo;
} else if (p[1] == '/') {
/* line comment */
p += 2;
for(;;) {
if (*p == '\0' && p >= s->buf_end)
break;
if (*p == '\r' || *p == '\n')
break;
if (*p >= 0x80) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
/* LS or PS are considered as line terminator */
if (c == CP_LS || c == CP_PS) {
break;
} else if (c == -1) {
p++; /* skip invalid UTF-8 */
}
} else {
p++;
}
}
goto redo;
} else {
goto def_token;
}
break;
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
case '_':
case '$':
/* identifier : only pure ascii characters are accepted */
p++;
atom = json_parse_ident(s, &p, c);
if (atom == JS_ATOM_NULL)
goto fail;
s->token.u.ident.atom = atom;
s->token.u.ident.has_escape = FALSE;
s->token.u.ident.is_reserved = FALSE;
s->token.val = TOK_IDENT;
break;
case '+':
if (!s->ext_json || !isdigit(p[1]))
goto def_token;
goto parse_number;
case '0':
if (isdigit(p[1]))
goto def_token;
goto parse_number;
case '-':
if (!isdigit(p[1]))
goto def_token;
goto parse_number;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
case '9':
/* number */
parse_number:
{
JSValue ret;
int flags, radix;
if (!s->ext_json) {
flags = 0;
radix = 10;
} else {
flags = ATOD_ACCEPT_BIN_OCT;
radix = 0;
}
ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
flags);
if (JS_IsException(ret))
goto fail;
s->token.val = TOK_NUMBER;
s->token.u.num.val = ret;
}
break;
default:
if (c >= 128) {
js_parse_error(s, "unexpected character");
goto fail;
}
def_token:
s->token.val = c;
p++;
break;
}
s->buf_ptr = p;
// dump_token(s, &s->token);
return 0;
fail:
s->token.val = TOK_ERROR;
return -1;
}
static int json_parse_expect(JSParseState *s, int tok)
{
if (s->token.val != tok) {
/* XXX: dump token correctly in all cases */
return js_parse_error(s, "expecting '%c'", tok);
}
return json_next_token(s);
}
static JSValue json_parse_value(JSParseState *s)
{
JSContext *ctx = s->ctx;
JSValue val = JS_NULL;
int ret;
switch(s->token.val) {
case '{':
{
JSValue prop_val;
JSAtom prop_name;
if (json_next_token(s))
goto fail;
val = JS_NewObject(ctx);
if (JS_IsException(val))
goto fail;
if (s->token.val != '}') {
for(;;) {
if (s->token.val == TOK_STRING) {
prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
if (prop_name == JS_ATOM_NULL)
goto fail;
} else if (s->ext_json && s->token.val == TOK_IDENT) {
prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);
} else {
js_parse_error(s, "expecting property name");
goto fail;
}
if (json_next_token(s))
goto fail1;
if (json_parse_expect(s, ':'))
goto fail1;
prop_val = json_parse_value(s);
if (JS_IsException(prop_val)) {
fail1:
JS_FreeAtom(ctx, prop_name);
goto fail;
}
ret = JS_DefinePropertyValue(ctx, val, prop_name,
prop_val, JS_PROP_C_W_E);
JS_FreeAtom(ctx, prop_name);
if (ret < 0)
goto fail;
if (s->token.val != ',')
break;
if (json_next_token(s))
goto fail;
if (s->ext_json && s->token.val == '}')
break;
}
}
if (json_parse_expect(s, '}'))
goto fail;
}
break;
case '[':
{
JSValue el;
uint32_t idx;
if (json_next_token(s))
goto fail;
val = JS_NewArray(ctx);
if (JS_IsException(val))
goto fail;
if (s->token.val != ']') {
idx = 0;
for(;;) {
el = json_parse_value(s);
if (JS_IsException(el))
goto fail;
ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
if (ret < 0)
goto fail;
if (s->token.val != ',')
break;
if (json_next_token(s))
goto fail;
idx++;
if (s->ext_json && s->token.val == ']')
break;
}
}
if (json_parse_expect(s, ']'))
goto fail;
}
break;
case TOK_STRING:
val = JS_DupValue(ctx, s->token.u.str.str);
if (json_next_token(s))
goto fail;
break;
case TOK_NUMBER:
val = s->token.u.num.val;
if (json_next_token(s))
goto fail;
break;
case TOK_IDENT:
if (s->token.u.ident.atom == JS_ATOM_false ||
s->token.u.ident.atom == JS_ATOM_true) {
val = JS_NewBool(ctx, (s->token.u.ident.atom == JS_ATOM_true));
} else if (s->token.u.ident.atom == JS_ATOM_null) {
val = JS_NULL;
} else {
goto def_token;
}
if (json_next_token(s))
goto fail;
break;
default:
def_token:
if (s->token.val == TOK_EOF) {
js_parse_error(s, "unexpected end of input");
} else {
js_parse_error(s, "unexpected token: '%.*s'",
(int)(s->buf_ptr - s->token.ptr), s->token.ptr);
}
goto fail;
}
return val;
fail:
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
const char *filename, int flags)
{
JSParseState s1, *s = &s1;
JSValue val = JS_UNDEFINED;
js_parse_init(ctx, s, buf, buf_len, filename);
s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
if (json_next_token(s))
goto fail;
val = json_parse_value(s);
if (JS_IsException(val))
goto fail;
if (s->token.val != TOK_EOF) {
if (js_parse_error(s, "unexpected data at the end"))
goto fail;
}
return val;
fail:
JS_FreeValue(ctx, val);
free_token(s, &s->token);
return JS_EXCEPTION;
}
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
const char *filename)
{
return JS_ParseJSON2(ctx, buf, buf_len, filename, 0);
}
static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
JSAtom name, JSValueConst reviver)
{
JSValue val, new_el, name_val, res;
JSValueConst args[2];
int ret, is_array;
uint32_t i, len = 0;
JSAtom prop;
JSPropertyEnum *atoms = NULL;
if (js_check_stack_overflow(ctx->rt, 0)) {
return JS_ThrowStackOverflow(ctx);
}
val = JS_GetProperty(ctx, holder, name);
if (JS_IsException(val))
return val;
if (JS_IsObject(val)) {
is_array = JS_IsArray(ctx, val);
if (is_array < 0)
goto fail;
if (is_array) {
if (js_get_length32(ctx, &len, val))
goto fail;
} else {
ret = JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, JS_VALUE_GET_OBJ(val), JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
if (ret < 0)
goto fail;
}
for(i = 0; i < len; i++) {
if (is_array) {
prop = JS_NewAtomUInt32(ctx, i);
if (prop == JS_ATOM_NULL)
goto fail;
} else {
prop = JS_DupAtom(ctx, atoms[i].atom);
}
new_el = internalize_json_property(ctx, val, prop, reviver);
if (JS_IsException(new_el)) {
JS_FreeAtom(ctx, prop);
goto fail;
}
if (JS_IsUndefined(new_el)) {
ret = JS_DeleteProperty(ctx, val, prop, 0);
} else {
ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E);
}
JS_FreeAtom(ctx, prop);
if (ret < 0)
goto fail;
}
}
js_free_prop_enum(ctx, atoms, len);
atoms = NULL;
name_val = JS_AtomToValue(ctx, name);
if (JS_IsException(name_val))
goto fail;
args[0] = name_val;
args[1] = val;
res = JS_Call(ctx, reviver, holder, 2, args);
JS_FreeValue(ctx, name_val);
JS_FreeValue(ctx, val);
return res;
fail:
js_free_prop_enum(ctx, atoms, len);
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValue obj, root;
JSValueConst reviver;
const char *str;
size_t len;
str = JS_ToCStringLen(ctx, &len, argv[0]);
if (!str)
return JS_EXCEPTION;
obj = JS_ParseJSON(ctx, str, len, "<input>");
JS_FreeCString(ctx, str);
if (JS_IsException(obj))
return obj;
if (argc > 1 && JS_IsFunction(ctx, argv[1])) {
reviver = argv[1];
root = JS_NewObject(ctx);
if (JS_IsException(root)) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj,
JS_PROP_C_W_E) < 0) {
JS_FreeValue(ctx, root);
return JS_EXCEPTION;
}
obj = internalize_json_property(ctx, root, JS_ATOM_empty_string,
reviver);
JS_FreeValue(ctx, root);
}
return obj;
}
JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
{
JSValue val;
JSString *p;
int i;
uint32_t c;
StringBuffer b_s, *b = &b_s;
char buf[16];
val = JS_ToStringCheckObject(ctx, val1);
if (JS_IsException(val))
return val;
p = JS_VALUE_GET_STRING(val);
if (string_buffer_init(ctx, b, p->len + 2))
goto fail;
if (string_buffer_putc8(b, '\"'))
goto fail;
for(i = 0; i < p->len; ) {
c = string_getc(p, &i);
switch(c) {
case '\t':
c = 't';
goto quote;
case '\r':
c = 'r';
goto quote;
case '\n':
c = 'n';
goto quote;
case '\b':
c = 'b';
goto quote;
case '\f':
c = 'f';
goto quote;
case '\"':
case '\\':
quote:
if (string_buffer_putc8(b, '\\'))
goto fail;
if (string_buffer_putc8(b, c))
goto fail;
break;
default:
if (c < 32 || (c >= 0xd800 && c < 0xe000)) {
snprintf(buf, sizeof(buf), "\\u%04x", c);
if (string_buffer_puts8(b, buf))
goto fail;
} else {
if (string_buffer_putc(b, c))
goto fail;
}
break;
}
}
if (string_buffer_putc8(b, '\"'))
goto fail;
JS_FreeValue(ctx, val);
return string_buffer_end(b);
fail:
JS_FreeValue(ctx, val);
string_buffer_free(b);
return JS_EXCEPTION;
}
static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) {
JSValue r = JS_ToQuotedString(ctx, val);
JS_FreeValue(ctx, val);
return r;
}
static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
JSValueConst holder, JSValue val, JSValueConst key)
{
JSValue v;
JSValueConst args[2];
if (JS_IsObject(val)
#ifdef CONFIG_BIGNUM
|| JS_IsBigInt(ctx, val) /* XXX: probably useless */
#endif
) {
JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
if (JS_IsException(f))
goto exception;
if (JS_IsFunction(ctx, f)) {
v = JS_CallFree(ctx, f, val, 1, &key);
JS_FreeValue(ctx, val);
val = v;
if (JS_IsException(val))
goto exception;
} else {
JS_FreeValue(ctx, f);
}
}
if (!JS_IsUndefined(jsc->replacer_func)) {
args[0] = key;
args[1] = val;
v = JS_Call(ctx, jsc->replacer_func, holder, 2, args);
JS_FreeValue(ctx, val);
val = v;
if (JS_IsException(val))
goto exception;
}
switch (JS_VALUE_GET_NORM_TAG(val)) {
case JS_TAG_OBJECT:
if (JS_IsFunction(ctx, val))
break;
case JS_TAG_STRING:
case JS_TAG_INT:
case JS_TAG_FLOAT64:
#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
#endif
case JS_TAG_BOOL:
case JS_TAG_NULL:
#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
#endif
case JS_TAG_EXCEPTION:
return val;
default:
break;
}
JS_FreeValue(ctx, val);
return JS_UNDEFINED;
exception:
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
JSValueConst holder, JSValue val,
JSValueConst indent)
{
JSValue indent1, sep, sep1, tab, v, prop;
JSObject *p;
int64_t i, len;
int cl, ret;
BOOL has_content;
indent1 = JS_UNDEFINED;
sep = JS_UNDEFINED;
sep1 = JS_UNDEFINED;
tab = JS_UNDEFINED;
prop = JS_UNDEFINED;
switch (JS_VALUE_GET_NORM_TAG(val)) {
case JS_TAG_OBJECT:
p = JS_VALUE_GET_OBJ(val);
cl = p->class_id;
if (cl == JS_CLASS_STRING) {
val = JS_ToStringFree(ctx, val);
if (JS_IsException(val))
goto exception;
val = JS_ToQuotedStringFree(ctx, val);
if (JS_IsException(val))
goto exception;
return string_buffer_concat_value_free(jsc->b, val);
} else if (cl == JS_CLASS_NUMBER) {
val = JS_ToNumberFree(ctx, val);
if (JS_IsException(val))
goto exception;
return string_buffer_concat_value_free(jsc->b, val);
} else if (cl == JS_CLASS_BOOLEAN) {
ret = string_buffer_concat_value(jsc->b, p->u.object_data);
JS_FreeValue(ctx, val);
return ret;
}
#ifdef CONFIG_BIGNUM
else if (cl == JS_CLASS_BIG_FLOAT) {
return string_buffer_concat_value_free(jsc->b, val);
} else if (cl == JS_CLASS_BIG_INT) {
JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
goto exception;
}
#endif
v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
if (JS_IsException(v))
goto exception;
if (JS_ToBoolFree(ctx, v)) {
JS_ThrowTypeError(ctx, "circular reference");
goto exception;
}
indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), JS_DupValue(ctx, jsc->gap));
if (JS_IsException(indent1))
goto exception;
if (!JS_IsEmptyString(jsc->gap)) {
sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), "");
if (JS_IsException(sep))
goto exception;
sep1 = JS_NewString(ctx, " ");
if (JS_IsException(sep1))
goto exception;
} else {
sep = JS_DupValue(ctx, jsc->empty);
sep1 = JS_DupValue(ctx, jsc->empty);
}
v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0);
if (check_exception_free(ctx, v))
goto exception;
ret = JS_IsArray(ctx, val);
if (ret < 0)
goto exception;
if (ret) {
if (js_get_length64(ctx, &len, val))
goto exception;
string_buffer_putc8(jsc->b, '[');
for(i = 0; i < len; i++) {
if (i > 0)
string_buffer_putc8(jsc->b, ',');
string_buffer_concat_value(jsc->b, sep);
v = JS_GetPropertyInt64(ctx, val, i);
if (JS_IsException(v))
goto exception;
/* XXX: could do this string conversion only when needed */
prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i));
if (JS_IsException(prop))
goto exception;
v = js_json_check(ctx, jsc, val, v, prop);
JS_FreeValue(ctx, prop);
prop = JS_UNDEFINED;
if (JS_IsException(v))
goto exception;
if (JS_IsUndefined(v))
v = JS_NULL;
if (js_json_to_str(ctx, jsc, val, v, indent1))
goto exception;
}
if (len > 0 && !JS_IsEmptyString(jsc->gap)) {
string_buffer_putc8(jsc->b, '\n');
string_buffer_concat_value(jsc->b, indent);
}
string_buffer_putc8(jsc->b, ']');
} else {
if (!JS_IsUndefined(jsc->property_list))
tab = JS_DupValue(ctx, jsc->property_list);
else
tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY);
if (JS_IsException(tab))
goto exception;
if (js_get_length64(ctx, &len, tab))
goto exception;
string_buffer_putc8(jsc->b, '{');
has_content = FALSE;
for(i = 0; i < len; i++) {
JS_FreeValue(ctx, prop);
prop = JS_GetPropertyInt64(ctx, tab, i);
if (JS_IsException(prop))
goto exception;
v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop));
if (JS_IsException(v))
goto exception;
v = js_json_check(ctx, jsc, val, v, prop);
if (JS_IsException(v))
goto exception;
if (!JS_IsUndefined(v)) {
if (has_content)
string_buffer_putc8(jsc->b, ',');
prop = JS_ToQuotedStringFree(ctx, prop);
if (JS_IsException(prop)) {
JS_FreeValue(ctx, v);
goto exception;
}
string_buffer_concat_value(jsc->b, sep);
string_buffer_concat_value(jsc->b, prop);
string_buffer_putc8(jsc->b, ':');
string_buffer_concat_value(jsc->b, sep1);
if (js_json_to_str(ctx, jsc, val, v, indent1))
goto exception;
has_content = TRUE;
}
}
if (has_content && JS_VALUE_GET_STRING(jsc->gap)->len != 0) {
string_buffer_putc8(jsc->b, '\n');
string_buffer_concat_value(jsc->b, indent);
}
string_buffer_putc8(jsc->b, '}');
}
if (check_exception_free(ctx, js_array_pop(ctx, jsc->stack, 0, NULL, 0)))
goto exception;
JS_FreeValue(ctx, val);
JS_FreeValue(ctx, tab);
JS_FreeValue(ctx, sep);
JS_FreeValue(ctx, sep1);
JS_FreeValue(ctx, indent1);
JS_FreeValue(ctx, prop);
return 0;
case JS_TAG_STRING:
val = JS_ToQuotedStringFree(ctx, val);
if (JS_IsException(val))
goto exception;
goto concat_value;
case JS_TAG_FLOAT64:
if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
val = JS_NULL;
}
goto concat_value;
case JS_TAG_INT:
#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
#endif
case JS_TAG_BOOL:
case JS_TAG_NULL:
concat_value:
return string_buffer_concat_value_free(jsc->b, val);
#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
goto exception;
#endif
default:
JS_FreeValue(ctx, val);
return 0;
}
exception:
JS_FreeValue(ctx, val);
JS_FreeValue(ctx, tab);
JS_FreeValue(ctx, sep);
JS_FreeValue(ctx, sep1);
JS_FreeValue(ctx, indent1);
JS_FreeValue(ctx, prop);
return -1;
}
JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
JSValueConst replacer, JSValueConst space0)
{
StringBuffer b_s;
JSONStringifyContext jsc_s, *jsc = &jsc_s;
JSValue val, v, space, ret, wrapper;
int res;
int64_t i, j, n;
jsc->replacer_func = JS_UNDEFINED;
jsc->stack = JS_UNDEFINED;
jsc->property_list = JS_UNDEFINED;
jsc->gap = JS_UNDEFINED;
jsc->b = &b_s;
jsc->empty = JS_AtomToString(ctx, JS_ATOM_empty_string);
ret = JS_UNDEFINED;
wrapper = JS_UNDEFINED;
string_buffer_init(ctx, jsc->b, 0);
jsc->stack = JS_NewArray(ctx);
if (JS_IsException(jsc->stack))
goto exception;
if (JS_IsFunction(ctx, replacer)) {
jsc->replacer_func = replacer;
} else {
res = JS_IsArray(ctx, replacer);
if (res < 0)
goto exception;
if (res) {
/* XXX: enumeration is not fully correct */
jsc->property_list = JS_NewArray(ctx);
if (JS_IsException(jsc->property_list))
goto exception;
if (js_get_length64(ctx, &n, replacer))
goto exception;
for (i = j = 0; i < n; i++) {
JSValue present;
v = JS_GetPropertyInt64(ctx, replacer, i);
if (JS_IsException(v))
goto exception;
if (JS_IsObject(v)) {
JSObject *p = JS_VALUE_GET_OBJ(v);
if (p->class_id == JS_CLASS_STRING ||
p->class_id == JS_CLASS_NUMBER) {
v = JS_ToStringFree(ctx, v);
if (JS_IsException(v))
goto exception;
} else {
JS_FreeValue(ctx, v);
continue;
}
} else if (JS_IsNumber(v)) {
v = JS_ToStringFree(ctx, v);
if (JS_IsException(v))
goto exception;
} else if (!JS_IsString(v)) {
JS_FreeValue(ctx, v);
continue;
}
present = js_array_includes(ctx, jsc->property_list,
1, (JSValueConst *)&v);
if (JS_IsException(present)) {
JS_FreeValue(ctx, v);
goto exception;
}
if (!JS_ToBoolFree(ctx, present)) {
JS_SetPropertyInt64(ctx, jsc->property_list, j++, v);
} else {
JS_FreeValue(ctx, v);
}
}
}
}
space = JS_DupValue(ctx, space0);
if (JS_IsObject(space)) {
JSObject *p = JS_VALUE_GET_OBJ(space);
if (p->class_id == JS_CLASS_NUMBER) {
space = JS_ToNumberFree(ctx, space);
} else if (p->class_id == JS_CLASS_STRING) {
space = JS_ToStringFree(ctx, space);
}
if (JS_IsException(space)) {
JS_FreeValue(ctx, space);
goto exception;
}
}
if (JS_IsNumber(space)) {
int n;
if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))
goto exception;
jsc->gap = JS_NewStringLen(ctx, " ", n);
} else if (JS_IsString(space)) {
JSString *p = JS_VALUE_GET_STRING(space);
jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10));
} else {
jsc->gap = JS_DupValue(ctx, jsc->empty);
}
JS_FreeValue(ctx, space);
if (JS_IsException(jsc->gap))
goto exception;
wrapper = JS_NewObject(ctx);
if (JS_IsException(wrapper))
goto exception;
if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string,
JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0)
goto exception;
val = JS_DupValue(ctx, obj);
val = js_json_check(ctx, jsc, wrapper, val, jsc->empty);
if (JS_IsException(val))
goto exception;
if (JS_IsUndefined(val)) {
ret = JS_UNDEFINED;
goto done1;
}
if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty))
goto exception;
ret = string_buffer_end(jsc->b);
goto done;
exception:
ret = JS_EXCEPTION;
done1:
string_buffer_free(jsc->b);
done:
JS_FreeValue(ctx, wrapper);
JS_FreeValue(ctx, jsc->empty);
JS_FreeValue(ctx, jsc->gap);
JS_FreeValue(ctx, jsc->property_list);
JS_FreeValue(ctx, jsc->stack);
return ret;
}
static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
// stringify(val, replacer, space)
return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);
}
static const JSCFunctionListEntry js_json_funcs[] = {
JS_CFUNC_DEF("parse", 2, js_json_parse ),
JS_CFUNC_DEF("stringify", 3, js_json_stringify ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "JSON", JS_PROP_CONFIGURABLE ),
};
static const JSCFunctionListEntry js_json_obj[] = {
JS_OBJECT_DEF("JSON", js_json_funcs, countof(js_json_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
};
void JS_AddIntrinsicJSON(JSContext *ctx)
{
/* add JSON as autoinit object */
JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_json_obj, countof(js_json_obj));
}

View file

@ -1,64 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/intrin/likely.h"
#include "third_party/quickjs/leb128.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
int get_leb128(uint32_t *pval, const uint8_t *buf, const uint8_t *buf_end)
{
const uint8_t *ptr = buf;
uint32_t v, a, i;
v = 0;
for(i = 0; i < 5; i++) {
if (UNLIKELY(ptr >= buf_end))
break;
a = *ptr++;
v |= (a & 0x7f) << (i * 7);
if (!(a & 0x80)) {
*pval = v;
return ptr - buf;
}
}
*pval = 0;
return -1;
}
int get_sleb128(int32_t *pval, const uint8_t *buf, const uint8_t *buf_end)
{
int ret;
uint32_t val;
ret = get_leb128(&val, buf, buf_end);
if (ret < 0) {
*pval = 0;
return -1;
}
*pval = (val >> 1) ^ -(val & 1);
return ret;
}

View file

@ -1,9 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LEB128_H_
#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LEB128_H_
COSMOPOLITAN_C_START_
int get_leb128(uint32_t *, const uint8_t *, const uint8_t *);
int get_sleb128(int32_t *, const uint8_t *, const uint8_t *);
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LEB128_H_ */

File diff suppressed because it is too large Load diff

View file

@ -1,514 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBBF_H_
#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBBF_H_
#include "libc/limits.h"
#include "libc/literal.h"
COSMOPOLITAN_C_START_
#if INTPTR_MAX >= INT64_MAX
#define LIMB_LOG2_BITS 6
#else
#define LIMB_LOG2_BITS 5
#endif
#define LIMB_BITS (1 << LIMB_LOG2_BITS)
#if LIMB_BITS == 64
typedef __int128 int128_t;
typedef unsigned __int128 uint128_t;
typedef int64_t slimb_t;
typedef uint64_t limb_t;
typedef uint128_t dlimb_t;
#define BF_RAW_EXP_MIN INT64_MIN
#define BF_RAW_EXP_MAX INT64_MAX
#define LIMB_DIGITS 19
#define BF_DEC_BASE UINT64_C(10000000000000000000)
#else
typedef int32_t slimb_t;
typedef uint32_t limb_t;
typedef uint64_t dlimb_t;
#define BF_RAW_EXP_MIN INT32_MIN
#define BF_RAW_EXP_MAX INT32_MAX
#define LIMB_DIGITS 9
#define BF_DEC_BASE 1000000000U
#endif
/* in bits */
/* minimum number of bits for the exponent */
#define BF_EXP_BITS_MIN 3
/* maximum number of bits for the exponent */
#define BF_EXP_BITS_MAX (LIMB_BITS - 3)
/* extended range for exponent, used internally */
#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)
/* minimum possible precision */
#define BF_PREC_MIN 2
/* minimum possible precision */
#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)
/* some operations support infinite precision */
#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */
#if LIMB_BITS == 64
#define BF_CHKSUM_MOD (UINT64_C(975620677) * UINT64_C(9795002197))
#else
#define BF_CHKSUM_MOD 975620677U
#endif
#define BF_EXP_ZERO BF_RAW_EXP_MIN
#define BF_EXP_INF (BF_RAW_EXP_MAX - 1)
#define BF_EXP_NAN BF_RAW_EXP_MAX
/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,
+/-infinity is represented with expn = BF_EXP_INF and len = 0,
NaN is represented with expn = BF_EXP_NAN and len = 0 (sign is ignored)
*/
typedef struct {
struct bf_context_t *ctx;
int sign;
slimb_t expn;
limb_t len;
limb_t *tab;
} bf_t;
typedef struct {
/* must be kept identical to bf_t */
struct bf_context_t *ctx;
int sign;
slimb_t expn;
limb_t len;
limb_t *tab;
} bfdec_t;
typedef enum {
BF_RNDN, /* round to nearest, ties to even */
BF_RNDZ, /* round to zero */
BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */
BF_RNDU, /* round to +inf */
BF_RNDNA, /* round to nearest, ties away from zero */
BF_RNDA, /* round away from zero */
BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,
inexact flag is always set) */
} bf_rnd_t;
/* allow subnormal numbers. Only available if the number of exponent
bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */
#define BF_FLAG_SUBNORMAL (1 << 3)
/* 'prec' is the precision after the radix point instead of the whole
mantissa. Can only be used with bf_round() and
bfdec_[add|sub|mul|div|sqrt|round](). */
#define BF_FLAG_RADPNT_PREC (1 << 4)
#define BF_RND_MASK 0x7
#define BF_EXP_BITS_SHIFT 5
#define BF_EXP_BITS_MASK 0x3f
/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */
#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)
/* contains the rounding mode and number of exponents bits */
typedef uint32_t bf_flags_t;
typedef void *bf_realloc_func_t(void *opaque, void *ptr, size_t size);
typedef struct {
bf_t val;
limb_t prec;
} BFConstCache;
typedef struct bf_context_t {
void *realloc_opaque;
bf_realloc_func_t *realloc_func;
BFConstCache log2_cache;
BFConstCache pi_cache;
struct BFNTTState *ntt_state;
} bf_context_t;
static inline int bf_get_exp_bits(bf_flags_t flags)
{
int e;
e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;
if (e == BF_EXP_BITS_MASK)
return BF_EXP_BITS_MAX + 1;
else
return BF_EXP_BITS_MAX - e;
}
static inline bf_flags_t bf_set_exp_bits(int n)
{
return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;
}
/* returned status */
#define BF_ST_INVALID_OP (1 << 0)
#define BF_ST_DIVIDE_ZERO (1 << 1)
#define BF_ST_OVERFLOW (1 << 2)
#define BF_ST_UNDERFLOW (1 << 3)
#define BF_ST_INEXACT (1 << 4)
/* indicate that a memory allocation error occured. NaN is returned */
#define BF_ST_MEM_ERROR (1 << 5)
#define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */
static inline slimb_t bf_max(slimb_t a, slimb_t b)
{
if (a > b)
return a;
else
return b;
}
static inline slimb_t bf_min(slimb_t a, slimb_t b)
{
if (a < b)
return a;
else
return b;
}
void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,
void *realloc_opaque);
void bf_context_end(bf_context_t *s);
/* free memory allocated for the bf cache data */
void bf_clear_cache(bf_context_t *s);
static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size)
{
return s->realloc_func(s->realloc_opaque, ptr, size);
}
/* 'size' must be != 0 */
static inline void *bf_malloc(bf_context_t *s, size_t size)
{
return bf_realloc(s, NULL, size);
}
static inline void bf_free(bf_context_t *s, void *ptr)
{
/* must test ptr otherwise equivalent to malloc(0) */
if (ptr)
bf_realloc(s, ptr, 0);
}
void bf_init(bf_context_t *s, bf_t *r);
static inline void bf_delete(bf_t *r)
{
bf_context_t *s = r->ctx;
/* we accept to delete a zeroed bf_t structure */
if (s && r->tab) {
bf_realloc(s, r->tab, 0);
}
}
static inline void bf_neg(bf_t *r)
{
r->sign ^= 1;
}
static inline int bf_is_finite(const bf_t *a)
{
return (a->expn < BF_EXP_INF);
}
static inline int bf_is_nan(const bf_t *a)
{
return (a->expn == BF_EXP_NAN);
}
static inline int bf_is_zero(const bf_t *a)
{
return (a->expn == BF_EXP_ZERO);
}
static inline void bf_memcpy(bf_t *r, const bf_t *a)
{
*r = *a;
}
int bf_set_ui(bf_t *r, uint64_t a);
int bf_set_si(bf_t *r, int64_t a);
void bf_set_nan(bf_t *r);
void bf_set_zero(bf_t *r, int is_neg);
void bf_set_inf(bf_t *r, int is_neg);
int bf_set(bf_t *r, const bf_t *a);
void bf_move(bf_t *r, bf_t *a);
int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode);
int bf_set_float64(bf_t *a, double d);
int bf_cmpu(const bf_t *a, const bf_t *b);
int bf_cmp_full(const bf_t *a, const bf_t *b);
int bf_cmp(const bf_t *a, const bf_t *b);
static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)
{
return bf_cmp(a, b) == 0;
}
static inline int bf_cmp_le(const bf_t *a, const bf_t *b)
{
return bf_cmp(a, b) <= 0;
}
static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)
{
return bf_cmp(a, b) < 0;
}
int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);
int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags);
int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,
bf_flags_t flags);
int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags);
int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
#define BF_DIVREM_EUCLIDIAN BF_RNDF
int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
limb_t prec, bf_flags_t flags, int rnd_mode);
int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
bf_flags_t flags, int rnd_mode);
int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
bf_flags_t flags, int rnd_mode);
/* round to integer with infinite precision */
int bf_rint(bf_t *r, int rnd_mode);
int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);
int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a);
int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
slimb_t bf_get_exp_min(const bf_t *a);
int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b);
int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b);
int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b);
/* additional flags for bf_atof */
/* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */
#define BF_ATOF_NO_HEX (1 << 16)
/* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */
#define BF_ATOF_BIN_OCT (1 << 17)
/* Do not parse NaN or Inf */
#define BF_ATOF_NO_NAN_INF (1 << 18)
/* return the exponent separately */
#define BF_ATOF_EXPONENT (1 << 19)
int bf_atof(bf_t *a, const char *str, const char **pnext, int radix,
limb_t prec, bf_flags_t flags);
/* this version accepts prec = BF_PREC_INF and returns the radix
exponent */
int bf_atof2(bf_t *r, slimb_t *pexponent,
const char *str, const char **pnext, int radix,
limb_t prec, bf_flags_t flags);
int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
slimb_t expn, limb_t prec, bf_flags_t flags);
/* Conversion of floating point number to string. Return a null
terminated string or NULL if memory error. *plen contains its
length if plen != NULL. The exponent letter is "e" for base 10,
"p" for bases 2, 8, 16 with a binary exponent and "@" for the other
bases. */
#define BF_FTOA_FORMAT_MASK (3 << 16)
/* fixed format: prec significant digits rounded with (flags &
BF_RND_MASK). Exponential notation is used if too many zeros are
needed.*/
#define BF_FTOA_FORMAT_FIXED (0 << 16)
/* fractional format: prec digits after the decimal point rounded with
(flags & BF_RND_MASK) */
#define BF_FTOA_FORMAT_FRAC (1 << 16)
/* free format:
For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum
number of digits to represent 'a'. The precision and the rounding
mode are ignored.
For the non binary radices with bf_ftoa(): use as many digits as
necessary so that bf_atof() return the same number when using
precision 'prec', rounding to nearest and the subnormal
configuration of 'flags'. The result is meaningful only if 'a' is
already rounded to 'prec' bits. If the subnormal flag is set, the
exponent in 'flags' must also be set to the desired exponent range.
*/
#define BF_FTOA_FORMAT_FREE (2 << 16)
/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits
(takes more computation time). Identical to BF_FTOA_FORMAT_FREE for
binary radices with bf_ftoa() and for bfdec_ftoa(). */
#define BF_FTOA_FORMAT_FREE_MIN (3 << 16)
/* force exponential notation for fixed or free format */
#define BF_FTOA_FORCE_EXP (1 << 20)
/* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for
base 2 if non zero value */
#define BF_FTOA_ADD_PREFIX (1 << 21)
/* return "Infinity" instead of "Inf" and add a "+" for positive
exponents */
#define BF_FTOA_JS_QUIRKS (1 << 22)
char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,
bf_flags_t flags);
/* modulo 2^n instead of saturation. NaN and infinity return 0 */
#define BF_GET_INT_MOD (1 << 0)
int bf_get_int32(int *pres, const bf_t *a, int flags);
int bf_get_int64(int64_t *pres, const bf_t *a, int flags);
int bf_get_uint64(uint64_t *pres, const bf_t *a);
/* the following functions are exported for testing only. */
void mp_print_str(const char *str, const limb_t *tab, limb_t n);
void bf_print_str(const char *str, const bf_t *a);
int bf_resize(bf_t *r, limb_t len);
int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len);
int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags);
int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k);
slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,
int is_ceil1);
int mp_mul(bf_context_t *s, limb_t *result,
const limb_t *op1, limb_t op1_size,
const limb_t *op2, limb_t op2_size);
limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2,
limb_t n, limb_t carry);
limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n);
int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n);
int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n);
limb_t bf_isqrt(limb_t a);
/* transcendental functions */
int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags);
int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);
int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */
int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);
int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,
limb_t prec, bf_flags_t flags);
int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
/* decimal floating point */
static inline void bfdec_init(bf_context_t *s, bfdec_t *r)
{
bf_init(s, (bf_t *)r);
}
static inline void bfdec_delete(bfdec_t *r)
{
bf_delete((bf_t *)r);
}
static inline void bfdec_neg(bfdec_t *r)
{
r->sign ^= 1;
}
static inline int bfdec_is_finite(const bfdec_t *a)
{
return (a->expn < BF_EXP_INF);
}
static inline int bfdec_is_nan(const bfdec_t *a)
{
return (a->expn == BF_EXP_NAN);
}
static inline int bfdec_is_zero(const bfdec_t *a)
{
return (a->expn == BF_EXP_ZERO);
}
static inline void bfdec_memcpy(bfdec_t *r, const bfdec_t *a)
{
bf_memcpy((bf_t *)r, (const bf_t *)a);
}
int bfdec_set_ui(bfdec_t *r, uint64_t a);
int bfdec_set_si(bfdec_t *r, int64_t a);
static inline void bfdec_set_nan(bfdec_t *r)
{
bf_set_nan((bf_t *)r);
}
static inline void bfdec_set_zero(bfdec_t *r, int is_neg)
{
bf_set_zero((bf_t *)r, is_neg);
}
static inline void bfdec_set_inf(bfdec_t *r, int is_neg)
{
bf_set_inf((bf_t *)r, is_neg);
}
static inline int bfdec_set(bfdec_t *r, const bfdec_t *a)
{
return bf_set((bf_t *)r, (bf_t *)a);
}
static inline void bfdec_move(bfdec_t *r, bfdec_t *a)
{
bf_move((bf_t *)r, (bf_t *)a);
}
static inline int bfdec_cmpu(const bfdec_t *a, const bfdec_t *b)
{
return bf_cmpu((const bf_t *)a, (const bf_t *)b);
}
static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b)
{
return bf_cmp_full((const bf_t *)a, (const bf_t *)b);
}
static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)
{
return bf_cmp((const bf_t *)a, (const bf_t *)b);
}
static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)
{
return bfdec_cmp(a, b) == 0;
}
static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)
{
return bfdec_cmp(a, b) <= 0;
}
static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)
{
return bfdec_cmp(a, b) < 0;
}
int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
bf_flags_t flags);
int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
bf_flags_t flags);
int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
bf_flags_t flags);
int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
bf_flags_t flags);
int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
bf_flags_t flags);
int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
bf_flags_t flags);
int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
limb_t prec, bf_flags_t flags, int rnd_mode);
int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
bf_flags_t flags, int rnd_mode);
int bfdec_rint(bfdec_t *r, int rnd_mode);
int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);
int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);
int bfdec_get_int32(int *pres, const bfdec_t *a);
int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b);
char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags);
int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,
limb_t prec, bf_flags_t flags);
/* the following functions are exported for testing only. */
extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];
void bfdec_print_str(const char *str, const bfdec_t *a);
static inline int bfdec_resize(bfdec_t *r, limb_t len)
{
return bf_resize((bf_t *)r, len);
}
int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags);
/* clang-format on */
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBBF_H_ */

View file

@ -1,59 +0,0 @@
/*
* Regular Expression Engine
*
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifdef DEF
DEF(invalid, 1) /* never used */
DEF(char, 3)
DEF(char32, 5)
DEF(dot, 1)
DEF(any, 1) /* same as dot but match any character including line terminator */
DEF(line_start, 1)
DEF(line_end, 1)
DEF(goto, 5)
DEF(split_goto_first, 5)
DEF(split_next_first, 5)
DEF(match, 1)
DEF(save_start, 2) /* save start position */
DEF(save_end, 2) /* save end position, must come after saved_start */
DEF(save_reset, 3) /* reset save positions */
DEF(loop, 5) /* decrement the top the stack and goto if != 0 */
DEF(push_i32, 5) /* push integer on the stack */
DEF(drop, 1)
DEF(word_boundary, 1)
DEF(not_word_boundary, 1)
DEF(back_reference, 2)
DEF(backward_back_reference, 2) /* must come after back_reference */
DEF(range, 3) /* variable length */
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(prev, 1) /* go to the previous char */
DEF(simple_greedy_quant, 17)
#endif /* DEF */

File diff suppressed because it is too large Load diff

View file

@ -1,69 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBREGEXP_H_
#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBREGEXP_H_
#include "third_party/quickjs/libunicode.h"
COSMOPOLITAN_C_START_
#define LRE_BOOL int /* for documentation purposes */
#define LRE_FLAG_GLOBAL (1 << 0)
#define LRE_FLAG_IGNORECASE (1 << 1)
#define LRE_FLAG_MULTILINE (1 << 2)
#define LRE_FLAG_DOTALL (1 << 3)
#define LRE_FLAG_UTF16 (1 << 4)
#define LRE_FLAG_STICKY (1 << 5)
#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
const char *buf, size_t buf_len, int re_flags,
void *opaque);
int lre_get_capture_count(const uint8_t *bc_buf);
int lre_get_flags(const uint8_t *bc_buf);
const char *lre_get_groupnames(const uint8_t *bc_buf);
int lre_exec(uint8_t **capture,
const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,
int cbuf_type, void *opaque);
int lre_parse_escape(const uint8_t **pp, int allow_utf16);
LRE_BOOL lre_is_space(int c);
/* must be provided by the user */
LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size);
void *lre_realloc(void *opaque, void *ptr, size_t size);
/* JS identifier test */
extern uint32_t const lre_id_start_table_ascii[4];
extern uint32_t const lre_id_continue_table_ascii[4];
static inline int lre_js_is_ident_first(int c)
{
if ((uint32_t)c < 128) {
return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1;
} else {
#ifdef CONFIG_ALL_UNICODE
return lre_is_id_start(c);
#else
return !lre_is_space(c);
#endif
}
}
static inline int lre_js_is_ident_next(int c)
{
if ((uint32_t)c < 128) {
return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1;
} else {
/* ZWNJ and ZWJ are accepted in identifiers */
#ifdef CONFIG_ALL_UNICODE
return lre_is_id_continue(c) || c == 0x200C || c == 0x200D;
#else
return !lre_is_space(c) || c == 0x200C || c == 0x200D;
#endif
}
}
#undef LRE_BOOL
/* clang-format on */
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBREGEXP_H_ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,103 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBUNICODE_H_
#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBUNICODE_H_
#include "third_party/quickjs/libunicode.h"
COSMOPOLITAN_C_START_
#define LRE_BOOL int /* for documentation purposes */
/* define it to include all the unicode tables (40KB larger) */
#define CONFIG_ALL_UNICODE
#define LRE_CC_RES_LEN_MAX 3
typedef enum {
UNICODE_NFC,
UNICODE_NFD,
UNICODE_NFKC,
UNICODE_NFKD,
} UnicodeNormalizationEnum;
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
LRE_BOOL lre_is_cased(uint32_t c);
LRE_BOOL lre_is_case_ignorable(uint32_t c);
/* char ranges */
typedef struct {
int len; /* in points, always even */
int size;
uint32_t *points; /* points sorted by increasing value */
void *mem_opaque;
void *(*realloc_func)(void *opaque, void *ptr, size_t size);
} CharRange;
typedef enum {
CR_OP_UNION,
CR_OP_INTER,
CR_OP_XOR,
} CharRangeOpEnum;
void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
void cr_free(CharRange *cr);
int cr_realloc(CharRange *cr, int size);
int cr_copy(CharRange *cr, const CharRange *cr1);
static inline int cr_add_point(CharRange *cr, uint32_t v)
{
if (cr->len >= cr->size) {
if (cr_realloc(cr, cr->len + 1))
return -1;
}
cr->points[cr->len++] = v;
return 0;
}
static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2)
{
if ((cr->len + 2) > cr->size) {
if (cr_realloc(cr, cr->len + 2))
return -1;
}
cr->points[cr->len++] = c1;
cr->points[cr->len++] = c2;
return 0;
}
int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len);
static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2)
{
uint32_t b_pt[2];
b_pt[0] = c1;
b_pt[1] = c2 + 1;
return cr_union1(cr, b_pt, 2);
}
int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
const uint32_t *b_pt, int b_len, int op);
int cr_invert(CharRange *cr);
#ifdef CONFIG_ALL_UNICODE
LRE_BOOL lre_is_id_start(uint32_t c);
LRE_BOOL lre_is_id_continue(uint32_t c);
int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
UnicodeNormalizationEnum n_type,
void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
/* Unicode character range functions */
int unicode_script(CharRange *cr,
const char *script_name, LRE_BOOL is_ext);
int unicode_general_category(CharRange *cr, const char *gc_name);
int unicode_prop(CharRange *cr, const char *prop_name);
#endif /* CONFIG_ALL_UNICODE */
#undef LRE_BOOL
/* clang-format on */
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBUNICODE_H_ */

View file

@ -1,76 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIST_H_
#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIST_H_
COSMOPOLITAN_C_START_
struct list_head {
struct list_head *prev;
struct list_head *next;
};
#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)))
static inline void init_list_head(struct list_head *head)
{
head->prev = head;
head->next = head;
}
/* insert 'el' between 'prev' and 'next' */
static inline void __list_add(struct list_head *el,
struct list_head *prev, struct list_head *next)
{
prev->next = el;
el->prev = prev;
el->next = next;
next->prev = el;
}
/* add 'el' at the head of the list 'head' (= after element head) */
static inline void list_add(struct list_head *el, struct list_head *head)
{
__list_add(el, head, head->next);
}
/* add 'el' at the end of the list 'head' (= before element head) */
static inline void list_add_tail(struct list_head *el, struct list_head *head)
{
__list_add(el, head->prev, head);
}
static inline void list_del(struct list_head *el)
{
struct list_head *prev, *next;
prev = el->prev;
next = el->next;
prev->next = next;
next->prev = prev;
el->prev = NULL; /* fail safe */
el->next = NULL; /* fail safe */
}
static inline int list_empty(struct list_head *el)
{
return el->next == el;
}
#define list_for_each(el, head) \
for(el = (head)->next; el != (head); el = el->next)
#define list_for_each_safe(el, el1, head) \
for(el = (head)->next, el1 = el->next; el != (head); \
el = el1, el1 = el->next)
#define list_for_each_prev(el, head) \
for(el = (head)->prev; el != (head); el = el->prev)
#define list_for_each_prev_safe(el, el1, head) \
for(el = (head)->prev, el1 = el->prev; el != (head); \
el = el1, el1 = el->prev)
/* clang-format on */
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIST_H_ */

View file

@ -1,748 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
int argc, JSValueConst *argv, int magic)
{
JSMapState *s;
JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED;
JSValueConst arr;
BOOL is_set, is_weak;
is_set = magic & MAGIC_SET;
is_weak = ((magic & MAGIC_WEAK) != 0);
obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic);
if (JS_IsException(obj))
return JS_EXCEPTION;
s = js_mallocz(ctx, sizeof(*s));
if (!s)
goto fail;
init_list_head(&s->records);
s->is_weak = is_weak;
JS_SetOpaque(obj, s);
s->hash_size = 1;
s->hash_table = js_malloc(ctx, sizeof(s->hash_table[0]) * s->hash_size);
if (!s->hash_table)
goto fail;
init_list_head(&s->hash_table[0]);
s->record_count_threshold = 4;
arr = JS_UNDEFINED;
if (argc > 0)
arr = argv[0];
if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) {
JSValue item, ret;
BOOL done;
adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set);
if (JS_IsException(adder))
goto fail;
if (!JS_IsFunction(ctx, adder)) {
JS_ThrowTypeError(ctx, "set/add is not a function");
goto fail;
}
iter = JS_GetIterator(ctx, arr, FALSE);
if (JS_IsException(iter))
goto fail;
next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
if (JS_IsException(next_method))
goto fail;
for(;;) {
item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
if (JS_IsException(item))
goto fail;
if (done) {
JS_FreeValue(ctx, item);
break;
}
if (is_set) {
ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);
if (JS_IsException(ret)) {
JS_FreeValue(ctx, item);
goto fail;
}
} else {
JSValue key, value;
JSValueConst args[2];
key = JS_UNDEFINED;
value = JS_UNDEFINED;
if (!JS_IsObject(item)) {
JS_ThrowTypeErrorNotAnObject(ctx);
goto fail1;
}
key = JS_GetPropertyUint32(ctx, item, 0);
if (JS_IsException(key))
goto fail1;
value = JS_GetPropertyUint32(ctx, item, 1);
if (JS_IsException(value))
goto fail1;
args[0] = key;
args[1] = value;
ret = JS_Call(ctx, adder, obj, 2, args);
if (JS_IsException(ret)) {
fail1:
JS_FreeValue(ctx, item);
JS_FreeValue(ctx, key);
JS_FreeValue(ctx, value);
goto fail;
}
JS_FreeValue(ctx, key);
JS_FreeValue(ctx, value);
}
JS_FreeValue(ctx, ret);
JS_FreeValue(ctx, item);
}
JS_FreeValue(ctx, next_method);
JS_FreeValue(ctx, iter);
JS_FreeValue(ctx, adder);
}
return obj;
fail:
if (JS_IsObject(iter)) {
/* close the iterator object, preserving pending exception */
JS_IteratorClose(ctx, iter, TRUE);
}
JS_FreeValue(ctx, next_method);
JS_FreeValue(ctx, iter);
JS_FreeValue(ctx, adder);
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
/* XXX: could normalize strings to speed up comparison */
static JSValueConst map_normalize_key(JSContext *ctx, JSValueConst key)
{
uint32_t tag = JS_VALUE_GET_TAG(key);
/* convert -0.0 to +0.0 */
if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0) {
key = JS_NewInt32(ctx, 0);
}
return key;
}
/* XXX: better hash ? */
static uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
{
uint32_t tag = JS_VALUE_GET_NORM_TAG(key);
uint32_t h;
double d;
JSFloat64Union u;
switch(tag) {
case JS_TAG_BOOL:
h = JS_VALUE_GET_INT(key);
break;
case JS_TAG_STRING:
h = hash_string(JS_VALUE_GET_STRING(key), 0);
break;
case JS_TAG_OBJECT:
case JS_TAG_SYMBOL:
h = (uintptr_t)JS_VALUE_GET_PTR(key) * 3163;
break;
case JS_TAG_INT:
d = JS_VALUE_GET_INT(key) * 3163;
goto hash_float64;
case JS_TAG_FLOAT64:
d = JS_VALUE_GET_FLOAT64(key);
/* normalize the NaN */
if (isnan(d))
d = JS_FLOAT64_NAN;
hash_float64:
u.d = d;
h = (u.u32[0] ^ u.u32[1]) * 3163;
break;
default:
h = 0; /* XXX: bignum support */
break;
}
h ^= tag;
return h;
}
static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s,
JSValueConst key)
{
struct list_head *el;
JSMapRecord *mr;
uint32_t h;
h = map_hash_key(ctx, key) & (s->hash_size - 1);
list_for_each(el, &s->hash_table[h]) {
mr = list_entry(el, JSMapRecord, hash_link);
if (js_same_value_zero(ctx, mr->key, key))
return mr;
}
return NULL;
}
static void map_hash_resize(JSContext *ctx, JSMapState *s)
{
uint32_t new_hash_size, i, h;
size_t slack;
struct list_head *new_hash_table, *el;
JSMapRecord *mr;
/* XXX: no reporting of memory allocation failure */
if (s->hash_size == 1)
new_hash_size = 4;
else
new_hash_size = s->hash_size * 2;
new_hash_table = js_realloc2(ctx, s->hash_table,
sizeof(new_hash_table[0]) * new_hash_size, &slack);
if (!new_hash_table)
return;
new_hash_size += slack / sizeof(*new_hash_table);
for(i = 0; i < new_hash_size; i++)
init_list_head(&new_hash_table[i]);
list_for_each(el, &s->records) {
mr = list_entry(el, JSMapRecord, link);
if (!mr->empty) {
h = map_hash_key(ctx, mr->key) & (new_hash_size - 1);
list_add_tail(&mr->hash_link, &new_hash_table[h]);
}
}
s->hash_table = new_hash_table;
s->hash_size = new_hash_size;
s->record_count_threshold = new_hash_size * 2;
}
static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
JSValueConst key)
{
uint32_t h;
JSMapRecord *mr;
mr = js_malloc(ctx, sizeof(*mr));
if (!mr)
return NULL;
mr->ref_count = 1;
mr->map = s;
mr->empty = FALSE;
if (s->is_weak) {
JSObject *p = JS_VALUE_GET_OBJ(key);
/* Add the weak reference */
mr->next_weak_ref = p->first_weak_ref;
p->first_weak_ref = mr;
} else {
JS_DupValue(ctx, key);
}
mr->key = (JSValue)key;
h = map_hash_key(ctx, key) & (s->hash_size - 1);
list_add_tail(&mr->hash_link, &s->hash_table[h]);
list_add_tail(&mr->link, &s->records);
s->record_count++;
if (s->record_count >= s->record_count_threshold) {
map_hash_resize(ctx, s);
}
return mr;
}
/* Remove the weak reference from the object weak
reference list. we don't use a doubly linked list to
save space, assuming a given object has few weak
references to it */
static void delete_weak_ref(JSRuntime *rt, JSMapRecord *mr)
{
JSMapRecord **pmr, *mr1;
JSObject *p;
p = JS_VALUE_GET_OBJ(mr->key);
pmr = &p->first_weak_ref;
for(;;) {
mr1 = *pmr;
assert(mr1 != NULL);
if (mr1 == mr)
break;
pmr = &mr1->next_weak_ref;
}
*pmr = mr1->next_weak_ref;
}
static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
{
if (mr->empty)
return;
list_del(&mr->hash_link);
if (s->is_weak) {
delete_weak_ref(rt, mr);
} else {
JS_FreeValueRT(rt, mr->key);
}
JS_FreeValueRT(rt, mr->value);
if (--mr->ref_count == 0) {
list_del(&mr->link);
js_free_rt(rt, mr);
} else {
/* keep a zombie record for iterators */
mr->empty = TRUE;
mr->key = JS_UNDEFINED;
mr->value = JS_UNDEFINED;
}
s->record_count--;
}
static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
{
if (--mr->ref_count == 0) {
/* the record can be safely removed */
assert(mr->empty);
list_del(&mr->link);
js_free_rt(rt, mr);
}
}
void reset_weak_ref(JSRuntime *rt, JSObject *p)
{
JSMapRecord *mr, *mr_next;
JSMapState *s;
(void)s;
/* first pass to remove the records from the WeakMap/WeakSet
lists */
for(mr = p->first_weak_ref; mr != NULL; mr = mr->next_weak_ref) {
s = mr->map;
assert(s->is_weak);
assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
list_del(&mr->hash_link);
list_del(&mr->link);
}
/* second pass to free the values to avoid modifying the weak
reference list while traversing it. */
for(mr = p->first_weak_ref; mr != NULL; mr = mr_next) {
mr_next = mr->next_weak_ref;
JS_FreeValueRT(rt, mr->value);
js_free_rt(rt, mr);
}
p->first_weak_ref = NULL; /* fail safe */
}
static JSValue js_map_set(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
JSMapRecord *mr;
JSValueConst key, value;
if (!s)
return JS_EXCEPTION;
key = map_normalize_key(ctx, argv[0]);
if (s->is_weak && !JS_IsObject(key))
return JS_ThrowTypeErrorNotAnObject(ctx);
if (magic & MAGIC_SET)
value = JS_UNDEFINED;
else
value = argv[1];
mr = map_find_record(ctx, s, key);
if (mr) {
JS_FreeValue(ctx, mr->value);
} else {
mr = map_add_record(ctx, s, key);
if (!mr)
return JS_EXCEPTION;
}
mr->value = JS_DupValue(ctx, value);
return JS_DupValue(ctx, this_val);
}
static JSValue js_map_get(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
JSMapRecord *mr;
JSValueConst key;
if (!s)
return JS_EXCEPTION;
key = map_normalize_key(ctx, argv[0]);
mr = map_find_record(ctx, s, key);
if (!mr)
return JS_UNDEFINED;
else
return JS_DupValue(ctx, mr->value);
}
static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
JSMapRecord *mr;
JSValueConst key;
if (!s)
return JS_EXCEPTION;
key = map_normalize_key(ctx, argv[0]);
mr = map_find_record(ctx, s, key);
return JS_NewBool(ctx, (mr != NULL));
}
static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
JSMapRecord *mr;
JSValueConst key;
if (!s)
return JS_EXCEPTION;
key = map_normalize_key(ctx, argv[0]);
mr = map_find_record(ctx, s, key);
if (!mr)
return JS_FALSE;
map_delete_record(ctx->rt, s, mr);
return JS_TRUE;
}
static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
struct list_head *el, *el1;
JSMapRecord *mr;
if (!s)
return JS_EXCEPTION;
list_for_each_safe(el, el1, &s->records) {
mr = list_entry(el, JSMapRecord, link);
map_delete_record(ctx->rt, s, mr);
}
return JS_UNDEFINED;
}
static JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic)
{
JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
if (!s)
return JS_EXCEPTION;
return JS_NewUint32(ctx, s->record_count);
}
static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
JSValueConst func, this_arg;
JSValue ret, args[3];
struct list_head *el;
JSMapRecord *mr;
if (!s)
return JS_EXCEPTION;
func = argv[0];
if (argc > 1)
this_arg = argv[1];
else
this_arg = JS_UNDEFINED;
if (check_function(ctx, func))
return JS_EXCEPTION;
/* Note: the list can be modified while traversing it, but the
current element is locked */
el = s->records.next;
while (el != &s->records) {
mr = list_entry(el, JSMapRecord, link);
if (!mr->empty) {
mr->ref_count++;
/* must duplicate in case the record is deleted */
args[1] = JS_DupValue(ctx, mr->key);
if (magic)
args[0] = args[1];
else
args[0] = JS_DupValue(ctx, mr->value);
args[2] = (JSValue)this_val;
ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);
JS_FreeValue(ctx, args[0]);
if (!magic)
JS_FreeValue(ctx, args[1]);
el = el->next;
map_decref_record(ctx->rt, mr);
if (JS_IsException(ret))
return ret;
JS_FreeValue(ctx, ret);
} else {
el = el->next;
}
}
return JS_UNDEFINED;
}
void js_map_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p;
JSMapState *s;
struct list_head *el, *el1;
JSMapRecord *mr;
p = JS_VALUE_GET_OBJ(val);
s = p->u.map_state;
if (s) {
/* if the object is deleted we are sure that no iterator is
using it */
list_for_each_safe(el, el1, &s->records) {
mr = list_entry(el, JSMapRecord, link);
if (!mr->empty) {
if (s->is_weak)
delete_weak_ref(rt, mr);
else
JS_FreeValueRT(rt, mr->key);
JS_FreeValueRT(rt, mr->value);
}
js_free_rt(rt, mr);
}
js_free_rt(rt, s->hash_table);
js_free_rt(rt, s);
}
}
void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
JSMapState *s;
struct list_head *el;
JSMapRecord *mr;
s = p->u.map_state;
if (s) {
list_for_each(el, &s->records) {
mr = list_entry(el, JSMapRecord, link);
if (!s->is_weak)
JS_MarkValue(rt, mr->key, mark_func);
JS_MarkValue(rt, mr->value, mark_func);
}
}
}
void js_map_iterator_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p;
JSMapIteratorData *it;
p = JS_VALUE_GET_OBJ(val);
it = p->u.map_iterator_data;
if (it) {
/* During the GC sweep phase the Map finalizer may be
called before the Map iterator finalizer */
if (JS_IsLiveObject(rt, it->obj) && it->cur_record) {
map_decref_record(rt, it->cur_record);
}
JS_FreeValueRT(rt, it->obj);
js_free_rt(rt, it);
}
}
void js_map_iterator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
JSMapIteratorData *it;
it = p->u.map_iterator_data;
if (it) {
/* the record is already marked by the object */
JS_MarkValue(rt, it->obj, mark_func);
}
}
static JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
JSIteratorKindEnum kind;
JSMapState *s;
JSMapIteratorData *it;
JSValue enum_obj;
kind = magic >> 2;
magic &= 3;
s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
if (!s)
return JS_EXCEPTION;
enum_obj = JS_NewObjectClass(ctx, JS_CLASS_MAP_ITERATOR + magic);
if (JS_IsException(enum_obj))
goto fail;
it = js_malloc(ctx, sizeof(*it));
if (!it) {
JS_FreeValue(ctx, enum_obj);
goto fail;
}
it->obj = JS_DupValue(ctx, this_val);
it->kind = kind;
it->cur_record = NULL;
JS_SetOpaque(enum_obj, it);
return enum_obj;
fail:
return JS_EXCEPTION;
}
static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv,
BOOL *pdone, int magic)
{
JSMapIteratorData *it;
JSMapState *s;
JSMapRecord *mr;
struct list_head *el;
it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic);
if (!it) {
*pdone = FALSE;
return JS_EXCEPTION;
}
if (JS_IsUndefined(it->obj))
goto done;
s = JS_GetOpaque(it->obj, JS_CLASS_MAP + magic);
assert(s != NULL);
if (!it->cur_record) {
el = s->records.next;
} else {
mr = it->cur_record;
el = mr->link.next;
map_decref_record(ctx->rt, mr); /* the record can be freed here */
}
for(;;) {
if (el == &s->records) {
/* no more record */
it->cur_record = NULL;
JS_FreeValue(ctx, it->obj);
it->obj = JS_UNDEFINED;
done:
/* end of enumeration */
*pdone = TRUE;
return JS_UNDEFINED;
}
mr = list_entry(el, JSMapRecord, link);
if (!mr->empty)
break;
/* get the next record */
el = mr->link.next;
}
/* lock the record so that it won't be freed */
mr->ref_count++;
it->cur_record = mr;
*pdone = FALSE;
if (it->kind == JS_ITERATOR_KIND_KEY) {
return JS_DupValue(ctx, mr->key);
} else {
JSValueConst args[2];
args[0] = mr->key;
if (magic)
args[1] = mr->key;
else
args[1] = mr->value;
if (it->kind == JS_ITERATOR_KIND_VALUE) {
return JS_DupValue(ctx, args[1]);
} else {
return js_create_array(ctx, 2, args);
}
}
}
static const JSCFunctionListEntry js_map_funcs[] = {
JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
};
static const JSCFunctionListEntry js_map_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, 0 ),
JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, 0 ),
JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, 0 ),
JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, 0 ),
JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, 0 ),
JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, 0),
JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, 0 ),
JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_VALUE << 2) | 0 ),
JS_CFUNC_MAGIC_DEF("keys", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | 0 ),
JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | 0 ),
JS_ALIAS_DEF("[Symbol.iterator]", "entries" ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map", JS_PROP_CONFIGURABLE ),
};
static const JSCFunctionListEntry js_map_iterator_proto_funcs[] = {
JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, 0 ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map Iterator", JS_PROP_CONFIGURABLE ),
};
static const JSCFunctionListEntry js_set_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET ),
JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET ),
JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET ),
JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ),
JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ),
JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ),
JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ),
JS_ALIAS_DEF("keys", "values" ),
JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | MAGIC_SET ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set", JS_PROP_CONFIGURABLE ),
};
static const JSCFunctionListEntry js_set_iterator_proto_funcs[] = {
JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, MAGIC_SET ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set Iterator", JS_PROP_CONFIGURABLE ),
};
static const JSCFunctionListEntry js_weak_map_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ),
JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ),
JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ),
JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ),
};
static const JSCFunctionListEntry js_weak_set_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ),
JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ),
JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakSet", JS_PROP_CONFIGURABLE ),
};
static const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = {
js_map_proto_funcs,
js_set_proto_funcs,
js_weak_map_proto_funcs,
js_weak_set_proto_funcs,
js_map_iterator_proto_funcs,
js_set_iterator_proto_funcs,
};
static const uint8_t js_map_proto_funcs_count[6] = {
countof(js_map_proto_funcs),
countof(js_set_proto_funcs),
countof(js_weak_map_proto_funcs),
countof(js_weak_set_proto_funcs),
countof(js_map_iterator_proto_funcs),
countof(js_set_iterator_proto_funcs),
};
void JS_AddIntrinsicMapSet(JSContext *ctx)
{
int i;
JSValue obj1;
char buf[ATOM_GET_STR_BUF_SIZE];
for(i = 0; i < 4; i++) {
const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),
JS_ATOM_Map + i);
ctx->class_proto[JS_CLASS_MAP + i] = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP + i],
js_map_proto_funcs_ptr[i],
js_map_proto_funcs_count[i]);
obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, 0,
JS_CFUNC_constructor_magic, i);
if (i < 2) {
JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs,
countof(js_map_funcs));
}
JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[JS_CLASS_MAP + i]);
}
for(i = 0; i < 2; i++) {
ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] =
JS_NewObjectProto(ctx, ctx->iterator_proto);
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP_ITERATOR + i],
js_map_proto_funcs_ptr[i + 4],
js_map_proto_funcs_count[i + 4]);
}
}

View file

@ -1,303 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/calls/struct/timeval.h"
#include "libc/time/time.h"
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
/* precondition: a and b are not NaN */
static double js_fmin(double a, double b)
{
if (a == 0 && b == 0) {
JSFloat64Union a1, b1;
a1.d = a;
b1.d = b;
a1.u64 |= b1.u64;
return a1.d;
} else {
return fmin(a, b);
}
}
/* precondition: a and b are not NaN */
static double js_fmax(double a, double b)
{
if (a == 0 && b == 0) {
JSFloat64Union a1, b1;
a1.d = a;
b1.d = b;
a1.u64 &= b1.u64;
return a1.d;
} else {
return fmax(a, b);
}
}
static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
BOOL is_max = magic;
double r, a;
int i;
uint32_t tag;
if (UNLIKELY(argc == 0)) {
return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
}
tag = JS_VALUE_GET_TAG(argv[0]);
if (tag == JS_TAG_INT) {
int a1, r1 = JS_VALUE_GET_INT(argv[0]);
for(i = 1; i < argc; i++) {
tag = JS_VALUE_GET_TAG(argv[i]);
if (tag != JS_TAG_INT) {
r = r1;
goto generic_case;
}
a1 = JS_VALUE_GET_INT(argv[i]);
if (is_max)
r1 = max_int(r1, a1);
else
r1 = min_int(r1, a1);
}
return JS_NewInt32(ctx, r1);
} else {
if (JS_ToFloat64(ctx, &r, argv[0]))
return JS_EXCEPTION;
i = 1;
generic_case:
while (i < argc) {
if (JS_ToFloat64(ctx, &a, argv[i]))
return JS_EXCEPTION;
if (!isnan(r)) {
if (isnan(a)) {
r = a;
} else {
if (is_max)
r = js_fmax(r, a);
else
r = js_fmin(r, a);
}
}
i++;
}
return JS_NewFloat64(ctx, r);
}
}
static double js_math_sign(double a)
{
if (isnan(a) || a == 0.0)
return a;
if (a < 0)
return -1;
else
return 1;
}
static double js_math_round(double a)
{
JSFloat64Union u;
uint64_t frac_mask, one;
unsigned int e, s;
u.d = a;
e = (u.u64 >> 52) & 0x7ff;
if (e < 1023) {
/* abs(a) < 1 */
if (e == (1023 - 1) && u.u64 != 0xbfe0000000000000) {
/* abs(a) > 0.5 or a = 0.5: return +/-1.0 */
u.u64 = (u.u64 & ((uint64_t)1 << 63)) | ((uint64_t)1023 << 52);
} else {
/* return +/-0.0 */
u.u64 &= (uint64_t)1 << 63;
}
} else if (e < (1023 + 52)) {
s = u.u64 >> 63;
one = (uint64_t)1 << (52 - (e - 1023));
frac_mask = one - 1;
u.u64 += (one >> 1) - s;
u.u64 &= ~frac_mask; /* truncate to an integer */
}
/* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */
return u.d;
}
static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
double r, a;
int i;
r = 0;
if (argc > 0) {
if (JS_ToFloat64(ctx, &r, argv[0]))
return JS_EXCEPTION;
if (argc == 1) {
r = fabs(r);
} else {
/* use the built-in function to minimize precision loss */
for (i = 1; i < argc; i++) {
if (JS_ToFloat64(ctx, &a, argv[i]))
return JS_EXCEPTION;
r = hypot(r, a);
}
}
}
return JS_NewFloat64(ctx, r);
}
static double js_math_fround(double a)
{
return (float)a;
}
static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
int a, b;
if (JS_ToInt32(ctx, &a, argv[0]))
return JS_EXCEPTION;
if (JS_ToInt32(ctx, &b, argv[1]))
return JS_EXCEPTION;
/* purposely ignoring overflow */
return JS_NewInt32(ctx, a * b);
}
static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
uint32_t a, r;
if (JS_ToUint32(ctx, &a, argv[0]))
return JS_EXCEPTION;
if (a == 0)
r = 32;
else
r = clz32(a);
return JS_NewInt32(ctx, r);
}
/* xorshift* random number generator by Marsaglia */
static uint64_t xorshift64star(uint64_t *pstate)
{
uint64_t x;
x = *pstate;
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
*pstate = x;
return x * 0x2545F4914F6CDD1D;
}
static void js_random_init(JSContext *ctx)
{
struct timeval tv;
gettimeofday(&tv, NULL);
ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
/* the state must be non zero */
if (ctx->random_state == 0)
ctx->random_state = 1;
}
static JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSFloat64Union u;
uint64_t v;
v = xorshift64star(&ctx->random_state);
/* 1.0 <= u.d < 2 */
u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);
return __JS_NewFloat64(ctx, u.d - 1.0);
}
double js_pow(double a, double b)
{
if (UNLIKELY(!isfinite(b)) && fabs(a) == 1) {
/* not compatible with IEEE 754 */
return JS_FLOAT64_NAN;
} else {
return pow(a, b);
}
}
static const JSCFunctionListEntry js_math_funcs[] = {
JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ),
JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos ),
JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin ),
JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan ),
JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2 ),
JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos ),
JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp ),
JS_CFUNC_SPECIAL_DEF("log", 1, f_f, log ),
JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_pow ),
JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin ),
JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan ),
/* ES6 */
JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, trunc ),
JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ),
JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh ),
JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh ),
JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh ),
JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh ),
JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh ),
JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ),
JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ),
JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ),
JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2 ),
JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ),
JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ),
JS_CFUNC_DEF("hypot", 2, js_math_hypot ),
JS_CFUNC_DEF("random", 0, js_math_random ),
JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ),
JS_CFUNC_DEF("imul", 2, js_math_imul ),
JS_CFUNC_DEF("clz32", 1, js_math_clz32 ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE ),
JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ),
JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ),
JS_PROP_DOUBLE_DEF("LN2", 0.6931471805599453, 0 ),
JS_PROP_DOUBLE_DEF("LOG2E", 1.4426950408889634, 0 ),
JS_PROP_DOUBLE_DEF("LOG10E", 0.4342944819032518, 0 ),
JS_PROP_DOUBLE_DEF("PI", 3.141592653589793, 0 ),
JS_PROP_DOUBLE_DEF("SQRT1_2", 0.7071067811865476, 0 ),
JS_PROP_DOUBLE_DEF("SQRT2", 1.4142135623730951, 0 ),
};
static const JSCFunctionListEntry js_math_obj[] = {
JS_OBJECT_DEF("Math", js_math_funcs, countof(js_math_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
};
void JS_AddIntrinsicMath(JSContext *ctx) {
/* Math: create as autoinit object */
js_random_init(ctx);
JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_math_obj, countof(js_math_obj));
}

View file

@ -1,188 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "third_party/quickjs/internal.h"
#include "third_party/quickjs/libregexp.h"
#include "third_party/quickjs/quickjs.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx)
{
return JS_ThrowTypeError(ctx, "revoked proxy");
}
JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
{
JSRuntime *rt = ctx->rt;
JSAtom name;
name = rt->class_array[class_id].class_name;
return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
}
/* warning: the refcount of the context is not incremented. Return
NULL in case of exception (case of revoked proxy only) */
JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)
{
JSObject *p;
JSContext *realm;
if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
return ctx;
p = JS_VALUE_GET_OBJ(func_obj);
switch(p->class_id) {
case JS_CLASS_C_FUNCTION:
realm = p->u.cfunc.realm;
break;
case JS_CLASS_BYTECODE_FUNCTION:
case JS_CLASS_GENERATOR_FUNCTION:
case JS_CLASS_ASYNC_FUNCTION:
case JS_CLASS_ASYNC_GENERATOR_FUNCTION:
{
JSFunctionBytecode *b;
b = p->u.func.function_bytecode;
realm = b->realm;
}
break;
case JS_CLASS_PROXY:
{
JSProxyData *s = p->u.opaque;
if (!s)
return ctx;
if (s->is_revoked) {
JS_ThrowTypeErrorRevokedProxy(ctx);
return NULL;
} else {
realm = JS_GetFunctionRealm(ctx, s->target);
}
}
break;
case JS_CLASS_BOUND_FUNCTION:
{
JSBoundFunction *bf = p->u.bound_function;
realm = JS_GetFunctionRealm(ctx, bf->func_obj);
}
break;
default:
realm = ctx;
break;
}
return realm;
}
JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
int class_id)
{
JSValue proto, obj;
JSContext *realm;
if (JS_IsUndefined(ctor)) {
proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
} else {
proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
if (JS_IsException(proto))
return proto;
if (!JS_IsObject(proto)) {
JS_FreeValue(ctx, proto);
realm = JS_GetFunctionRealm(ctx, ctor);
if (!realm)
return JS_EXCEPTION;
proto = JS_DupValue(ctx, realm->class_proto[class_id]);
}
}
obj = JS_NewObjectProtoClass(ctx, proto, class_id);
JS_FreeValue(ctx, proto);
return obj;
}
int JS_ToBoolFree(JSContext *ctx, JSValue val)
{
uint32_t tag = JS_VALUE_GET_TAG(val);
switch(tag) {
case JS_TAG_INT:
return JS_VALUE_GET_INT(val) != 0;
case JS_TAG_BOOL:
case JS_TAG_NULL:
case JS_TAG_UNDEFINED:
return JS_VALUE_GET_INT(val);
case JS_TAG_EXCEPTION:
return -1;
case JS_TAG_STRING:
{
BOOL ret = JS_VALUE_GET_STRING(val)->len != 0;
JS_FreeValue(ctx, val);
return ret;
}
#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
case JS_TAG_BIG_FLOAT:
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
BOOL ret;
ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
JS_FreeValue(ctx, val);
return ret;
}
case JS_TAG_BIG_DECIMAL:
{
JSBigDecimal *p = JS_VALUE_GET_PTR(val);
BOOL ret;
ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
JS_FreeValue(ctx, val);
return ret;
}
#endif
case JS_TAG_OBJECT:
{
JSObject *p = JS_VALUE_GET_OBJ(val);
BOOL ret;
ret = !p->is_HTMLDDA;
JS_FreeValue(ctx, val);
return ret;
}
break;
default:
if (JS_TAG_IS_FLOAT64(tag)) {
double d = JS_VALUE_GET_FLOAT64(val);
return !isnan(d) && d != 0;
} else {
JS_FreeValue(ctx, val);
return TRUE;
}
}
}
int JS_ToBool(JSContext *ctx, JSValueConst val)
{
return JS_ToBoolFree(ctx, JS_DupValue(ctx, val));
}
JSValue js_get_this(JSContext *ctx, JSValueConst this_val)
{
return JS_DupValue(ctx, this_val);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,109 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
{
int i;
BOOL force_ordinary;
JSAtom method_name;
JSValue method, ret;
if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
return val;
force_ordinary = hint & HINT_FORCE_ORDINARY;
hint &= ~HINT_FORCE_ORDINARY;
if (!force_ordinary) {
method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive);
if (JS_IsException(method))
goto exception;
/* ECMA says *If exoticToPrim is not undefined* but tests in
test262 use null as a non callable converter */
if (!JS_IsUndefined(method) && !JS_IsNull(method)) {
JSAtom atom;
JSValue arg;
switch(hint) {
case HINT_STRING:
atom = JS_ATOM_string;
break;
case HINT_NUMBER:
atom = JS_ATOM_number;
break;
default:
case HINT_NONE:
atom = JS_ATOM_default;
break;
}
arg = JS_AtomToString(ctx, atom);
ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
JS_FreeValue(ctx, arg);
if (JS_IsException(ret))
goto exception;
JS_FreeValue(ctx, val);
if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT)
return ret;
JS_FreeValue(ctx, ret);
return JS_ThrowTypeError(ctx, "toPrimitive");
}
}
if (hint != HINT_STRING)
hint = HINT_NUMBER;
for(i = 0; i < 2; i++) {
if ((i ^ hint) == 0) {
method_name = JS_ATOM_toString;
} else {
method_name = JS_ATOM_valueOf;
}
method = JS_GetProperty(ctx, val, method_name);
if (JS_IsException(method))
goto exception;
if (JS_IsFunction(ctx, method)) {
ret = JS_CallFree(ctx, method, val, 0, NULL);
if (JS_IsException(ret))
goto exception;
if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
JS_FreeValue(ctx, val);
return ret;
}
JS_FreeValue(ctx, ret);
} else {
JS_FreeValue(ctx, method);
}
}
JS_ThrowTypeError(ctx, "toPrimitive");
exception:
JS_FreeValue(ctx, val);
return JS_EXCEPTION;
}
JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint)
{
return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint);
}

File diff suppressed because it is too large Load diff

View file

@ -1,964 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
static void js_proxy_finalizer(JSRuntime *rt, JSValue val)
{
JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
if (s) {
JS_FreeValueRT(rt, s->target);
JS_FreeValueRT(rt, s->handler);
js_free_rt(rt, s);
}
}
static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func)
{
JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
if (s) {
JS_MarkValue(rt, s->target, mark_func);
JS_MarkValue(rt, s->handler, mark_func);
}
}
static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
JSValueConst obj, JSAtom name)
{
JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
JSValue method;
/* safer to test recursion in all proxy methods */
if (js_check_stack_overflow(ctx->rt, 0)) {
JS_ThrowStackOverflow(ctx);
return NULL;
}
/* 's' should never be NULL */
if (s->is_revoked) {
JS_ThrowTypeErrorRevokedProxy(ctx);
return NULL;
}
method = JS_GetProperty(ctx, s->handler, name);
if (JS_IsException(method))
return NULL;
if (JS_IsNull(method))
method = JS_UNDEFINED;
*pmethod = method;
return s;
}
JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
{
JSProxyData *s;
JSValue method, ret, proto1;
int res;
s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf);
if (!s)
return JS_EXCEPTION;
if (JS_IsUndefined(method))
return JS_GetPrototype(ctx, s->target);
ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
if (JS_IsException(ret))
return ret;
if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&
JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
goto fail;
}
res = JS_IsExtensible(ctx, s->target);
if (res < 0) {
JS_FreeValue(ctx, ret);
return JS_EXCEPTION;
}
if (!res) {
/* check invariant */
proto1 = JS_GetPrototype(ctx, s->target);
if (JS_IsException(proto1)) {
JS_FreeValue(ctx, ret);
return JS_EXCEPTION;
}
if (JS_VALUE_GET_OBJ(proto1) != JS_VALUE_GET_OBJ(ret)) {
JS_FreeValue(ctx, proto1);
fail:
JS_FreeValue(ctx, ret);
return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
}
JS_FreeValue(ctx, proto1);
}
return ret;
}
int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
JSValueConst proto_val, BOOL throw_flag)
{
JSProxyData *s;
JSValue method, ret, proto1;
JSValueConst args[2];
BOOL res;
int res2;
s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf);
if (!s)
return -1;
if (JS_IsUndefined(method))
return JS_SetPrototypeInternal(ctx, s->target, proto_val, throw_flag);
args[0] = s->target;
args[1] = proto_val;
ret = JS_CallFree(ctx, method, s->handler, 2, args);
if (JS_IsException(ret))
return -1;
res = JS_ToBoolFree(ctx, ret);
if (!res) {
if (throw_flag) {
JS_ThrowTypeError(ctx, "proxy: bad prototype");
return -1;
} else {
return FALSE;
}
}
res2 = JS_IsExtensible(ctx, s->target);
if (res2 < 0)
return -1;
if (!res2) {
proto1 = JS_GetPrototype(ctx, s->target);
if (JS_IsException(proto1))
return -1;
if (JS_VALUE_GET_OBJ(proto_val) != JS_VALUE_GET_OBJ(proto1)) {
JS_FreeValue(ctx, proto1);
JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
return -1;
}
JS_FreeValue(ctx, proto1);
}
return TRUE;
}
int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj)
{
JSProxyData *s;
JSValue method, ret;
BOOL res;
int res2;
s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible);
if (!s)
return -1;
if (JS_IsUndefined(method))
return JS_IsExtensible(ctx, s->target);
ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
if (JS_IsException(ret))
return -1;
res = JS_ToBoolFree(ctx, ret);
res2 = JS_IsExtensible(ctx, s->target);
if (res2 < 0)
return res2;
if (res != res2) {
JS_ThrowTypeError(ctx, "proxy: inconsistent isExtensible");
return -1;
}
return res;
}
int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj)
{
JSProxyData *s;
JSValue method, ret;
BOOL res;
int res2;
s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions);
if (!s)
return -1;
if (JS_IsUndefined(method))
return JS_PreventExtensions(ctx, s->target);
ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
if (JS_IsException(ret))
return -1;
res = JS_ToBoolFree(ctx, ret);
if (res) {
res2 = JS_IsExtensible(ctx, s->target);
if (res2 < 0)
return res2;
if (res2) {
JS_ThrowTypeError(ctx, "proxy: inconsistent preventExtensions");
return -1;
}
}
return res;
}
static int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
{
JSProxyData *s;
JSValue method, ret1, atom_val;
int ret, res;
JSObject *p;
JSValueConst args[2];
BOOL res2;
s = get_proxy_method(ctx, &method, obj, JS_ATOM_has);
if (!s)
return -1;
if (JS_IsUndefined(method))
return JS_HasProperty(ctx, s->target, atom);
atom_val = JS_AtomToValue(ctx, atom);
if (JS_IsException(atom_val)) {
JS_FreeValue(ctx, method);
return -1;
}
args[0] = s->target;
args[1] = atom_val;
ret1 = JS_CallFree(ctx, method, s->handler, 2, args);
JS_FreeValue(ctx, atom_val);
if (JS_IsException(ret1))
return -1;
ret = JS_ToBoolFree(ctx, ret1);
if (!ret) {
JSPropertyDescriptor desc;
p = JS_VALUE_GET_OBJ(s->target);
res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
if (res < 0)
return -1;
if (res) {
res2 = !(desc.flags & JS_PROP_CONFIGURABLE);
js_free_desc(ctx, &desc);
if (res2 || !p->extensible) {
JS_ThrowTypeError(ctx, "proxy: inconsistent has");
return -1;
}
}
}
return ret;
}
static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
JSValueConst receiver)
{
JSProxyData *s;
JSValue method, ret, atom_val;
int res;
JSValueConst args[3];
JSPropertyDescriptor desc;
s = get_proxy_method(ctx, &method, obj, JS_ATOM_get);
if (!s)
return JS_EXCEPTION;
/* Note: recursion is possible thru the prototype of s->target */
if (JS_IsUndefined(method))
return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE);
atom_val = JS_AtomToValue(ctx, atom);
if (JS_IsException(atom_val)) {
JS_FreeValue(ctx, method);
return JS_EXCEPTION;
}
args[0] = s->target;
args[1] = atom_val;
args[2] = receiver;
ret = JS_CallFree(ctx, method, s->handler, 3, args);
JS_FreeValue(ctx, atom_val);
if (JS_IsException(ret))
return JS_EXCEPTION;
res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
if (res < 0)
return JS_EXCEPTION;
if (res) {
if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
if (!js_same_value(ctx, desc.value, ret)) {
goto fail;
}
} else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET) {
if (JS_IsUndefined(desc.getter) && !JS_IsUndefined(ret)) {
fail:
js_free_desc(ctx, &desc);
JS_FreeValue(ctx, ret);
return JS_ThrowTypeError(ctx, "proxy: inconsistent get");
}
}
js_free_desc(ctx, &desc);
}
return ret;
}
static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
JSValueConst value, JSValueConst receiver, int flags)
{
JSProxyData *s;
JSValue method, ret1, atom_val;
int ret, res;
JSValueConst args[4];
s = get_proxy_method(ctx, &method, obj, JS_ATOM_set);
if (!s)
return -1;
if (JS_IsUndefined(method)) {
return JS_SetPropertyGeneric(ctx, s->target, atom,
JS_DupValue(ctx, value), receiver,
flags);
}
atom_val = JS_AtomToValue(ctx, atom);
if (JS_IsException(atom_val)) {
JS_FreeValue(ctx, method);
return -1;
}
args[0] = s->target;
args[1] = atom_val;
args[2] = value;
args[3] = receiver;
ret1 = JS_CallFree(ctx, method, s->handler, 4, args);
JS_FreeValue(ctx, atom_val);
if (JS_IsException(ret1))
return -1;
ret = JS_ToBoolFree(ctx, ret1);
if (ret) {
JSPropertyDescriptor desc;
res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
if (res < 0)
return -1;
if (res) {
if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
if (!js_same_value(ctx, desc.value, value)) {
goto fail;
}
} else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET && JS_IsUndefined(desc.setter)) {
fail:
js_free_desc(ctx, &desc);
JS_ThrowTypeError(ctx, "proxy: inconsistent set");
return -1;
}
js_free_desc(ctx, &desc);
}
} else {
if ((flags & JS_PROP_THROW) ||
((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
JS_ThrowTypeError(ctx, "proxy: cannot set property");
return -1;
}
}
return ret;
}
static JSValue js_create_desc(JSContext *ctx, JSValueConst val,
JSValueConst getter, JSValueConst setter,
int flags)
{
JSValue ret;
ret = JS_NewObject(ctx);
if (JS_IsException(ret))
return ret;
if (flags & JS_PROP_HAS_GET) {
JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, getter),
JS_PROP_C_W_E);
}
if (flags & JS_PROP_HAS_SET) {
JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, setter),
JS_PROP_C_W_E);
}
if (flags & JS_PROP_HAS_VALUE) {
JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, val),
JS_PROP_C_W_E);
}
if (flags & JS_PROP_HAS_WRITABLE) {
JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
JS_NewBool(ctx, (flags & JS_PROP_WRITABLE) != 0),
JS_PROP_C_W_E);
}
if (flags & JS_PROP_HAS_ENUMERABLE) {
JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
JS_NewBool(ctx, (flags & JS_PROP_ENUMERABLE) != 0),
JS_PROP_C_W_E);
}
if (flags & JS_PROP_HAS_CONFIGURABLE) {
JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
JS_NewBool(ctx, (flags & JS_PROP_CONFIGURABLE) != 0),
JS_PROP_C_W_E);
}
return ret;
}
static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc,
JSValueConst obj, JSAtom prop)
{
JSProxyData *s;
JSValue method, trap_result_obj, prop_val;
int res, target_desc_ret, ret;
JSObject *p;
JSValueConst args[2];
JSPropertyDescriptor result_desc, target_desc;
s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor);
if (!s)
return -1;
p = JS_VALUE_GET_OBJ(s->target);
if (JS_IsUndefined(method)) {
return JS_GetOwnPropertyInternal(ctx, pdesc, p, prop);
}
prop_val = JS_AtomToValue(ctx, prop);
if (JS_IsException(prop_val)) {
JS_FreeValue(ctx, method);
return -1;
}
args[0] = s->target;
args[1] = prop_val;
trap_result_obj = JS_CallFree(ctx, method, s->handler, 2, args);
JS_FreeValue(ctx, prop_val);
if (JS_IsException(trap_result_obj))
return -1;
if (!JS_IsObject(trap_result_obj) && !JS_IsUndefined(trap_result_obj)) {
JS_FreeValue(ctx, trap_result_obj);
goto fail;
}
target_desc_ret = JS_GetOwnPropertyInternal(ctx, &target_desc, p, prop);
if (target_desc_ret < 0) {
JS_FreeValue(ctx, trap_result_obj);
return -1;
}
if (target_desc_ret)
js_free_desc(ctx, &target_desc);
if (JS_IsUndefined(trap_result_obj)) {
if (target_desc_ret) {
if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible)
goto fail;
}
ret = FALSE;
} else {
int flags1, extensible_target;
extensible_target = JS_IsExtensible(ctx, s->target);
if (extensible_target < 0) {
JS_FreeValue(ctx, trap_result_obj);
return -1;
}
res = js_obj_to_desc(ctx, &result_desc, trap_result_obj);
JS_FreeValue(ctx, trap_result_obj);
if (res < 0)
return -1;
if (target_desc_ret) {
/* convert result_desc.flags to defineProperty flags */
flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE;
if (result_desc.flags & JS_PROP_GETSET)
flags1 |= JS_PROP_HAS_GET | JS_PROP_HAS_SET;
else
flags1 |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE;
/* XXX: not complete check: need to compare value &
getter/setter as in defineproperty */
if (!check_define_prop_flags(target_desc.flags, flags1))
goto fail1;
} else {
if (!extensible_target)
goto fail1;
}
if (!(result_desc.flags & JS_PROP_CONFIGURABLE)) {
if (!target_desc_ret || (target_desc.flags & JS_PROP_CONFIGURABLE))
goto fail1;
if ((result_desc.flags &
(JS_PROP_GETSET | JS_PROP_WRITABLE)) == 0 &&
target_desc_ret &&
(target_desc.flags & JS_PROP_WRITABLE) != 0) {
/* proxy-missing-checks */
fail1:
js_free_desc(ctx, &result_desc);
fail:
JS_ThrowTypeError(ctx, "proxy: inconsistent getOwnPropertyDescriptor");
return -1;
}
}
ret = TRUE;
if (pdesc) {
*pdesc = result_desc;
} else {
js_free_desc(ctx, &result_desc);
}
}
return ret;
}
static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
JSAtom prop, JSValueConst val,
JSValueConst getter, JSValueConst setter,
int flags)
{
JSProxyData *s;
JSValue method, ret1, prop_val, desc_val;
int res, ret;
JSObject *p;
JSValueConst args[3];
JSPropertyDescriptor desc;
BOOL setting_not_configurable;
s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty);
if (!s)
return -1;
if (JS_IsUndefined(method)) {
return JS_DefineProperty(ctx, s->target, prop, val, getter, setter, flags);
}
prop_val = JS_AtomToValue(ctx, prop);
if (JS_IsException(prop_val)) {
JS_FreeValue(ctx, method);
return -1;
}
desc_val = js_create_desc(ctx, val, getter, setter, flags);
if (JS_IsException(desc_val)) {
JS_FreeValue(ctx, prop_val);
JS_FreeValue(ctx, method);
return -1;
}
args[0] = s->target;
args[1] = prop_val;
args[2] = desc_val;
ret1 = JS_CallFree(ctx, method, s->handler, 3, args);
JS_FreeValue(ctx, prop_val);
JS_FreeValue(ctx, desc_val);
if (JS_IsException(ret1))
return -1;
ret = JS_ToBoolFree(ctx, ret1);
if (!ret) {
if (flags & JS_PROP_THROW) {
JS_ThrowTypeError(ctx, "proxy: defineProperty exception");
return -1;
} else {
return 0;
}
}
p = JS_VALUE_GET_OBJ(s->target);
res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
if (res < 0)
return -1;
setting_not_configurable = ((flags & (JS_PROP_HAS_CONFIGURABLE |
JS_PROP_CONFIGURABLE)) ==
JS_PROP_HAS_CONFIGURABLE);
if (!res) {
if (!p->extensible || setting_not_configurable)
goto fail;
} else {
if (!check_define_prop_flags(desc.flags, flags) ||
((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)) {
goto fail1;
}
if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) ==
JS_PROP_GETSET) {
if ((flags & JS_PROP_HAS_GET) &&
!js_same_value(ctx, getter, desc.getter)) {
goto fail1;
}
if ((flags & JS_PROP_HAS_SET) &&
!js_same_value(ctx, setter, desc.setter)) {
goto fail1;
}
}
} else if (flags & JS_PROP_HAS_VALUE) {
if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) ==
JS_PROP_WRITABLE && !(flags & JS_PROP_WRITABLE)) {
/* missing-proxy-check feature */
goto fail1;
} else if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
!js_same_value(ctx, val, desc.value)) {
goto fail1;
}
}
if (flags & JS_PROP_HAS_WRITABLE) {
if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE |
JS_PROP_WRITABLE)) == JS_PROP_WRITABLE) {
/* proxy-missing-checks */
fail1:
js_free_desc(ctx, &desc);
fail:
JS_ThrowTypeError(ctx, "proxy: inconsistent defineProperty");
return -1;
}
}
js_free_desc(ctx, &desc);
}
return 1;
}
static int js_proxy_delete_property(JSContext *ctx, JSValueConst obj,
JSAtom atom)
{
JSProxyData *s;
JSValue method, ret, atom_val;
int res, res2, is_extensible;
JSValueConst args[2];
s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty);
if (!s)
return -1;
if (JS_IsUndefined(method)) {
return JS_DeleteProperty(ctx, s->target, atom, 0);
}
atom_val = JS_AtomToValue(ctx, atom);;
if (JS_IsException(atom_val)) {
JS_FreeValue(ctx, method);
return -1;
}
args[0] = s->target;
args[1] = atom_val;
ret = JS_CallFree(ctx, method, s->handler, 2, args);
JS_FreeValue(ctx, atom_val);
if (JS_IsException(ret))
return -1;
res = JS_ToBoolFree(ctx, ret);
if (res) {
JSPropertyDescriptor desc;
res2 = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
if (res2 < 0)
return -1;
if (res2) {
if (!(desc.flags & JS_PROP_CONFIGURABLE))
goto fail;
is_extensible = JS_IsExtensible(ctx, s->target);
if (is_extensible < 0)
goto fail1;
if (!is_extensible) {
/* proxy-missing-checks */
fail:
JS_ThrowTypeError(ctx, "proxy: inconsistent deleteProperty");
fail1:
js_free_desc(ctx, &desc);
return -1;
}
js_free_desc(ctx, &desc);
}
}
return res;
}
/* return the index of the property or -1 if not found */
static int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom)
{
int i;
for(i = 0; i < n; i++) {
if (tab[i].atom == atom)
return i;
}
return -1;
}
static int js_proxy_get_own_property_names(JSContext *ctx,
JSPropertyEnum **ptab,
uint32_t *plen,
JSValueConst obj)
{
JSProxyData *s;
JSValue method, prop_array, val;
uint32_t len, i, len2;
JSPropertyEnum *tab, *tab2;
JSAtom atom;
JSPropertyDescriptor desc;
int res, is_extensible, idx;
s = get_proxy_method(ctx, &method, obj, JS_ATOM_ownKeys);
if (!s)
return -1;
if (JS_IsUndefined(method)) {
return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
JS_VALUE_GET_OBJ(s->target),
JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
}
prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
if (JS_IsException(prop_array))
return -1;
tab = NULL;
len = 0;
tab2 = NULL;
len2 = 0;
if (js_get_length32(ctx, &len, prop_array))
goto fail;
if (len > 0) {
tab = js_mallocz(ctx, sizeof(tab[0]) * len);
if (!tab)
goto fail;
}
for(i = 0; i < len; i++) {
val = JS_GetPropertyUint32(ctx, prop_array, i);
if (JS_IsException(val))
goto fail;
if (!JS_IsString(val) && !JS_IsSymbol(val)) {
JS_FreeValue(ctx, val);
JS_ThrowTypeError(ctx, "proxy: properties must be strings or symbols");
goto fail;
}
atom = JS_ValueToAtom(ctx, val);
JS_FreeValue(ctx, val);
if (atom == JS_ATOM_NULL)
goto fail;
tab[i].atom = atom;
tab[i].is_enumerable = FALSE; /* XXX: redundant? */
}
/* check duplicate properties (XXX: inefficient, could store the
* properties an a temporary object to use the hash) */
for(i = 1; i < len; i++) {
if (find_prop_key(tab, i, tab[i].atom) >= 0) {
JS_ThrowTypeError(ctx, "proxy: duplicate property");
goto fail;
}
}
is_extensible = JS_IsExtensible(ctx, s->target);
if (is_extensible < 0)
goto fail;
/* check if there are non configurable properties */
if (s->is_revoked) {
JS_ThrowTypeErrorRevokedProxy(ctx);
goto fail;
}
if (JS_GetOwnPropertyNamesInternal(ctx, &tab2, &len2, JS_VALUE_GET_OBJ(s->target),
JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
goto fail;
for(i = 0; i < len2; i++) {
if (s->is_revoked) {
JS_ThrowTypeErrorRevokedProxy(ctx);
goto fail;
}
res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target),
tab2[i].atom);
if (res < 0)
goto fail;
if (res) { /* safety, property should be found */
js_free_desc(ctx, &desc);
if (!(desc.flags & JS_PROP_CONFIGURABLE) || !is_extensible) {
idx = find_prop_key(tab, len, tab2[i].atom);
if (idx < 0) {
JS_ThrowTypeError(ctx, "proxy: target property must be present in proxy ownKeys");
goto fail;
}
/* mark the property as found */
if (!is_extensible)
tab[idx].is_enumerable = TRUE;
}
}
}
if (!is_extensible) {
/* check that all property in 'tab' were checked */
for(i = 0; i < len; i++) {
if (!tab[i].is_enumerable) {
JS_ThrowTypeError(ctx, "proxy: property not present in target were returned by non extensible proxy");
goto fail;
}
}
}
js_free_prop_enum(ctx, tab2, len2);
JS_FreeValue(ctx, prop_array);
*ptab = tab;
*plen = len;
return 0;
fail:
js_free_prop_enum(ctx, tab2, len2);
js_free_prop_enum(ctx, tab, len);
JS_FreeValue(ctx, prop_array);
return -1;
}
static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj,
JSValueConst new_target,
int argc, JSValueConst *argv)
{
JSProxyData *s;
JSValue method, arg_array, ret;
JSValueConst args[3];
s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct);
if (!s)
return JS_EXCEPTION;
if (!JS_IsConstructor(ctx, s->target))
return JS_ThrowTypeError(ctx, "not a constructor");
if (JS_IsUndefined(method))
return JS_CallConstructor2(ctx, s->target, new_target, argc, argv);
arg_array = js_create_array(ctx, argc, argv);
if (JS_IsException(arg_array)) {
ret = JS_EXCEPTION;
goto fail;
}
args[0] = s->target;
args[1] = arg_array;
args[2] = new_target;
ret = JS_Call(ctx, method, s->handler, 3, args);
if (!JS_IsException(ret) && JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
JS_FreeValue(ctx, ret);
ret = JS_ThrowTypeErrorNotAnObject(ctx);
}
fail:
JS_FreeValue(ctx, method);
JS_FreeValue(ctx, arg_array);
return ret;
}
static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
JSValueConst this_obj,
int argc, JSValueConst *argv, int flags)
{
JSProxyData *s;
JSValue method, arg_array, ret;
JSValueConst args[3];
if (flags & JS_CALL_FLAG_CONSTRUCTOR)
return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv);
s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply);
if (!s)
return JS_EXCEPTION;
if (!s->is_func) {
JS_FreeValue(ctx, method);
return JS_ThrowTypeError(ctx, "not a function");
}
if (JS_IsUndefined(method))
return JS_Call(ctx, s->target, this_obj, argc, argv);
arg_array = js_create_array(ctx, argc, argv);
if (JS_IsException(arg_array)) {
ret = JS_EXCEPTION;
goto fail;
}
args[0] = s->target;
args[1] = this_obj;
args[2] = arg_array;
ret = JS_Call(ctx, method, s->handler, 3, args);
fail:
JS_FreeValue(ctx, method);
JS_FreeValue(ctx, arg_array);
return ret;
}
int js_proxy_isArray(JSContext *ctx, JSValueConst obj)
{
JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
if (!s)
return FALSE;
if (js_check_stack_overflow(ctx->rt, 0)) {
JS_ThrowStackOverflow(ctx);
return -1;
}
if (s->is_revoked) {
JS_ThrowTypeErrorRevokedProxy(ctx);
return -1;
}
return JS_IsArray(ctx, s->target);
}
static const JSClassExoticMethods js_proxy_exotic_methods = {
.get_own_property = js_proxy_get_own_property,
.define_own_property = js_proxy_define_own_property,
.delete_property = js_proxy_delete_property,
.get_own_property_names = js_proxy_get_own_property_names,
.has_property = js_proxy_has,
.get_property = js_proxy_get,
.set_property = js_proxy_set,
};
static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValueConst target, handler;
JSValue obj;
JSProxyData *s;
target = argv[0];
handler = argv[1];
if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT ||
JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT)
return JS_ThrowTypeErrorNotAnObject(ctx);
obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY);
if (JS_IsException(obj))
return obj;
s = js_malloc(ctx, sizeof(JSProxyData));
if (!s) {
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
s->target = JS_DupValue(ctx, target);
s->handler = JS_DupValue(ctx, handler);
s->is_func = JS_IsFunction(ctx, target);
s->is_revoked = FALSE;
JS_SetOpaque(obj, s);
JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target));
return obj;
}
static JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic,
JSValue *func_data)
{
JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY);
if (s) {
/* We do not free the handler and target in case they are
referenced as constants in the C call stack */
s->is_revoked = TRUE;
JS_FreeValue(ctx, func_data[0]);
func_data[0] = JS_NULL;
}
return JS_UNDEFINED;
}
static JSValue js_proxy_revoke_constructor(JSContext *ctx,
JSValueConst proxy_obj)
{
return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj);
}
static JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj;
proxy_obj = js_proxy_constructor(ctx, JS_UNDEFINED, argc, argv);
if (JS_IsException(proxy_obj))
goto fail;
revoke_obj = js_proxy_revoke_constructor(ctx, proxy_obj);
if (JS_IsException(revoke_obj))
goto fail;
obj = JS_NewObject(ctx);
if (JS_IsException(obj))
goto fail;
// XXX: exceptions?
JS_DefinePropertyValue(ctx, obj, JS_ATOM_proxy, proxy_obj, JS_PROP_C_W_E);
JS_DefinePropertyValue(ctx, obj, JS_ATOM_revoke, revoke_obj, JS_PROP_C_W_E);
return obj;
fail:
JS_FreeValue(ctx, proxy_obj);
JS_FreeValue(ctx, revoke_obj);
return JS_EXCEPTION;
}
static const JSCFunctionListEntry js_proxy_funcs[] = {
JS_CFUNC_DEF("revocable", 2, js_proxy_revocable ),
};
static const JSClassShortDef js_proxy_class_def[] = {
{ JS_ATOM_Object, js_proxy_finalizer, js_proxy_mark }, /* JS_CLASS_PROXY */
};
void JS_AddIntrinsicProxy(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
JSValue obj1;
if (!JS_IsRegisteredClass(rt, JS_CLASS_PROXY)) {
init_class_range(rt, js_proxy_class_def, JS_CLASS_PROXY,
countof(js_proxy_class_def));
rt->class_array[JS_CLASS_PROXY].exotic = &js_proxy_exotic_methods;
rt->class_array[JS_CLASS_PROXY].call = js_proxy_call;
}
obj1 = JS_NewCFunction2(ctx, js_proxy_constructor, "Proxy", 2,
JS_CFUNC_constructor, 0);
JS_SetConstructorBit(ctx, obj1, TRUE);
JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs,
countof(js_proxy_funcs));
JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Proxy",
obj1, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
}

View file

@ -1,578 +0,0 @@
/*
* QuickJS stand alone interpreter
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/weirdtypes.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "third_party/quickjs/cutils.h"
#include "third_party/quickjs/quickjs-libc.h"
#include "tool/args/args.h"
STATIC_STACK_SIZE(0x80000);
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
extern const uint8_t qjsc_repl[];
extern const uint32_t qjsc_repl_size;
#ifdef CONFIG_BIGNUM
extern const uint8_t qjsc_qjscalc[];
extern const uint32_t qjsc_qjscalc_size;
static int bignum_ext;
#endif
static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
const char *filename, int eval_flags)
{
JSValue val;
int ret;
if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) {
/* for the modules, we compile then run to be able to set
import.meta */
val = JS_Eval(ctx, buf, buf_len, filename,
eval_flags | JS_EVAL_FLAG_COMPILE_ONLY);
if (!JS_IsException(val)) {
js_module_set_import_meta(ctx, val, TRUE, TRUE);
val = JS_EvalFunction(ctx, val);
}
} else {
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
}
if (JS_IsException(val)) {
js_std_dump_error(ctx);
ret = -1;
} else {
ret = 0;
}
JS_FreeValue(ctx, val);
return ret;
}
static int eval_file(JSContext *ctx, const char *filename, int module)
{
uint8_t *buf;
int ret, eval_flags;
size_t buf_len;
buf = js_load_file(ctx, &buf_len, filename);
if (!buf) {
perror(filename);
exit(1);
}
if (module < 0) {
module = (has_suffix(filename, ".mjs") ||
JS_DetectModule((const char *)buf, buf_len));
}
if (module)
eval_flags = JS_EVAL_TYPE_MODULE;
else
eval_flags = JS_EVAL_TYPE_GLOBAL;
ret = eval_buf(ctx, buf, buf_len, filename, eval_flags);
js_free(ctx, buf);
return ret;
}
/* also used to initialize the worker context */
static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx;
ctx = JS_NewContext(rt);
if (!ctx)
return NULL;
#ifdef CONFIG_BIGNUM
if (bignum_ext) {
JS_AddIntrinsicBigFloat(ctx);
JS_AddIntrinsicBigDecimal(ctx);
JS_AddIntrinsicOperators(ctx);
JS_EnableBignumExt(ctx, TRUE);
}
#endif
/* system modules */
js_init_module_std(ctx, "std");
js_init_module_os(ctx, "os");
return ctx;
}
#if defined(__APPLE__)
#define MALLOC_OVERHEAD 0
#else
#define MALLOC_OVERHEAD 8
#endif
struct trace_malloc_data {
uint8_t *base;
};
static inline unsigned long long js_trace_malloc_ptr_offset(uint8_t *ptr,
struct trace_malloc_data *dp)
{
return ptr - dp->base;
}
/* default memory allocation functions with memory limitation */
static inline size_t js_trace_malloc_usable_size(void *ptr)
{
#if defined(__APPLE__)
return malloc_size(ptr);
#elif defined(_WIN32)
return _msize(ptr);
#elif defined(EMSCRIPTEN)
return 0;
#elif defined(__linux__)
return malloc_usable_size(ptr);
#else
/* change this to `return 0;` if compilation fails */
return malloc_usable_size(ptr);
#endif
}
static void
#ifdef _WIN32
/* mingw printf is used */
__attribute__((format(gnu_printf, 2, 3)))
#else
__attribute__((format(printf, 2, 3)))
#endif
js_trace_malloc_printf(JSMallocState *s, const char *fmt, ...)
{
va_list ap;
int c;
va_start(ap, fmt);
while ((c = *fmt++) != '\0') {
if (c == '%') {
/* only handle %p and %zd */
if (*fmt == 'p') {
uint8_t *ptr = va_arg(ap, void *);
if (ptr == NULL) {
printf("NULL");
} else {
printf("H%+06lld.%zd",
js_trace_malloc_ptr_offset(ptr, s->opaque),
js_trace_malloc_usable_size(ptr));
}
fmt++;
continue;
}
if (fmt[0] == 'z' && fmt[1] == 'd') {
size_t sz = va_arg(ap, size_t);
printf("%zd", sz);
fmt += 2;
continue;
}
}
putc(c, stdout);
}
va_end(ap);
}
static void js_trace_malloc_init(struct trace_malloc_data *s)
{
free(s->base = malloc(8));
}
static void *js_trace_malloc(JSMallocState *s, size_t size)
{
void *ptr;
/* Do not allocate zero bytes: behavior is platform dependent */
assert(size != 0);
if (UNLIKELY(s->malloc_size + size > s->malloc_limit))
return NULL;
ptr = malloc(size);
js_trace_malloc_printf(s, "A %zd -> %p\n", size, ptr);
if (ptr) {
s->malloc_count++;
s->malloc_size += js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
}
return ptr;
}
static void js_trace_free(JSMallocState *s, void *ptr)
{
if (!ptr)
return;
js_trace_malloc_printf(s, "F %p\n", ptr);
s->malloc_count--;
s->malloc_size -= js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
free(ptr);
}
static void *js_trace_realloc(JSMallocState *s, void *ptr, size_t size)
{
size_t old_size;
if (!ptr) {
if (size == 0)
return NULL;
return js_trace_malloc(s, size);
}
old_size = js_trace_malloc_usable_size(ptr);
if (size == 0) {
js_trace_malloc_printf(s, "R %zd %p\n", size, ptr);
s->malloc_count--;
s->malloc_size -= old_size + MALLOC_OVERHEAD;
free(ptr);
return NULL;
}
if (s->malloc_size + size - old_size > s->malloc_limit)
return NULL;
js_trace_malloc_printf(s, "R %zd %p", size, ptr);
ptr = realloc(ptr, size);
js_trace_malloc_printf(s, " -> %p\n", ptr);
if (ptr) {
s->malloc_size += js_trace_malloc_usable_size(ptr) - old_size;
}
return ptr;
}
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__) || defined(__COSMOPOLITAN__)
(size_t (*)(const void *))malloc_usable_size,
#else
/* change this to `NULL,` if compilation fails */
malloc_usable_size,
#endif
};
#define PROG_NAME "qjs"
void help(void)
{
printf("QuickJS version " CONFIG_VERSION "\n"
"usage: " PROG_NAME " [options] [file [args]]\n"
"-h --help list options\n"
"-e --eval EXPR evaluate EXPR\n"
"-i --interactive go to interactive mode\n"
"-m --module load as ES6 module (default=autodetect)\n"
" --script load as ES6 script (default=autodetect)\n"
"-I --include file include an additional file\n"
" --std make 'std' and 'os' available to the loaded script\n"
#ifdef CONFIG_BIGNUM
" --bignum enable the bignum extensions (BigFloat, BigDecimal)\n"
" --qjscalc load the QJSCalc runtime (default if invoked as qjscalc)\n"
#endif
"-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);
}
int main(int argc, char **argv)
{
JSRuntime *rt;
JSContext *ctx;
struct trace_malloc_data trace_data = { NULL };
int optind;
char *expr = NULL;
int interactive = 0;
int dump_memory = 0;
int trace_memory = 0;
int empty_run = 0;
int module = -1;
int load_std = 0;
int dump_unhandled_promise_rejection = 0;
size_t memory_limit = 0;
char *include_list[32];
int i, include_count = 0;
#ifdef CONFIG_BIGNUM
int load_jscalc;
#endif
size_t stack_size = 0;
LoadZipArgs(&argc, &argv);
#if IsModeDbg()
ShowCrashReports();
#endif
#ifdef CONFIG_BIGNUM
/* load jscalc runtime if invoked as 'qjscalc' */
{
const char *p, *exename;
exename = argv[0];
p = strrchr(exename, '/');
if (p)
exename = p + 1;
load_jscalc = !strcmp(exename, "qjscalc");
}
#endif
/* cannot use getopt because we want to pass the command line to
the script */
optind = 1;
while (optind < argc && *argv[optind] == '-') {
char *arg = argv[optind] + 1;
const char *longopt = "";
/* a single - is not an option, it also stops argument scanning */
if (!*arg)
break;
optind++;
if (*arg == '-') {
longopt = arg + 1;
arg += strlen(arg);
/* -- stops argument scanning */
if (!*longopt)
break;
}
for (; *arg || *longopt; longopt = "") {
char opt = *arg;
if (opt)
arg++;
if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) {
help();
continue;
}
if (opt == 'e' || !strcmp(longopt, "eval")) {
if (*arg) {
expr = arg;
break;
}
if (optind < argc) {
expr = argv[optind++];
break;
}
fprintf(stderr, "qjs: missing expression for -e\n");
exit(2);
}
if (opt == 'I' || !strcmp(longopt, "include")) {
if (optind >= argc) {
fprintf(stderr, "expecting filename");
exit(1);
}
if (include_count >= countof(include_list)) {
fprintf(stderr, "too many included files");
exit(1);
}
include_list[include_count++] = argv[optind++];
continue;
}
if (opt == 'i' || !strcmp(longopt, "interactive")) {
interactive++;
continue;
}
if (opt == 'm' || !strcmp(longopt, "module")) {
module = 1;
continue;
}
if (!strcmp(longopt, "script")) {
module = 0;
continue;
}
if (opt == 'd' || !strcmp(longopt, "dump")) {
dump_memory++;
continue;
}
if (opt == 'T' || !strcmp(longopt, "trace")) {
trace_memory++;
continue;
}
if (!strcmp(longopt, "std")) {
load_std = 1;
continue;
}
if (!strcmp(longopt, "unhandled-rejection")) {
dump_unhandled_promise_rejection = 1;
continue;
}
#ifdef CONFIG_BIGNUM
if (!strcmp(longopt, "bignum")) {
bignum_ext = 1;
continue;
}
if (!strcmp(longopt, "qjscalc")) {
load_jscalc = 1;
continue;
}
#endif
if (opt == 'q' || !strcmp(longopt, "quit")) {
empty_run++;
continue;
}
if (!strcmp(longopt, "memory-limit")) {
if (optind >= argc) {
fprintf(stderr, "expecting memory limit");
exit(1);
}
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 {
fprintf(stderr, "qjs: unknown option '--%s'\n", longopt);
}
help();
}
}
#ifdef CONFIG_BIGNUM
if (load_jscalc)
bignum_ext = 1;
#endif
if (trace_memory) {
js_trace_malloc_init(&trace_data);
rt = JS_NewRuntime2(&trace_mf, &trace_data);
} else {
rt = JS_NewRuntime();
}
if (!rt) {
fprintf(stderr, "qjs: cannot allocate JS runtime\n");
exit(2);
}
if (memory_limit != 0)
JS_SetMemoryLimit(rt, memory_limit);
if (stack_size != 0)
JS_SetMaxStackSize(rt, stack_size);
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
ctx = JS_NewCustomContext(rt);
if (!ctx) {
fprintf(stderr, "qjs: cannot allocate JS context\n");
exit(2);
}
/* loader for ES6 modules */
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
if (dump_unhandled_promise_rejection) {
JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker,
NULL);
}
if (!empty_run) {
#ifdef CONFIG_BIGNUM
if (load_jscalc) {
js_std_eval_binary(ctx, qjsc_qjscalc, qjsc_qjscalc_size, 0);
}
#endif
js_std_add_helpers(ctx, argc - optind, argv + optind);
/* make 'std' and 'os' visible to non module code */
if (load_std) {
const char *str = "import * as std from 'std';\n"
"import * as os from 'os';\n"
"globalThis.std = std;\n"
"globalThis.os = os;\n";
eval_buf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE);
}
for(i = 0; i < include_count; i++) {
if (eval_file(ctx, include_list[i], module))
goto fail;
}
if (expr) {
if (eval_buf(ctx, expr, strlen(expr), "<cmdline>", 0)) goto fail;
} else if (optind >= argc) {
/* interactive mode */
interactive = 1;
} else {
const char *filename;
filename = argv[optind];
if (eval_file(ctx, filename, module)) goto fail;
}
if (interactive) {
js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0);
}
js_std_loop(ctx);
}
if (dump_memory) {
JSMemoryUsage stats;
JS_ComputeMemoryUsage(rt, &stats);
JS_DumpMemoryUsage(stdout, &stats, rt);
}
js_std_free_handlers(rt);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
if (empty_run && dump_memory) {
clock_t t[5];
double best[5] = {0};
int i, j;
for (i = 0; i < 100; i++) {
t[0] = clock();
rt = JS_NewRuntime();
t[1] = clock();
ctx = JS_NewContext(rt);
t[2] = clock();
JS_FreeContext(ctx);
t[3] = clock();
JS_FreeRuntime(rt);
t[4] = clock();
for (j = 4; j > 0; j--) {
double ms = 1000.0 * (t[j] - t[j - 1]) / CLOCKS_PER_SEC;
if (i == 0 || best[j] > ms)
best[j] = ms;
}
}
printf("\nInstantiation times (ms): %.3f = %.3f+%.3f+%.3f+%.3f\n",
best[1] + best[2] + best[3] + best[4],
best[1], best[2], best[3], best[4]);
}
return 0;
fail:
js_std_free_handlers(rt);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return 1;
}

View file

@ -1,734 +0,0 @@
/*
* QuickJS command line compiler
*
* Copyright (c) 2018-2021 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/log/log.h"
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/x/xasprintf.h"
#include "third_party/getopt/getopt.internal.h"
#include "third_party/quickjs/cutils.h"
#include "third_party/quickjs/quickjs-libc.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
typedef struct {
char *name;
char *short_name;
int flags;
} namelist_entry_t;
typedef struct namelist_t {
namelist_entry_t *array;
int count;
int size;
} namelist_t;
typedef struct {
const char *option_name;
const char *init_name;
} FeatureEntry;
static namelist_t cname_list;
static namelist_t cmodule_list;
static namelist_t init_module_list;
static uint64_t feature_bitmap;
static FILE *outfile;
static BOOL byte_swap;
static BOOL dynamic_export;
static const char *c_ident_prefix = "qjsc_";
#define FE_ALL (-1)
static const FeatureEntry feature_list[] = {
{ "date", "Date" },
{ "eval", "Eval" },
{ "string-normalize", "StringNormalize" },
{ "regexp", "RegExp" },
{ "json", "JSON" },
{ "proxy", "Proxy" },
{ "map", "MapSet" },
{ "typedarray", "TypedArrays" },
{ "promise", "Promise" },
#define FE_MODULE_LOADER 9
{ "module-loader", NULL },
#ifdef CONFIG_BIGNUM
{ "bigint", "BigInt" },
#endif
};
void namelist_add(namelist_t *lp, const char *name, const char *short_name,
int flags)
{
namelist_entry_t *e;
if (lp->count == lp->size) {
size_t newsize = lp->size + (lp->size >> 1) + 4;
namelist_entry_t *a =
realloc(lp->array, sizeof(lp->array[0]) * newsize);
/* XXX: check for realloc failure */
lp->array = a;
lp->size = newsize;
}
e = &lp->array[lp->count++];
e->name = strdup(name);
if (short_name)
e->short_name = strdup(short_name);
else
e->short_name = NULL;
e->flags = flags;
}
void namelist_free(namelist_t *lp)
{
while (lp->count > 0) {
namelist_entry_t *e = &lp->array[--lp->count];
free(e->name);
free(e->short_name);
}
free(lp->array);
lp->array = NULL;
lp->size = 0;
}
namelist_entry_t *namelist_find(namelist_t *lp, const char *name)
{
int i;
for(i = 0; i < lp->count; i++) {
namelist_entry_t *e = &lp->array[i];
if (!strcmp(e->name, name))
return e;
}
return NULL;
}
static void get_c_name(char *buf, size_t buf_size, const char *file)
{
const char *p, *r;
size_t len, i;
int c;
char *q;
p = strrchr(file, '/');
if (!p)
p = file;
else
p++;
r = strrchr(p, '.');
if (!r)
len = strlen(p);
else
len = r - p;
pstrcpy(buf, buf_size, c_ident_prefix);
q = buf + strlen(buf);
for(i = 0; i < len; i++) {
c = p[i];
if (!((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z'))) {
c = '_';
}
if ((q - buf) < buf_size - 1)
*q++ = c;
}
*q = '\0';
}
static void dump_hex(FILE *f, const uint8_t *buf, size_t len)
{
size_t i, col;
col = 0;
for(i = 0; i < len; i++) {
fprintf(f, " 0x%02x,", buf[i]);
if (++col == 8) {
fprintf(f, "\n");
col = 0;
}
}
if (col != 0)
fprintf(f, "\n");
}
static void output_object_code(JSContext *ctx,
FILE *fo, JSValueConst obj, const char *c_name,
BOOL load_only)
{
uint8_t *out_buf;
size_t out_buf_len;
int flags;
flags = JS_WRITE_OBJ_BYTECODE;
if (byte_swap)
flags |= JS_WRITE_OBJ_BSWAP;
out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags);
if (!out_buf) {
js_std_dump_error(ctx);
exit(1);
}
namelist_add(&cname_list, c_name, NULL, load_only);
fprintf(fo, "const uint32_t %s_size = %u;\n\n",
c_name, (unsigned int)out_buf_len);
fprintf(fo, "const uint8_t %s[%u] = {\n",
c_name, (unsigned int)out_buf_len);
dump_hex(fo, out_buf, out_buf_len);
fprintf(fo, "};\n\n");
js_free(ctx, out_buf);
}
static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m)
{
/* should never be called when compiling JS code */
abort();
}
static void find_unique_cname(char *cname, size_t cname_size)
{
char *cname1;
int suffix_num;
size_t len, max_len;
assert(cname_size >= 32);
/* find a C name not matching an existing module C name by
adding a numeric suffix */
len = strlen(cname);
max_len = cname_size - 16;
if (len > max_len)
cname[max_len] = '\0';
suffix_num = 1;
cname1 = NULL;
for(;;) {
free(cname1);
cname1 = xasprintf("%s_%d", cname, suffix_num);
if (!namelist_find(&cname_list, cname1))
break;
suffix_num++;
}
pstrcpy(cname, cname_size, cname1);
free(cname1);
}
JSModuleDef *jsc_module_loader(JSContext *ctx,
const char *module_name, void *opaque)
{
JSModuleDef *m;
namelist_entry_t *e;
/* check if it is a declared C or system module */
e = namelist_find(&cmodule_list, module_name);
if (e) {
/* add in the static init module list */
namelist_add(&init_module_list, e->name, e->short_name, 0);
/* create a dummy module */
m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
} else if (has_suffix(module_name, ".so")) {
fprintf(stderr, "Warning: binary module '%s' will be dynamically loaded\n", module_name);
/* create a dummy module */
m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
/* the resulting executable will export its symbols for the
dynamic library */
dynamic_export = TRUE;
} else {
size_t buf_len;
uint8_t *buf;
JSValue func_val;
char cname[1024];
buf = js_load_file(ctx, &buf_len, module_name);
if (!buf) {
JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
module_name);
return NULL;
}
/* compile the module */
func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
js_free(ctx, buf);
if (JS_IsException(func_val))
return NULL;
get_c_name(cname, sizeof(cname), module_name);
if (namelist_find(&cname_list, cname)) {
find_unique_cname(cname, sizeof(cname));
}
output_object_code(ctx, outfile, func_val, cname, TRUE);
/* the module is already referenced, so we must free it */
m = JS_VALUE_GET_PTR(func_val);
JS_FreeValue(ctx, func_val);
}
return m;
}
static void compile_file(JSContext *ctx, FILE *fo,
const char *filename,
const char *c_name1,
int module)
{
uint8_t *buf;
char c_name[1024];
int eval_flags;
JSValue obj;
size_t buf_len;
buf = js_load_file(ctx, &buf_len, filename);
if (!buf) {
fprintf(stderr, "Could not load '%s'\n", filename);
exit(1);
}
eval_flags = JS_EVAL_FLAG_COMPILE_ONLY;
if (module < 0) {
module = (has_suffix(filename, ".mjs") ||
JS_DetectModule((const char *)buf, buf_len));
}
if (module)
eval_flags |= JS_EVAL_TYPE_MODULE;
else
eval_flags |= JS_EVAL_TYPE_GLOBAL;
obj = JS_Eval(ctx, (const char *)buf, buf_len, filename, eval_flags);
if (JS_IsException(obj)) {
js_std_dump_error(ctx);
exit(1);
}
js_free(ctx, buf);
if (c_name1) {
pstrcpy(c_name, sizeof(c_name), c_name1);
} else {
get_c_name(c_name, sizeof(c_name), filename);
}
output_object_code(ctx, fo, obj, c_name, FALSE);
JS_FreeValue(ctx, obj);
}
static const char main_c_template1[] =
"int main(int argc, char **argv)\n"
"{\n"
" JSRuntime *rt;\n"
" JSContext *ctx;\n"
" rt = JS_NewRuntime();\n"
" js_std_set_worker_new_context_func(JS_NewCustomContext);\n"
" js_std_init_handlers(rt);\n"
;
static const char main_c_template2[] =
" js_std_loop(ctx);\n"
" JS_FreeContext(ctx);\n"
" JS_FreeRuntime(rt);\n"
" return 0;\n"
"}\n";
#define PROG_NAME "qjsc"
void help(void)
{
printf("QuickJS Compiler version " CONFIG_VERSION "\n"
"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"
"-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"
"-D module_name compile a dynamically loaded module or worker\n"
"-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;
printf("-flto use link time optimization\n");
printf("-fbignum enable bignum extensions\n");
printf("-fno-[");
for(i = 0; i < countof(feature_list); i++) {
if (i != 0)
printf("|");
printf("%s", feature_list[i].option_name);
}
printf("]\n"
" disable selected language features (smaller code size)\n");
}
#endif
exit(1);
}
#if defined(CONFIG_CC) && !defined(_WIN32)
int exec_cmd(char **argv)
{
int pid, status, ret;
pid = fork();
if (pid == 0) {
execvp(argv[0], argv);
exit(1);
}
for(;;) {
ret = waitpid(pid, &status, 0);
if (ret == pid && WIFEXITED(status))
break;
}
return WEXITSTATUS(status);
}
static int output_executable(const char *out_filename, const char *cfilename,
BOOL use_lto, BOOL verbose, const char *exename)
{
const char *argv[64];
const char **arg, *bn_suffix, *lto_suffix;
char libjsname[1024];
char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p;
int ret;
/* get the directory of the executable */
pstrcpy(exe_dir, sizeof(exe_dir), exename);
p = strrchr(exe_dir, '/');
if (p) {
*p = '\0';
} else {
pstrcpy(exe_dir, sizeof(exe_dir), ".");
}
/* if 'quickjs.h' is present at the same path as the executable, we
use it as include and lib directory */
snprintf(buf, sizeof(buf), "%s/quickjs.h", exe_dir);
if (access(buf, R_OK) == 0) {
pstrcpy(inc_dir, sizeof(inc_dir), exe_dir);
pstrcpy(lib_dir, sizeof(lib_dir), exe_dir);
} else {
snprintf(inc_dir, sizeof(inc_dir), "%s/include/quickjs", CONFIG_PREFIX);
snprintf(lib_dir, sizeof(lib_dir), "%s/lib/quickjs", CONFIG_PREFIX);
}
lto_suffix = "";
bn_suffix = "";
arg = argv;
*arg++ = CONFIG_CC;
*arg++ = "-O2";
#ifdef CONFIG_LTO
if (use_lto) {
*arg++ = "-flto";
lto_suffix = ".lto";
}
#endif
/* XXX: use the executable path to find the includes files and
libraries */
*arg++ = "-D";
*arg++ = "_GNU_SOURCE";
*arg++ = "-I";
*arg++ = inc_dir;
*arg++ = "-o";
*arg++ = out_filename;
if (dynamic_export)
*arg++ = "-rdynamic";
*arg++ = cfilename;
snprintf(libjsname, sizeof(libjsname), "%s/libquickjs%s%s.a",
lib_dir, bn_suffix, lto_suffix);
*arg++ = libjsname;
*arg++ = "-lm";
*arg++ = "-ldl";
*arg++ = "-lpthread";
*arg = NULL;
if (verbose) {
for(arg = argv; *arg != NULL; arg++)
printf("%s ", *arg);
printf("\n");
}
ret = exec_cmd((char **)argv);
unlink(cfilename);
return ret;
}
#else
static int output_executable(const char *out_filename, const char *cfilename,
BOOL use_lto, BOOL verbose, const char *exename)
{
fprintf(stderr, "Executable output is not supported for this target\n");
exit(1);
return 0;
}
#endif
typedef enum {
OUTPUT_C,
OUTPUT_C_MAIN,
OUTPUT_EXECUTABLE,
} OutputTypeEnum;
int main(int argc, char **argv)
{
int c, i, verbose;
const char *out_filename, *cname;
char *cfilename = gc(malloc(1024));
FILE *fo;
JSRuntime *rt;
JSContext *ctx;
BOOL use_lto;
int module;
OutputTypeEnum output_type;
size_t stack_size;
#ifdef CONFIG_BIGNUM
BOOL bignum_ext = FALSE;
#endif
namelist_t dynamic_module_list;
#if IsModeDbg()
ShowCrashReports();
#endif
if (argc == 2 && !strcmp(argv[1], "-n")) return 0;
out_filename = NULL;
output_type = OUTPUT_EXECUTABLE;
cname = NULL;
feature_bitmap = FE_ALL;
module = -1;
byte_swap = FALSE;
verbose = 0;
use_lto = FALSE;
stack_size = 0;
bzero(&dynamic_module_list, sizeof(dynamic_module_list));
/* 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:S:D:");
if (c == -1)
break;
switch(c) {
case 'h':
help();
case 'o':
out_filename = optarg;
break;
case 'c':
output_type = OUTPUT_C;
break;
case 'e':
output_type = OUTPUT_C_MAIN;
break;
case 'N':
cname = optarg;
break;
case 'f':
{
const char *p;
p = optarg;
if (!strcmp(optarg, "lto")) {
use_lto = TRUE;
} else if (strstart(p, "no-", &p)) {
use_lto = TRUE;
for(i = 0; i < countof(feature_list); i++) {
if (!strcmp(p, feature_list[i].option_name)) {
feature_bitmap &= ~((uint64_t)1 << i);
break;
}
}
if (i == countof(feature_list))
goto bad_feature;
} else
#ifdef CONFIG_BIGNUM
if (!strcmp(optarg, "bignum")) {
bignum_ext = TRUE;
} else
#endif
{
bad_feature:
fprintf(stderr, "unsupported feature: %s\n", optarg);
exit(1);
}
}
break;
case 'm':
module = 1;
break;
case 'M':
{
char *p;
char path[1024];
char cname[1024];
pstrcpy(path, sizeof(path), optarg);
p = strchr(path, ',');
if (p) {
*p = '\0';
pstrcpy(cname, sizeof(cname), p + 1);
} else {
get_c_name(cname, sizeof(cname), path);
}
namelist_add(&cmodule_list, path, cname, 0);
}
break;
case 'D':
namelist_add(&dynamic_module_list, optarg, NULL, 0);
break;
case 'x':
byte_swap = TRUE;
break;
case 'v':
verbose++;
break;
case 'p':
c_ident_prefix = optarg;
break;
case 'S':
stack_size = (size_t)strtod(optarg, NULL);
break;
default:
break;
}
}
if (optind >= argc)
help();
if (!out_filename) {
if (output_type == OUTPUT_EXECUTABLE) {
out_filename = "a.out";
} else {
out_filename = "out.c";
}
}
if (output_type == OUTPUT_EXECUTABLE) {
snprintf(cfilename, 1024, "/tmp/out%d.c", getpid());
} else {
pstrcpy(cfilename, 1024, out_filename);
}
fo = fopen(cfilename, "w");
if (!fo) {
perror(cfilename);
exit(1);
}
outfile = fo;
rt = JS_NewRuntime();
ctx = JS_NewContext(rt);
#ifdef CONFIG_BIGNUM
if (bignum_ext) {
JS_AddIntrinsicBigFloat(ctx);
JS_AddIntrinsicBigDecimal(ctx);
JS_AddIntrinsicOperators(ctx);
JS_EnableBignumExt(ctx, TRUE);
}
#endif
/* loader for ES6 modules */
JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL);
fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n"
"\n"
);
if (output_type != OUTPUT_C) {
fprintf(fo, "#include \"quickjs-libc.h\"\n"
"\n"
);
} else {
#ifndef _COSMO_SOURCE
fprintf(fo, "#include <inttypes.h>\n"
"\n"
);
#endif
}
for(i = optind; i < argc; i++) {
const char *filename = argv[i];
compile_file(ctx, fo, filename, cname, module);
cname = NULL;
}
for(i = 0; i < dynamic_module_list.count; i++) {
if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) {
fprintf(stderr, "Could not load dynamic module '%s'\n",
dynamic_module_list.array[i].name);
exit(1);
}
}
if (output_type != OUTPUT_C) {
fprintf(fo,
"static JSContext *JS_NewCustomContext(JSRuntime *rt)\n"
"{\n"
" JSContext *ctx = JS_NewContextRaw(rt);\n"
" if (!ctx)\n"
" return NULL;\n");
/* add the basic objects */
fprintf(fo, " JS_AddIntrinsicBaseObjects(ctx);\n");
for(i = 0; i < countof(feature_list); i++) {
if ((feature_bitmap & ((uint64_t)1 << i)) &&
feature_list[i].init_name) {
fprintf(fo, " JS_AddIntrinsic%s(ctx);\n",
feature_list[i].init_name);
}
}
#ifdef CONFIG_BIGNUM
if (bignum_ext) {
fprintf(fo,
" JS_AddIntrinsicBigFloat(ctx);\n"
" JS_AddIntrinsicBigDecimal(ctx);\n"
" JS_AddIntrinsicOperators(ctx);\n"
" JS_EnableBignumExt(ctx, 1);\n");
}
#endif
/* add the precompiled modules (XXX: could modify the module
loader instead) */
for(i = 0; i < init_module_list.count; i++) {
namelist_entry_t *e = &init_module_list.array[i];
/* initialize the static C modules */
fprintf(fo,
" {\n"
" extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n"
" js_init_module_%s(ctx, \"%s\");\n"
" }\n",
e->short_name, e->short_name, e->name);
}
for(i = 0; i < cname_list.count; i++) {
namelist_entry_t *e = &cname_list.array[i];
if (e->flags) {
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n",
e->name, e->name);
}
}
fprintf(fo,
" return ctx;\n"
"}\n\n");
fputs(main_c_template1, fo);
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");
}
fprintf(fo,
" ctx = JS_NewCustomContext(rt);\n"
" js_std_add_helpers(ctx, argc, argv);\n");
for(i = 0; i < cname_list.count; i++) {
namelist_entry_t *e = &cname_list.array[i];
if (!e->flags) {
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n",
e->name, e->name);
}
}
fputs(main_c_template2, fo);
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
fclose(fo);
if (output_type == OUTPUT_EXECUTABLE) {
return output_executable(out_filename, cfilename, use_lto, verbose,
argv[0]);
}
namelist_free(&cname_list);
namelist_free(&cmodule_list);
namelist_free(&init_module_list);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,273 +0,0 @@
/*
* QuickJS atom definitions
*
* Copyright (c) 2017-2018 Fabrice Bellard
* Copyright (c) 2017-2018 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifdef DEF
/* Note: first atoms are considered as keywords in the parser */
DEF(null, "null") /* must be first */
DEF(false, "false")
DEF(true, "true")
DEF(if, "if")
DEF(else, "else")
DEF(return, "return")
DEF(var, "var")
DEF(this, "this")
DEF(delete, "delete")
DEF(void, "void")
DEF(typeof, "typeof")
DEF(new, "new")
DEF(in, "in")
DEF(instanceof, "instanceof")
DEF(do, "do")
DEF(while, "while")
DEF(for, "for")
DEF(break, "break")
DEF(continue, "continue")
DEF(switch, "switch")
DEF(case, "case")
DEF(default, "default")
DEF(throw, "throw")
DEF(try, "try")
DEF(catch, "catch")
DEF(finally, "finally")
DEF(function, "function")
DEF(debugger, "debugger")
DEF(with, "with")
/* FutureReservedWord */
DEF(class, "class")
DEF(const, "const")
DEF(enum, "enum")
DEF(export, "export")
DEF(extends, "extends")
DEF(import, "import")
DEF(super, "super")
/* FutureReservedWords when parsing strict mode code */
DEF(implements, "implements")
DEF(interface, "interface")
DEF(let, "let")
DEF(package, "package")
DEF(private, "private")
DEF(protected, "protected")
DEF(public, "public")
DEF(static, "static")
DEF(yield, "yield")
DEF(await, "await")
/* empty string */
DEF(empty_string, "")
/* identifiers */
DEF(length, "length")
DEF(fileName, "fileName")
DEF(lineNumber, "lineNumber")
DEF(message, "message")
DEF(errors, "errors")
DEF(stack, "stack")
DEF(name, "name")
DEF(toString, "toString")
DEF(toLocaleString, "toLocaleString")
DEF(valueOf, "valueOf")
DEF(eval, "eval")
DEF(prototype, "prototype")
DEF(constructor, "constructor")
DEF(configurable, "configurable")
DEF(writable, "writable")
DEF(enumerable, "enumerable")
DEF(value, "value")
DEF(get, "get")
DEF(set, "set")
DEF(of, "of")
DEF(__proto__, "__proto__")
DEF(undefined, "undefined")
DEF(number, "number")
DEF(boolean, "boolean")
DEF(string, "string")
DEF(object, "object")
DEF(symbol, "symbol")
DEF(integer, "integer")
DEF(unknown, "unknown")
DEF(arguments, "arguments")
DEF(callee, "callee")
DEF(caller, "caller")
DEF(_eval_, "<eval>")
DEF(_ret_, "<ret>")
DEF(_var_, "<var>")
DEF(_arg_var_, "<arg_var>")
DEF(_with_, "<with>")
DEF(lastIndex, "lastIndex")
DEF(target, "target")
DEF(index, "index")
DEF(input, "input")
DEF(defineProperties, "defineProperties")
DEF(apply, "apply")
DEF(join, "join")
DEF(concat, "concat")
DEF(split, "split")
DEF(construct, "construct")
DEF(getPrototypeOf, "getPrototypeOf")
DEF(setPrototypeOf, "setPrototypeOf")
DEF(isExtensible, "isExtensible")
DEF(preventExtensions, "preventExtensions")
DEF(has, "has")
DEF(deleteProperty, "deleteProperty")
DEF(defineProperty, "defineProperty")
DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor")
DEF(ownKeys, "ownKeys")
DEF(add, "add")
DEF(done, "done")
DEF(next, "next")
DEF(values, "values")
DEF(source, "source")
DEF(flags, "flags")
DEF(global, "global")
DEF(unicode, "unicode")
DEF(raw, "raw")
DEF(new_target, "new.target")
DEF(this_active_func, "this.active_func")
DEF(home_object, "<home_object>")
DEF(computed_field, "<computed_field>")
DEF(static_computed_field, "<static_computed_field>") /* must come after computed_fields */
DEF(class_fields_init, "<class_fields_init>")
DEF(brand, "<brand>")
DEF(hash_constructor, "#constructor")
DEF(as, "as")
DEF(from, "from")
DEF(meta, "meta")
DEF(_default_, "*default*")
DEF(_star_, "*")
DEF(Module, "Module")
DEF(then, "then")
DEF(resolve, "resolve")
DEF(reject, "reject")
DEF(promise, "promise")
DEF(proxy, "proxy")
DEF(revoke, "revoke")
DEF(async, "async")
DEF(exec, "exec")
DEF(groups, "groups")
DEF(status, "status")
DEF(reason, "reason")
DEF(globalThis, "globalThis")
#ifdef CONFIG_BIGNUM
DEF(bigint, "bigint")
DEF(bigfloat, "bigfloat")
DEF(bigdecimal, "bigdecimal")
DEF(roundingMode, "roundingMode")
DEF(maximumSignificantDigits, "maximumSignificantDigits")
DEF(maximumFractionDigits, "maximumFractionDigits")
#endif
#ifdef CONFIG_ATOMICS
DEF(not_equal, "not-equal")
DEF(timed_out, "timed-out")
DEF(ok, "ok")
#endif
DEF(toJSON, "toJSON")
/* class names */
DEF(Object, "Object")
DEF(Array, "Array")
DEF(Error, "Error")
DEF(Number, "Number")
DEF(String, "String")
DEF(Boolean, "Boolean")
DEF(Symbol, "Symbol")
DEF(Arguments, "Arguments")
DEF(Math, "Math")
DEF(JSON, "JSON")
DEF(Date, "Date")
DEF(Function, "Function")
DEF(GeneratorFunction, "GeneratorFunction")
DEF(ForInIterator, "ForInIterator")
DEF(RegExp, "RegExp")
DEF(ArrayBuffer, "ArrayBuffer")
DEF(SharedArrayBuffer, "SharedArrayBuffer")
/* must keep same order as class IDs for typed arrays */
DEF(Uint8ClampedArray, "Uint8ClampedArray")
DEF(Int8Array, "Int8Array")
DEF(Uint8Array, "Uint8Array")
DEF(Int16Array, "Int16Array")
DEF(Uint16Array, "Uint16Array")
DEF(Int32Array, "Int32Array")
DEF(Uint32Array, "Uint32Array")
#ifdef CONFIG_BIGNUM
DEF(BigInt64Array, "BigInt64Array")
DEF(BigUint64Array, "BigUint64Array")
#endif
DEF(Float32Array, "Float32Array")
DEF(Float64Array, "Float64Array")
DEF(DataView, "DataView")
#ifdef CONFIG_BIGNUM
DEF(BigInt, "BigInt")
DEF(BigFloat, "BigFloat")
DEF(BigFloatEnv, "BigFloatEnv")
DEF(BigDecimal, "BigDecimal")
DEF(OperatorSet, "OperatorSet")
DEF(Operators, "Operators")
#endif
DEF(Map, "Map")
DEF(Set, "Set") /* Map + 1 */
DEF(WeakMap, "WeakMap") /* Map + 2 */
DEF(WeakSet, "WeakSet") /* Map + 3 */
DEF(Map_Iterator, "Map Iterator")
DEF(Set_Iterator, "Set Iterator")
DEF(Array_Iterator, "Array Iterator")
DEF(String_Iterator, "String Iterator")
DEF(RegExp_String_Iterator, "RegExp String Iterator")
DEF(Generator, "Generator")
DEF(Proxy, "Proxy")
DEF(Promise, "Promise")
DEF(PromiseResolveFunction, "PromiseResolveFunction")
DEF(PromiseRejectFunction, "PromiseRejectFunction")
DEF(AsyncFunction, "AsyncFunction")
DEF(AsyncFunctionResolve, "AsyncFunctionResolve")
DEF(AsyncFunctionReject, "AsyncFunctionReject")
DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction")
DEF(AsyncGenerator, "AsyncGenerator")
DEF(EvalError, "EvalError")
DEF(RangeError, "RangeError")
DEF(ReferenceError, "ReferenceError")
DEF(SyntaxError, "SyntaxError")
DEF(TypeError, "TypeError")
DEF(URIError, "URIError")
DEF(InternalError, "InternalError")
/* private symbols */
DEF(Private_brand, "<brand>")
/* symbols */
DEF(Symbol_toPrimitive, "Symbol.toPrimitive")
DEF(Symbol_iterator, "Symbol.iterator")
DEF(Symbol_match, "Symbol.match")
DEF(Symbol_matchAll, "Symbol.matchAll")
DEF(Symbol_replace, "Symbol.replace")
DEF(Symbol_search, "Symbol.search")
DEF(Symbol_split, "Symbol.split")
DEF(Symbol_toStringTag, "Symbol.toStringTag")
DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable")
DEF(Symbol_hasInstance, "Symbol.hasInstance")
DEF(Symbol_species, "Symbol.species")
DEF(Symbol_unscopables, "Symbol.unscopables")
DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
#ifdef CONFIG_BIGNUM
DEF(Symbol_operatorSet, "Symbol.operatorSet")
#endif
#endif /* DEF */

File diff suppressed because it is too large Load diff

View file

@ -1,27 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBC_H_
#define COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBC_H_
#include "third_party/quickjs/quickjs.h"
COSMOPOLITAN_C_START_
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);
int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
JS_BOOL use_realpath, JS_BOOL is_main);
JSModuleDef *js_module_loader(JSContext *ctx,
const char *module_name, void *opaque);
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
int flags);
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
JSValueConst reason,
JS_BOOL is_handled, void *opaque);
void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
/* clang-format on */
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_THIRD_PARTY_QUICKJS_LIBC_H_ */

View file

@ -1,366 +0,0 @@
/*
* QuickJS opcode definitions
*
* Copyright (c) 2017-2018 Fabrice Bellard
* Copyright (c) 2017-2018 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifdef FMT
FMT(none)
FMT(none_int)
FMT(none_loc)
FMT(none_arg)
FMT(none_var_ref)
FMT(u8)
FMT(i8)
FMT(loc8)
FMT(const8)
FMT(label8)
FMT(u16)
FMT(i16)
FMT(label16)
FMT(npop)
FMT(npopx)
FMT(npop_u16)
FMT(loc)
FMT(arg)
FMT(var_ref)
FMT(u32)
FMT(i32)
FMT(const)
FMT(label)
FMT(atom)
FMT(atom_u8)
FMT(atom_u16)
FMT(atom_label_u8)
FMT(atom_label_u16)
FMT(label_u16)
#undef FMT
#endif /* FMT */
#ifdef DEF
#ifndef def
#define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f)
#endif
DEF(invalid, 1, 0, 0, none) /* never emitted */
/* push values */
DEF( push_i32, 5, 0, 1, i32)
DEF( push_const, 5, 0, 1, const)
DEF( fclosure, 5, 0, 1, const) /* must follow push_const */
DEF(push_atom_value, 5, 0, 1, atom)
DEF( private_symbol, 5, 0, 1, atom)
DEF( undefined, 1, 0, 1, none)
DEF( null, 1, 0, 1, none)
DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */
DEF( push_false, 1, 0, 1, none)
DEF( push_true, 1, 0, 1, none)
DEF( object, 1, 0, 1, none)
DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */
DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */
DEF( drop, 1, 1, 0, none) /* a -> */
DEF( nip, 1, 2, 1, none) /* a b -> b */
DEF( nip1, 1, 3, 2, none) /* a b c -> b c */
DEF( dup, 1, 1, 2, none) /* a -> a a */
DEF( dup1, 1, 2, 3, none) /* a b -> a a b */
DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */
DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */
DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */
DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */
DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */
DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */
DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */
DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */
DEF( swap, 1, 2, 2, none) /* a b -> b a */
DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */
DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */
DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */
DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */
DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */
DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */
DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */
DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */
DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */
DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */
DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */
DEF( apply, 3, 3, 1, u16)
DEF( return, 1, 1, 0, none)
DEF( return_undef, 1, 0, 0, none)
DEF(check_ctor_return, 1, 1, 2, none)
DEF( check_ctor, 1, 0, 0, none)
DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
DEF( return_async, 1, 1, 0, none)
DEF( throw, 1, 1, 0, none)
DEF( throw_error, 6, 0, 0, atom_u8)
DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
bytecode string */
DEF( get_super, 1, 1, 1, none)
DEF( import, 1, 1, 1, none) /* dynamic module import */
DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */
DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */
DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */
DEF( put_var, 5, 1, 0, atom) /* must come after get_var */
DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */
DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */
DEF( get_ref_value, 1, 2, 3, none)
DEF( put_ref_value, 1, 3, 0, none)
DEF( define_var, 6, 0, 0, atom_u8)
DEF(check_define_var, 6, 0, 0, atom_u8)
DEF( define_func, 6, 1, 0, atom_u8)
DEF( get_field, 5, 1, 1, atom)
DEF( get_field2, 5, 1, 2, atom)
DEF( put_field, 5, 2, 0, atom)
DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */
DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */
DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */
DEF( get_array_el, 1, 2, 1, none)
DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */
DEF( put_array_el, 1, 3, 0, none)
DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */
DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */
DEF( define_field, 5, 2, 1, atom)
DEF( set_name, 5, 1, 1, atom)
DEF(set_name_computed, 1, 2, 2, none)
DEF( set_proto, 1, 2, 1, none)
DEF(set_home_object, 1, 2, 2, none)
DEF(define_array_el, 1, 3, 2, none)
DEF( append, 1, 3, 2, none) /* append enumerated object, update length */
DEF(copy_data_properties, 2, 3, 3, u8)
DEF( define_method, 6, 2, 1, atom_u8)
DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */
DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */
DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */
DEF( get_loc, 3, 0, 1, loc)
DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */
DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */
DEF( get_arg, 3, 0, 1, arg)
DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */
DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */
DEF( get_var_ref, 3, 0, 1, var_ref)
DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */
DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */
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_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)
DEF( close_loc, 3, 0, 0, loc)
DEF( if_false, 5, 1, 0, label)
DEF( if_true, 5, 1, 0, label) /* must come after if_false */
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( to_object, 1, 1, 1, none)
//DEF( to_string, 1, 1, 1, none)
DEF( to_propkey, 1, 1, 1, none)
DEF( to_propkey2, 1, 2, 2, none)
DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */
DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8)
DEF( make_loc_ref, 7, 0, 2, atom_u16)
DEF( make_arg_ref, 7, 0, 2, atom_u16)
DEF(make_var_ref_ref, 7, 0, 2, atom_u16)
DEF( make_var_ref, 5, 0, 2, atom)
DEF( for_in_start, 1, 1, 1, none)
DEF( for_of_start, 1, 1, 3, none)
DEF(for_await_of_start, 1, 1, 3, none)
DEF( for_in_next, 1, 1, 3, none)
DEF( for_of_next, 2, 3, 5, u8)
DEF(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)
DEF( yield, 1, 1, 2, none)
DEF( yield_star, 1, 1, 2, none)
DEF(async_yield_star, 1, 1, 2, none)
DEF( await, 1, 1, 1, none)
/* arithmetic/logic operations */
DEF( neg, 1, 1, 1, none)
DEF( plus, 1, 1, 1, none)
DEF( dec, 1, 1, 1, none)
DEF( inc, 1, 1, 1, none)
DEF( post_dec, 1, 1, 2, none)
DEF( post_inc, 1, 1, 2, none)
DEF( dec_loc, 2, 0, 0, loc8)
DEF( inc_loc, 2, 0, 0, loc8)
DEF( add_loc, 2, 1, 0, loc8)
DEF( not, 1, 1, 1, none)
DEF( lnot, 1, 1, 1, none)
DEF( typeof, 1, 1, 1, none)
DEF( delete, 1, 2, 1, none)
DEF( delete_var, 5, 0, 1, atom)
DEF( mul, 1, 2, 1, none)
DEF( div, 1, 2, 1, none)
DEF( mod, 1, 2, 1, none)
DEF( add, 1, 2, 1, none)
DEF( sub, 1, 2, 1, none)
DEF( pow, 1, 2, 1, none)
DEF( shl, 1, 2, 1, none)
DEF( sar, 1, 2, 1, none)
DEF( shr, 1, 2, 1, none)
DEF( lt, 1, 2, 1, none)
DEF( lte, 1, 2, 1, none)
DEF( gt, 1, 2, 1, none)
DEF( gte, 1, 2, 1, none)
DEF( instanceof, 1, 2, 1, none)
DEF( in, 1, 2, 1, none)
DEF( eq, 1, 2, 1, none)
DEF( neq, 1, 2, 1, none)
DEF( strict_eq, 1, 2, 1, none)
DEF( strict_neq, 1, 2, 1, none)
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)
#ifdef CONFIG_BIGNUM
DEF( mul_pow10, 1, 2, 1, none)
DEF( math_mod, 1, 2, 1, none)
#endif
/* must be the last non short and non temporary opcode */
DEF( nop, 1, 0, 0, none)
/* temporary opcodes: never emitted in the final bytecode */
def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */
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 */
def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
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_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, 1, 1, atom_u16) /* obj value ->, 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 */
#if SHORT_OPCODES
DEF( push_minus1, 1, 0, 1, none_int)
DEF( push_0, 1, 0, 1, none_int)
DEF( push_1, 1, 0, 1, none_int)
DEF( push_2, 1, 0, 1, none_int)
DEF( push_3, 1, 0, 1, none_int)
DEF( push_4, 1, 0, 1, none_int)
DEF( push_5, 1, 0, 1, none_int)
DEF( push_6, 1, 0, 1, none_int)
DEF( push_7, 1, 0, 1, none_int)
DEF( push_i8, 2, 0, 1, i8)
DEF( push_i16, 3, 0, 1, i16)
DEF( push_const8, 2, 0, 1, const8)
DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */
DEF(push_empty_string, 1, 0, 1, none)
DEF( get_loc8, 2, 0, 1, loc8)
DEF( put_loc8, 2, 1, 0, loc8)
DEF( set_loc8, 2, 1, 1, loc8)
DEF( get_loc0, 1, 0, 1, none_loc)
DEF( get_loc1, 1, 0, 1, none_loc)
DEF( get_loc2, 1, 0, 1, none_loc)
DEF( get_loc3, 1, 0, 1, none_loc)
DEF( put_loc0, 1, 1, 0, none_loc)
DEF( put_loc1, 1, 1, 0, none_loc)
DEF( put_loc2, 1, 1, 0, none_loc)
DEF( put_loc3, 1, 1, 0, none_loc)
DEF( set_loc0, 1, 1, 1, none_loc)
DEF( set_loc1, 1, 1, 1, none_loc)
DEF( set_loc2, 1, 1, 1, none_loc)
DEF( set_loc3, 1, 1, 1, none_loc)
DEF( get_arg0, 1, 0, 1, none_arg)
DEF( get_arg1, 1, 0, 1, none_arg)
DEF( get_arg2, 1, 0, 1, none_arg)
DEF( get_arg3, 1, 0, 1, none_arg)
DEF( put_arg0, 1, 1, 0, none_arg)
DEF( put_arg1, 1, 1, 0, none_arg)
DEF( put_arg2, 1, 1, 0, none_arg)
DEF( put_arg3, 1, 1, 0, none_arg)
DEF( set_arg0, 1, 1, 1, none_arg)
DEF( set_arg1, 1, 1, 1, none_arg)
DEF( set_arg2, 1, 1, 1, none_arg)
DEF( set_arg3, 1, 1, 1, none_arg)
DEF( get_var_ref0, 1, 0, 1, none_var_ref)
DEF( get_var_ref1, 1, 0, 1, none_var_ref)
DEF( get_var_ref2, 1, 0, 1, none_var_ref)
DEF( get_var_ref3, 1, 0, 1, none_var_ref)
DEF( put_var_ref0, 1, 1, 0, none_var_ref)
DEF( put_var_ref1, 1, 1, 0, none_var_ref)
DEF( put_var_ref2, 1, 1, 0, none_var_ref)
DEF( put_var_ref3, 1, 1, 0, none_var_ref)
DEF( set_var_ref0, 1, 1, 1, none_var_ref)
DEF( set_var_ref1, 1, 1, 1, none_var_ref)
DEF( set_var_ref2, 1, 1, 1, none_var_ref)
DEF( set_var_ref3, 1, 1, 1, none_var_ref)
DEF( get_length, 1, 1, 1, none)
DEF( if_false8, 2, 1, 0, label8)
DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */
DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */
DEF( goto16, 3, 0, 0, label16)
DEF( call0, 1, 1, 1, npopx)
DEF( call1, 1, 1, 1, npopx)
DEF( call2, 1, 1, 1, npopx)
DEF( call3, 1, 1, 1, npopx)
DEF( is_undefined, 1, 1, 1, none)
DEF( is_null, 1, 1, 1, none)
DEF(typeof_is_undefined, 1, 1, 1, none)
DEF( typeof_is_function, 1, 1, 1, none)
#endif
#undef DEF
#undef def
#endif /* DEF */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1 +0,0 @@
The main documentation is in doc/quickjs.pdf or doc/quickjs.html.

View file

@ -1,196 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);
}
static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValueConst func, array_arg, new_target;
JSValue *tab, ret;
uint32_t len;
func = argv[0];
array_arg = argv[1];
if (argc > 2) {
new_target = argv[2];
if (!JS_IsConstructor(ctx, new_target))
return JS_ThrowTypeError(ctx, "not a constructor");
} else {
new_target = func;
}
tab = build_arg_list(ctx, &len, array_arg);
if (!tab)
return JS_EXCEPTION;
ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab);
free_arg_list(ctx, tab, len);
return ret;
}
static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValueConst obj;
JSAtom atom;
int ret;
obj = argv[0];
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
return JS_ThrowTypeErrorNotAnObject(ctx);
atom = JS_ValueToAtom(ctx, argv[1]);
if (UNLIKELY(atom == JS_ATOM_NULL))
return JS_EXCEPTION;
ret = JS_DeleteProperty(ctx, obj, atom, 0);
JS_FreeAtom(ctx, atom);
if (ret < 0)
return JS_EXCEPTION;
else
return JS_NewBool(ctx, ret);
}
static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValueConst obj, prop, receiver;
JSAtom atom;
JSValue ret;
obj = argv[0];
prop = argv[1];
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
return JS_ThrowTypeErrorNotAnObject(ctx);
if (argc > 2)
receiver = argv[2];
else
receiver = obj;
atom = JS_ValueToAtom(ctx, prop);
if (UNLIKELY(atom == JS_ATOM_NULL))
return JS_EXCEPTION;
ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE);
JS_FreeAtom(ctx, atom);
return ret;
}
static JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValueConst obj, prop;
JSAtom atom;
int ret;
obj = argv[0];
prop = argv[1];
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
return JS_ThrowTypeErrorNotAnObject(ctx);
atom = JS_ValueToAtom(ctx, prop);
if (UNLIKELY(atom == JS_ATOM_NULL))
return JS_EXCEPTION;
ret = JS_HasProperty(ctx, obj, atom);
JS_FreeAtom(ctx, atom);
if (ret < 0)
return JS_EXCEPTION;
else
return JS_NewBool(ctx, ret);
}
static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSValueConst obj, prop, val, receiver;
int ret;
JSAtom atom;
obj = argv[0];
prop = argv[1];
val = argv[2];
if (argc > 3)
receiver = argv[3];
else
receiver = obj;
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
return JS_ThrowTypeErrorNotAnObject(ctx);
atom = JS_ValueToAtom(ctx, prop);
if (UNLIKELY(atom == JS_ATOM_NULL))
return JS_EXCEPTION;
ret = JS_SetPropertyGeneric(ctx, obj, atom,
JS_DupValue(ctx, val), receiver, 0);
JS_FreeAtom(ctx, atom);
if (ret < 0)
return JS_EXCEPTION;
else
return JS_NewBool(ctx, ret);
}
static JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
int ret;
ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], FALSE);
if (ret < 0)
return JS_EXCEPTION;
else
return JS_NewBool(ctx, ret);
}
static JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
return JS_ThrowTypeErrorNotAnObject(ctx);
return JS_GetOwnPropertyNames2(ctx, argv[0],
JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK,
JS_ITERATOR_KIND_KEY);
}
static const JSCFunctionListEntry js_reflect_funcs[] = {
JS_CFUNC_DEF("apply", 3, js_reflect_apply ),
JS_CFUNC_DEF("construct", 2, js_reflect_construct ),
JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 1 ),
JS_CFUNC_DEF("deleteProperty", 2, js_reflect_deleteProperty ),
JS_CFUNC_DEF("get", 2, js_reflect_get ),
JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 1 ),
JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 1 ),
JS_CFUNC_DEF("has", 2, js_reflect_has ),
JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 1 ),
JS_CFUNC_DEF("ownKeys", 1, js_reflect_ownKeys ),
JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 1 ),
JS_CFUNC_DEF("set", 3, js_reflect_set ),
JS_CFUNC_DEF("setPrototypeOf", 2, js_reflect_setPrototypeOf ),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Reflect", JS_PROP_CONFIGURABLE ),
};
static const JSCFunctionListEntry js_reflect_obj[] = {
JS_OBJECT_DEF("Reflect", js_reflect_funcs, countof(js_reflect_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
};
void JS_AddIntrinsicReflect(JSContext *ctx) {
JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_reflect_obj, countof(js_reflect_obj));
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,449 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/str/str.h"
#include "third_party/quickjs/internal.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
int init_shape_hash(JSRuntime *rt)
{
rt->shape_hash_bits = 4; /* 16 shapes */
rt->shape_hash_size = 1 << rt->shape_hash_bits;
rt->shape_hash_count = 0;
rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
rt->shape_hash_size);
if (!rt->shape_hash)
return -1;
return 0;
}
/* same magic hash multiplier as the Linux kernel */
static uint32_t shape_hash(uint32_t h, uint32_t val)
{
return (h + val) * 0x9e370001;
}
/* truncate the shape hash to 'hash_bits' bits */
static uint32_t get_shape_hash(uint32_t h, int hash_bits)
{
return h >> (32 - hash_bits);
}
static uint32_t shape_initial_hash(JSObject *proto)
{
uint32_t h;
h = shape_hash(1, (uintptr_t)proto);
if (sizeof(proto) > 4)
h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32);
return h;
}
static int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits)
{
int new_shape_hash_size, i;
uint32_t h;
JSShape **new_shape_hash, *sh, *sh_next;
new_shape_hash_size = 1 << new_shape_hash_bits;
new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
new_shape_hash_size);
if (!new_shape_hash)
return -1;
for(i = 0; i < rt->shape_hash_size; i++) {
for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) {
sh_next = sh->shape_hash_next;
h = get_shape_hash(sh->hash, new_shape_hash_bits);
sh->shape_hash_next = new_shape_hash[h];
new_shape_hash[h] = sh;
}
}
js_free_rt(rt, rt->shape_hash);
rt->shape_hash_bits = new_shape_hash_bits;
rt->shape_hash_size = new_shape_hash_size;
rt->shape_hash = new_shape_hash;
return 0;
}
void js_shape_hash_link(JSRuntime *rt, JSShape *sh)
{
uint32_t h;
h = get_shape_hash(sh->hash, rt->shape_hash_bits);
sh->shape_hash_next = rt->shape_hash[h];
rt->shape_hash[h] = sh;
rt->shape_hash_count++;
}
void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh)
{
uint32_t h;
JSShape **psh;
h = get_shape_hash(sh->hash, rt->shape_hash_bits);
psh = &rt->shape_hash[h];
while (*psh != sh)
psh = &(*psh)->shape_hash_next;
*psh = sh->shape_hash_next;
rt->shape_hash_count--;
}
/* create a new empty shape with prototype 'proto' */
JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, int hash_size, int prop_size)
{
JSRuntime *rt = ctx->rt;
void *sh_alloc;
JSShape *sh;
/* resize the shape hash table if necessary */
if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) {
resize_shape_hash(rt, rt->shape_hash_bits + 1);
}
sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size));
if (!sh_alloc)
return NULL;
sh = get_shape_from_alloc(sh_alloc, hash_size);
sh->header.ref_count = 1;
add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
if (proto)
JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto));
sh->proto = proto;
bzero(prop_hash_end(sh) - hash_size, sizeof(prop_hash_end(sh)[0]) *
hash_size);
sh->prop_hash_mask = hash_size - 1;
sh->prop_size = prop_size;
sh->prop_count = 0;
sh->deleted_prop_count = 0;
/* insert in the hash table */
sh->hash = shape_initial_hash(proto);
sh->is_hashed = TRUE;
sh->has_small_array_index = FALSE;
js_shape_hash_link(ctx->rt, sh);
return sh;
}
JSShape *js_new_shape(JSContext *ctx, JSObject *proto)
{
return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE,
JS_PROP_INITIAL_SIZE);
}
/* The shape is cloned. The new shape is not inserted in the shape
hash table */
JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1)
{
JSShape *sh;
void *sh_alloc, *sh_alloc1;
size_t size;
JSShapeProperty *pr;
uint32_t i, hash_size;
hash_size = sh1->prop_hash_mask + 1;
size = get_shape_size(hash_size, sh1->prop_size);
sh_alloc = js_malloc(ctx, size);
if (!sh_alloc)
return NULL;
sh_alloc1 = get_alloc_from_shape(sh1);
memcpy(sh_alloc, sh_alloc1, size);
sh = get_shape_from_alloc(sh_alloc, hash_size);
sh->header.ref_count = 1;
add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
sh->is_hashed = FALSE;
if (sh->proto) {
JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
}
for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
JS_DupAtom(ctx, pr->atom);
}
return sh;
}
JSShape *js_dup_shape(JSShape *sh)
{
sh->header.ref_count++;
return sh;
}
static void js_free_shape0(JSRuntime *rt, JSShape *sh)
{
uint32_t i;
JSShapeProperty *pr;
assert(sh->header.ref_count == 0);
if (sh->is_hashed)
js_shape_hash_unlink(rt, sh);
if (sh->proto != NULL) {
JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
}
pr = get_shape_prop(sh);
for(i = 0; i < sh->prop_count; i++) {
JS_FreeAtomRT(rt, pr->atom);
pr++;
}
remove_gc_object(&sh->header);
js_free_rt(rt, get_alloc_from_shape(sh));
}
void js_free_shape(JSRuntime *rt, JSShape *sh)
{
if (UNLIKELY(--sh->header.ref_count <= 0)) {
js_free_shape0(rt, sh);
}
}
int add_shape_property(JSContext *ctx, JSShape **psh,
JSObject *p, JSAtom atom, int prop_flags)
{
JSRuntime *rt = ctx->rt;
JSShape *sh = *psh;
JSShapeProperty *pr, *prop;
uint32_t hash_mask, new_shape_hash = 0;
intptr_t h;
/* update the shape hash */
if (sh->is_hashed) {
js_shape_hash_unlink(rt, sh);
new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags);
}
if (UNLIKELY(sh->prop_count >= sh->prop_size)) {
if (resize_properties(ctx, psh, p, sh->prop_count + 1)) {
/* in case of error, reinsert in the hash table.
sh is still valid if resize_properties() failed */
if (sh->is_hashed)
js_shape_hash_link(rt, sh);
return -1;
}
sh = *psh;
}
if (sh->is_hashed) {
sh->hash = new_shape_hash;
js_shape_hash_link(rt, sh);
}
/* Initialize the new shape property.
The object property at p->prop[sh->prop_count] is uninitialized */
prop = get_shape_prop(sh);
pr = &prop[sh->prop_count++];
pr->atom = JS_DupAtom(ctx, atom);
pr->flags = prop_flags;
sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom);
/* add in hash table */
hash_mask = sh->prop_hash_mask;
h = atom & hash_mask;
pr->hash_next = prop_hash_end(sh)[-h - 1];
prop_hash_end(sh)[-h - 1] = sh->prop_count;
return 0;
}
/* find a hashed empty shape matching the prototype. Return NULL if
not found */
JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto)
{
JSShape *sh1;
uint32_t h, h1;
h = shape_initial_hash(proto);
h1 = get_shape_hash(h, rt->shape_hash_bits);
for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
if (sh1->hash == h &&
sh1->proto == proto &&
sh1->prop_count == 0) {
return sh1;
}
}
return NULL;
}
/* find a hashed shape matching sh + (prop, prop_flags). Return NULL if
not found */
JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh, JSAtom atom, int prop_flags)
{
JSShape *sh1;
uint32_t h, h1, i, n;
h = sh->hash;
h = shape_hash(h, atom);
h = shape_hash(h, prop_flags);
h1 = get_shape_hash(h, rt->shape_hash_bits);
for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
/* we test the hash first so that the rest is done only if the
shapes really match */
if (sh1->hash == h &&
sh1->proto == sh->proto &&
sh1->prop_count == ((n = sh->prop_count) + 1)) {
for(i = 0; i < n; i++) {
if (UNLIKELY(sh1->prop[i].atom != sh->prop[i].atom) ||
UNLIKELY(sh1->prop[i].flags != sh->prop[i].flags))
goto next;
}
if (UNLIKELY(sh1->prop[n].atom != atom) ||
UNLIKELY(sh1->prop[n].flags != prop_flags))
goto next;
return sh1;
}
next: ;
}
return NULL;
}
static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
{
char atom_buf[ATOM_GET_STR_BUF_SIZE];
int j;
/* XXX: should output readable class prototype */
printf("%5d %3d%c %14p %5d %5d", i,
sh->header.ref_count, " *"[sh->is_hashed],
(void *)sh->proto, sh->prop_size, sh->prop_count);
for(j = 0; j < sh->prop_count; j++) {
printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf),
sh->prop[j].atom));
}
printf("\n");
}
static __maybe_unused void JS_DumpShapes(JSRuntime *rt)
{
int i;
JSShape *sh;
struct list_head *el;
JSObject *p;
JSGCObjectHeader *gp;
printf("JSShapes: {\n");
printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS");
for(i = 0; i < rt->shape_hash_size; i++) {
for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
JS_DumpShape(rt, i, sh);
assert(sh->is_hashed);
}
}
/* dump non-hashed shapes */
list_for_each(el, &rt->gc_obj_list) {
gp = list_entry(el, JSGCObjectHeader, link);
if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
p = (JSObject *)gp;
if (!p->shape->is_hashed) {
JS_DumpShape(rt, -1, p->shape);
}
}
}
printf("}\n");
}
JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id)
{
JSObject *p;
js_trigger_gc(ctx->rt, sizeof(JSObject));
p = js_malloc(ctx, sizeof(JSObject));
if (UNLIKELY(!p))
goto fail;
p->class_id = class_id;
p->extensible = TRUE;
p->free_mark = 0;
p->is_exotic = 0;
p->fast_array = 0;
p->is_constructor = 0;
p->is_uncatchable_error = 0;
p->tmp_mark = 0;
p->is_HTMLDDA = 0;
p->first_weak_ref = NULL;
p->u.opaque = NULL;
p->shape = sh;
p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size);
if (UNLIKELY(!p->prop)) {
js_free(ctx, p);
fail:
js_free_shape(ctx->rt, sh);
return JS_EXCEPTION;
}
switch(class_id) {
case JS_CLASS_OBJECT:
break;
case JS_CLASS_ARRAY:
{
JSProperty *pr;
p->is_exotic = 1;
p->fast_array = 1;
p->u.array.u.values = NULL;
p->u.array.count = 0;
p->u.array.u1.size = 0;
/* the length property is always the first one */
if (LIKELY(sh == ctx->array_shape)) {
pr = &p->prop[0];
} else {
/* only used for the first array */
/* cannot fail */
pr = add_property(ctx, p, JS_ATOM_length,
JS_PROP_WRITABLE | JS_PROP_LENGTH);
}
pr->u.value = JS_NewInt32(ctx, 0);
}
break;
case JS_CLASS_C_FUNCTION:
p->prop[0].u.value = JS_UNDEFINED;
break;
case JS_CLASS_ARGUMENTS:
case JS_CLASS_UINT8C_ARRAY:
case JS_CLASS_INT8_ARRAY:
case JS_CLASS_UINT8_ARRAY:
case JS_CLASS_INT16_ARRAY:
case JS_CLASS_UINT16_ARRAY:
case JS_CLASS_INT32_ARRAY:
case JS_CLASS_UINT32_ARRAY:
#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
case JS_CLASS_BIG_UINT64_ARRAY:
#endif
case JS_CLASS_FLOAT32_ARRAY:
case JS_CLASS_FLOAT64_ARRAY:
p->is_exotic = 1;
p->fast_array = 1;
p->u.array.u.ptr = NULL;
p->u.array.count = 0;
break;
case JS_CLASS_DATAVIEW:
p->u.array.u.ptr = NULL;
p->u.array.count = 0;
break;
case JS_CLASS_NUMBER:
case JS_CLASS_STRING:
case JS_CLASS_BOOLEAN:
case JS_CLASS_SYMBOL:
case JS_CLASS_DATE:
#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT:
case JS_CLASS_BIG_FLOAT:
case JS_CLASS_BIG_DECIMAL:
#endif
p->u.object_data = JS_UNDEFINED;
goto set_exotic;
case JS_CLASS_REGEXP:
p->u.regexp.pattern = NULL;
p->u.regexp.bytecode = NULL;
goto set_exotic;
default:
set_exotic:
if (ctx->rt->class_array[class_id].exotic) {
p->is_exotic = 1;
}
break;
}
p->header.ref_count = 1;
add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT);
return JS_MKPTR(JS_TAG_OBJECT, p);
}

File diff suppressed because it is too large Load diff

View file

@ -1,331 +0,0 @@
/*
* QuickJS Javascript Engine
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libc/str/str.h"
#include "third_party/quickjs/internal.h"
#include "third_party/quickjs/libregexp.h"
#include "third_party/quickjs/quickjs.h"
asm(".ident\t\"\\n\\n\
QuickJS (MIT License)\\n\
Copyright (c) 2017-2021 Fabrice Bellard\\n\
Copyright (c) 2017-2021 Charlie Gordon\"");
asm(".include \"libc/disclaimer.inc\"");
/* It is valid to call string_buffer_end() and all string_buffer functions even
if string_buffer_init() or another string_buffer function returns an error.
If the error_status is set, string_buffer_end() returns JS_EXCEPTION.
*/
int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size, int is_wide)
{
s->ctx = ctx;
s->size = size;
s->len = 0;
s->is_wide_char = is_wide;
s->error_status = 0;
s->str = js_alloc_string(ctx, size, is_wide);
if (UNLIKELY(!s->str)) {
s->size = 0;
return s->error_status = -1;
}
#ifdef DUMP_LEAKS
/* the StringBuffer may reallocate the JSString, only link it at the end */
list_del(&s->str->link);
#endif
return 0;
}
int string_buffer_init(JSContext *ctx, StringBuffer *s, int size)
{
return string_buffer_init2(ctx, s, size, 0);
}
void string_buffer_free(StringBuffer *s)
{
js_free(s->ctx, s->str);
s->str = NULL;
}
int string_buffer_set_error(StringBuffer *s)
{
js_free(s->ctx, s->str);
s->str = NULL;
s->size = 0;
s->len = 0;
return s->error_status = -1;
}
int string_buffer_widen(StringBuffer *s, int size)
{
JSString *str;
size_t slack;
int i;
if (s->error_status)
return -1;
str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack);
if (!str)
return string_buffer_set_error(s);
size += slack >> 1;
for(i = s->len; i-- > 0;) {
str->u.str16[i] = str->u.str8[i];
}
s->is_wide_char = 1;
s->size = size;
s->str = str;
return 0;
}
int string_buffer_realloc(StringBuffer *s, int new_len, int c)
{
JSString *new_str;
int new_size;
size_t new_size_bytes, slack;
if (s->error_status)
return -1;
if (new_len > JS_STRING_LEN_MAX) {
JS_ThrowInternalError(s->ctx, "string too long");
return string_buffer_set_error(s);
}
new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX);
if (!s->is_wide_char && c >= 0x100) {
return string_buffer_widen(s, new_size);
}
new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char;
new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack);
if (!new_str)
return string_buffer_set_error(s);
new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX);
s->size = new_size;
s->str = new_str;
return 0;
}
int string_buffer_putc_slow(StringBuffer *s, uint32_t c)
{
if (UNLIKELY(s->len >= s->size)) {
if (string_buffer_realloc(s, s->len + 1, c))
return -1;
}
if (s->is_wide_char) {
s->str->u.str16[s->len++] = c;
} else if (c < 0x100) {
s->str->u.str8[s->len++] = c;
} else {
if (string_buffer_widen(s, s->size))
return -1;
s->str->u.str16[s->len++] = c;
}
return 0;
}
/* 0 <= c <= 0xff */
int string_buffer_putc8(StringBuffer *s, uint32_t c)
{
if (UNLIKELY(s->len >= s->size)) {
if (string_buffer_realloc(s, s->len + 1, c))
return -1;
}
if (s->is_wide_char) {
s->str->u.str16[s->len++] = c;
} else {
s->str->u.str8[s->len++] = c;
}
return 0;
}
/* 0 <= c <= 0xffff */
int string_buffer_putc16(StringBuffer *s, uint32_t c)
{
if (LIKELY(s->len < s->size)) {
if (s->is_wide_char) {
s->str->u.str16[s->len++] = c;
return 0;
} else if (c < 0x100) {
s->str->u.str8[s->len++] = c;
return 0;
}
}
return string_buffer_putc_slow(s, c);
}
/* 0 <= c <= 0x10ffff */
int string_buffer_putc(StringBuffer *s, uint32_t c)
{
if (UNLIKELY(c >= 0x10000)) {
/* surrogate pair */
c -= 0x10000;
if (string_buffer_putc16(s, (c >> 10) + 0xd800))
return -1;
c = (c & 0x3ff) + 0xdc00;
}
return string_buffer_putc16(s, c);
}
int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len)
{
int i;
if (s->len + len > s->size) {
if (string_buffer_realloc(s, s->len + len, 0))
return -1;
}
if (s->is_wide_char) {
for (i = 0; i < len; i++) {
s->str->u.str16[s->len + i] = p[i];
}
s->len += len;
} else {
memcpy(&s->str->u.str8[s->len], p, len);
s->len += len;
}
return 0;
}
int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len)
{
int c = 0, i;
for (i = 0; i < len; i++) {
c |= p[i];
}
if (s->len + len > s->size) {
if (string_buffer_realloc(s, s->len + len, c))
return -1;
} else if (!s->is_wide_char && c >= 0x100) {
if (string_buffer_widen(s, s->size))
return -1;
}
if (s->is_wide_char) {
memcpy(&s->str->u.str16[s->len], p, len << 1);
s->len += len;
} else {
for (i = 0; i < len; i++) {
s->str->u.str8[s->len + i] = p[i];
}
s->len += len;
}
return 0;
}
/* appending an ASCII string */
int string_buffer_puts8(StringBuffer *s, const char *str)
{
return string_buffer_write8(s, (const uint8_t *)str, strlen(str));
}
int string_buffer_concat(StringBuffer *s, const JSString *p, uint32_t from, uint32_t to)
{
if (to <= from)
return 0;
if (p->is_wide_char)
return string_buffer_write16(s, p->u.str16 + from, to - from);
else
return string_buffer_write8(s, p->u.str8 + from, to - from);
}
int string_buffer_concat_value(StringBuffer *s, JSValueConst v)
{
JSString *p;
JSValue v1;
int res;
if (s->error_status) {
/* prevent exception overload */
return -1;
}
if (UNLIKELY(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
v1 = JS_ToString(s->ctx, v);
if (JS_IsException(v1))
return string_buffer_set_error(s);
p = JS_VALUE_GET_STRING(v1);
res = string_buffer_concat(s, p, 0, p->len);
JS_FreeValue(s->ctx, v1);
return res;
}
p = JS_VALUE_GET_STRING(v);
return string_buffer_concat(s, p, 0, p->len);
}
int string_buffer_concat_value_free(StringBuffer *s, JSValue v)
{
JSString *p;
int res;
if (s->error_status) {
/* prevent exception overload */
JS_FreeValue(s->ctx, v);
return -1;
}
if (UNLIKELY(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
v = JS_ToStringFree(s->ctx, v);
if (JS_IsException(v))
return string_buffer_set_error(s);
}
p = JS_VALUE_GET_STRING(v);
res = string_buffer_concat(s, p, 0, p->len);
JS_FreeValue(s->ctx, v);
return res;
}
int string_buffer_fill(StringBuffer *s, int c, int count)
{
/* XXX: optimize */
if (s->len + count > s->size) {
if (string_buffer_realloc(s, s->len + count, c))
return -1;
}
while (count-- > 0) {
if (string_buffer_putc16(s, c))
return -1;
}
return 0;
}
JSValue string_buffer_end(StringBuffer *s)
{
JSString *str;
str = s->str;
if (s->error_status)
return JS_EXCEPTION;
if (s->len == 0) {
js_free(s->ctx, str);
s->str = NULL;
return JS_AtomToString(s->ctx, JS_ATOM_empty_string);
}
if (s->len < s->size) {
/* smaller size so js_realloc should not fail, but OK if it does */
/* XXX: should add some slack to avoid unnecessary calls */
/* XXX: might need to use malloc+free to ensure smaller size */
str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) +
(s->len << s->is_wide_char) + 1 - s->is_wide_char);
if (str == NULL)
str = s->str;
s->str = str;
}
if (!s->is_wide_char)
str->u.str8[s->len] = 0;
#ifdef DUMP_LEAKS
list_add_tail(&str->link, &s->ctx->rt->string_list);
#endif
str->is_wide_char = s->is_wide_char;
str->len = s->len;
s->str = NULL;
return JS_MKPTR(JS_TAG_STRING, str);
}

View file

@ -1,212 +0,0 @@
[config]
# general settings for test262 ES6 version
# framework style: old, new
style=new
# handle tests tagged as [noStrict]: yes, no, skip
nostrict=yes
# handle tests tagged as [strictOnly]: yes, no, skip
strict=yes
# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all
mode=default
# handle tests flagged as [async]: yes, no, skip
# for these, load 'harness/doneprintHandle.js' prior to test
# and expect `print('Test262:AsyncTestComplete')` to be called for
# successful termination
async=yes
# handle tests flagged as [module]: yes, no, skip
module=yes
# output error messages: yes, no
verbose=yes
# load harness files from this directory
harnessdir=/opt/test262/harness
# names of harness include files to skip
#harnessexclude=
# name of the error file for known errors
errorfile=third_party/quickjs/test262_errors.txt
# exclude tests enumerated in this file (see also [exclude] section)
#excludefile=test262_exclude.txt
# report test results to this file
reportfile=o/test262_report.txt
# enumerate tests from this directory
testdir=/opt/test262/test
[features]
# Standard language features and proposed extensions
# list the features that are included
# skipped features are tagged as such to avoid warnings
AggregateError
align-detached-buffer-semantics-with-web-reality
arbitrary-module-namespace-names=skip
array-find-from-last=skip
Array.prototype.at=skip
Array.prototype.flat
Array.prototype.flatMap
Array.prototype.flatten
Array.prototype.values
ArrayBuffer
arrow-function
async-functions
async-iteration
Atomics
Atomics.waitAsync=skip
BigInt
caller
class
class-fields-private
class-fields-private-in=skip
class-fields-public
class-methods-private
class-static-block=skip
class-static-fields-public
class-static-fields-private
class-static-methods-private
cleanupSome=skip
coalesce-expression
computed-property-names
const
cross-realm
DataView
DataView.prototype.getFloat32
DataView.prototype.getFloat64
DataView.prototype.getInt16
DataView.prototype.getInt32
DataView.prototype.getInt8
DataView.prototype.getUint16
DataView.prototype.getUint32
DataView.prototype.setUint8
default-parameters
destructuring-assignment
destructuring-binding
dynamic-import
error-cause=skip
export-star-as-namespace-from-module
FinalizationGroup=skip
FinalizationRegistry=skip
FinalizationRegistry.prototype.cleanupSome=skip
Float32Array
Float64Array
for-in-order
for-of
generators
globalThis
hashbang
host-gc-required=skip
import.meta
import-assertions=skip
Int16Array
Int32Array
Int8Array
IsHTMLDDA
json-modules=skip
json-superset
legacy-regexp=skip
let
logical-assignment-operators
Map
new.target
numeric-separator-literal
object-rest
object-spread
Object.fromEntries
Object.hasOwn
Object.is
optional-catch-binding
optional-chaining
Promise
Promise.allSettled
Promise.any
Promise.prototype.finally
Proxy
proxy-missing-checks
Reflect
Reflect.construct
Reflect.set
Reflect.setPrototypeOf
regexp-dotall
regexp-lookbehind
regexp-match-indices=skip
regexp-named-groups
regexp-unicode-property-escapes
resizable-arraybuffer=skip
rest-parameters
Set
ShadowRealm=skip
SharedArrayBuffer
string-trimming
String.fromCodePoint
String.prototype.endsWith
String.prototype.includes
String.prototype.at=skip
String.prototype.matchAll
String.prototype.replaceAll
String.prototype.trimEnd
String.prototype.trimStart
super
Symbol
Symbol.asyncIterator
Symbol.hasInstance
Symbol.isConcatSpreadable
Symbol.iterator
Symbol.match
Symbol.matchAll
Symbol.prototype.description
Symbol.replace
Symbol.search
Symbol.species
Symbol.split
Symbol.toPrimitive
Symbol.toStringTag
Symbol.unscopables
tail-call-optimization=skip
template
Temporal=skip
top-level-await=skip
TypedArray
TypedArray.prototype.at=skip
u180e
Uint16Array
Uint32Array
Uint8Array
Uint8ClampedArray
WeakMap
WeakRef=skip
WeakSet
well-formed-json-stringify
__getter__
__proto__
__setter__
[exclude]
# list excluded tests and directories here
# intl not supported
/opt/test262/test/intl402/
# incompatible with the "caller" feature
/opt/test262/test/built-ins/Function/prototype/restricted-property-caller.js
/opt/test262/test/built-ins/Function/prototype/restricted-property-arguments.js
/opt/test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
# slow tests
#/opt/test262/test/built-ins/RegExp/CharacterClassEscapes/
#/opt/test262/test/built-ins/RegExp/property-escapes/
# No threads in Cosmopolitan ATM
/opt/test262/test/built-ins/Atomics/
[tests]
# list test files or use config.testdir

View file

@ -1,35 +0,0 @@
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: Test262Error: Expected a ReferenceError but got a ReferenceError
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError
test262/test/built-ins/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/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: Test262Error: (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: strict mode: Test262Error: (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: Test262Error: (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: strict mode: Test262Error: (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:34: TypeError: cannot convert bigint to number (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: strict mode: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: strict mode: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: strict mode: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: strict mode: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: strict mode: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: strict mode: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
test262/test/language/expressions/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/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

@ -1,410 +0,0 @@
[config]
# general settings for test262 ES5 version
# framework style: old, new
style=old
# handle tests tagged as @noStrict: yes, no, skip
nostrict=yes
# handle tests tagged as @strictOnly: yes, no, skip
strict=yes
# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all
mode=default
# output error messages: yes, no
verbose=yes
# load harness files this directory
harnessdir=test262o/test/harness
# name of the error file for known errors
errorfile=test262o_errors.txt
# exclude tests enumerated in this file
#excludefile=test262o_excluded.txt
# report test results to this file
reportfile=test262o_report.txt
# enumerate tests from this directory
testdir=test262o/test/suite
[exclude]
# list excluded tests and directories here
# intl not supported
test262o/test/suite/intl402/
# ES6 != ES5: block scoped function definitions allowed in strict mode
test262o/test/suite/bestPractice/Sbp_A1_T1.js
test262o/test/suite/bestPractice/Sbp_A2_T1.js
test262o/test/suite/bestPractice/Sbp_A2_T2.js
test262o/test/suite/bestPractice/Sbp_A3_T1.js
test262o/test/suite/bestPractice/Sbp_A3_T2.js
test262o/test/suite/bestPractice/Sbp_A4_T1.js
test262o/test/suite/bestPractice/Sbp_A4_T2.js
test262o/test/suite/bestPractice/Sbp_A5_T2.js
# ES6 != ES5: `y={x};` is shorthand for `y={x:x}`
test262o/test/suite/ch12/12.1/S12.1_A4_T2.js
test262o/test/suite/ch12/12.6/12.6.4/S12.6.4_A15.js
# ES6 != ES5: function length property is configurable
test262o/test/suite/ch11/11.4/11.4.1/11.4.1-5-a-28-s.js
test262o/test/suite/ch13/13.2/13.2-15-1.js
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.1/S15.1.2.1_A4.2.js
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A9.2.js
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A7.2.js
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.4/S15.1.2.4_A2.2.js
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.5/S15.1.2.5_A2.2.js
test262o/test/suite/ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A5.2.js
test262o/test/suite/ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A5.2.js
test262o/test/suite/ch15/15.1/15.1.3/15.1.3.3/S15.1.3.3_A5.2.js
test262o/test/suite/ch15/15.1/15.1.3/15.1.3.4/S15.1.3.4_A5.2.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-186.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-187.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-191.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-194.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-201.js
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.2/S15.2.4.2_A9.js
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.3/S15.2.4.3_A9.js
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.4/S15.2.4.4_A9.js
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.5/S15.2.4.5_A9.js
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.6/S15.2.4.6_A9.js
test262o/test/suite/ch15/15.2/15.2.4/15.2.4.7/S15.2.4.7_A9.js
test262o/test/suite/ch15/15.3/15.3.3/15.3.3.2/15.3.3.2-1.js
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.2/S15.3.4.2_A9.js
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.3/S15.3.4.3_A9.js
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.4/S15.3.4.4_A9.js
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-15-2.js
test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T1.js
test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T2.js
test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T3.js
test262o/test/suite/ch15/15.4/15.4.3/S15.4.3_A2.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.2/S15.4.4.2_A4.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.3/S15.4.4.3_A4.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.4/S15.4.4.4_A4.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A6.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A5.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A6.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A5.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A5.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A5.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A7.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A5.2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A5.2.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.4/S15.5.4.4_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.5/S15.5.4.5_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.6/S15.5.4.6_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.7/S15.5.4.7_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.8/S15.5.4.8_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.9/S15.5.4.9_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.10/S15.5.4.10_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.11/S15.5.4.11_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.12/S15.5.4.12_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.13/S15.5.4.13_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.14/S15.5.4.14_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.15/S15.5.4.15_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.16/S15.5.4.16_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.17/S15.5.4.17_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.18/S15.5.4.18_A9.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.19/S15.5.4.19_A9.js
test262o/test/suite/ch15/15.9/15.9.4/15.9.4.2/S15.9.4.2_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.4/15.9.4.3/S15.9.4.3_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.1/S15.9.5.1_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.2/S15.9.5.2_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.3/S15.9.5.3_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.4/S15.9.5.4_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.5/S15.9.5.5_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.6/S15.9.5.6_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.7/S15.9.5.7_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.8/S15.9.5.8_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.9/S15.9.5.9_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.10/S15.9.5.10_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.11/S15.9.5.11_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.12/S15.9.5.12_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.13/S15.9.5.13_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.14/S15.9.5.14_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.15/S15.9.5.15_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.16/S15.9.5.16_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.17/S15.9.5.17_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.18/S15.9.5.18_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.19/S15.9.5.19_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.20/S15.9.5.20_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.21/S15.9.5.21_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.22/S15.9.5.22_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.23/S15.9.5.23_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.24/S15.9.5.24_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.25/S15.9.5.25_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.26/S15.9.5.26_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.27/S15.9.5.27_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.28/S15.9.5.28_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.29/S15.9.5.29_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.30/S15.9.5.30_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.31/S15.9.5.31_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.32/S15.9.5.32_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.33/S15.9.5.33_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.34/S15.9.5.34_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.35/S15.9.5.35_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.36/S15.9.5.36_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.37/S15.9.5.37_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.38/S15.9.5.38_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.39/S15.9.5.39_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.40/S15.9.5.40_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.41/S15.9.5.41_A3_T2.js
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.42/S15.9.5.42_A3_T2.js
test262o/test/suite/ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A9.js
test262o/test/suite/ch15/15.10/15.10.6/15.10.6.3/S15.10.6.3_A9.js
test262o/test/suite/ch15/15.10/15.10.6/15.10.6.4/S15.10.6.4_A9.js
# ES6 != ES5: object literals may have duplicates
test262o/test/suite/ch11/11.1/11.1.5/11.1.5-4-4-a-1-s.js
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-b-1.js
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-b-2.js
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-c-1.js
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-c-2.js
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-1.js
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-2.js
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-3.js
test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-4.js
# ES6 != ES5: Date.prototype is no longer an instance of Date
test262o/test/suite/ch15/15.9/15.9.5/15.9.5.40/15.9.5.40_1.js
# ES6 != ES5: Object.getPrototypeOf converts argument to object
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1-3.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1-4.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1.js
# ES6 != ES5: Object.getPrototypeOf(NativeError)
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-12.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-13.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-14.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-15.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-16.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-17.js
# ES6 != ES5: Object.getOwnPropertyDescriptor converts argument to object
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-3.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-4.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1.js
# ES6 != ES5: Object.getOwnPropertyNames converts argument to object
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-4.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-5.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1.js
# ES6 != ES5: Object.seal accepts all types
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-1.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-2.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-3.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-4.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1.js
# ES6 != ES5: Object.freeze accepts all types
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-1.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-2.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-3.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-4.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1.js
# ES6 != ES5: Object.preventExtensions accepts all types
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-1.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-2.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-3.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-4.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1.js
# ES6 != ES5: Object.isSealed accepts all types
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.11/15.2.3.11-1.js
# ES6 != ES5: Object.isFrozen accepts all types
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-1.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-2.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-3.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-4.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1.js
# ES6 != ES5: Object.isExtensible accepts all types
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-1.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-2.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-3.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-4.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1.js
# ES6 != ES5: Object.keys converts argument to object
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-1.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-2.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-3.js
# ES6 != ES5: source and other properties of RegExp.prototype are not own properties
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-212.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-213.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-214.js
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-215.js
# ES6 != ES5: String numeric object properties are enumerated first
test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-44.js
# ES6: new RegExp(regex, flags) is valid
test262o/test/suite/ch15/15.10/15.10.3/S15.10.3.1_A2_T1.js
test262o/test/suite/ch15/15.10/15.10.3/S15.10.3.1_A2_T2.js
test262o/test/suite/ch15/15.10/15.10.4/15.10.4.1/15.10.4.1-1.js
test262o/test/suite/ch15/15.10/15.10.4/S15.10.4.1_A2_T1.js
test262o/test/suite/ch15/15.10/15.10.4/S15.10.4.1_A2_T2.js
# ES6 != ES5: RegExp.prototype.test behavior
test262o/test/suite/ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A5_T3.js
# ES6 != ES5: source, global, ignoreCase, multiline, lastIndex are not data properties
# of RegExp objects and RegExp.prototype is not a RegExp object
test262o/test/suite/ch15/15.10/15.10.6/15.10.6.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/15.10.7.1-1.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/15.10.7.1-2.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A8.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A9.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A10.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/15.10.7.2-1.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/15.10.7.2-2.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A8.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A9.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A10.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/15.10.7.3-1.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/15.10.7.3-2.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A8.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A9.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A10.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/15.10.7.4-1.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/15.10.7.4-2.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A8.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A9.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A10.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.5/15.10.7.5-1.js
test262o/test/suite/ch15/15.10/15.10.7/15.10.7.5/15.10.7.5-2.js
# ES6 != ES5: Error.prototype is a normal object
test262o/test/suite/ch15/15.11/15.11.4/S15.11.4_A2.js
# ES6 different ToLength() semantics
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A4_T3.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A2_T2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T1.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T3.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A2_T2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A4_T1.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A4_T3.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A3_T3.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A3_T3.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T1.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T3.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A4_T3.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A3_T1.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A3_T3.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A3_T2.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-7.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-8.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-12.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-14.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-25.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-28.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-29.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-7.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-12.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-25.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-28.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-7.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-8.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-12.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-14.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-25.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-29.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-7.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-8.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-12.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-14.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-25.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-28.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-29.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-7.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-12.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-25.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-7.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-8.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-12.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-14.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-25.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-28.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-29.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-7.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-12.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-25.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-7.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-12.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-25.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-7.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-12.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-25.js
# ES6 different ToLength() semantics causes near infinite runtime
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-14.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-14.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-14.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-14.js
test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-14.js
# ES6 arguments/caller changes
test262o/test/suite/ch10/10.6/10.6-13-b-1-s.js
test262o/test/suite/ch10/10.6/10.6-13-b-2-s.js
test262o/test/suite/ch10/10.6/10.6-13-b-3-s.js
test262o/test/suite/ch10/10.6/10.6-14-1-s.js
test262o/test/suite/ch10/10.6/10.6-14-b-1-s.js
test262o/test/suite/ch10/10.6/10.6-14-b-4-s.js
test262o/test/suite/ch13/13.2/13.2-29-s.js
test262o/test/suite/ch13/13.2/13.2-30-s.js
test262o/test/suite/ch13/13.2/13.2-31-s.js
test262o/test/suite/ch13/13.2/13.2-32-s.js
test262o/test/suite/ch13/13.2/13.2-33-s.js
test262o/test/suite/ch13/13.2/13.2-34-s.js
test262o/test/suite/ch13/13.2/13.2-35-s.js
test262o/test/suite/ch13/13.2/13.2-36-s.js
test262o/test/suite/ch13/13.2/S13.2.3_A1.js
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-1.js
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-4.js
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-5.js
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-1.js
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-4.js
test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-5.js
# u180e is no longer considered as a space
test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A2.js
test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A3_T1.js
test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A3_T2.js
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A2_T10.js
test262o/test/suite/ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A2_T10.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-2.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-3.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-4.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-5.js
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-6.js
test262o/test/suite/ch15/15.10/15.10.2/15.10.2.12/S15.10.2.12_A1_T1.js
test262o/test/suite/ch15/15.10/15.10.2/15.10.2.12/S15.10.2.12_A2_T1.js
# E6 eval return value is different
test262o/test/suite/ch12/12.6/12.6.3/S12.6.3_A9.js
test262o/test/suite/ch12/12.6/12.6.3/S12.6.3_A9.1.js
# ECMA 2019 optional-catch-binding feature allows try{}catch{}
test262o/test/suite/ch12/12.14/S12.14_A16_T4.js
# Syntax error instead of ReferenceError in ES2020
test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-1.js
test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-2.js
test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-3.js
test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-4.js
[tests]
# list test files or use config.testdir

View file

@ -1,96 +0,0 @@
/*
* QuickJS: binary JSON module (test only)
*
* Copyright (c) 2017-2019 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "../quickjs-libc.h"
#include "../cutils.h"
static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
uint8_t *buf;
uint64_t pos, len;
JSValue obj;
size_t size;
int flags;
if (JS_ToIndex(ctx, &pos, argv[1]))
return JS_EXCEPTION;
if (JS_ToIndex(ctx, &len, argv[2]))
return JS_EXCEPTION;
buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
if (!buf)
return JS_EXCEPTION;
if (pos + len > size)
return JS_ThrowRangeError(ctx, "array buffer overflow");
flags = 0;
if (JS_ToBool(ctx, argv[3]))
flags |= JS_READ_OBJ_REFERENCE;
obj = JS_ReadObject(ctx, buf + pos, len, flags);
return obj;
}
static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
size_t len;
uint8_t *buf;
JSValue array;
int flags;
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);
js_free(ctx, buf);
return array;
}
static const JSCFunctionListEntry js_bjson_funcs[] = {
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)
{
return JS_SetModuleExportList(ctx, m, js_bjson_funcs,
countof(js_bjson_funcs));
}
#ifdef JS_SHARED_LIBRARY
#define JS_INIT_MODULE js_init_module
#else
#define JS_INIT_MODULE js_init_module_bjson
#endif
JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
{
JSModuleDef *m;
m = JS_NewCModule(ctx, module_name, js_bjson_init);
if (!m)
return NULL;
JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs));
return m;
}

File diff suppressed because it is too large Load diff

View file

@ -1,71 +0,0 @@
diff --git a/harness/atomicsHelper.js b/harness/atomicsHelper.js
index 9c1217351e..3c24755558 100644
--- a/harness/atomicsHelper.js
+++ b/harness/atomicsHelper.js
@@ -227,10 +227,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) {
* }
*/
$262.agent.timeouts = {
- yield: 100,
- small: 200,
- long: 1000,
- huge: 10000,
+// yield: 100,
+// small: 200,
+// long: 1000,
+// huge: 10000,
+ yield: 20,
+ small: 20,
+ long: 100,
+ huge: 1000,
};
/**
diff --git a/harness/regExpUtils.js b/harness/regExpUtils.js
index be7039fda0..7b38abf8df 100644
--- a/harness/regExpUtils.js
+++ b/harness/regExpUtils.js
@@ -6,24 +6,27 @@ description: |
defines: [buildString, testPropertyEscapes, matchValidator]
---*/
+if ($262 && typeof $262.codePointRange === "function") {
+ /* use C function to build the codePointRange (much faster with
+ slow JS engines) */
+ codePointRange = $262.codePointRange;
+} else {
+ codePointRange = function codePointRange(start, end) {
+ const codePoints = [];
+ let length = 0;
+ for (codePoint = start; codePoint < end; codePoint++) {
+ codePoints[length++] = codePoint;
+ }
+ return String.fromCodePoint.apply(null, codePoints);
+ }
+}
+
function buildString({ loneCodePoints, ranges }) {
- const CHUNK_SIZE = 10000;
- let result = Reflect.apply(String.fromCodePoint, null, loneCodePoints);
- for (let i = 0; i < ranges.length; i++) {
- const range = ranges[i];
- const start = range[0];
- const end = range[1];
- const codePoints = [];
- for (let length = 0, codePoint = start; codePoint <= end; codePoint++) {
- codePoints[length++] = codePoint;
- if (length === CHUNK_SIZE) {
- result += Reflect.apply(String.fromCodePoint, null, codePoints);
- codePoints.length = length = 0;
- }
+ let result = String.fromCodePoint.apply(null, loneCodePoints);
+ for (const [start, end] of ranges) {
+ result += codePointRange(start, end + 1);
}
- result += Reflect.apply(String.fromCodePoint, null, codePoints);
- }
- return result;
+ return result;
}
function testPropertyEscapes(regex, string, expression) {

View file

@ -1,326 +0,0 @@
"use strict";
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 + ")" : ""));
}
function assertThrows(err, func)
{
var ex;
ex = false;
try {
func();
} catch(e) {
ex = true;
assert(e instanceof err);
}
assert(ex, true, "exception expected");
}
// load more elaborate version of assert if available
try { __loadScript("test_assert.js"); } catch(e) {}
/*----------------*/
function bigint_pow(a, n)
{
var r, i;
r = 1n;
for(i = 0n; i < n; i++)
r *= a;
return r;
}
/* a must be < b */
function test_less(a, b)
{
assert(a < b);
assert(!(b < a));
assert(a <= b);
assert(!(b <= a));
assert(b > a);
assert(!(a > b));
assert(b >= a);
assert(!(a >= b));
assert(a != b);
assert(!(a == b));
}
/* a must be numerically equal to b */
function test_eq(a, b)
{
assert(a == b);
assert(b == a);
assert(!(a != b));
assert(!(b != a));
assert(a <= b);
assert(b <= a);
assert(!(a < b));
assert(a >= b);
assert(b >= a);
assert(!(a > b));
}
function test_bigint1()
{
var a, r;
test_less(2n, 3n);
test_eq(3n, 3n);
test_less(2, 3n);
test_eq(3, 3n);
test_less(2.1, 3n);
test_eq(Math.sqrt(4), 2n);
a = bigint_pow(3n, 100n);
assert((a - 1n) != a);
assert(a == 515377520732011331036461129765621272702107522001n);
assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1n);
r = 1n << 31n;
assert(r, 2147483648n, "1 << 31n === 2147483648n");
r = 1n << 32n;
assert(r, 4294967296n, "1 << 32n === 4294967296n");
}
function test_bigint2()
{
assert(BigInt(""), 0n);
assert(BigInt(" 123"), 123n);
assert(BigInt(" 123 "), 123n);
assertThrows(SyntaxError, () => { BigInt("+") } );
assertThrows(SyntaxError, () => { BigInt("-") } );
assertThrows(SyntaxError, () => { BigInt("\x00a") } );
assertThrows(SyntaxError, () => { BigInt(" 123 r") } );
}
function test_divrem(div1, a, b, q)
{
var div, divrem, t;
div = BigInt[div1];
divrem = BigInt[div1 + "rem"];
assert(div(a, b) == q);
t = divrem(a, b);
assert(t[0] == q);
assert(a == b * q + t[1]);
}
function test_idiv1(div, a, b, r)
{
test_divrem(div, a, b, r[0]);
test_divrem(div, -a, b, r[1]);
test_divrem(div, a, -b, r[2]);
test_divrem(div, -a, -b, r[3]);
}
/* QuickJS BigInt extensions */
function test_bigint_ext()
{
var r;
assert(BigInt.floorLog2(0n) === -1n);
assert(BigInt.floorLog2(7n) === 2n);
assert(BigInt.sqrt(0xffffffc000000000000000n) === 17592185913343n);
r = BigInt.sqrtrem(0xffffffc000000000000000n);
assert(r[0] === 17592185913343n);
assert(r[1] === 35167191957503n);
test_idiv1("tdiv", 3n, 2n, [1n, -1n, -1n, 1n]);
test_idiv1("fdiv", 3n, 2n, [1n, -2n, -2n, 1n]);
test_idiv1("cdiv", 3n, 2n, [2n, -1n, -1n, 2n]);
test_idiv1("ediv", 3n, 2n, [1n, -2n, -1n, 2n]);
}
function test_bigfloat()
{
var e, a, b, sqrt2;
assert(typeof 1n === "bigint");
assert(typeof 1l === "bigfloat");
assert(1 == 1.0l);
assert(1 !== 1.0l);
test_less(2l, 3l);
test_eq(3l, 3l);
test_less(2, 3l);
test_eq(3, 3l);
test_less(2.1, 3l);
test_eq(Math.sqrt(9), 3l);
test_less(2n, 3l);
test_eq(3n, 3l);
e = new BigFloatEnv(128);
assert(e.prec == 128);
a = BigFloat.sqrt(2l, e);
assert(a === BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));
assert(e.inexact === true);
assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcc908b2fb1366ea95l);
b = BigFloatEnv.setPrec(BigFloat.sqrt.bind(null, 2), 128);
assert(a === b);
assert(BigFloat.isNaN(BigFloat(NaN)));
assert(BigFloat.isFinite(1l));
assert(!BigFloat.isFinite(1l/0l));
assert(BigFloat.abs(-3l) === 3l);
assert(BigFloat.sign(-3l) === -1l);
assert(BigFloat.exp(0.2l) === 1.2214027581601698339210719946396742l);
assert(BigFloat.log(3l) === 1.0986122886681096913952452369225256l);
assert(BigFloat.pow(2.1l, 1.6l) === 3.277561666451861947162828744873745l);
assert(BigFloat.sin(-1l) === -0.841470984807896506652502321630299l);
assert(BigFloat.cos(1l) === 0.5403023058681397174009366074429766l);
assert(BigFloat.tan(0.1l) === 0.10033467208545054505808004578111154l);
assert(BigFloat.asin(0.3l) === 0.30469265401539750797200296122752915l);
assert(BigFloat.acos(0.4l) === 1.1592794807274085998465837940224159l);
assert(BigFloat.atan(0.7l) === 0.610725964389208616543758876490236l);
assert(BigFloat.atan2(7.1l, -5.1l) === 2.1937053809751415549388104628759813l);
assert(BigFloat.floor(2.5l) === 2l);
assert(BigFloat.ceil(2.5l) === 3l);
assert(BigFloat.trunc(-2.5l) === -2l);
assert(BigFloat.round(2.5l) === 3l);
assert(BigFloat.fmod(3l,2l) === 1l);
assert(BigFloat.remainder(3l,2l) === -1l);
/* string conversion */
assert((1234.125l).toString(), "1234.125");
assert((1234.125l).toFixed(2), "1234.13");
assert((1234.125l).toFixed(2, "down"), "1234.12");
assert((1234.125l).toExponential(), "1.234125e+3");
assert((1234.125l).toExponential(5), "1.23413e+3");
assert((1234.125l).toExponential(5, BigFloatEnv.RNDZ), "1.23412e+3");
assert((1234.125l).toPrecision(6), "1234.13");
assert((1234.125l).toPrecision(6, BigFloatEnv.RNDZ), "1234.12");
/* string conversion with binary base */
assert((0x123.438l).toString(16), "123.438");
assert((0x323.438l).toString(16), "323.438");
assert((0x723.438l).toString(16), "723.438");
assert((0xf23.438l).toString(16), "f23.438");
assert((0x123.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "123.44");
assert((0x323.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "323.44");
assert((0x723.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "723.44");
assert((0xf23.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "f23.44");
assert((0x0.0000438l).toFixed(6, BigFloatEnv.RNDNA, 16), "0.000044");
assert((0x1230000000l).toFixed(1, BigFloatEnv.RNDNA, 16), "1230000000.0");
assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "123.44");
assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDZ, 16), "123.43");
assert((0x323.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "323.44");
assert((0x723.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "723.44");
assert((-0xf23.438l).toPrecision(5, BigFloatEnv.RNDD, 16), "-f23.44");
assert((0x123.438l).toExponential(4, BigFloatEnv.RNDNA, 16), "1.2344p+8");
}
function test_bigdecimal()
{
assert(1m === 1m);
assert(1m !== 2m);
test_less(1m, 2m);
test_eq(2m, 2m);
test_less(1, 2m);
test_eq(2, 2m);
test_less(1.1, 2m);
test_eq(Math.sqrt(4), 2m);
test_less(2n, 3m);
test_eq(3n, 3m);
assert(BigDecimal("1234.1") === 1234.1m);
assert(BigDecimal(" 1234.1") === 1234.1m);
assert(BigDecimal(" 1234.1 ") === 1234.1m);
assert(BigDecimal(0.1) === 0.1m);
assert(BigDecimal(123) === 123m);
assert(BigDecimal(true) === 1m);
assert(123m + 1m === 124m);
assert(123m - 1m === 122m);
assert(3.2m * 3m === 9.6m);
assert(10m / 2m === 5m);
assertThrows(RangeError, () => { 10m / 3m } );
assert(10m % 3m === 1m);
assert(-10m % 3m === -1m);
assert(1234.5m ** 3m === 1881365963.625m);
assertThrows(RangeError, () => { 2m ** 3.1m } );
assertThrows(RangeError, () => { 2m ** -3m } );
assert(BigDecimal.sqrt(2m,
{ roundingMode: "half-even",
maximumSignificantDigits: 4 }) === 1.414m);
assert(BigDecimal.sqrt(101m,
{ roundingMode: "half-even",
maximumFractionDigits: 3 }) === 10.050m);
assert(BigDecimal.sqrt(0.002m,
{ roundingMode: "half-even",
maximumFractionDigits: 3 }) === 0.045m);
assert(BigDecimal.round(3.14159m,
{ roundingMode: "half-even",
maximumFractionDigits: 3 }) === 3.142m);
assert(BigDecimal.add(3.14159m, 0.31212m,
{ roundingMode: "half-even",
maximumFractionDigits: 2 }) === 3.45m);
assert(BigDecimal.sub(3.14159m, 0.31212m,
{ roundingMode: "down",
maximumFractionDigits: 2 }) === 2.82m);
assert(BigDecimal.mul(3.14159m, 0.31212m,
{ roundingMode: "half-even",
maximumFractionDigits: 3 }) === 0.981m);
assert(BigDecimal.mod(3.14159m, 0.31211m,
{ roundingMode: "half-even",
maximumFractionDigits: 4 }) === 0.0205m);
assert(BigDecimal.div(20m, 3m,
{ roundingMode: "half-even",
maximumSignificantDigits: 3 }) === 6.67m);
assert(BigDecimal.div(20m, 3m,
{ roundingMode: "half-even",
maximumFractionDigits: 50 }) ===
6.66666666666666666666666666666666666666666666666667m);
/* string conversion */
assert((1234.125m).toString(), "1234.125");
assert((1234.125m).toFixed(2), "1234.13");
assert((1234.125m).toFixed(2, "down"), "1234.12");
assert((1234.125m).toExponential(), "1.234125e+3");
assert((1234.125m).toExponential(5), "1.23413e+3");
assert((1234.125m).toExponential(5, "down"), "1.23412e+3");
assert((1234.125m).toPrecision(6), "1234.13");
assert((1234.125m).toPrecision(6, "down"), "1234.12");
assert((-1234.125m).toPrecision(6, "floor"), "-1234.13");
}
test_bigint1();
test_bigint2();
test_bigint_ext();
test_bigfloat();
test_bigdecimal();

View file

@ -1,191 +0,0 @@
import * as bjson from "./bjson.so";
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 + ")" : ""));
}
function toHex(a)
{
var i, s = "", tab, v;
tab = new Uint8Array(a);
for(i = 0; i < tab.length; i++) {
v = tab[i].toString(16);
if (v.length < 2)
v = "0" + v;
if (i !== 0)
s += " ";
s += v;
}
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;
switch(typeof(a)) {
case "object":
if (a === null)
return "null";
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)
s += ",";
s += toStr(a[i]);
}
s += "]";
} else {
props = Object.keys(a);
s = "{";
for(i = 0; i < props.length; i++) {
if (i != 0)
s += ",";
prop = props[i];
s += prop + ":" + toStr(a[prop]);
}
s += "}";
}
return s;
case "undefined":
return "undefined";
case "string":
return a.__quote();
case "number":
case "bigfloat":
if (a == 0 && 1 / a < 0)
return "-0";
else
return a.toString();
break;
default:
return a.toString();
}
}
function bjson_test(a)
{
var buf, r, a_str, r_str;
a_str = toStr(a);
buf = bjson.write(a);
if (0) {
print(a_str, "->", toHex(buf));
}
r = bjson.read(buf, 0, buf.byteLength);
r_str = toStr(r);
if (a_str != r_str) {
print(a_str);
print(r_str);
assert(false);
}
}
/* 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;
bjson_test({x:1, y:2, if:3});
bjson_test([1, 2, 3]);
bjson_test([1.0, "aa", true, false, undefined, null, NaN, -Infinity, -0.0]);
if (typeof BigInt !== "undefined") {
bjson_test([BigInt("1"), -BigInt("0x123456789"),
BigInt("0x123456789abcdef123456789abcdef")]);
}
if (typeof BigFloat !== "undefined") {
BigFloatEnv.setPrec(function () {
bjson_test([BigFloat("0.1"), BigFloat("-1e30"), BigFloat("0"),
BigFloat("-0"), BigFloat("Infinity"), BigFloat("-Infinity"),
0.0 / BigFloat("0"), BigFloat.MAX_VALUE,
BigFloat.MIN_VALUE]);
}, 113, 15);
}
if (typeof BigDecimal !== "undefined") {
bjson_test([BigDecimal("0"),
BigDecimal("0.8"), BigDecimal("123321312321321e100"),
BigDecimal("-1233213123213214332333223332e100"),
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;
try {
bjson.write(obj);
assert(false);
} catch(e) {
assert(e instanceof TypeError);
}
bjson_test_reference();
}
bjson_test_all();

View file

@ -1,685 +0,0 @@
"use strict";
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 + ")" : ""));
}
function assert_throws(expected_error, func)
{
var err = false;
try {
func();
} catch(e) {
err = true;
if (!(e instanceof expected_error)) {
throw Error("unexpected exception type");
}
}
if (!err) {
throw Error("expected exception");
}
}
// load more elaborate version of assert if available
try { __loadScript("test_assert.js"); } catch(e) {}
/*----------------*/
function my_func(a, b)
{
return a + b;
}
function test_function()
{
function f(a, b) {
var i, tab = [];
tab.push(this);
for(i = 0; i < arguments.length; i++)
tab.push(arguments[i]);
return tab;
}
function constructor1(a) {
this.x = a;
}
var r, g;
r = my_func.call(null, 1, 2);
assert(r, 3, "call");
r = my_func.apply(null, [1, 2]);
assert(r, 3, "apply");
r = (function () { return 1; }).apply(null, undefined);
assert(r, 1);
assert_throws(TypeError, (function() {
Reflect.apply((function () { return 1; }), null, undefined);
}));
r = new Function("a", "b", "return a + b;");
assert(r(2,3), 5, "function");
g = f.bind(1, 2);
assert(g.length, 1);
assert(g.name, "bound f");
assert(g(3), [1,2,3]);
g = constructor1.bind(null, 1);
r = new g();
assert(r.x, 1);
}
function test()
{
var r, a, b, c, err;
r = Error("hello");
assert(r.message, "hello", "Error");
a = new Object();
a.x = 1;
assert(a.x, 1, "Object");
assert(Object.getPrototypeOf(a), Object.prototype, "getPrototypeOf");
Object.defineProperty(a, "y", { value: 3, writable: true, configurable: true, enumerable: true });
assert(a.y, 3, "defineProperty");
Object.defineProperty(a, "z", { get: function () { return 4; }, set: function(val) { this.z_val = val; }, configurable: true, enumerable: true });
assert(a.z, 4, "get");
a.z = 5;
assert(a.z_val, 5, "set");
a = { get z() { return 4; }, set z(val) { this.z_val = val; } };
assert(a.z, 4, "get");
a.z = 5;
assert(a.z_val, 5, "set");
b = Object.create(a);
assert(Object.getPrototypeOf(b), a, "create");
c = {u:2};
/* XXX: refcount bug in 'b' instead of 'a' */
Object.setPrototypeOf(a, c);
assert(Object.getPrototypeOf(a), c, "setPrototypeOf");
a = {};
assert(a.toString(), "[object Object]", "toString");
a = {x:1};
assert(Object.isExtensible(a), true, "extensible");
Object.preventExtensions(a);
err = false;
try {
a.y = 2;
} catch(e) {
err = true;
}
assert(Object.isExtensible(a), false, "extensible");
assert(typeof a.y, "undefined", "extensible");
assert(err, true, "extensible");
}
function test_enum()
{
var a, tab;
a = {x:1,
"18014398509481984": 1,
"9007199254740992": 1,
"9007199254740991": 1,
"4294967296": 1,
"4294967295": 1,
y:1,
"4294967294": 1,
"1": 2};
tab = Object.keys(a);
// console.log("tab=" + tab.toString());
assert(tab, ["1","4294967294","x","18014398509481984","9007199254740992","9007199254740991","4294967296","4294967295","y"], "keys");
}
function test_array()
{
var a, err;
a = [1, 2, 3];
assert(a.length, 3, "array");
assert(a[2], 3, "array1");
a = new Array(10);
assert(a.length, 10, "array2");
a = new Array(1, 2);
assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array3");
a = [1, 2, 3];
a.length = 2;
assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array4");
a = [];
a[1] = 10;
a[4] = 3;
assert(a.length, 5);
a = [1,2];
a.length = 5;
a[4] = 1;
a.length = 4;
assert(a[4] !== 1, true, "array5");
a = [1,2];
a.push(3,4);
assert(a.join(), "1,2,3,4", "join");
a = [1,2,3,4,5];
Object.defineProperty(a, "3", { configurable: false });
err = false;
try {
a.length = 2;
} catch(e) {
err = true;
}
assert(err && a.toString() === "1,2,3,4");
}
function test_string()
{
var a;
a = String("abc");
assert(a.length, 3, "string");
assert(a[1], "b", "string");
assert(a.charCodeAt(1), 0x62, "string");
assert(String.fromCharCode(65), "A", "string");
assert(String.fromCharCode.apply(null, [65, 66, 67]), "ABC", "string");
assert(a.charAt(1), "b");
assert(a.charAt(-1), "");
assert(a.charAt(3), "");
a = "abcd";
assert(a.substring(1, 3), "bc", "substring");
a = String.fromCharCode(0x20ac);
assert(a.charCodeAt(0), 0x20ac, "unicode");
assert(a, "€", "unicode");
assert(a, "\u20ac", "unicode");
assert(a, "\u{20ac}", "unicode");
assert("a", "\x61", "unicode");
a = "\u{10ffff}";
assert(a.length, 2, "unicode");
assert(a, "\u{dbff}\u{dfff}", "unicode");
assert(a.codePointAt(0), 0x10ffff);
assert(String.fromCodePoint(0x10ffff), a);
assert("a".concat("b", "c"), "abc");
assert("abcabc".indexOf("cab"), 2);
assert("abcabc".indexOf("cab2"), -1);
assert("abc".indexOf("c"), 2);
assert("aaa".indexOf("a"), 0);
assert("aaa".indexOf("a", NaN), 0);
assert("aaa".indexOf("a", -Infinity), 0);
assert("aaa".indexOf("a", -1), 0);
assert("aaa".indexOf("a", -0), 0);
assert("aaa".indexOf("a", 0), 0);
assert("aaa".indexOf("a", 1), 1);
assert("aaa".indexOf("a", 2), 2);
assert("aaa".indexOf("a", 3), -1);
assert("aaa".indexOf("a", 4), -1);
assert("aaa".indexOf("a", Infinity), -1);
assert("aaa".indexOf(""), 0);
assert("aaa".indexOf("", NaN), 0);
assert("aaa".indexOf("", -Infinity), 0);
assert("aaa".indexOf("", -1), 0);
assert("aaa".indexOf("", -0), 0);
assert("aaa".indexOf("", 0), 0);
assert("aaa".indexOf("", 1), 1);
assert("aaa".indexOf("", 2), 2);
assert("aaa".indexOf("", 3), 3);
assert("aaa".indexOf("", 4), 3);
assert("aaa".indexOf("", Infinity), 3);
assert("aaa".lastIndexOf("a"), 2);
assert("aaa".lastIndexOf("a", NaN), 2);
assert("aaa".lastIndexOf("a", -Infinity), 0);
assert("aaa".lastIndexOf("a", -1), 0);
assert("aaa".lastIndexOf("a", -0), 0);
assert("aaa".lastIndexOf("a", 0), 0);
assert("aaa".lastIndexOf("a", 1), 1);
assert("aaa".lastIndexOf("a", 2), 2);
assert("aaa".lastIndexOf("a", 3), 2);
assert("aaa".lastIndexOf("a", 4), 2);
assert("aaa".lastIndexOf("a", Infinity), 2);
assert("aaa".lastIndexOf(""), 3);
assert("aaa".lastIndexOf("", NaN), 3);
assert("aaa".lastIndexOf("", -Infinity), 0);
assert("aaa".lastIndexOf("", -1), 0);
assert("aaa".lastIndexOf("", -0), 0);
assert("aaa".lastIndexOf("", 0), 0);
assert("aaa".lastIndexOf("", 1), 1);
assert("aaa".lastIndexOf("", 2), 2);
assert("aaa".lastIndexOf("", 3), 3);
assert("aaa".lastIndexOf("", 4), 3);
assert("aaa".lastIndexOf("", Infinity), 3);
assert("a,b,c".split(","), ["a","b","c"]);
assert(",b,c".split(","), ["","b","c"]);
assert("a,b,".split(","), ["a","b",""]);
assert("aaaa".split(), [ "aaaa" ]);
assert("aaaa".split(undefined, 0), [ ]);
assert("aaaa".split(""), [ "a", "a", "a", "a" ]);
assert("aaaa".split("", 0), [ ]);
assert("aaaa".split("", 1), [ "a" ]);
assert("aaaa".split("", 2), [ "a", "a" ]);
assert("aaaa".split("a"), [ "", "", "", "", "" ]);
assert("aaaa".split("a", 2), [ "", "" ]);
assert("aaaa".split("aa"), [ "", "", "" ]);
assert("aaaa".split("aa", 0), [ ]);
assert("aaaa".split("aa", 1), [ "" ]);
assert("aaaa".split("aa", 2), [ "", "" ]);
assert("aaaa".split("aaa"), [ "", "a" ]);
assert("aaaa".split("aaaa"), [ "", "" ]);
assert("aaaa".split("aaaaa"), [ "aaaa" ]);
assert("aaaa".split("aaaaa", 0), [ ]);
assert("aaaa".split("aaaaa", 1), [ "aaaa" ]);
assert(eval('"\0"'), "\0");
assert("abc".padStart(Infinity, ""), "abc");
}
function test_math()
{
var a;
a = 1.4;
assert(Math.floor(a), 1);
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()
{
assert(parseInt("123"), 123);
assert(parseInt(" 123r"), 123);
assert(parseInt("0x123"), 0x123);
assert(parseInt("0o123"), 0);
assert(+" 123 ", 123);
assert(+"0b111", 7);
assert(+"0o123", 83);
assert(parseFloat("0x1234"), 0);
assert(parseFloat("Infinity"), Infinity);
assert(parseFloat("-Infinity"), -Infinity);
assert(parseFloat("123.2"), 123.2);
assert(parseFloat("123.2e3"), 123200);
assert(Number.isNaN(Number("+")));
assert(Number.isNaN(Number("-")));
assert(Number.isNaN(Number("\x00a")));
assert((25).toExponential(0), "3e+1");
assert((-25).toExponential(0), "-3e+1");
assert((2.5).toPrecision(1), "3");
assert((-2.5).toPrecision(1), "-3");
assert((1.125).toFixed(2), "1.13");
assert((-1.125).toFixed(2), "-1.13");
}
function test_eval2()
{
var g_call_count = 0;
/* force non strict mode for f1 and f2 */
var f1 = new Function("eval", "eval(1, 2)");
var f2 = new Function("eval", "eval(...[1, 2])");
function g(a, b) {
assert(a, 1);
assert(b, 2);
g_call_count++;
}
f1(g);
f2(g);
assert(g_call_count, 2);
}
function test_eval()
{
function f(b) {
var x = 1;
return eval(b);
}
var r, a;
r = eval("1+1;");
assert(r, 2, "eval");
r = eval("var my_var=2; my_var;");
assert(r, 2, "eval");
assert(typeof my_var, "undefined");
assert(eval("if (1) 2; else 3;"), 2);
assert(eval("if (0) 2; else 3;"), 3);
assert(f.call(1, "this"), 1);
a = 2;
assert(eval("a"), 2);
eval("a = 3");
assert(a, 3);
assert(f("arguments.length", 1), 2);
assert(f("arguments[1]", 1), 1);
a = 4;
assert(f("a"), 4);
f("a=3");
assert(a, 3);
test_eval2();
}
function test_typed_array()
{
var buffer, a, i, str;
a = new Uint8Array(4);
assert(a.length, 4);
for(i = 0; i < a.length; i++)
a[i] = i;
assert(a.join(","), "0,1,2,3");
a[0] = -1;
assert(a[0], 255);
a = new Int8Array(3);
a[0] = 255;
assert(a[0], -1);
a = new Int32Array(3);
a[0] = Math.pow(2, 32) - 1;
assert(a[0], -1);
assert(a.BYTES_PER_ELEMENT, 4);
a = new Uint8ClampedArray(4);
a[0] = -100;
a[1] = 1.5;
a[2] = 0.5;
a[3] = 1233.5;
assert(a.toString(), "0,2,0,255");
buffer = new ArrayBuffer(16);
assert(buffer.byteLength, 16);
a = new Uint32Array(buffer, 12, 1);
assert(a.length, 1);
a[0] = -1;
a = new Uint16Array(buffer, 2);
a[0] = -1;
a = new Float32Array(buffer, 8, 1);
a[0] = 1;
a = new Uint8Array(buffer);
str = a.toString();
/* test little and big endian cases */
if (str !== "0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255" &&
str !== "0,0,255,255,0,0,0,0,63,128,0,0,255,255,255,255") {
assert(false);
}
assert(a.buffer, buffer);
a = new Uint8Array([1, 2, 3, 4]);
assert(a.toString(), "1,2,3,4");
a.set([10, 11], 2);
assert(a.toString(), "1,2,10,11");
}
function test_json()
{
var a, s;
s = '{"x":1,"y":true,"z":null,"a":[1,2,3],"s":"str"}';
a = JSON.parse(s);
assert(a.x, 1);
assert(a.y, true);
assert(a.z, null);
assert(JSON.stringify(a), s);
/* indentation test */
assert(JSON.stringify([[{x:1,y:{},z:[]},2,3]],undefined,1),
`[
[
{
"x": 1,
"y": {},
"z": []
},
2,
3
]
]`);
}
function test_date()
{
var d = new Date(1506098258091), a, s;
assert(d.toISOString(), "2017-09-22T16:37:38.091Z");
d.setUTCHours(18, 10, 11);
assert(d.toISOString(), "2017-09-22T18:10:11.091Z");
a = Date.parse(d.toISOString());
assert((new Date(a)).toISOString(), d.toISOString());
s = new Date("2020-01-01T01:01:01.1Z").toISOString();
assert(s == "2020-01-01T01:01:01.100Z");
s = new Date("2020-01-01T01:01:01.12Z").toISOString();
assert(s == "2020-01-01T01:01:01.120Z");
s = new Date("2020-01-01T01:01:01.123Z").toISOString();
assert(s == "2020-01-01T01:01:01.123Z");
s = new Date("2020-01-01T01:01:01.1234Z").toISOString();
assert(s == "2020-01-01T01:01:01.123Z");
s = new Date("2020-01-01T01:01:01.12345Z").toISOString();
assert(s == "2020-01-01T01:01:01.123Z");
s = new Date("2020-01-01T01:01:01.1235Z").toISOString();
assert(s == "2020-01-01T01:01:01.124Z");
s = new Date("2020-01-01T01:01:01.9999Z").toISOString();
assert(s == "2020-01-01T01:01:02.000Z");
}
function test_regexp()
{
var a, str;
str = "abbbbbc";
a = /(b+)c/.exec(str);
assert(a[0], "bbbbbc");
assert(a[1], "bbbbb");
assert(a.index, 1);
assert(a.input, str);
a = /(b+)c/.test(str);
assert(a, true);
assert(/\x61/.exec("a")[0], "a");
assert(/\u0061/.exec("a")[0], "a");
assert(/\ca/.exec("\x01")[0], "\x01");
assert(/\\a/.exec("\\a")[0], "\\a");
assert(/\c0/.exec("\\c0")[0], "\\c0");
a = /(\.(?=com|org)|\/)/.exec("ah.com");
assert(a.index === 2 && a[0] === ".");
a = /(\.(?!com|org)|\/)/.exec("ah.com");
assert(a, null);
a = /(?=(a+))/.exec("baaabac");
assert(a.index === 1 && a[0] === "" && a[1] === "aaa");
a = /(z)((a+)?(b+)?(c))*/.exec("zaacbbbcac");
assert(a, ["zaacbbbcac","z","ac","a",,"c"]);
a = eval("/\0a/");
assert(a.toString(), "/\0a/");
assert(a.exec("\0a")[0], "\0a");
assert(/{1a}/.toString(), "/{1a}/");
a = /a{1+/.exec("a{11");
assert(a, ["a{11"] );
}
function test_symbol()
{
var a, b, obj, c;
a = Symbol("abc");
obj = {};
obj[a] = 2;
assert(obj[a], 2);
assert(typeof obj["abc"], "undefined");
assert(String(a), "Symbol(abc)");
b = Symbol("abc");
assert(a == a);
assert(a === a);
assert(a != b);
assert(a !== b);
b = Symbol.for("abc");
c = Symbol.for("abc");
assert(b === c);
assert(b !== a);
assert(Symbol.keyFor(b), "abc");
assert(Symbol.keyFor(a), undefined);
a = Symbol("aaa");
assert(a.valueOf(), a);
assert(a.toString(), "Symbol(aaa)");
b = Object(a);
assert(b.valueOf(), a);
assert(b.toString(), "Symbol(aaa)");
}
function test_map()
{
var a, i, n, tab, o, v;
n = 1000;
a = new Map();
tab = [];
for(i = 0; i < n; i++) {
v = { };
o = { id: i };
tab[i] = [o, v];
a.set(o, v);
}
assert(a.size, n);
for(i = 0; i < n; i++) {
assert(a.get(tab[i][0]), tab[i][1]);
}
i = 0;
a.forEach(function (v, o) {
assert(o, tab[i++][0]);
assert(a.has(o));
assert(a.delete(o));
assert(!a.has(o));
});
assert(a.size, 0);
}
function test_weak_map()
{
var a, i, n, tab, o, v, n2;
a = new WeakMap();
n = 10;
tab = [];
for(i = 0; i < n; i++) {
v = { };
o = { id: i };
tab[i] = [o, v];
a.set(o, v);
}
o = null;
n2 = n >> 1;
for(i = 0; i < n2; i++) {
a.delete(tab[i][0]);
}
for(i = n2; i < n; i++) {
tab[i][0] = null; /* should remove the object from the WeakMap too */
}
/* the WeakMap should be empty here */
}
function test_generator()
{
function *f() {
var ret;
yield 1;
ret = yield 2;
assert(ret, "next_arg");
return 3;
}
function *f2() {
yield 1;
yield 2;
return "ret_val";
}
function *f1() {
var ret = yield *f2();
assert(ret, "ret_val");
return 3;
}
var g, v;
g = f();
v = g.next();
assert(v.value === 1 && v.done === false);
v = g.next();
assert(v.value === 2 && v.done === false);
v = g.next("next_arg");
assert(v.value === 3 && v.done === true);
v = g.next();
assert(v.value === undefined && v.done === true);
g = f1();
v = g.next();
assert(v.value === 1 && v.done === false);
v = g.next();
assert(v.value === 2 && v.done === false);
v = g.next();
assert(v.value === 3 && v.done === true);
v = g.next();
assert(v.value === undefined && v.done === true);
}
test();
test_function();
test_enum();
test_array();
test_string();
test_math();
test_number();
test_eval();
test_typed_array();
test_json();
test_date();
test_regexp();
test_symbol();
test_map();
test_weak_map();
test_generator();

View file

@ -1,221 +0,0 @@
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 + ")" : ""));
}
// load more elaborate version of assert if available
try { __loadScript("test_assert.js"); } catch(e) {}
/*----------------*/
var log_str = "";
function log(str)
{
log_str += str + ",";
}
function f(a, b, c)
{
var x = 10;
log("a="+a);
function g(d) {
function h() {
log("d=" + d);
log("x=" + x);
}
log("b=" + b);
log("c=" + c);
h();
}
g(4);
return g;
}
var g1 = f(1, 2, 3);
g1(5);
assert(log_str, "a=1,b=2,c=3,d=4,x=10,b=2,c=3,d=5,x=10,", "closure1");
function test_closure1()
{
function f2()
{
var val = 1;
function set(a) {
val = a;
}
function get(a) {
return val;
}
return { "set": set, "get": get };
}
var obj = f2();
obj.set(10);
var r;
r = obj.get();
assert(r, 10, "closure2");
}
function test_closure2()
{
var expr_func = function myfunc1(n) {
function myfunc2(n) {
return myfunc1(n - 1);
}
if (n == 0)
return 0;
else
return myfunc2(n);
};
var r;
r = expr_func(1);
assert(r, 0, "expr_func");
}
function test_closure3()
{
function fib(n)
{
if (n <= 0)
return 0;
else if (n == 1)
return 1;
else
return fib(n - 1) + fib(n - 2);
}
var fib_func = function fib1(n)
{
if (n <= 0)
return 0;
else if (n == 1)
return 1;
else
return fib1(n - 1) + fib1(n - 2);
};
assert(fib(6), 8, "fib");
assert(fib_func(6), 8, "fib_func");
}
function test_arrow_function()
{
"use strict";
function f1() {
return (() => arguments)();
}
function f2() {
return (() => this)();
}
function f3() {
return (() => eval("this"))();
}
function f4() {
return (() => eval("new.target"))();
}
var a;
a = f1(1, 2);
assert(a.length, 2);
assert(a[0] === 1 && a[1] === 2);
assert(f2.call("this_val") === "this_val");
assert(f3.call("this_val") === "this_val");
assert(new f4() === f4);
var o1 = { f() { return this; } };
var o2 = { f() {
return (() => eval("super.f()"))();
} };
o2.__proto__ = o1;
assert(o2.f() === o2);
}
function test_with()
{
var o1 = { x: "o1", y: "o1" };
var x = "local";
eval('var z="var_obj";');
assert(z === "var_obj");
with (o1) {
assert(x === "o1");
assert(eval("x") === "o1");
var f = function () {
o2 = { x: "o2" };
with (o2) {
assert(x === "o2");
assert(y === "o1");
assert(z === "var_obj");
assert(eval("x") === "o2");
assert(eval("y") === "o1");
assert(eval("z") === "var_obj");
assert(eval('eval("x")') === "o2");
}
};
f();
}
}
function test_eval_closure()
{
var tab;
tab = [];
for(let i = 0; i < 3; i++) {
eval("tab.push(function g1() { return i; })");
}
for(let i = 0; i < 3; i++) {
assert(tab[i]() === i);
}
tab = [];
for(let i = 0; i < 3; i++) {
let f = function f() {
eval("tab.push(function g2() { return i; })");
};
f();
}
for(let i = 0; i < 3; i++) {
assert(tab[i]() === i);
}
}
function test_eval_const()
{
const a = 1;
var success = false;
var f = function () {
eval("a = 1");
};
try {
f();
} catch(e) {
success = (e instanceof TypeError);
}
assert(success);
}
test_closure1();
test_closure2();
test_closure3();
test_arrow_function();
test_with();
test_eval_closure();
test_eval_const();

View file

@ -1,547 +0,0 @@
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 + ")" : ""));
}
function assert_throws(expected_error, func)
{
var err = false;
try {
func();
} catch(e) {
err = true;
if (!(e instanceof expected_error)) {
throw Error("unexpected exception type");
}
}
if (!err) {
throw Error("expected exception");
}
}
// load more elaborate version of assert if available
try { __loadScript("test_assert.js"); } catch(e) {}
/*----------------*/
function test_op1()
{
var r, a;
r = 1 + 2;
assert(r, 3, "1 + 2 === 3");
r = 1 - 2;
assert(r, -1, "1 - 2 === -1");
r = -1;
assert(r, -1, "-1 === -1");
r = +2;
assert(r, 2, "+2 === 2");
r = 2 * 3;
assert(r, 6, "2 * 3 === 6");
r = 4 / 2;
assert(r, 2, "4 / 2 === 2");
r = 4 % 3;
assert(r, 1, "4 % 3 === 3");
r = 4 << 2;
assert(r, 16, "4 << 2 === 16");
r = 1 << 0;
assert(r, 1, "1 << 0 === 1");
r = 1 << 31;
assert(r, -2147483648, "1 << 31 === -2147483648");
r = 1 << 32;
assert(r, 1, "1 << 32 === 1");
r = (1 << 31) < 0;
assert(r, true, "(1 << 31) < 0 === true");
r = -4 >> 1;
assert(r, -2, "-4 >> 1 === -2");
r = -4 >>> 1;
assert(r, 0x7ffffffe, "-4 >>> 1 === 0x7ffffffe");
r = 1 & 1;
assert(r, 1, "1 & 1 === 1");
r = 0 | 1;
assert(r, 1, "0 | 1 === 1");
r = 1 ^ 1;
assert(r, 0, "1 ^ 1 === 0");
r = ~1;
assert(r, -2, "~1 === -2");
r = !1;
assert(r, false, "!1 === false");
assert((1 < 2), true, "(1 < 2) === true");
assert((2 > 1), true, "(2 > 1) === true");
assert(('b' > 'a'), true, "('b' > 'a') === true");
assert(2 ** 8, 256, "2 ** 8 === 256");
}
function test_cvt()
{
assert((NaN | 0) === 0);
assert((Infinity | 0) === 0);
assert(((-Infinity) | 0) === 0);
assert(("12345" | 0) === 12345);
assert(("0x12345" | 0) === 0x12345);
assert(((4294967296 * 3 - 4) | 0) === -4);
assert(("12345" >>> 0) === 12345);
assert(("0x12345" >>> 0) === 0x12345);
assert((NaN >>> 0) === 0);
assert((Infinity >>> 0) === 0);
assert(((-Infinity) >>> 0) === 0);
assert(((4294967296 * 3 - 4) >>> 0) === (4294967296 - 4));
}
function test_eq()
{
assert(null == undefined);
assert(undefined == null);
assert(true == 1);
assert(0 == false);
assert("" == 0);
assert("123" == 123);
assert("122" != 123);
assert((new Number(1)) == 1);
assert(2 == (new Number(2)));
assert((new String("abc")) == "abc");
assert({} != "abc");
}
function test_inc_dec()
{
var a, r;
a = 1;
r = a++;
assert(r === 1 && a === 2, true, "++");
a = 1;
r = ++a;
assert(r === 2 && a === 2, true, "++");
a = 1;
r = a--;
assert(r === 1 && a === 0, true, "--");
a = 1;
r = --a;
assert(r === 0 && a === 0, true, "--");
a = {x:true};
a.x++;
assert(a.x, 2, "++");
a = {x:true};
a.x--;
assert(a.x, 0, "--");
a = [true];
a[0]++;
assert(a[0], 2, "++");
a = {x:true};
r = a.x++;
assert(r === 1 && a.x === 2, true, "++");
a = {x:true};
r = a.x--;
assert(r === 1 && a.x === 0, true, "--");
a = [true];
r = a[0]++;
assert(r === 1 && a[0] === 2, true, "++");
a = [true];
r = a[0]--;
assert(r === 1 && a[0] === 0, true, "--");
}
function F(x)
{
this.x = x;
}
function test_op2()
{
var a, b;
a = new Object;
a.x = 1;
assert(a.x, 1, "new");
b = new F(2);
assert(b.x, 2, "new");
a = {x : 2};
assert(("x" in a), true, "in");
assert(("y" in a), false, "in");
a = {};
assert((a instanceof Object), true, "instanceof");
assert((a instanceof String), false, "instanceof");
assert((typeof 1), "number", "typeof");
assert((typeof Object), "function", "typeof");
assert((typeof null), "object", "typeof");
assert((typeof unknown_var), "undefined", "typeof");
a = {x: 1, if: 2, async: 3};
assert(a.if === 2);
assert(a.async === 3);
}
function test_delete()
{
var a, err;
a = {x: 1, y: 1};
assert((delete a.x), true, "delete");
assert(("x" in a), false, "delete");
/* the following are not tested by test262 */
assert(delete "abc"[100], true);
err = false;
try {
delete null.a;
} catch(e) {
err = (e instanceof TypeError);
}
assert(err, true, "delete");
err = false;
try {
a = { f() { delete super.a; } };
a.f();
} catch(e) {
err = (e instanceof ReferenceError);
}
assert(err, true, "delete");
}
function test_prototype()
{
var f = function f() { };
assert(f.prototype.constructor, f, "prototype");
var g = function g() { };
/* QuickJS bug */
Object.defineProperty(g, "prototype", { writable: false });
assert(g.prototype.constructor, g, "prototype");
}
function test_arguments()
{
function f2() {
assert(arguments.length, 2, "arguments");
assert(arguments[0], 1, "arguments");
assert(arguments[1], 3, "arguments");
}
f2(1, 3);
}
function test_class()
{
var o;
class C {
constructor() {
this.x = 10;
}
f() {
return 1;
}
static F() {
return -1;
}
get y() {
return 12;
}
};
class D extends C {
constructor() {
super();
this.z = 20;
}
g() {
return 2;
}
static G() {
return -2;
}
h() {
return super.f();
}
static H() {
return super["F"]();
}
}
assert(C.F() === -1);
assert(Object.getOwnPropertyDescriptor(C.prototype, "y").get.name === "get y");
o = new C();
assert(o.f() === 1);
assert(o.x === 10);
assert(D.F() === -1);
assert(D.G() === -2);
assert(D.H() === -1);
o = new D();
assert(o.f() === 1);
assert(o.g() === 2);
assert(o.x === 10);
assert(o.z === 20);
assert(o.h() === 1);
/* test class name scope */
var E1 = class E { static F() { return E; } };
assert(E1 === E1.F());
};
function test_template()
{
var a, b;
b = 123;
a = `abc${b}d`;
assert(a, "abc123d");
a = String.raw `abc${b}d`;
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()
{
var x = 0, get = 1, set = 2; async = 3;
a = { get: 2, set: 3, async: 4 };
assert(JSON.stringify(a), '{"get":2,"set":3,"async":4}');
a = { x, get, set, async };
assert(JSON.stringify(a), '{"x":0,"get":1,"set":2,"async":3}');
}
function test_regexp_skip()
{
var a, b;
[a, b = /abc\(/] = [1];
assert(a === 1);
[a, b =/abc\(/] = [2];
assert(a === 2);
}
function test_labels()
{
do x: { break x; } while(0);
if (1)
x: { break x; }
else
x: { break x; }
with ({}) x: { break x; };
while (0) x: { break x; };
}
function test_destructuring()
{
function * g () { return 0; };
var [x] = g();
assert(x, void 0);
}
function test_spread()
{
var x;
x = [1, 2, ...[3, 4]];
assert(x.toString(), "1,2,3,4");
x = [ ...[ , ] ];
assert(Object.getOwnPropertyNames(x).toString(), "0,length");
}
function test_function_length()
{
assert( ((a, b = 1, c) => {}).length, 1);
assert( (([a,b]) => {}).length, 1);
assert( (({a,b}) => {}).length, 1);
assert( ((c, [a,b] = 1, d) => {}).length, 1);
}
function test_argument_scope()
{
var f;
var c = "global";
f = function(a = eval("var arguments")) {};
assert_throws(SyntaxError, f);
f = function(a = eval("1"), b = arguments[0]) { return b; };
assert(f(12), 12);
f = function(a, b = arguments[0]) { return b; };
assert(f(12), 12);
f = function(a, b = () => arguments) { return b; };
assert(f(12)()[0], 12);
f = function(a = eval("1"), b = () => arguments) { return b; };
assert(f(12)()[0], 12);
(function() {
"use strict";
f = function(a = this) { return a; };
assert(f.call(123), 123);
f = function f(a = f) { return a; };
assert(f(), f);
f = function f(a = eval("f")) { return a; };
assert(f(), f);
})();
f = (a = eval("var c = 1"), probe = () => c) => {
var c = 2;
assert(c, 2);
assert(probe(), 1);
}
f();
f = (a = eval("var arguments = 1"), probe = () => arguments) => {
var arguments = 2;
assert(arguments, 2);
assert(probe(), 1);
}
f();
f = function f(a = eval("var c = 1"), b = c, probe = () => c) {
assert(b, 1);
assert(c, 1);
assert(probe(), 1)
}
f();
assert(c, "global");
f = function f(a, b = c, probe = () => c) {
eval("var c = 1");
assert(c, 1);
assert(b, "global");
assert(probe(), "global")
}
f();
assert(c, "global");
f = function f(a = eval("var c = 1"), probe = (d = eval("c")) => d) {
assert(probe(), 1)
}
f();
}
function test_function_expr_name()
{
var f;
/* non strict mode test : assignment to the function name silently
fails */
f = function myfunc() {
myfunc = 1;
return myfunc;
};
assert(f(), f);
f = function myfunc() {
myfunc = 1;
(() => {
myfunc = 1;
})();
return myfunc;
};
assert(f(), f);
f = function myfunc() {
eval("myfunc = 1");
return myfunc;
};
assert(f(), f);
/* strict mode test : assignment to the function name raises a
TypeError exception */
f = function myfunc() {
"use strict";
myfunc = 1;
};
assert_throws(TypeError, f);
f = function myfunc() {
"use strict";
(() => {
myfunc = 1;
})();
};
assert_throws(TypeError, f);
f = function myfunc() {
"use strict";
eval("myfunc = 1");
};
assert_throws(TypeError, f);
}
test_op1();
test_cvt();
test_eq();
test_inc_dec();
test_op2();
test_delete();
test_prototype();
test_arguments();
test_class();
test_template();
test_template_skip();
test_object_literal();
test_regexp_skip();
test_labels();
test_destructuring();
test_spread();
test_function_length();
test_argument_scope();
test_function_expr_name();

View file

@ -1,368 +0,0 @@
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 + ")" : ""));
}
// load more elaborate version of assert if available
try { __loadScript("test_assert.js"); } catch(e) {}
/*----------------*/
function test_while()
{
var i, c;
i = 0;
c = 0;
while (i < 3) {
c++;
i++;
}
assert(c === 3);
}
function test_while_break()
{
var i, c;
i = 0;
c = 0;
while (i < 3) {
c++;
if (i == 1)
break;
i++;
}
assert(c === 2 && i === 1);
}
function test_do_while()
{
var i, c;
i = 0;
c = 0;
do {
c++;
i++;
} while (i < 3);
assert(c === 3 && i === 3);
}
function test_for()
{
var i, c;
c = 0;
for(i = 0; i < 3; i++) {
c++;
}
assert(c === 3 && i === 3);
c = 0;
for(var j = 0; j < 3; j++) {
c++;
}
assert(c === 3 && j === 3);
}
function test_for_in()
{
var i, tab, a, b;
tab = [];
for(i in {x:1, y: 2}) {
tab.push(i);
}
assert(tab.toString(), "x,y", "for_in");
/* prototype chain test */
a = {x:2, y: 2, "1": 3};
b = {"4" : 3 };
Object.setPrototypeOf(a, b);
tab = [];
for(i in a) {
tab.push(i);
}
assert(tab.toString(), "1,x,y,4", "for_in");
/* non enumerable properties hide enumerables ones in the
prototype chain */
a = {y: 2, "1": 3};
Object.defineProperty(a, "x", { value: 1 });
b = {"x" : 3 };
Object.setPrototypeOf(a, b);
tab = [];
for(i in a) {
tab.push(i);
}
assert(tab.toString(), "1,y", "for_in");
/* array optimization */
a = [];
for(i = 0; i < 10; i++)
a.push(i);
tab = [];
for(i in a) {
tab.push(i);
}
assert(tab.toString(), "0,1,2,3,4,5,6,7,8,9", "for_in");
/* iterate with a field */
a={x:0};
tab = [];
for(a.x in {x:1, y: 2}) {
tab.push(a.x);
}
assert(tab.toString(), "x,y", "for_in");
/* iterate with a variable field */
a=[0];
tab = [];
for(a[0] in {x:1, y: 2}) {
tab.push(a[0]);
}
assert(tab.toString(), "x,y", "for_in");
/* variable definition in the for in */
tab = [];
for(var j in {x:1, y: 2}) {
tab.push(j);
}
assert(tab.toString(), "x,y", "for_in");
/* variable assigment in the for in */
tab = [];
for(var k = 2 in {x:1, y: 2}) {
tab.push(k);
}
assert(tab.toString(), "x,y", "for_in");
}
function test_for_in2()
{
var i;
tab = [];
for(i in {x:1, y: 2, z:3}) {
if (i === "y")
continue;
tab.push(i);
}
assert(tab.toString() == "x,z");
tab = [];
for(i in {x:1, y: 2, z:3}) {
if (i === "z")
break;
tab.push(i);
}
assert(tab.toString() == "x,y");
}
function test_for_break()
{
var i, c;
c = 0;
L1: for(i = 0; i < 3; i++) {
c++;
if (i == 0)
continue;
while (1) {
break L1;
}
}
assert(c === 2 && i === 1);
}
function test_switch1()
{
var i, a, s;
s = "";
for(i = 0; i < 3; i++) {
a = "?";
switch(i) {
case 0:
a = "a";
break;
case 1:
a = "b";
break;
default:
a = "c";
break;
}
s += a;
}
assert(s === "abc" && i === 3);
}
function test_switch2()
{
var i, a, s;
s = "";
for(i = 0; i < 4; i++) {
a = "?";
switch(i) {
case 0:
a = "a";
break;
case 1:
a = "b";
break;
case 2:
continue;
default:
a = "" + i;
break;
}
s += a;
}
assert(s === "ab3" && i === 4);
}
function test_try_catch1()
{
try {
throw "hello";
} catch (e) {
assert(e, "hello", "catch");
return;
}
assert(false, "catch");
}
function test_try_catch2()
{
var a;
try {
a = 1;
} catch (e) {
a = 2;
}
assert(a, 1, "catch");
}
function test_try_catch3()
{
var s;
s = "";
try {
s += "t";
} catch (e) {
s += "c";
} finally {
s += "f";
}
assert(s, "tf", "catch");
}
function test_try_catch4()
{
var s;
s = "";
try {
s += "t";
throw "c";
} catch (e) {
s += e;
} finally {
s += "f";
}
assert(s, "tcf", "catch");
}
function test_try_catch5()
{
var s;
s = "";
for(;;) {
try {
s += "t";
break;
s += "b";
} finally {
s += "f";
}
}
assert(s, "tf", "catch");
}
function test_try_catch6()
{
function f() {
try {
s += 't';
return 1;
} finally {
s += "f";
}
}
var s = "";
assert(f() === 1);
assert(s, "tf", "catch6");
}
function test_try_catch7()
{
var s;
s = "";
try {
try {
s += "t";
throw "a";
} finally {
s += "f";
}
} catch(e) {
s += e;
} finally {
s += "g";
}
assert(s, "tfag", "catch");
}
function test_try_catch8()
{
var i, s;
s = "";
for(var i in {x:1, y:2}) {
try {
s += i;
throw "a";
} catch (e) {
s += e;
} finally {
s += "f";
}
}
assert(s === "xafyaf");
}
test_while();
test_while_break();
test_do_while();
test_for();
test_for_break();
test_switch1();
test_switch2();
test_for_in();
test_for_in2();
test_try_catch1();
test_try_catch2();
test_try_catch3();
test_try_catch4();
test_try_catch5();
test_try_catch6();
test_try_catch7();
test_try_catch8();

View file

@ -1,207 +0,0 @@
"use strict";
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 + ")" : ""));
}
/* operators overloading with Operators.create() */
function test_operators_create() {
class Vec2
{
constructor(x, y) {
this.x = x;
this.y = y;
}
static mul_scalar(p1, a) {
var r = new Vec2();
r.x = p1.x * a;
r.y = p1.y * a;
return r;
}
toString() {
return "Vec2(" + this.x + "," + this.y + ")";
}
}
Vec2.prototype[Symbol.operatorSet] = Operators.create(
{
"+"(p1, p2) {
var r = new Vec2();
r.x = p1.x + p2.x;
r.y = p1.y + p2.y;
return r;
},
"-"(p1, p2) {
var r = new Vec2();
r.x = p1.x - p2.x;
r.y = p1.y - p2.y;
return r;
},
"=="(a, b) {
return a.x == b.x && a.y == b.y;
},
"<"(a, b) {
var r;
/* lexicographic order */
if (a.x == b.x)
r = (a.y < b.y);
else
r = (a.x < b.x);
return r;
},
"++"(a) {
var r = new Vec2();
r.x = a.x + 1;
r.y = a.y + 1;
return r;
}
},
{
left: Number,
"*"(a, b) {
return Vec2.mul_scalar(b, a);
}
},
{
right: Number,
"*"(a, b) {
return Vec2.mul_scalar(a, b);
}
});
var a = new Vec2(1, 2);
var b = new Vec2(3, 4);
var r;
r = a * 2 + 3 * b;
assert(r.x === 11 && r.y === 16);
assert(a == a, true);
assert(a == b, false);
assert(a != a, false);
assert(a < b, true);
assert(a <= b, true);
assert(b < a, false);
assert(b <= a, false);
assert(a <= a, true);
assert(a >= a, true);
a++;
assert(a.x === 2 && a.y === 3);
r = ++a;
assert(a.x === 3 && a.y === 4);
assert(r === a);
}
/* operators overloading thru inheritance */
function test_operators()
{
var Vec2;
function mul_scalar(p1, a) {
var r = new Vec2();
r.x = p1.x * a;
r.y = p1.y * a;
return r;
}
var vec2_ops = Operators({
"+"(p1, p2) {
var r = new Vec2();
r.x = p1.x + p2.x;
r.y = p1.y + p2.y;
return r;
},
"-"(p1, p2) {
var r = new Vec2();
r.x = p1.x - p2.x;
r.y = p1.y - p2.y;
return r;
},
"=="(a, b) {
return a.x == b.x && a.y == b.y;
},
"<"(a, b) {
var r;
/* lexicographic order */
if (a.x == b.x)
r = (a.y < b.y);
else
r = (a.x < b.x);
return r;
},
"++"(a) {
var r = new Vec2();
r.x = a.x + 1;
r.y = a.y + 1;
return r;
}
},
{
left: Number,
"*"(a, b) {
return mul_scalar(b, a);
}
},
{
right: Number,
"*"(a, b) {
return mul_scalar(a, b);
}
});
Vec2 = class Vec2 extends vec2_ops
{
constructor(x, y) {
super();
this.x = x;
this.y = y;
}
toString() {
return "Vec2(" + this.x + "," + this.y + ")";
}
}
var a = new Vec2(1, 2);
var b = new Vec2(3, 4);
var r;
r = a * 2 + 3 * b;
assert(r.x === 11 && r.y === 16);
assert(a == a, true);
assert(a == b, false);
assert(a != a, false);
assert(a < b, true);
assert(a <= b, true);
assert(b < a, false);
assert(b <= a, false);
assert(a <= a, true);
assert(a >= a, true);
a++;
assert(a.x === 2 && a.y === 3);
r = ++a;
assert(a.x === 3 && a.y === 4);
assert(r === a);
}
function test_default_op()
{
assert(Object(1) + 2, 3);
assert(Object(1) + true, 2);
assert(-Object(1), -1);
}
test_operators_create();
test_operators();
test_default_op();

Some files were not shown because too many files have changed in this diff Show more