mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Retire third_party/quickjs/
QuickJS cosmocc binaries are now being distributed on https://bellard.org/quickjs/
This commit is contained in:
parent
08793aa143
commit
1ef63eb206
111 changed files with 0 additions and 98553 deletions
1
Makefile
1
Makefile
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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];
|
||||
|
|
1
third_party/BUILD.mk
vendored
1
third_party/BUILD.mk
vendored
|
@ -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 \
|
||||
|
|
1
third_party/python/Modules/_pickle.c
vendored
1
third_party/python/Modules/_pickle.c
vendored
|
@ -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");
|
||||
|
|
1
third_party/python/Objects/weakrefobject.c
vendored
1
third_party/python/Objects/weakrefobject.c
vendored
|
@ -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))
|
||||
|
|
1
third_party/python/Python/peephole.c
vendored
1
third_party/python/Python/peephole.c
vendored
|
@ -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. */
|
||||
|
||||
|
|
216
third_party/quickjs/BUILD.mk
vendored
216
third_party/quickjs/BUILD.mk
vendored
|
@ -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)
|
148
third_party/quickjs/Changelog
vendored
148
third_party/quickjs/Changelog
vendored
|
@ -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
|
22
third_party/quickjs/LICENSE
vendored
22
third_party/quickjs/LICENSE
vendored
|
@ -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.
|
16
third_party/quickjs/README.cosmo
vendored
16
third_party/quickjs/README.cosmo
vendored
|
@ -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
|
70
third_party/quickjs/TODO
vendored
70
third_party/quickjs/TODO
vendored
|
@ -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
|
1951
third_party/quickjs/array.c
vendored
1951
third_party/quickjs/array.c
vendored
File diff suppressed because it is too large
Load diff
322
third_party/quickjs/atof.c
vendored
322
third_party/quickjs/atof.c
vendored
|
@ -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
|
243
third_party/quickjs/atom.c
vendored
243
third_party/quickjs/atom.c
vendored
|
@ -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;
|
||||
}
|
520
third_party/quickjs/atomics.c
vendored
520
third_party/quickjs/atomics.c
vendored
|
@ -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 */
|
724
third_party/quickjs/bigdecimal.c
vendored
724
third_party/quickjs/bigdecimal.c
vendored
|
@ -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;
|
||||
}
|
851
third_party/quickjs/bigint.c
vendored
851
third_party/quickjs/bigint.c
vendored
|
@ -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));
|
||||
}
|
2239
third_party/quickjs/byte.c
vendored
2239
third_party/quickjs/byte.c
vendored
File diff suppressed because it is too large
Load diff
4107
third_party/quickjs/call.c
vendored
4107
third_party/quickjs/call.c
vendored
File diff suppressed because it is too large
Load diff
515
third_party/quickjs/cutils.c
vendored
515
third_party/quickjs/cutils.c
vendored
|
@ -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
|
259
third_party/quickjs/cutils.h
vendored
259
third_party/quickjs/cutils.h
vendored
|
@ -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_ */
|
1032
third_party/quickjs/date.c
vendored
1032
third_party/quickjs/date.c
vendored
File diff suppressed because it is too large
Load diff
175
third_party/quickjs/dbuf.c
vendored
175
third_party/quickjs/dbuf.c
vendored
|
@ -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));
|
||||
}
|
30
third_party/quickjs/diglet.c
vendored
30
third_party/quickjs/diglet.c
vendored
|
@ -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;
|
||||
}
|
8
third_party/quickjs/diglet.h
vendored
8
third_party/quickjs/diglet.h
vendored
|
@ -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_ */
|
734
third_party/quickjs/doc/jsbignum.html
vendored
734
third_party/quickjs/doc/jsbignum.html
vendored
|
@ -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 < 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 < 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’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> (“round to nearest with ties to even”)<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><=</code></dt>
|
||||
<dt><code>>=</code></dt>
|
||||
<dt><code><</code></dt>
|
||||
<dt><code>></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>"floor"</code>, <code>"ceiling"</code>, <code>"down"</code>, <code>"up"</code>,
|
||||
<code>"half-even"</code>, <code>"half-up"</code>). Either
|
||||
<code>maximumSignificantDigits</code> or <code>maximumFractionDigits</code> 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).
|
||||
</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 = "half-up")</code></dt>
|
||||
<dt><code>toFixed(p, rnd_mode = "half-up")</code></dt>
|
||||
<dt><code>toExponential(p, rnd_mode = "half-up")</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>"use math"</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 === "bigfloat"</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 === "number "</code>, <code>typeof 1n === "number"</code> but <code>typeof 9007199254740992 === "bigint" </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>
|
BIN
third_party/quickjs/doc/jsbignum.pdf
vendored
BIN
third_party/quickjs/doc/jsbignum.pdf
vendored
Binary file not shown.
589
third_party/quickjs/doc/jsbignum.texi
vendored
589
third_party/quickjs/doc/jsbignum.texi
vendored
|
@ -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
|
1383
third_party/quickjs/doc/quickjs.html
vendored
1383
third_party/quickjs/doc/quickjs.html
vendored
File diff suppressed because it is too large
Load diff
BIN
third_party/quickjs/doc/quickjs.pdf
vendored
BIN
third_party/quickjs/doc/quickjs.pdf
vendored
Binary file not shown.
1097
third_party/quickjs/doc/quickjs.texi
vendored
1097
third_party/quickjs/doc/quickjs.texi
vendored
File diff suppressed because it is too large
Load diff
458
third_party/quickjs/eq.c
vendored
458
third_party/quickjs/eq.c
vendored
|
@ -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 */
|
||||
}
|
416
third_party/quickjs/err.c
vendored
416
third_party/quickjs/err.c
vendored
|
@ -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);
|
||||
}
|
72
third_party/quickjs/examples/fib.c
vendored
72
third_party/quickjs/examples/fib.c
vendored
|
@ -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;
|
||||
}
|
10
third_party/quickjs/examples/fib_module.js
vendored
10
third_party/quickjs/examples/fib_module.js
vendored
|
@ -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);
|
||||
}
|
1
third_party/quickjs/examples/hello.js
vendored
1
third_party/quickjs/examples/hello.js
vendored
|
@ -1 +0,0 @@
|
|||
console.log("Hello World");
|
6
third_party/quickjs/examples/hello_module.js
vendored
6
third_party/quickjs/examples/hello_module.js
vendored
|
@ -1,6 +0,0 @@
|
|||
/* example of JS module */
|
||||
|
||||
import { fib } from "./fib_module.js";
|
||||
|
||||
console.log("Hello World");
|
||||
console.log("fib(10)=", fib(10));
|
68
third_party/quickjs/examples/pi_bigdecimal.js
vendored
68
third_party/quickjs/examples/pi_bigdecimal.js
vendored
|
@ -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"));
|
||||
})();
|
66
third_party/quickjs/examples/pi_bigfloat.js
vendored
66
third_party/quickjs/examples/pi_bigfloat.js
vendored
|
@ -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);
|
||||
})();
|
118
third_party/quickjs/examples/pi_bigint.js
vendored
118
third_party/quickjs/examples/pi_bigint.js
vendored
|
@ -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);
|
151
third_party/quickjs/examples/point.c
vendored
151
third_party/quickjs/examples/point.c
vendored
|
@ -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;
|
||||
}
|
6
third_party/quickjs/examples/test_fib.js
vendored
6
third_party/quickjs/examples/test_fib.js
vendored
|
@ -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));
|
40
third_party/quickjs/examples/test_point.js
vendored
40
third_party/quickjs/examples/test_point.js
vendored
|
@ -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();
|
1160
third_party/quickjs/float.c
vendored
1160
third_party/quickjs/float.c
vendored
File diff suppressed because it is too large
Load diff
495
third_party/quickjs/gc.c
vendored
495
third_party/quickjs/gc.c
vendored
|
@ -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);
|
||||
}
|
509
third_party/quickjs/gen.c
vendored
509
third_party/quickjs/gen.c
vendored
|
@ -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);
|
||||
}
|
2211
third_party/quickjs/internal.h
vendored
2211
third_party/quickjs/internal.h
vendored
File diff suppressed because it is too large
Load diff
47
third_party/quickjs/iter.c
vendored
47
third_party/quickjs/iter.c
vendored
|
@ -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));
|
||||
}
|
991
third_party/quickjs/json.c
vendored
991
third_party/quickjs/json.c
vendored
|
@ -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));
|
||||
}
|
64
third_party/quickjs/leb128.c
vendored
64
third_party/quickjs/leb128.c
vendored
|
@ -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;
|
||||
}
|
9
third_party/quickjs/leb128.h
vendored
9
third_party/quickjs/leb128.h
vendored
|
@ -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_ */
|
8504
third_party/quickjs/libbf.c
vendored
8504
third_party/quickjs/libbf.c
vendored
File diff suppressed because it is too large
Load diff
514
third_party/quickjs/libbf.h
vendored
514
third_party/quickjs/libbf.h
vendored
|
@ -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_ */
|
59
third_party/quickjs/libregexp-opcode.inc
vendored
59
third_party/quickjs/libregexp-opcode.inc
vendored
|
@ -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 */
|
2618
third_party/quickjs/libregexp.c
vendored
2618
third_party/quickjs/libregexp.c
vendored
File diff suppressed because it is too large
Load diff
69
third_party/quickjs/libregexp.h
vendored
69
third_party/quickjs/libregexp.h
vendored
|
@ -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_ */
|
4447
third_party/quickjs/libunicode-table.inc
vendored
4447
third_party/quickjs/libunicode-table.inc
vendored
File diff suppressed because it is too large
Load diff
1564
third_party/quickjs/libunicode.c
vendored
1564
third_party/quickjs/libunicode.c
vendored
File diff suppressed because it is too large
Load diff
103
third_party/quickjs/libunicode.h
vendored
103
third_party/quickjs/libunicode.h
vendored
|
@ -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_ */
|
76
third_party/quickjs/list.h
vendored
76
third_party/quickjs/list.h
vendored
|
@ -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_ */
|
748
third_party/quickjs/map.c
vendored
748
third_party/quickjs/map.c
vendored
|
@ -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]);
|
||||
}
|
||||
}
|
303
third_party/quickjs/math.c
vendored
303
third_party/quickjs/math.c
vendored
|
@ -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));
|
||||
}
|
188
third_party/quickjs/mem.c
vendored
188
third_party/quickjs/mem.c
vendored
|
@ -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);
|
||||
}
|
1247
third_party/quickjs/object.c
vendored
1247
third_party/quickjs/object.c
vendored
File diff suppressed because it is too large
Load diff
6148
third_party/quickjs/parse.c
vendored
6148
third_party/quickjs/parse.c
vendored
File diff suppressed because it is too large
Load diff
109
third_party/quickjs/prim.c
vendored
109
third_party/quickjs/prim.c
vendored
|
@ -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);
|
||||
}
|
1568
third_party/quickjs/promise.c
vendored
1568
third_party/quickjs/promise.c
vendored
File diff suppressed because it is too large
Load diff
964
third_party/quickjs/proxy.c
vendored
964
third_party/quickjs/proxy.c
vendored
|
@ -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);
|
||||
}
|
578
third_party/quickjs/qjs.c
vendored
578
third_party/quickjs/qjs.c
vendored
|
@ -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;
|
||||
}
|
734
third_party/quickjs/qjsc.c
vendored
734
third_party/quickjs/qjsc.c
vendored
|
@ -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;
|
||||
}
|
2657
third_party/quickjs/qjscalc.js
vendored
2657
third_party/quickjs/qjscalc.js
vendored
File diff suppressed because it is too large
Load diff
273
third_party/quickjs/quickjs-atom.inc
vendored
273
third_party/quickjs/quickjs-atom.inc
vendored
|
@ -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 */
|
3844
third_party/quickjs/quickjs-libc.c
vendored
3844
third_party/quickjs/quickjs-libc.c
vendored
File diff suppressed because it is too large
Load diff
27
third_party/quickjs/quickjs-libc.h
vendored
27
third_party/quickjs/quickjs-libc.h
vendored
|
@ -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_ */
|
366
third_party/quickjs/quickjs-opcode.inc
vendored
366
third_party/quickjs/quickjs-opcode.inc
vendored
|
@ -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 */
|
14986
third_party/quickjs/quickjs.c
vendored
14986
third_party/quickjs/quickjs.c
vendored
File diff suppressed because it is too large
Load diff
1012
third_party/quickjs/quickjs.h
vendored
1012
third_party/quickjs/quickjs.h
vendored
File diff suppressed because it is too large
Load diff
1
third_party/quickjs/readme.txt
vendored
1
third_party/quickjs/readme.txt
vendored
|
@ -1 +0,0 @@
|
|||
The main documentation is in doc/quickjs.pdf or doc/quickjs.html.
|
196
third_party/quickjs/reflect.c
vendored
196
third_party/quickjs/reflect.c
vendored
|
@ -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));
|
||||
}
|
1409
third_party/quickjs/regexp.c
vendored
1409
third_party/quickjs/regexp.c
vendored
File diff suppressed because it is too large
Load diff
1573
third_party/quickjs/repl.js
vendored
1573
third_party/quickjs/repl.js
vendored
File diff suppressed because it is too large
Load diff
2116
third_party/quickjs/run-test262.c
vendored
2116
third_party/quickjs/run-test262.c
vendored
File diff suppressed because it is too large
Load diff
449
third_party/quickjs/shape.c
vendored
449
third_party/quickjs/shape.c
vendored
|
@ -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);
|
||||
}
|
2312
third_party/quickjs/str.c
vendored
2312
third_party/quickjs/str.c
vendored
File diff suppressed because it is too large
Load diff
331
third_party/quickjs/strbuf.c
vendored
331
third_party/quickjs/strbuf.c
vendored
|
@ -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);
|
||||
}
|
212
third_party/quickjs/test262.conf
vendored
212
third_party/quickjs/test262.conf
vendored
|
@ -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
|
35
third_party/quickjs/test262_errors.txt
vendored
35
third_party/quickjs/test262_errors.txt
vendored
|
@ -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.
|
410
third_party/quickjs/test262o.conf
vendored
410
third_party/quickjs/test262o.conf
vendored
|
@ -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
|
0
third_party/quickjs/test262o_errors.txt
vendored
0
third_party/quickjs/test262o_errors.txt
vendored
96
third_party/quickjs/tests/bjson.c
vendored
96
third_party/quickjs/tests/bjson.c
vendored
|
@ -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;
|
||||
}
|
1065
third_party/quickjs/tests/microbench.js
vendored
1065
third_party/quickjs/tests/microbench.js
vendored
File diff suppressed because it is too large
Load diff
71
third_party/quickjs/tests/test262.patch
vendored
71
third_party/quickjs/tests/test262.patch
vendored
|
@ -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) {
|
326
third_party/quickjs/tests/test_bignum.js
vendored
326
third_party/quickjs/tests/test_bignum.js
vendored
|
@ -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();
|
191
third_party/quickjs/tests/test_bjson.js
vendored
191
third_party/quickjs/tests/test_bjson.js
vendored
|
@ -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();
|
685
third_party/quickjs/tests/test_builtin.js
vendored
685
third_party/quickjs/tests/test_builtin.js
vendored
|
@ -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();
|
221
third_party/quickjs/tests/test_closure.js
vendored
221
third_party/quickjs/tests/test_closure.js
vendored
|
@ -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();
|
547
third_party/quickjs/tests/test_language.js
vendored
547
third_party/quickjs/tests/test_language.js
vendored
|
@ -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();
|
368
third_party/quickjs/tests/test_loop.js
vendored
368
third_party/quickjs/tests/test_loop.js
vendored
|
@ -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();
|
207
third_party/quickjs/tests/test_op_overloading.js
vendored
207
third_party/quickjs/tests/test_op_overloading.js
vendored
|
@ -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
Loading…
Reference in a new issue