mirror of
https://github.com/bellard/quickjs.git
synced 2024-11-24 06:38:12 +08:00
2020-01-05 release
This commit is contained in:
parent
9096e544ba
commit
91459fb672
86
Changelog
Normal file
86
Changelog
Normal file
@ -0,0 +1,86 @@
|
||||
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
|
439
Makefile
Normal file
439
Makefile
Normal file
@ -0,0 +1,439 @@
|
||||
#
|
||||
# QuickJS Javascript Engine
|
||||
#
|
||||
# Copyright (c) 2017-2019 Fabrice Bellard
|
||||
# Copyright (c) 2017-2019 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.
|
||||
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
CONFIG_DARWIN=y
|
||||
endif
|
||||
# Windows cross compilation from Linux
|
||||
#CONFIG_WIN32=y
|
||||
# use link time optimization (smaller and faster executables but slower build)
|
||||
CONFIG_LTO=y
|
||||
# consider warnings as errors (for development)
|
||||
#CONFIG_WERROR=y
|
||||
# force 32 bit build for some utilities
|
||||
#CONFIG_M32=y
|
||||
|
||||
ifdef CONFIG_DARWIN
|
||||
# use clang instead of gcc
|
||||
CONFIG_CLANG=y
|
||||
CONFIG_DEFAULT_AR=y
|
||||
endif
|
||||
|
||||
# installation directory
|
||||
prefix=/usr/local
|
||||
|
||||
# use the gprof profiler
|
||||
#CONFIG_PROFILE=y
|
||||
# use address sanitizer
|
||||
#CONFIG_ASAN=y
|
||||
|
||||
OBJDIR=.obj
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
CROSS_PREFIX=i686-w64-mingw32-
|
||||
EXE=.exe
|
||||
else
|
||||
CROSS_PREFIX=
|
||||
EXE=
|
||||
endif
|
||||
ifdef CONFIG_CLANG
|
||||
HOST_CC=clang
|
||||
CC=$(CROSS_PREFIX)clang
|
||||
CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -Wno-sign-compare
|
||||
CFLAGS += -Wno-missing-field-initializers
|
||||
CFLAGS += -Wundef -Wuninitialized
|
||||
CFLAGS += -Wunused -Wno-unused-parameter
|
||||
CFLAGS += -Wwrite-strings
|
||||
CFLAGS += -Wchar-subscripts -funsigned-char
|
||||
CFLAGS += -MMD -MF $(OBJDIR)/$(@F).d
|
||||
ifdef CONFIG_DEFAULT_AR
|
||||
AR=$(CROSS_PREFIX)ar
|
||||
else
|
||||
ifdef CONFIG_LTO
|
||||
AR=$(CROSS_PREFIX)llvm-ar
|
||||
else
|
||||
AR=$(CROSS_PREFIX)ar
|
||||
endif
|
||||
endif
|
||||
else
|
||||
HOST_CC=gcc
|
||||
CC=$(CROSS_PREFIX)gcc
|
||||
CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
|
||||
CFLAGS += -Wno-array-bounds -Wno-format-truncation
|
||||
ifdef CONFIG_LTO
|
||||
AR=$(CROSS_PREFIX)gcc-ar
|
||||
else
|
||||
AR=$(CROSS_PREFIX)ar
|
||||
endif
|
||||
endif
|
||||
STRIP=$(CROSS_PREFIX)strip
|
||||
ifdef CONFIG_WERROR
|
||||
CFLAGS+=-Werror
|
||||
endif
|
||||
DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
|
||||
CFLAGS+=$(DEFINES)
|
||||
CFLAGS_DEBUG=$(CFLAGS) -O0
|
||||
CFLAGS_SMALL=$(CFLAGS) -Os
|
||||
CFLAGS_OPT=$(CFLAGS) -O2
|
||||
CFLAGS_NOLTO:=$(CFLAGS_OPT)
|
||||
LDFLAGS=-g
|
||||
ifdef CONFIG_LTO
|
||||
CFLAGS_SMALL+=-flto
|
||||
CFLAGS_OPT+=-flto
|
||||
LDFLAGS+=-flto
|
||||
endif
|
||||
ifdef CONFIG_PROFILE
|
||||
CFLAGS+=-p
|
||||
LDFLAGS+=-p
|
||||
endif
|
||||
ifdef CONFIG_ASAN
|
||||
CFLAGS+=-fsanitize=address
|
||||
LDFLAGS+=-fsanitize=address
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
LDEXPORT=
|
||||
else
|
||||
LDEXPORT=-rdynamic
|
||||
endif
|
||||
|
||||
PROGS=qjs$(EXE) qjsc$(EXE) run-test262
|
||||
ifneq ($(CROSS_PREFIX),)
|
||||
QJSC_CC=gcc
|
||||
QJSC=./host-qjsc
|
||||
PROGS+=$(QJSC)
|
||||
else
|
||||
QJSC_CC=$(CC)
|
||||
QJSC=./qjsc$(EXE)
|
||||
endif
|
||||
ifndef CONFIG_WIN32
|
||||
PROGS+=qjscalc
|
||||
endif
|
||||
ifdef CONFIG_M32
|
||||
PROGS+=qjs32 qjs32_s
|
||||
endif
|
||||
PROGS+=libquickjs.a
|
||||
ifdef CONFIG_LTO
|
||||
PROGS+=libquickjs.lto.a
|
||||
endif
|
||||
|
||||
# examples
|
||||
ifeq ($(CROSS_PREFIX),)
|
||||
ifdef CONFIG_ASAN
|
||||
PROGS+=
|
||||
else
|
||||
PROGS+=examples/hello examples/hello_module examples/test_fib
|
||||
ifndef CONFIG_DARWIN
|
||||
PROGS+=examples/fib.so examples/point.so
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS)
|
||||
|
||||
QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/libbf.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o
|
||||
|
||||
QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(OBJDIR)/qjscalc.o $(QJS_LIB_OBJS)
|
||||
|
||||
LIBS=-lm
|
||||
ifndef CONFIG_WIN32
|
||||
LIBS+=-ldl
|
||||
endif
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests
|
||||
|
||||
qjs$(EXE): $(QJS_OBJS)
|
||||
$(CC) $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
|
||||
|
||||
qjs-debug$(EXE): $(patsubst %.o, %.debug.o, $(QJS_OBJS))
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
qjsc$(EXE): $(OBJDIR)/qjsc.o $(QJS_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
ifneq ($(CROSS_PREFIX),)
|
||||
|
||||
$(QJSC): $(OBJDIR)/qjsc.host.o \
|
||||
$(patsubst %.o, %.host.o, $(QJS_LIB_OBJS))
|
||||
$(HOST_CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
endif #CROSS_PREFIX
|
||||
|
||||
QJSC_DEFINES:=-DCONFIG_CC=\"$(QJSC_CC)\" -DCONFIG_PREFIX=\"$(prefix)\"
|
||||
ifdef CONFIG_LTO
|
||||
QJSC_DEFINES+=-DCONFIG_LTO
|
||||
endif
|
||||
QJSC_HOST_DEFINES:=-DCONFIG_CC=\"$(HOST_CC)\" -DCONFIG_PREFIX=\"$(prefix)\"
|
||||
|
||||
$(OBJDIR)/qjsc.o: CFLAGS+=$(QJSC_DEFINES)
|
||||
$(OBJDIR)/qjsc.host.o: CFLAGS+=$(QJSC_HOST_DEFINES)
|
||||
|
||||
qjs32: $(patsubst %.o, %.m32.o, $(QJS_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
|
||||
|
||||
qjs32_s: $(patsubst %.o, %.m32s.o, $(QJS_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
@size $@
|
||||
|
||||
qjscalc: qjs
|
||||
ln -sf $< $@
|
||||
|
||||
ifdef CONFIG_LTO
|
||||
LTOEXT=.lto
|
||||
else
|
||||
LTOEXT=
|
||||
endif
|
||||
|
||||
libquickjs$(LTOEXT).a: $(QJS_LIB_OBJS)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
ifdef CONFIG_LTO
|
||||
libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS))
|
||||
$(AR) rcs $@ $^
|
||||
endif # CONFIG_LTO
|
||||
|
||||
repl.c: $(QJSC) repl.js
|
||||
$(QJSC) -c -o $@ -m repl.js
|
||||
|
||||
qjscalc.c: $(QJSC) qjscalc.js
|
||||
$(QJSC) -fbignum -c -o $@ qjscalc.js
|
||||
|
||||
ifneq ($(wildcard unicode/UnicodeData.txt),)
|
||||
$(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o \
|
||||
$(OBJDIR)/libunicode.nolto.o: libunicode-table.h
|
||||
|
||||
libunicode-table.h: unicode_gen
|
||||
./unicode_gen unicode $@
|
||||
endif
|
||||
|
||||
run-test262: $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
|
||||
|
||||
run-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
|
||||
|
||||
run-test262-32: $(patsubst %.o, %.m32.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
|
||||
|
||||
# object suffix order: nolto, [m32|m32s]
|
||||
|
||||
$(OBJDIR)/%.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_OPT) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.host.o: %.c | $(OBJDIR)
|
||||
$(HOST_CC) $(CFLAGS_OPT) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.pic.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_OPT) -fPIC -DJS_SHARED_LIBRARY -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.nolto.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_NOLTO) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.m32.o: %.c | $(OBJDIR)
|
||||
$(CC) -m32 $(CFLAGS_OPT) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.m32s.o: %.c | $(OBJDIR)
|
||||
$(CC) -m32 $(CFLAGS_SMALL) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.debug.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_DEBUG) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.check.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -DCONFIG_CHECK_JSVALUE -c -o $@ $<
|
||||
|
||||
regexp_test: libregexp.c libunicode.c cutils.c
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -DTEST -o $@ libregexp.c libunicode.c cutils.c $(LIBS)
|
||||
|
||||
jscompress: jscompress.c
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ jscompress.c
|
||||
|
||||
unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c unicode_gen_def.h
|
||||
$(HOST_CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o
|
||||
|
||||
clean:
|
||||
rm -f repl.c qjscalc.c out.c
|
||||
rm -f *.a *.o *.d *~ jscompress unicode_gen regexp_test $(PROGS)
|
||||
rm -f hello.c hello_module.c test_fib.c
|
||||
rm -f examples/*.so tests/*.so
|
||||
rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug
|
||||
rm -rf run-test262-debug run-test262-32
|
||||
|
||||
install: all
|
||||
mkdir -p "$(DESTDIR)$(prefix)/bin"
|
||||
$(STRIP) qjs qjsc
|
||||
install -m755 qjs qjsc "$(DESTDIR)$(prefix)/bin"
|
||||
ln -sf qjs "$(DESTDIR)$(prefix)/bin/qjscalc"
|
||||
mkdir -p "$(DESTDIR)$(prefix)/lib/quickjs"
|
||||
install -m644 libquickjs.a "$(DESTDIR)$(prefix)/lib/quickjs"
|
||||
ifdef CONFIG_LTO
|
||||
install -m644 libquickjs.lto.a "$(DESTDIR)$(prefix)/lib/quickjs"
|
||||
endif
|
||||
mkdir -p "$(DESTDIR)$(prefix)/include/quickjs"
|
||||
install -m644 quickjs.h quickjs-libc.h "$(DESTDIR)$(prefix)/include/quickjs"
|
||||
|
||||
###############################################################################
|
||||
# examples
|
||||
|
||||
# example of static JS compilation
|
||||
HELLO_SRCS=examples/hello.js
|
||||
HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \
|
||||
-fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
|
||||
-fno-date -fno-module-loader -fno-bigint
|
||||
|
||||
hello.c: $(QJSC) $(HELLO_SRCS)
|
||||
$(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS)
|
||||
|
||||
ifdef CONFIG_M32
|
||||
examples/hello: $(OBJDIR)/hello.m32s.o $(patsubst %.o, %.m32s.o, $(QJS_LIB_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
else
|
||||
examples/hello: $(OBJDIR)/hello.o $(QJS_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
endif
|
||||
|
||||
# example of static JS compilation with modules
|
||||
HELLO_MODULE_SRCS=examples/hello_module.js
|
||||
HELLO_MODULE_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \
|
||||
-fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
|
||||
-fno-date -m
|
||||
examples/hello_module: $(QJSC) libquickjs$(LTOEXT).a $(HELLO_MODULE_SRCS)
|
||||
$(QJSC) $(HELLO_MODULE_OPTS) -o $@ $(HELLO_MODULE_SRCS)
|
||||
|
||||
# use of an external C module (static compilation)
|
||||
|
||||
test_fib.c: $(QJSC) examples/test_fib.js
|
||||
$(QJSC) -e -M examples/fib.so,fib -m -o $@ examples/test_fib.js
|
||||
|
||||
examples/test_fib: $(OBJDIR)/test_fib.o $(OBJDIR)/examples/fib.o libquickjs$(LTOEXT).a
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
examples/fib.so: $(OBJDIR)/examples/fib.pic.o
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^
|
||||
|
||||
examples/point.so: $(OBJDIR)/examples/point.pic.o
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^
|
||||
|
||||
###############################################################################
|
||||
# documentation
|
||||
|
||||
DOCS=doc/quickjs.pdf doc/quickjs.html doc/jsbignum.pdf doc/jsbignum.html
|
||||
|
||||
build_doc: $(DOCS)
|
||||
|
||||
clean_doc:
|
||||
rm -f $(DOCS)
|
||||
|
||||
doc/%.pdf: doc/%.texi
|
||||
texi2pdf --clean -o $@ -q $<
|
||||
|
||||
doc/%.html.pre: doc/%.texi
|
||||
makeinfo --html --no-headers --no-split --number-sections -o $@ $<
|
||||
|
||||
doc/%.html: doc/%.html.pre
|
||||
sed -e 's|</style>|</style>\n<meta name="viewport" content="width=device-width, initial-scale=1.0">|' < $< > $@
|
||||
|
||||
###############################################################################
|
||||
# tests
|
||||
|
||||
ifndef CONFIG_DARWIN
|
||||
test: tests/bjson.so examples/point.so
|
||||
endif
|
||||
ifdef CONFIG_M32
|
||||
test: qjs32
|
||||
endif
|
||||
|
||||
test: qjs
|
||||
./qjs tests/test_closure.js
|
||||
./qjs tests/test_op.js
|
||||
./qjs tests/test_builtin.js
|
||||
./qjs tests/test_loop.js
|
||||
./qjs tests/test_std.js
|
||||
ifndef CONFIG_DARWIN
|
||||
./qjs --bignum tests/test_bjson.js
|
||||
./qjs examples/test_point.js
|
||||
endif
|
||||
./qjs --bignum tests/test_bignum.js
|
||||
./qjs --qjscalc tests/test_qjscalc.js
|
||||
ifdef CONFIG_M32
|
||||
./qjs32 tests/test_closure.js
|
||||
./qjs32 tests/test_op.js
|
||||
./qjs32 tests/test_builtin.js
|
||||
./qjs32 tests/test_loop.js
|
||||
./qjs32 tests/test_std.js
|
||||
./qjs32 --bignum tests/test_bignum.js
|
||||
./qjs32 --qjscalc tests/test_qjscalc.js
|
||||
endif
|
||||
|
||||
stats: qjs qjs32
|
||||
./qjs -qd
|
||||
./qjs32 -qd
|
||||
|
||||
microbench: qjs
|
||||
./qjs tests/microbench.js
|
||||
|
||||
microbench-32: qjs32
|
||||
./qjs32 tests/microbench.js
|
||||
|
||||
# ES5 tests (obsolete)
|
||||
test2o: run-test262
|
||||
time ./run-test262 -m -c test262o.conf
|
||||
|
||||
test2o-32: run-test262-32
|
||||
time ./run-test262-32 -m -c test262o.conf
|
||||
|
||||
test2o-update: run-test262
|
||||
./run-test262 -u -c test262o.conf
|
||||
|
||||
# Test262 tests
|
||||
test2-default: run-test262
|
||||
time ./run-test262 -m -c test262.conf
|
||||
|
||||
test2: run-test262
|
||||
time ./run-test262 -m -c test262.conf -a
|
||||
|
||||
test2-32: run-test262-32
|
||||
time ./run-test262-32 -m -c test262.conf -a
|
||||
|
||||
test2-update: run-test262
|
||||
./run-test262 -u -c test262.conf -a
|
||||
|
||||
test2-check: run-test262
|
||||
time ./run-test262 -m -c test262.conf -E -a
|
||||
|
||||
testall: all test microbench test2o test2
|
||||
|
||||
testall-32: all test-32 microbench-32 test2o-32 test2-32
|
||||
|
||||
testall-complete: testall testall-32
|
||||
|
||||
bench-v8: qjs
|
||||
make -C tests/bench-v8
|
||||
./qjs -d tests/bench-v8/combined.js
|
||||
|
||||
tests/bjson.so: $(OBJDIR)/tests/bjson.pic.o
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS)
|
||||
|
||||
-include $(wildcard $(OBJDIR)/*.d)
|
78
TODO
Normal file
78
TODO
Normal file
@ -0,0 +1,78 @@
|
||||
Misc:
|
||||
- use custom printf to avoid C library compatibility issues
|
||||
- rename CONFIG_ALL_UNICODE, CONFIG_BIGNUM, CONFIG_ATOMICS, CONFIG_CHECK_JSVALUE ?
|
||||
- unify coding style and naming conventions
|
||||
- use names from the ECMA spec in library implementation
|
||||
- modules: if no ".", use a well known module loading path ?
|
||||
- use JSHoistedDef only for global variables (JSHoistedDef.var_name != JS_ATOM_NULL)
|
||||
- add index in JSVarDef and is_arg flag to merge args and vars in JSFunctionDef
|
||||
- replace most JSVarDef flags with var_type enumeration
|
||||
- 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:
|
||||
- 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
|
||||
- bignum: handle memory errors
|
||||
- use memory pools for objects, etc?
|
||||
- improve JS_ComputeMemoryUsage() with more info
|
||||
|
||||
Optimizations:
|
||||
- 64-bit atoms in 64-bit mode ?
|
||||
- use auto-init properties for more global objects
|
||||
- reuse stack slots for disjoint scopes, if strip
|
||||
- optimize `for of` iterator for built-in array objects
|
||||
- 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
|
||||
- optimize function storage with length and name accessors?
|
||||
- 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
|
||||
- comparative performance benchmark
|
||||
- use variable name when throwing uninitialized exception if available
|
||||
- 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)
|
||||
|
||||
Extensions:
|
||||
- support more features in [features] section
|
||||
- add built-in preprocessor in compiler, get rid of jscompress
|
||||
handle #if, #ifdef, #line, limited support for #define
|
||||
- get rid of __loadScript, use more common name
|
||||
- BSD sockets
|
||||
- Workers
|
||||
|
||||
REPL:
|
||||
- debugger
|
||||
- readline: support MS Windows terminal
|
||||
- readline: handle dynamic terminal resizing
|
||||
- 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
|
||||
|
||||
Test262o: 0/11262 errors, 463 excluded
|
||||
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
|
||||
|
||||
Test262: 4/67619 errors, 913 excluded, 1660 skipped
|
||||
Test262bn: 4/69722 errors, 846 excluded, 672 skipped
|
||||
test262 commit: 19fd4bea797646ae9bbfc9d325f14052ca370b54
|
620
cutils.c
Normal file
620
cutils.c
Normal file
@ -0,0 +1,620 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cutils.h"
|
||||
|
||||
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 */
|
||||
|
||||
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)
|
||||
{
|
||||
memset(s, 0, 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 __attribute__((format(printf, 2, 3))) 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);
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
}
|
||||
|
||||
/* 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 ... 0xdf:
|
||||
l = 1;
|
||||
break;
|
||||
case 0xe0 ... 0xef:
|
||||
l = 2;
|
||||
break;
|
||||
case 0xf0 ... 0xf7:
|
||||
l = 3;
|
||||
break;
|
||||
case 0xf8 ... 0xfb:
|
||||
l = 4;
|
||||
break;
|
||||
case 0xfc ... 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
|
293
cutils.h
Normal file
293
cutils.h
Normal file
@ -0,0 +1,293 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef CUTILS_H
|
||||
#define CUTILS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/* set if CPU is big endian */
|
||||
#undef WORDS_BIGENDIAN
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#define force_inline inline __attribute__((always_inline))
|
||||
#define no_inline __attribute__((noinline))
|
||||
#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 offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
#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 *buf, int buf_size, const char *str);
|
||||
char *pstrcat(char *buf, int buf_size, const char *s);
|
||||
int strstart(const char *str, const char *val, const char **ptr);
|
||||
int has_suffix(const char *str, const char *suffix);
|
||||
|
||||
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 */
|
||||
static inline int clz32(unsigned int a)
|
||||
{
|
||||
return __builtin_clz(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int clz64(uint64_t a)
|
||||
{
|
||||
return __builtin_clzll(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int ctz32(unsigned int a)
|
||||
{
|
||||
return __builtin_ctz(a);
|
||||
}
|
||||
|
||||
/* WARNING: undefined if a = 0 */
|
||||
static inline int ctz64(uint64_t a)
|
||||
{
|
||||
return __builtin_ctzll(a);
|
||||
}
|
||||
|
||||
struct __attribute__((packed)) packed_u64 {
|
||||
uint64_t v;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) packed_u32 {
|
||||
uint32_t v;
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) 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;
|
||||
}
|
||||
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
|
||||
static inline uint32_t bswap32(uint32_t v)
|
||||
{
|
||||
return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
|
||||
((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
|
||||
}
|
||||
|
||||
static inline uint64_t bswap64(uint64_t v)
|
||||
{
|
||||
return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
|
||||
((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
|
||||
((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
|
||||
((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
|
||||
((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
|
||||
((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
|
||||
((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
|
||||
((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
|
||||
}
|
||||
|
||||
/* 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 *s);
|
||||
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
|
||||
int dbuf_realloc(DynBuf *s, size_t new_size);
|
||||
int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len);
|
||||
int dbuf_put(DynBuf *s, const uint8_t *data, size_t len);
|
||||
int dbuf_put_self(DynBuf *s, size_t offset, size_t len);
|
||||
int dbuf_putc(DynBuf *s, uint8_t c);
|
||||
int dbuf_putstr(DynBuf *s, const char *str);
|
||||
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);
|
||||
}
|
||||
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
|
||||
const char *fmt, ...);
|
||||
void dbuf_free(DynBuf *s);
|
||||
static inline BOOL dbuf_error(DynBuf *s) {
|
||||
return s->error;
|
||||
}
|
||||
|
||||
#define UTF8_CHAR_LEN_MAX 6
|
||||
|
||||
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 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);
|
||||
|
||||
#endif /* CUTILS_H */
|
1045
doc/jsbignum.html
Normal file
1045
doc/jsbignum.html
Normal file
File diff suppressed because it is too large
Load Diff
BIN
doc/jsbignum.pdf
Normal file
BIN
doc/jsbignum.pdf
Normal file
Binary file not shown.
835
doc/jsbignum.texi
Normal file
835
doc/jsbignum.texi
Normal file
@ -0,0 +1,835 @@
|
||||
\input texinfo
|
||||
|
||||
@iftex
|
||||
@afourpaper
|
||||
@headings double
|
||||
@end iftex
|
||||
|
||||
@titlepage
|
||||
@afourpaper
|
||||
@sp 7
|
||||
@center @titlefont{Javascript Bignum Extensions}
|
||||
@sp 3
|
||||
@center Version 2018-06-16
|
||||
@sp 3
|
||||
@center Author: Fabrice Bellard
|
||||
@end titlepage
|
||||
|
||||
@setfilename spec.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 Overloading of the standard operators
|
||||
to support new types such as complex numbers, fractions or matrices.
|
||||
|
||||
@item Bigint mode where arbitrarily large integers are available by default (no @code{n} suffix is necessary as in the TC39 BigInt proposal@footnote{@url{https://tc39.github.io/proposal-bigint/}}).
|
||||
|
||||
@item Arbitrarily large floating point numbers (@code{BigFloat}) in base 2 using the IEEE 754 semantics.
|
||||
|
||||
@item Optional @code{math} mode which modifies the semantics of the division, modulo and power operator. The division and power operator return a fraction with integer operands and the modulo operator is defined as the Euclidian remainder.
|
||||
|
||||
@end itemize
|
||||
|
||||
The extensions are independent from each other except the @code{math}
|
||||
mode which relies on the bigint mode and the operator overloading.
|
||||
|
||||
@chapter Operator overloading
|
||||
|
||||
@section Introduction
|
||||
|
||||
If the operands of an operator have at least one object type, a custom
|
||||
operator method is searched before doing the legacy Javascript
|
||||
@code{ToNumber} conversion.
|
||||
|
||||
For unary operators, the custom function is looked up in the object
|
||||
and has the following name:
|
||||
|
||||
@table @code
|
||||
@item unary +
|
||||
@code{Symbol.operatorPlus}
|
||||
|
||||
@item unary -
|
||||
@code{Symbol.operatorNeg}
|
||||
|
||||
@item ++
|
||||
@code{Symbol.operatorInc}
|
||||
|
||||
@item --
|
||||
@code{Symbol.operatorDec}
|
||||
|
||||
@item ~
|
||||
@code{Symbol.operatorNot}
|
||||
|
||||
@end table
|
||||
|
||||
For binary operators:
|
||||
|
||||
@itemize
|
||||
|
||||
@item
|
||||
If both operands have the same constructor function, then the operator
|
||||
is looked up in the constructor.
|
||||
|
||||
@item
|
||||
Otherwise, the property @code{Symbol.operatorOrder} is looked up in both
|
||||
constructors and converted to @code{Int32}. The operator is then
|
||||
looked in the constructor with the larger @code{Symbol.operatorOrder}
|
||||
value. A @code{TypeError} is raised if both constructors have the same
|
||||
@code{Symbol.operatorOrder} value.
|
||||
|
||||
@end itemize
|
||||
|
||||
The operator is looked up with the following name:
|
||||
|
||||
@table @code
|
||||
@item +
|
||||
@code{Symbol.operatorAdd}
|
||||
|
||||
@item -
|
||||
@code{Symbol.operatorSub}
|
||||
|
||||
@item *
|
||||
@code{Symbol.operatorMul}
|
||||
|
||||
@item /
|
||||
@code{Symbol.operatorDiv}
|
||||
|
||||
@item %
|
||||
@code{Symbol.operatorMod}
|
||||
|
||||
@item % (math mode)
|
||||
@code{Symbol.operatorMathMod}
|
||||
|
||||
@item **
|
||||
@code{Symbol.operatorPow}
|
||||
|
||||
@item |
|
||||
@code{Symbol.operatorOr}
|
||||
|
||||
@item ^
|
||||
@code{Symbol.operatorXor}
|
||||
|
||||
@item &
|
||||
@code{Symbol.operatorAnd}
|
||||
|
||||
@item <<
|
||||
@code{Symbol.operatorShl}
|
||||
|
||||
@item >>
|
||||
@code{Symbol.operatorShr}
|
||||
|
||||
@item <
|
||||
@code{Symbol.operatorCmpLT}
|
||||
|
||||
@item >
|
||||
@code{Symbol.operatorCmpLT}, operands swapped
|
||||
|
||||
@item <=
|
||||
@code{Symbol.operatorCmpLE}
|
||||
|
||||
@item >=
|
||||
@code{Symbol.operatorCmpLE}, operands swapped
|
||||
|
||||
@item ==, !=
|
||||
@code{Symbol.operatorCmpEQ}
|
||||
|
||||
@end table
|
||||
|
||||
The return value of @code{Symbol.operatorCmpLT}, @code{Symbol.operatorCmpLE} and
|
||||
@code{Symbol.operatorCmpEQ} is converted to @code{Boolean}.
|
||||
|
||||
@section Builtin Object changes
|
||||
|
||||
@subsection @code{Symbol} constructor
|
||||
|
||||
The following global symbols are added for the operator overloading:
|
||||
@table @code
|
||||
@item operatorOrder
|
||||
@item operatorAdd
|
||||
@item operatorSub
|
||||
@item operatorMul
|
||||
@item operatorDiv
|
||||
@item operatorMod
|
||||
@item operatorPow
|
||||
@item operatorShl
|
||||
@item operatorShr
|
||||
@item operatorAnd
|
||||
@item operatorOr
|
||||
@item operatorXor
|
||||
@item operatorCmpLT
|
||||
@item operatorCmpLE
|
||||
@item operatorCmpEQ
|
||||
@item operatorPlus
|
||||
@item operatorNeg
|
||||
@item operatorNot
|
||||
@item operatorInc
|
||||
@item operatorDec
|
||||
@end table
|
||||
|
||||
|
||||
@chapter The BigInt Mode
|
||||
|
||||
@section Introduction
|
||||
|
||||
The bigint mode is enabled with the @code{"use bigint"} directive. It
|
||||
propagates the same way as the strict mode. In bigint mode, all
|
||||
integers are considered as @code{bigint} (arbitrarily large integer,
|
||||
similar to the TC39 BigInt
|
||||
proposal@footnote{@url{https://tc39.github.io/proposal-bigint/}})
|
||||
instead of @code{number} (floating point number). In order to be able
|
||||
to exchange data between standard and bigint modes, numbers are
|
||||
internally represented as 3 different types:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Small integer (SmallInt): 32 bit integer@footnote{Could be extended to 53 bits without changing the principle.}.
|
||||
|
||||
@item Big integer (BigInt): arbitrarily large integer.
|
||||
|
||||
@item Floating point number (Float).
|
||||
|
||||
@end itemize
|
||||
|
||||
In standard mode, the semantics of each operation is modified so that
|
||||
when it returns a @code{number}, it is either of SmallInt or
|
||||
Float. But the difference between SmallInt and Float is not observable
|
||||
in standard mode.
|
||||
|
||||
In bigint mode, each operation behaves differently whether its
|
||||
operands are integer or float. The difference between SmallInt and
|
||||
BigInt is not observable (i.e. they are both integers).
|
||||
|
||||
The following table summarizes the observable types:
|
||||
|
||||
@multitable @columnfractions .3 .3 .3
|
||||
@headitem Internal type @tab Observable type@* (standard mode) @tab Observable type@* (bigint mode)
|
||||
@item SmallInt @tab number @tab bigint
|
||||
@item BigInt @tab bigint @tab bigint
|
||||
@item Float @tab number @tab number
|
||||
@end multitable
|
||||
|
||||
@section Changes that introduce incompatibilities with Javascript
|
||||
|
||||
@subsection Standard mode
|
||||
|
||||
There is no incompatibility with Javascript.
|
||||
|
||||
@subsection Bigint mode
|
||||
|
||||
The following changes are visible:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Integer and Float are different types. Constants are typed. For example: @code{typeof 1.0 === "number"} and @code{typeof 1 === "bigint"}. Another consequence is that @code{1.0 === 1} is false.
|
||||
|
||||
@item The range of integers is unlimited. In standard mode: @code{2**53 + 1 === 2**53}. This is no longer true with the bignum extensions.
|
||||
|
||||
@item Binary bitwise operators do not truncate to 32 bits i.e. @code{0x800000000 | 1 === 0x800000001} while it gives @code{1} in standard mode.
|
||||
|
||||
@item Bitwise shift operators do not truncate to 32 bits and do not mask the shift count with @code{0x1f} i.e. @code{1 << 32 === 4294967296} while it gives @code{1} in standard mode. However, the @code{>>>} operator (unsigned right shift) which is useless with bignums keeps its standard mode behavior@footnote{The unsigned right right operator could be removed in bigint mode.}.
|
||||
|
||||
@item Operators with integer operands never return the minus zero floating point value as result. Hence @code{Object.is(0, -0) === true}. Use @code{-0.0} to create a minus zero floating point value.
|
||||
|
||||
@item The @code{ToPrimitive} abstract operation is called with the @code{"integer"} preferred type when an integer is required (e.g. for bitwise binary or shift operations).
|
||||
|
||||
@item The prototype of integers is no longer @code{Number.prototype}. Instead@* @code{Object.getPrototypeOf(1) === BigInt.prototype}. The prototype of floats remains Number.prototype.
|
||||
|
||||
@item If the TC39 BigInt proposal is supported, there is no observable difference between integers and @code{bigint}s.
|
||||
|
||||
@end itemize
|
||||
|
||||
@section Operators
|
||||
|
||||
@subsection Arithmetic operators
|
||||
|
||||
The operands are converted to number values as in normal
|
||||
Javascript. Then the general case is that an Integer is returned if
|
||||
both operands are Integer. Otherwise, a float is returned.
|
||||
|
||||
The @code{+} operator also accepts strings as input and behaves like
|
||||
standard Javascript in this case.
|
||||
|
||||
The binary operator @code{%} returns the truncated remainder of the
|
||||
division. When the result is an Integer type, a dividend of zero yields a
|
||||
RangeError exception.
|
||||
|
||||
The binary operator @code{%} in math mode returns the Euclidian
|
||||
remainder of the division i.e. it is always positive.
|
||||
|
||||
The binary operator @code{/} returns a float.
|
||||
|
||||
The binary operator @code{/} in math mode returns a float if one of
|
||||
the operands is float. Otherwise, @code{BigInt[Symbol.operatorDiv]} is
|
||||
invoked.
|
||||
|
||||
The returned type of @code{a ** b} is Float if @math{a} or @math{b}
|
||||
are Float. If @math{a} and @math{b} are integers:
|
||||
@itemize
|
||||
@item @math{b < 0} returns a Float in bigint mode. In math mode, @code{BigInt[Symbol.operatorPow]} is invoked.
|
||||
|
||||
@item @math{b >= 0} returns an integer.
|
||||
@end itemize
|
||||
|
||||
The unary @code{-} and unary @code{+} return the same type as their
|
||||
operand. They performs no floating point rounding when the result is a
|
||||
float.
|
||||
|
||||
The unary operators @code{++} and @code{--} return the same type as
|
||||
their operand.
|
||||
|
||||
In standard mode:
|
||||
|
||||
If the operator returns an Integer and that the result fits a
|
||||
SmallInt, it is converted to SmallInt. Otherwise, the Integer is
|
||||
converted to a Float.
|
||||
|
||||
In bigint mode:
|
||||
|
||||
If the operator returns an Integer and that the result fits a
|
||||
SmallInt, it is converted to SmallInt. Otherwise it is a BigInt.
|
||||
|
||||
@subsection Logical operators
|
||||
|
||||
In standard mode:
|
||||
|
||||
The operands have their standard behavior. If the result fits a
|
||||
SmallInt it is converted to a SmallInt. Otherwise it is a Float.
|
||||
|
||||
In bigint mode:
|
||||
|
||||
The operands are converted to integer values. The floating point
|
||||
values are converted to integer by rounding them to zero.
|
||||
|
||||
The logical operators are defined assuming the integers are
|
||||
represented in two complement notation.
|
||||
|
||||
For @code{<<} and @code{<<}, the shift can be positive or negative. So
|
||||
@code{a << b} is defined as @math{\lfloor a/2^{-b} \rfloor} and
|
||||
@code{a >> b} is defined as @math{\lfloor a/2^{b} \rfloor}.
|
||||
|
||||
The operator @code{>>>} is supported for backward compatibility and
|
||||
behaves the same way as Javascript i.e. implicit conversion to @code{Uint32}.
|
||||
|
||||
If the result fits a SmallInt it is converted to a SmallInt. Otherwise
|
||||
it is a BigInt.
|
||||
|
||||
@subsection Relational operators
|
||||
|
||||
The relational operators <, <=, >, >=, ==, != work as expected with
|
||||
integers and floating point numbers (e.g. @code{1.0 == 1} is true).
|
||||
|
||||
The strict equality operators === and !== have the usual Javascript
|
||||
semantics. In particular, different types never equal, so @code{1.0
|
||||
=== 1} is false.
|
||||
|
||||
@section Number literals
|
||||
|
||||
Number literals in bigint mode have a slightly different behavior than
|
||||
in standard Javascript:
|
||||
|
||||
@enumerate
|
||||
|
||||
@item
|
||||
A number literal without a decimal point or an exponent is considered
|
||||
as an Integer. Otherwise it is a Float.
|
||||
|
||||
@item
|
||||
Hexadecimal, octal or binary floating point literals are accepted with
|
||||
a decimal point or an exponent. The exponent is specified with the
|
||||
@code{p} letter assuming a base 2. The same convention is used by
|
||||
C99. Example: @code{0x1p3} is the same as @code{8.0}.
|
||||
|
||||
@end enumerate
|
||||
|
||||
@section Builtin Object changes
|
||||
|
||||
@subsection @code{BigInt} function
|
||||
|
||||
The @code{BigInt} function cannot be invoked as a constructor. When
|
||||
invoked as a function, it converts its first parameter to an
|
||||
integer. When a floating point number is given as parameter, it is
|
||||
truncated to an integer with infinite precision.
|
||||
|
||||
@code{BigInt} properties:
|
||||
|
||||
@table @code
|
||||
|
||||
@item asIntN(bits, a)
|
||||
Set @math{b=a \pmod{2^{bits}}}. Return @math{b} if @math{b < 2^{bits-1}}
|
||||
otherwise @math{b-2^{bits}}.
|
||||
|
||||
@item asUintN(bits, a)
|
||||
Return @math{a \pmod{2^{bits}}}.
|
||||
|
||||
@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
|
||||
|
||||
@subsection @code{BigInt.prototype}
|
||||
|
||||
It is a normal object.
|
||||
|
||||
@subsection @code{Number} constructor
|
||||
|
||||
The number constructor returns its argument rounded to a Float using
|
||||
the global floating point environment. In bigint mode, the Number
|
||||
constructor returns a Float. In standard mode, it returns a SmallInt
|
||||
if the value fits it, otherwise a Float.
|
||||
|
||||
@subsection @code{Number.prototype}
|
||||
|
||||
The following properties are modified:
|
||||
|
||||
@table @code
|
||||
@item toString(radix)
|
||||
|
||||
In bigint mode, integers are converted to the specified radix with
|
||||
infinite precision.
|
||||
|
||||
@item toPrecision(p)
|
||||
@item toFixed(p)
|
||||
@item toExponential(p)
|
||||
|
||||
In bigint mode, integers are accepted and converted to string with
|
||||
infinite precision.
|
||||
|
||||
@item parseInt(string, radix)
|
||||
|
||||
In bigint mode, an integer is returned and the conversion is done with
|
||||
infinite precision.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection @code{Math} object
|
||||
|
||||
The following properties are modified:
|
||||
|
||||
@table @code
|
||||
@item abs(x)
|
||||
Absolute value. Return an integer if @code{x} is an Integer. Otherwise
|
||||
return a Float. No rounding is performed.
|
||||
|
||||
@item min(a, b)
|
||||
@item max(a, b)
|
||||
No rounding is performed. The returned type is the same one as the
|
||||
minimum (resp. maximum) value.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter Arbitrarily large floating point numbers
|
||||
|
||||
@section Introduction
|
||||
|
||||
This extension adds the @code{BigFloat} primitive type. The
|
||||
@code{BigFloat} type represents floating point numbers are 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}. If @code{BigFloatEnv.expBits} is
|
||||
strictly smaller than the maximum allowed number of exponent bits
|
||||
(@code{BigFloatEnv.expBitsMax}), then the global environment subnormal
|
||||
flag is set to @code{true}. Otherwise it is set to @code{false};
|
||||
|
||||
For example, @code{prec = 53} and @code{ expBits = 11} give exactly
|
||||
the same precision as the IEEE 754 64 bit floating point. The
|
||||
default precision is @code{prec = 113} and @code{ expBits = 15} (IEEE
|
||||
754 128 bit floating point).
|
||||
|
||||
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 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 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
|
||||
|
||||
@item toPrecision(p[, rnd_mode])
|
||||
@item toFixed(p[, rnd_mode])
|
||||
@item toExponential(p[, rnd_mode])
|
||||
Same semantics as the corresponding @code{Number} functions with
|
||||
BigFloats. There is no limit on the accepted precision @code{p}. The
|
||||
rounding mode can be optionally specified. It is set by default to
|
||||
@code{BigFloatEnv.RNDNA}.
|
||||
|
||||
@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{53}.
|
||||
|
||||
@item expBits
|
||||
Getter. Return the exponent size in bits of the global floating point
|
||||
environment assuming an IEEE 754 representation. If @code{expBits <
|
||||
expBitsMax}, then subnormal numbers are supported. The initial value
|
||||
is @code{11}.
|
||||
|
||||
@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}. @code{p}
|
||||
must be >= 53 and @code{e} must be >= 11 so that the global precision
|
||||
is at least equivalent to the IEEE 754 64 bit doubles.
|
||||
|
||||
@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 53.
|
||||
|
||||
@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 11.
|
||||
|
||||
@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 RNDNU
|
||||
Read-only integer. Round to nearest, with ties to +Infinity 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
|
||||
|
||||
@subsection @code{Math} object
|
||||
|
||||
The following properties are modified:
|
||||
|
||||
@table @code
|
||||
@item abs(x)
|
||||
Absolute value. If @code{x} is a BigFloat, its absolute value is
|
||||
returned as a BigFloat. No rounding is performed.
|
||||
|
||||
@item min(a, b)
|
||||
@item max(a, b)
|
||||
The returned type is the same one as the minimum (resp. maximum)
|
||||
value, so @code{BigFloat} values are accepted. When a @code{BigFloat}
|
||||
is returned, no rounding is performed.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter Math mode
|
||||
|
||||
@section Introduction
|
||||
|
||||
A new @emph{math mode} is enabled with the @code{"use math"}
|
||||
directive. @code{"use bigint"} is implied in math mode. With this
|
||||
mode, writing mathematical expressions is more intuitive, exact
|
||||
results (e.g. fractions) can be computed for all operators and floating
|
||||
point literals have the @code{BigFloat} type by default.
|
||||
|
||||
It propagates the same way as the @emph{strict mode}. In
|
||||
this mode:
|
||||
|
||||
@itemize
|
||||
|
||||
@item The @code{^} operator is a similar 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 division operator invokes @code{BigInt[Symbol.operatorDiv]} in case both operands are integers.
|
||||
|
||||
@item The power operator invokes @code{BigInt[Symbol.operatorPow]} in case both operands are integers and the exponent is strictly negative.
|
||||
|
||||
@item The modulo operator returns the Euclidian remainder (always positive) instead of the truncated remainder.
|
||||
|
||||
@item Floating point literals are @code{BigFloat} by default (i.e. a @code{l} suffix is implied).
|
||||
|
||||
@end itemize
|
||||
|
||||
@section Builtin Object changes
|
||||
|
||||
@subsection @code{Symbol} constructor
|
||||
|
||||
The following global symbol is added for the operator overloading:
|
||||
@table @code
|
||||
@item operatorMathMod
|
||||
@end table
|
||||
|
||||
@section Remaining issues
|
||||
|
||||
@enumerate
|
||||
|
||||
@item A new floating point literal suffix could be added for @code{Number} literals.
|
||||
|
||||
@end enumerate
|
||||
|
||||
@bye
|
1254
doc/quickjs.html
Normal file
1254
doc/quickjs.html
Normal file
File diff suppressed because it is too large
Load Diff
BIN
doc/quickjs.pdf
Normal file
BIN
doc/quickjs.pdf
Normal file
Binary file not shown.
983
doc/quickjs.texi
Normal file
983
doc/quickjs.texi
Normal file
@ -0,0 +1,983 @@
|
||||
\input texinfo
|
||||
|
||||
@iftex
|
||||
@afourpaper
|
||||
@headings double
|
||||
@end iftex
|
||||
|
||||
@titlepage
|
||||
@afourpaper
|
||||
@sp 7
|
||||
@center @titlefont{QuickJS Javascript Engine}
|
||||
@sp 3
|
||||
@end titlepage
|
||||
|
||||
@setfilename spec.info
|
||||
@settitle QuickJS Javascript Engine
|
||||
|
||||
@contents
|
||||
|
||||
@chapter Introduction
|
||||
|
||||
QuickJS is a small and embeddable Javascript engine. It supports the
|
||||
upcoming ES2020 specification
|
||||
@footnote{@url{https://www.ecma-international.org/ecma-262/10.0}}
|
||||
including modules, asynchronous generators, proxies and BigInt.
|
||||
|
||||
It supports mathematical extensions such as big decimal float float
|
||||
numbers (BigDecimal), big binary floating point numbers (BigFloat),
|
||||
and operator overloading.
|
||||
|
||||
@section Main Features
|
||||
|
||||
@itemize
|
||||
|
||||
@item Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple ``hello world'' program.
|
||||
|
||||
@item Fast interpreter with very low startup time: runs the 69000 tests of the ECMAScript Test Suite@footnote{@url{https://github.com/tc39/test262}} in about 95 seconds on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds.
|
||||
|
||||
@item Almost complete ES2019 support including modules, asynchronous
|
||||
generators and full Annex B support (legacy web compatibility). Many
|
||||
features from the upcoming ES2020 specification
|
||||
@footnote{@url{https://tc39.github.io/ecma262/}} are also supported.
|
||||
|
||||
@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2019 features.
|
||||
|
||||
@item Compile Javascript sources to executables with no external dependency.
|
||||
|
||||
@item Garbage collection using reference counting (to reduce memory usage and have deterministic behavior) with cycle removal.
|
||||
|
||||
@item Mathematical extensions: BigDecimal, BigFloat, operator overloading, bigint mode, math mode.
|
||||
|
||||
@item Command line interpreter with contextual colorization and completion implemented in Javascript.
|
||||
|
||||
@item Small built-in standard library with C library wrappers.
|
||||
|
||||
@end itemize
|
||||
|
||||
@chapter Usage
|
||||
|
||||
@section Installation
|
||||
|
||||
A Makefile is provided to compile the engine on Linux or MacOS/X. A
|
||||
preliminary Windows support is available thru cross compilation on a
|
||||
Linux host with the MingGW tools.
|
||||
|
||||
Edit the top of the @code{Makefile} if you wish to select specific
|
||||
options then run @code{make}.
|
||||
|
||||
You can type @code{make install} as root if you wish to install the binaries and support files to
|
||||
@code{/usr/local} (this is not necessary to use QuickJS).
|
||||
|
||||
@section Quick start
|
||||
|
||||
@code{qjs} is the command line interpreter (Read-Eval-Print Loop). You can pass
|
||||
Javascript files and/or expressions as arguments to execute them:
|
||||
|
||||
@example
|
||||
./qjs examples/hello.js
|
||||
@end example
|
||||
|
||||
@code{qjsc} is the command line compiler:
|
||||
|
||||
@example
|
||||
./qjsc -o hello examples/hello.js
|
||||
./hello
|
||||
@end example
|
||||
|
||||
generates a @code{hello} executable with no external dependency.
|
||||
|
||||
@section Command line options
|
||||
|
||||
@subsection @code{qjs} interpreter
|
||||
|
||||
@verbatim
|
||||
usage: qjs [options] [files]
|
||||
@end verbatim
|
||||
|
||||
Options are:
|
||||
@table @code
|
||||
@item -h
|
||||
@item --help
|
||||
List options.
|
||||
|
||||
@item -e @code{EXPR}
|
||||
@item --eval @code{EXPR}
|
||||
Evaluate EXPR.
|
||||
|
||||
@item -i
|
||||
@item --interactive
|
||||
Go to interactive mode (it is not the default when files are provided on the command line).
|
||||
|
||||
@item -m
|
||||
@item --module
|
||||
Load as ES6 module (default=autodetect). A module is autodetected if
|
||||
the filename extension is @code{.mjs} or if the first keyword of the
|
||||
source is @code{import}.
|
||||
|
||||
@item --script
|
||||
Load as ES6 script (default=autodetect).
|
||||
|
||||
@item --bignum
|
||||
Enable the bignum extensions: BigDecimal object, BigFloat object and
|
||||
the @code{"use bigint"} and @code{"use math"} directives.
|
||||
|
||||
@end table
|
||||
|
||||
Advanced options are:
|
||||
|
||||
@table @code
|
||||
@item --std
|
||||
Make the @code{std} and @code{os} modules available to the loaded
|
||||
script even if it is not a module.
|
||||
|
||||
@item -d
|
||||
@item --dump
|
||||
Dump the memory usage stats.
|
||||
|
||||
@item -q
|
||||
@item --quit
|
||||
just instantiate the interpreter and quit.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection @code{qjsc} compiler
|
||||
|
||||
@verbatim
|
||||
usage: qjsc [options] [files]
|
||||
@end verbatim
|
||||
|
||||
Options are:
|
||||
@table @code
|
||||
@item -c
|
||||
Only output bytecode in a C file. The default is to output an executable file.
|
||||
@item -e
|
||||
Output @code{main()} and bytecode in a C file. The default is to output an
|
||||
executable file.
|
||||
@item -o output
|
||||
Set the output filename (default = @file{out.c} or @file{a.out}).
|
||||
|
||||
@item -N cname
|
||||
Set the C name of the generated data.
|
||||
|
||||
@item -m
|
||||
Compile as Javascript module (default=autodetect).
|
||||
|
||||
@item -M module_name[,cname]
|
||||
Add initialization code for an external C module. See the
|
||||
@code{c_module} example.
|
||||
|
||||
@item -x
|
||||
Byte swapped output (only used for cross compilation).
|
||||
|
||||
@item -flto
|
||||
Use link time optimization. The compilation is slower but the
|
||||
executable is smaller and faster. This option is automatically set
|
||||
when the @code{-fno-x} options are used.
|
||||
|
||||
@item -fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint]
|
||||
Disable selected language features to produce a smaller executable file.
|
||||
|
||||
@item -fbignum
|
||||
Enable the bignum extensions: BigDecimal object, BigFloat object and
|
||||
the @code{"use bigint"} and @code{"use math"} directives.
|
||||
|
||||
@end table
|
||||
|
||||
@section @code{qjscalc} application
|
||||
|
||||
The @code{qjscalc} application is a superset of the @code{qjs}
|
||||
command line interpreter implementing a Javascript calculator with
|
||||
arbitrarily large integer and floating point numbers, fractions,
|
||||
complex numbers, polynomials and matrices. The source code is in
|
||||
@file{qjscalc.js}. More documentation and a web version are available at
|
||||
@url{http://numcalc.com}.
|
||||
|
||||
@section Built-in tests
|
||||
|
||||
Run @code{make test} to run the few built-in tests included in the
|
||||
QuickJS archive.
|
||||
|
||||
@section Test262 (ECMAScript Test Suite)
|
||||
|
||||
A test262 runner is included in the QuickJS archive. The test262 tests
|
||||
can be installed in the QuickJS source directory with:
|
||||
|
||||
@example
|
||||
git clone https://github.com/tc39/test262.git test262
|
||||
cd test262
|
||||
patch -p1 < ../tests/test262.patch
|
||||
cd ..
|
||||
@end example
|
||||
|
||||
The patch adds the implementation specific @code{harness} functions
|
||||
and optimizes the inefficient RegExp character classes and Unicode
|
||||
property escapes tests (the tests themselves are not modified, only a
|
||||
slow string initialization function is optimized).
|
||||
|
||||
The tests can be run with
|
||||
@example
|
||||
make test2
|
||||
@end example
|
||||
|
||||
The configuration files @code{test262.conf}
|
||||
(resp. @code{test262o.conf} for the old ES5.1 tests@footnote{The old
|
||||
ES5.1 tests can be extracted with @code{git clone --single-branch
|
||||
--branch es5-tests https://github.com/tc39/test262.git test262o}}))
|
||||
contain the options to run the various tests. Tests can be excluded
|
||||
based on features or filename.
|
||||
|
||||
The file @code{test262_errors.txt} contains the current list of
|
||||
errors. The runner displays a message when a new error appears or when
|
||||
an existing error is corrected or modified. Use the @code{-u} option
|
||||
to update the current list of errors (or @code{make test2-update}).
|
||||
|
||||
The file @code{test262_report.txt} contains the logs of all the
|
||||
tests. It is useful to have a clearer analysis of a particular
|
||||
error. In case of crash, the last line corresponds to the failing
|
||||
test.
|
||||
|
||||
Use the syntax @code{./run-test262 -c test262.conf -f filename.js} to
|
||||
run a single test. Use the syntax @code{./run-test262 -c test262.conf
|
||||
N} to start testing at test number @code{N}.
|
||||
|
||||
For more information, run @code{./run-test262} to see the command line
|
||||
options of the test262 runner.
|
||||
|
||||
@code{run-test262} accepts the @code{-N} option to be invoked from
|
||||
@code{test262-harness}@footnote{@url{https://github.com/bterlson/test262-harness}}
|
||||
thru @code{eshost}. Unless you want to compare QuickJS with other
|
||||
engines under the same conditions, we do not recommend to run the
|
||||
tests this way as it is much slower (typically half an hour instead of
|
||||
about 100 seconds).
|
||||
|
||||
@chapter Specifications
|
||||
|
||||
@section Language support
|
||||
|
||||
@subsection ES2019 support
|
||||
|
||||
The ES2019 specification is almost fully supported including the Annex
|
||||
B (legacy web compatibility) and the Unicode related features.
|
||||
|
||||
The following features are not supported yet:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Realms (although the C API supports different runtimes and contexts)
|
||||
|
||||
@item Tail calls@footnote{We believe the current specification of tails calls is too complicated and presents limited practical interests.}
|
||||
|
||||
@end itemize
|
||||
|
||||
@subsection JSON
|
||||
|
||||
The JSON parser is currently more tolerant than the specification.
|
||||
|
||||
@subsection ECMA402
|
||||
|
||||
ECMA402 (Internationalization API) is not supported.
|
||||
|
||||
@subsection Extensions
|
||||
|
||||
@itemize
|
||||
|
||||
@item The directive @code{"use strip"} indicates that the debug information (including the source code of the functions) should not be retained to save memory. As @code{"use strict"}, the directive can be global to a script or local to a function.
|
||||
|
||||
@item The first line of a script beginning with @code{#!} is ignored.
|
||||
|
||||
@end itemize
|
||||
|
||||
@subsection Mathematical extensions
|
||||
|
||||
The mathematical extensions are fully backward compatible with
|
||||
standard Javascript. See @code{jsbignum.pdf} for more information.
|
||||
|
||||
@itemize
|
||||
|
||||
@item @code{BigDecimal} support: arbitrary large floating point numbers in base 10.
|
||||
|
||||
@item @code{BigFloat} support: arbitrary large floating point numbers in base 2.
|
||||
|
||||
@item Operator overloading.
|
||||
|
||||
@item The directive @code{"use bigint"} enables the bigint mode where integers are @code{BigInt} by default.
|
||||
|
||||
@item The directive @code{"use math"} enables the math mode where the division and power operators on integers produce fractions. Floating point literals are @code{BigFloat} by default and integers are @code{BigInt} by default.
|
||||
|
||||
@end itemize
|
||||
|
||||
@section Modules
|
||||
|
||||
ES6 modules are fully supported. The default name resolution is the
|
||||
following:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Module names with a leading @code{.} or @code{..} are relative
|
||||
to the current module path.
|
||||
|
||||
@item Module names without a leading @code{.} or @code{..} are system
|
||||
modules, such as @code{std} or @code{os}.
|
||||
|
||||
@item Module names ending with @code{.so} are native modules using the
|
||||
QuickJS C API.
|
||||
|
||||
@end itemize
|
||||
|
||||
@section Standard library
|
||||
|
||||
The standard library is included by default in the command line
|
||||
interpreter. It contains the two modules @code{std} and @code{os} and
|
||||
a few global objects.
|
||||
|
||||
@subsection Global objects
|
||||
|
||||
@table @code
|
||||
@item scriptArgs
|
||||
Provides the command line arguments. The first argument is the script name.
|
||||
@item print(...args)
|
||||
Print the arguments separated by spaces and a trailing newline.
|
||||
@item console.log(...args)
|
||||
Same as print().
|
||||
|
||||
@end table
|
||||
|
||||
@subsection @code{std} module
|
||||
|
||||
The @code{std} module provides wrappers to the libc @file{stdlib.h}
|
||||
and @file{stdio.h} and a few other utilities.
|
||||
|
||||
Available exports:
|
||||
|
||||
@table @code
|
||||
|
||||
@item exit(n)
|
||||
Exit the process.
|
||||
|
||||
@item evalScript(str, options = undefined)
|
||||
Evaluate the string @code{str} as a script (global
|
||||
eval). @code{options} is an optional object containing the following
|
||||
optional properties:
|
||||
|
||||
@table @code
|
||||
@item backtrace_barrier
|
||||
Boolean (default = false). If true, error backtraces do not list the
|
||||
stack frames below the evalScript.
|
||||
@end table
|
||||
|
||||
@item loadScript(filename)
|
||||
Evaluate the file @code{filename} as a script (global eval).
|
||||
|
||||
@item Error(errno)
|
||||
|
||||
@code{std.Error} constructor. Error instances contain the field
|
||||
@code{errno} (error code) and @code{message} (result of
|
||||
@code{std.Error.strerror(errno)}).
|
||||
|
||||
The constructor contains the following fields:
|
||||
|
||||
@table @code
|
||||
@item EINVAL
|
||||
@item EIO
|
||||
@item EACCES
|
||||
@item EEXIST
|
||||
@item ENOSPC
|
||||
@item ENOSYS
|
||||
@item EBUSY
|
||||
@item ENOENT
|
||||
@item EPERM
|
||||
@item EPIPE
|
||||
Integer value of common errors (additional error codes may be defined).
|
||||
@item strerror(errno)
|
||||
Return a string that describes the error @code{errno}.
|
||||
@end table
|
||||
|
||||
@item open(filename, flags)
|
||||
Open a file (wrapper to the libc @code{fopen()}). Throws
|
||||
@code{std.Error} in case of I/O error.
|
||||
|
||||
@item popen(command, flags)
|
||||
Open a process by creating a pipe (wrapper to the libc @code{popen()}). Throws
|
||||
@code{std.Error} in case of I/O error.
|
||||
|
||||
@item fdopen(fd, flags)
|
||||
Open a file from a file handle (wrapper to the libc
|
||||
@code{fdopen()}). Throws @code{std.Error} in case of I/O error.
|
||||
|
||||
@item tmpfile()
|
||||
Open a temporary file. Throws @code{std.Error} in case of I/O error.
|
||||
|
||||
@item puts(str)
|
||||
Equivalent to @code{std.out.puts(str)}.
|
||||
|
||||
@item printf(fmt, ...args)
|
||||
Equivalent to @code{std.out.printf(fmt, ...args)}
|
||||
|
||||
@item sprintf(fmt, ...args)
|
||||
Equivalent to the libc sprintf().
|
||||
|
||||
@item in
|
||||
@item out
|
||||
@item err
|
||||
Wrappers to the libc file @code{stdin}, @code{stdout}, @code{stderr}.
|
||||
|
||||
@item SEEK_SET
|
||||
@item SEEK_CUR
|
||||
@item SEEK_END
|
||||
Constants for seek().
|
||||
|
||||
@item gc()
|
||||
Manually invoke the cycle removal algorithm. The cycle removal
|
||||
algorithm is automatically started when needed, so this function is
|
||||
useful in case of specific memory constraints or for testing.
|
||||
|
||||
@item getenv(name)
|
||||
Return the value of the environment variable @code{name} or
|
||||
@code{undefined} if it is not defined.
|
||||
|
||||
@item urlGet(url, options = undefined)
|
||||
|
||||
Download @code{url} using the @file{curl} command line
|
||||
utility. @code{options} is an optional object containing the following
|
||||
optional properties:
|
||||
|
||||
@table @code
|
||||
@item binary
|
||||
Boolean (default = false). If true, the response is an ArrayBuffer
|
||||
instead of a string. When a string is returned, the data is assumed
|
||||
to be UTF-8 encoded.
|
||||
|
||||
@item full
|
||||
Boolean (default = false). If true, return the an object contains
|
||||
the properties @code{response} (response content),
|
||||
@code{responseHeaders} (headers separated by CRLF), @code{status}
|
||||
(status code). If @code{full} is false, only the response is
|
||||
returned if the status is between 200 and 299. Otherwise an
|
||||
@code{std.Error} exception is raised.
|
||||
|
||||
@end table
|
||||
|
||||
@end table
|
||||
|
||||
FILE prototype:
|
||||
|
||||
@table @code
|
||||
@item close()
|
||||
Close the file.
|
||||
@item puts(str)
|
||||
Outputs the string with the UTF-8 encoding.
|
||||
@item printf(fmt, ...args)
|
||||
Formatted printf, same formats as the libc printf.
|
||||
@item flush()
|
||||
Flush the buffered file.
|
||||
@item seek(offset, whence)
|
||||
Seek to a give file position (whence is @code{std.SEEK_*}). Throws a
|
||||
@code{std.Error} in case of I/O error.
|
||||
@item tell()
|
||||
Return the current file position.
|
||||
@item eof()
|
||||
Return true if end of file.
|
||||
@item fileno()
|
||||
Return the associated OS handle.
|
||||
|
||||
@item read(buffer, position, length)
|
||||
Read @code{length} bytes from the file to the ArrayBuffer @code{buffer} at byte
|
||||
position @code{position} (wrapper to the libc @code{fread}).
|
||||
|
||||
@item write(buffer, position, length)
|
||||
Write @code{length} bytes to the file from the ArrayBuffer @code{buffer} at byte
|
||||
position @code{position} (wrapper to the libc @code{fread}).
|
||||
|
||||
@item getline()
|
||||
Return the next line from the file, assuming UTF-8 encoding, excluding
|
||||
the trailing line feed.
|
||||
|
||||
@item readAsString(max_size = undefined)
|
||||
Read @code{max_size} bytes from the file and return them as a string
|
||||
assuming UTF-8 encoding. If @code{max_size} is not present, the file
|
||||
is read up its end.
|
||||
|
||||
@item getByte()
|
||||
Return the next byte from the file. Return -1 if the end of file is reached.
|
||||
|
||||
@item putByte(c)
|
||||
Write one byte to the file.
|
||||
@end table
|
||||
|
||||
@subsection @code{os} module
|
||||
|
||||
The @code{os} module provides Operating System specific functions:
|
||||
|
||||
@itemize
|
||||
@item low level file access
|
||||
@item signals
|
||||
@item timers
|
||||
@item asynchronous I/O
|
||||
@end itemize
|
||||
|
||||
The OS functions usually return 0 if OK or an OS specific negative
|
||||
error code.
|
||||
|
||||
Available exports:
|
||||
|
||||
@table @code
|
||||
@item open(filename, flags, mode = 0o666)
|
||||
Open a file. Return a handle or < 0 if error.
|
||||
|
||||
@item O_RDONLY
|
||||
@item O_WRONLY
|
||||
@item O_RDWR
|
||||
@item O_APPEND
|
||||
@item O_CREAT
|
||||
@item O_EXCL
|
||||
@item O_TRUNC
|
||||
POSIX open flags.
|
||||
|
||||
@item O_TEXT
|
||||
(Windows specific). Open the file in text mode. The default is binary mode.
|
||||
|
||||
@item close(fd)
|
||||
Close the file handle @code{fd}.
|
||||
|
||||
@item seek(fd, offset, whence)
|
||||
Seek in the file. Use @code{std.SEEK_*} for @code{whence}.
|
||||
|
||||
@item read(fd, buffer, offset, length)
|
||||
Read @code{length} bytes from the file handle @code{fd} to the
|
||||
ArrayBuffer @code{buffer} at byte position @code{offset}.
|
||||
Return the number of read bytes or < 0 if error.
|
||||
|
||||
@item write(fd, buffer, offset, length)
|
||||
Write @code{length} bytes to the file handle @code{fd} from the
|
||||
ArrayBuffer @code{buffer} at byte position @code{offset}.
|
||||
Return the number of written bytes or < 0 if error.
|
||||
|
||||
@item isatty(fd)
|
||||
Return @code{true} is @code{fd} is a TTY (terminal) handle.
|
||||
|
||||
@item ttyGetWinSize(fd)
|
||||
Return the TTY size as @code{[width, height]} or @code{null} if not available.
|
||||
|
||||
@item ttySetRaw(fd)
|
||||
Set the TTY in raw mode.
|
||||
|
||||
@item remove(filename)
|
||||
Remove a file. Return 0 if OK or < 0 if error.
|
||||
|
||||
@item rename(oldname, newname)
|
||||
Rename a file. Return 0 if OK or < 0 if error.
|
||||
|
||||
@item realpath(path)
|
||||
Return @code{[str, err]} where @code{str} is the canonicalized absolute
|
||||
pathname of @code{path} and @code{err} the error code.
|
||||
|
||||
@item getcwd()
|
||||
Return @code{[str, err]} where @code{str} is the current working directory
|
||||
and @code{err} the error code.
|
||||
|
||||
@item mkdir(path, mode = 0o777)
|
||||
Create a directory at @code{path}. Return the error code.
|
||||
|
||||
@item stat(path)
|
||||
@item lstat(path)
|
||||
|
||||
Return @code{[obj, err]} where @code{obj} is an object containing the
|
||||
file status of @code{path}. @code{err} is the error code. The
|
||||
following fields are defined in @code{obj}: dev, ino, mode, nlink,
|
||||
uid, gid, rdev, size, blocks, atime, mtime, ctime. The times are
|
||||
specified in milliseconds since 1970. @code{lstat()} is the same as
|
||||
@code{stat()} excepts that it returns information about the link
|
||||
itself.
|
||||
|
||||
@item S_IFMT
|
||||
@item S_IFIFO
|
||||
@item S_IFCHR
|
||||
@item S_IFDIR
|
||||
@item S_IFBLK
|
||||
@item S_IFREG
|
||||
@item S_IFSOCK
|
||||
@item S_IFLNK
|
||||
@item S_ISGID
|
||||
@item S_ISUID
|
||||
Constants to interpret the @code{mode} property returned by
|
||||
@code{stat()}. They have the same value as in the C system header
|
||||
@file{sys/stat.h}.
|
||||
|
||||
@item utimes(path, atime, mtime)
|
||||
Change the access and modification times of the file @code{path}. The
|
||||
times are specified in milliseconds since 1970.
|
||||
|
||||
@item symlink(target, linkpath)
|
||||
Create a link at @code{linkpath} containing the string @code{target}.
|
||||
|
||||
@item readlink(path)
|
||||
Return @code{[str, err]} where @code{str} is the link target and @code{err}
|
||||
the error code.
|
||||
|
||||
@item readdir(path)
|
||||
Return @code{[array, err]} where @code{array} is an array of strings
|
||||
containing the filenames of the directory @code{path}. @code{err} is
|
||||
the error code.
|
||||
|
||||
@item setReadHandler(fd, func)
|
||||
Add a read handler to the file handle @code{fd}. @code{func} is called
|
||||
each time there is data pending for @code{fd}. A single read handler
|
||||
per file handle is supported. Use @code{func = null} to remove the
|
||||
handler.
|
||||
|
||||
@item setWriteHandler(fd, func)
|
||||
Add a write handler to the file handle @code{fd}. @code{func} is
|
||||
called each time data can be written to @code{fd}. A single write
|
||||
handler per file handle is supported. Use @code{func = null} to remove
|
||||
the handler.
|
||||
|
||||
@item signal(signal, func)
|
||||
Call the function @code{func} when the signal @code{signal}
|
||||
happens. Only a single handler per signal number is supported. Use
|
||||
@code{null} to set the default handler or @code{undefined} to ignore
|
||||
the signal.
|
||||
|
||||
@item SIGINT
|
||||
@item SIGABRT
|
||||
@item SIGFPE
|
||||
@item SIGILL
|
||||
@item SIGSEGV
|
||||
@item SIGTERM
|
||||
POSIX signal numbers.
|
||||
|
||||
@item kill(pid, sig)
|
||||
Send the signal @code{sig} to the process @code{pid}.
|
||||
|
||||
@item exec(args[, options])
|
||||
Execute a process with the arguments @code{args}. @code{options} is an
|
||||
object containing optional parameters:
|
||||
|
||||
@table @code
|
||||
@item block
|
||||
Boolean (default = true). If true, wait until the process is
|
||||
terminated. In this case, @code{exec} return the exit code if positive
|
||||
or the negated signal number if the process was interrupted by a
|
||||
signal. If false, do not block and return the process id of the child.
|
||||
|
||||
@item usePath
|
||||
Boolean (default = true). If true, the file is searched in the
|
||||
@code{PATH} environment variable.
|
||||
|
||||
@item file
|
||||
String (default = @code{args[0]}). Set the file to be executed.
|
||||
|
||||
@item cwd
|
||||
String. If present, set the working directory of the new process.
|
||||
|
||||
@item stdin
|
||||
@item stdout
|
||||
@item stderr
|
||||
If present, set the handle in the child for stdin, stdout or stderr.
|
||||
|
||||
@end table
|
||||
|
||||
@item waitpid(pid, options)
|
||||
@code{waitpid} Unix system call. Return the array @code{[ret, status]}.
|
||||
|
||||
@item WNOHANG
|
||||
Constant for the @code{options} argument of @code{waitpid}.
|
||||
|
||||
@item dup(fd)
|
||||
@code{dup} Unix system call.
|
||||
|
||||
@item dup2(oldfd, newfd)
|
||||
@code{dup2} Unix system call.
|
||||
|
||||
@item pipe()
|
||||
@code{pipe} Unix system call. Return two handles as @code{[read_fd,
|
||||
write_fd]} or null in case of error.
|
||||
|
||||
@item sleep(delay_ms)
|
||||
Sleep during @code{delay_ms} milliseconds.
|
||||
|
||||
@item setTimeout(func, delay)
|
||||
Call the function @code{func} after @code{delay} ms. Return a handle
|
||||
to the timer.
|
||||
|
||||
@item clearTimeout(handle)
|
||||
Cancel a timer.
|
||||
|
||||
@item platform
|
||||
Return a string representing the platform: @code{"linux"}, @code{"darwin"},
|
||||
@code{"win32"} or @code{"js"}.
|
||||
|
||||
@end table
|
||||
|
||||
@section QuickJS C API
|
||||
|
||||
The C API was designed to be simple and efficient. The C API is
|
||||
defined in the header @code{quickjs.h}.
|
||||
|
||||
@subsection Runtime and contexts
|
||||
|
||||
@code{JSRuntime} represents a Javascript runtime corresponding to an
|
||||
object heap. Several runtimes can exist at the same time but they
|
||||
cannot exchange objects. Inside a given runtime, no multi-threading is
|
||||
supported.
|
||||
|
||||
@code{JSContext} represents a Javascript context (or Realm). Each
|
||||
JSContext has its own global objects and system objects. There can be
|
||||
several JSContexts per JSRuntime and they can share objects, similar
|
||||
to frames of the same origin sharing Javascript objects in a
|
||||
web browser.
|
||||
|
||||
@subsection JSValue
|
||||
|
||||
@code{JSValue} represents a Javascript value which can be a primitive
|
||||
type or an object. Reference counting is used, so it is important to
|
||||
explicitly duplicate (@code{JS_DupValue()}, increment the reference
|
||||
count) or free (@code{JS_FreeValue()}, decrement the reference count)
|
||||
JSValues.
|
||||
|
||||
@subsection C functions
|
||||
|
||||
C functions can be created with
|
||||
@code{JS_NewCFunction()}. @code{JS_SetPropertyFunctionList()} is a
|
||||
shortcut to easily add functions, setters and getters properties to a
|
||||
given object.
|
||||
|
||||
Unlike other embedded Javascript engines, there is no implicit stack,
|
||||
so C functions get their parameters as normal C parameters. As a
|
||||
general rule, C functions take constant @code{JSValue}s as parameters
|
||||
(so they don't need to free them) and return a newly allocated (=live)
|
||||
@code{JSValue}.
|
||||
|
||||
@subsection Exceptions
|
||||
|
||||
Exceptions: most C functions can return a Javascript exception. It
|
||||
must be explicitly tested and handled by the C code. The specific
|
||||
@code{JSValue} @code{JS_EXCEPTION} indicates that an exception
|
||||
occurred. The actual exception object is stored in the
|
||||
@code{JSContext} and can be retrieved with @code{JS_GetException()}.
|
||||
|
||||
@subsection Script evaluation
|
||||
|
||||
Use @code{JS_Eval()} to evaluate a script or module source.
|
||||
|
||||
If the script or module was compiled to bytecode with @code{qjsc}, it
|
||||
can be evaluated by calling @code{js_std_eval_binary()}. The advantage
|
||||
is that no compilation is needed so it is faster and smaller because
|
||||
the compiler can be removed from the executable if no @code{eval} is
|
||||
required.
|
||||
|
||||
Note: the bytecode format is linked to a given QuickJS
|
||||
version. Moreover, no security check is done before its
|
||||
execution. Hence the bytecode should not be loaded from untrusted
|
||||
sources. That's why there is no option to output the bytecode to a
|
||||
binary file in @code{qjsc}.
|
||||
|
||||
@subsection JS Classes
|
||||
|
||||
C opaque data can be attached to a Javascript object. The type of the
|
||||
C opaque data is determined with the class ID (@code{JSClassID}) of
|
||||
the object. Hence the first step is to register a new class ID and JS
|
||||
class (@code{JS_NewClassID()}, @code{JS_NewClass()}). Then you can
|
||||
create objects of this class with @code{JS_NewObjectClass()} and get or
|
||||
set the C opaque point with
|
||||
@code{JS_GetOpaque()}/@code{JS_SetOpaque()}.
|
||||
|
||||
When defining a new JS class, it is possible to declare a finalizer
|
||||
which is called when the object is destroyed. A @code{gc_mark} method
|
||||
can be provided so that the cycle removal algorithm can find the other
|
||||
objects referenced by this object. Other methods are available to
|
||||
define exotic object behaviors.
|
||||
|
||||
The Class ID are globally allocated (i.e. for all runtimes). The
|
||||
JSClass are allocated per @code{JSRuntime}. @code{JS_SetClassProto()}
|
||||
is used to define a prototype for a given class in a given
|
||||
JSContext. @code{JS_NewObjectClass()} sets this prototype in the
|
||||
created object.
|
||||
|
||||
Examples are available in @file{quickjs-libc.c}.
|
||||
|
||||
@subsection C Modules
|
||||
|
||||
Native ES6 modules are supported and can be dynamically or statically
|
||||
linked. Look at the @file{test_bjson} and @file{bjson.so}
|
||||
examples. The standard library @file{quickjs-libc.c} is also a good example
|
||||
of a native module.
|
||||
|
||||
@subsection Memory handling
|
||||
|
||||
Use @code{JS_SetMemoryLimit()} to set a global memory allocation limit
|
||||
to a given JSRuntime.
|
||||
|
||||
Custom memory allocation functions can be provided with
|
||||
@code{JS_NewRuntime2()}.
|
||||
|
||||
The maximum system stack size can be set with @code{JS_SetMaxStackSize()}.
|
||||
|
||||
@subsection Execution timeout and interrupts
|
||||
|
||||
Use @code{JS_SetInterruptHandler()} to set a callback which is
|
||||
regularly called by the engine when it is executing code. This
|
||||
callback can be used to implement an execution timeout.
|
||||
|
||||
It is used by the command line interpreter to implement a
|
||||
@code{Ctrl-C} handler.
|
||||
|
||||
@chapter Internals
|
||||
|
||||
@section Bytecode
|
||||
|
||||
The compiler generates bytecode directly with no intermediate
|
||||
representation such as a parse tree, hence it is very fast. Several
|
||||
optimizations passes are done over the generated bytecode.
|
||||
|
||||
A stack-based bytecode was chosen because it is simple and generates
|
||||
compact code.
|
||||
|
||||
For each function, the maximum stack size is computed at compile time so that
|
||||
no runtime stack overflow tests are needed.
|
||||
|
||||
A separate compressed line number table is maintained for the debug
|
||||
information.
|
||||
|
||||
Access to closure variables is optimized and is almost as fast as local
|
||||
variables.
|
||||
|
||||
Direct @code{eval} in strict mode is optimized.
|
||||
|
||||
@section Executable generation
|
||||
|
||||
@subsection @code{qjsc} compiler
|
||||
|
||||
The @code{qjsc} compiler generates C sources from Javascript files. By
|
||||
default the C sources are compiled with the system compiler
|
||||
(@code{gcc} or @code{clang}).
|
||||
|
||||
The generated C source contains the bytecode of the compiled functions
|
||||
or modules. If a full complete executable is needed, it also
|
||||
contains a @code{main()} function with the necessary C code to initialize the
|
||||
Javascript engine and to load and execute the compiled functions and
|
||||
modules.
|
||||
|
||||
Javascript code can be mixed with C modules.
|
||||
|
||||
In order to have smaller executables, specific Javascript features can
|
||||
be disabled, in particular @code{eval} or the regular expressions. The
|
||||
code removal relies on the Link Time Optimization of the system
|
||||
compiler.
|
||||
|
||||
@subsection Binary JSON
|
||||
|
||||
@code{qjsc} works by compiling scripts or modules and then serializing
|
||||
them to a binary format. A subset of this format (without functions or
|
||||
modules) can be used as binary JSON. The example @file{test_bjson.js}
|
||||
shows how to use it.
|
||||
|
||||
Warning: the binary JSON format may change without notice, so it
|
||||
should not be used to store persistent data. The @file{test_bjson.js}
|
||||
example is only used to test the binary object format functions.
|
||||
|
||||
@section Runtime
|
||||
|
||||
@subsection Strings
|
||||
|
||||
Strings are stored either as an 8 bit or a 16 bit array of
|
||||
characters. Hence random access to characters is always fast.
|
||||
|
||||
The C API provides functions to convert Javascript Strings to C UTF-8 encoded
|
||||
strings. The most common case where the Javascript string contains
|
||||
only ASCII characters involves no copying.
|
||||
|
||||
@subsection Objects
|
||||
|
||||
The object shapes (object prototype, property names and flags) are shared
|
||||
between objects to save memory.
|
||||
|
||||
Arrays with no holes (except at the end of the array) are optimized.
|
||||
|
||||
TypedArray accesses are optimized.
|
||||
|
||||
@subsection Atoms
|
||||
|
||||
Object property names and some strings are stored as Atoms (unique
|
||||
strings) to save memory and allow fast comparison. Atoms are
|
||||
represented as a 32 bit integer. Half of the atom range is reserved for
|
||||
immediate integer literals from @math{0} to @math{2^{31}-1}.
|
||||
|
||||
@subsection Numbers
|
||||
|
||||
Numbers are represented either as 32-bit signed integers or 64-bit IEEE-754
|
||||
floating point values. Most operations have fast paths for the 32-bit
|
||||
integer case.
|
||||
|
||||
@subsection Garbage collection
|
||||
|
||||
Reference counting is used to free objects automatically and
|
||||
deterministically. A separate cycle removal pass is done when the allocated
|
||||
memory becomes too large. The cycle removal algorithm only uses the
|
||||
reference counts and the object content, so no explicit garbage
|
||||
collection roots need to be manipulated in the C code.
|
||||
|
||||
@subsection JSValue
|
||||
|
||||
It is a Javascript value which can be a primitive type (such as
|
||||
Number, String, ...) or an Object. NaN boxing is used in the 32-bit version
|
||||
to store 64-bit floating point numbers. The representation is
|
||||
optimized so that 32-bit integers and reference counted values can be
|
||||
efficiently tested.
|
||||
|
||||
In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The
|
||||
rationale is that in 64-bit code memory usage is less critical.
|
||||
|
||||
In both cases (32 or 64 bits), JSValue exactly fits two CPU registers,
|
||||
so it can be efficiently returned by C functions.
|
||||
|
||||
@subsection Function call
|
||||
|
||||
The engine is optimized so that function calls are fast. The system
|
||||
stack holds the Javascript parameters and local variables.
|
||||
|
||||
@section RegExp
|
||||
|
||||
A specific regular expression engine was developed. It is both small
|
||||
and efficient and supports all the ES2020 features including the
|
||||
Unicode properties. As the Javascript compiler, it directly generates
|
||||
bytecode without a parse tree.
|
||||
|
||||
Backtracking with an explicit stack is used so that there is no
|
||||
recursion on the system stack. Simple quantifiers are specifically
|
||||
optimized to avoid recursions.
|
||||
|
||||
Infinite recursions coming from quantifiers with empty terms are
|
||||
avoided.
|
||||
|
||||
The full regexp library weights about 15 KiB (x86 code), excluding the
|
||||
Unicode library.
|
||||
|
||||
@section Unicode
|
||||
|
||||
A specific Unicode library was developed so that there is no
|
||||
dependency on an external large Unicode library such as ICU. All the
|
||||
Unicode tables are compressed while keeping a reasonable access
|
||||
speed.
|
||||
|
||||
The library supports case conversion, Unicode normalization, Unicode
|
||||
script queries, Unicode general category queries and all Unicode
|
||||
binary properties.
|
||||
|
||||
The full Unicode library weights about 45 KiB (x86 code).
|
||||
|
||||
@section BigInt, BigFloat, BigDecimal
|
||||
|
||||
BigInt, BigFloat and BigDecimal are implemented with the @code{libbf}
|
||||
library@footnote{@url{https://bellard.org/libbf}}. It weights about 90
|
||||
KiB (x86 code) and provides arbitrary precision IEEE 754 floating
|
||||
point operations and transcendental functions with exact rounding.
|
||||
|
||||
@chapter License
|
||||
|
||||
QuickJS is released under the MIT license.
|
||||
|
||||
Unless otherwise specified, the QuickJS sources are copyright Fabrice
|
||||
Bellard and Charlie Gordon.
|
||||
|
||||
@bye
|
72
examples/fib.c
Normal file
72
examples/fib.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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
examples/fib_module.js
Normal file
10
examples/fib_module.js
Normal file
@ -0,0 +1,10 @@
|
||||
/* 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
examples/hello.js
Normal file
1
examples/hello.js
Normal file
@ -0,0 +1 @@
|
||||
console.log("Hello World");
|
6
examples/hello_module.js
Normal file
6
examples/hello_module.js
Normal file
@ -0,0 +1,6 @@
|
||||
/* example of JS module */
|
||||
|
||||
import { fib } from "./fib_module.js";
|
||||
|
||||
console.log("Hello World");
|
||||
console.log("fib(10)=", fib(10));
|
70
examples/pi_bigdecimal.js
Normal file
70
examples/pi_bigdecimal.js
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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 = 13591409d;
|
||||
const CHUD_B = 545140134d;
|
||||
const CHUD_C = 640320d;
|
||||
const CHUD_C3 = 10939058860032000d; /* 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 = (2d * b1 - 1d) * (6d * b1 - 1d) * (6d * b1 - 5d);
|
||||
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 = 0d;
|
||||
}
|
||||
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 / 12d) * 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);
|
||||
r = BigDecimal.round(r, { roundingMode: "down",
|
||||
maximumFractionDigits: n_digits })
|
||||
print(r);
|
||||
})();
|
66
examples/pi_bigfloat.js
Normal file
66
examples/pi_bigfloat.js
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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
examples/pi_bigint.js
Normal file
118
examples/pi_bigint.js
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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
examples/point.c
Normal file
151
examples/point.c
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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));
|
||||
JS_SetClassProto(ctx, js_point_class_id, point_proto);
|
||||
|
||||
point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0);
|
||||
/* set proto.constructor and ctor.prototype */
|
||||
JS_SetConstructor(ctx, point_class, point_proto);
|
||||
|
||||
JS_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
examples/test_fib.js
Normal file
6
examples/test_fib.js
Normal file
@ -0,0 +1,6 @@
|
||||
/* example of JS module importing a C module */
|
||||
|
||||
import { fib } from "./fib.so";
|
||||
|
||||
console.log("Hello World");
|
||||
console.log("fib(10)=", fib(10));
|
40
examples/test_point.js
Normal file
40
examples/test_point.js
Normal file
@ -0,0 +1,40 @@
|
||||
/* 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();
|
918
jscompress.c
Normal file
918
jscompress.c
Normal file
@ -0,0 +1,918 @@
|
||||
/*
|
||||
* Javascript Compressor
|
||||
*
|
||||
* Copyright (c) 2008-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.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cutils.h"
|
||||
|
||||
typedef struct JSToken {
|
||||
int tok;
|
||||
char buf[20];
|
||||
char *str;
|
||||
int len;
|
||||
int size;
|
||||
int line_num; /* line number for start of token */
|
||||
int lines; /* number of embedded linefeeds in token */
|
||||
} JSToken;
|
||||
|
||||
enum {
|
||||
TOK_EOF = 256,
|
||||
TOK_IDENT,
|
||||
TOK_STR1,
|
||||
TOK_STR2,
|
||||
TOK_STR3,
|
||||
TOK_NUM,
|
||||
TOK_COM,
|
||||
TOK_LCOM,
|
||||
};
|
||||
|
||||
void tok_reset(JSToken *tt)
|
||||
{
|
||||
if (tt->str != tt->buf) {
|
||||
free(tt->str);
|
||||
tt->str = tt->buf;
|
||||
tt->size = sizeof(tt->buf);
|
||||
}
|
||||
tt->len = 0;
|
||||
}
|
||||
|
||||
void tok_add_ch(JSToken *tt, int c)
|
||||
{
|
||||
if (tt->len + 1 > tt->size) {
|
||||
tt->size *= 2;
|
||||
if (tt->str == tt->buf) {
|
||||
tt->str = malloc(tt->size);
|
||||
memcpy(tt->str, tt->buf, tt->len);
|
||||
} else {
|
||||
tt->str = realloc(tt->str, tt->size);
|
||||
}
|
||||
}
|
||||
tt->str[tt->len++] = c;
|
||||
}
|
||||
|
||||
FILE *infile;
|
||||
const char *filename;
|
||||
int output_line_num;
|
||||
int line_num;
|
||||
int ch;
|
||||
JSToken tokc;
|
||||
|
||||
int skip_mask;
|
||||
#define DEFINE_MAX 20
|
||||
char *define_tab[DEFINE_MAX];
|
||||
int define_len;
|
||||
|
||||
void error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
if (filename) {
|
||||
fprintf(stderr, "%s:%d: ", filename, line_num);
|
||||
} else {
|
||||
fprintf(stderr, "jscompress: ");
|
||||
}
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void define_symbol(const char *def)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < define_len; i++) {
|
||||
if (!strcmp(tokc.str, define_tab[i]))
|
||||
return;
|
||||
}
|
||||
if (define_len >= DEFINE_MAX)
|
||||
error("too many defines");
|
||||
define_tab[define_len++] = strdup(def);
|
||||
}
|
||||
|
||||
void undefine_symbol(const char *def)
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 0; i < define_len; i++) {
|
||||
if (!strcmp(tokc.str, define_tab[i])) {
|
||||
free(define_tab[i]);
|
||||
} else {
|
||||
define_tab[j++] = define_tab[i];
|
||||
}
|
||||
}
|
||||
define_len = j;
|
||||
}
|
||||
|
||||
const char *find_symbol(const char *def)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < define_len; i++) {
|
||||
if (!strcmp(tokc.str, define_tab[i]))
|
||||
return "1";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void next(void);
|
||||
|
||||
void nextch(void)
|
||||
{
|
||||
ch = fgetc(infile);
|
||||
if (ch == '\n')
|
||||
line_num++;
|
||||
}
|
||||
|
||||
int skip_blanks(void)
|
||||
{
|
||||
for (;;) {
|
||||
next();
|
||||
if (tokc.tok != ' ' && tokc.tok != '\t' &&
|
||||
tokc.tok != TOK_COM && tokc.tok != TOK_LCOM)
|
||||
return tokc.tok;
|
||||
}
|
||||
}
|
||||
|
||||
void parse_directive(void)
|
||||
{
|
||||
int ifdef, mask = skip_mask;
|
||||
/* simplistic preprocessor:
|
||||
#define / #undef / #ifdef / #ifndef / #else / #endif
|
||||
no symbol substitution.
|
||||
*/
|
||||
skip_mask = 0; /* disable skipping to parse preprocessor line */
|
||||
nextch();
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected preprocessing directive after #");
|
||||
|
||||
if (!strcmp(tokc.str, "define")) {
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected identifier after #define");
|
||||
define_symbol(tokc.str);
|
||||
} else if (!strcmp(tokc.str, "undef")) {
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected identifier after #undef");
|
||||
undefine_symbol(tokc.str);
|
||||
} else if ((ifdef = 1, !strcmp(tokc.str, "ifdef")) ||
|
||||
(ifdef = 0, !strcmp(tokc.str, "ifndef"))) {
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected identifier after #ifdef/#ifndef");
|
||||
mask = (mask << 2) | 2 | ifdef;
|
||||
if (find_symbol(tokc.str))
|
||||
mask ^= 1;
|
||||
} else if (!strcmp(tokc.str, "else")) {
|
||||
if (!(mask & 2))
|
||||
error("#else without a #if");
|
||||
mask ^= 1;
|
||||
} else if (!strcmp(tokc.str, "endif")) {
|
||||
if (!(mask & 2))
|
||||
error("#endif without a #if");
|
||||
mask >>= 2;
|
||||
} else {
|
||||
error("unsupported preprocessing directive");
|
||||
}
|
||||
if (skip_blanks() != '\n')
|
||||
error("extra characters on preprocessing line");
|
||||
skip_mask = mask;
|
||||
}
|
||||
|
||||
/* return -1 if invalid char */
|
||||
static int hex_to_num(int ch)
|
||||
{
|
||||
if (ch >= 'a' && ch <= 'f')
|
||||
return ch - 'a' + 10;
|
||||
else if (ch >= 'A' && ch <= 'F')
|
||||
return ch - 'A' + 10;
|
||||
else if (ch >= '0' && ch <= '9')
|
||||
return ch - '0';
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
void next(void)
|
||||
{
|
||||
again:
|
||||
tok_reset(&tokc);
|
||||
tokc.line_num = line_num;
|
||||
tokc.lines = 0;
|
||||
switch(ch) {
|
||||
case EOF:
|
||||
tokc.tok = TOK_EOF;
|
||||
if (skip_mask)
|
||||
error("missing #endif");
|
||||
break;
|
||||
case 'a' ... 'z':
|
||||
case 'A' ... 'Z':
|
||||
case '_':
|
||||
case '$':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
while ((ch >= 'a' && ch <= 'z') ||
|
||||
(ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9') ||
|
||||
(ch == '_' || ch == '$')) {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_IDENT;
|
||||
break;
|
||||
case '.':
|
||||
nextch();
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, '.');
|
||||
goto has_dot;
|
||||
}
|
||||
tokc.tok = '.';
|
||||
break;
|
||||
case '0':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
if (ch == 'x' || ch == 'X') {
|
||||
/* hexa */
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
while ((ch >= 'a' && ch <= 'f') ||
|
||||
(ch >= 'A' && ch <= 'F') ||
|
||||
(ch >= '0' && ch <= '9')) {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_NUM;
|
||||
break;
|
||||
}
|
||||
goto has_digit;
|
||||
|
||||
case '1' ... '9':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
has_digit:
|
||||
/* decimal */
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
if (ch == '.') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
has_dot:
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
if (ch == 'e' || ch == 'E') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
if (ch == '+' || ch == '-') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_NUM;
|
||||
break;
|
||||
case '`':
|
||||
{
|
||||
nextch();
|
||||
while (ch != '`' && ch != EOF) {
|
||||
if (ch == '\\') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
if (ch == EOF) {
|
||||
error("unexpected char after '\\'");
|
||||
}
|
||||
tok_add_ch(&tokc, ch);
|
||||
} else {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
nextch();
|
||||
tok_add_ch(&tokc, 0);
|
||||
tokc.tok = TOK_STR3;
|
||||
}
|
||||
break;
|
||||
case '\"':
|
||||
case '\'':
|
||||
{
|
||||
int n, i, c, hex_digit_count;
|
||||
int quote_ch;
|
||||
quote_ch = ch;
|
||||
nextch();
|
||||
while (ch != quote_ch && ch != EOF) {
|
||||
if (ch == '\\') {
|
||||
nextch();
|
||||
switch(ch) {
|
||||
case 'n':
|
||||
tok_add_ch(&tokc, '\n');
|
||||
nextch();
|
||||
break;
|
||||
case 'r':
|
||||
tok_add_ch(&tokc, '\r');
|
||||
nextch();
|
||||
break;
|
||||
case 't':
|
||||
tok_add_ch(&tokc, '\t');
|
||||
nextch();
|
||||
break;
|
||||
case 'v':
|
||||
tok_add_ch(&tokc, '\v');
|
||||
nextch();
|
||||
break;
|
||||
case '\"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
break;
|
||||
case '0' ... '7':
|
||||
n = 0;
|
||||
while (ch >= '0' && ch <= '7') {
|
||||
n = n * 8 + (ch - '0');
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, n);
|
||||
break;
|
||||
case 'x':
|
||||
case 'u':
|
||||
if (ch == 'x')
|
||||
hex_digit_count = 2;
|
||||
else
|
||||
hex_digit_count = 4;
|
||||
nextch();
|
||||
n = 0;
|
||||
for(i = 0; i < hex_digit_count; i++) {
|
||||
c = hex_to_num(ch);
|
||||
if (c < 0)
|
||||
error("unexpected char after '\\x'");
|
||||
n = n * 16 + c;
|
||||
nextch();
|
||||
}
|
||||
if (n >= 256)
|
||||
error("unicode is currently unsupported");
|
||||
tok_add_ch(&tokc, n);
|
||||
break;
|
||||
|
||||
default:
|
||||
error("unexpected char after '\\'");
|
||||
}
|
||||
} else {
|
||||
/* XXX: should refuse embedded newlines */
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
nextch();
|
||||
tok_add_ch(&tokc, 0);
|
||||
if (quote_ch == '\'')
|
||||
tokc.tok = TOK_STR1;
|
||||
else
|
||||
tokc.tok = TOK_STR2;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
nextch();
|
||||
if (ch == '/') {
|
||||
tok_add_ch(&tokc, '/');
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
while (ch != '\n' && ch != EOF) {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_LCOM;
|
||||
} else if (ch == '*') {
|
||||
int last;
|
||||
tok_add_ch(&tokc, '/');
|
||||
tok_add_ch(&tokc, ch);
|
||||
last = 0;
|
||||
for(;;) {
|
||||
nextch();
|
||||
if (ch == EOF)
|
||||
error("unterminated comment");
|
||||
if (ch == '\n')
|
||||
tokc.lines++;
|
||||
tok_add_ch(&tokc, ch);
|
||||
if (last == '*' && ch == '/')
|
||||
break;
|
||||
last = ch;
|
||||
}
|
||||
nextch();
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_COM;
|
||||
} else {
|
||||
tokc.tok = '/';
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
parse_directive();
|
||||
goto again;
|
||||
case '\n':
|
||||
/* adjust line number */
|
||||
tokc.line_num--;
|
||||
tokc.lines++;
|
||||
/* fall thru */
|
||||
default:
|
||||
tokc.tok = ch;
|
||||
nextch();
|
||||
break;
|
||||
}
|
||||
if (skip_mask & 1)
|
||||
goto again;
|
||||
}
|
||||
|
||||
void print_tok(FILE *f, JSToken *tt)
|
||||
{
|
||||
/* keep output lines in sync with input lines */
|
||||
while (output_line_num < tt->line_num) {
|
||||
putc('\n', f);
|
||||
output_line_num++;
|
||||
}
|
||||
|
||||
switch(tt->tok) {
|
||||
case TOK_IDENT:
|
||||
case TOK_COM:
|
||||
case TOK_LCOM:
|
||||
fprintf(f, "%s", tt->str);
|
||||
break;
|
||||
case TOK_NUM:
|
||||
{
|
||||
unsigned long a;
|
||||
char *p;
|
||||
a = strtoul(tt->str, &p, 0);
|
||||
if (*p == '\0' && a <= 0x7fffffff) {
|
||||
/* must be an integer */
|
||||
fprintf(f, "%d", (int)a);
|
||||
} else {
|
||||
fprintf(f, "%s", tt->str);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TOK_STR3:
|
||||
fprintf(f, "`%s`", tt->str);
|
||||
break;
|
||||
case TOK_STR1:
|
||||
case TOK_STR2:
|
||||
{
|
||||
int i, c, quote_ch;
|
||||
if (tt->tok == TOK_STR1)
|
||||
quote_ch = '\'';
|
||||
else
|
||||
quote_ch = '\"';
|
||||
fprintf(f, "%c", quote_ch);
|
||||
for(i = 0; i < tt->len - 1; i++) {
|
||||
c = (uint8_t)tt->str[i];
|
||||
switch(c) {
|
||||
case '\r':
|
||||
fprintf(f, "\\r");
|
||||
break;
|
||||
case '\n':
|
||||
fprintf(f, "\\n");
|
||||
break;
|
||||
case '\t':
|
||||
fprintf(f, "\\t");
|
||||
break;
|
||||
case '\v':
|
||||
fprintf(f, "\\v");
|
||||
break;
|
||||
case '\"':
|
||||
case '\'':
|
||||
if (c == quote_ch)
|
||||
fprintf(f, "\\%c", c);
|
||||
else
|
||||
fprintf(f, "%c", c);
|
||||
break;
|
||||
case '\\':
|
||||
fprintf(f, "\\\\");
|
||||
break;
|
||||
default:
|
||||
/* XXX: no utf-8 support! */
|
||||
if (c >= 32 && c <= 255) {
|
||||
fprintf(f, "%c", c);
|
||||
} else if (c <= 255)
|
||||
fprintf(f, "\\x%02x", c);
|
||||
else
|
||||
fprintf(f, "\\u%04x", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(f, "%c", quote_ch);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (tokc.tok >= 256)
|
||||
error("unsupported token in print_tok: %d", tt->tok);
|
||||
fprintf(f, "%c", tt->tok);
|
||||
break;
|
||||
}
|
||||
output_line_num += tt->lines;
|
||||
}
|
||||
|
||||
/* check if token pasting could occur */
|
||||
static BOOL compat_token(int c1, int c2)
|
||||
{
|
||||
if ((c1 == TOK_IDENT || c1 == TOK_NUM) &&
|
||||
(c2 == TOK_IDENT || c2 == TOK_NUM))
|
||||
return FALSE;
|
||||
|
||||
if ((c1 == c2 && strchr("+-<>&|=*/.", c1))
|
||||
|| (c2 == '=' && strchr("+-<>&|!*/^%", c1))
|
||||
|| (c1 == '=' && c2 == '>')
|
||||
|| (c1 == '/' && c2 == '*')
|
||||
|| (c1 == '.' && c2 == TOK_NUM)
|
||||
|| (c1 == TOK_NUM && c2 == '.'))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void js_compress(const char *filename, const char *outfilename,
|
||||
BOOL do_strip, BOOL keep_header)
|
||||
{
|
||||
FILE *outfile;
|
||||
int ltok, seen_space;
|
||||
|
||||
line_num = 1;
|
||||
infile = fopen(filename, "rb");
|
||||
if (!infile) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
output_line_num = 1;
|
||||
outfile = fopen(outfilename, "wb");
|
||||
if (!outfile) {
|
||||
perror(outfilename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
nextch();
|
||||
next();
|
||||
ltok = 0;
|
||||
seen_space = 0;
|
||||
if (do_strip) {
|
||||
if (keep_header) {
|
||||
while (tokc.tok == ' ' ||
|
||||
tokc.tok == '\n' ||
|
||||
tokc.tok == '\t' ||
|
||||
tokc.tok == '\v' ||
|
||||
tokc.tok == '\b' ||
|
||||
tokc.tok == '\f') {
|
||||
seen_space = 1;
|
||||
next();
|
||||
}
|
||||
if (tokc.tok == TOK_COM) {
|
||||
print_tok(outfile, &tokc);
|
||||
//fprintf(outfile, "\n");
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
if (tokc.tok == TOK_EOF)
|
||||
break;
|
||||
if (tokc.tok == ' ' ||
|
||||
tokc.tok == '\r' ||
|
||||
tokc.tok == '\t' ||
|
||||
tokc.tok == '\v' ||
|
||||
tokc.tok == '\b' ||
|
||||
tokc.tok == '\f' ||
|
||||
tokc.tok == TOK_LCOM ||
|
||||
tokc.tok == TOK_COM) {
|
||||
/* don't print spaces or comments */
|
||||
seen_space = 1;
|
||||
} else if (tokc.tok == TOK_STR3) {
|
||||
print_tok(outfile, &tokc);
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
} else if (tokc.tok == TOK_STR1 || tokc.tok == TOK_STR2) {
|
||||
int count, i;
|
||||
/* find the optimal quote char */
|
||||
count = 0;
|
||||
for(i = 0; i < tokc.len; i++) {
|
||||
if (tokc.str[i] == '\'')
|
||||
count++;
|
||||
else if (tokc.str[i] == '\"')
|
||||
count--;
|
||||
}
|
||||
if (count > 0)
|
||||
tokc.tok = TOK_STR2;
|
||||
else if (count < 0)
|
||||
tokc.tok = TOK_STR1;
|
||||
print_tok(outfile, &tokc);
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
} else {
|
||||
if (seen_space && !compat_token(ltok, tokc.tok)) {
|
||||
fprintf(outfile, " ");
|
||||
}
|
||||
print_tok(outfile, &tokc);
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
}
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
/* just handle preprocessing */
|
||||
while (tokc.tok != TOK_EOF) {
|
||||
print_tok(outfile, &tokc);
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
fclose(outfile);
|
||||
fclose(infile);
|
||||
}
|
||||
|
||||
#define HASH_SIZE 30011
|
||||
#define MATCH_LEN_MIN 3
|
||||
#define MATCH_LEN_MAX (4 + 63)
|
||||
#define DIST_MAX 65535
|
||||
|
||||
static int find_longest_match(int *pdist, const uint8_t *src, int src_len,
|
||||
const int *hash_next, int cur_pos)
|
||||
{
|
||||
int pos, i, match_len, match_pos, pos_min, len_max;
|
||||
|
||||
len_max = min_int(src_len - cur_pos, MATCH_LEN_MAX);
|
||||
match_len = 0;
|
||||
match_pos = 0;
|
||||
pos_min = max_int(cur_pos - DIST_MAX - 1, 0);
|
||||
pos = hash_next[cur_pos];
|
||||
while (pos >= pos_min) {
|
||||
for(i = 0; i < len_max; i++) {
|
||||
if (src[cur_pos + i] != src[pos + i])
|
||||
break;
|
||||
}
|
||||
if (i > match_len) {
|
||||
match_len = i;
|
||||
match_pos = pos;
|
||||
}
|
||||
pos = hash_next[pos];
|
||||
}
|
||||
*pdist = cur_pos - match_pos - 1;
|
||||
return match_len;
|
||||
}
|
||||
|
||||
int lz_compress(uint8_t **pdst, const uint8_t *src, int src_len)
|
||||
{
|
||||
int *hash_table, *hash_next;
|
||||
uint32_t h, v;
|
||||
int i, dist, len, len1, dist1;
|
||||
uint8_t *dst, *q;
|
||||
|
||||
/* build the hash table */
|
||||
|
||||
hash_table = malloc(sizeof(hash_table[0]) * HASH_SIZE);
|
||||
for(i = 0; i < HASH_SIZE; i++)
|
||||
hash_table[i] = -1;
|
||||
hash_next = malloc(sizeof(hash_next[0]) * src_len);
|
||||
for(i = 0; i < src_len; i++)
|
||||
hash_next[i] = -1;
|
||||
|
||||
for(i = 0; i < src_len - MATCH_LEN_MIN + 1; i++) {
|
||||
h = ((src[i] << 16) | (src[i + 1] << 8) | src[i + 2]) % HASH_SIZE;
|
||||
hash_next[i] = hash_table[h];
|
||||
hash_table[h] = i;
|
||||
}
|
||||
for(;i < src_len; i++) {
|
||||
hash_next[i] = -1;
|
||||
}
|
||||
free(hash_table);
|
||||
|
||||
dst = malloc(src_len + 4); /* never larger than the source */
|
||||
q = dst;
|
||||
*q++ = src_len >> 24;
|
||||
*q++ = src_len >> 16;
|
||||
*q++ = src_len >> 8;
|
||||
*q++ = src_len >> 0;
|
||||
/* compress */
|
||||
i = 0;
|
||||
while (i < src_len) {
|
||||
if (src[i] >= 128)
|
||||
return -1;
|
||||
len = find_longest_match(&dist, src, src_len, hash_next, i);
|
||||
if (len >= MATCH_LEN_MIN) {
|
||||
/* heuristic: see if better length just after */
|
||||
len1 = find_longest_match(&dist1, src, src_len, hash_next, i + 1);
|
||||
if (len1 > len)
|
||||
goto no_match;
|
||||
}
|
||||
if (len < MATCH_LEN_MIN) {
|
||||
no_match:
|
||||
*q++ = src[i];
|
||||
i++;
|
||||
} else if (len <= (3 + 15) && dist < (1 << 10)) {
|
||||
v = 0x8000 | ((len - 3) << 10) | dist;
|
||||
*q++ = v >> 8;
|
||||
*q++ = v;
|
||||
i += len;
|
||||
} else if (len >= 4 && len <= (4 + 63) && dist < (1 << 16)) {
|
||||
v = 0xc00000 | ((len - 4) << 16) | dist;
|
||||
*q++ = v >> 16;
|
||||
*q++ = v >> 8;
|
||||
*q++ = v;
|
||||
i += len;
|
||||
} else {
|
||||
goto no_match;
|
||||
}
|
||||
}
|
||||
free(hash_next);
|
||||
*pdst = dst;
|
||||
return q - dst;
|
||||
}
|
||||
|
||||
static int load_file(uint8_t **pbuf, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
uint8_t *buf;
|
||||
int buf_len;
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
buf_len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
buf = malloc(buf_len + 1);
|
||||
fread(buf, 1, buf_len, f);
|
||||
buf[buf_len] = '\0';
|
||||
fclose(f);
|
||||
*pbuf = buf;
|
||||
return buf_len;
|
||||
}
|
||||
|
||||
static void save_file(const char *filename, const uint8_t *buf, int buf_len)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
fwrite(buf, 1, buf_len, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void save_c_source(const char *filename, const uint8_t *buf, int buf_len,
|
||||
const char *var_name)
|
||||
{
|
||||
FILE *f;
|
||||
int i;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(f, "/* This file is automatically generated - do not edit */\n\n");
|
||||
fprintf(f, "const uint8_t %s[] = {\n", var_name);
|
||||
for(i = 0; i < buf_len; i++) {
|
||||
fprintf(f, " 0x%02x,", buf[i]);
|
||||
if ((i % 8) == 7 || (i == buf_len - 1))
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fprintf(f, "};\n");
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#define DEFAULT_OUTPUT_FILENAME "out.js"
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("jscompress version 1.0 Copyright (c) 2008-2018 Fabrice Bellard\n"
|
||||
"usage: jscompress [options] filename\n"
|
||||
"Javascript compressor\n"
|
||||
"\n"
|
||||
"-h print this help\n"
|
||||
"-n do not compress spaces\n"
|
||||
"-H keep the first comment\n"
|
||||
"-c compress to file\n"
|
||||
"-C name compress to C source ('name' is the variable name)\n"
|
||||
"-D symbol define preprocessor symbol\n"
|
||||
"-U symbol undefine preprocessor symbol\n"
|
||||
"-o outfile set the output filename (default=%s)\n",
|
||||
DEFAULT_OUTPUT_FILENAME);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c, do_strip, keep_header, compress;
|
||||
const char *out_filename, *c_var, *fname;
|
||||
char tmpfilename[1024];
|
||||
|
||||
do_strip = 1;
|
||||
keep_header = 0;
|
||||
out_filename = DEFAULT_OUTPUT_FILENAME;
|
||||
compress = 0;
|
||||
c_var = NULL;
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "hno:HcC:D:U:");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'h':
|
||||
help();
|
||||
break;
|
||||
case 'n':
|
||||
do_strip = 0;
|
||||
break;
|
||||
case 'o':
|
||||
out_filename = optarg;
|
||||
break;
|
||||
case 'H':
|
||||
keep_header = 1;
|
||||
break;
|
||||
case 'c':
|
||||
compress = 1;
|
||||
break;
|
||||
case 'C':
|
||||
c_var = optarg;
|
||||
compress = 1;
|
||||
break;
|
||||
case 'D':
|
||||
define_symbol(optarg);
|
||||
break;
|
||||
case 'U':
|
||||
undefine_symbol(optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (optind >= argc)
|
||||
help();
|
||||
|
||||
filename = argv[optind++];
|
||||
|
||||
if (compress) {
|
||||
#if defined(__ANDROID__)
|
||||
/* XXX: use another directory ? */
|
||||
snprintf(tmpfilename, sizeof(tmpfilename), "out.%d", getpid());
|
||||
#else
|
||||
snprintf(tmpfilename, sizeof(tmpfilename), "/tmp/out.%d", getpid());
|
||||
#endif
|
||||
fname = tmpfilename;
|
||||
} else {
|
||||
fname = out_filename;
|
||||
}
|
||||
js_compress(filename, fname, do_strip, keep_header);
|
||||
|
||||
if (compress) {
|
||||
uint8_t *buf1, *buf2;
|
||||
int buf1_len, buf2_len;
|
||||
|
||||
buf1_len = load_file(&buf1, fname);
|
||||
unlink(fname);
|
||||
buf2_len = lz_compress(&buf2, buf1, buf1_len);
|
||||
if (buf2_len < 0) {
|
||||
fprintf(stderr, "Could not compress file (UTF8 chars are forbidden)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (c_var) {
|
||||
save_c_source(out_filename, buf2, buf2_len, c_var);
|
||||
} else {
|
||||
save_file(out_filename, buf2, buf2_len);
|
||||
}
|
||||
free(buf1);
|
||||
free(buf2);
|
||||
}
|
||||
return 0;
|
||||
}
|
499
libbf.h
Normal file
499
libbf.h
Normal file
@ -0,0 +1,499 @@
|
||||
/*
|
||||
* Tiny arbitrary precision floating point library
|
||||
*
|
||||
* Copyright (c) 2017-2020 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.
|
||||
*/
|
||||
#ifndef LIBBF_H
|
||||
#define LIBBF_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#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 EXP_MIN INT64_MIN
|
||||
#define 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 EXP_MIN INT32_MIN
|
||||
#define EXP_MAX INT32_MAX
|
||||
|
||||
#define LIMB_DIGITS 9
|
||||
#define BF_DEC_BASE 1000000000U
|
||||
|
||||
#endif
|
||||
|
||||
/* in bits */
|
||||
#define BF_EXP_BITS_MIN 3
|
||||
#define BF_EXP_BITS_MAX (LIMB_BITS - 2)
|
||||
#define BF_PREC_MIN 2
|
||||
#define BF_PREC_MAX (((limb_t)1 << BF_EXP_BITS_MAX) - 2)
|
||||
#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 EXP_MIN
|
||||
#define BF_EXP_INF (EXP_MAX - 1)
|
||||
#define BF_EXP_NAN 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 */
|
||||
BF_RNDU, /* round to +inf */
|
||||
BF_RNDNA, /* round to nearest, ties away from zero */
|
||||
BF_RNDNU, /* round to nearest, ties to +inf */
|
||||
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_MAX and prec != BF_PREC_INF. Not supported
|
||||
for decimal floating point numbers. */
|
||||
#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(), bfdec_round() and
|
||||
bfdev_div(). */
|
||||
#define BF_FLAG_RADPNT_PREC (1 << 4)
|
||||
|
||||
#define BF_RND_MASK 0x7
|
||||
#define BF_EXP_BITS_SHIFT 5
|
||||
#define BF_EXP_BITS_MASK 0x3f
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return BF_EXP_BITS_MAX - ((flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK);
|
||||
}
|
||||
|
||||
static inline bf_flags_t bf_set_exp_bits(int n)
|
||||
{
|
||||
return (BF_EXP_BITS_MAX - n) << 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_eq(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp_le(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp_lt(const bf_t *a, const bf_t *b);
|
||||
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_fmod(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bf_remainder(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
/* 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 the 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: use as many digits as necessary so that bf_atof()
|
||||
return the same number when using precision 'prec', rounding to
|
||||
nearest and the subnormal+exponent configuration of 'flags'. The
|
||||
result is meaningful only if 'a' is already rounded to the wanted
|
||||
precision.
|
||||
|
||||
Infinite precision (BF_PREC_INF) is supported when the radix is a
|
||||
power of two. */
|
||||
#define BF_FTOA_FORMAT_FREE (2 << 16)
|
||||
/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits
|
||||
(takes more computation time). */
|
||||
#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);
|
||||
|
||||
/* 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_QUICKS (1 << 16)
|
||||
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_eq(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmp_eq((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmp_le((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmp_lt((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
|
||||
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_fmod(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
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 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);
|
||||
|
||||
#endif /* LIBBF_H */
|
58
libregexp-opcode.h
Normal file
58
libregexp-opcode.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 */
|
2541
libregexp.c
Normal file
2541
libregexp.c
Normal file
File diff suppressed because it is too large
Load Diff
91
libregexp.h
Normal file
91
libregexp.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef LIBREGEXP_H
|
||||
#define LIBREGEXP_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "libunicode.h"
|
||||
|
||||
#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);
|
||||
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
|
||||
|
||||
#endif /* LIBREGEXP_H */
|
4313
libunicode-table.h
Normal file
4313
libunicode-table.h
Normal file
File diff suppressed because it is too large
Load Diff
1538
libunicode.c
Normal file
1538
libunicode.c
Normal file
File diff suppressed because it is too large
Load Diff
124
libunicode.h
Normal file
124
libunicode.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Unicode utilities
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef LIBUNICODE_H
|
||||
#define LIBUNICODE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#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
|
||||
|
||||
#endif /* LIBUNICODE_H */
|
100
list.h
Normal file
100
list.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Linux klist like system
|
||||
*
|
||||
* Copyright (c) 2016-2017 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.
|
||||
*/
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
#ifndef NULL
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
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)
|
||||
|
||||
#endif /* LIST_H */
|
520
qjs.c
Normal file
520
qjs.c
Normal file
@ -0,0 +1,520 @@
|
||||
/*
|
||||
* QuickJS stand alone interpreter
|
||||
*
|
||||
* Copyright (c) 2017-2020 Fabrice Bellard
|
||||
* Copyright (c) 2017-2020 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if defined(__APPLE__)
|
||||
#include <malloc/malloc.h>
|
||||
#elif defined(__linux__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#include "cutils.h"
|
||||
#include "quickjs-libc.h"
|
||||
|
||||
/* enable bignums */
|
||||
#define CONFIG_BIGNUM
|
||||
|
||||
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;
|
||||
#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;
|
||||
}
|
||||
|
||||
#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 __attribute__((format(printf, 2, 3)))
|
||||
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__)
|
||||
(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]\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"
|
||||
" --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"
|
||||
" --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;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
int load_jscalc, bignum_ext = 0;
|
||||
#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, "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 (opt) {
|
||||
fprintf(stderr, "qjs: unknown option '-%c'\n", opt);
|
||||
} else {
|
||||
fprintf(stderr, "qjs: unknown option '--%s'\n", longopt);
|
||||
}
|
||||
help();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
ctx = JS_NewContext(rt);
|
||||
if (!ctx) {
|
||||
fprintf(stderr, "qjs: cannot allocate JS context\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (bignum_ext || load_jscalc) {
|
||||
JS_AddIntrinsicBigFloat(ctx);
|
||||
JS_AddIntrinsicBigDecimal(ctx);
|
||||
JS_EnableBignumExt(ctx, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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);
|
||||
|
||||
/* system modules */
|
||||
js_init_module_std(ctx, "std");
|
||||
js_init_module_os(ctx, "os");
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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];
|
||||
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;
|
||||
}
|
707
qjsc.c
Normal file
707
qjsc.c
Normal file
@ -0,0 +1,707 @@
|
||||
/*
|
||||
* QuickJS command line compiler
|
||||
*
|
||||
* Copyright (c) 2018-2020 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#if !defined(_WIN32)
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include "cutils.h"
|
||||
#include "quickjs-libc.h"
|
||||
|
||||
/* enable bignums */
|
||||
#define CONFIG_BIGNUM
|
||||
|
||||
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 },
|
||||
{ "bigint", "BigInt" },
|
||||
};
|
||||
|
||||
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[1024];
|
||||
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;
|
||||
for(;;) {
|
||||
snprintf(cname1, sizeof(cname1), "%s_%d", cname, suffix_num);
|
||||
if (!namelist_find(&cname_list, cname1))
|
||||
break;
|
||||
suffix_num++;
|
||||
}
|
||||
pstrcpy(cname, cname_size, 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"
|
||||
;
|
||||
|
||||
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"
|
||||
"-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"
|
||||
);
|
||||
#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 = 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[1024];
|
||||
FILE *fo;
|
||||
JSRuntime *rt;
|
||||
JSContext *ctx;
|
||||
BOOL use_lto, bignum_ext;
|
||||
int module;
|
||||
OutputTypeEnum output_type;
|
||||
|
||||
out_filename = NULL;
|
||||
output_type = OUTPUT_EXECUTABLE;
|
||||
cname = NULL;
|
||||
feature_bitmap = FE_ALL;
|
||||
module = -1;
|
||||
byte_swap = FALSE;
|
||||
verbose = 0;
|
||||
use_lto = FALSE;
|
||||
bignum_ext = FALSE;
|
||||
|
||||
/* 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:");
|
||||
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 if (!strcmp(optarg, "bignum")) {
|
||||
bignum_ext = TRUE;
|
||||
} else {
|
||||
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 'x':
|
||||
byte_swap = TRUE;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'p':
|
||||
c_ident_prefix = optarg;
|
||||
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) {
|
||||
#if defined(_WIN32) || defined(__ANDROID__)
|
||||
/* XXX: find a /tmp directory ? */
|
||||
snprintf(cfilename, sizeof(cfilename), "out%d.c", getpid());
|
||||
#else
|
||||
snprintf(cfilename, sizeof(cfilename), "/tmp/out%d.c", getpid());
|
||||
#endif
|
||||
} else {
|
||||
pstrcpy(cfilename, sizeof(cfilename), 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_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 {
|
||||
fprintf(fo, "#include <inttypes.h>\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
for(i = optind; i < argc; i++) {
|
||||
const char *filename = argv[i];
|
||||
compile_file(ctx, fo, filename, cname, module);
|
||||
cname = NULL;
|
||||
}
|
||||
|
||||
if (output_type != OUTPUT_C) {
|
||||
fputs(main_c_template1, fo);
|
||||
fprintf(fo, " ctx = JS_NewContextRaw(rt);\n");
|
||||
|
||||
/* add the module loader if necessary */
|
||||
if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
|
||||
fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, 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);
|
||||
}
|
||||
}
|
||||
if (bignum_ext) {
|
||||
fprintf(fo,
|
||||
" JS_AddIntrinsicBigFloat(ctx);\n"
|
||||
" JS_AddIntrinsicBigDecimal(ctx);\n"
|
||||
" JS_EnableBignumExt(ctx, 1);\n");
|
||||
}
|
||||
|
||||
fprintf(fo, " js_std_add_helpers(ctx, argc, argv);\n");
|
||||
|
||||
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];
|
||||
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, %s);\n",
|
||||
e->name, e->name,
|
||||
e->flags ? "1" : "0");
|
||||
}
|
||||
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;
|
||||
}
|
2442
qjscalc.js
Normal file
2442
qjscalc.js
Normal file
File diff suppressed because it is too large
Load Diff
289
quickjs-atom.h
Normal file
289
quickjs-atom.h
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* 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(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(_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")
|
||||
#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_operatorOrder, "Symbol.operatorOrder")
|
||||
DEF(Symbol_operatorAdd, "Symbol.operatorAdd")
|
||||
DEF(Symbol_operatorSub, "Symbol.operatorSub")
|
||||
DEF(Symbol_operatorMul, "Symbol.operatorMul")
|
||||
DEF(Symbol_operatorDiv, "Symbol.operatorDiv")
|
||||
DEF(Symbol_operatorMod, "Symbol.operatorMod")
|
||||
DEF(Symbol_operatorPow, "Symbol.operatorPow")
|
||||
DEF(Symbol_operatorShl, "Symbol.operatorShl")
|
||||
DEF(Symbol_operatorShr, "Symbol.operatorShr")
|
||||
DEF(Symbol_operatorAnd, "Symbol.operatorAnd")
|
||||
DEF(Symbol_operatorOr, "Symbol.operatorOr")
|
||||
DEF(Symbol_operatorXor, "Symbol.operatorXor")
|
||||
DEF(Symbol_operatorCmpLT, "Symbol.operatorCmpLT")
|
||||
DEF(Symbol_operatorCmpLE, "Symbol.operatorCmpLE")
|
||||
DEF(Symbol_operatorCmpEQ, "Symbol.operatorCmpEQ")
|
||||
DEF(Symbol_operatorPlus, "Symbol.operatorPlus")
|
||||
DEF(Symbol_operatorNeg, "Symbol.operatorNeg")
|
||||
DEF(Symbol_operatorNot, "Symbol.operatorNot")
|
||||
DEF(Symbol_operatorInc, "Symbol.operatorInc")
|
||||
DEF(Symbol_operatorDec, "Symbol.operatorDec")
|
||||
DEF(Symbol_operatorMathMod, "Symbol.operatorMathMod")
|
||||
#endif
|
||||
|
||||
#endif /* DEF */
|
2804
quickjs-libc.c
Normal file
2804
quickjs-libc.c
Normal file
File diff suppressed because it is too large
Load Diff
49
quickjs-libc.h
Normal file
49
quickjs-libc.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* QuickJS C library
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef QUICKJS_LIBC_H
|
||||
#define QUICKJS_LIBC_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "quickjs.h"
|
||||
|
||||
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_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);
|
||||
|
||||
#endif /* QUICKJS_LIBC_H */
|
371
quickjs-opcode.h
Normal file
371
quickjs-opcode.h
Normal file
@ -0,0 +1,371 @@
|
||||
/*
|
||||
* 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_var, 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_ctor, 1, 1, 1, none)
|
||||
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(for_await_of_next, 1, 3, 4, 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(async_iterator_close, 1, 3, 2, none)
|
||||
DEF(async_iterator_next, 1, 4, 4, none)
|
||||
DEF(async_iterator_get, 2, 4, 5, u8)
|
||||
DEF( initial_yield, 1, 0, 0, none)
|
||||
DEF( yield, 1, 1, 2, none)
|
||||
DEF( yield_star, 1, 2, 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_div, 1, 2, 1, none)
|
||||
DEF( math_mod, 1, 2, 1, none)
|
||||
DEF( math_pow, 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(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */
|
||||
|
||||
def(close_var_object, 1, 0, 0, none) /* emitted in phase 1, removed in phase 2 */
|
||||
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( is_function, 1, 1, 1, none)
|
||||
#endif
|
||||
|
||||
#undef DEF
|
||||
#undef def
|
||||
#endif /* DEF */
|
976
quickjs.h
Normal file
976
quickjs.h
Normal file
@ -0,0 +1,976 @@
|
||||
/*
|
||||
* QuickJS Javascript Engine
|
||||
*
|
||||
* Copyright (c) 2017-2020 Fabrice Bellard
|
||||
* Copyright (c) 2017-2020 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.
|
||||
*/
|
||||
#ifndef QUICKJS_H
|
||||
#define QUICKJS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define js_likely(x) __builtin_expect(!!(x), 1)
|
||||
#define js_unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#define js_force_inline inline __attribute__((always_inline))
|
||||
#define __js_printf_like(f, a) __attribute__((format(printf, f, a)))
|
||||
#else
|
||||
#define js_likely(x) (x)
|
||||
#define js_unlikely(x) (x)
|
||||
#define js_force_inline inline
|
||||
#define __js_printf_like(a, b)
|
||||
#endif
|
||||
|
||||
#define JS_BOOL int
|
||||
|
||||
typedef struct JSRuntime JSRuntime;
|
||||
typedef struct JSContext JSContext;
|
||||
typedef struct JSObject JSObject;
|
||||
typedef struct JSClass JSClass;
|
||||
typedef uint32_t JSClassID;
|
||||
typedef uint32_t JSAtom;
|
||||
|
||||
#if defined(__x86_64__) || defined(__aarch64__)
|
||||
#define JS_PTR64
|
||||
#define JS_PTR64_DEF(a) a
|
||||
#else
|
||||
#define JS_PTR64_DEF(a)
|
||||
#endif
|
||||
|
||||
#ifndef JS_PTR64
|
||||
#define JS_NAN_BOXING
|
||||
#endif
|
||||
|
||||
enum {
|
||||
/* all tags with a reference count are negative */
|
||||
JS_TAG_FIRST = -11, /* first negative tag */
|
||||
JS_TAG_BIG_DECIMAL = -11,
|
||||
JS_TAG_BIG_INT = -10,
|
||||
JS_TAG_BIG_FLOAT = -9,
|
||||
JS_TAG_SYMBOL = -8,
|
||||
JS_TAG_STRING = -7,
|
||||
JS_TAG_MODULE = -3, /* used internally */
|
||||
JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */
|
||||
JS_TAG_OBJECT = -1,
|
||||
|
||||
JS_TAG_INT = 0,
|
||||
JS_TAG_BOOL = 1,
|
||||
JS_TAG_NULL = 2,
|
||||
JS_TAG_UNDEFINED = 3,
|
||||
JS_TAG_UNINITIALIZED = 4,
|
||||
JS_TAG_CATCH_OFFSET = 5,
|
||||
JS_TAG_EXCEPTION = 6,
|
||||
JS_TAG_FLOAT64 = 7,
|
||||
/* any larger tag is FLOAT64 if JS_NAN_BOXING */
|
||||
};
|
||||
|
||||
typedef struct JSRefCountHeader {
|
||||
int ref_count;
|
||||
} JSRefCountHeader;
|
||||
|
||||
#define JS_FLOAT64_NAN NAN
|
||||
|
||||
#ifdef CONFIG_CHECK_JSVALUE
|
||||
/* JSValue consistency : it is not possible to run the code in this
|
||||
mode, but it is useful to detect simple reference counting
|
||||
errors. It would be interesting to modify a static C analyzer to
|
||||
handle specific annotations (clang has such annotations but only
|
||||
for objective C) */
|
||||
typedef struct __JSValue *JSValue;
|
||||
typedef const struct __JSValue *JSValueConst;
|
||||
|
||||
#define JS_VALUE_GET_TAG(v) (int)((uintptr_t)(v) & 0xf)
|
||||
/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */
|
||||
#define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v)
|
||||
#define JS_VALUE_GET_INT(v) (int)((intptr_t)(v) >> 4)
|
||||
#define JS_VALUE_GET_BOOL(v) JS_VALUE_GET_INT(v)
|
||||
#define JS_VALUE_GET_FLOAT64(v) (double)JS_VALUE_GET_INT(v)
|
||||
#define JS_VALUE_GET_PTR(v) (void *)((intptr_t)(v) & ~0xf)
|
||||
|
||||
#define JS_MKVAL(tag, val) (JSValue)(intptr_t)(((val) << 4) | (tag))
|
||||
#define JS_MKPTR(tag, p) (JSValue)((intptr_t)(p) | (tag))
|
||||
|
||||
#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)
|
||||
|
||||
#define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 1)
|
||||
|
||||
static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
|
||||
{
|
||||
return JS_MKVAL(JS_TAG_FLOAT64, (int)d);
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(JS_NAN_BOXING)
|
||||
|
||||
typedef uint64_t JSValue;
|
||||
|
||||
#define JSValueConst JSValue
|
||||
|
||||
#define JS_VALUE_GET_TAG(v) (int)((v) >> 32)
|
||||
#define JS_VALUE_GET_INT(v) (int)(v)
|
||||
#define JS_VALUE_GET_BOOL(v) (int)(v)
|
||||
#define JS_VALUE_GET_PTR(v) (void *)(intptr_t)(v)
|
||||
|
||||
#define JS_MKVAL(tag, val) (((uint64_t)(tag) << 32) | (uint32_t)(val))
|
||||
#define JS_MKPTR(tag, ptr) (((uint64_t)(tag) << 32) | (uintptr_t)(ptr))
|
||||
|
||||
#define JS_FLOAT64_TAG_ADDEND (0x7ff80000 - JS_TAG_FIRST + 1) /* quiet NaN encoding */
|
||||
|
||||
static inline double JS_VALUE_GET_FLOAT64(JSValue v)
|
||||
{
|
||||
union {
|
||||
JSValue v;
|
||||
double d;
|
||||
} u;
|
||||
u.v = v;
|
||||
u.v += (uint64_t)JS_FLOAT64_TAG_ADDEND << 32;
|
||||
return u.d;
|
||||
}
|
||||
|
||||
#define JS_NAN (0x7ff8000000000000 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32))
|
||||
|
||||
static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u;
|
||||
JSValue v;
|
||||
u.d = d;
|
||||
/* normalize NaN */
|
||||
if (js_unlikely((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000))
|
||||
v = JS_NAN;
|
||||
else
|
||||
v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32);
|
||||
return v;
|
||||
}
|
||||
|
||||
#define JS_TAG_IS_FLOAT64(tag) ((unsigned)((tag) - JS_TAG_FIRST) >= (JS_TAG_FLOAT64 - JS_TAG_FIRST))
|
||||
|
||||
/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */
|
||||
static inline int JS_VALUE_GET_NORM_TAG(JSValue v)
|
||||
{
|
||||
uint32_t tag;
|
||||
tag = JS_VALUE_GET_TAG(v);
|
||||
if (JS_TAG_IS_FLOAT64(tag))
|
||||
return JS_TAG_FLOAT64;
|
||||
else
|
||||
return tag;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
{
|
||||
uint32_t tag;
|
||||
tag = JS_VALUE_GET_TAG(v);
|
||||
return tag == (JS_NAN >> 32);
|
||||
}
|
||||
|
||||
#else /* !JS_NAN_BOXING */
|
||||
|
||||
typedef union JSValueUnion {
|
||||
int32_t int32;
|
||||
double float64;
|
||||
void *ptr;
|
||||
} JSValueUnion;
|
||||
|
||||
typedef struct JSValue {
|
||||
JSValueUnion u;
|
||||
int64_t tag;
|
||||
} JSValue;
|
||||
|
||||
#define JSValueConst JSValue
|
||||
|
||||
#define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag)
|
||||
/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */
|
||||
#define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v)
|
||||
#define JS_VALUE_GET_INT(v) ((v).u.int32)
|
||||
#define JS_VALUE_GET_BOOL(v) ((v).u.int32)
|
||||
#define JS_VALUE_GET_FLOAT64(v) ((v).u.float64)
|
||||
#define JS_VALUE_GET_PTR(v) ((v).u.ptr)
|
||||
|
||||
#define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }
|
||||
#define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag }
|
||||
|
||||
#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)
|
||||
|
||||
#define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 }
|
||||
|
||||
static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
|
||||
{
|
||||
JSValue v;
|
||||
v.tag = JS_TAG_FLOAT64;
|
||||
v.u.float64 = d;
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u;
|
||||
if (v.tag != JS_TAG_FLOAT64)
|
||||
return 0;
|
||||
u.d = v.u.float64;
|
||||
return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000;
|
||||
}
|
||||
|
||||
#endif /* !JS_NAN_BOXING */
|
||||
|
||||
#define JS_VALUE_IS_BOTH_INT(v1, v2) ((JS_VALUE_GET_TAG(v1) | JS_VALUE_GET_TAG(v2)) == 0)
|
||||
#define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2)))
|
||||
|
||||
#define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v))
|
||||
#define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v))
|
||||
#define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST)
|
||||
|
||||
/* special values */
|
||||
#define JS_NULL JS_MKVAL(JS_TAG_NULL, 0)
|
||||
#define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0)
|
||||
#define JS_FALSE JS_MKVAL(JS_TAG_BOOL, 0)
|
||||
#define JS_TRUE JS_MKVAL(JS_TAG_BOOL, 1)
|
||||
#define JS_EXCEPTION JS_MKVAL(JS_TAG_EXCEPTION, 0)
|
||||
#define JS_UNINITIALIZED JS_MKVAL(JS_TAG_UNINITIALIZED, 0)
|
||||
|
||||
/* flags for object properties */
|
||||
#define JS_PROP_CONFIGURABLE (1 << 0)
|
||||
#define JS_PROP_WRITABLE (1 << 1)
|
||||
#define JS_PROP_ENUMERABLE (1 << 2)
|
||||
#define JS_PROP_C_W_E (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)
|
||||
#define JS_PROP_LENGTH (1 << 3) /* used internally in Arrays */
|
||||
#define JS_PROP_TMASK (3 << 4) /* mask for NORMAL, GETSET, VARREF, AUTOINIT */
|
||||
#define JS_PROP_NORMAL (0 << 4)
|
||||
#define JS_PROP_GETSET (1 << 4)
|
||||
#define JS_PROP_VARREF (2 << 4) /* used internally */
|
||||
#define JS_PROP_AUTOINIT (3 << 4) /* used internally */
|
||||
|
||||
/* flags for JS_DefineProperty */
|
||||
#define JS_PROP_HAS_SHIFT 8
|
||||
#define JS_PROP_HAS_CONFIGURABLE (1 << 8)
|
||||
#define JS_PROP_HAS_WRITABLE (1 << 9)
|
||||
#define JS_PROP_HAS_ENUMERABLE (1 << 10)
|
||||
#define JS_PROP_HAS_GET (1 << 11)
|
||||
#define JS_PROP_HAS_SET (1 << 12)
|
||||
#define JS_PROP_HAS_VALUE (1 << 13)
|
||||
|
||||
/* throw an exception if false would be returned
|
||||
(JS_DefineProperty/JS_SetProperty) */
|
||||
#define JS_PROP_THROW (1 << 14)
|
||||
/* throw an exception if false would be returned in strict mode
|
||||
(JS_SetProperty) */
|
||||
#define JS_PROP_THROW_STRICT (1 << 15)
|
||||
|
||||
#define JS_PROP_NO_ADD (1 << 16) /* internal use */
|
||||
#define JS_PROP_NO_EXOTIC (1 << 17) /* internal use */
|
||||
|
||||
#define JS_DEFAULT_STACK_SIZE (256 * 1024)
|
||||
|
||||
/* JS_Eval() flags */
|
||||
#define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */
|
||||
#define JS_EVAL_TYPE_MODULE (1 << 0) /* module code */
|
||||
#define JS_EVAL_TYPE_DIRECT (2 << 0) /* direct call (internal use) */
|
||||
#define JS_EVAL_TYPE_INDIRECT (3 << 0) /* indirect call (internal use) */
|
||||
#define JS_EVAL_TYPE_MASK (3 << 0)
|
||||
|
||||
#define JS_EVAL_FLAG_STRICT (1 << 3) /* force 'strict' mode */
|
||||
#define JS_EVAL_FLAG_STRIP (1 << 4) /* force 'strip' mode */
|
||||
/* compile but do not run. The result is an object with a
|
||||
JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed
|
||||
with JS_EvalFunction(). */
|
||||
#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5)
|
||||
/* don't include the stack frames before this eval in the Error() backtraces */
|
||||
#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)
|
||||
|
||||
typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
|
||||
typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
|
||||
typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data);
|
||||
|
||||
typedef struct JSMallocState {
|
||||
size_t malloc_count;
|
||||
size_t malloc_size;
|
||||
size_t malloc_limit;
|
||||
void *opaque; /* user opaque */
|
||||
} JSMallocState;
|
||||
|
||||
typedef struct JSMallocFunctions {
|
||||
void *(*js_malloc)(JSMallocState *s, size_t size);
|
||||
void (*js_free)(JSMallocState *s, void *ptr);
|
||||
void *(*js_realloc)(JSMallocState *s, void *ptr, size_t size);
|
||||
size_t (*js_malloc_usable_size)(const void *ptr);
|
||||
} JSMallocFunctions;
|
||||
|
||||
typedef struct JSGCObjectHeader JSGCObjectHeader;
|
||||
|
||||
JSRuntime *JS_NewRuntime(void);
|
||||
/* info lifetime must exceed that of rt */
|
||||
void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
|
||||
void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
|
||||
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
|
||||
JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque);
|
||||
void JS_FreeRuntime(JSRuntime *rt);
|
||||
typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp);
|
||||
void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
|
||||
void JS_RunGC(JSRuntime *rt);
|
||||
JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj);
|
||||
|
||||
JSContext *JS_NewContext(JSRuntime *rt);
|
||||
void JS_FreeContext(JSContext *s);
|
||||
void *JS_GetContextOpaque(JSContext *ctx);
|
||||
void JS_SetContextOpaque(JSContext *ctx, void *opaque);
|
||||
JSRuntime *JS_GetRuntime(JSContext *ctx);
|
||||
void JS_SetMaxStackSize(JSContext *ctx, size_t stack_size);
|
||||
void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj);
|
||||
JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id);
|
||||
|
||||
/* the following functions are used to select the intrinsic object to
|
||||
save memory */
|
||||
JSContext *JS_NewContextRaw(JSRuntime *rt);
|
||||
void JS_AddIntrinsicBaseObjects(JSContext *ctx);
|
||||
void JS_AddIntrinsicDate(JSContext *ctx);
|
||||
void JS_AddIntrinsicEval(JSContext *ctx);
|
||||
void JS_AddIntrinsicStringNormalize(JSContext *ctx);
|
||||
void JS_AddIntrinsicRegExpCompiler(JSContext *ctx);
|
||||
void JS_AddIntrinsicRegExp(JSContext *ctx);
|
||||
void JS_AddIntrinsicJSON(JSContext *ctx);
|
||||
void JS_AddIntrinsicProxy(JSContext *ctx);
|
||||
void JS_AddIntrinsicMapSet(JSContext *ctx);
|
||||
void JS_AddIntrinsicTypedArrays(JSContext *ctx);
|
||||
void JS_AddIntrinsicPromise(JSContext *ctx);
|
||||
void JS_AddIntrinsicBigInt(JSContext *ctx);
|
||||
void JS_AddIntrinsicBigFloat(JSContext *ctx);
|
||||
void JS_AddIntrinsicBigDecimal(JSContext *ctx);
|
||||
/* enable "use bigint", "use math" and operator overloading */
|
||||
void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable);
|
||||
|
||||
JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv);
|
||||
|
||||
void *js_malloc_rt(JSRuntime *rt, size_t size);
|
||||
void js_free_rt(JSRuntime *rt, void *ptr);
|
||||
void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size);
|
||||
size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr);
|
||||
void *js_mallocz_rt(JSRuntime *rt, size_t size);
|
||||
|
||||
void *js_malloc(JSContext *ctx, size_t size);
|
||||
void js_free(JSContext *ctx, void *ptr);
|
||||
void *js_realloc(JSContext *ctx, void *ptr, size_t size);
|
||||
size_t js_malloc_usable_size(JSContext *ctx, const void *ptr);
|
||||
void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack);
|
||||
void *js_mallocz(JSContext *ctx, size_t size);
|
||||
char *js_strdup(JSContext *ctx, const char *str);
|
||||
char *js_strndup(JSContext *ctx, const char *s, size_t n);
|
||||
|
||||
typedef struct JSMemoryUsage {
|
||||
int64_t malloc_size, malloc_limit, memory_used_size;
|
||||
int64_t malloc_count;
|
||||
int64_t memory_used_count;
|
||||
int64_t atom_count, atom_size;
|
||||
int64_t str_count, str_size;
|
||||
int64_t obj_count, obj_size;
|
||||
int64_t prop_count, prop_size;
|
||||
int64_t shape_count, shape_size;
|
||||
int64_t js_func_count, js_func_size, js_func_code_size;
|
||||
int64_t js_func_pc2line_count, js_func_pc2line_size;
|
||||
int64_t c_func_count, array_count;
|
||||
int64_t fast_array_count, fast_array_elements;
|
||||
int64_t binary_object_count, binary_object_size;
|
||||
} JSMemoryUsage;
|
||||
|
||||
void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s);
|
||||
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt);
|
||||
|
||||
/* atom support */
|
||||
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len);
|
||||
JSAtom JS_NewAtom(JSContext *ctx, const char *str);
|
||||
JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n);
|
||||
JSAtom JS_DupAtom(JSContext *ctx, JSAtom v);
|
||||
void JS_FreeAtom(JSContext *ctx, JSAtom v);
|
||||
void JS_FreeAtomRT(JSRuntime *rt, JSAtom v);
|
||||
JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom);
|
||||
JSValue JS_AtomToString(JSContext *ctx, JSAtom atom);
|
||||
const char *JS_AtomToCString(JSContext *ctx, JSAtom atom);
|
||||
JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val);
|
||||
|
||||
/* object class support */
|
||||
|
||||
typedef struct JSPropertyEnum {
|
||||
JS_BOOL is_enumerable;
|
||||
JSAtom atom;
|
||||
} JSPropertyEnum;
|
||||
|
||||
typedef struct JSPropertyDescriptor {
|
||||
int flags;
|
||||
JSValue value;
|
||||
JSValue getter;
|
||||
JSValue setter;
|
||||
} JSPropertyDescriptor;
|
||||
|
||||
typedef struct JSClassExoticMethods {
|
||||
/* Return -1 if exception (can only happen in case of Proxy object),
|
||||
FALSE if the property does not exists, TRUE if it exists. If 1 is
|
||||
returned, the property descriptor 'desc' is filled if != NULL. */
|
||||
int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc,
|
||||
JSValueConst obj, JSAtom prop);
|
||||
/* '*ptab' should hold the '*plen' property keys. Return 0 if OK,
|
||||
-1 if exception. The 'is_enumerable' field is ignored.
|
||||
*/
|
||||
int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab,
|
||||
uint32_t *plen,
|
||||
JSValueConst obj);
|
||||
/* return < 0 if exception, or TRUE/FALSE */
|
||||
int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop);
|
||||
/* return < 0 if exception or TRUE/FALSE */
|
||||
int (*define_own_property)(JSContext *ctx, JSValueConst this_obj,
|
||||
JSAtom prop, JSValueConst val,
|
||||
JSValueConst getter, JSValueConst setter,
|
||||
int flags);
|
||||
/* The following methods can be emulated with the previous ones,
|
||||
so they are usually not needed */
|
||||
/* return < 0 if exception or TRUE/FALSE */
|
||||
int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom);
|
||||
JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom,
|
||||
JSValueConst receiver);
|
||||
/* return < 0 if exception or TRUE/FALSE */
|
||||
int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom,
|
||||
JSValueConst value, JSValueConst receiver, int flags);
|
||||
} JSClassExoticMethods;
|
||||
|
||||
typedef void JSClassFinalizer(JSRuntime *rt, JSValue val);
|
||||
typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val,
|
||||
JS_MarkFunc *mark_func);
|
||||
#define JS_CALL_FLAG_CONSTRUCTOR (1 << 0)
|
||||
typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj,
|
||||
JSValueConst this_val, int argc, JSValueConst *argv,
|
||||
int flags);
|
||||
|
||||
typedef struct JSClassDef {
|
||||
const char *class_name;
|
||||
JSClassFinalizer *finalizer;
|
||||
JSClassGCMark *gc_mark;
|
||||
/* if call != NULL, the object is a function. If (flags &
|
||||
JS_CALL_FLAG_CONSTRUCTOR) != 0, the function is called as a
|
||||
constructor. In this case, 'this_val' is new.target. A
|
||||
constructor call only happens if the object constructor bit is
|
||||
set (see JS_SetConstructorBit()). */
|
||||
JSClassCall *call;
|
||||
/* XXX: suppress this indirection ? It is here only to save memory
|
||||
because only a few classes need these methods */
|
||||
JSClassExoticMethods *exotic;
|
||||
} JSClassDef;
|
||||
|
||||
JSClassID JS_NewClassID(JSClassID *pclass_id);
|
||||
int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def);
|
||||
int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);
|
||||
|
||||
/* value handling */
|
||||
|
||||
static js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val)
|
||||
{
|
||||
return JS_MKVAL(JS_TAG_BOOL, val);
|
||||
}
|
||||
|
||||
static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val)
|
||||
{
|
||||
return JS_MKVAL(JS_TAG_INT, val);
|
||||
}
|
||||
|
||||
static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val)
|
||||
{
|
||||
return JS_MKVAL(JS_TAG_CATCH_OFFSET, val);
|
||||
}
|
||||
|
||||
JSValue JS_NewInt64(JSContext *ctx, int64_t v);
|
||||
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v);
|
||||
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);
|
||||
|
||||
static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d)
|
||||
{
|
||||
JSValue v;
|
||||
int32_t val;
|
||||
union {
|
||||
double d;
|
||||
uint64_t u;
|
||||
} u, t;
|
||||
u.d = d;
|
||||
val = (int32_t)d;
|
||||
t.d = val;
|
||||
/* -0 cannot be represented as integer, so we compare the bit
|
||||
representation */
|
||||
if (u.u == t.u) {
|
||||
v = JS_MKVAL(JS_TAG_INT, val);
|
||||
} else {
|
||||
v = __JS_NewFloat64(ctx, d);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
JS_BOOL JS_IsNumber(JSValueConst v);
|
||||
|
||||
static inline JS_BOOL JS_IsInteger(JSValueConst v)
|
||||
{
|
||||
int tag = JS_VALUE_GET_TAG(v);
|
||||
return tag == JS_TAG_INT || tag == JS_TAG_BIG_INT;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsBigFloat(JSValueConst v)
|
||||
{
|
||||
int tag = JS_VALUE_GET_TAG(v);
|
||||
return tag == JS_TAG_BIG_FLOAT;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsBigDecimal(JSValueConst v)
|
||||
{
|
||||
int tag = JS_VALUE_GET_TAG(v);
|
||||
return tag == JS_TAG_BIG_DECIMAL;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsBool(JSValueConst v)
|
||||
{
|
||||
return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsNull(JSValueConst v)
|
||||
{
|
||||
return JS_VALUE_GET_TAG(v) == JS_TAG_NULL;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsUndefined(JSValueConst v)
|
||||
{
|
||||
return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsException(JSValueConst v)
|
||||
{
|
||||
return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION);
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsUninitialized(JSValueConst v)
|
||||
{
|
||||
return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED);
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsString(JSValueConst v)
|
||||
{
|
||||
return JS_VALUE_GET_TAG(v) == JS_TAG_STRING;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsSymbol(JSValueConst v)
|
||||
{
|
||||
return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsObject(JSValueConst v)
|
||||
{
|
||||
return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT;
|
||||
}
|
||||
|
||||
JSValue JS_Throw(JSContext *ctx, JSValue obj);
|
||||
JSValue JS_GetException(JSContext *ctx);
|
||||
JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val);
|
||||
void JS_ResetUncatchableError(JSContext *ctx);
|
||||
JSValue JS_NewError(JSContext *ctx);
|
||||
JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...);
|
||||
JSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...);
|
||||
JSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...);
|
||||
JSValue __js_printf_like(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...);
|
||||
JSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
|
||||
JSValue JS_ThrowOutOfMemory(JSContext *ctx);
|
||||
|
||||
void __JS_FreeValue(JSContext *ctx, JSValue v);
|
||||
static inline void JS_FreeValue(JSContext *ctx, JSValue v)
|
||||
{
|
||||
if (JS_VALUE_HAS_REF_COUNT(v)) {
|
||||
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
|
||||
if (--p->ref_count <= 0) {
|
||||
__JS_FreeValue(ctx, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
void __JS_FreeValueRT(JSRuntime *rt, JSValue v);
|
||||
static inline void JS_FreeValueRT(JSRuntime *rt, JSValue v)
|
||||
{
|
||||
if (JS_VALUE_HAS_REF_COUNT(v)) {
|
||||
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
|
||||
if (--p->ref_count <= 0) {
|
||||
__JS_FreeValueRT(rt, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v)
|
||||
{
|
||||
if (JS_VALUE_HAS_REF_COUNT(v)) {
|
||||
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
|
||||
p->ref_count++;
|
||||
}
|
||||
return (JSValue)v;
|
||||
}
|
||||
|
||||
static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
|
||||
{
|
||||
if (JS_VALUE_HAS_REF_COUNT(v)) {
|
||||
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
|
||||
p->ref_count++;
|
||||
}
|
||||
return (JSValue)v;
|
||||
}
|
||||
|
||||
int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */
|
||||
int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val);
|
||||
static int inline JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
|
||||
{
|
||||
return JS_ToInt32(ctx, (int32_t*)pres, val);
|
||||
}
|
||||
int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
|
||||
int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val);
|
||||
int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val);
|
||||
int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
|
||||
|
||||
JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1);
|
||||
JSValue JS_NewString(JSContext *ctx, const char *str);
|
||||
JSValue JS_NewAtomString(JSContext *ctx, const char *str);
|
||||
JSValue JS_ToString(JSContext *ctx, JSValueConst val);
|
||||
JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val);
|
||||
const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, JS_BOOL cesu8);
|
||||
static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValueConst val1)
|
||||
{
|
||||
return JS_ToCStringLen2(ctx, plen, val1, 0);
|
||||
}
|
||||
static inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1)
|
||||
{
|
||||
return JS_ToCStringLen2(ctx, NULL, val1, 0);
|
||||
}
|
||||
void JS_FreeCString(JSContext *ctx, const char *ptr);
|
||||
|
||||
JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto, JSClassID class_id);
|
||||
JSValue JS_NewObjectClass(JSContext *ctx, int class_id);
|
||||
JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto);
|
||||
JSValue JS_NewObject(JSContext *ctx);
|
||||
|
||||
JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val);
|
||||
JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val);
|
||||
JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val);
|
||||
|
||||
JSValue JS_NewArray(JSContext *ctx);
|
||||
int JS_IsArray(JSContext *ctx, JSValueConst val);
|
||||
|
||||
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
|
||||
JSAtom prop, JSValueConst receiver,
|
||||
JS_BOOL throw_ref_error);
|
||||
static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj,
|
||||
JSAtom prop)
|
||||
{
|
||||
return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0);
|
||||
}
|
||||
JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
|
||||
const char *prop);
|
||||
JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
|
||||
uint32_t idx);
|
||||
|
||||
int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj,
|
||||
JSAtom prop, JSValue val,
|
||||
int flags);
|
||||
static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj,
|
||||
JSAtom prop, JSValue val)
|
||||
{
|
||||
return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW);
|
||||
}
|
||||
int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
|
||||
uint32_t idx, JSValue val);
|
||||
int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,
|
||||
int64_t idx, JSValue val);
|
||||
int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
|
||||
const char *prop, JSValue val);
|
||||
int JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop);
|
||||
int JS_IsExtensible(JSContext *ctx, JSValueConst obj);
|
||||
int JS_PreventExtensions(JSContext *ctx, JSValueConst obj);
|
||||
int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags);
|
||||
int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val);
|
||||
JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val);
|
||||
|
||||
#define JS_GPN_STRING_MASK (1 << 0)
|
||||
#define JS_GPN_SYMBOL_MASK (1 << 1)
|
||||
#define JS_GPN_PRIVATE_MASK (1 << 2)
|
||||
/* only include the enumerable properties */
|
||||
#define JS_GPN_ENUM_ONLY (1 << 4)
|
||||
/* set theJSPropertyEnum.is_enumerable field */
|
||||
#define JS_GPN_SET_ENUM (1 << 5)
|
||||
|
||||
int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
|
||||
uint32_t *plen, JSValueConst obj, int flags);
|
||||
int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
|
||||
JSValueConst obj, JSAtom prop);
|
||||
|
||||
JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
|
||||
int argc, JSValueConst *argv);
|
||||
JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,
|
||||
int argc, JSValueConst *argv);
|
||||
JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
|
||||
int argc, JSValueConst *argv);
|
||||
JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
|
||||
JSValueConst new_target,
|
||||
int argc, JSValueConst *argv);
|
||||
JS_BOOL JS_DetectModule(const char *input, size_t input_len);
|
||||
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
|
||||
JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
|
||||
const char *filename, int eval_flags);
|
||||
JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj);
|
||||
JSValue JS_GetGlobalObject(JSContext *ctx);
|
||||
int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj);
|
||||
int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
|
||||
JSAtom prop, JSValueConst val,
|
||||
JSValueConst getter, JSValueConst setter, int flags);
|
||||
int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,
|
||||
JSAtom prop, JSValue val, int flags);
|
||||
int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,
|
||||
uint32_t idx, JSValue val, int flags);
|
||||
int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
|
||||
const char *prop, JSValue val, int flags);
|
||||
int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
|
||||
JSAtom prop, JSValue getter, JSValue setter,
|
||||
int flags);
|
||||
void JS_SetOpaque(JSValue obj, void *opaque);
|
||||
void *JS_GetOpaque(JSValueConst obj, JSClassID class_id);
|
||||
void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id);
|
||||
|
||||
/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
|
||||
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
const char *filename);
|
||||
JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
|
||||
JSValueConst replacer, JSValueConst space0);
|
||||
|
||||
typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr);
|
||||
JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
|
||||
JSFreeArrayBufferDataFunc *free_func, void *opaque,
|
||||
JS_BOOL is_shared);
|
||||
JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len);
|
||||
void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj);
|
||||
uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj);
|
||||
JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
|
||||
size_t *pbyte_offset,
|
||||
size_t *pbyte_length,
|
||||
size_t *pbytes_per_element);
|
||||
|
||||
JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
|
||||
|
||||
/* is_handled = TRUE means that the rejection is handled */
|
||||
typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise,
|
||||
JSValueConst reason,
|
||||
JS_BOOL is_handled, void *opaque);
|
||||
void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque);
|
||||
|
||||
/* return != 0 if the JS code needs to be interrupted */
|
||||
typedef int JSInterruptHandler(JSRuntime *rt, void *opaque);
|
||||
void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque);
|
||||
/* if can_block is TRUE, Atomics.wait() can be used */
|
||||
void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block);
|
||||
|
||||
typedef struct JSModuleDef JSModuleDef;
|
||||
|
||||
/* return the module specifier (allocated with js_malloc()) or NULL if
|
||||
exception */
|
||||
typedef char *JSModuleNormalizeFunc(JSContext *ctx,
|
||||
const char *module_base_name,
|
||||
const char *module_name, void *opaque);
|
||||
typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx,
|
||||
const char *module_name, void *opaque);
|
||||
|
||||
/* module_normalize = NULL is allowed and invokes the default module
|
||||
filename normalizer */
|
||||
void JS_SetModuleLoaderFunc(JSRuntime *rt,
|
||||
JSModuleNormalizeFunc *module_normalize,
|
||||
JSModuleLoaderFunc *module_loader, void *opaque);
|
||||
/* return the import.meta object of a module */
|
||||
JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m);
|
||||
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m);
|
||||
|
||||
/* JS Job support */
|
||||
|
||||
typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValueConst *argv);
|
||||
int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValueConst *argv);
|
||||
|
||||
JS_BOOL JS_IsJobPending(JSRuntime *rt);
|
||||
int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);
|
||||
|
||||
/* Object Writer/Reader (currently only used to handle precompiled code) */
|
||||
#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
|
||||
#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */
|
||||
uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
|
||||
int flags);
|
||||
#define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */
|
||||
#define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */
|
||||
JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
||||
int flags);
|
||||
/* load the dependencies of the module 'obj'. Useful when JS_ReadObject()
|
||||
returns a module. */
|
||||
int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
|
||||
|
||||
/* C function definition */
|
||||
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
|
||||
JS_CFUNC_generic,
|
||||
JS_CFUNC_generic_magic,
|
||||
JS_CFUNC_constructor,
|
||||
JS_CFUNC_constructor_magic,
|
||||
JS_CFUNC_constructor_or_func,
|
||||
JS_CFUNC_constructor_or_func_magic,
|
||||
JS_CFUNC_f_f,
|
||||
JS_CFUNC_f_f_f,
|
||||
JS_CFUNC_getter,
|
||||
JS_CFUNC_setter,
|
||||
JS_CFUNC_getter_magic,
|
||||
JS_CFUNC_setter_magic,
|
||||
JS_CFUNC_iterator_next,
|
||||
} JSCFunctionEnum;
|
||||
|
||||
typedef union JSCFunctionType {
|
||||
JSCFunction *generic;
|
||||
JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
|
||||
JSCFunction *constructor;
|
||||
JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic);
|
||||
JSCFunction *constructor_or_func;
|
||||
double (*f_f)(double);
|
||||
double (*f_f_f)(double, double);
|
||||
JSValue (*getter)(JSContext *ctx, JSValueConst this_val);
|
||||
JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val);
|
||||
JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic);
|
||||
JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic);
|
||||
JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv, int *pdone, int magic);
|
||||
} JSCFunctionType;
|
||||
|
||||
JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
|
||||
const char *name,
|
||||
int length, JSCFunctionEnum cproto, int magic);
|
||||
JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
|
||||
int length, int magic, int data_len,
|
||||
JSValueConst *data);
|
||||
|
||||
static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name,
|
||||
int length)
|
||||
{
|
||||
return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0);
|
||||
}
|
||||
|
||||
static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func,
|
||||
const char *name,
|
||||
int length, JSCFunctionEnum cproto, int magic)
|
||||
{
|
||||
return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic);
|
||||
}
|
||||
void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
|
||||
JSValueConst proto);
|
||||
|
||||
/* C property definition */
|
||||
|
||||
typedef struct JSCFunctionListEntry {
|
||||
const char *name;
|
||||
uint8_t prop_flags;
|
||||
uint8_t def_type;
|
||||
int16_t magic;
|
||||
union {
|
||||
struct {
|
||||
uint8_t length; /* XXX: should move outside union */
|
||||
uint8_t cproto; /* XXX: should move outside union */
|
||||
JSCFunctionType cfunc;
|
||||
} func;
|
||||
struct {
|
||||
JSCFunctionType get;
|
||||
JSCFunctionType set;
|
||||
} getset;
|
||||
struct {
|
||||
const char *name;
|
||||
int base;
|
||||
} alias;
|
||||
struct {
|
||||
const struct JSCFunctionListEntry *tab;
|
||||
int len;
|
||||
} prop_list;
|
||||
const char *str;
|
||||
int32_t i32;
|
||||
int64_t i64;
|
||||
double f64;
|
||||
} u;
|
||||
} JSCFunctionListEntry;
|
||||
|
||||
#define JS_DEF_CFUNC 0
|
||||
#define JS_DEF_CGETSET 1
|
||||
#define JS_DEF_CGETSET_MAGIC 2
|
||||
#define JS_DEF_PROP_STRING 3
|
||||
#define JS_DEF_PROP_INT32 4
|
||||
#define JS_DEF_PROP_INT64 5
|
||||
#define JS_DEF_PROP_DOUBLE 6
|
||||
#define JS_DEF_PROP_UNDEFINED 7
|
||||
#define JS_DEF_OBJECT 8
|
||||
#define JS_DEF_ALIAS 9
|
||||
|
||||
/* Note: c++ does not like nested designators */
|
||||
#define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } }
|
||||
#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } }
|
||||
#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } }
|
||||
#define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } }
|
||||
#define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u = { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } }
|
||||
#define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u = { .str = cstr } }
|
||||
#define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } }
|
||||
#define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u = { .i64 = val } }
|
||||
#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = { .f64 = val } }
|
||||
#define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } }
|
||||
#define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u = { .prop_list = { tab, len } } }
|
||||
#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } }
|
||||
#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } }
|
||||
|
||||
void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
|
||||
const JSCFunctionListEntry *tab,
|
||||
int len);
|
||||
|
||||
/* C module definition */
|
||||
|
||||
typedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m);
|
||||
|
||||
JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
|
||||
JSModuleInitFunc *func);
|
||||
/* can only be called before the module is instantiated */
|
||||
int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str);
|
||||
int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
|
||||
const JSCFunctionListEntry *tab, int len);
|
||||
/* can only be called after the module is instantiated */
|
||||
int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
|
||||
JSValue val);
|
||||
int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
|
||||
const JSCFunctionListEntry *tab, int len);
|
||||
|
||||
#undef js_unlikely
|
||||
#undef js_force_inline
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" { */
|
||||
#endif
|
||||
|
||||
#endif /* QUICKJS_H */
|
1
readme.txt
Normal file
1
readme.txt
Normal file
@ -0,0 +1 @@
|
||||
The main documentation is in doc/quickjs.pdf or doc/quickjs.html.
|
107
release.sh
Executable file
107
release.sh
Executable file
@ -0,0 +1,107 @@
|
||||
#!/bin/sh
|
||||
# Release the QuickJS source code
|
||||
|
||||
set -e
|
||||
|
||||
version=`cat VERSION`
|
||||
|
||||
if [ "$1" = "-h" ] ; then
|
||||
echo "release.sh [all]"
|
||||
echo ""
|
||||
echo "all: build all the archives. Otherwise only build the quickjs source archive."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
extras="no"
|
||||
binary="no"
|
||||
quickjs="no"
|
||||
|
||||
if [ "$1" = "all" ] ; then
|
||||
extras="yes"
|
||||
binary="yes"
|
||||
quickjs="yes"
|
||||
elif [ "$1" = "binary" ] ; then
|
||||
binary="yes"
|
||||
else
|
||||
quickjs="yes"
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# extras
|
||||
|
||||
if [ "$extras" = "yes" ] ; then
|
||||
|
||||
d="quickjs-${version}"
|
||||
name="quickjs-extras-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir $outdir/unicode $outdir/tests
|
||||
|
||||
cp unicode/* $outdir/unicode
|
||||
cp -a tests/bench-v8 $outdir/tests
|
||||
|
||||
( cd /tmp && tar Jcvf /tmp/${name}.tar.xz ${d} )
|
||||
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# binary release
|
||||
|
||||
if [ "$binary" = "yes" ] ; then
|
||||
|
||||
d="quickjs-linux-x86_64-${version}"
|
||||
name="quickjs-linux-x86_64-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
files="qjs run-test262"
|
||||
|
||||
make -j4 $files
|
||||
|
||||
strip $files
|
||||
cp $files $outdir
|
||||
|
||||
( cd /tmp/$d && rm -f ../${name}.zip && zip -r ../${name}.zip . )
|
||||
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# quickjs
|
||||
|
||||
if [ "$quickjs" = "yes" ] ; then
|
||||
|
||||
make build_doc
|
||||
|
||||
d="quickjs-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir $outdir/doc $outdir/tests $outdir/examples
|
||||
|
||||
cp Makefile VERSION TODO Changelog readme.txt release.sh unicode_download.sh \
|
||||
qjs.c qjsc.c qjscalc.js repl.js \
|
||||
quickjs.c quickjs.h quickjs-atom.h \
|
||||
quickjs-libc.c quickjs-libc.h quickjs-opcode.h \
|
||||
cutils.c cutils.h list.h \
|
||||
libregexp.c libregexp.h libregexp-opcode.h \
|
||||
libunicode.c libunicode.h libunicode-table.h \
|
||||
libbf.c libbf.h \
|
||||
jscompress.c unicode_gen.c unicode_gen_def.h \
|
||||
run-test262.c test262o.conf test262.conf \
|
||||
test262o_errors.txt test262_errors.txt \
|
||||
$outdir
|
||||
|
||||
cp tests/*.js tests/*.patch tests/bjson.c $outdir/tests
|
||||
|
||||
cp examples/*.js examples/*.c $outdir/examples
|
||||
|
||||
cp doc/quickjs.texi doc/quickjs.pdf doc/quickjs.html \
|
||||
doc/jsbignum.texi doc/jsbignum.html doc/jsbignum.pdf \
|
||||
$outdir/doc
|
||||
|
||||
( cd /tmp && tar Jcvf /tmp/${d}.tar.xz ${d} )
|
||||
|
||||
fi
|
2098
run-test262.c
Normal file
2098
run-test262.c
Normal file
File diff suppressed because it is too large
Load Diff
182
test262.conf
Normal file
182
test262.conf
Normal file
@ -0,0 +1,182 @@
|
||||
[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=test262/harness
|
||||
|
||||
# names of harness include files to skip
|
||||
#harnessexclude=
|
||||
|
||||
# name of the error file for known errors
|
||||
errorfile=test262_errors.txt
|
||||
|
||||
# exclude tests enumerated in this file (see also [exclude] section)
|
||||
#excludefile=test262_exclude.txt
|
||||
|
||||
# report test results to this file
|
||||
reportfile=test262_report.txt
|
||||
|
||||
# enumerate tests from this directory
|
||||
testdir=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=skip
|
||||
Array.prototype.flat
|
||||
Array.prototype.flatMap
|
||||
Array.prototype.flatten
|
||||
Array.prototype.values
|
||||
ArrayBuffer
|
||||
arrow-function
|
||||
async-functions
|
||||
async-iteration
|
||||
Atomics
|
||||
BigInt
|
||||
caller
|
||||
class
|
||||
class-fields-private
|
||||
class-fields-public
|
||||
class-methods-private
|
||||
class-static-fields-public
|
||||
class-static-fields-private
|
||||
class-static-methods-private
|
||||
coalesce-expression
|
||||
computed-property-names
|
||||
const
|
||||
cross-realm=skip
|
||||
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-arg
|
||||
default-parameters
|
||||
destructuring-assignment
|
||||
destructuring-binding
|
||||
dynamic-import
|
||||
export-star-as-namespace-from-module
|
||||
FinalizationGroup=skip
|
||||
Float32Array
|
||||
Float64Array
|
||||
for-in-order
|
||||
for-of
|
||||
generators
|
||||
globalThis
|
||||
hashbang
|
||||
host-gc-required=skip
|
||||
import.meta
|
||||
Int32Array
|
||||
Int8Array
|
||||
IsHTMLDDA=skip
|
||||
json-superset
|
||||
let
|
||||
Map
|
||||
new.target
|
||||
numeric-separator-literal
|
||||
object-rest
|
||||
object-spread
|
||||
Object.fromEntries
|
||||
Object.is
|
||||
optional-catch-binding
|
||||
optional-chaining
|
||||
Promise.allSettled
|
||||
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
|
||||
rest-parameters
|
||||
Set
|
||||
SharedArrayBuffer
|
||||
string-trimming
|
||||
String.fromCodePoint
|
||||
String.prototype.endsWith
|
||||
String.prototype.includes
|
||||
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
|
||||
top-level-await=skip
|
||||
TypedArray
|
||||
u180e
|
||||
Uint16Array
|
||||
Uint8Array
|
||||
Uint8ClampedArray
|
||||
WeakMap
|
||||
WeakRef=skip
|
||||
WeakSet
|
||||
well-formed-json-stringify
|
||||
|
||||
[exclude]
|
||||
# list excluded tests and directories here
|
||||
|
||||
# intl not supported
|
||||
test262/test/intl402/
|
||||
|
||||
# incompatible with the "caller" feature
|
||||
test262/test/built-ins/Function/prototype/restricted-property-caller.js
|
||||
test262/test/built-ins/Function/prototype/restricted-property-arguments.js
|
||||
test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
|
||||
|
||||
# slow tests
|
||||
#test262/test/built-ins/RegExp/CharacterClassEscapes/
|
||||
#test262/test/built-ins/RegExp/property-escapes/
|
||||
|
||||
[tests]
|
||||
# list test files or use config.testdir
|
4
test262_errors.txt
Normal file
4
test262_errors.txt
Normal file
@ -0,0 +1,4 @@
|
||||
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: value has no property
|
||||
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: value has no property
|
410
test262o.conf
Normal file
410
test262o.conf
Normal file
@ -0,0 +1,410 @@
|
||||
[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
test262o_errors.txt
Normal file
0
test262o_errors.txt
Normal file
88
tests/bjson.c
Normal file
88
tests/bjson.c
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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");
|
||||
obj = JS_ReadObject(ctx, buf + pos, len, 0);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
size_t len;
|
||||
uint8_t *buf;
|
||||
JSValue array;
|
||||
|
||||
buf = JS_WriteObject(ctx, &len, argv[0], 0);
|
||||
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", 3, js_bjson_read ),
|
||||
JS_CFUNC_DEF("write", 1, 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;
|
||||
}
|
1053
tests/microbench.js
Normal file
1053
tests/microbench.js
Normal file
File diff suppressed because it is too large
Load Diff
71
tests/test262.patch
Normal file
71
tests/test262.patch
Normal file
@ -0,0 +1,71 @@
|
||||
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) {
|
241
tests/test_bignum.js
Normal file
241
tests/test_bignum.js
Normal file
@ -0,0 +1,241 @@
|
||||
"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);
|
||||
}
|
||||
|
||||
function test_bigdecimal()
|
||||
{
|
||||
assert(1d === 1d);
|
||||
assert(1d !== 2d);
|
||||
test_less(1d, 2d);
|
||||
test_eq(2d, 2d);
|
||||
|
||||
test_less(1, 2d);
|
||||
test_eq(2, 2d);
|
||||
|
||||
test_less(1.1, 2d);
|
||||
test_eq(Math.sqrt(4), 2d);
|
||||
|
||||
test_less(2n, 3d);
|
||||
test_eq(3n, 3d);
|
||||
|
||||
assert(BigDecimal("1234.1") === 1234.1d);
|
||||
assert(BigDecimal(" 1234.1") === 1234.1d);
|
||||
assert(BigDecimal(" 1234.1 ") === 1234.1d);
|
||||
|
||||
assert(BigDecimal(0.1) === 0.1d);
|
||||
assert(BigDecimal(123) === 123d);
|
||||
assert(BigDecimal(true) === 1d);
|
||||
|
||||
assert(123d + 1d === 124d);
|
||||
assert(123d - 1d === 122d);
|
||||
|
||||
assert(3.2d * 3d === 9.6d);
|
||||
assert(10d / 2d === 5d);
|
||||
assertThrows(RangeError, () => { 10d / 3d } );
|
||||
assert(BigDecimal.div(20d, 3d,
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: 3 }) === 6.67d);
|
||||
assert(BigDecimal.div(20d, 3d,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 3 }) === 6.667d);
|
||||
|
||||
assert(10d % 3d === 1d);
|
||||
assert(-10d % 3d === -1d);
|
||||
|
||||
assert(-10d % 3d === -1d);
|
||||
|
||||
assert(1234.5d ** 3d === 1881365963.625d);
|
||||
assertThrows(RangeError, () => { 2d ** 3.1d } );
|
||||
assertThrows(RangeError, () => { 2d ** -3d } );
|
||||
|
||||
assert(BigDecimal.sqrt(2d,
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: 4 }) === 1.414d);
|
||||
|
||||
assert(BigDecimal.round(3.14159d,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 3 }) === 3.142d);
|
||||
}
|
||||
|
||||
test_bigint1();
|
||||
test_bigint2();
|
||||
test_bigint_ext();
|
||||
test_bigfloat();
|
||||
test_bigdecimal();
|
125
tests/test_bjson.js
Normal file
125
tests/test_bjson.js
Normal file
@ -0,0 +1,125 @@
|
||||
import * as bjson from "./bjson.so";
|
||||
|
||||
function assert(b, str)
|
||||
{
|
||||
if (b) {
|
||||
return;
|
||||
} else {
|
||||
throw Error("assertion failed: " + str);
|
||||
}
|
||||
}
|
||||
|
||||
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 toStr(a)
|
||||
{
|
||||
var s, i, props, prop;
|
||||
|
||||
switch(typeof(a)) {
|
||||
case "object":
|
||||
if (a === null)
|
||||
return "null";
|
||||
if (Array.isArray(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);
|
||||
}
|
||||
}
|
||||
|
||||
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")]);
|
||||
}
|
||||
|
||||
/* tested with a circular reference */
|
||||
obj = {};
|
||||
obj.x = obj;
|
||||
try {
|
||||
bjson.write(obj);
|
||||
assert(false);
|
||||
} catch(e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
}
|
||||
|
||||
bjson_test_all();
|
647
tests/test_builtin.js
Normal file
647
tests/test_builtin.js
Normal file
@ -0,0 +1,647 @@
|
||||
"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 + ")" : ""));
|
||||
}
|
||||
|
||||
// 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 = 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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
assert(a.toString(), "0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255");
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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
tests/test_closure.js
Normal file
221
tests/test_closure.js
Normal file
@ -0,0 +1,221 @@
|
||||
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();
|
368
tests/test_loop.js
Normal file
368
tests/test_loop.js
Normal file
@ -0,0 +1,368 @@
|
||||
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();
|
363
tests/test_op.js
Normal file
363
tests/test_op.js
Normal file
@ -0,0 +1,363 @@
|
||||
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_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()
|
||||
{
|
||||
function f() { }
|
||||
assert(f.prototype.constructor, f, "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");
|
||||
}
|
||||
|
||||
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; };
|
||||
}
|
||||
|
||||
test_op1();
|
||||
test_cvt();
|
||||
test_eq();
|
||||
test_inc_dec();
|
||||
test_op2();
|
||||
test_delete();
|
||||
test_prototype();
|
||||
test_arguments();
|
||||
test_class();
|
||||
test_template();
|
||||
test_object_literal();
|
||||
test_regexp_skip();
|
||||
test_labels();
|
244
tests/test_qjscalc.js
Normal file
244
tests/test_qjscalc.js
Normal file
@ -0,0 +1,244 @@
|
||||
"use math";
|
||||
"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 pow(a, n)
|
||||
{
|
||||
var r, i;
|
||||
r = 1;
|
||||
for(i = 0; i < n; i++)
|
||||
r *= a;
|
||||
return r;
|
||||
}
|
||||
|
||||
function test_integer()
|
||||
{
|
||||
var a, r;
|
||||
a = pow(3, 100);
|
||||
assert((a - 1) != a);
|
||||
assert(a == 515377520732011331036461129765621272702107522001);
|
||||
assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1);
|
||||
assert(Integer.isInteger(1) === true);
|
||||
assert(Integer.isInteger(1.0) === false);
|
||||
|
||||
assert(Integer.floorLog2(0) === -1);
|
||||
assert(Integer.floorLog2(7) === 2);
|
||||
|
||||
r = 1 << 31;
|
||||
assert(r, 2147483648, "1 << 31 === 2147483648");
|
||||
|
||||
r = 1 << 32;
|
||||
assert(r, 4294967296, "1 << 32 === 4294967296");
|
||||
|
||||
r = (1 << 31) < 0;
|
||||
assert(r, false, "(1 << 31) < 0 === false");
|
||||
}
|
||||
|
||||
function test_float()
|
||||
{
|
||||
var e, a, b, sqrt2;
|
||||
|
||||
assert(typeof 1 === "bigint");
|
||||
assert(typeof 1.0 === "bigfloat");
|
||||
assert(1 == 1.0);
|
||||
assert(1 !== 1.0);
|
||||
}
|
||||
|
||||
/* jscalc tests */
|
||||
|
||||
function test_modulo()
|
||||
{
|
||||
var i, p, a, b;
|
||||
|
||||
/* Euclidian modulo operator */
|
||||
assert((-3) % 2 == 1);
|
||||
assert(3 % (-2) == 1);
|
||||
|
||||
p = 101;
|
||||
for(i = 1; i < p; i++) {
|
||||
a = Integer.invmod(i, p);
|
||||
assert(a >= 0 && a < p);
|
||||
assert((i * a) % p == 1);
|
||||
}
|
||||
|
||||
assert(Integer.isPrime(2^107-1));
|
||||
assert(!Integer.isPrime((2^107-1) * (2^89-1)));
|
||||
a = Integer.factor((2^89-1)*2^3*11*13^2*1009);
|
||||
assert(a == [ 2,2,2,11,13,13,1009,618970019642690137449562111 ]);
|
||||
}
|
||||
|
||||
function test_mod()
|
||||
{
|
||||
var a, b, p;
|
||||
|
||||
a = Mod(3, 101);
|
||||
b = Mod(-1, 101);
|
||||
assert((a + b) == Mod(2, 101));
|
||||
assert(a ^ 100 == Mod(1, 101));
|
||||
|
||||
p = 2 ^ 607 - 1; /* mersenne prime */
|
||||
a = Mod(3, p) ^ (p - 1);
|
||||
assert(a == Mod(1, p));
|
||||
}
|
||||
|
||||
function test_polynomial()
|
||||
{
|
||||
var a, b, q, r, t, i;
|
||||
a = (1 + X) ^ 4;
|
||||
assert(a == X^4+4*X^3+6*X^2+4*X+1);
|
||||
|
||||
r = (1 + X);
|
||||
q = (1+X+X^2);
|
||||
b = (1 - X^2);
|
||||
a = q * b + r;
|
||||
t = Polynomial.divrem(a, b);
|
||||
assert(t[0] == q);
|
||||
assert(t[1] == r);
|
||||
|
||||
a = 1 + 2*X + 3*X^2;
|
||||
assert(a.apply(0.1) == 1.23);
|
||||
|
||||
a = 1-2*X^2+2*X^3;
|
||||
assert(deriv(a) == (6*X^2-4*X));
|
||||
assert(deriv(integ(a)) == a);
|
||||
|
||||
a = (X-1)*(X-2)*(X-3)*(X-4)*(X-0.1);
|
||||
r = polroots(a);
|
||||
for(i = 0; i < r.length; i++) {
|
||||
b = abs(a.apply(r[i]));
|
||||
assert(b <= 1e-13);
|
||||
}
|
||||
}
|
||||
|
||||
function test_poly_mod()
|
||||
{
|
||||
var a, p;
|
||||
|
||||
/* modulo using polynomials */
|
||||
p = X^2 + X + 1;
|
||||
a = PolyMod(3+X, p) ^ 10;
|
||||
assert(a == PolyMod(-3725*X-18357, p));
|
||||
|
||||
a = PolyMod(1/X, 1+X^2);
|
||||
assert(a == PolyMod(-X, X^2+1));
|
||||
}
|
||||
|
||||
function test_rfunc()
|
||||
{
|
||||
var a;
|
||||
a = (X+1)/((X+1)*(X-1));
|
||||
assert(a == 1/(X-1));
|
||||
a = (X + 2) / (X - 2);
|
||||
assert(a.apply(1/3) == -7/5);
|
||||
|
||||
assert(deriv((X^2-X+1)/(X-1)) == (X^2-2*X)/(X^2-2*X+1));
|
||||
}
|
||||
|
||||
function test_series()
|
||||
{
|
||||
var a, b;
|
||||
a = 1+X+O(X^5);
|
||||
b = a.inverse();
|
||||
assert(b == 1-X+X^2-X^3+X^4+O(X^5));
|
||||
assert(deriv(b) == -1+2*X-3*X^2+4*X^3+O(X^4));
|
||||
assert(deriv(integ(b)) == b);
|
||||
|
||||
a = Series(1/(1-X), 5);
|
||||
assert(a == 1+X+X^2+X^3+X^4+O(X^5));
|
||||
b = a.apply(0.1);
|
||||
assert(b == 1.1111);
|
||||
|
||||
assert(exp(3*X^2+O(X^10)) == 1+3*X^2+9/2*X^4+9/2*X^6+27/8*X^8+O(X^10));
|
||||
assert(sin(X+O(X^6)) == X-1/6*X^3+1/120*X^5+O(X^6));
|
||||
assert(cos(X+O(X^6)) == 1-1/2*X^2+1/24*X^4+O(X^6));
|
||||
assert(tan(X+O(X^8)) == X+1/3*X^3+2/15*X^5+17/315*X^7+O(X^8));
|
||||
assert((1+X+O(X^6))^(2+X) == 1+2*X+2*X^2+3/2*X^3+5/6*X^4+5/12*X^5+O(X^6));
|
||||
}
|
||||
|
||||
function test_matrix()
|
||||
{
|
||||
var a, b, r;
|
||||
a = [[1, 2],[3, 4]];
|
||||
b = [3, 4];
|
||||
r = a * b;
|
||||
assert(r == [11, 25]);
|
||||
r = (a^-1) * 2;
|
||||
assert(r == [[-4, 2],[3, -1]]);
|
||||
|
||||
assert(norm2([1,2,3]) == 14);
|
||||
|
||||
assert(diag([1,2,3]) == [ [ 1, 0, 0 ], [ 0, 2, 0 ], [ 0, 0, 3 ] ]);
|
||||
assert(trans(a) == [ [ 1, 3 ], [ 2, 4 ] ]);
|
||||
assert(trans([1,2,3]) == [[1,2,3]]);
|
||||
assert(trace(a) == 5);
|
||||
|
||||
assert(charpoly(Matrix.hilbert(4)) == X^4-176/105*X^3+3341/12600*X^2-41/23625*X+1/6048000);
|
||||
assert(det(Matrix.hilbert(4)) == 1/6048000);
|
||||
|
||||
a = [[1,2,1],[-2,-3,1],[3,5,0]];
|
||||
assert(rank(a) == 2);
|
||||
assert(ker(a) == [ [ 5 ], [ -3 ], [ 1 ] ]);
|
||||
|
||||
assert(dp([1, 2, 3], [3, -4, -7]) === -26);
|
||||
assert(cp([1, 2, 3], [3, -4, -7]) == [ -2, 16, -10 ]);
|
||||
}
|
||||
|
||||
function assert_eq(a, ref)
|
||||
{
|
||||
assert(abs(a / ref - 1.0) <= 1e-15);
|
||||
}
|
||||
|
||||
function test_trig()
|
||||
{
|
||||
assert_eq(sin(1/2), 0.479425538604203);
|
||||
assert_eq(sin(2+3*I), 9.154499146911428-4.168906959966565*I);
|
||||
assert_eq(cos(2+3*I), -4.189625690968807-9.109227893755337*I);
|
||||
assert_eq((2+0.5*I)^(1.1-0.5*I), 2.494363021357619-0.23076804554558092*I);
|
||||
assert_eq(sqrt(2*I), 1 + I);
|
||||
}
|
||||
|
||||
test_integer();
|
||||
test_float();
|
||||
|
||||
test_modulo();
|
||||
test_mod();
|
||||
test_polynomial();
|
||||
test_poly_mod();
|
||||
test_rfunc();
|
||||
test_series();
|
||||
test_matrix();
|
||||
test_trig();
|
247
tests/test_std.js
Normal file
247
tests/test_std.js
Normal file
@ -0,0 +1,247 @@
|
||||
import * as std from "std";
|
||||
import * as os from "os";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { std.loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
function test_printf()
|
||||
{
|
||||
assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc");
|
||||
}
|
||||
|
||||
function test_file1()
|
||||
{
|
||||
var f, len, str, size, buf, ret, i, str1;
|
||||
|
||||
f = std.tmpfile();
|
||||
str = "hello world\n";
|
||||
f.puts(str);
|
||||
|
||||
f.seek(0, std.SEEK_SET);
|
||||
str1 = f.readAsString();
|
||||
assert(str1 === str);
|
||||
|
||||
f.seek(0, std.SEEK_END);
|
||||
size = f.tell();
|
||||
assert(size === str.length);
|
||||
|
||||
f.seek(0, std.SEEK_SET);
|
||||
|
||||
buf = new Uint8Array(size);
|
||||
ret = f.read(buf.buffer, 0, size);
|
||||
assert(ret === size);
|
||||
for(i = 0; i < size; i++)
|
||||
assert(buf[i] === str.charCodeAt(i));
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
||||
function test_file2()
|
||||
{
|
||||
var f, str, i, size;
|
||||
f = std.tmpfile();
|
||||
str = "hello world\n";
|
||||
size = str.length;
|
||||
for(i = 0; i < size; i++)
|
||||
f.putByte(str.charCodeAt(i));
|
||||
f.seek(0, std.SEEK_SET);
|
||||
for(i = 0; i < size; i++) {
|
||||
assert(str.charCodeAt(i) === f.getByte());
|
||||
}
|
||||
assert(f.getByte() === -1);
|
||||
f.close();
|
||||
}
|
||||
|
||||
function test_getline()
|
||||
{
|
||||
var f, line, line_count, lines, i;
|
||||
|
||||
lines = ["hello world", "line 1", "line 2" ];
|
||||
f = std.tmpfile();
|
||||
for(i = 0; i < lines.length; i++) {
|
||||
f.puts(lines[i], "\n");
|
||||
}
|
||||
|
||||
f.seek(0, std.SEEK_SET);
|
||||
assert(!f.eof());
|
||||
line_count = 0;
|
||||
for(;;) {
|
||||
line = f.getline();
|
||||
if (line === null)
|
||||
break;
|
||||
assert(line == lines[line_count]);
|
||||
line_count++;
|
||||
}
|
||||
assert(f.eof());
|
||||
assert(line_count === lines.length);
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
||||
function test_popen()
|
||||
{
|
||||
var str, f, fname = "tmp_file.txt";
|
||||
var content = "hello world";
|
||||
|
||||
f = std.open(fname, "w");
|
||||
f.puts(content);
|
||||
f.close();
|
||||
|
||||
/* execute the 'cat' shell command */
|
||||
f = std.popen("cat " + fname, "r");
|
||||
str = f.readAsString();
|
||||
f.close();
|
||||
|
||||
assert(str, content);
|
||||
|
||||
os.remove(fname);
|
||||
}
|
||||
|
||||
function test_os()
|
||||
{
|
||||
var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
|
||||
|
||||
assert(os.isatty(0));
|
||||
|
||||
fdir = "test_tmp_dir";
|
||||
fname = "tmp_file.txt";
|
||||
fpath = fdir + "/" + fname;
|
||||
link_path = fdir + "/test_link";
|
||||
|
||||
os.remove(link_path);
|
||||
os.remove(fpath);
|
||||
os.remove(fdir);
|
||||
|
||||
err = os.mkdir(fdir, 0o755);
|
||||
assert(err === 0);
|
||||
|
||||
fd = os.open(fpath, os.O_RDWR | os.O_CREAT | os.O_TRUNC);
|
||||
assert(fd >= 0);
|
||||
|
||||
buf = new Uint8Array(10);
|
||||
for(i = 0; i < buf.length; i++)
|
||||
buf[i] = i;
|
||||
assert(os.write(fd, buf.buffer, 0, buf.length) === buf.length);
|
||||
|
||||
assert(os.seek(fd, 0, os.SEEK_SET) === 0);
|
||||
buf2 = new Uint8Array(buf.length);
|
||||
assert(os.read(fd, buf2.buffer, 0, buf2.length) === buf2.length);
|
||||
|
||||
for(i = 0; i < buf.length; i++)
|
||||
assert(buf[i] == buf2[i]);
|
||||
|
||||
assert(os.close(fd) === 0);
|
||||
|
||||
[files, err] = os.readdir(fdir);
|
||||
assert(err, 0);
|
||||
assert(files.indexOf(fname) >= 0);
|
||||
|
||||
fdate = 10000;
|
||||
|
||||
err = os.utimes(fpath, fdate, fdate);
|
||||
assert(err, 0);
|
||||
|
||||
[st, err] = os.stat(fpath);
|
||||
assert(err, 0);
|
||||
assert(st.mode & os.S_IFMT, os.S_IFREG);
|
||||
assert(st.mtime, fdate);
|
||||
|
||||
err = os.symlink(fname, link_path);
|
||||
assert(err === 0);
|
||||
|
||||
[st, err] = os.lstat(link_path);
|
||||
assert(err, 0);
|
||||
assert(st.mode & os.S_IFMT, os.S_IFLNK);
|
||||
|
||||
[buf, err] = os.readlink(link_path);
|
||||
assert(err, 0);
|
||||
assert(buf, fname);
|
||||
|
||||
assert(os.remove(link_path) === 0);
|
||||
|
||||
[buf, err] = os.getcwd();
|
||||
assert(err, 0);
|
||||
|
||||
[buf2, err] = os.realpath(".");
|
||||
assert(err, 0);
|
||||
|
||||
assert(buf, buf2);
|
||||
|
||||
assert(os.remove(fpath) === 0);
|
||||
|
||||
fd = os.open(fpath, os.O_RDONLY);
|
||||
assert(fd < 0);
|
||||
|
||||
assert(os.remove(fdir) === 0);
|
||||
}
|
||||
|
||||
function test_os_exec()
|
||||
{
|
||||
var ret, fds, pid, f, status;
|
||||
|
||||
ret = os.exec(["true"]);
|
||||
assert(ret, 0);
|
||||
|
||||
ret = os.exec(["/bin/sh", "-c", "exit 1"], { usePath: false });
|
||||
assert(ret, 1);
|
||||
|
||||
fds = os.pipe();
|
||||
pid = os.exec(["echo", "hello"], { stdout: fds[1], block: false } );
|
||||
assert(pid >= 0);
|
||||
os.close(fds[1]); /* close the write end (as it is only in the child) */
|
||||
f = std.fdopen(fds[0], "r");
|
||||
assert(f.getline(), "hello");
|
||||
assert(f.getline(), null);
|
||||
f.close();
|
||||
[ret, status] = os.waitpid(pid, 0);
|
||||
assert(ret, pid);
|
||||
assert(status & 0x7f, 0); /* exited */
|
||||
assert(status >> 8, 0); /* exit code */
|
||||
|
||||
pid = os.exec(["cat"], { block: false } );
|
||||
assert(pid >= 0);
|
||||
os.kill(pid, os.SIGQUIT);
|
||||
[ret, status] = os.waitpid(pid, 0);
|
||||
assert(ret, pid);
|
||||
assert(status & 0x7f, os.SIGQUIT);
|
||||
}
|
||||
|
||||
function test_timer()
|
||||
{
|
||||
var th, i;
|
||||
|
||||
/* just test that a timer can be inserted and removed */
|
||||
th = [];
|
||||
for(i = 0; i < 3; i++)
|
||||
th[i] = os.setTimeout(function () { }, 1000);
|
||||
for(i = 0; i < 3; i++)
|
||||
os.clearTimeout(th[i]);
|
||||
}
|
||||
|
||||
test_printf();
|
||||
test_file1();
|
||||
test_file2();
|
||||
test_getline();
|
||||
test_popen();
|
||||
test_os();
|
||||
test_os_exec();
|
||||
test_timer();
|
19
unicode_download.sh
Executable file
19
unicode_download.sh
Executable file
@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
url="ftp://ftp.unicode.org/Public/12.1.0/ucd"
|
||||
emoji_url="ftp://ftp.unicode.org/Public/emoji/12.0/emoji-data.txt"
|
||||
|
||||
files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \
|
||||
SpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \
|
||||
UnicodeData.txt DerivedCoreProperties.txt NormalizationTest.txt Scripts.txt \
|
||||
PropertyValueAliases.txt"
|
||||
|
||||
mkdir -p unicode
|
||||
|
||||
for f in $files; do
|
||||
g="${url}/${f}"
|
||||
wget $g -O unicode/$f
|
||||
done
|
||||
|
||||
wget $emoji_url -O unicode/emoji-data.txt
|
3057
unicode_gen.c
Normal file
3057
unicode_gen.c
Normal file
File diff suppressed because it is too large
Load Diff
280
unicode_gen_def.h
Normal file
280
unicode_gen_def.h
Normal file
@ -0,0 +1,280 @@
|
||||
#ifdef UNICODE_GENERAL_CATEGORY
|
||||
DEF(Cn, "Unassigned") /* must be zero */
|
||||
DEF(Lu, "Uppercase_Letter")
|
||||
DEF(Ll, "Lowercase_Letter")
|
||||
DEF(Lt, "Titlecase_Letter")
|
||||
DEF(Lm, "Modifier_Letter")
|
||||
DEF(Lo, "Other_Letter")
|
||||
DEF(Mn, "Nonspacing_Mark")
|
||||
DEF(Mc, "Spacing_Mark")
|
||||
DEF(Me, "Enclosing_Mark")
|
||||
DEF(Nd, "Decimal_Number,digit")
|
||||
DEF(Nl, "Letter_Number")
|
||||
DEF(No, "Other_Number")
|
||||
DEF(Sm, "Math_Symbol")
|
||||
DEF(Sc, "Currency_Symbol")
|
||||
DEF(Sk, "Modifier_Symbol")
|
||||
DEF(So, "Other_Symbol")
|
||||
DEF(Pc, "Connector_Punctuation")
|
||||
DEF(Pd, "Dash_Punctuation")
|
||||
DEF(Ps, "Open_Punctuation")
|
||||
DEF(Pe, "Close_Punctuation")
|
||||
DEF(Pi, "Initial_Punctuation")
|
||||
DEF(Pf, "Final_Punctuation")
|
||||
DEF(Po, "Other_Punctuation")
|
||||
DEF(Zs, "Space_Separator")
|
||||
DEF(Zl, "Line_Separator")
|
||||
DEF(Zp, "Paragraph_Separator")
|
||||
DEF(Cc, "Control,cntrl")
|
||||
DEF(Cf, "Format")
|
||||
DEF(Cs, "Surrogate")
|
||||
DEF(Co, "Private_Use")
|
||||
/* synthetic properties */
|
||||
DEF(LC, "Cased_Letter")
|
||||
DEF(L, "Letter")
|
||||
DEF(M, "Mark,Combining_Mark")
|
||||
DEF(N, "Number")
|
||||
DEF(S, "Symbol")
|
||||
DEF(P, "Punctuation,punct")
|
||||
DEF(Z, "Separator")
|
||||
DEF(C, "Other")
|
||||
#endif
|
||||
|
||||
#ifdef UNICODE_SCRIPT
|
||||
/* scripts aliases names in PropertyValueAliases.txt */
|
||||
DEF(Unknown, "Zzzz")
|
||||
DEF(Adlam, "Adlm")
|
||||
DEF(Ahom, "Ahom")
|
||||
DEF(Anatolian_Hieroglyphs, "Hluw")
|
||||
DEF(Arabic, "Arab")
|
||||
DEF(Armenian, "Armn")
|
||||
DEF(Avestan, "Avst")
|
||||
DEF(Balinese, "Bali")
|
||||
DEF(Bamum, "Bamu")
|
||||
DEF(Bassa_Vah, "Bass")
|
||||
DEF(Batak, "Batk")
|
||||
DEF(Bengali, "Beng")
|
||||
DEF(Bhaiksuki, "Bhks")
|
||||
DEF(Bopomofo, "Bopo")
|
||||
DEF(Brahmi, "Brah")
|
||||
DEF(Braille, "Brai")
|
||||
DEF(Buginese, "Bugi")
|
||||
DEF(Buhid, "Buhd")
|
||||
DEF(Canadian_Aboriginal, "Cans")
|
||||
DEF(Carian, "Cari")
|
||||
DEF(Caucasian_Albanian, "Aghb")
|
||||
DEF(Chakma, "Cakm")
|
||||
DEF(Cham, "Cham")
|
||||
DEF(Cherokee, "Cher")
|
||||
DEF(Common, "Zyyy")
|
||||
DEF(Coptic, "Copt,Qaac")
|
||||
DEF(Cuneiform, "Xsux")
|
||||
DEF(Cypriot, "Cprt")
|
||||
DEF(Cyrillic, "Cyrl")
|
||||
DEF(Deseret, "Dsrt")
|
||||
DEF(Devanagari, "Deva")
|
||||
DEF(Dogra, "Dogr")
|
||||
DEF(Duployan, "Dupl")
|
||||
DEF(Egyptian_Hieroglyphs, "Egyp")
|
||||
DEF(Elbasan, "Elba")
|
||||
DEF(Elymaic, "Elym")
|
||||
DEF(Ethiopic, "Ethi")
|
||||
DEF(Georgian, "Geor")
|
||||
DEF(Glagolitic, "Glag")
|
||||
DEF(Gothic, "Goth")
|
||||
DEF(Grantha, "Gran")
|
||||
DEF(Greek, "Grek")
|
||||
DEF(Gujarati, "Gujr")
|
||||
DEF(Gunjala_Gondi, "Gong")
|
||||
DEF(Gurmukhi, "Guru")
|
||||
DEF(Han, "Hani")
|
||||
DEF(Hangul, "Hang")
|
||||
DEF(Hanifi_Rohingya, "Rohg")
|
||||
DEF(Hanunoo, "Hano")
|
||||
DEF(Hatran, "Hatr")
|
||||
DEF(Hebrew, "Hebr")
|
||||
DEF(Hiragana, "Hira")
|
||||
DEF(Imperial_Aramaic, "Armi")
|
||||
DEF(Inherited, "Zinh,Qaai")
|
||||
DEF(Inscriptional_Pahlavi, "Phli")
|
||||
DEF(Inscriptional_Parthian, "Prti")
|
||||
DEF(Javanese, "Java")
|
||||
DEF(Kaithi, "Kthi")
|
||||
DEF(Kannada, "Knda")
|
||||
DEF(Katakana, "Kana")
|
||||
DEF(Kayah_Li, "Kali")
|
||||
DEF(Kharoshthi, "Khar")
|
||||
DEF(Khmer, "Khmr")
|
||||
DEF(Khojki, "Khoj")
|
||||
DEF(Khudawadi, "Sind")
|
||||
DEF(Lao, "Laoo")
|
||||
DEF(Latin, "Latn")
|
||||
DEF(Lepcha, "Lepc")
|
||||
DEF(Limbu, "Limb")
|
||||
DEF(Linear_A, "Lina")
|
||||
DEF(Linear_B, "Linb")
|
||||
DEF(Lisu, "Lisu")
|
||||
DEF(Lycian, "Lyci")
|
||||
DEF(Lydian, "Lydi")
|
||||
DEF(Makasar, "Maka")
|
||||
DEF(Mahajani, "Mahj")
|
||||
DEF(Malayalam, "Mlym")
|
||||
DEF(Mandaic, "Mand")
|
||||
DEF(Manichaean, "Mani")
|
||||
DEF(Marchen, "Marc")
|
||||
DEF(Masaram_Gondi, "Gonm")
|
||||
DEF(Medefaidrin, "Medf")
|
||||
DEF(Meetei_Mayek, "Mtei")
|
||||
DEF(Mende_Kikakui, "Mend")
|
||||
DEF(Meroitic_Cursive, "Merc")
|
||||
DEF(Meroitic_Hieroglyphs, "Mero")
|
||||
DEF(Miao, "Plrd")
|
||||
DEF(Modi, "Modi")
|
||||
DEF(Mongolian, "Mong")
|
||||
DEF(Mro, "Mroo")
|
||||
DEF(Multani, "Mult")
|
||||
DEF(Myanmar, "Mymr")
|
||||
DEF(Nabataean, "Nbat")
|
||||
DEF(Nandinagari, "Nand")
|
||||
DEF(New_Tai_Lue, "Talu")
|
||||
DEF(Newa, "Newa")
|
||||
DEF(Nko, "Nkoo")
|
||||
DEF(Nushu, "Nshu")
|
||||
DEF(Nyiakeng_Puachue_Hmong, "Hmnp")
|
||||
DEF(Ogham, "Ogam")
|
||||
DEF(Ol_Chiki, "Olck")
|
||||
DEF(Old_Hungarian, "Hung")
|
||||
DEF(Old_Italic, "Ital")
|
||||
DEF(Old_North_Arabian, "Narb")
|
||||
DEF(Old_Permic, "Perm")
|
||||
DEF(Old_Persian, "Xpeo")
|
||||
DEF(Old_Sogdian, "Sogo")
|
||||
DEF(Old_South_Arabian, "Sarb")
|
||||
DEF(Old_Turkic, "Orkh")
|
||||
DEF(Oriya, "Orya")
|
||||
DEF(Osage, "Osge")
|
||||
DEF(Osmanya, "Osma")
|
||||
DEF(Pahawh_Hmong, "Hmng")
|
||||
DEF(Palmyrene, "Palm")
|
||||
DEF(Pau_Cin_Hau, "Pauc")
|
||||
DEF(Phags_Pa, "Phag")
|
||||
DEF(Phoenician, "Phnx")
|
||||
DEF(Psalter_Pahlavi, "Phlp")
|
||||
DEF(Rejang, "Rjng")
|
||||
DEF(Runic, "Runr")
|
||||
DEF(Samaritan, "Samr")
|
||||
DEF(Saurashtra, "Saur")
|
||||
DEF(Sharada, "Shrd")
|
||||
DEF(Shavian, "Shaw")
|
||||
DEF(Siddham, "Sidd")
|
||||
DEF(SignWriting, "Sgnw")
|
||||
DEF(Sinhala, "Sinh")
|
||||
DEF(Sogdian, "Sogd")
|
||||
DEF(Sora_Sompeng, "Sora")
|
||||
DEF(Soyombo, "Soyo")
|
||||
DEF(Sundanese, "Sund")
|
||||
DEF(Syloti_Nagri, "Sylo")
|
||||
DEF(Syriac, "Syrc")
|
||||
DEF(Tagalog, "Tglg")
|
||||
DEF(Tagbanwa, "Tagb")
|
||||
DEF(Tai_Le, "Tale")
|
||||
DEF(Tai_Tham, "Lana")
|
||||
DEF(Tai_Viet, "Tavt")
|
||||
DEF(Takri, "Takr")
|
||||
DEF(Tamil, "Taml")
|
||||
DEF(Tangut, "Tang")
|
||||
DEF(Telugu, "Telu")
|
||||
DEF(Thaana, "Thaa")
|
||||
DEF(Thai, "Thai")
|
||||
DEF(Tibetan, "Tibt")
|
||||
DEF(Tifinagh, "Tfng")
|
||||
DEF(Tirhuta, "Tirh")
|
||||
DEF(Ugaritic, "Ugar")
|
||||
DEF(Vai, "Vaii")
|
||||
DEF(Wancho, "Wcho")
|
||||
DEF(Warang_Citi, "Wara")
|
||||
DEF(Yi, "Yiii")
|
||||
DEF(Zanabazar_Square, "Zanb")
|
||||
#endif
|
||||
|
||||
#ifdef UNICODE_PROP_LIST
|
||||
/* Prop list not exported to regexp */
|
||||
DEF(Hyphen, "")
|
||||
DEF(Other_Math, "")
|
||||
DEF(Other_Alphabetic, "")
|
||||
DEF(Other_Lowercase, "")
|
||||
DEF(Other_Uppercase, "")
|
||||
DEF(Other_Grapheme_Extend, "")
|
||||
DEF(Other_Default_Ignorable_Code_Point, "")
|
||||
DEF(Other_ID_Start, "")
|
||||
DEF(Other_ID_Continue, "")
|
||||
DEF(Prepended_Concatenation_Mark, "")
|
||||
/* additional computed properties for smaller tables */
|
||||
DEF(ID_Continue1, "")
|
||||
DEF(XID_Start1, "")
|
||||
DEF(XID_Continue1, "")
|
||||
DEF(Changes_When_Titlecased1, "")
|
||||
DEF(Changes_When_Casefolded1, "")
|
||||
DEF(Changes_When_NFKC_Casefolded1, "")
|
||||
|
||||
/* Prop list exported to JS */
|
||||
DEF(ASCII_Hex_Digit, "AHex")
|
||||
DEF(Bidi_Control, "Bidi_C")
|
||||
DEF(Dash, "")
|
||||
DEF(Deprecated, "Dep")
|
||||
DEF(Diacritic, "Dia")
|
||||
DEF(Extender, "Ext")
|
||||
DEF(Hex_Digit, "Hex")
|
||||
DEF(IDS_Binary_Operator, "IDSB")
|
||||
DEF(IDS_Trinary_Operator, "IDST")
|
||||
DEF(Ideographic, "Ideo")
|
||||
DEF(Join_Control, "Join_C")
|
||||
DEF(Logical_Order_Exception, "LOE")
|
||||
DEF(Noncharacter_Code_Point, "NChar")
|
||||
DEF(Pattern_Syntax, "Pat_Syn")
|
||||
DEF(Pattern_White_Space, "Pat_WS")
|
||||
DEF(Quotation_Mark, "QMark")
|
||||
DEF(Radical, "")
|
||||
DEF(Regional_Indicator, "RI")
|
||||
DEF(Sentence_Terminal, "STerm")
|
||||
DEF(Soft_Dotted, "SD")
|
||||
DEF(Terminal_Punctuation, "Term")
|
||||
DEF(Unified_Ideograph, "UIdeo")
|
||||
DEF(Variation_Selector, "VS")
|
||||
DEF(White_Space, "space")
|
||||
DEF(Bidi_Mirrored, "Bidi_M")
|
||||
DEF(Emoji, "")
|
||||
DEF(Emoji_Component, "")
|
||||
DEF(Emoji_Modifier, "")
|
||||
DEF(Emoji_Modifier_Base, "")
|
||||
DEF(Emoji_Presentation, "")
|
||||
DEF(Extended_Pictographic, "")
|
||||
DEF(Default_Ignorable_Code_Point, "DI")
|
||||
DEF(ID_Start, "IDS")
|
||||
DEF(Case_Ignorable, "CI")
|
||||
|
||||
/* other binary properties */
|
||||
DEF(ASCII,"")
|
||||
DEF(Alphabetic, "Alpha")
|
||||
DEF(Any, "")
|
||||
DEF(Assigned,"")
|
||||
DEF(Cased, "")
|
||||
DEF(Changes_When_Casefolded, "CWCF")
|
||||
DEF(Changes_When_Casemapped, "CWCM")
|
||||
DEF(Changes_When_Lowercased, "CWL")
|
||||
DEF(Changes_When_NFKC_Casefolded, "CWKCF")
|
||||
DEF(Changes_When_Titlecased, "CWT")
|
||||
DEF(Changes_When_Uppercased, "CWU")
|
||||
DEF(Grapheme_Base, "Gr_Base")
|
||||
DEF(Grapheme_Extend, "Gr_Ext")
|
||||
DEF(ID_Continue, "IDC")
|
||||
DEF(Lowercase, "Lower")
|
||||
DEF(Math, "")
|
||||
DEF(Uppercase, "Upper")
|
||||
DEF(XID_Continue, "XIDC")
|
||||
DEF(XID_Start, "XIDS")
|
||||
|
||||
/* internal tables with index */
|
||||
DEF(Cased1, "")
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user