mirror of
https://github.com/bellard/quickjs.git
synced 2025-09-27 05:38:45 +03:00
Merge commit '894ce9d' into upgrade-20250910
This commit is contained in:
commit
a555f9d893
285
.github/workflows/ci.yml
vendored
Normal file
285
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,285 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**'
|
||||
- '!.gitignore'
|
||||
- '!LICENSE'
|
||||
- '!TODO'
|
||||
- '!doc/**'
|
||||
- '!examples/**'
|
||||
- '.github/workflows/ci.yml'
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
name: Linux (Ubuntu)
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y
|
||||
- name: Stats
|
||||
run: |
|
||||
./qjs -qd
|
||||
- name: Run built-in tests
|
||||
run: |
|
||||
make test
|
||||
- name: Run microbench
|
||||
run: |
|
||||
make microbench
|
||||
|
||||
linux-lto:
|
||||
name: Linux LTO
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_LTO=y
|
||||
- name: Run built-in tests
|
||||
run: |
|
||||
make test
|
||||
- name: Run microbench
|
||||
run: |
|
||||
make microbench
|
||||
|
||||
linux-32bit:
|
||||
name: Linux 32bit
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install gcc-multilib
|
||||
run: |
|
||||
sudo apt install -y gcc-multilib
|
||||
- name: Build
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_M32=y
|
||||
- name: Run built-in tests
|
||||
run: |
|
||||
make CONFIG_M32=y test
|
||||
|
||||
linux-asan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_ASAN=y
|
||||
- name: Run built-in tests
|
||||
env:
|
||||
ASAN_OPTIONS: halt_on_error=1
|
||||
run: |
|
||||
make CONFIG_ASAN=y test
|
||||
|
||||
linux-msan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build
|
||||
env:
|
||||
CC: clang
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_MSAN=y CONFIG_CLANG=y
|
||||
- name: Run built-in tests
|
||||
env:
|
||||
MSAN_OPTIONS: halt_on_error=1
|
||||
run: |
|
||||
make CONFIG_MSAN=y CONFIG_CLANG=y test
|
||||
|
||||
linux-ubsan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_UBSAN=y
|
||||
- name: Run built-in tests
|
||||
env:
|
||||
UBSAN_OPTIONS: halt_on_error=1
|
||||
run: |
|
||||
make CONFIG_UBSAN=y test
|
||||
|
||||
macos:
|
||||
name: macOS
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y
|
||||
- name: Stats
|
||||
run: |
|
||||
./qjs -qd
|
||||
- name: Run built-in tests
|
||||
run: |
|
||||
make test
|
||||
|
||||
macos-asan:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_ASAN=y
|
||||
- name: Run built-in tests
|
||||
env:
|
||||
ASAN_OPTIONS: halt_on_error=1
|
||||
run: |
|
||||
make CONFIG_ASAN=y test
|
||||
|
||||
macos-ubsan:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_UBSAN=y
|
||||
- name: Run built-in tests
|
||||
env:
|
||||
UBSAN_OPTIONS: halt_on_error=1
|
||||
run: |
|
||||
make CONFIG_UBSAN=y test
|
||||
|
||||
freebsd:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build + test
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
prepare: |
|
||||
pkg install -y gmake
|
||||
run: |
|
||||
gmake
|
||||
./qjs -qd
|
||||
gmake test
|
||||
|
||||
cosmopolitan:
|
||||
name: Cosmopolitan
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install Cosmopolitan
|
||||
run: |
|
||||
mkdir ~/cosmocc
|
||||
cd ~/cosmocc
|
||||
wget https://cosmo.zip/pub/cosmocc/cosmocc.zip
|
||||
unzip cosmocc.zip
|
||||
echo "$HOME/cosmocc/bin" >> "$GITHUB_PATH"
|
||||
- name: Build
|
||||
run: |
|
||||
make CONFIG_COSMO=y
|
||||
- name: Run built-in tests
|
||||
run: |
|
||||
make CONFIG_COSMO=y test
|
||||
|
||||
mingw-windows:
|
||||
name: MinGW Windows target
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install MinGW and Wine
|
||||
run: |
|
||||
sudo apt install -y wine mingw-w64
|
||||
cp /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll .
|
||||
- name: Setup Wine
|
||||
run: |
|
||||
wine --version
|
||||
winecfg /v
|
||||
# binfmt doesn't work in GitHub Actions
|
||||
#sudo apt install -y binfmt-support wine-binfmt
|
||||
#echo ":Wine:M::MZ::/usr/bin/wine:" > /etc/binfmt.d/wine.conf
|
||||
#sudo systemctl restart systemd-binfmt
|
||||
- name: Build
|
||||
run: |
|
||||
make CONFIG_WIN32=y
|
||||
- name: Run built-in tests
|
||||
run: |
|
||||
# If binfmt support worked, could just run `make CONFIG_WIN32=y test`
|
||||
make WINE=/usr/bin/wine CONFIG_WIN32=y test
|
||||
|
||||
windows-msys:
|
||||
name: Windows MSYS2
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: UCRT64
|
||||
update: true
|
||||
install: git make mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-dlfcn
|
||||
- name: Build
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y
|
||||
- name: Stats
|
||||
run: |
|
||||
./qjs -qd
|
||||
- name: Run built-in tests
|
||||
run: |
|
||||
make test
|
||||
- name: Run microbench
|
||||
run: |
|
||||
make microbench
|
||||
|
||||
|
||||
qemu-alpine:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform:
|
||||
- linux/386
|
||||
- linux/riscv64
|
||||
- linux/arm64
|
||||
- linux/arm/v6
|
||||
- linux/arm/v7
|
||||
- linux/s390x
|
||||
- linux/ppc64le
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Get qemu
|
||||
# See https://github.com/tonistiigi/binfmt/issues/215#issuecomment-2613004741
|
||||
run: docker run --privileged --rm tonistiigi/binfmt:master --install all
|
||||
- name: Run tests on ${{ matrix.platform }}
|
||||
run: docker run --rm --interactive --mount type=bind,source=$(pwd),target=/host --platform ${{ matrix.platform }} alpine sh -c "apk add git patch make gcc libc-dev && cd /host && make test"
|
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
*.a
|
||||
.obj/
|
||||
tests/bjson.so
|
||||
examples/test_fib
|
||||
test_fib.c
|
||||
examples/*.so
|
||||
examples/hello
|
||||
examples/hello_module
|
||||
examples/hello.exe
|
||||
examples/test_fib.exe
|
||||
hello.c
|
||||
microbench*.txt
|
||||
qjs
|
||||
qjs.exe
|
||||
qjsc
|
||||
qjsc.exe
|
||||
host-qjsc
|
||||
qjscalc
|
||||
qjscalc.c
|
||||
repl.c
|
||||
run-test262
|
||||
run-test262.exe
|
||||
test262
|
||||
test262_*.txt
|
||||
test262o
|
||||
test262o_*.txt
|
||||
unicode
|
||||
unicode_gen
|
||||
run_octane
|
||||
run_sunspider_like
|
||||
libwinpthread*.dll
|
18
Changelog
18
Changelog
@ -1,3 +1,19 @@
|
||||
2025-04-26:
|
||||
|
||||
- removed the bignum extensions and qjscalc
|
||||
- new BigInt implementation optimized for small numbers
|
||||
- added WeakRef, FinalizationRegistry and symbols as weakrefs
|
||||
- added builtin float64 printing and parsing functions for more correctness
|
||||
- faster repeated string concatenation
|
||||
- qjs: promise unhandled rejections are fatal errors by default
|
||||
- added column number in debug information
|
||||
- removed the "use strip" extension
|
||||
- qjs: added -s and --strip-source options
|
||||
- qjsc: added -s and --keep-source options
|
||||
- added JS_GetAnyOpaque()
|
||||
- added more callbacks for exotic objects in JSClassExoticMethods
|
||||
- misc bug fixes
|
||||
|
||||
2024-01-13:
|
||||
|
||||
- top-level-await support in modules
|
||||
@ -13,7 +29,7 @@ TypedArray.prototype.{with,toReversed,toSorted}
|
||||
- added RegExp 'd' flag
|
||||
- fixed RegExp zero length match logic
|
||||
- fixed RegExp case insensitive flag
|
||||
- added os.getpid() and os.now()
|
||||
- added os.sleepAsync(), os.getpid() and os.now()
|
||||
- added cosmopolitan build
|
||||
- misc bug fixes
|
||||
|
||||
|
2
LICENSE
2
LICENSE
@ -1,5 +1,5 @@
|
||||
QuickJS Javascript Engine
|
||||
|
||||
|
||||
Copyright (c) 2017-2021 Fabrice Bellard
|
||||
Copyright (c) 2017-2021 Charlie Gordon
|
||||
|
||||
|
308
Makefile
308
Makefile
@ -1,6 +1,6 @@
|
||||
#
|
||||
# QuickJS Javascript Engine
|
||||
#
|
||||
#
|
||||
# Copyright (c) 2017-2021 Fabrice Bellard
|
||||
# Copyright (c) 2017-2021 Charlie Gordon
|
||||
#
|
||||
@ -25,13 +25,19 @@
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
CONFIG_DARWIN=y
|
||||
endif
|
||||
ifeq ($(shell uname -s),FreeBSD)
|
||||
CONFIG_FREEBSD=y
|
||||
endif
|
||||
# Windows cross compilation from Linux
|
||||
# May need to have libwinpthread*.dll alongside the executable
|
||||
# (On Ubuntu/Debian may be installed with mingw-w64-x86-64-dev
|
||||
# to /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll)
|
||||
#CONFIG_WIN32=y
|
||||
# use link time optimization (smaller and faster executables but slower build)
|
||||
CONFIG_LTO=y
|
||||
#CONFIG_LTO=y
|
||||
# consider warnings as errors (for development)
|
||||
#CONFIG_WERROR=y
|
||||
# force 32 bit build for some utilities
|
||||
# force 32 bit build on x86_64
|
||||
#CONFIG_M32=y
|
||||
# cosmopolitan build (see https://github.com/jart/cosmopolitan)
|
||||
#CONFIG_COSMO=y
|
||||
@ -43,16 +49,34 @@ PREFIX?=/usr/local
|
||||
#CONFIG_PROFILE=y
|
||||
# use address sanitizer
|
||||
#CONFIG_ASAN=y
|
||||
# include the code for BigFloat/BigDecimal, math mode and faster large integers
|
||||
CONFIG_BIGNUM=y
|
||||
# use memory sanitizer
|
||||
#CONFIG_MSAN=y
|
||||
# use UB sanitizer
|
||||
#CONFIG_UBSAN=y
|
||||
|
||||
OBJDIR=.obj
|
||||
|
||||
ifdef CONFIG_ASAN
|
||||
OBJDIR:=$(OBJDIR)/asan
|
||||
endif
|
||||
ifdef CONFIG_MSAN
|
||||
OBJDIR:=$(OBJDIR)/msan
|
||||
endif
|
||||
ifdef CONFIG_UBSAN
|
||||
OBJDIR:=$(OBJDIR)/ubsan
|
||||
endif
|
||||
|
||||
ifdef CONFIG_DARWIN
|
||||
# use clang instead of gcc
|
||||
CONFIG_CLANG=y
|
||||
CONFIG_DEFAULT_AR=y
|
||||
endif
|
||||
ifdef CONFIG_FREEBSD
|
||||
# use clang instead of gcc
|
||||
CONFIG_CLANG=y
|
||||
CONFIG_DEFAULT_AR=y
|
||||
CONFIG_LTO=
|
||||
endif
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
ifdef CONFIG_M32
|
||||
@ -61,6 +85,10 @@ ifdef CONFIG_WIN32
|
||||
CROSS_PREFIX?=x86_64-w64-mingw32-
|
||||
endif
|
||||
EXE=.exe
|
||||
else ifdef MSYSTEM
|
||||
CONFIG_WIN32=y
|
||||
CROSS_PREFIX?=
|
||||
EXE=.exe
|
||||
else
|
||||
CROSS_PREFIX?=
|
||||
EXE=
|
||||
@ -87,6 +115,7 @@ ifdef CONFIG_CLANG
|
||||
AR=$(CROSS_PREFIX)ar
|
||||
endif
|
||||
endif
|
||||
LIB_FUZZING_ENGINE ?= "-fsanitize=fuzzer"
|
||||
else ifdef CONFIG_COSMO
|
||||
CONFIG_LTO=
|
||||
HOST_CC=gcc
|
||||
@ -99,25 +128,34 @@ else
|
||||
HOST_CC=gcc
|
||||
CC=$(CROSS_PREFIX)gcc
|
||||
CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
|
||||
CFLAGS += -Wno-array-bounds -Wno-format-truncation
|
||||
CFLAGS += -Wno-array-bounds -Wno-format-truncation -Wno-infinite-recursion
|
||||
ifdef CONFIG_LTO
|
||||
AR=$(CROSS_PREFIX)gcc-ar
|
||||
else
|
||||
AR=$(CROSS_PREFIX)ar
|
||||
endif
|
||||
endif
|
||||
STRIP=$(CROSS_PREFIX)strip
|
||||
STRIP?=$(CROSS_PREFIX)strip
|
||||
ifdef CONFIG_M32
|
||||
CFLAGS+=-msse2 -mfpmath=sse # use SSE math for correct FP rounding
|
||||
ifndef CONFIG_WIN32
|
||||
CFLAGS+=-m32
|
||||
LDFLAGS+=-m32
|
||||
endif
|
||||
endif
|
||||
CFLAGS+=-fwrapv # ensure that signed overflows behave as expected
|
||||
ifdef CONFIG_WERROR
|
||||
CFLAGS+=-Werror
|
||||
endif
|
||||
DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
|
||||
ifdef CONFIG_BIGNUM
|
||||
DEFINES+=-DCONFIG_BIGNUM
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior
|
||||
endif
|
||||
ifndef CONFIG_WIN32
|
||||
ifeq ($(shell $(CC) -o /dev/null compat/test-closefrom.c 2>/dev/null && echo 1),1)
|
||||
DEFINES+=-DHAVE_CLOSEFROM
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS+=$(DEFINES)
|
||||
CFLAGS_DEBUG=$(CFLAGS) -O0
|
||||
@ -142,6 +180,14 @@ ifdef CONFIG_ASAN
|
||||
CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
endif
|
||||
ifdef CONFIG_MSAN
|
||||
CFLAGS+=-fsanitize=memory -fno-omit-frame-pointer
|
||||
LDFLAGS+=-fsanitize=memory -fno-omit-frame-pointer
|
||||
endif
|
||||
ifdef CONFIG_UBSAN
|
||||
CFLAGS+=-fsanitize=undefined -fno-omit-frame-pointer
|
||||
LDFLAGS+=-fsanitize=undefined -fno-omit-frame-pointer
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
LDEXPORT=
|
||||
else
|
||||
@ -150,11 +196,14 @@ endif
|
||||
|
||||
ifndef CONFIG_COSMO
|
||||
ifndef CONFIG_DARWIN
|
||||
ifndef CONFIG_WIN32
|
||||
CONFIG_SHARED_LIBS=y # building shared libraries is supported
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
PROGS=qjs$(EXE) qjsc$(EXE) run-test262$(EXE)
|
||||
|
||||
PROGS=qjs$(EXE) qjsc$(EXE) run-test262
|
||||
ifneq ($(CROSS_PREFIX),)
|
||||
QJSC_CC=gcc
|
||||
QJSC=./host-qjsc
|
||||
@ -163,12 +212,6 @@ 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
|
||||
@ -176,28 +219,34 @@ endif
|
||||
|
||||
# examples
|
||||
ifeq ($(CROSS_PREFIX),)
|
||||
PROGS+=examples/hello
|
||||
ifndef CONFIG_ASAN
|
||||
ifndef CONFIG_MSAN
|
||||
ifndef CONFIG_UBSAN
|
||||
PROGS+=examples/hello examples/test_fib
|
||||
# no -m32 option in qjsc
|
||||
ifndef CONFIG_M32
|
||||
ifndef CONFIG_WIN32
|
||||
PROGS+=examples/hello_module
|
||||
endif
|
||||
endif
|
||||
ifdef CONFIG_SHARED_LIBS
|
||||
PROGS+=examples/test_fib examples/fib.so examples/point.so
|
||||
PROGS+=examples/fib.so examples/point.so
|
||||
endif
|
||||
endif
|
||||
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)/cutils.o $(OBJDIR)/quickjs-libc.o $(OBJDIR)/libbf.o
|
||||
QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/dtoa.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o
|
||||
|
||||
QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS)
|
||||
ifdef CONFIG_BIGNUM
|
||||
QJS_OBJS+=$(OBJDIR)/qjscalc.o
|
||||
endif
|
||||
|
||||
HOST_LIBS=-lm -ldl -lpthread
|
||||
LIBS=-lm
|
||||
LIBS=-lm -lpthread
|
||||
ifndef CONFIG_WIN32
|
||||
LIBS+=-ldl -lpthread
|
||||
LIBS+=-ldl
|
||||
endif
|
||||
LIBS+=$(EXTRA_LIBS)
|
||||
|
||||
@ -213,6 +262,17 @@ qjs-debug$(EXE): $(patsubst %.o, %.debug.o, $(QJS_OBJS))
|
||||
qjsc$(EXE): $(OBJDIR)/qjsc.o $(QJS_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
fuzz_eval: $(OBJDIR)/fuzz_eval.o $(OBJDIR)/fuzz_common.o libquickjs.fuzz.a
|
||||
$(CC) $(CFLAGS_OPT) $^ -o fuzz_eval $(LIB_FUZZING_ENGINE)
|
||||
|
||||
fuzz_compile: $(OBJDIR)/fuzz_compile.o $(OBJDIR)/fuzz_common.o libquickjs.fuzz.a
|
||||
$(CC) $(CFLAGS_OPT) $^ -o fuzz_compile $(LIB_FUZZING_ENGINE)
|
||||
|
||||
fuzz_regexp: $(OBJDIR)/fuzz_regexp.o $(OBJDIR)/libregexp.fuzz.o $(OBJDIR)/cutils.fuzz.o $(OBJDIR)/libunicode.fuzz.o
|
||||
$(CC) $(CFLAGS_OPT) $^ -o fuzz_regexp $(LIB_FUZZING_ENGINE)
|
||||
|
||||
libfuzzer: fuzz_eval fuzz_compile fuzz_regexp
|
||||
|
||||
ifneq ($(CROSS_PREFIX),)
|
||||
|
||||
$(QJSC): $(OBJDIR)/qjsc.host.o \
|
||||
@ -230,16 +290,6 @@ 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
|
||||
@ -254,34 +304,33 @@ 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
|
||||
libquickjs.fuzz.a: $(patsubst %.o, %.fuzz.o, $(QJS_LIB_OBJS))
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
qjscalc.c: $(QJSC) qjscalc.js
|
||||
$(QJSC) -fbignum -c -o $@ qjscalc.js
|
||||
repl.c: $(QJSC) repl.js
|
||||
$(QJSC) -s -c -o $@ -m repl.js
|
||||
|
||||
ifneq ($(wildcard unicode/UnicodeData.txt),)
|
||||
$(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o \
|
||||
$(OBJDIR)/libunicode.nolto.o: libunicode-table.h
|
||||
$(OBJDIR)/libunicode.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)
|
||||
run-test262$(EXE): $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
run-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
run-test262-32: $(patsubst %.o, %.m32.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
# object suffix order: nolto, [m32|m32s]
|
||||
# object suffix order: nolto
|
||||
|
||||
$(OBJDIR)/%.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_OPT) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/fuzz_%.o: fuzz/fuzz_%.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_OPT) -c -I. -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.host.o: %.c | $(OBJDIR)
|
||||
$(HOST_CC) $(CFLAGS_OPT) -c -o $@ $<
|
||||
|
||||
@ -291,15 +340,12 @@ $(OBJDIR)/%.pic.o: %.c | $(OBJDIR)
|
||||
$(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)/%.fuzz.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_OPT) -fsanitize=fuzzer-no-link -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.check.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -DCONFIG_CHECK_JSVALUE -c -o $@ $<
|
||||
|
||||
@ -310,18 +356,18 @@ unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c u
|
||||
$(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 *~ unicode_gen regexp_test $(PROGS)
|
||||
rm -f repl.c out.c
|
||||
rm -f *.a *.o *.d *~ unicode_gen regexp_test fuzz_eval fuzz_compile fuzz_regexp $(PROGS)
|
||||
rm -f hello.c test_fib.c
|
||||
rm -f examples/*.so tests/*.so
|
||||
rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug
|
||||
rm -rf run-test262-debug run-test262-32
|
||||
rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug$(EXE)
|
||||
rm -rf run-test262-debug$(EXE)
|
||||
rm -f run_octane run_sunspider_like
|
||||
|
||||
install: all
|
||||
mkdir -p "$(DESTDIR)$(PREFIX)/bin"
|
||||
$(STRIP) qjs qjsc
|
||||
install -m755 qjs qjsc "$(DESTDIR)$(PREFIX)/bin"
|
||||
ln -sf qjs "$(DESTDIR)$(PREFIX)/bin/qjscalc"
|
||||
$(STRIP) qjs$(EXE) qjsc$(EXE)
|
||||
install -m755 qjs$(EXE) qjsc$(EXE) "$(DESTDIR)$(PREFIX)/bin"
|
||||
mkdir -p "$(DESTDIR)$(PREFIX)/lib/quickjs"
|
||||
install -m644 libquickjs.a "$(DESTDIR)$(PREFIX)/lib/quickjs"
|
||||
ifdef CONFIG_LTO
|
||||
@ -337,22 +383,17 @@ endif
|
||||
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
|
||||
-fno-date -fno-module-loader
|
||||
|
||||
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 \
|
||||
HELLO_MODULE_OPTS=-fno-string-normalize -fno-map -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)
|
||||
@ -375,17 +416,20 @@ examples/point.so: $(OBJDIR)/examples/point.pic.o
|
||||
###############################################################################
|
||||
# documentation
|
||||
|
||||
DOCS=doc/quickjs.pdf doc/quickjs.html doc/jsbignum.pdf doc/jsbignum.html
|
||||
DOCS=doc/quickjs.pdf doc/quickjs.html
|
||||
|
||||
build_doc: $(DOCS)
|
||||
|
||||
clean_doc:
|
||||
clean_doc:
|
||||
rm -f $(DOCS)
|
||||
|
||||
doc/%.pdf: doc/%.texi
|
||||
doc/version.texi: VERSION
|
||||
@echo "@set VERSION `cat $<`" > $@
|
||||
|
||||
doc/%.pdf: doc/%.texi doc/version.texi
|
||||
texi2pdf --clean -o $@ -q $<
|
||||
|
||||
doc/%.html.pre: doc/%.texi
|
||||
doc/%.html.pre: doc/%.texi doc/version.texi
|
||||
makeinfo --html --no-headers --no-split --number-sections -o $@ $<
|
||||
|
||||
doc/%.html: doc/%.html.pre
|
||||
@ -397,91 +441,97 @@ doc/%.html: doc/%.html.pre
|
||||
ifdef CONFIG_SHARED_LIBS
|
||||
test: tests/bjson.so examples/point.so
|
||||
endif
|
||||
ifdef CONFIG_M32
|
||||
test: qjs32
|
||||
endif
|
||||
|
||||
test: qjs
|
||||
./qjs tests/test_closure.js
|
||||
./qjs tests/test_language.js
|
||||
./qjs tests/test_builtin.js
|
||||
./qjs tests/test_loop.js
|
||||
./qjs tests/test_std.js
|
||||
./qjs tests/test_worker.js
|
||||
test: qjs$(EXE)
|
||||
$(WINE) ./qjs$(EXE) tests/test_closure.js
|
||||
$(WINE) ./qjs$(EXE) tests/test_language.js
|
||||
$(WINE) ./qjs$(EXE) --std tests/test_builtin.js
|
||||
$(WINE) ./qjs$(EXE) tests/test_loop.js
|
||||
$(WINE) ./qjs$(EXE) tests/test_bigint.js
|
||||
$(WINE) ./qjs$(EXE) tests/test_cyclic_import.js
|
||||
$(WINE) ./qjs$(EXE) tests/test_worker.js
|
||||
ifndef CONFIG_WIN32
|
||||
$(WINE) ./qjs$(EXE) tests/test_std.js
|
||||
endif
|
||||
ifdef CONFIG_SHARED_LIBS
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs --bignum tests/test_bjson.js
|
||||
$(WINE) ./qjs$(EXE) tests/test_bjson.js
|
||||
$(WINE) ./qjs$(EXE) examples/test_point.js
|
||||
endif
|
||||
|
||||
stats: qjs$(EXE)
|
||||
$(WINE) ./qjs$(EXE) -qd
|
||||
|
||||
microbench: qjs$(EXE)
|
||||
$(WINE) ./qjs$(EXE) --std tests/microbench.js
|
||||
|
||||
ifeq ($(wildcard test262o/tests.txt),)
|
||||
test2o test2o-update:
|
||||
@echo test262o tests not installed
|
||||
else
|
||||
./qjs tests/test_bjson.js
|
||||
endif
|
||||
./qjs examples/test_point.js
|
||||
endif
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs --bignum tests/test_op_overloading.js
|
||||
./qjs --bignum tests/test_bignum.js
|
||||
./qjs --qjscalc tests/test_qjscalc.js
|
||||
endif
|
||||
ifdef CONFIG_M32
|
||||
./qjs32 tests/test_closure.js
|
||||
./qjs32 tests/test_language.js
|
||||
./qjs32 tests/test_builtin.js
|
||||
./qjs32 tests/test_loop.js
|
||||
./qjs32 tests/test_std.js
|
||||
./qjs32 tests/test_worker.js
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs32 --bignum tests/test_op_overloading.js
|
||||
./qjs32 --bignum tests/test_bignum.js
|
||||
./qjs32 --qjscalc tests/test_qjscalc.js
|
||||
endif
|
||||
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
|
||||
time ./run-test262 -t -m -c test262o.conf
|
||||
|
||||
test2o-update: run-test262
|
||||
./run-test262 -u -c test262o.conf
|
||||
./run-test262 -t -u -c test262o.conf
|
||||
endif
|
||||
|
||||
ifeq ($(wildcard test262/features.txt),)
|
||||
test2 test2-update test2-default test2-check:
|
||||
@echo test262 tests not installed
|
||||
else
|
||||
# Test262 tests
|
||||
test2-default: run-test262
|
||||
time ./run-test262 -m -c test262.conf
|
||||
time ./run-test262 -t -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
|
||||
time ./run-test262 -t -m -c test262.conf -a
|
||||
|
||||
test2-update: run-test262
|
||||
./run-test262 -u -c test262.conf -a
|
||||
./run-test262 -t -u -c test262.conf -a
|
||||
|
||||
test2-check: run-test262
|
||||
time ./run-test262 -m -c test262.conf -E -a
|
||||
time ./run-test262 -t -m -c test262.conf -E -a
|
||||
endif
|
||||
|
||||
testall: all test microbench test2o test2
|
||||
|
||||
testall-32: all test-32 microbench-32 test2o-32 test2-32
|
||||
testall-complete: testall
|
||||
|
||||
testall-complete: testall testall-32
|
||||
node-test:
|
||||
node tests/test_closure.js
|
||||
node tests/test_language.js
|
||||
node tests/test_builtin.js
|
||||
node tests/test_loop.js
|
||||
node tests/test_bigint.js
|
||||
|
||||
node-microbench:
|
||||
node tests/microbench.js -s microbench-node.txt
|
||||
node --jitless tests/microbench.js -s microbench-node-jitless.txt
|
||||
|
||||
bench-v8: qjs
|
||||
make -C tests/bench-v8
|
||||
./qjs -d tests/bench-v8/combined.js
|
||||
|
||||
node-bench-v8:
|
||||
make -C tests/bench-v8
|
||||
node --jitless tests/bench-v8/combined.js
|
||||
|
||||
tests/bjson.so: $(OBJDIR)/tests/bjson.pic.o
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS)
|
||||
|
||||
BENCHMARKDIR=../quickjs-benchmarks
|
||||
|
||||
run_sunspider_like: $(BENCHMARKDIR)/run_sunspider_like.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -DNO_INCLUDE_DIR -I. -o $@ $< libquickjs$(LTOEXT).a $(LIBS)
|
||||
|
||||
run_octane: $(BENCHMARKDIR)/run_octane.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -DNO_INCLUDE_DIR -I. -o $@ $< libquickjs$(LTOEXT).a $(LIBS)
|
||||
|
||||
benchmarks: run_sunspider_like run_octane
|
||||
./run_sunspider_like $(BENCHMARKDIR)/kraken-1.0/
|
||||
./run_sunspider_like $(BENCHMARKDIR)/kraken-1.1/
|
||||
./run_sunspider_like $(BENCHMARKDIR)/sunspider-1.0/
|
||||
./run_octane $(BENCHMARKDIR)/
|
||||
|
||||
-include $(wildcard $(OBJDIR)/*.d)
|
||||
|
14
TODO
14
TODO
@ -37,17 +37,16 @@ REPL:
|
||||
- close all predefined methods in repl.js and jscalc.js
|
||||
|
||||
Optimization ideas:
|
||||
- 64-bit atoms in 64-bit mode ?
|
||||
- 64-bit small bigint in 64-bit mode ?
|
||||
- use 64 bit JSValue in 64 bit mode
|
||||
- use JSValue as atoms and use a specific constant pool in functions to
|
||||
reference atoms from the bytecode
|
||||
- reuse stack slots for disjoint scopes, if strip
|
||||
- add heuristic to avoid some cycles in closures
|
||||
- small String (0-2 charcodes) with immediate storage
|
||||
- small String (1 codepoint) with immediate storage
|
||||
- perform static string concatenation at compile time
|
||||
- optimize string concatenation with ropes or miniropes?
|
||||
- add implicit numeric strings for Uint32 numbers?
|
||||
- optimize `s += a + b`, `s += a.b` and similar simple expressions
|
||||
- ensure string canonical representation and optimise comparisons and hashes?
|
||||
- remove JSObject.first_weak_ref, use bit+context based hashed array for weak references
|
||||
- property access optimization on the global object, functions,
|
||||
prototypes and special non extensible objects.
|
||||
- create object literals with the correct length by backpatching length argument
|
||||
@ -63,5 +62,6 @@ Optimization ideas:
|
||||
Test262o: 0/11262 errors, 463 excluded
|
||||
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
|
||||
|
||||
Result: 10/76947 errors, 1497 excluded, 8117 skipped
|
||||
Test262 commit: 6cbb6da9473c56d95358d8e679c5a6d2b4574efb
|
||||
Result: 70/78178 errors, 1610 excluded, 7236 skipped
|
||||
Test262 commit: 56e77d6325067a545ea7e8ff5be5d9284334e33c
|
||||
|
||||
|
6
compat/test-closefrom.c
Normal file
6
compat/test-closefrom.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <unistd.h>
|
||||
|
||||
int main(void) {
|
||||
closefrom(3);
|
||||
return 0;
|
||||
}
|
8
cutils.c
8
cutils.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* C utilities
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017 Fabrice Bellard
|
||||
* Copyright (c) 2018 Charlie Gordon
|
||||
*
|
||||
@ -140,7 +140,7 @@ int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)
|
||||
if (dbuf_realloc(s, s->size + len))
|
||||
return -1;
|
||||
}
|
||||
memcpy(s->buf + s->size, data, len);
|
||||
memcpy_no_ub(s->buf + s->size, data, len);
|
||||
s->size += len;
|
||||
return 0;
|
||||
}
|
||||
@ -172,10 +172,12 @@ int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
|
||||
va_list ap;
|
||||
char buf[128];
|
||||
int len;
|
||||
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
if (len < sizeof(buf)) {
|
||||
/* fast case */
|
||||
return dbuf_put(s, (uint8_t *)buf, len);
|
||||
|
91
cutils.h
91
cutils.h
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* C utilities
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017 Fabrice Bellard
|
||||
* Copyright (c) 2018 Charlie Gordon
|
||||
*
|
||||
@ -26,11 +26,9 @@
|
||||
#define CUTILS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.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))
|
||||
@ -48,9 +46,16 @@
|
||||
#ifndef countof
|
||||
#define countof(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
#ifndef container_of
|
||||
/* return the pointer of type 'type *' containing 'ptr' as field 'member' */
|
||||
#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
|
||||
#endif
|
||||
|
||||
#if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
#define minimum_length(n) static n
|
||||
#else
|
||||
#define minimum_length(n) n
|
||||
#endif
|
||||
|
||||
typedef int BOOL;
|
||||
|
||||
@ -66,6 +71,12 @@ 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);
|
||||
|
||||
/* Prevent UB when n == 0 and (src == NULL or dest == NULL) */
|
||||
static inline void memcpy_no_ub(void *dest, const void *src, size_t n) {
|
||||
if (n)
|
||||
memcpy(dest, src, n);
|
||||
}
|
||||
|
||||
static inline int max_int(int a, int b)
|
||||
{
|
||||
if (a > b)
|
||||
@ -210,28 +221,34 @@ static inline void put_u8(uint8_t *tab, uint8_t val)
|
||||
*tab = val;
|
||||
}
|
||||
|
||||
#ifndef bswap16
|
||||
static inline uint16_t bswap16(uint16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef bswap32
|
||||
static inline uint32_t bswap32(uint32_t v)
|
||||
{
|
||||
return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
|
||||
((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef bswap64
|
||||
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)) |
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXX: should take an extra argument to pass slack information to the caller */
|
||||
typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
|
||||
@ -281,6 +298,36 @@ static inline void dbuf_set_error(DynBuf *s)
|
||||
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 BOOL is_surrogate(uint32_t c)
|
||||
{
|
||||
return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF
|
||||
}
|
||||
|
||||
static inline BOOL is_hi_surrogate(uint32_t c)
|
||||
{
|
||||
return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF
|
||||
}
|
||||
|
||||
static inline BOOL is_lo_surrogate(uint32_t c)
|
||||
{
|
||||
return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF
|
||||
}
|
||||
|
||||
static inline uint32_t get_hi_surrogate(uint32_t c)
|
||||
{
|
||||
return (c >> 10) - (0x10000 >> 10) + 0xD800;
|
||||
}
|
||||
|
||||
static inline uint32_t get_lo_surrogate(uint32_t c)
|
||||
{
|
||||
return (c & 0x3FF) | 0xDC00;
|
||||
}
|
||||
|
||||
static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo)
|
||||
{
|
||||
return 0x10000 + 0x400 * (hi - 0xD800) + (lo - 0xDC00);
|
||||
}
|
||||
|
||||
static inline int from_hex(int c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
@ -297,4 +344,24 @@ void rqsort(void *base, size_t nmemb, size_t size,
|
||||
int (*cmp)(const void *, const void *, void *),
|
||||
void *arg);
|
||||
|
||||
static inline uint64_t float64_as_uint64(double d)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u;
|
||||
u.d = d;
|
||||
return u.u64;
|
||||
}
|
||||
|
||||
static inline double uint64_as_float64(uint64_t u64)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u;
|
||||
u.u64 = u64;
|
||||
return u.d;
|
||||
}
|
||||
|
||||
#endif /* CUTILS_H */
|
||||
|
@ -1,589 +0,0 @@
|
||||
\input texinfo
|
||||
|
||||
@iftex
|
||||
@afourpaper
|
||||
@headings double
|
||||
@end iftex
|
||||
|
||||
@titlepage
|
||||
@afourpaper
|
||||
@sp 7
|
||||
@center @titlefont{Javascript Bignum Extensions}
|
||||
@sp 3
|
||||
@center Version 2020-01-11
|
||||
@sp 3
|
||||
@center Author: Fabrice Bellard
|
||||
@end titlepage
|
||||
|
||||
@setfilename jsbignum.info
|
||||
@settitle Javascript Bignum Extensions
|
||||
|
||||
@contents
|
||||
|
||||
@chapter Introduction
|
||||
|
||||
The Bignum extensions add the following features to the Javascript
|
||||
language while being 100% backward compatible:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Operator overloading with a dispatch logic inspired from the proposal available at @url{https://github.com/tc39/proposal-operator-overloading/}.
|
||||
|
||||
@item Arbitrarily large floating point numbers (@code{BigFloat}) in base 2 using the IEEE 754 semantics.
|
||||
|
||||
@item Arbitrarily large floating point numbers (@code{BigDecimal}) in base 10 based on the proposal available at
|
||||
@url{https://github.com/littledan/proposal-bigdecimal}.
|
||||
|
||||
@item @code{math} mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (@code{%}) is defined as the Euclidian
|
||||
remainder. @code{^} is an alias to the power operator
|
||||
(@code{**}). @code{^^} is used as the exclusive or operator.
|
||||
|
||||
@end itemize
|
||||
|
||||
The extensions are independent from each other except the @code{math}
|
||||
mode which relies on BigFloat and operator overloading.
|
||||
|
||||
@chapter Operator overloading
|
||||
|
||||
Operator overloading is inspired from the proposal available at
|
||||
@url{https://github.com/tc39/proposal-operator-overloading/}. It
|
||||
implements the same dispatch logic but finds the operator sets by
|
||||
looking at the @code{Symbol.operatorSet} property in the objects. The
|
||||
changes were done in order to simplify the implementation.
|
||||
|
||||
More precisely, the following modifications were made:
|
||||
|
||||
@itemize
|
||||
|
||||
@item @code{with operators from} is not supported. Operator overloading is always enabled.
|
||||
|
||||
@item The dispatch is not based on a static @code{[[OperatorSet]]} field in all instances. Instead, a dynamic lookup of the @code{Symbol.operatorSet} property is done. This property is typically added in the prototype of each object.
|
||||
|
||||
@item @code{Operators.create(...dictionaries)} is used to create a new OperatorSet object. The @code{Operators} function is supported as an helper to be closer to the TC39 proposal.
|
||||
|
||||
@item @code{[]} cannot be overloaded.
|
||||
|
||||
@item In math mode, the BigInt division and power operators can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
|
||||
|
||||
@end itemize
|
||||
|
||||
@chapter BigInt extensions
|
||||
|
||||
A few properties are added to the BigInt object:
|
||||
|
||||
@table @code
|
||||
|
||||
@item tdiv(a, b)
|
||||
Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError
|
||||
exception.
|
||||
|
||||
@item fdiv(a, b)
|
||||
Return @math{\lfloor a/b \rfloor}. @code{b = 0} raises a RangeError
|
||||
exception.
|
||||
|
||||
@item cdiv(a, b)
|
||||
Return @math{\lceil a/b \rceil}. @code{b = 0} raises a RangeError
|
||||
exception.
|
||||
|
||||
@item ediv(a, b)
|
||||
Return @math{sgn(b) \lfloor a/{|b|} \rfloor} (Euclidian
|
||||
division). @code{b = 0} raises a RangeError exception.
|
||||
|
||||
@item tdivrem(a, b)
|
||||
@item fdivrem(a, b)
|
||||
@item cdivrem(a, b)
|
||||
@item edivrem(a, b)
|
||||
Return an array of two elements. The first element is the quotient,
|
||||
the second is the remainder. The same rounding is done as the
|
||||
corresponding division operation.
|
||||
|
||||
@item sqrt(a)
|
||||
Return @math{\lfloor \sqrt(a) \rfloor}. A RangeError exception is
|
||||
raised if @math{a < 0}.
|
||||
|
||||
@item sqrtrem(a)
|
||||
Return an array of two elements. The first element is @math{\lfloor
|
||||
\sqrt{a} \rfloor}. The second element is @math{a-\lfloor \sqrt{a}
|
||||
\rfloor^2}. A RangeError exception is raised if @math{a < 0}.
|
||||
|
||||
@item floorLog2(a)
|
||||
Return -1 if @math{a \leq 0} otherwise return @math{\lfloor \log2(a) \rfloor}.
|
||||
|
||||
@item ctz(a)
|
||||
Return the number of trailing zeros in the two's complement binary representation of a. Return -1 if @math{a=0}.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter BigFloat
|
||||
|
||||
@section Introduction
|
||||
|
||||
This extension adds the @code{BigFloat} primitive type. The
|
||||
@code{BigFloat} type represents floating point numbers in base 2
|
||||
with the IEEE 754 semantics. A floating
|
||||
point number is represented as a sign, mantissa and exponent. The
|
||||
special values @code{NaN}, @code{+/-Infinity}, @code{+0} and @code{-0}
|
||||
are supported. The mantissa and exponent can have any bit length with
|
||||
an implementation specific minimum and maximum.
|
||||
|
||||
@section Floating point rounding
|
||||
|
||||
Each floating point operation operates with infinite precision and
|
||||
then rounds the result according to the specified floating point
|
||||
environment (@code{BigFloatEnv} object). The status flags of the
|
||||
environment are also set according to the result of the operation.
|
||||
|
||||
If no floating point environment is provided, the global floating
|
||||
point environment is used.
|
||||
|
||||
The rounding mode of the global floating point environment is always
|
||||
@code{RNDN} (``round to nearest with ties to even'')@footnote{The
|
||||
rationale is that the rounding mode changes must always be
|
||||
explicit.}. The status flags of the global environment cannot be
|
||||
read@footnote{The rationale is to avoid side effects for the built-in
|
||||
operators.}. The precision of the global environment is
|
||||
@code{BigFloatEnv.prec}. The number of exponent bits of the global
|
||||
environment is @code{BigFloatEnv.expBits}. The global environment
|
||||
subnormal flag is set to @code{true}.
|
||||
|
||||
For example, @code{prec = 53} and @code{ expBits = 11} exactly give
|
||||
the same precision as the IEEE 754 64 bit floating point format. The
|
||||
default precision is @code{prec = 113} and @code{ expBits = 15} (IEEE
|
||||
754 128 bit floating point format).
|
||||
|
||||
The global floating point environment can only be modified temporarily
|
||||
when calling a function (see @code{BigFloatEnv.setPrec}). Hence a
|
||||
function can change the global floating point environment for its
|
||||
callees but not for its caller.
|
||||
|
||||
@section Operators
|
||||
|
||||
The builtin operators are extended so that a BigFloat is returned if
|
||||
at least one operand is a BigFloat. The computations are always done
|
||||
with infinite precision and rounded according to the global floating
|
||||
point environment.
|
||||
|
||||
@code{typeof} applied on a @code{BigFloat} returns @code{bigfloat}.
|
||||
|
||||
BigFloat can be compared with all the other numeric types and the
|
||||
result follows the expected mathematical relations.
|
||||
|
||||
However, since BigFloat and Number are different types they are never
|
||||
equal when using the strict comparison operators (e.g. @code{0.0 ===
|
||||
0.0l} is false).
|
||||
|
||||
@section BigFloat literals
|
||||
|
||||
BigFloat literals are floating point numbers with a trailing @code{l}
|
||||
suffix. BigFloat literals have an infinite precision. They are rounded
|
||||
according to the global floating point environment when they are
|
||||
evaluated.@footnote{Base 10 floating point literals cannot usually be
|
||||
exactly represented as base 2 floating point number. In order to
|
||||
ensure that the literal is represented accurately with the current
|
||||
precision, it must be evaluated at runtime.}
|
||||
|
||||
@section Builtin Object changes
|
||||
|
||||
@subsection @code{BigFloat} function
|
||||
|
||||
The @code{BigFloat} function cannot be invoked as a constructor. When
|
||||
invoked as a function: the parameter is converted to a primitive
|
||||
type. If the result is a numeric type, it is converted to BigFloat
|
||||
without rounding. If the result is a string, it is converted to
|
||||
BigFloat using the precision of the global floating point environment.
|
||||
|
||||
@code{BigFloat} properties:
|
||||
|
||||
@table @code
|
||||
|
||||
@item LN2
|
||||
@item PI
|
||||
Getter. Return the value of the corresponding mathematical constant
|
||||
rounded to nearest, ties to even with the current global
|
||||
precision. The constant values are cached for small precisions.
|
||||
|
||||
@item MIN_VALUE
|
||||
@item MAX_VALUE
|
||||
@item EPSILON
|
||||
Getter. Return the minimum, maximum and epsilon @code{BigFloat} values
|
||||
(same definition as the corresponding @code{Number} constants).
|
||||
|
||||
@item fpRound(a[, e])
|
||||
Round the floating point number @code{a} according to the floating
|
||||
point environment @code{e} or the global environment if @code{e} is
|
||||
undefined.
|
||||
|
||||
@item parseFloat(a[, radix[, e]])
|
||||
Parse the string @code{a} as a floating point number in radix
|
||||
@code{radix}. The radix is 0 (default) or from 2 to 36. The radix 0
|
||||
means radix 10 unless there is a hexadecimal or binary prefix. The
|
||||
result is rounded according to the floating point environment @code{e}
|
||||
or the global environment if @code{e} is undefined.
|
||||
|
||||
@item isFinite(a)
|
||||
Return true if @code{a} is a finite bigfloat.
|
||||
|
||||
@item isNaN(a)
|
||||
Return true if @code{a} is a NaN bigfloat.
|
||||
|
||||
@item add(a, b[, e])
|
||||
@item sub(a, b[, e])
|
||||
@item mul(a, b[, e])
|
||||
@item div(a, b[, e])
|
||||
Perform the specified floating point operation and round the floating
|
||||
point number @code{a} according to the floating point environment
|
||||
@code{e} or the global environment if @code{e} is undefined. If
|
||||
@code{e} is specified, the floating point status flags are updated.
|
||||
|
||||
@item floor(x)
|
||||
@item ceil(x)
|
||||
@item round(x)
|
||||
@item trunc(x)
|
||||
Round to an integer. No additional rounding is performed.
|
||||
|
||||
@item abs(x)
|
||||
Return the absolute value of x. No additional rounding is performed.
|
||||
|
||||
@item fmod(x, y[, e])
|
||||
@item remainder(x, y[, e])
|
||||
Floating point remainder. The quotient is truncated to zero (fmod) or
|
||||
to the nearest integer with ties to even (remainder). @code{e} is an
|
||||
optional floating point environment.
|
||||
|
||||
@item sqrt(x[, e])
|
||||
Square root. Return a rounded floating point number. @code{e} is an
|
||||
optional floating point environment.
|
||||
|
||||
@item sin(x[, e])
|
||||
@item cos(x[, e])
|
||||
@item tan(x[, e])
|
||||
@item asin(x[, e])
|
||||
@item acos(x[, e])
|
||||
@item atan(x[, e])
|
||||
@item atan2(x, y[, e])
|
||||
@item exp(x[, e])
|
||||
@item log(x[, e])
|
||||
@item pow(x, y[, e])
|
||||
Transcendental operations. Return a rounded floating point
|
||||
number. @code{e} is an optional floating point environment.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection @code{BigFloat.prototype}
|
||||
|
||||
The following properties are modified:
|
||||
|
||||
@table @code
|
||||
@item valueOf()
|
||||
Return the bigfloat primitive value corresponding to @code{this}.
|
||||
|
||||
@item toString(radix)
|
||||
|
||||
For floating point numbers:
|
||||
|
||||
@itemize
|
||||
@item
|
||||
If the radix is a power of two, the conversion is done with infinite
|
||||
precision.
|
||||
@item
|
||||
Otherwise, the number is rounded to nearest with ties to even using
|
||||
the global precision. It is then converted to string using the minimum
|
||||
number of digits so that its conversion back to a floating point using
|
||||
the global precision and round to nearest gives the same number.
|
||||
|
||||
@end itemize
|
||||
|
||||
The exponent letter is @code{e} for base 10, @code{p} for bases 2, 8,
|
||||
16 with a binary exponent and @code{@@} for the other bases.
|
||||
|
||||
@item toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
|
||||
@item toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
|
||||
@item toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
|
||||
Same semantics as the corresponding @code{Number} functions with
|
||||
BigFloats. There is no limit on the accepted precision @code{p}. The
|
||||
rounding mode and radix can be optionally specified. The radix must be
|
||||
between 2 and 36.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection @code{BigFloatEnv} constructor
|
||||
|
||||
The @code{BigFloatEnv([p, [,rndMode]]} constructor cannot be invoked as a
|
||||
function. The floating point environment contains:
|
||||
|
||||
@itemize
|
||||
@item the mantissa precision in bits
|
||||
|
||||
@item the exponent size in bits assuming an IEEE 754 representation;
|
||||
|
||||
@item the subnormal flag (if true, subnormal floating point numbers can
|
||||
be generated by the floating point operations).
|
||||
|
||||
@item the rounding mode
|
||||
|
||||
@item the floating point status. The status flags can only be set by the floating point operations. They can be reset with @code{BigFloatEnv.prototype.clearStatus()} or with the various status flag setters.
|
||||
|
||||
@end itemize
|
||||
|
||||
@code{new BigFloatEnv([p, [,rndMode]]} creates a new floating point
|
||||
environment. The status flags are reset. If no parameter is given the
|
||||
precision, exponent bits and subnormal flags are copied from the
|
||||
global floating point environment. Otherwise, the precision is set to
|
||||
@code{p}, the number of exponent bits is set to @code{expBitsMax} and the
|
||||
subnormal flags is set to @code{false}. If @code{rndMode} is
|
||||
@code{undefined}, the rounding mode is set to @code{RNDN}.
|
||||
|
||||
@code{BigFloatEnv} properties:
|
||||
|
||||
@table @code
|
||||
|
||||
@item prec
|
||||
Getter. Return the precision in bits of the global floating point
|
||||
environment. The initial value is @code{113}.
|
||||
|
||||
@item expBits
|
||||
Getter. Return the exponent size in bits of the global floating point
|
||||
environment assuming an IEEE 754 representation. The initial value is
|
||||
@code{15}.
|
||||
|
||||
@item setPrec(f, p[, e])
|
||||
Set the precision of the global floating point environment to @code{p}
|
||||
and the exponent size to @code{e} then call the function
|
||||
@code{f}. Then the Float precision and exponent size are reset to
|
||||
their precious value and the return value of @code{f} is returned (or
|
||||
an exception is raised if @code{f} raised an exception). If @code{e}
|
||||
is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}.
|
||||
|
||||
@item precMin
|
||||
Read-only integer. Return the minimum allowed precision. Must be at least 2.
|
||||
|
||||
@item precMax
|
||||
Read-only integer. Return the maximum allowed precision. Must be at least 113.
|
||||
|
||||
@item expBitsMin
|
||||
Read-only integer. Return the minimum allowed exponent size in
|
||||
bits. Must be at least 3.
|
||||
|
||||
@item expBitsMax
|
||||
Read-only integer. Return the maximum allowed exponent size in
|
||||
bits. Must be at least 15.
|
||||
|
||||
@item RNDN
|
||||
Read-only integer. Round to nearest, with ties to even rounding mode.
|
||||
|
||||
@item RNDZ
|
||||
Read-only integer. Round to zero rounding mode.
|
||||
|
||||
@item RNDD
|
||||
Read-only integer. Round to -Infinity rounding mode.
|
||||
|
||||
@item RNDU
|
||||
Read-only integer. Round to +Infinity rounding mode.
|
||||
|
||||
@item RNDNA
|
||||
Read-only integer. Round to nearest, with ties away from zero rounding mode.
|
||||
|
||||
@item RNDA
|
||||
Read-only integer. Round away from zero rounding mode.
|
||||
|
||||
@item RNDF@footnote{Could be removed in case a deterministic behavior for floating point operations is required.}
|
||||
Read-only integer. Faithful rounding mode. The result is
|
||||
non-deterministically rounded to -Infinity or +Infinity. This rounding
|
||||
mode usually gives a faster and deterministic running time for the
|
||||
floating point operations.
|
||||
|
||||
@end table
|
||||
|
||||
@code{BigFloatEnv.prototype} properties:
|
||||
|
||||
@table @code
|
||||
|
||||
@item prec
|
||||
Getter and setter (Integer). Return or set the precision in bits.
|
||||
|
||||
@item expBits
|
||||
Getter and setter (Integer). Return or set the exponent size in bits
|
||||
assuming an IEEE 754 representation.
|
||||
|
||||
@item rndMode
|
||||
Getter and setter (Integer). Return or set the rounding mode.
|
||||
|
||||
@item subnormal
|
||||
Getter and setter (Boolean). subnormal flag. It is false when
|
||||
@code{expBits = expBitsMax}.
|
||||
|
||||
@item clearStatus()
|
||||
Clear the status flags.
|
||||
|
||||
@item invalidOperation
|
||||
@item divideByZero
|
||||
@item overflow
|
||||
@item underflow
|
||||
@item inexact
|
||||
Getter and setter (Boolean). Status flags.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter BigDecimal
|
||||
|
||||
This extension adds the @code{BigDecimal} primitive type. The
|
||||
@code{BigDecimal} type represents floating point numbers in base
|
||||
10. It is inspired from the proposal available at
|
||||
@url{https://github.com/littledan/proposal-bigdecimal}.
|
||||
|
||||
The @code{BigDecimal} floating point numbers are always normalized and
|
||||
finite. There is no concept of @code{-0}, @code{Infinity} or
|
||||
@code{NaN}. By default, all the computations are done with infinite
|
||||
precision.
|
||||
|
||||
@section Operators
|
||||
|
||||
The following builtin operators support BigDecimal:
|
||||
|
||||
@table @code
|
||||
|
||||
@item +
|
||||
@item -
|
||||
@item *
|
||||
Both operands must be BigDecimal. The result is computed with infinite
|
||||
precision.
|
||||
@item %
|
||||
Both operands must be BigDecimal. The result is computed with infinite
|
||||
precision. A range error is throws in case of division by zero.
|
||||
|
||||
@item /
|
||||
Both operands must be BigDecimal. A range error is throws in case of
|
||||
division by zero or if the result cannot be represented with infinite
|
||||
precision (use @code{BigDecimal.div} to specify the rounding).
|
||||
|
||||
@item **
|
||||
Both operands must be BigDecimal. The exponent must be a positive
|
||||
integer. The result is computed with infinite precision.
|
||||
|
||||
@item ===
|
||||
When one of the operand is a BigDecimal, return true if both operands
|
||||
are a BigDecimal and if they are equal.
|
||||
|
||||
@item ==
|
||||
@item !=
|
||||
@item <=
|
||||
@item >=
|
||||
@item <
|
||||
@item >
|
||||
|
||||
Numerical comparison. When one of the operand is not a BigDecimal, it is
|
||||
converted to BigDecimal by using ToString(). Hence comparisons between
|
||||
Number and BigDecimal do not use the exact mathematical value of the
|
||||
Number value.
|
||||
|
||||
@end table
|
||||
|
||||
@section BigDecimal literals
|
||||
|
||||
BigDecimal literals are decimal floating point numbers with a trailing
|
||||
@code{m} suffix.
|
||||
|
||||
@section Builtin Object changes
|
||||
|
||||
@subsection The @code{BigDecimal} function.
|
||||
|
||||
It returns @code{0m} if no parameter is provided. Otherwise the first
|
||||
parameter is converted to a bigdecimal by using ToString(). Hence
|
||||
Number values are not converted to their exact numerical value as
|
||||
BigDecimal.
|
||||
|
||||
@subsection Properties of the @code{BigDecimal} object
|
||||
|
||||
@table @code
|
||||
|
||||
@item add(a, b[, e])
|
||||
@item sub(a, b[, e])
|
||||
@item mul(a, b[, e])
|
||||
@item div(a, b[, e])
|
||||
@item mod(a, b[, e])
|
||||
@item sqrt(a, e)
|
||||
@item round(a, e)
|
||||
Perform the specified floating point operation and round the floating
|
||||
point result according to the rounding object @code{e}. If the
|
||||
rounding object is not present, the operation is executed with
|
||||
infinite precision.
|
||||
|
||||
For @code{div}, a @code{RangeError} exception is thrown in case of
|
||||
division by zero or if the result cannot be represented with infinite
|
||||
precision if no rounding object is present.
|
||||
|
||||
For @code{sqrt}, a range error is thrown if @code{a} is less than
|
||||
zero.
|
||||
|
||||
The rounding object must contain the following properties:
|
||||
@code{roundingMode} is a string specifying the rounding mode
|
||||
(@code{"floor"}, @code{"ceiling"}, @code{"down"}, @code{"up"},
|
||||
@code{"half-even"}, @code{"half-up"}). Either
|
||||
@code{maximumSignificantDigits} or @code{maximumFractionDigits} must
|
||||
be present to specify respectively the number of significant digits
|
||||
(must be >= 1) or the number of digits after the decimal point (must
|
||||
be >= 0).
|
||||
|
||||
@end table
|
||||
|
||||
@subsection Properties of the @code{BigDecimal.prototype} object
|
||||
|
||||
@table @code
|
||||
@item valueOf()
|
||||
Return the bigdecimal primitive value corresponding to @code{this}.
|
||||
|
||||
@item toString()
|
||||
Convert @code{this} to a string with infinite precision in base 10.
|
||||
|
||||
@item toPrecision(p, rnd_mode = "half-up")
|
||||
@item toFixed(p, rnd_mode = "half-up")
|
||||
@item toExponential(p, rnd_mode = "half-up")
|
||||
Convert the BigDecimal @code{this} to string with the specified
|
||||
precision @code{p}. There is no limit on the accepted precision
|
||||
@code{p}. The rounding mode can be optionally
|
||||
specified. @code{toPrecision} outputs either in decimal fixed notation
|
||||
or in decimal exponential notation with a @code{p} digits of
|
||||
precision. @code{toExponential} outputs in decimal exponential
|
||||
notation with @code{p} digits after the decimal point. @code{toFixed}
|
||||
outputs in decimal notation with @code{p} digits after the decimal
|
||||
point.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter Math mode
|
||||
|
||||
A new @emph{math mode} is enabled with the @code{"use math"}
|
||||
directive. It propagates the same way as the @emph{strict mode}. It is
|
||||
designed so that arbitrarily large integers and floating point numbers
|
||||
are available by default. In order to minimize the number of changes
|
||||
in the Javascript semantics, integers are represented either as Number
|
||||
or BigInt depending on their magnitude. Floating point numbers are
|
||||
always represented as BigFloat.
|
||||
|
||||
The following changes are made to the Javascript semantics:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Floating point literals (i.e. number with a decimal point or an exponent) are @code{BigFloat} by default (i.e. a @code{l} suffix is implied). Hence @code{typeof 1.0 === "bigfloat"}.
|
||||
|
||||
@item Integer literals (i.e. numbers without a decimal point or an exponent) with or without the @code{n} suffix are @code{BigInt} if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to @code{2**53-1}. Hence @code{typeof 1 === "number "}, @code{typeof 1n === "number"} but @code{typeof 9007199254740992 === "bigint" }.
|
||||
|
||||
@item All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt.
|
||||
|
||||
@item The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result.
|
||||
|
||||
@item The @code{^} operator is an alias to the power operator (@code{**}).
|
||||
|
||||
@item The power operator (both @code{^} and @code{**}) grammar is modified so that @code{-2^2} is allowed and yields @code{-4}.
|
||||
|
||||
@item The logical xor operator is still available with the @code{^^} operator.
|
||||
|
||||
@item The modulo operator (@code{%}) returns the Euclidian remainder (always positive) instead of the truncated remainder.
|
||||
|
||||
@item The integer division operator can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
|
||||
|
||||
@item The integer power operator with a non zero negative exponent can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
|
||||
|
||||
@end itemize
|
||||
|
||||
@bye
|
@ -5,11 +5,14 @@
|
||||
@headings double
|
||||
@end iftex
|
||||
|
||||
@include version.texi
|
||||
|
||||
@titlepage
|
||||
@afourpaper
|
||||
@sp 7
|
||||
@center @titlefont{QuickJS Javascript Engine}
|
||||
@sp 3
|
||||
@center Version: @value{VERSION}
|
||||
@end titlepage
|
||||
|
||||
@setfilename spec.info
|
||||
@ -19,14 +22,10 @@
|
||||
|
||||
@chapter Introduction
|
||||
|
||||
QuickJS is a small and embeddable Javascript engine. It supports most of the
|
||||
ES2023 specification
|
||||
@footnote{@url{https://tc39.es/ecma262/2023 }}
|
||||
including modules, asynchronous generators, proxies and BigInt.
|
||||
|
||||
It supports mathematical extensions such as big decimal float float
|
||||
numbers (BigDecimal), big binary floating point numbers (BigFloat),
|
||||
and operator overloading.
|
||||
QuickJS (version @value{VERSION}) is a small and embeddable Javascript
|
||||
engine. It supports most of the ES2023 specification
|
||||
@footnote{@url{https://tc39.es/ecma262/2023 }} including modules,
|
||||
asynchronous generators, proxies and BigInt.
|
||||
|
||||
@section Main Features
|
||||
|
||||
@ -47,8 +46,6 @@ features from the upcoming ES2024 specification
|
||||
|
||||
@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.
|
||||
@ -123,10 +120,6 @@ 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 math"} directive.
|
||||
|
||||
@item -I file
|
||||
@item --include file
|
||||
Include an additional file.
|
||||
@ -160,7 +153,7 @@ Options are:
|
||||
@table @code
|
||||
@item -c
|
||||
Only output bytecode in a C file. The default is to output an executable file.
|
||||
@item -e
|
||||
@item -e
|
||||
Output @code{main()} and bytecode in a C file. The default is to output an
|
||||
executable file.
|
||||
@item -o output
|
||||
@ -193,21 +186,8 @@ 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 math"} directive.
|
||||
|
||||
@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
|
||||
@ -281,45 +261,12 @@ The following features are not supported yet:
|
||||
|
||||
@item Tail calls@footnote{We believe the current specification of tails calls is too complicated and presents limited practical interests.}
|
||||
|
||||
@item WeakRef and FinalizationRegistry objects
|
||||
|
||||
@item Symbols as WeakMap keys
|
||||
|
||||
@end itemize
|
||||
|
||||
@subsection ECMA402
|
||||
|
||||
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
|
||||
@ -379,7 +326,9 @@ optional properties:
|
||||
stack frames below the evalScript.
|
||||
@item async
|
||||
Boolean (default = false). If true, @code{await} is accepted in the
|
||||
script and a promise is returned.
|
||||
script and a promise is returned. The promise is resolved with an
|
||||
object whose @code{value} property holds the value returned by the
|
||||
script.
|
||||
@end table
|
||||
|
||||
@item loadScript(filename)
|
||||
@ -487,7 +436,7 @@ optional properties:
|
||||
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}
|
||||
@ -594,7 +543,7 @@ Available exports:
|
||||
Open a file. Return a handle or < 0 if error.
|
||||
|
||||
@item O_RDONLY
|
||||
@item O_WRONLY
|
||||
@item O_WRONLY
|
||||
@item O_RDWR
|
||||
@item O_APPEND
|
||||
@item O_CREAT
|
||||
@ -732,7 +681,7 @@ object containing optional parameters:
|
||||
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.
|
||||
@ -756,7 +705,7 @@ object containing optional parameters:
|
||||
@item uid
|
||||
Integer. If present, the process uid with @code{setuid}.
|
||||
|
||||
@item gid
|
||||
@item gid
|
||||
Integer. If present, the process gid with @code{setgid}.
|
||||
|
||||
@end table
|
||||
@ -827,7 +776,7 @@ The worker instances have the following properties:
|
||||
|
||||
@table @code
|
||||
@item postMessage(msg)
|
||||
|
||||
|
||||
Send a message to the corresponding worker. @code{msg} is cloned in
|
||||
the destination worker using an algorithm similar to the @code{HTML}
|
||||
structured clone algorithm. @code{SharedArrayBuffer} are shared
|
||||
@ -970,7 +919,7 @@ 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
|
||||
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
|
||||
@ -1103,12 +1052,11 @@ binary properties.
|
||||
|
||||
The full Unicode library weights about 45 KiB (x86 code).
|
||||
|
||||
@section BigInt, BigFloat, BigDecimal
|
||||
@section BigInt
|
||||
|
||||
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.
|
||||
BigInts are represented using binary two's complement notation. An
|
||||
additional short bigint value is used to optimize the performance on
|
||||
small BigInt values.
|
||||
|
||||
@chapter License
|
||||
|
||||
|
83
dtoa.h
Normal file
83
dtoa.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Tiny float64 printing and parsing library
|
||||
*
|
||||
* Copyright (c) 2024 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.
|
||||
*/
|
||||
|
||||
//#define JS_DTOA_DUMP_STATS
|
||||
|
||||
/* maximum number of digits for fixed and frac formats */
|
||||
#define JS_DTOA_MAX_DIGITS 101
|
||||
|
||||
/* radix != 10 is only supported with flags = JS_DTOA_FORMAT_FREE */
|
||||
/* use as many digits as necessary */
|
||||
#define JS_DTOA_FORMAT_FREE (0 << 0)
|
||||
/* use n_digits significant digits (1 <= n_digits <= JS_DTOA_MAX_DIGITS) */
|
||||
#define JS_DTOA_FORMAT_FIXED (1 << 0)
|
||||
/* force fractional format: [-]dd.dd with n_digits fractional digits.
|
||||
0 <= n_digits <= JS_DTOA_MAX_DIGITS */
|
||||
#define JS_DTOA_FORMAT_FRAC (2 << 0)
|
||||
#define JS_DTOA_FORMAT_MASK (3 << 0)
|
||||
|
||||
/* select exponential notation either in fixed or free format */
|
||||
#define JS_DTOA_EXP_AUTO (0 << 2)
|
||||
#define JS_DTOA_EXP_ENABLED (1 << 2)
|
||||
#define JS_DTOA_EXP_DISABLED (2 << 2)
|
||||
#define JS_DTOA_EXP_MASK (3 << 2)
|
||||
|
||||
#define JS_DTOA_MINUS_ZERO (1 << 4) /* show the minus sign for -0 */
|
||||
|
||||
/* only accepts integers (no dot, no exponent) */
|
||||
#define JS_ATOD_INT_ONLY (1 << 0)
|
||||
/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
|
||||
#define JS_ATOD_ACCEPT_BIN_OCT (1 << 1)
|
||||
/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
|
||||
#define JS_ATOD_ACCEPT_LEGACY_OCTAL (1 << 2)
|
||||
/* accept _ between digits as a digit separator */
|
||||
#define JS_ATOD_ACCEPT_UNDERSCORES (1 << 3)
|
||||
|
||||
typedef struct {
|
||||
uint64_t mem[37];
|
||||
} JSDTOATempMem;
|
||||
|
||||
typedef struct {
|
||||
uint64_t mem[27];
|
||||
} JSATODTempMem;
|
||||
|
||||
/* return a maximum bound of the string length */
|
||||
int js_dtoa_max_len(double d, int radix, int n_digits, int flags);
|
||||
/* return the string length */
|
||||
int js_dtoa(char *buf, double d, int radix, int n_digits, int flags,
|
||||
JSDTOATempMem *tmp_mem);
|
||||
double js_atod(const char *str, const char **pnext, int radix, int flags,
|
||||
JSATODTempMem *tmp_mem);
|
||||
|
||||
#ifdef JS_DTOA_DUMP_STATS
|
||||
void js_dtoa_dump_stats(void);
|
||||
#endif
|
||||
|
||||
/* additional exported functions */
|
||||
size_t u32toa(char *buf, uint32_t n);
|
||||
size_t i32toa(char *buf, int32_t n);
|
||||
size_t u64toa(char *buf, uint64_t n);
|
||||
size_t i64toa(char *buf, int64_t n);
|
||||
size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix);
|
||||
size_t i64toa_radix(char *buf, int64_t n, unsigned int radix);
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* QuickJS: Example of C module
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* PI computation in Javascript using the QuickJS bigdecimal type
|
||||
* (decimal floating point)
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/* compute PI with a precision of 'prec' digits */
|
||||
function calc_pi(prec) {
|
||||
const CHUD_A = 13591409m;
|
||||
const CHUD_B = 545140134m;
|
||||
const CHUD_C = 640320m;
|
||||
const CHUD_C3 = 10939058860032000m; /* C^3/24 */
|
||||
const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */
|
||||
|
||||
/* return [P, Q, G] */
|
||||
function chud_bs(a, b, need_G) {
|
||||
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1;
|
||||
if (a == (b - 1n)) {
|
||||
b1 = BigDecimal(b);
|
||||
G = (2m * b1 - 1m) * (6m * b1 - 1m) * (6m * b1 - 5m);
|
||||
P = G * (CHUD_B * b1 + CHUD_A);
|
||||
if (b & 1n)
|
||||
P = -P;
|
||||
G = G;
|
||||
Q = b1 * b1 * b1 * CHUD_C3;
|
||||
} else {
|
||||
c = (a + b) >> 1n;
|
||||
[P1, Q1, G1] = chud_bs(a, c, true);
|
||||
[P2, Q2, G2] = chud_bs(c, b, need_G);
|
||||
P = P1 * Q2 + P2 * G1;
|
||||
Q = Q1 * Q2;
|
||||
if (need_G)
|
||||
G = G1 * G2;
|
||||
else
|
||||
G = 0m;
|
||||
}
|
||||
return [P, Q, G];
|
||||
}
|
||||
|
||||
var n, P, Q, G;
|
||||
/* number of serie terms */
|
||||
n = BigInt(Math.ceil(prec / CHUD_DIGITS_PER_TERM)) + 10n;
|
||||
[P, Q, G] = chud_bs(0n, n, false);
|
||||
Q = BigDecimal.div(Q, (P + Q * CHUD_A),
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: prec });
|
||||
G = (CHUD_C / 12m) * BigDecimal.sqrt(CHUD_C,
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: prec });
|
||||
return Q * G;
|
||||
}
|
||||
|
||||
(function() {
|
||||
var r, n_digits, n_bits;
|
||||
if (typeof scriptArgs != "undefined") {
|
||||
if (scriptArgs.length < 2) {
|
||||
print("usage: pi n_digits");
|
||||
return;
|
||||
}
|
||||
n_digits = scriptArgs[1] | 0;
|
||||
} else {
|
||||
n_digits = 1000;
|
||||
}
|
||||
/* we add more digits to reduce the probability of bad rounding for
|
||||
the last digits */
|
||||
r = calc_pi(n_digits + 20);
|
||||
print(r.toFixed(n_digits, "down"));
|
||||
})();
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* PI computation in Javascript using the QuickJS bigfloat type
|
||||
* (binary floating point)
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/* compute PI with a precision of 'prec' bits */
|
||||
function calc_pi() {
|
||||
const CHUD_A = 13591409n;
|
||||
const CHUD_B = 545140134n;
|
||||
const CHUD_C = 640320n;
|
||||
const CHUD_C3 = 10939058860032000n; /* C^3/24 */
|
||||
const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
|
||||
|
||||
/* return [P, Q, G] */
|
||||
function chud_bs(a, b, need_G) {
|
||||
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
|
||||
if (a == (b - 1n)) {
|
||||
G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
|
||||
P = BigFloat(G * (CHUD_B * b + CHUD_A));
|
||||
if (b & 1n)
|
||||
P = -P;
|
||||
G = BigFloat(G);
|
||||
Q = BigFloat(b * b * b * CHUD_C3);
|
||||
} else {
|
||||
c = (a + b) >> 1n;
|
||||
[P1, Q1, G1] = chud_bs(a, c, true);
|
||||
[P2, Q2, G2] = chud_bs(c, b, need_G);
|
||||
P = P1 * Q2 + P2 * G1;
|
||||
Q = Q1 * Q2;
|
||||
if (need_G)
|
||||
G = G1 * G2;
|
||||
else
|
||||
G = 0l;
|
||||
}
|
||||
return [P, Q, G];
|
||||
}
|
||||
|
||||
var n, P, Q, G;
|
||||
/* number of serie terms */
|
||||
n = BigInt(Math.ceil(BigFloatEnv.prec / CHUD_BITS_PER_TERM)) + 10n;
|
||||
[P, Q, G] = chud_bs(0n, n, false);
|
||||
Q = Q / (P + Q * BigFloat(CHUD_A));
|
||||
G = BigFloat((CHUD_C / 12n)) * BigFloat.sqrt(BigFloat(CHUD_C));
|
||||
return Q * G;
|
||||
}
|
||||
|
||||
(function() {
|
||||
var r, n_digits, n_bits;
|
||||
if (typeof scriptArgs != "undefined") {
|
||||
if (scriptArgs.length < 2) {
|
||||
print("usage: pi n_digits");
|
||||
return;
|
||||
}
|
||||
n_digits = scriptArgs[1];
|
||||
} else {
|
||||
n_digits = 1000;
|
||||
}
|
||||
n_bits = Math.ceil(n_digits * Math.log2(10));
|
||||
/* we add more bits to reduce the probability of bad rounding for
|
||||
the last digits */
|
||||
BigFloatEnv.setPrec( () => {
|
||||
r = calc_pi();
|
||||
print(r.toFixed(n_digits, BigFloatEnv.RNDZ));
|
||||
}, n_bits + 32);
|
||||
})();
|
@ -54,7 +54,7 @@ function calc_pi(prec) {
|
||||
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;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
@ -49,7 +49,7 @@ static JSValue js_point_ctor(JSContext *ctx,
|
||||
JSPointData *s;
|
||||
JSValue obj = JS_UNDEFINED;
|
||||
JSValue proto;
|
||||
|
||||
|
||||
s = js_mallocz(ctx, sizeof(*s));
|
||||
if (!s)
|
||||
return JS_EXCEPTION;
|
||||
@ -112,7 +112,7 @@ static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val,
|
||||
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),
|
||||
@ -123,19 +123,19 @@ static const JSCFunctionListEntry js_point_proto_funcs[] = {
|
||||
static int js_point_init(JSContext *ctx, JSModuleDef *m)
|
||||
{
|
||||
JSValue point_proto, point_class;
|
||||
|
||||
|
||||
/* create the Point class */
|
||||
JS_NewClassID(&js_point_class_id);
|
||||
JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class);
|
||||
|
||||
point_proto = JS_NewObject(ctx);
|
||||
JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs));
|
||||
|
||||
|
||||
point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0);
|
||||
/* set proto.constructor and ctor.prototype */
|
||||
JS_SetConstructor(ctx, point_class, point_proto);
|
||||
JS_SetClassProto(ctx, js_point_class_id, point_proto);
|
||||
|
||||
|
||||
JS_SetModuleExport(ctx, m, "Point", point_class);
|
||||
return 0;
|
||||
}
|
||||
|
27
fuzz/README
Normal file
27
fuzz/README
Normal file
@ -0,0 +1,27 @@
|
||||
libFuzzer support for QuickJS
|
||||
=============================
|
||||
|
||||
Build QuickJS with libFuzzer support as follows:
|
||||
|
||||
CONFIG_CLANG=y make libfuzzer
|
||||
|
||||
This can be extended with sanitizer support to improve efficacy:
|
||||
|
||||
CONFIG_CLANG=y CONFIG_ASAN=y make libfuzzer
|
||||
|
||||
|
||||
Currently, there are three fuzzing targets defined: fuzz_eval, fuzz_compile and fuzz_regexp.
|
||||
The above build command will produce an executable binary for each of them, which can be
|
||||
simply executed as:
|
||||
|
||||
./fuzz_eval
|
||||
|
||||
or with an initial corpus:
|
||||
|
||||
./fuzz_compile corpus_dir/
|
||||
|
||||
or with a predefined dictionary to improve its efficacy:
|
||||
|
||||
./fuzz_eval -dict fuzz/fuzz.dict
|
||||
|
||||
or with arbitrary CLI arguments provided by libFuzzer (https://llvm.org/docs/LibFuzzer.html).
|
254
fuzz/fuzz.dict
Normal file
254
fuzz/fuzz.dict
Normal file
@ -0,0 +1,254 @@
|
||||
"__loadScript"
|
||||
"abs"
|
||||
"acos"
|
||||
"acosh"
|
||||
"add"
|
||||
"AggregateError"
|
||||
"and"
|
||||
"apply"
|
||||
"Array"
|
||||
"ArrayBuffer"
|
||||
"asin"
|
||||
"asinh"
|
||||
"atan"
|
||||
"atan2"
|
||||
"atanh"
|
||||
"Atomics"
|
||||
"BigInt"
|
||||
"BigInt64Array"
|
||||
"BigUint64Array"
|
||||
"Boolean"
|
||||
"cbrt"
|
||||
"ceil"
|
||||
"chdir"
|
||||
"clearTimeout"
|
||||
"close"
|
||||
"clz32"
|
||||
"compareExchange"
|
||||
"console"
|
||||
"construct"
|
||||
"cos"
|
||||
"cosh"
|
||||
"DataView"
|
||||
"Date"
|
||||
"decodeURI"
|
||||
"decodeURIComponent"
|
||||
"defineProperty"
|
||||
"deleteProperty"
|
||||
"dup"
|
||||
"dup2"
|
||||
"E"
|
||||
"encodeURI"
|
||||
"encodeURIComponent"
|
||||
"err"
|
||||
"Error"
|
||||
"escape"
|
||||
"eval"
|
||||
"EvalError"
|
||||
"evalScript"
|
||||
"exchange"
|
||||
"exec"
|
||||
"exit"
|
||||
"exp"
|
||||
"expm1"
|
||||
"fdopen"
|
||||
"Float32Array"
|
||||
"Float64Array"
|
||||
"floor"
|
||||
"fround"
|
||||
"Function"
|
||||
"gc"
|
||||
"get"
|
||||
"getcwd"
|
||||
"getenv"
|
||||
"getenviron"
|
||||
"getOwnPropertyDescriptor"
|
||||
"getpid"
|
||||
"getPrototypeOf"
|
||||
"globalThis"
|
||||
"has"
|
||||
"hypot"
|
||||
"imul"
|
||||
"in"
|
||||
"Infinity"
|
||||
"Int16Array"
|
||||
"Int32Array"
|
||||
"Int8Array"
|
||||
"InternalError"
|
||||
"isatty"
|
||||
"isExtensible"
|
||||
"isFinite"
|
||||
"isLockFree"
|
||||
"isNaN"
|
||||
"iterateBuiltIns"
|
||||
"JSON"
|
||||
"kill"
|
||||
"length"
|
||||
"LN10"
|
||||
"LN2"
|
||||
"load"
|
||||
"loadFile"
|
||||
"loadScript"
|
||||
"log"
|
||||
"log10"
|
||||
"LOG10E"
|
||||
"log1p"
|
||||
"log2"
|
||||
"LOG2E"
|
||||
"lstat"
|
||||
"Map"
|
||||
"Math"
|
||||
"max"
|
||||
"min"
|
||||
"mkdir"
|
||||
"NaN"
|
||||
"notify"
|
||||
"now"
|
||||
"Number"
|
||||
"O_APPEND"
|
||||
"O_CREAT"
|
||||
"O_EXCL"
|
||||
"O_RDONLY"
|
||||
"O_RDWR"
|
||||
"O_TRUNC"
|
||||
"O_WRONLY"
|
||||
"Object"
|
||||
"open"
|
||||
"Operators"
|
||||
"or"
|
||||
"os"
|
||||
"out"
|
||||
"ownKeys"
|
||||
"parse"
|
||||
"parseExtJSON"
|
||||
"parseFloat"
|
||||
"parseInt"
|
||||
"PI"
|
||||
"pipe"
|
||||
"platform"
|
||||
"popen"
|
||||
"pow"
|
||||
"preventExtensions"
|
||||
"print"
|
||||
"printf"
|
||||
"Promise"
|
||||
"Proxy"
|
||||
"puts"
|
||||
"random"
|
||||
"RangeError"
|
||||
"read"
|
||||
"readdir"
|
||||
"readlink"
|
||||
"realpath"
|
||||
"ReferenceError"
|
||||
"Reflect"
|
||||
"RegExp"
|
||||
"remove"
|
||||
"rename"
|
||||
"round"
|
||||
"S_IFBLK"
|
||||
"S_IFCHR"
|
||||
"S_IFDIR"
|
||||
"S_IFIFO"
|
||||
"S_IFLNK"
|
||||
"S_IFMT"
|
||||
"S_IFREG"
|
||||
"S_IFSOCK"
|
||||
"S_ISGID"
|
||||
"S_ISUID"
|
||||
"scriptArgs"
|
||||
"seek"
|
||||
"SEEK_CUR"
|
||||
"SEEK_END"
|
||||
"SEEK_SET"
|
||||
"set"
|
||||
"Set"
|
||||
"setenv"
|
||||
"setPrototypeOf"
|
||||
"setReadHandler"
|
||||
"setTimeout"
|
||||
"setWriteHandler"
|
||||
"SharedArrayBuffer"
|
||||
"SIGABRT"
|
||||
"SIGALRM"
|
||||
"SIGCHLD"
|
||||
"SIGCONT"
|
||||
"SIGFPE"
|
||||
"SIGILL"
|
||||
"SIGINT"
|
||||
"sign"
|
||||
"signal"
|
||||
"SIGPIPE"
|
||||
"SIGQUIT"
|
||||
"SIGSEGV"
|
||||
"SIGSTOP"
|
||||
"SIGTERM"
|
||||
"SIGTSTP"
|
||||
"SIGTTIN"
|
||||
"SIGTTOU"
|
||||
"SIGUSR1"
|
||||
"SIGUSR2"
|
||||
"sin"
|
||||
"sinh"
|
||||
"sleep"
|
||||
"sleepAsync"
|
||||
"sprintf"
|
||||
"sqrt"
|
||||
"SQRT1_2"
|
||||
"SQRT2"
|
||||
"stat"
|
||||
"std"
|
||||
"store"
|
||||
"strerror"
|
||||
"String"
|
||||
"stringify"
|
||||
"sub"
|
||||
"Symbol"
|
||||
"symlink"
|
||||
"SyntaxError"
|
||||
"tan"
|
||||
"tanh"
|
||||
"tmpfile"
|
||||
"trunc"
|
||||
"ttyGetWinSize"
|
||||
"ttySetRaw"
|
||||
"TypeError"
|
||||
"Uint16Array"
|
||||
"Uint32Array"
|
||||
"Uint8Array"
|
||||
"Uint8ClampedArray"
|
||||
"undefined"
|
||||
"unescape"
|
||||
"unsetenv"
|
||||
"URIError"
|
||||
"urlGet"
|
||||
"utimes"
|
||||
"wait"
|
||||
"waitpid"
|
||||
"WeakMap"
|
||||
"WeakSet"
|
||||
"WNOHANG"
|
||||
"Worker"
|
||||
"write"
|
||||
"xor"
|
||||
"v0"
|
||||
"v1"
|
||||
"v2"
|
||||
"v3"
|
||||
"v4"
|
||||
"v5"
|
||||
"v6"
|
||||
"v7"
|
||||
"v8"
|
||||
"v9"
|
||||
"v10"
|
||||
"v11"
|
||||
"v12"
|
||||
"v13"
|
||||
"v14"
|
||||
"v15"
|
||||
"v16"
|
||||
"v17"
|
||||
"v18"
|
||||
"v19"
|
||||
"v20"
|
58
fuzz/fuzz_common.c
Normal file
58
fuzz/fuzz_common.c
Normal file
@ -0,0 +1,58 @@
|
||||
/* Copyright 2020 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "fuzz/fuzz_common.h"
|
||||
|
||||
// handle timeouts from infinite loops
|
||||
static int interrupt_handler(JSRuntime *rt, void *opaque)
|
||||
{
|
||||
nbinterrupts++;
|
||||
return (nbinterrupts > 100);
|
||||
}
|
||||
|
||||
void reset_nbinterrupts() {
|
||||
nbinterrupts = 0;
|
||||
}
|
||||
|
||||
void test_one_input_init(JSRuntime *rt, JSContext *ctx) {
|
||||
// 64 Mo
|
||||
JS_SetMemoryLimit(rt, 0x4000000);
|
||||
// 64 Kb
|
||||
JS_SetMaxStackSize(rt, 0x10000);
|
||||
|
||||
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
|
||||
JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL);
|
||||
js_std_add_helpers(ctx, 0, NULL);
|
||||
|
||||
// Load os and std
|
||||
js_std_init_handlers(rt);
|
||||
js_init_module_std(ctx, "std");
|
||||
js_init_module_os(ctx, "os");
|
||||
const char *str = "import * as std from 'std';\n"
|
||||
"import * as os from 'os';\n"
|
||||
"globalThis.std = std;\n"
|
||||
"globalThis.os = os;\n";
|
||||
JSValue std_val = JS_Eval(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
if (!JS_IsException(std_val)) {
|
||||
js_module_set_import_meta(ctx, std_val, 1, 1);
|
||||
std_val = JS_EvalFunction(ctx, std_val);
|
||||
} else {
|
||||
js_std_dump_error(ctx);
|
||||
}
|
||||
std_val = js_std_await(ctx, std_val);
|
||||
JS_FreeValue(ctx, std_val);
|
||||
}
|
22
fuzz/fuzz_common.h
Normal file
22
fuzz/fuzz_common.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* Copyright 2020 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "quickjs.h"
|
||||
#include "quickjs-libc.h"
|
||||
|
||||
static int nbinterrupts = 0;
|
||||
|
||||
void reset_nbinterrupts();
|
||||
void test_one_input_init(JSRuntime *rt, JSContext *ctx);
|
93
fuzz/fuzz_compile.c
Normal file
93
fuzz/fuzz_compile.c
Normal file
@ -0,0 +1,93 @@
|
||||
/* Copyright 2020 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "quickjs.h"
|
||||
#include "quickjs-libc.h"
|
||||
#include "cutils.h"
|
||||
#include "fuzz/fuzz_common.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
JSRuntime *rt = JS_NewRuntime();
|
||||
JSContext *ctx = JS_NewContext(rt);
|
||||
test_one_input_init(rt, ctx);
|
||||
|
||||
uint8_t *null_terminated_data = malloc(size + 1);
|
||||
memcpy(null_terminated_data, data, size);
|
||||
null_terminated_data[size] = 0;
|
||||
|
||||
JSValue obj = JS_Eval(ctx, (const char *)null_terminated_data, size, "<none>", JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_MODULE);
|
||||
free(null_terminated_data);
|
||||
//TODO target with JS_ParseJSON
|
||||
if (JS_IsException(obj)) {
|
||||
js_std_free_handlers(rt);
|
||||
JS_FreeValue(ctx, obj);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
obj = js_std_await(ctx, obj);
|
||||
size_t bytecode_size;
|
||||
uint8_t* bytecode = JS_WriteObject(ctx, &bytecode_size, obj, JS_WRITE_OBJ_BYTECODE);
|
||||
JS_FreeValue(ctx, obj);
|
||||
if (!bytecode) {
|
||||
js_std_free_handlers(rt);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
obj = JS_ReadObject(ctx, bytecode, bytecode_size, JS_READ_OBJ_BYTECODE);
|
||||
js_free(ctx, bytecode);
|
||||
if (JS_IsException(obj)) {
|
||||
js_std_free_handlers(rt);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
reset_nbinterrupts();
|
||||
/* this is based on
|
||||
* js_std_eval_binary(ctx, bytecode, bytecode_size, 0);
|
||||
* modified so as not to exit on JS exception
|
||||
*/
|
||||
JSValue val;
|
||||
if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
|
||||
if (JS_ResolveModule(ctx, obj) < 0) {
|
||||
JS_FreeValue(ctx, obj);
|
||||
js_std_free_handlers(rt);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
||||
js_module_set_import_meta(ctx, obj, FALSE, TRUE);
|
||||
}
|
||||
val = JS_EvalFunction(ctx, obj);
|
||||
if (JS_IsException(val)) {
|
||||
js_std_dump_error(ctx);
|
||||
} else {
|
||||
js_std_loop(ctx);
|
||||
}
|
||||
JS_FreeValue(ctx, val);
|
||||
js_std_free_handlers(rt);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
|
||||
return 0;
|
||||
}
|
49
fuzz/fuzz_eval.c
Normal file
49
fuzz/fuzz_eval.c
Normal file
@ -0,0 +1,49 @@
|
||||
/* Copyright 2020 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "quickjs.h"
|
||||
#include "quickjs-libc.h"
|
||||
#include "fuzz/fuzz_common.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
JSRuntime *rt = JS_NewRuntime();
|
||||
JSContext *ctx = JS_NewContext(rt);
|
||||
test_one_input_init(rt, ctx);
|
||||
|
||||
uint8_t *null_terminated_data = malloc(size + 1);
|
||||
memcpy(null_terminated_data, data, size);
|
||||
null_terminated_data[size] = 0;
|
||||
|
||||
reset_nbinterrupts();
|
||||
//the final 0 does not count (as in strlen)
|
||||
JSValue val = JS_Eval(ctx, (const char *)null_terminated_data, size, "<none>", JS_EVAL_TYPE_GLOBAL);
|
||||
free(null_terminated_data);
|
||||
//TODO targets with JS_ParseJSON, JS_ReadObject
|
||||
if (!JS_IsException(val)) {
|
||||
js_std_loop(ctx);
|
||||
JS_FreeValue(ctx, val);
|
||||
}
|
||||
js_std_free_handlers(rt);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
return 0;
|
||||
}
|
66
fuzz/fuzz_regexp.c
Normal file
66
fuzz/fuzz_regexp.c
Normal file
@ -0,0 +1,66 @@
|
||||
/* Copyright 2020 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "libregexp.h"
|
||||
#include "quickjs-libc.h"
|
||||
|
||||
static int nbinterrupts = 0;
|
||||
|
||||
int lre_check_stack_overflow(void *opaque, size_t alloca_size) { return 0; }
|
||||
|
||||
void *lre_realloc(void *opaque, void *ptr, size_t size)
|
||||
{
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
int lre_check_timeout(void *opaque)
|
||||
{
|
||||
nbinterrupts++;
|
||||
return (nbinterrupts > 100);
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
int len, ret, i;
|
||||
uint8_t *bc;
|
||||
char error_msg[64];
|
||||
const uint8_t *input;
|
||||
uint8_t *capture[255 * 2];
|
||||
size_t size1 = size;
|
||||
|
||||
//Splits buffer into 2 sub buffers delimited by null character
|
||||
for (i = 0; i < size; i++) {
|
||||
if (data[i] == 0) {
|
||||
size1 = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (size1 == size) {
|
||||
//missing delimiter
|
||||
return 0;
|
||||
}
|
||||
bc = lre_compile(&len, error_msg, sizeof(error_msg), (const char *) data,
|
||||
size1, 0, NULL);
|
||||
if (!bc) {
|
||||
return 0;
|
||||
}
|
||||
input = data + size1 + 1;
|
||||
ret = lre_exec(capture, bc, input, 0, size - (size1 + 1), 0, NULL);
|
||||
if (ret == 1) {
|
||||
lre_get_capture_count(bc);
|
||||
}
|
||||
free(bc);
|
||||
|
||||
return 0;
|
||||
}
|
24
fuzz/generate_dict.js
Normal file
24
fuzz/generate_dict.js
Normal file
@ -0,0 +1,24 @@
|
||||
// Function to recursively iterate through built-in names.
|
||||
function collectBuiltinNames(obj, visited = new Set(), result = new Set()) {
|
||||
// Check if the object has already been visited to avoid infinite recursion.
|
||||
if (visited.has(obj))
|
||||
return;
|
||||
|
||||
// Add the current object to the set of visited objects
|
||||
visited.add(obj);
|
||||
// Get the property names of the current object
|
||||
const properties = Object.getOwnPropertyNames(obj);
|
||||
// Iterate through each property
|
||||
for (var i=0; i < properties.length; i++) {
|
||||
var property = properties[i];
|
||||
if (property != "collectBuiltinNames" && typeof property != "number")
|
||||
result.add(property);
|
||||
// Check if the property is an object and if so, recursively iterate through its properties.
|
||||
if (typeof obj[property] === 'object' && obj[property] !== null)
|
||||
collectBuiltinNames(obj[property], visited, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Start the recursive iteration with the global object.
|
||||
console.log(Array.from(collectBuiltinNames(this)).join('\n'));
|
535
libbf.h
535
libbf.h
@ -1,535 +0,0 @@
|
||||
/*
|
||||
* Tiny arbitrary precision floating point library
|
||||
*
|
||||
* Copyright (c) 2017-2021 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBBF_H
|
||||
#define LIBBF_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX)
|
||||
#define LIMB_LOG2_BITS 6
|
||||
#else
|
||||
#define LIMB_LOG2_BITS 5
|
||||
#endif
|
||||
|
||||
#define LIMB_BITS (1 << LIMB_LOG2_BITS)
|
||||
|
||||
#if LIMB_BITS == 64
|
||||
typedef __int128 int128_t;
|
||||
typedef unsigned __int128 uint128_t;
|
||||
typedef int64_t slimb_t;
|
||||
typedef uint64_t limb_t;
|
||||
typedef uint128_t dlimb_t;
|
||||
#define BF_RAW_EXP_MIN INT64_MIN
|
||||
#define BF_RAW_EXP_MAX INT64_MAX
|
||||
|
||||
#define LIMB_DIGITS 19
|
||||
#define BF_DEC_BASE UINT64_C(10000000000000000000)
|
||||
|
||||
#else
|
||||
|
||||
typedef int32_t slimb_t;
|
||||
typedef uint32_t limb_t;
|
||||
typedef uint64_t dlimb_t;
|
||||
#define BF_RAW_EXP_MIN INT32_MIN
|
||||
#define BF_RAW_EXP_MAX INT32_MAX
|
||||
|
||||
#define LIMB_DIGITS 9
|
||||
#define BF_DEC_BASE 1000000000U
|
||||
|
||||
#endif
|
||||
|
||||
/* in bits */
|
||||
/* minimum number of bits for the exponent */
|
||||
#define BF_EXP_BITS_MIN 3
|
||||
/* maximum number of bits for the exponent */
|
||||
#define BF_EXP_BITS_MAX (LIMB_BITS - 3)
|
||||
/* extended range for exponent, used internally */
|
||||
#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)
|
||||
/* minimum possible precision */
|
||||
#define BF_PREC_MIN 2
|
||||
/* minimum possible precision */
|
||||
#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)
|
||||
/* some operations support infinite precision */
|
||||
#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */
|
||||
|
||||
#if LIMB_BITS == 64
|
||||
#define BF_CHKSUM_MOD (UINT64_C(975620677) * UINT64_C(9795002197))
|
||||
#else
|
||||
#define BF_CHKSUM_MOD 975620677U
|
||||
#endif
|
||||
|
||||
#define BF_EXP_ZERO BF_RAW_EXP_MIN
|
||||
#define BF_EXP_INF (BF_RAW_EXP_MAX - 1)
|
||||
#define BF_EXP_NAN BF_RAW_EXP_MAX
|
||||
|
||||
/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,
|
||||
+/-infinity is represented with expn = BF_EXP_INF and len = 0,
|
||||
NaN is represented with expn = BF_EXP_NAN and len = 0 (sign is ignored)
|
||||
*/
|
||||
typedef struct {
|
||||
struct bf_context_t *ctx;
|
||||
int sign;
|
||||
slimb_t expn;
|
||||
limb_t len;
|
||||
limb_t *tab;
|
||||
} bf_t;
|
||||
|
||||
typedef struct {
|
||||
/* must be kept identical to bf_t */
|
||||
struct bf_context_t *ctx;
|
||||
int sign;
|
||||
slimb_t expn;
|
||||
limb_t len;
|
||||
limb_t *tab;
|
||||
} bfdec_t;
|
||||
|
||||
typedef enum {
|
||||
BF_RNDN, /* round to nearest, ties to even */
|
||||
BF_RNDZ, /* round to zero */
|
||||
BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */
|
||||
BF_RNDU, /* round to +inf */
|
||||
BF_RNDNA, /* round to nearest, ties away from zero */
|
||||
BF_RNDA, /* round away from zero */
|
||||
BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,
|
||||
inexact flag is always set) */
|
||||
} bf_rnd_t;
|
||||
|
||||
/* allow subnormal numbers. Only available if the number of exponent
|
||||
bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */
|
||||
#define BF_FLAG_SUBNORMAL (1 << 3)
|
||||
/* 'prec' is the precision after the radix point instead of the whole
|
||||
mantissa. Can only be used with bf_round() and
|
||||
bfdec_[add|sub|mul|div|sqrt|round](). */
|
||||
#define BF_FLAG_RADPNT_PREC (1 << 4)
|
||||
|
||||
#define BF_RND_MASK 0x7
|
||||
#define BF_EXP_BITS_SHIFT 5
|
||||
#define BF_EXP_BITS_MASK 0x3f
|
||||
|
||||
/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */
|
||||
#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)
|
||||
|
||||
/* contains the rounding mode and number of exponents bits */
|
||||
typedef uint32_t bf_flags_t;
|
||||
|
||||
typedef void *bf_realloc_func_t(void *opaque, void *ptr, size_t size);
|
||||
|
||||
typedef struct {
|
||||
bf_t val;
|
||||
limb_t prec;
|
||||
} BFConstCache;
|
||||
|
||||
typedef struct bf_context_t {
|
||||
void *realloc_opaque;
|
||||
bf_realloc_func_t *realloc_func;
|
||||
BFConstCache log2_cache;
|
||||
BFConstCache pi_cache;
|
||||
struct BFNTTState *ntt_state;
|
||||
} bf_context_t;
|
||||
|
||||
static inline int bf_get_exp_bits(bf_flags_t flags)
|
||||
{
|
||||
int e;
|
||||
e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;
|
||||
if (e == BF_EXP_BITS_MASK)
|
||||
return BF_EXP_BITS_MAX + 1;
|
||||
else
|
||||
return BF_EXP_BITS_MAX - e;
|
||||
}
|
||||
|
||||
static inline bf_flags_t bf_set_exp_bits(int n)
|
||||
{
|
||||
return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;
|
||||
}
|
||||
|
||||
/* returned status */
|
||||
#define BF_ST_INVALID_OP (1 << 0)
|
||||
#define BF_ST_DIVIDE_ZERO (1 << 1)
|
||||
#define BF_ST_OVERFLOW (1 << 2)
|
||||
#define BF_ST_UNDERFLOW (1 << 3)
|
||||
#define BF_ST_INEXACT (1 << 4)
|
||||
/* indicate that a memory allocation error occured. NaN is returned */
|
||||
#define BF_ST_MEM_ERROR (1 << 5)
|
||||
|
||||
#define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */
|
||||
|
||||
static inline slimb_t bf_max(slimb_t a, slimb_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline slimb_t bf_min(slimb_t a, slimb_t b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func,
|
||||
void *realloc_opaque);
|
||||
void bf_context_end(bf_context_t *s);
|
||||
/* free memory allocated for the bf cache data */
|
||||
void bf_clear_cache(bf_context_t *s);
|
||||
|
||||
static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size)
|
||||
{
|
||||
return s->realloc_func(s->realloc_opaque, ptr, size);
|
||||
}
|
||||
|
||||
/* 'size' must be != 0 */
|
||||
static inline void *bf_malloc(bf_context_t *s, size_t size)
|
||||
{
|
||||
return bf_realloc(s, NULL, size);
|
||||
}
|
||||
|
||||
static inline void bf_free(bf_context_t *s, void *ptr)
|
||||
{
|
||||
/* must test ptr otherwise equivalent to malloc(0) */
|
||||
if (ptr)
|
||||
bf_realloc(s, ptr, 0);
|
||||
}
|
||||
|
||||
void bf_init(bf_context_t *s, bf_t *r);
|
||||
|
||||
static inline void bf_delete(bf_t *r)
|
||||
{
|
||||
bf_context_t *s = r->ctx;
|
||||
/* we accept to delete a zeroed bf_t structure */
|
||||
if (s && r->tab) {
|
||||
bf_realloc(s, r->tab, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bf_neg(bf_t *r)
|
||||
{
|
||||
r->sign ^= 1;
|
||||
}
|
||||
|
||||
static inline int bf_is_finite(const bf_t *a)
|
||||
{
|
||||
return (a->expn < BF_EXP_INF);
|
||||
}
|
||||
|
||||
static inline int bf_is_nan(const bf_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_NAN);
|
||||
}
|
||||
|
||||
static inline int bf_is_zero(const bf_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_ZERO);
|
||||
}
|
||||
|
||||
static inline void bf_memcpy(bf_t *r, const bf_t *a)
|
||||
{
|
||||
*r = *a;
|
||||
}
|
||||
|
||||
int bf_set_ui(bf_t *r, uint64_t a);
|
||||
int bf_set_si(bf_t *r, int64_t a);
|
||||
void bf_set_nan(bf_t *r);
|
||||
void bf_set_zero(bf_t *r, int is_neg);
|
||||
void bf_set_inf(bf_t *r, int is_neg);
|
||||
int bf_set(bf_t *r, const bf_t *a);
|
||||
void bf_move(bf_t *r, bf_t *a);
|
||||
int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode);
|
||||
int bf_set_float64(bf_t *a, double d);
|
||||
|
||||
int bf_cmpu(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp_full(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp(const bf_t *a, const bf_t *b);
|
||||
static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
static inline int bf_cmp_le(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) <= 0;
|
||||
}
|
||||
|
||||
static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);
|
||||
int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags);
|
||||
int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags);
|
||||
int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
#define BF_DIVREM_EUCLIDIAN BF_RNDF
|
||||
int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
|
||||
limb_t prec, bf_flags_t flags, int rnd_mode);
|
||||
int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
/* round to integer with infinite precision */
|
||||
int bf_rint(bf_t *r, int rnd_mode);
|
||||
int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);
|
||||
int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a);
|
||||
int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
slimb_t bf_get_exp_min(const bf_t *a);
|
||||
int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
|
||||
/* additional flags for bf_atof */
|
||||
/* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */
|
||||
#define BF_ATOF_NO_HEX (1 << 16)
|
||||
/* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */
|
||||
#define BF_ATOF_BIN_OCT (1 << 17)
|
||||
/* Do not parse NaN or Inf */
|
||||
#define BF_ATOF_NO_NAN_INF (1 << 18)
|
||||
/* return the exponent separately */
|
||||
#define BF_ATOF_EXPONENT (1 << 19)
|
||||
|
||||
int bf_atof(bf_t *a, const char *str, const char **pnext, int radix,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
/* this version accepts prec = BF_PREC_INF and returns the radix
|
||||
exponent */
|
||||
int bf_atof2(bf_t *r, slimb_t *pexponent,
|
||||
const char *str, const char **pnext, int radix,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
|
||||
slimb_t expn, limb_t prec, bf_flags_t flags);
|
||||
|
||||
|
||||
/* Conversion of floating point number to string. Return a null
|
||||
terminated string or NULL if memory error. *plen contains its
|
||||
length if plen != NULL. The exponent letter is "e" for base 10,
|
||||
"p" for bases 2, 8, 16 with a binary exponent and "@" for the other
|
||||
bases. */
|
||||
|
||||
#define BF_FTOA_FORMAT_MASK (3 << 16)
|
||||
|
||||
/* fixed format: prec significant digits rounded with (flags &
|
||||
BF_RND_MASK). Exponential notation is used if too many zeros are
|
||||
needed.*/
|
||||
#define BF_FTOA_FORMAT_FIXED (0 << 16)
|
||||
/* fractional format: prec digits after the decimal point rounded with
|
||||
(flags & BF_RND_MASK) */
|
||||
#define BF_FTOA_FORMAT_FRAC (1 << 16)
|
||||
/* free format:
|
||||
|
||||
For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum
|
||||
number of digits to represent 'a'. The precision and the rounding
|
||||
mode are ignored.
|
||||
|
||||
For the non binary radices with bf_ftoa(): use as many digits as
|
||||
necessary so that bf_atof() return the same number when using
|
||||
precision 'prec', rounding to nearest and the subnormal
|
||||
configuration of 'flags'. The result is meaningful only if 'a' is
|
||||
already rounded to 'prec' bits. If the subnormal flag is set, the
|
||||
exponent in 'flags' must also be set to the desired exponent range.
|
||||
*/
|
||||
#define BF_FTOA_FORMAT_FREE (2 << 16)
|
||||
/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits
|
||||
(takes more computation time). Identical to BF_FTOA_FORMAT_FREE for
|
||||
binary radices with bf_ftoa() and for bfdec_ftoa(). */
|
||||
#define BF_FTOA_FORMAT_FREE_MIN (3 << 16)
|
||||
|
||||
/* force exponential notation for fixed or free format */
|
||||
#define BF_FTOA_FORCE_EXP (1 << 20)
|
||||
/* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for
|
||||
base 2 if non zero value */
|
||||
#define BF_FTOA_ADD_PREFIX (1 << 21)
|
||||
/* return "Infinity" instead of "Inf" and add a "+" for positive
|
||||
exponents */
|
||||
#define BF_FTOA_JS_QUIRKS (1 << 22)
|
||||
|
||||
char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
|
||||
/* modulo 2^n instead of saturation. NaN and infinity return 0 */
|
||||
#define BF_GET_INT_MOD (1 << 0)
|
||||
int bf_get_int32(int *pres, const bf_t *a, int flags);
|
||||
int bf_get_int64(int64_t *pres, const bf_t *a, int flags);
|
||||
int bf_get_uint64(uint64_t *pres, const bf_t *a);
|
||||
|
||||
/* the following functions are exported for testing only. */
|
||||
void mp_print_str(const char *str, const limb_t *tab, limb_t n);
|
||||
void bf_print_str(const char *str, const bf_t *a);
|
||||
int bf_resize(bf_t *r, limb_t len);
|
||||
int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len);
|
||||
int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags);
|
||||
int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k);
|
||||
slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,
|
||||
int is_ceil1);
|
||||
int mp_mul(bf_context_t *s, limb_t *result,
|
||||
const limb_t *op1, limb_t op1_size,
|
||||
const limb_t *op2, limb_t op2_size);
|
||||
limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2,
|
||||
limb_t n, limb_t carry);
|
||||
limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n);
|
||||
int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n);
|
||||
int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n);
|
||||
limb_t bf_isqrt(limb_t a);
|
||||
|
||||
/* transcendental functions */
|
||||
int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags);
|
||||
int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);
|
||||
int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */
|
||||
int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);
|
||||
int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
|
||||
/* decimal floating point */
|
||||
|
||||
static inline void bfdec_init(bf_context_t *s, bfdec_t *r)
|
||||
{
|
||||
bf_init(s, (bf_t *)r);
|
||||
}
|
||||
static inline void bfdec_delete(bfdec_t *r)
|
||||
{
|
||||
bf_delete((bf_t *)r);
|
||||
}
|
||||
|
||||
static inline void bfdec_neg(bfdec_t *r)
|
||||
{
|
||||
r->sign ^= 1;
|
||||
}
|
||||
|
||||
static inline int bfdec_is_finite(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn < BF_EXP_INF);
|
||||
}
|
||||
|
||||
static inline int bfdec_is_nan(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_NAN);
|
||||
}
|
||||
|
||||
static inline int bfdec_is_zero(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_ZERO);
|
||||
}
|
||||
|
||||
static inline void bfdec_memcpy(bfdec_t *r, const bfdec_t *a)
|
||||
{
|
||||
bf_memcpy((bf_t *)r, (const bf_t *)a);
|
||||
}
|
||||
|
||||
int bfdec_set_ui(bfdec_t *r, uint64_t a);
|
||||
int bfdec_set_si(bfdec_t *r, int64_t a);
|
||||
|
||||
static inline void bfdec_set_nan(bfdec_t *r)
|
||||
{
|
||||
bf_set_nan((bf_t *)r);
|
||||
}
|
||||
static inline void bfdec_set_zero(bfdec_t *r, int is_neg)
|
||||
{
|
||||
bf_set_zero((bf_t *)r, is_neg);
|
||||
}
|
||||
static inline void bfdec_set_inf(bfdec_t *r, int is_neg)
|
||||
{
|
||||
bf_set_inf((bf_t *)r, is_neg);
|
||||
}
|
||||
static inline int bfdec_set(bfdec_t *r, const bfdec_t *a)
|
||||
{
|
||||
return bf_set((bf_t *)r, (bf_t *)a);
|
||||
}
|
||||
static inline void bfdec_move(bfdec_t *r, bfdec_t *a)
|
||||
{
|
||||
bf_move((bf_t *)r, (bf_t *)a);
|
||||
}
|
||||
static inline int bfdec_cmpu(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmpu((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmp_full((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmp((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) == 0;
|
||||
}
|
||||
static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) <= 0;
|
||||
}
|
||||
static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
|
||||
limb_t prec, bf_flags_t flags, int rnd_mode);
|
||||
int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
int bfdec_rint(bfdec_t *r, int rnd_mode);
|
||||
int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_get_int32(int *pres, const bfdec_t *a);
|
||||
int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b);
|
||||
|
||||
char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
|
||||
/* the following functions are exported for testing only. */
|
||||
extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];
|
||||
void bfdec_print_str(const char *str, const bfdec_t *a);
|
||||
static inline int bfdec_resize(bfdec_t *r, limb_t len)
|
||||
{
|
||||
return bf_resize((bf_t *)r, len);
|
||||
}
|
||||
int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags);
|
||||
|
||||
#endif /* LIBBF_H */
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Regular Expression Engine
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
450
libregexp.c
450
libregexp.c
File diff suppressed because it is too large
Load Diff
53
libregexp.h
53
libregexp.h
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Regular Expression Engine
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -25,21 +25,20 @@
|
||||
#define LIBREGEXP_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "libunicode.h"
|
||||
|
||||
#define LRE_BOOL int /* for documentation purposes */
|
||||
#include <stdint.h>
|
||||
|
||||
#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_UNICODE (1 << 4)
|
||||
#define LRE_FLAG_STICKY (1 << 5)
|
||||
#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */
|
||||
|
||||
#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
|
||||
|
||||
#define LRE_RET_MEMORY_ERROR (-1)
|
||||
#define LRE_RET_TIMEOUT (-2)
|
||||
|
||||
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);
|
||||
@ -51,43 +50,11 @@ int lre_exec(uint8_t **capture,
|
||||
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);
|
||||
/* must be provided by the user, return non zero if overflow */
|
||||
int lre_check_stack_overflow(void *opaque, size_t alloca_size);
|
||||
/* must be provided by the user, return non zero if time out */
|
||||
int lre_check_timeout(void *opaque);
|
||||
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 */
|
||||
|
3466
libunicode-table.h
3466
libunicode-table.h
File diff suppressed because it is too large
Load Diff
582
libunicode.c
582
libunicode.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Unicode utilities
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -149,9 +149,9 @@ static int lre_case_conv_entry(uint32_t *res, uint32_t c, int conv_type, uint32_
|
||||
}
|
||||
|
||||
/* conv_type:
|
||||
0 = to upper
|
||||
0 = to upper
|
||||
1 = to lower
|
||||
2 = case folding (= to lower with modifications)
|
||||
2 = case folding (= to lower with modifications)
|
||||
*/
|
||||
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
|
||||
{
|
||||
@ -168,7 +168,7 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type)
|
||||
} else {
|
||||
uint32_t v, code, len;
|
||||
int idx, idx_min, idx_max;
|
||||
|
||||
|
||||
idx_min = 0;
|
||||
idx_max = countof(case_conv_table1) - 1;
|
||||
while (idx_min <= idx_max) {
|
||||
@ -240,7 +240,7 @@ int lre_canonicalize(uint32_t c, BOOL is_unicode)
|
||||
} else {
|
||||
uint32_t v, code, len;
|
||||
int idx, idx_min, idx_max;
|
||||
|
||||
|
||||
idx_min = 0;
|
||||
idx_max = countof(case_conv_table1) - 1;
|
||||
while (idx_min <= idx_max) {
|
||||
@ -262,11 +262,7 @@ int lre_canonicalize(uint32_t c, BOOL is_unicode)
|
||||
|
||||
static uint32_t get_le24(const uint8_t *ptr)
|
||||
{
|
||||
#if defined(__x86__) || defined(__x86_64__)
|
||||
return *(uint16_t *)ptr | (ptr[2] << 16);
|
||||
#else
|
||||
return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define UNICODE_INDEX_BLOCK_LEN 32
|
||||
@ -311,12 +307,20 @@ static BOOL lre_is_in_table(uint32_t c, const uint8_t *table,
|
||||
uint32_t code, b, bit;
|
||||
int pos;
|
||||
const uint8_t *p;
|
||||
|
||||
|
||||
pos = get_index_pos(&code, c, index_table, index_table_len);
|
||||
if (pos < 0)
|
||||
return FALSE; /* outside the table */
|
||||
p = table + pos;
|
||||
bit = 0;
|
||||
/* Compressed run length encoding:
|
||||
00..3F: 2 packed lengths: 3-bit + 3-bit
|
||||
40..5F: 5-bits plus extra byte for length
|
||||
60..7F: 5-bits plus 2 extra bytes for length
|
||||
80..FF: 7-bit length
|
||||
lengths must be incremented to get character count
|
||||
Ranges alternate between false and true return value.
|
||||
*/
|
||||
for(;;) {
|
||||
b = *p++;
|
||||
if (b < 64) {
|
||||
@ -344,7 +348,7 @@ BOOL lre_is_cased(uint32_t c)
|
||||
{
|
||||
uint32_t v, code, len;
|
||||
int idx, idx_min, idx_max;
|
||||
|
||||
|
||||
idx_min = 0;
|
||||
idx_max = countof(case_conv_table1) - 1;
|
||||
while (idx_min <= idx_max) {
|
||||
@ -403,7 +407,7 @@ int cr_realloc(CharRange *cr, int size)
|
||||
{
|
||||
int new_size;
|
||||
uint32_t *new_buf;
|
||||
|
||||
|
||||
if (size > cr->size) {
|
||||
new_size = max_int(size, cr->size * 3 / 2);
|
||||
new_buf = cr->realloc_func(cr->mem_opaque, cr->points,
|
||||
@ -430,7 +434,7 @@ static void cr_compress(CharRange *cr)
|
||||
{
|
||||
int i, j, k, len;
|
||||
uint32_t *pt;
|
||||
|
||||
|
||||
pt = cr->points;
|
||||
len = cr->len;
|
||||
i = 0;
|
||||
@ -460,7 +464,7 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
|
||||
{
|
||||
int a_idx, b_idx, is_in;
|
||||
uint32_t v;
|
||||
|
||||
|
||||
a_idx = 0;
|
||||
b_idx = 0;
|
||||
for(;;) {
|
||||
@ -533,6 +537,207 @@ int cr_invert(CharRange *cr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CASE_U (1 << 0)
|
||||
#define CASE_L (1 << 1)
|
||||
#define CASE_F (1 << 2)
|
||||
|
||||
/* use the case conversion table to generate range of characters.
|
||||
CASE_U: set char if modified by uppercasing,
|
||||
CASE_L: set char if modified by lowercasing,
|
||||
CASE_F: set char if modified by case folding,
|
||||
*/
|
||||
static int unicode_case1(CharRange *cr, int case_mask)
|
||||
{
|
||||
#define MR(x) (1 << RUN_TYPE_ ## x)
|
||||
const uint32_t tab_run_mask[3] = {
|
||||
MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) |
|
||||
MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
|
||||
|
||||
MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2),
|
||||
|
||||
MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
|
||||
};
|
||||
#undef MR
|
||||
uint32_t mask, v, code, type, len, i, idx;
|
||||
|
||||
if (case_mask == 0)
|
||||
return 0;
|
||||
mask = 0;
|
||||
for(i = 0; i < 3; i++) {
|
||||
if ((case_mask >> i) & 1)
|
||||
mask |= tab_run_mask[i];
|
||||
}
|
||||
for(idx = 0; idx < countof(case_conv_table1); idx++) {
|
||||
v = case_conv_table1[idx];
|
||||
type = (v >> (32 - 17 - 7 - 4)) & 0xf;
|
||||
code = v >> (32 - 17);
|
||||
len = (v >> (32 - 17 - 7)) & 0x7f;
|
||||
if ((mask >> type) & 1) {
|
||||
// printf("%d: type=%d %04x %04x\n", idx, type, code, code + len - 1);
|
||||
switch(type) {
|
||||
case RUN_TYPE_UL:
|
||||
if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
|
||||
goto def_case;
|
||||
code += ((case_mask & CASE_U) != 0);
|
||||
for(i = 0; i < len; i += 2) {
|
||||
if (cr_add_interval(cr, code + i, code + i + 1))
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case RUN_TYPE_LSU:
|
||||
if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
|
||||
goto def_case;
|
||||
if (!(case_mask & CASE_U)) {
|
||||
if (cr_add_interval(cr, code, code + 1))
|
||||
return -1;
|
||||
}
|
||||
if (cr_add_interval(cr, code + 1, code + 2))
|
||||
return -1;
|
||||
if (case_mask & CASE_U) {
|
||||
if (cr_add_interval(cr, code + 2, code + 3))
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
def_case:
|
||||
if (cr_add_interval(cr, code, code + len))
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int point_cmp(const void *p1, const void *p2, void *arg)
|
||||
{
|
||||
uint32_t v1 = *(uint32_t *)p1;
|
||||
uint32_t v2 = *(uint32_t *)p2;
|
||||
return (v1 > v2) - (v1 < v2);
|
||||
}
|
||||
|
||||
static void cr_sort_and_remove_overlap(CharRange *cr)
|
||||
{
|
||||
uint32_t start, end, start1, end1, i, j;
|
||||
|
||||
/* the resulting ranges are not necessarily sorted and may overlap */
|
||||
rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL);
|
||||
j = 0;
|
||||
for(i = 0; i < cr->len; ) {
|
||||
start = cr->points[i];
|
||||
end = cr->points[i + 1];
|
||||
i += 2;
|
||||
while (i < cr->len) {
|
||||
start1 = cr->points[i];
|
||||
end1 = cr->points[i + 1];
|
||||
if (start1 > end) {
|
||||
/* |------|
|
||||
* |-------| */
|
||||
break;
|
||||
} else if (end1 <= end) {
|
||||
/* |------|
|
||||
* |--| */
|
||||
i += 2;
|
||||
} else {
|
||||
/* |------|
|
||||
* |-------| */
|
||||
end = end1;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
cr->points[j] = start;
|
||||
cr->points[j + 1] = end;
|
||||
j += 2;
|
||||
}
|
||||
cr->len = j;
|
||||
}
|
||||
|
||||
/* canonicalize a character set using the JS regex case folding rules
|
||||
(see lre_canonicalize()) */
|
||||
int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode)
|
||||
{
|
||||
CharRange cr_inter, cr_mask, cr_result, cr_sub;
|
||||
uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d;
|
||||
|
||||
cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func);
|
||||
cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func);
|
||||
cr_init(&cr_result, cr->mem_opaque, cr->realloc_func);
|
||||
cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func);
|
||||
|
||||
if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U))
|
||||
goto fail;
|
||||
if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
|
||||
goto fail;
|
||||
|
||||
if (cr_invert(&cr_mask))
|
||||
goto fail;
|
||||
if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
|
||||
goto fail;
|
||||
|
||||
/* cr_inter = cr & cr_mask */
|
||||
/* cr_sub = cr & ~cr_mask */
|
||||
|
||||
/* use the case conversion table to compute the result */
|
||||
d_start = -1;
|
||||
d_end = -1;
|
||||
idx = 0;
|
||||
v = case_conv_table1[idx];
|
||||
code = v >> (32 - 17);
|
||||
len = (v >> (32 - 17 - 7)) & 0x7f;
|
||||
for(i = 0; i < cr_inter.len; i += 2) {
|
||||
start = cr_inter.points[i];
|
||||
end = cr_inter.points[i + 1];
|
||||
|
||||
for(c = start; c < end; c++) {
|
||||
for(;;) {
|
||||
if (c >= code && c < code + len)
|
||||
break;
|
||||
idx++;
|
||||
assert(idx < countof(case_conv_table1));
|
||||
v = case_conv_table1[idx];
|
||||
code = v >> (32 - 17);
|
||||
len = (v >> (32 - 17 - 7)) & 0x7f;
|
||||
}
|
||||
d = lre_case_folding_entry(c, idx, v, is_unicode);
|
||||
/* try to merge with the current interval */
|
||||
if (d_start == -1) {
|
||||
d_start = d;
|
||||
d_end = d + 1;
|
||||
} else if (d_end == d) {
|
||||
d_end++;
|
||||
} else {
|
||||
cr_add_interval(&cr_result, d_start, d_end);
|
||||
d_start = d;
|
||||
d_end = d + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d_start != -1) {
|
||||
if (cr_add_interval(&cr_result, d_start, d_end))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* the resulting ranges are not necessarily sorted and may overlap */
|
||||
cr_sort_and_remove_overlap(&cr_result);
|
||||
|
||||
/* or with the character not affected by the case folding */
|
||||
cr->len = 0;
|
||||
if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION))
|
||||
goto fail;
|
||||
|
||||
cr_free(&cr_inter);
|
||||
cr_free(&cr_mask);
|
||||
cr_free(&cr_result);
|
||||
cr_free(&cr_sub);
|
||||
return 0;
|
||||
fail:
|
||||
cr_free(&cr_inter);
|
||||
cr_free(&cr_mask);
|
||||
cr_free(&cr_result);
|
||||
cr_free(&cr_sub);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
|
||||
BOOL lre_is_id_start(uint32_t c)
|
||||
@ -761,7 +966,7 @@ static int unicode_decomp_char(uint32_t *res, uint32_t c, BOOL is_compat1)
|
||||
{
|
||||
uint32_t v, type, is_compat, code, len;
|
||||
int idx_min, idx_max, idx;
|
||||
|
||||
|
||||
idx_min = 0;
|
||||
idx_max = countof(unicode_decomp_table1) - 1;
|
||||
while (idx_min <= idx_max) {
|
||||
@ -791,7 +996,7 @@ static int unicode_compose_pair(uint32_t c0, uint32_t c1)
|
||||
uint32_t code, len, type, v, idx1, d_idx, d_offset, ch;
|
||||
int idx_min, idx_max, idx, d;
|
||||
uint32_t pair[2];
|
||||
|
||||
|
||||
idx_min = 0;
|
||||
idx_max = countof(unicode_comp_table) - 1;
|
||||
while (idx_min <= idx_max) {
|
||||
@ -827,12 +1032,19 @@ static int unicode_get_cc(uint32_t c)
|
||||
uint32_t code, n, type, cc, c1, b;
|
||||
int pos;
|
||||
const uint8_t *p;
|
||||
|
||||
|
||||
pos = get_index_pos(&code, c,
|
||||
unicode_cc_index, sizeof(unicode_cc_index) / 3);
|
||||
if (pos < 0)
|
||||
return 0;
|
||||
p = unicode_cc_table + pos;
|
||||
/* Compressed run length encoding:
|
||||
- 2 high order bits are combining class type
|
||||
- 0:0, 1:230, 2:extra byte linear progression, 3:extra byte
|
||||
- 00..2F: range length (add 1)
|
||||
- 30..37: 3-bit range-length + 1 extra byte
|
||||
- 38..3F: 3-bit range-length + 2 extra byte
|
||||
*/
|
||||
for(;;) {
|
||||
b = *p++;
|
||||
type = b >> 6;
|
||||
@ -876,7 +1088,7 @@ static int unicode_get_cc(uint32_t c)
|
||||
static void sort_cc(int *buf, int len)
|
||||
{
|
||||
int i, j, k, cc, cc1, start, ch1;
|
||||
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
cc = unicode_get_cc(buf[i]);
|
||||
if (cc != 0) {
|
||||
@ -915,7 +1127,7 @@ static void to_nfd_rec(DynBuf *dbuf,
|
||||
uint32_t c, v;
|
||||
int i, l;
|
||||
uint32_t res[UNICODE_DECOMP_LEN_MAX];
|
||||
|
||||
|
||||
for(i = 0; i < src_len; i++) {
|
||||
c = src[i];
|
||||
if (c >= 0xac00 && c < 0xd7a4) {
|
||||
@ -960,7 +1172,7 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
|
||||
int *buf, buf_len, i, p, starter_pos, cc, last_cc, out_len;
|
||||
BOOL is_compat;
|
||||
DynBuf dbuf_s, *dbuf = &dbuf_s;
|
||||
|
||||
|
||||
is_compat = n_type >> 1;
|
||||
|
||||
dbuf_init2(dbuf, opaque, realloc_func);
|
||||
@ -988,15 +1200,15 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
|
||||
}
|
||||
buf = (int *)dbuf->buf;
|
||||
buf_len = dbuf->size / sizeof(int);
|
||||
|
||||
|
||||
sort_cc(buf, buf_len);
|
||||
|
||||
|
||||
if (buf_len <= 1 || (n_type & 1) != 0) {
|
||||
/* NFD / NFKD */
|
||||
*pdst = (uint32_t *)buf;
|
||||
return buf_len;
|
||||
}
|
||||
|
||||
|
||||
i = 1;
|
||||
out_len = 1;
|
||||
while (i < buf_len) {
|
||||
@ -1033,7 +1245,7 @@ static int unicode_find_name(const char *name_table, const char *name)
|
||||
const char *p, *r;
|
||||
int pos;
|
||||
size_t name_len, len;
|
||||
|
||||
|
||||
p = name_table;
|
||||
pos = 0;
|
||||
name_len = strlen(name);
|
||||
@ -1066,13 +1278,13 @@ int unicode_script(CharRange *cr,
|
||||
CharRange cr1_s, *cr1;
|
||||
CharRange cr2_s, *cr2 = &cr2_s;
|
||||
BOOL is_common;
|
||||
|
||||
|
||||
script_idx = unicode_find_name(unicode_script_name_table, script_name);
|
||||
if (script_idx < 0)
|
||||
return -2;
|
||||
/* Note: we remove the "Unknown" Script */
|
||||
script_idx += UNICODE_SCRIPT_Unknown + 1;
|
||||
|
||||
|
||||
is_common = (script_idx == UNICODE_SCRIPT_Common ||
|
||||
script_idx == UNICODE_SCRIPT_Inherited);
|
||||
if (is_ext) {
|
||||
@ -1185,6 +1397,15 @@ static int unicode_general_category1(CharRange *cr, uint32_t gc_mask)
|
||||
p = unicode_gc_table;
|
||||
p_end = unicode_gc_table + countof(unicode_gc_table);
|
||||
c = 0;
|
||||
/* Compressed range encoding:
|
||||
initial byte:
|
||||
bits 0..4: category number (special case 31)
|
||||
bits 5..7: range length (add 1)
|
||||
special case bits 5..7 == 7: read an extra byte
|
||||
- 00..7F: range length (add 7 + 1)
|
||||
- 80..BF: 6-bits plus extra byte for range length (add 7 + 128)
|
||||
- C0..FF: 6-bits plus 2 extra bytes for range length (add 7 + 128 + 16384)
|
||||
*/
|
||||
while (p < p_end) {
|
||||
b = *p++;
|
||||
n = b >> 5;
|
||||
@ -1238,6 +1459,14 @@ static int unicode_prop1(CharRange *cr, int prop_idx)
|
||||
p_end = p + unicode_prop_len_table[prop_idx];
|
||||
c = 0;
|
||||
bit = 0;
|
||||
/* Compressed range encoding:
|
||||
00..3F: 2 packed lengths: 3-bit + 3-bit
|
||||
40..5F: 5-bits plus extra byte for length
|
||||
60..7F: 5-bits plus 2 extra bytes for length
|
||||
80..FF: 7-bit length
|
||||
lengths must be incremented to get character count
|
||||
Ranges alternate between false and true return value.
|
||||
*/
|
||||
while (p < p_end) {
|
||||
c0 = c;
|
||||
b = *p++;
|
||||
@ -1268,207 +1497,6 @@ static int unicode_prop1(CharRange *cr, int prop_idx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CASE_U (1 << 0)
|
||||
#define CASE_L (1 << 1)
|
||||
#define CASE_F (1 << 2)
|
||||
|
||||
/* use the case conversion table to generate range of characters.
|
||||
CASE_U: set char if modified by uppercasing,
|
||||
CASE_L: set char if modified by lowercasing,
|
||||
CASE_F: set char if modified by case folding,
|
||||
*/
|
||||
static int unicode_case1(CharRange *cr, int case_mask)
|
||||
{
|
||||
#define MR(x) (1 << RUN_TYPE_ ## x)
|
||||
const uint32_t tab_run_mask[3] = {
|
||||
MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) |
|
||||
MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
|
||||
|
||||
MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2),
|
||||
|
||||
MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3),
|
||||
};
|
||||
#undef MR
|
||||
uint32_t mask, v, code, type, len, i, idx;
|
||||
|
||||
if (case_mask == 0)
|
||||
return 0;
|
||||
mask = 0;
|
||||
for(i = 0; i < 3; i++) {
|
||||
if ((case_mask >> i) & 1)
|
||||
mask |= tab_run_mask[i];
|
||||
}
|
||||
for(idx = 0; idx < countof(case_conv_table1); idx++) {
|
||||
v = case_conv_table1[idx];
|
||||
type = (v >> (32 - 17 - 7 - 4)) & 0xf;
|
||||
code = v >> (32 - 17);
|
||||
len = (v >> (32 - 17 - 7)) & 0x7f;
|
||||
if ((mask >> type) & 1) {
|
||||
// printf("%d: type=%d %04x %04x\n", idx, type, code, code + len - 1);
|
||||
switch(type) {
|
||||
case RUN_TYPE_UL:
|
||||
if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
|
||||
goto def_case;
|
||||
code += ((case_mask & CASE_U) != 0);
|
||||
for(i = 0; i < len; i += 2) {
|
||||
if (cr_add_interval(cr, code + i, code + i + 1))
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case RUN_TYPE_LSU:
|
||||
if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))
|
||||
goto def_case;
|
||||
if (!(case_mask & CASE_U)) {
|
||||
if (cr_add_interval(cr, code, code + 1))
|
||||
return -1;
|
||||
}
|
||||
if (cr_add_interval(cr, code + 1, code + 2))
|
||||
return -1;
|
||||
if (case_mask & CASE_U) {
|
||||
if (cr_add_interval(cr, code + 2, code + 3))
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
def_case:
|
||||
if (cr_add_interval(cr, code, code + len))
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int point_cmp(const void *p1, const void *p2, void *arg)
|
||||
{
|
||||
uint32_t v1 = *(uint32_t *)p1;
|
||||
uint32_t v2 = *(uint32_t *)p2;
|
||||
return (v1 > v2) - (v1 < v2);
|
||||
}
|
||||
|
||||
static void cr_sort_and_remove_overlap(CharRange *cr)
|
||||
{
|
||||
uint32_t start, end, start1, end1, i, j;
|
||||
|
||||
/* the resulting ranges are not necessarily sorted and may overlap */
|
||||
rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL);
|
||||
j = 0;
|
||||
for(i = 0; i < cr->len; ) {
|
||||
start = cr->points[i];
|
||||
end = cr->points[i + 1];
|
||||
i += 2;
|
||||
while (i < cr->len) {
|
||||
start1 = cr->points[i];
|
||||
end1 = cr->points[i + 1];
|
||||
if (start1 > end) {
|
||||
/* |------|
|
||||
* |-------| */
|
||||
break;
|
||||
} else if (end1 <= end) {
|
||||
/* |------|
|
||||
* |--| */
|
||||
i += 2;
|
||||
} else {
|
||||
/* |------|
|
||||
* |-------| */
|
||||
end = end1;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
cr->points[j] = start;
|
||||
cr->points[j + 1] = end;
|
||||
j += 2;
|
||||
}
|
||||
cr->len = j;
|
||||
}
|
||||
|
||||
/* canonicalize a character set using the JS regex case folding rules
|
||||
(see lre_canonicalize()) */
|
||||
int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode)
|
||||
{
|
||||
CharRange cr_inter, cr_mask, cr_result, cr_sub;
|
||||
uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d;
|
||||
|
||||
cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func);
|
||||
cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func);
|
||||
cr_init(&cr_result, cr->mem_opaque, cr->realloc_func);
|
||||
cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func);
|
||||
|
||||
if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U))
|
||||
goto fail;
|
||||
if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
|
||||
goto fail;
|
||||
|
||||
if (cr_invert(&cr_mask))
|
||||
goto fail;
|
||||
if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))
|
||||
goto fail;
|
||||
|
||||
/* cr_inter = cr & cr_mask */
|
||||
/* cr_sub = cr & ~cr_mask */
|
||||
|
||||
/* use the case conversion table to compute the result */
|
||||
d_start = -1;
|
||||
d_end = -1;
|
||||
idx = 0;
|
||||
v = case_conv_table1[idx];
|
||||
code = v >> (32 - 17);
|
||||
len = (v >> (32 - 17 - 7)) & 0x7f;
|
||||
for(i = 0; i < cr_inter.len; i += 2) {
|
||||
start = cr_inter.points[i];
|
||||
end = cr_inter.points[i + 1];
|
||||
|
||||
for(c = start; c < end; c++) {
|
||||
for(;;) {
|
||||
if (c >= code && c < code + len)
|
||||
break;
|
||||
idx++;
|
||||
assert(idx < countof(case_conv_table1));
|
||||
v = case_conv_table1[idx];
|
||||
code = v >> (32 - 17);
|
||||
len = (v >> (32 - 17 - 7)) & 0x7f;
|
||||
}
|
||||
d = lre_case_folding_entry(c, idx, v, is_unicode);
|
||||
/* try to merge with the current interval */
|
||||
if (d_start == -1) {
|
||||
d_start = d;
|
||||
d_end = d + 1;
|
||||
} else if (d_end == d) {
|
||||
d_end++;
|
||||
} else {
|
||||
cr_add_interval(&cr_result, d_start, d_end);
|
||||
d_start = d;
|
||||
d_end = d + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d_start != -1) {
|
||||
if (cr_add_interval(&cr_result, d_start, d_end))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* the resulting ranges are not necessarily sorted and may overlap */
|
||||
cr_sort_and_remove_overlap(&cr_result);
|
||||
|
||||
/* or with the character not affected by the case folding */
|
||||
cr->len = 0;
|
||||
if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION))
|
||||
goto fail;
|
||||
|
||||
cr_free(&cr_inter);
|
||||
cr_free(&cr_mask);
|
||||
cr_free(&cr_result);
|
||||
cr_free(&cr_sub);
|
||||
return 0;
|
||||
fail:
|
||||
cr_free(&cr_inter);
|
||||
cr_free(&cr_mask);
|
||||
cr_free(&cr_result);
|
||||
cr_free(&cr_sub);
|
||||
return -1;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
POP_GC,
|
||||
POP_PROP,
|
||||
@ -1488,7 +1516,7 @@ static int unicode_prop_ops(CharRange *cr, ...)
|
||||
CharRange stack[POP_STACK_LEN_MAX];
|
||||
int stack_len, op, ret, i;
|
||||
uint32_t a;
|
||||
|
||||
|
||||
va_start(ap, cr);
|
||||
stack_len = 0;
|
||||
for(;;) {
|
||||
@ -1574,7 +1602,7 @@ int unicode_general_category(CharRange *cr, const char *gc_name)
|
||||
{
|
||||
int gc_idx;
|
||||
uint32_t gc_mask;
|
||||
|
||||
|
||||
gc_idx = unicode_find_name(unicode_gc_name_table, gc_name);
|
||||
if (gc_idx < 0)
|
||||
return -2;
|
||||
@ -1592,7 +1620,7 @@ int unicode_general_category(CharRange *cr, const char *gc_name)
|
||||
int unicode_prop(CharRange *cr, const char *prop_name)
|
||||
{
|
||||
int prop_idx, ret;
|
||||
|
||||
|
||||
prop_idx = unicode_find_name(unicode_prop_name_table, prop_name);
|
||||
if (prop_idx < 0)
|
||||
return -2;
|
||||
@ -1786,3 +1814,97 @@ int unicode_prop(CharRange *cr, const char *prop_name)
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ALL_UNICODE */
|
||||
|
||||
/*---- lre codepoint categorizing functions ----*/
|
||||
|
||||
#define S UNICODE_C_SPACE
|
||||
#define D UNICODE_C_DIGIT
|
||||
#define X UNICODE_C_XDIGIT
|
||||
#define U UNICODE_C_UPPER
|
||||
#define L UNICODE_C_LOWER
|
||||
#define _ UNICODE_C_UNDER
|
||||
#define d UNICODE_C_DOLLAR
|
||||
|
||||
uint8_t const lre_ctype_bits[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, S, S, S, S, S, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
S, 0, 0, 0, d, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
X|D, X|D, X|D, X|D, X|D, X|D, X|D, X|D,
|
||||
X|D, X|D, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, X|U, X|U, X|U, X|U, X|U, X|U, U,
|
||||
U, U, U, U, U, U, U, U,
|
||||
U, U, U, U, U, U, U, U,
|
||||
U, U, U, 0, 0, 0, 0, _,
|
||||
|
||||
0, X|L, X|L, X|L, X|L, X|L, X|L, L,
|
||||
L, L, L, L, L, L, L, L,
|
||||
L, L, L, L, L, L, L, L,
|
||||
L, L, L, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
S, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
#undef S
|
||||
#undef D
|
||||
#undef X
|
||||
#undef U
|
||||
#undef L
|
||||
#undef _
|
||||
#undef d
|
||||
|
||||
/* code point ranges for Zs,Zl or Zp property */
|
||||
static const uint16_t char_range_s[] = {
|
||||
10,
|
||||
0x0009, 0x000D + 1,
|
||||
0x0020, 0x0020 + 1,
|
||||
0x00A0, 0x00A0 + 1,
|
||||
0x1680, 0x1680 + 1,
|
||||
0x2000, 0x200A + 1,
|
||||
/* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */
|
||||
/* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */
|
||||
0x2028, 0x2029 + 1,
|
||||
0x202F, 0x202F + 1,
|
||||
0x205F, 0x205F + 1,
|
||||
0x3000, 0x3000 + 1,
|
||||
/* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */
|
||||
0xFEFF, 0xFEFF + 1,
|
||||
};
|
||||
|
||||
BOOL lre_is_space_non_ascii(uint32_t c)
|
||||
{
|
||||
size_t i, n;
|
||||
|
||||
n = countof(char_range_s);
|
||||
for(i = 5; i < n; i += 2) {
|
||||
uint32_t low = char_range_s[i];
|
||||
uint32_t high = char_range_s[i + 1];
|
||||
if (c < low)
|
||||
return FALSE;
|
||||
if (c < high)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
105
libunicode.h
105
libunicode.h
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Unicode utilities
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -24,27 +24,13 @@
|
||||
#ifndef LIBUNICODE_H
|
||||
#define LIBUNICODE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define LRE_BOOL int /* for documentation purposes */
|
||||
#include <stdint.h>
|
||||
|
||||
/* 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);
|
||||
int lre_canonicalize(uint32_t c, BOOL is_unicode);
|
||||
LRE_BOOL lre_is_cased(uint32_t c);
|
||||
LRE_BOOL lre_is_case_ignorable(uint32_t c);
|
||||
|
||||
/* char ranges */
|
||||
|
||||
typedef struct {
|
||||
@ -102,12 +88,14 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
|
||||
|
||||
int cr_invert(CharRange *cr);
|
||||
|
||||
int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode);
|
||||
int cr_regexp_canonicalize(CharRange *cr, int is_unicode);
|
||||
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
|
||||
LRE_BOOL lre_is_id_start(uint32_t c);
|
||||
LRE_BOOL lre_is_id_continue(uint32_t c);
|
||||
typedef enum {
|
||||
UNICODE_NFC,
|
||||
UNICODE_NFD,
|
||||
UNICODE_NFKC,
|
||||
UNICODE_NFKD,
|
||||
} UnicodeNormalizationEnum;
|
||||
|
||||
int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
|
||||
UnicodeNormalizationEnum n_type,
|
||||
@ -115,13 +103,80 @@ int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
|
||||
|
||||
/* Unicode character range functions */
|
||||
|
||||
int unicode_script(CharRange *cr,
|
||||
const char *script_name, LRE_BOOL is_ext);
|
||||
int unicode_script(CharRange *cr, const char *script_name, int 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 */
|
||||
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
|
||||
int lre_canonicalize(uint32_t c, int is_unicode);
|
||||
|
||||
#undef LRE_BOOL
|
||||
/* Code point type categories */
|
||||
enum {
|
||||
UNICODE_C_SPACE = (1 << 0),
|
||||
UNICODE_C_DIGIT = (1 << 1),
|
||||
UNICODE_C_UPPER = (1 << 2),
|
||||
UNICODE_C_LOWER = (1 << 3),
|
||||
UNICODE_C_UNDER = (1 << 4),
|
||||
UNICODE_C_DOLLAR = (1 << 5),
|
||||
UNICODE_C_XDIGIT = (1 << 6),
|
||||
};
|
||||
extern uint8_t const lre_ctype_bits[256];
|
||||
|
||||
/* zero or non-zero return value */
|
||||
int lre_is_cased(uint32_t c);
|
||||
int lre_is_case_ignorable(uint32_t c);
|
||||
int lre_is_id_start(uint32_t c);
|
||||
int lre_is_id_continue(uint32_t c);
|
||||
|
||||
static inline int lre_is_space_byte(uint8_t c) {
|
||||
return lre_ctype_bits[c] & UNICODE_C_SPACE;
|
||||
}
|
||||
|
||||
static inline int lre_is_id_start_byte(uint8_t c) {
|
||||
return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |
|
||||
UNICODE_C_UNDER | UNICODE_C_DOLLAR);
|
||||
}
|
||||
|
||||
static inline int lre_is_id_continue_byte(uint8_t c) {
|
||||
return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |
|
||||
UNICODE_C_UNDER | UNICODE_C_DOLLAR |
|
||||
UNICODE_C_DIGIT);
|
||||
}
|
||||
|
||||
int lre_is_space_non_ascii(uint32_t c);
|
||||
|
||||
static inline int lre_is_space(uint32_t c) {
|
||||
if (c < 256)
|
||||
return lre_is_space_byte(c);
|
||||
else
|
||||
return lre_is_space_non_ascii(c);
|
||||
}
|
||||
|
||||
static inline int lre_js_is_ident_first(uint32_t c) {
|
||||
if (c < 128) {
|
||||
return lre_is_id_start_byte(c);
|
||||
} else {
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
return lre_is_id_start(c);
|
||||
#else
|
||||
return !lre_is_space_non_ascii(c);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static inline int lre_js_is_ident_next(uint32_t c) {
|
||||
if (c < 128) {
|
||||
return lre_is_id_continue_byte(c);
|
||||
} else {
|
||||
/* ZWNJ and ZWJ are accepted in identifiers */
|
||||
if (c >= 0x200C && c <= 0x200D)
|
||||
return TRUE;
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
return lre_is_id_continue(c);
|
||||
#else
|
||||
return !lre_is_space_non_ascii(c);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LIBUNICODE_H */
|
||||
|
4
list.h
4
list.h
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Linux klist like system
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2016-2017 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -45,7 +45,7 @@ static inline void init_list_head(struct list_head *head)
|
||||
}
|
||||
|
||||
/* insert 'el' between 'prev' and 'next' */
|
||||
static inline void __list_add(struct list_head *el,
|
||||
static inline void __list_add(struct list_head *el,
|
||||
struct list_head *prev, struct list_head *next)
|
||||
{
|
||||
prev->next = el;
|
||||
|
124
qjs.c
124
qjs.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* QuickJS stand alone interpreter
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2021 Fabrice Bellard
|
||||
* Copyright (c) 2017-2021 Charlie Gordon
|
||||
*
|
||||
@ -34,8 +34,10 @@
|
||||
#include <time.h>
|
||||
#if defined(__APPLE__)
|
||||
#include <malloc/malloc.h>
|
||||
#elif defined(__linux__)
|
||||
#elif defined(__linux__) || defined(__GLIBC__)
|
||||
#include <malloc.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <malloc_np.h>
|
||||
#endif
|
||||
|
||||
#include "cutils.h"
|
||||
@ -43,11 +45,6 @@
|
||||
|
||||
extern const uint8_t qjsc_repl[];
|
||||
extern const uint32_t qjsc_repl_size;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
extern const uint8_t qjsc_qjscalc[];
|
||||
extern const uint32_t qjsc_qjscalc_size;
|
||||
static int bignum_ext;
|
||||
#endif
|
||||
|
||||
static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
|
||||
const char *filename, int eval_flags)
|
||||
@ -64,6 +61,7 @@ static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
|
||||
js_module_set_import_meta(ctx, val, TRUE, TRUE);
|
||||
val = JS_EvalFunction(ctx, val);
|
||||
}
|
||||
val = js_std_await(ctx, val);
|
||||
} else {
|
||||
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
|
||||
}
|
||||
@ -82,7 +80,7 @@ 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);
|
||||
@ -109,14 +107,6 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt)
|
||||
ctx = JS_NewContext(rt);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (bignum_ext) {
|
||||
JS_AddIntrinsicBigFloat(ctx);
|
||||
JS_AddIntrinsicBigDecimal(ctx);
|
||||
JS_AddIntrinsicOperators(ctx);
|
||||
JS_EnableBignumExt(ctx, TRUE);
|
||||
}
|
||||
#endif
|
||||
/* system modules */
|
||||
js_init_module_std(ctx, "std");
|
||||
js_init_module_os(ctx, "os");
|
||||
@ -148,7 +138,7 @@ static size_t js_trace_malloc_usable_size(const void *ptr)
|
||||
return _msize((void *)ptr);
|
||||
#elif defined(EMSCRIPTEN)
|
||||
return 0;
|
||||
#elif defined(__linux__)
|
||||
#elif defined(__linux__) || defined(__GLIBC__)
|
||||
return malloc_usable_size((void *)ptr);
|
||||
#else
|
||||
/* change this to `return 0;` if compilation fails */
|
||||
@ -267,6 +257,32 @@ static const JSMallocFunctions trace_mf = {
|
||||
js_trace_malloc_usable_size,
|
||||
};
|
||||
|
||||
static size_t get_suffixed_size(const char *str)
|
||||
{
|
||||
char *p;
|
||||
size_t v;
|
||||
v = (size_t)strtod(str, &p);
|
||||
switch(*p) {
|
||||
case 'G':
|
||||
v <<= 30;
|
||||
break;
|
||||
case 'M':
|
||||
v <<= 20;
|
||||
break;
|
||||
case 'k':
|
||||
case 'K':
|
||||
v <<= 10;
|
||||
break;
|
||||
default:
|
||||
if (*p != '\0') {
|
||||
fprintf(stderr, "qjs: invalid suffix: %s\n", p);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
#define PROG_NAME "qjs"
|
||||
|
||||
void help(void)
|
||||
@ -280,15 +296,13 @@ void help(void)
|
||||
" --script load as ES6 script (default=autodetect)\n"
|
||||
"-I --include file include an additional file\n"
|
||||
" --std make 'std' and 'os' available to the loaded script\n"
|
||||
#ifdef CONFIG_BIGNUM
|
||||
" --bignum enable the bignum extensions (BigFloat, BigDecimal)\n"
|
||||
" --qjscalc load the QJSCalc runtime (default if invoked as qjscalc)\n"
|
||||
#endif
|
||||
"-T --trace trace memory allocation\n"
|
||||
"-d --dump dump the memory usage stats\n"
|
||||
" --memory-limit n limit the memory usage to 'n' bytes\n"
|
||||
" --stack-size n limit the stack size to 'n' bytes\n"
|
||||
" --unhandled-rejection dump unhandled promise rejections\n"
|
||||
" --memory-limit n limit the memory usage to 'n' bytes (SI suffixes allowed)\n"
|
||||
" --stack-size n limit the stack size to 'n' bytes (SI suffixes allowed)\n"
|
||||
" --no-unhandled-rejection ignore unhandled promise rejections\n"
|
||||
"-s strip all the debug info\n"
|
||||
" --strip-source strip the source code\n"
|
||||
"-q --quit just instantiate the interpreter and quit\n");
|
||||
exit(1);
|
||||
}
|
||||
@ -306,27 +320,13 @@ int main(int argc, char **argv)
|
||||
int empty_run = 0;
|
||||
int module = -1;
|
||||
int load_std = 0;
|
||||
int dump_unhandled_promise_rejection = 0;
|
||||
int dump_unhandled_promise_rejection = 1;
|
||||
size_t memory_limit = 0;
|
||||
char *include_list[32];
|
||||
int i, include_count = 0;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
int load_jscalc;
|
||||
#endif
|
||||
int strip_flags = 0;
|
||||
size_t stack_size = 0;
|
||||
|
||||
#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;
|
||||
@ -400,20 +400,10 @@ int main(int argc, char **argv)
|
||||
load_std = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "unhandled-rejection")) {
|
||||
dump_unhandled_promise_rejection = 1;
|
||||
if (!strcmp(longopt, "no-unhandled-rejection")) {
|
||||
dump_unhandled_promise_rejection = 0;
|
||||
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;
|
||||
@ -423,7 +413,7 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr, "expecting memory limit");
|
||||
exit(1);
|
||||
}
|
||||
memory_limit = (size_t)strtod(argv[optind++], NULL);
|
||||
memory_limit = get_suffixed_size(argv[optind++]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "stack-size")) {
|
||||
@ -431,7 +421,15 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr, "expecting stack size");
|
||||
exit(1);
|
||||
}
|
||||
stack_size = (size_t)strtod(argv[optind++], NULL);
|
||||
stack_size = get_suffixed_size(argv[optind++]);
|
||||
continue;
|
||||
}
|
||||
if (opt == 's') {
|
||||
strip_flags = JS_STRIP_DEBUG;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "strip-source")) {
|
||||
strip_flags = JS_STRIP_SOURCE;
|
||||
continue;
|
||||
}
|
||||
if (opt) {
|
||||
@ -443,11 +441,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (load_jscalc)
|
||||
bignum_ext = 1;
|
||||
#endif
|
||||
|
||||
if (trace_memory) {
|
||||
js_trace_malloc_init(&trace_data);
|
||||
rt = JS_NewRuntime2(&trace_mf, &trace_data);
|
||||
@ -462,6 +455,7 @@ int main(int argc, char **argv)
|
||||
JS_SetMemoryLimit(rt, memory_limit);
|
||||
if (stack_size != 0)
|
||||
JS_SetMaxStackSize(rt, stack_size);
|
||||
JS_SetStripInfo(rt, strip_flags);
|
||||
js_std_set_worker_new_context_func(JS_NewCustomContext);
|
||||
js_std_init_handlers(rt);
|
||||
ctx = JS_NewCustomContext(rt);
|
||||
@ -477,13 +471,8 @@ int main(int argc, char **argv)
|
||||
JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
if (!empty_run) {
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (load_jscalc) {
|
||||
js_std_eval_binary(ctx, qjsc_qjscalc, qjsc_qjscalc_size, 0);
|
||||
}
|
||||
#endif
|
||||
js_std_add_helpers(ctx, argc - optind, argv + optind);
|
||||
|
||||
/* make 'std' and 'os' visible to non module code */
|
||||
@ -514,11 +503,12 @@ int main(int argc, char **argv)
|
||||
goto fail;
|
||||
}
|
||||
if (interactive) {
|
||||
JS_SetHostPromiseRejectionTracker(rt, NULL, NULL);
|
||||
js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0);
|
||||
}
|
||||
js_std_loop(ctx);
|
||||
}
|
||||
|
||||
|
||||
if (dump_memory) {
|
||||
JSMemoryUsage stats;
|
||||
JS_ComputeMemoryUsage(rt, &stats);
|
||||
|
264
qjsc.c
264
qjsc.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* QuickJS command line compiler
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2018-2021 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -76,7 +76,7 @@ static const FeatureEntry feature_list[] = {
|
||||
{ "promise", "Promise" },
|
||||
#define FE_MODULE_LOADER 9
|
||||
{ "module-loader", NULL },
|
||||
{ "bigint", "BigInt" },
|
||||
{ "weakref", "WeakRef" },
|
||||
};
|
||||
|
||||
void namelist_add(namelist_t *lp, const char *name, const char *short_name,
|
||||
@ -129,7 +129,7 @@ static void get_c_name(char *buf, size_t buf_size, const char *file)
|
||||
size_t len, i;
|
||||
int c;
|
||||
char *q;
|
||||
|
||||
|
||||
p = strrchr(file, '/');
|
||||
if (!p)
|
||||
p = file;
|
||||
@ -187,8 +187,8 @@ static void output_object_code(JSContext *ctx,
|
||||
}
|
||||
|
||||
namelist_add(&cname_list, c_name, NULL, load_only);
|
||||
|
||||
fprintf(fo, "const uint32_t %s_size = %u;\n\n",
|
||||
|
||||
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);
|
||||
@ -251,14 +251,14 @@ JSModuleDef *jsc_module_loader(JSContext *ctx,
|
||||
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);
|
||||
@ -270,7 +270,7 @@ JSModuleDef *jsc_module_loader(JSContext *ctx,
|
||||
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);
|
||||
@ -288,7 +288,7 @@ static void compile_file(JSContext *ctx, FILE *fo,
|
||||
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);
|
||||
@ -353,13 +353,14 @@ void help(void)
|
||||
"-M module_name[,cname] add initialization code for an external C module\n"
|
||||
"-x byte swapped output\n"
|
||||
"-p prefix set the prefix of the generated C names\n"
|
||||
"-S n set the maximum stack size to 'n' bytes (default=%d)\n",
|
||||
"-S n set the maximum stack size to 'n' bytes (default=%d)\n"
|
||||
"-s strip all the debug info\n"
|
||||
"--keep-source keep the source code\n",
|
||||
JS_DEFAULT_STACK_SIZE);
|
||||
#ifdef CONFIG_LTO
|
||||
{
|
||||
int i;
|
||||
printf("-flto use link time optimization\n");
|
||||
printf("-fbignum enable bignum extensions\n");
|
||||
printf("-fno-[");
|
||||
for(i = 0; i < countof(feature_list); i++) {
|
||||
if (i != 0)
|
||||
@ -383,7 +384,7 @@ int exec_cmd(char **argv)
|
||||
if (pid == 0) {
|
||||
execvp(argv[0], argv);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
ret = waitpid(pid, &status, 0);
|
||||
@ -401,7 +402,7 @@ static int output_executable(const char *out_filename, const char *cfilename,
|
||||
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, '/');
|
||||
@ -421,10 +422,10 @@ static int output_executable(const char *out_filename, const char *cfilename,
|
||||
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";
|
||||
@ -452,13 +453,13 @@ static int output_executable(const char *out_filename, const char *cfilename,
|
||||
*arg++ = "-ldl";
|
||||
*arg++ = "-lpthread";
|
||||
*arg = NULL;
|
||||
|
||||
|
||||
if (verbose) {
|
||||
for(arg = argv; *arg != NULL; arg++)
|
||||
printf("%s ", *arg);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
ret = exec_cmd((char **)argv);
|
||||
unlink(cfilename);
|
||||
return ret;
|
||||
@ -473,6 +474,31 @@ static int output_executable(const char *out_filename, const char *cfilename,
|
||||
}
|
||||
#endif
|
||||
|
||||
static size_t get_suffixed_size(const char *str)
|
||||
{
|
||||
char *p;
|
||||
size_t v;
|
||||
v = (size_t)strtod(str, &p);
|
||||
switch(*p) {
|
||||
case 'G':
|
||||
v <<= 30;
|
||||
break;
|
||||
case 'M':
|
||||
v <<= 20;
|
||||
break;
|
||||
case 'k':
|
||||
case 'K':
|
||||
v <<= 10;
|
||||
break;
|
||||
default:
|
||||
if (*p != '\0') {
|
||||
fprintf(stderr, "qjs: invalid suffix: %s\n", p);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
OUTPUT_C,
|
||||
@ -480,9 +506,24 @@ typedef enum {
|
||||
OUTPUT_EXECUTABLE,
|
||||
} OutputTypeEnum;
|
||||
|
||||
static const char *get_short_optarg(int *poptind, int opt,
|
||||
const char *arg, int argc, char **argv)
|
||||
{
|
||||
const char *optarg;
|
||||
if (*arg) {
|
||||
optarg = arg;
|
||||
} else if (*poptind < argc) {
|
||||
optarg = argv[(*poptind)++];
|
||||
} else {
|
||||
fprintf(stderr, "qjsc: expecting parameter for -%c\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
return optarg;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c, i, verbose;
|
||||
int i, verbose, strip_flags;
|
||||
const char *out_filename, *cname;
|
||||
char cfilename[1024];
|
||||
FILE *fo;
|
||||
@ -492,11 +533,8 @@ int main(int argc, char **argv)
|
||||
int module;
|
||||
OutputTypeEnum output_type;
|
||||
size_t stack_size;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
BOOL bignum_ext = FALSE;
|
||||
#endif
|
||||
namelist_t dynamic_module_list;
|
||||
|
||||
|
||||
out_filename = NULL;
|
||||
output_type = OUTPUT_EXECUTABLE;
|
||||
cname = NULL;
|
||||
@ -504,38 +542,60 @@ int main(int argc, char **argv)
|
||||
module = -1;
|
||||
byte_swap = FALSE;
|
||||
verbose = 0;
|
||||
strip_flags = JS_STRIP_SOURCE;
|
||||
use_lto = FALSE;
|
||||
stack_size = 0;
|
||||
memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));
|
||||
|
||||
|
||||
/* add system modules */
|
||||
namelist_add(&cmodule_list, "std", "std", 0);
|
||||
namelist_add(&cmodule_list, "os", "os", 0);
|
||||
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:");
|
||||
if (c == -1)
|
||||
optind = 1;
|
||||
while (optind < argc && *argv[optind] == '-') {
|
||||
char *arg = argv[optind] + 1;
|
||||
const char *longopt = "";
|
||||
const char *optarg;
|
||||
/* a single - is not an option, it also stops argument scanning */
|
||||
if (!*arg)
|
||||
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':
|
||||
{
|
||||
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 == 'o') {
|
||||
out_filename = get_short_optarg(&optind, opt, arg, argc, argv);
|
||||
break;
|
||||
}
|
||||
if (opt == 'c') {
|
||||
output_type = OUTPUT_C;
|
||||
continue;
|
||||
}
|
||||
if (opt == 'e') {
|
||||
output_type = OUTPUT_C_MAIN;
|
||||
continue;
|
||||
}
|
||||
if (opt == 'N') {
|
||||
cname = get_short_optarg(&optind, opt, arg, argc, argv);
|
||||
break;
|
||||
}
|
||||
if (opt == 'f') {
|
||||
const char *p;
|
||||
optarg = get_short_optarg(&optind, opt, arg, argc, argv);
|
||||
p = optarg;
|
||||
if (!strcmp(optarg, "lto")) {
|
||||
if (!strcmp(p, "lto")) {
|
||||
use_lto = TRUE;
|
||||
} else if (strstart(p, "no-", &p)) {
|
||||
use_lto = TRUE;
|
||||
@ -547,27 +607,23 @@ int main(int argc, char **argv)
|
||||
}
|
||||
if (i == countof(feature_list))
|
||||
goto bad_feature;
|
||||
} else
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (!strcmp(optarg, "bignum")) {
|
||||
bignum_ext = TRUE;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
bad_feature:
|
||||
fprintf(stderr, "unsupported feature: %s\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
module = 1;
|
||||
break;
|
||||
case 'M':
|
||||
{
|
||||
if (opt == 'm') {
|
||||
module = 1;
|
||||
continue;
|
||||
}
|
||||
if (opt == 'M') {
|
||||
char *p;
|
||||
char path[1024];
|
||||
char cname[1024];
|
||||
|
||||
optarg = get_short_optarg(&optind, opt, arg, argc, argv);
|
||||
pstrcpy(path, sizeof(path), optarg);
|
||||
p = strchr(path, ',');
|
||||
if (p) {
|
||||
@ -577,25 +633,44 @@ int main(int argc, char **argv)
|
||||
get_c_name(cname, sizeof(cname), path);
|
||||
}
|
||||
namelist_add(&cmodule_list, path, cname, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
namelist_add(&dynamic_module_list, optarg, NULL, 0);
|
||||
break;
|
||||
case 'x':
|
||||
byte_swap = TRUE;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'p':
|
||||
c_ident_prefix = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
stack_size = (size_t)strtod(optarg, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (opt == 'D') {
|
||||
optarg = get_short_optarg(&optind, opt, arg, argc, argv);
|
||||
namelist_add(&dynamic_module_list, optarg, NULL, 0);
|
||||
break;
|
||||
}
|
||||
if (opt == 'x') {
|
||||
byte_swap = 1;
|
||||
continue;
|
||||
}
|
||||
if (opt == 'v') {
|
||||
verbose++;
|
||||
continue;
|
||||
}
|
||||
if (opt == 'p') {
|
||||
c_ident_prefix = get_short_optarg(&optind, opt, arg, argc, argv);
|
||||
break;
|
||||
}
|
||||
if (opt == 'S') {
|
||||
optarg = get_short_optarg(&optind, opt, arg, argc, argv);
|
||||
stack_size = get_suffixed_size(optarg);
|
||||
break;
|
||||
}
|
||||
if (opt == 's') {
|
||||
strip_flags = JS_STRIP_DEBUG;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "keep-source")) {
|
||||
strip_flags = 0;
|
||||
continue;
|
||||
}
|
||||
if (opt) {
|
||||
fprintf(stderr, "qjsc: unknown option '-%c'\n", opt);
|
||||
} else {
|
||||
fprintf(stderr, "qjsc: unknown option '--%s'\n", longopt);
|
||||
}
|
||||
help();
|
||||
}
|
||||
}
|
||||
|
||||
@ -620,32 +695,26 @@ int main(int argc, char **argv)
|
||||
} 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_AddIntrinsicOperators(ctx);
|
||||
JS_EnableBignumExt(ctx, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
JS_SetStripInfo(rt, strip_flags);
|
||||
|
||||
/* 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"
|
||||
@ -669,7 +738,7 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (output_type != OUTPUT_C) {
|
||||
fprintf(fo,
|
||||
"static JSContext *JS_NewCustomContext(JSRuntime *rt)\n"
|
||||
@ -686,21 +755,12 @@ int main(int argc, char **argv)
|
||||
feature_list[i].init_name);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (bignum_ext) {
|
||||
fprintf(fo,
|
||||
" JS_AddIntrinsicBigFloat(ctx);\n"
|
||||
" JS_AddIntrinsicBigDecimal(ctx);\n"
|
||||
" JS_AddIntrinsicOperators(ctx);\n"
|
||||
" JS_EnableBignumExt(ctx, 1);\n");
|
||||
}
|
||||
#endif
|
||||
/* add the precompiled modules (XXX: could modify the module
|
||||
loader instead) */
|
||||
for(i = 0; i < init_module_list.count; i++) {
|
||||
namelist_entry_t *e = &init_module_list.array[i];
|
||||
/* initialize the static C modules */
|
||||
|
||||
|
||||
fprintf(fo,
|
||||
" {\n"
|
||||
" extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n"
|
||||
@ -718,19 +778,19 @@ int main(int argc, char **argv)
|
||||
fprintf(fo,
|
||||
" return ctx;\n"
|
||||
"}\n\n");
|
||||
|
||||
|
||||
fputs(main_c_template1, fo);
|
||||
|
||||
if (stack_size != 0) {
|
||||
fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n",
|
||||
(unsigned int)stack_size);
|
||||
}
|
||||
|
||||
|
||||
/* add the module loader if necessary */
|
||||
if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
|
||||
fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
|
||||
}
|
||||
|
||||
|
||||
fprintf(fo,
|
||||
" ctx = JS_NewCustomContext(rt);\n"
|
||||
" js_std_add_helpers(ctx, argc, argv);\n");
|
||||
@ -744,7 +804,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
fputs(main_c_template2, fo);
|
||||
}
|
||||
|
||||
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
|
||||
|
2657
qjscalc.js
2657
qjscalc.js
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* QuickJS atom definitions
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
* Copyright (c) 2017-2018 Charlie Gordon
|
||||
*
|
||||
@ -81,6 +81,7 @@ DEF(empty_string, "")
|
||||
DEF(length, "length")
|
||||
DEF(fileName, "fileName")
|
||||
DEF(lineNumber, "lineNumber")
|
||||
DEF(columnNumber, "columnNumber")
|
||||
DEF(message, "message")
|
||||
DEF(cause, "cause")
|
||||
DEF(errors, "errors")
|
||||
@ -172,13 +173,10 @@ DEF(status, "status")
|
||||
DEF(reason, "reason")
|
||||
DEF(globalThis, "globalThis")
|
||||
DEF(bigint, "bigint")
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF(bigfloat, "bigfloat")
|
||||
DEF(bigdecimal, "bigdecimal")
|
||||
DEF(roundingMode, "roundingMode")
|
||||
DEF(maximumSignificantDigits, "maximumSignificantDigits")
|
||||
DEF(maximumFractionDigits, "maximumFractionDigits")
|
||||
#endif
|
||||
DEF(minus_zero, "-0")
|
||||
DEF(Infinity, "Infinity")
|
||||
DEF(minus_Infinity, "-Infinity")
|
||||
DEF(NaN, "NaN")
|
||||
/* the following 3 atoms are only used with CONFIG_ATOMICS */
|
||||
DEF(not_equal, "not-equal")
|
||||
DEF(timed_out, "timed-out")
|
||||
@ -204,7 +202,7 @@ DEF(RegExp, "RegExp")
|
||||
DEF(ArrayBuffer, "ArrayBuffer")
|
||||
DEF(SharedArrayBuffer, "SharedArrayBuffer")
|
||||
/* must keep same order as class IDs for typed arrays */
|
||||
DEF(Uint8ClampedArray, "Uint8ClampedArray")
|
||||
DEF(Uint8ClampedArray, "Uint8ClampedArray")
|
||||
DEF(Int8Array, "Int8Array")
|
||||
DEF(Uint8Array, "Uint8Array")
|
||||
DEF(Int16Array, "Int16Array")
|
||||
@ -217,13 +215,8 @@ DEF(Float32Array, "Float32Array")
|
||||
DEF(Float64Array, "Float64Array")
|
||||
DEF(DataView, "DataView")
|
||||
DEF(BigInt, "BigInt")
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF(BigFloat, "BigFloat")
|
||||
DEF(BigFloatEnv, "BigFloatEnv")
|
||||
DEF(BigDecimal, "BigDecimal")
|
||||
DEF(OperatorSet, "OperatorSet")
|
||||
DEF(Operators, "Operators")
|
||||
#endif
|
||||
DEF(WeakRef, "WeakRef")
|
||||
DEF(FinalizationRegistry, "FinalizationRegistry")
|
||||
DEF(Map, "Map")
|
||||
DEF(Set, "Set") /* Map + 1 */
|
||||
DEF(WeakMap, "WeakMap") /* Map + 2 */
|
||||
@ -266,8 +259,5 @@ DEF(Symbol_hasInstance, "Symbol.hasInstance")
|
||||
DEF(Symbol_species, "Symbol.species")
|
||||
DEF(Symbol_unscopables, "Symbol.unscopables")
|
||||
DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF(Symbol_operatorSet, "Symbol.operatorSet")
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* DEF */
|
||||
|
757
quickjs-libc.c
757
quickjs-libc.c
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* QuickJS C library
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -37,6 +37,7 @@ 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);
|
||||
JSValue js_std_await(JSContext *ctx, JSValue obj);
|
||||
void js_std_init_handlers(JSRuntime *rt);
|
||||
void js_std_free_handlers(JSRuntime *rt);
|
||||
void js_std_dump_error(JSContext *ctx);
|
||||
@ -51,7 +52,7 @@ void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
|
||||
JSValueConst reason,
|
||||
JS_BOOL is_handled, void *opaque);
|
||||
void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" { */
|
||||
#endif
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* QuickJS opcode definitions
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
* Copyright (c) 2017-2018 Charlie Gordon
|
||||
*
|
||||
@ -110,6 +110,7 @@ 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( init_ctor, 1, 0, 1, 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)
|
||||
@ -165,7 +166,7 @@ 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( 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)
|
||||
@ -173,7 +174,7 @@ DEF( get_loc_check, 3, 0, 1, loc)
|
||||
DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */
|
||||
DEF( put_loc_check_init, 3, 1, 0, loc)
|
||||
DEF(get_loc_checkthis, 3, 0, 1, loc)
|
||||
DEF(get_var_ref_check, 3, 0, 1, var_ref)
|
||||
DEF(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)
|
||||
@ -195,7 +196,6 @@ DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order a
|
||||
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)
|
||||
@ -207,8 +207,9 @@ 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) /* iter next catch_offset -> iter next catch_offset obj */
|
||||
DEF(iterator_check_object, 1, 1, 1, none)
|
||||
DEF(iterator_get_value_done, 1, 1, 2, none)
|
||||
DEF(iterator_get_value_done, 1, 2, 3, none) /* catch_offset obj -> catch_offset value done */
|
||||
DEF( iterator_close, 1, 3, 0, none)
|
||||
DEF( iterator_next, 1, 4, 4, none)
|
||||
DEF( iterator_call, 2, 4, 5, u8)
|
||||
@ -258,12 +259,9 @@ DEF( xor, 1, 2, 1, none)
|
||||
DEF( or, 1, 2, 1, none)
|
||||
DEF(is_undefined_or_null, 1, 1, 1, none)
|
||||
DEF( private_in, 1, 2, 1, none)
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF( mul_pow10, 1, 2, 1, none)
|
||||
DEF( math_mod, 1, 2, 1, none)
|
||||
#endif
|
||||
DEF(push_bigint_i32, 5, 0, 1, i32)
|
||||
/* must be the last non short and non temporary opcode */
|
||||
DEF( nop, 1, 0, 0, none)
|
||||
DEF( nop, 1, 0, 0, none)
|
||||
|
||||
/* temporary opcodes: never emitted in the final bytecode */
|
||||
|
||||
@ -289,7 +287,7 @@ def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1,
|
||||
def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
|
||||
def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
|
||||
def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
|
||||
|
||||
|
||||
def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */
|
||||
|
||||
#if SHORT_OPCODES
|
||||
|
158
quickjs.h
158
quickjs.h
@ -27,6 +27,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -48,7 +49,6 @@ extern "C" {
|
||||
|
||||
typedef struct JSRuntime JSRuntime;
|
||||
typedef struct JSContext JSContext;
|
||||
typedef struct JSObject JSObject;
|
||||
typedef struct JSClass JSClass;
|
||||
typedef uint32_t JSClassID;
|
||||
typedef uint32_t JSAtom;
|
||||
@ -64,14 +64,21 @@ typedef uint32_t JSAtom;
|
||||
#define JS_NAN_BOXING
|
||||
#endif
|
||||
|
||||
#if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX)
|
||||
#define JS_LIMB_BITS 64
|
||||
#else
|
||||
#define JS_LIMB_BITS 32
|
||||
#endif
|
||||
|
||||
#define JS_SHORT_BIG_INT_BITS JS_LIMB_BITS
|
||||
|
||||
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_FIRST = -9, /* first negative tag */
|
||||
JS_TAG_BIG_INT = -9,
|
||||
JS_TAG_SYMBOL = -8,
|
||||
JS_TAG_STRING = -7,
|
||||
JS_TAG_STRING_ROPE = -6,
|
||||
JS_TAG_MODULE = -3, /* used internally */
|
||||
JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */
|
||||
JS_TAG_OBJECT = -1,
|
||||
@ -83,7 +90,8 @@ enum {
|
||||
JS_TAG_UNINITIALIZED = 4,
|
||||
JS_TAG_CATCH_OFFSET = 5,
|
||||
JS_TAG_EXCEPTION = 6,
|
||||
JS_TAG_FLOAT64 = 7,
|
||||
JS_TAG_SHORT_BIG_INT = 7,
|
||||
JS_TAG_FLOAT64 = 8,
|
||||
/* any larger tag is FLOAT64 if JS_NAN_BOXING */
|
||||
};
|
||||
|
||||
@ -108,6 +116,7 @@ typedef const struct __JSValue *JSValueConst;
|
||||
#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_SHORT_BIG_INT(v) 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))
|
||||
@ -126,7 +135,12 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int32_t d)
|
||||
{
|
||||
return JS_MKVAL(JS_TAG_SHORT_BIG_INT, d);
|
||||
}
|
||||
|
||||
#elif defined(JS_NAN_BOXING)
|
||||
|
||||
typedef uint64_t JSValue;
|
||||
@ -136,6 +150,7 @@ typedef uint64_t 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_SHORT_BIG_INT(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))
|
||||
@ -191,13 +206,23 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
tag = JS_VALUE_GET_TAG(v);
|
||||
return tag == (JS_NAN >> 32);
|
||||
}
|
||||
|
||||
|
||||
static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int32_t d)
|
||||
{
|
||||
return JS_MKVAL(JS_TAG_SHORT_BIG_INT, d);
|
||||
}
|
||||
|
||||
#else /* !JS_NAN_BOXING */
|
||||
|
||||
typedef union JSValueUnion {
|
||||
int32_t int32;
|
||||
double float64;
|
||||
void *ptr;
|
||||
#if JS_SHORT_BIG_INT_BITS == 32
|
||||
int32_t short_big_int;
|
||||
#else
|
||||
int64_t short_big_int;
|
||||
#endif
|
||||
} JSValueUnion;
|
||||
|
||||
typedef struct JSValue {
|
||||
@ -213,6 +238,7 @@ typedef struct JSValue {
|
||||
#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_SHORT_BIG_INT(v) ((v).u.short_big_int)
|
||||
#define JS_VALUE_GET_PTR(v) ((v).u.ptr)
|
||||
|
||||
#define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }
|
||||
@ -242,13 +268,19 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000;
|
||||
}
|
||||
|
||||
static inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d)
|
||||
{
|
||||
JSValue v;
|
||||
v.tag = JS_TAG_SHORT_BIG_INT;
|
||||
v.u.short_big_int = d;
|
||||
return v;
|
||||
}
|
||||
|
||||
#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 */
|
||||
@ -290,7 +322,9 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
#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)
|
||||
#ifndef JS_DEFAULT_STACK_SIZE
|
||||
#define JS_DEFAULT_STACK_SIZE (1024 * 1024)
|
||||
#endif
|
||||
|
||||
/* JS_Eval() flags */
|
||||
#define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */
|
||||
@ -300,7 +334,6 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
#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(). */
|
||||
@ -309,7 +342,7 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)
|
||||
/* allow top-level await in normal script. JS_Eval() returns a
|
||||
promise. Only allowed with JS_EVAL_TYPE_GLOBAL */
|
||||
#define JS_EVAL_FLAG_ASYNC (1 << 7)
|
||||
#define JS_EVAL_FLAG_ASYNC (1 << 7)
|
||||
|
||||
typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
|
||||
typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
|
||||
@ -373,13 +406,7 @@ 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 operator overloading */
|
||||
void JS_AddIntrinsicOperators(JSContext *ctx);
|
||||
/* enable "use math" */
|
||||
void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable);
|
||||
void JS_AddIntrinsicWeakRef(JSContext *ctx);
|
||||
|
||||
JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv);
|
||||
@ -474,6 +501,17 @@ typedef struct JSClassExoticMethods {
|
||||
/* return < 0 if exception or TRUE/FALSE */
|
||||
int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom,
|
||||
JSValueConst value, JSValueConst receiver, int flags);
|
||||
|
||||
/* To get a consistent object behavior when get_prototype != NULL,
|
||||
get_property, set_property and set_prototype must be != NULL
|
||||
and the object must be created with a JS_NULL prototype. */
|
||||
JSValue (*get_prototype)(JSContext *ctx, JSValueConst obj);
|
||||
/* return < 0 if exception or TRUE/FALSE */
|
||||
int (*set_prototype)(JSContext *ctx, JSValueConst obj, JSValueConst proto_val);
|
||||
/* return < 0 if exception or TRUE/FALSE */
|
||||
int (*is_extensible)(JSContext *ctx, JSValueConst obj);
|
||||
/* return < 0 if exception or TRUE/FALSE */
|
||||
int (*prevent_extensions)(JSContext *ctx, JSValueConst obj);
|
||||
} JSClassExoticMethods;
|
||||
|
||||
typedef void JSClassFinalizer(JSRuntime *rt, JSValue val);
|
||||
@ -499,7 +537,10 @@ typedef struct JSClassDef {
|
||||
JSClassExoticMethods *exotic;
|
||||
} JSClassDef;
|
||||
|
||||
#define JS_INVALID_CLASS_ID 0
|
||||
JSClassID JS_NewClassID(JSClassID *pclass_id);
|
||||
/* Returns the class ID if `v` is an object, otherwise returns JS_INVALID_CLASS_ID. */
|
||||
JSClassID JS_GetClassID(JSValue v);
|
||||
int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def);
|
||||
int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);
|
||||
|
||||
@ -547,23 +588,21 @@ 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);
|
||||
if (d >= INT32_MIN && d <= INT32_MAX) {
|
||||
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)
|
||||
return JS_MKVAL(JS_TAG_INT, val);
|
||||
}
|
||||
return v;
|
||||
return __JS_NewFloat64(ctx, d);
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsNumber(JSValueConst v)
|
||||
@ -575,19 +614,7 @@ static inline JS_BOOL JS_IsNumber(JSValueConst v)
|
||||
static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)
|
||||
{
|
||||
int tag = JS_VALUE_GET_TAG(v);
|
||||
return 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;
|
||||
return tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsBool(JSValueConst v)
|
||||
@ -617,7 +644,8 @@ static inline JS_BOOL JS_IsUninitialized(JSValueConst v)
|
||||
|
||||
static inline JS_BOOL JS_IsString(JSValueConst v)
|
||||
{
|
||||
return JS_VALUE_GET_TAG(v) == JS_TAG_STRING;
|
||||
return JS_VALUE_GET_TAG(v) == JS_TAG_STRING ||
|
||||
JS_VALUE_GET_TAG(v) == JS_TAG_STRING_ROPE;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsSymbol(JSValueConst v)
|
||||
@ -632,7 +660,9 @@ static inline JS_BOOL JS_IsObject(JSValueConst v)
|
||||
|
||||
JSValue JS_Throw(JSContext *ctx, JSValue obj);
|
||||
JSValue JS_GetException(JSContext *ctx);
|
||||
JS_BOOL JS_HasException(JSContext *ctx);
|
||||
JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val);
|
||||
void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, JS_BOOL flag);
|
||||
void JS_ResetUncatchableError(JSContext *ctx);
|
||||
JSValue JS_NewError(JSContext *ctx);
|
||||
JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...);
|
||||
@ -681,6 +711,10 @@ static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
|
||||
return (JSValue)v;
|
||||
}
|
||||
|
||||
JS_BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2);
|
||||
JS_BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2);
|
||||
JS_BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
|
||||
|
||||
int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */
|
||||
int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val);
|
||||
static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
|
||||
@ -696,7 +730,10 @@ int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
|
||||
int JS_ToInt64Ext(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);
|
||||
static inline JSValue JS_NewString(JSContext *ctx, const char *str)
|
||||
{
|
||||
return JS_NewStringLen(ctx, str, strlen(str));
|
||||
}
|
||||
JSValue JS_NewAtomString(JSContext *ctx, const char *str);
|
||||
JSValue JS_ToString(JSContext *ctx, JSValueConst val);
|
||||
JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val);
|
||||
@ -723,6 +760,8 @@ 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_NewDate(JSContext *ctx, double epoch_ms);
|
||||
|
||||
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
|
||||
JSAtom prop, JSValueConst receiver,
|
||||
JS_BOOL throw_ref_error);
|
||||
@ -804,6 +843,7 @@ int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
|
||||
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);
|
||||
void *JS_GetAnyOpaque(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,
|
||||
@ -821,6 +861,23 @@ JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
|
||||
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);
|
||||
|
||||
typedef enum JSTypedArrayEnum {
|
||||
JS_TYPED_ARRAY_UINT8C = 0,
|
||||
JS_TYPED_ARRAY_INT8,
|
||||
JS_TYPED_ARRAY_UINT8,
|
||||
JS_TYPED_ARRAY_INT16,
|
||||
JS_TYPED_ARRAY_UINT16,
|
||||
JS_TYPED_ARRAY_INT32,
|
||||
JS_TYPED_ARRAY_UINT32,
|
||||
JS_TYPED_ARRAY_BIG_INT64,
|
||||
JS_TYPED_ARRAY_BIG_UINT64,
|
||||
JS_TYPED_ARRAY_FLOAT32,
|
||||
JS_TYPED_ARRAY_FLOAT64,
|
||||
} JSTypedArrayEnum;
|
||||
|
||||
JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,
|
||||
JSTypedArrayEnum array_type);
|
||||
JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
|
||||
size_t *pbyte_offset,
|
||||
size_t *pbyte_length,
|
||||
@ -855,6 +912,12 @@ 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);
|
||||
/* select which debug info is stripped from the compiled code */
|
||||
#define JS_STRIP_SOURCE (1 << 0) /* strip source code */
|
||||
#define JS_STRIP_DEBUG (1 << 1) /* strip all debug info including source code */
|
||||
void JS_SetStripInfo(JSRuntime *rt, int flags);
|
||||
int JS_GetStripInfo(JSRuntime *rt);
|
||||
|
||||
/* set the [IsHTMLDDA] internal slot */
|
||||
void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj);
|
||||
|
||||
@ -876,6 +939,7 @@ void JS_SetModuleLoaderFunc(JSRuntime *rt,
|
||||
/* return the import.meta object of a module */
|
||||
JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m);
|
||||
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m);
|
||||
JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m);
|
||||
|
||||
/* JS Job support */
|
||||
|
||||
@ -968,7 +1032,7 @@ static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *fun
|
||||
{
|
||||
return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic);
|
||||
}
|
||||
void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
|
||||
void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
|
||||
JSValueConst proto);
|
||||
|
||||
/* C property definition */
|
||||
|
21
readme-cosmo.txt
Normal file
21
readme-cosmo.txt
Normal file
@ -0,0 +1,21 @@
|
||||
The executables included in this archive run on Linux, Mac, Windows,
|
||||
FreeBSD, OpenBSD and NetBSD for both the ARM64 and x86_64
|
||||
architectures.
|
||||
|
||||
Platform Notes:
|
||||
|
||||
- if you get errors on Linux, you should disable the binfmt_misc
|
||||
module which automatically invokes wine with Windows executable:
|
||||
|
||||
sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/cli' # remove Ubuntu's MZ interpreter
|
||||
sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/status' # remove ALL binfmt_misc entries
|
||||
|
||||
- Under Windows, you can rename the executables with a .exe extension.
|
||||
|
||||
- Use the --assimilate option to build a platform specific binary for
|
||||
better startup time:
|
||||
|
||||
./qjs --assimilate
|
||||
|
||||
- See https://github.com/jart/cosmopolitan for more information about
|
||||
platform specific issues.
|
58
release.sh
58
release.sh
@ -8,12 +8,12 @@ version=`cat VERSION`
|
||||
if [ "$1" = "-h" ] ; then
|
||||
echo "release.sh [release_list]"
|
||||
echo ""
|
||||
echo "release_list: extras binary win_binary quickjs"
|
||||
|
||||
echo "release_list: extras binary win_binary cosmo_binary quickjs"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
release_list="extras binary win_binary quickjs"
|
||||
release_list="extras binary win_binary cosmo_binary quickjs"
|
||||
|
||||
if [ "$1" != "" ] ; then
|
||||
release_list="$1"
|
||||
@ -29,7 +29,7 @@ name="quickjs-extras-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir $outdir/unicode $outdir/tests
|
||||
mkdir -p $outdir $outdir/unicode $outdir/tests
|
||||
|
||||
cp unicode/* $outdir/unicode
|
||||
cp -a tests/bench-v8 $outdir/tests
|
||||
@ -53,7 +53,10 @@ outdir="/tmp/${d}"
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
make CONFIG_WIN32=y qjs.exe
|
||||
make clean
|
||||
make CONFIG_WIN32=y clean
|
||||
|
||||
make CONFIG_WIN32=y CONFIG_LTO=y qjs.exe
|
||||
cp qjs.exe $outdir
|
||||
${cross_prefix}strip $outdir/qjs.exe
|
||||
cp $dlldir/libwinpthread-1.dll $outdir
|
||||
@ -75,7 +78,7 @@ mkdir -p $outdir
|
||||
make clean
|
||||
make CONFIG_WIN32=y clean
|
||||
|
||||
make CONFIG_WIN32=y CONFIG_M32=y qjs.exe
|
||||
make CONFIG_WIN32=y CONFIG_M32=y CONFIG_LTO=y qjs.exe
|
||||
cp qjs.exe $outdir
|
||||
${cross_prefix}strip $outdir/qjs.exe
|
||||
cp $dlldir/libwinpthread-1.dll $outdir
|
||||
@ -83,7 +86,7 @@ cp $dlldir/libwinpthread-1.dll $outdir
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
fi
|
||||
|
||||
|
||||
#################################################"
|
||||
# Linux binary release
|
||||
|
||||
@ -91,9 +94,8 @@ if echo $release_list | grep -w -q binary ; then
|
||||
|
||||
make clean
|
||||
make CONFIG_WIN32=y clean
|
||||
make -j4 qjs run-test262
|
||||
make -j4 CONFIG_M32=y qjs32 run-test262-32
|
||||
strip qjs run-test262 qjs32 run-test262-32
|
||||
make -j4 CONFIG_LTO=y qjs run-test262
|
||||
strip qjs run-test262
|
||||
|
||||
d="quickjs-linux-x86_64-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
@ -105,14 +107,39 @@ cp qjs run-test262 $outdir
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
make clean
|
||||
make -j4 CONFIG_LTO=y CONFIG_M32=y qjs run-test262
|
||||
strip qjs run-test262
|
||||
|
||||
d="quickjs-linux-i686-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
cp qjs32 $outdir/qjs
|
||||
cp run-test262-32 $outdir/run-test262
|
||||
cp qjs run-test262 $outdir
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# Cosmopolitan binary release
|
||||
|
||||
if echo $release_list | grep -w -q cosmo_binary ; then
|
||||
|
||||
export PATH=$PATH:$HOME/cosmocc/bin
|
||||
|
||||
d="quickjs-cosmo-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
make clean
|
||||
make CONFIG_COSMO=y -j4 qjs run-test262
|
||||
cp qjs run-test262 $outdir
|
||||
cp readme-cosmo.txt $outdir/readme.txt
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
@ -133,13 +160,13 @@ mkdir -p $outdir $outdir/doc $outdir/tests $outdir/examples
|
||||
|
||||
cp Makefile VERSION TODO Changelog readme.txt LICENSE \
|
||||
release.sh unicode_download.sh \
|
||||
qjs.c qjsc.c qjscalc.js repl.js \
|
||||
qjs.c qjsc.c 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 \
|
||||
dtoa.c dtoa.h \
|
||||
unicode_gen.c unicode_gen_def.h \
|
||||
run-test262.c test262o.conf test262.conf \
|
||||
test262o_errors.txt test262_errors.txt \
|
||||
@ -150,8 +177,7 @@ 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
|
||||
$outdir/doc
|
||||
|
||||
( cd /tmp && tar Jcvf /tmp/${d}.tar.xz ${d} )
|
||||
|
||||
|
321
repl.js
321
repl.js
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* QuickJS Read Eval Print Loop
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2020 Fabrice Bellard
|
||||
* Copyright (c) 2017-2020 Charlie Gordon
|
||||
*
|
||||
@ -22,8 +22,6 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
"use strip";
|
||||
|
||||
import * as std from "std";
|
||||
import * as os from "os";
|
||||
|
||||
@ -31,7 +29,7 @@ import * as os from "os";
|
||||
/* add 'os' and 'std' bindings */
|
||||
g.os = os;
|
||||
g.std = std;
|
||||
|
||||
|
||||
/* close global objects */
|
||||
var Object = g.Object;
|
||||
var String = g.String;
|
||||
@ -41,11 +39,6 @@ import * as os from "os";
|
||||
var isFinite = g.isFinite;
|
||||
var parseFloat = g.parseFloat;
|
||||
|
||||
/* XXX: use preprocessor ? */
|
||||
var config_numcalc = (typeof os.open === "undefined");
|
||||
var has_jscalc = (typeof Fraction === "function");
|
||||
var has_bignum = (typeof BigFloat === "function");
|
||||
|
||||
var colors = {
|
||||
none: "\x1b[0m",
|
||||
black: "\x1b[30m",
|
||||
@ -67,60 +60,38 @@ import * as os from "os";
|
||||
bright_white: "\x1b[37;1m",
|
||||
};
|
||||
|
||||
var styles;
|
||||
if (config_numcalc) {
|
||||
styles = {
|
||||
'default': 'black',
|
||||
'comment': 'white',
|
||||
'string': 'green',
|
||||
'regex': 'cyan',
|
||||
'number': 'green',
|
||||
'keyword': 'blue',
|
||||
'function': 'gray',
|
||||
'type': 'bright_magenta',
|
||||
'identifier': 'yellow',
|
||||
'error': 'bright_red',
|
||||
'result': 'black',
|
||||
'error_msg': 'bright_red',
|
||||
};
|
||||
} else {
|
||||
styles = {
|
||||
'default': 'bright_green',
|
||||
'comment': 'white',
|
||||
'string': 'bright_cyan',
|
||||
'regex': 'cyan',
|
||||
'number': 'green',
|
||||
'keyword': 'bright_white',
|
||||
'function': 'bright_yellow',
|
||||
'type': 'bright_magenta',
|
||||
'identifier': 'bright_green',
|
||||
'error': 'red',
|
||||
'result': 'bright_white',
|
||||
'error_msg': 'bright_red',
|
||||
};
|
||||
}
|
||||
var styles = {
|
||||
'default': 'bright_green',
|
||||
'comment': 'white',
|
||||
'string': 'bright_cyan',
|
||||
'regex': 'cyan',
|
||||
'number': 'green',
|
||||
'keyword': 'bright_white',
|
||||
'function': 'bright_yellow',
|
||||
'type': 'bright_magenta',
|
||||
'identifier': 'bright_green',
|
||||
'error': 'red',
|
||||
'result': 'bright_white',
|
||||
'error_msg': 'bright_red',
|
||||
};
|
||||
|
||||
var history = [];
|
||||
var clip_board = "";
|
||||
var prec;
|
||||
var expBits;
|
||||
var log2_10;
|
||||
|
||||
|
||||
var pstate = "";
|
||||
var prompt = "";
|
||||
var plen = 0;
|
||||
var ps1;
|
||||
if (config_numcalc)
|
||||
ps1 = "> ";
|
||||
else
|
||||
ps1 = "qjs > ";
|
||||
var ps1 = "qjs > ";
|
||||
var ps2 = " ... ";
|
||||
var utf8 = true;
|
||||
var show_time = false;
|
||||
var show_colors = true;
|
||||
var eval_start_time;
|
||||
var eval_time = 0;
|
||||
|
||||
|
||||
var mexpr = "";
|
||||
var level = 0;
|
||||
var cmd = "";
|
||||
@ -138,12 +109,12 @@ import * as os from "os";
|
||||
var term_read_buf;
|
||||
var term_width;
|
||||
/* current X position of the cursor in the terminal */
|
||||
var term_cursor_x = 0;
|
||||
|
||||
var term_cursor_x = 0;
|
||||
|
||||
function termInit() {
|
||||
var tab;
|
||||
term_fd = std.in.fileno();
|
||||
|
||||
|
||||
/* get the terminal size */
|
||||
term_width = 80;
|
||||
if (os.isatty(term_fd)) {
|
||||
@ -170,14 +141,14 @@ import * as os from "os";
|
||||
/* send Ctrl-C to readline */
|
||||
handle_byte(3);
|
||||
}
|
||||
|
||||
|
||||
function term_read_handler() {
|
||||
var l, i;
|
||||
l = os.read(term_fd, term_read_buf.buffer, 0, term_read_buf.length);
|
||||
for(i = 0; i < l; i++)
|
||||
handle_byte(term_read_buf[i]);
|
||||
}
|
||||
|
||||
|
||||
function handle_byte(c) {
|
||||
if (!utf8) {
|
||||
handle_char(c);
|
||||
@ -195,12 +166,12 @@ import * as os from "os";
|
||||
handle_char(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function is_alpha(c) {
|
||||
return typeof c === "string" &&
|
||||
((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
|
||||
}
|
||||
|
||||
|
||||
function is_digit(c) {
|
||||
return typeof c === "string" && (c >= '0' && c <= '9');
|
||||
}
|
||||
@ -232,7 +203,7 @@ import * as os from "os";
|
||||
d = c.codePointAt(0); /* can be NaN if empty string */
|
||||
return d >= 0xdc00 && d < 0xe000;
|
||||
}
|
||||
|
||||
|
||||
function is_balanced(a, b) {
|
||||
switch (a + b) {
|
||||
case "()":
|
||||
@ -271,7 +242,7 @@ import * as os from "os";
|
||||
} else {
|
||||
l = Math.min(term_width - 1 - term_cursor_x, delta);
|
||||
print_csi(l, "C"); /* right */
|
||||
delta -= l;
|
||||
delta -= l;
|
||||
term_cursor_x += l;
|
||||
}
|
||||
}
|
||||
@ -399,7 +370,7 @@ import * as os from "os";
|
||||
|
||||
function backward_word() {
|
||||
cursor_pos = skip_word_backward(cursor_pos);
|
||||
}
|
||||
}
|
||||
|
||||
function accept_line() {
|
||||
std.puts("\n");
|
||||
@ -577,7 +548,7 @@ import * as os from "os";
|
||||
readline_print_prompt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function reset() {
|
||||
cmd = "";
|
||||
cursor_pos = 0;
|
||||
@ -613,6 +584,9 @@ import * as os from "os";
|
||||
base = get_context_word(line, pos);
|
||||
if (["true", "false", "null", "this"].includes(base) || !isNaN(+base))
|
||||
return eval(base);
|
||||
// Check if `base` is a set of regexp flags
|
||||
if (pos - base.length >= 3 && line[pos - base.length - 1] === '/')
|
||||
return new RegExp('', base);
|
||||
obj = get_context_object(line, pos - base.length);
|
||||
if (obj === null || obj === void 0)
|
||||
return obj;
|
||||
@ -731,7 +705,7 @@ import * as os from "os";
|
||||
readline_print_prompt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var commands = { /* command table */
|
||||
"\x01": beginning_of_line, /* ^A - bol */
|
||||
"\x02": backward_char, /* ^B - backward-char */
|
||||
@ -807,9 +781,9 @@ import * as os from "os";
|
||||
cursor_pos = cmd.length;
|
||||
history_index = history.length;
|
||||
readline_cb = cb;
|
||||
|
||||
|
||||
prompt = pstate;
|
||||
|
||||
|
||||
if (mexpr) {
|
||||
prompt += dupstr(" ", plen - prompt.length);
|
||||
prompt += ps2;
|
||||
@ -894,7 +868,7 @@ import * as os from "os";
|
||||
} else {
|
||||
alert(); /* beep! */
|
||||
}
|
||||
|
||||
|
||||
cursor_pos = (cursor_pos < 0) ? 0 :
|
||||
(cursor_pos > cmd.length) ? cmd.length : cursor_pos;
|
||||
update();
|
||||
@ -932,48 +906,6 @@ import * as os from "os";
|
||||
}
|
||||
}
|
||||
|
||||
function bigfloat_to_string(a, radix) {
|
||||
var s;
|
||||
if (!BigFloat.isFinite(a)) {
|
||||
/* NaN, Infinite */
|
||||
if (eval_mode !== "math") {
|
||||
return "BigFloat(" + a.toString() + ")";
|
||||
} else {
|
||||
return a.toString();
|
||||
}
|
||||
} else {
|
||||
if (a == 0) {
|
||||
if (1 / a < 0)
|
||||
s = "-0";
|
||||
else
|
||||
s = "0";
|
||||
} else {
|
||||
if (radix == 16) {
|
||||
var s;
|
||||
if (a < 0) {
|
||||
a = -a;
|
||||
s = "-";
|
||||
} else {
|
||||
s = "";
|
||||
}
|
||||
s += "0x" + a.toString(16);
|
||||
} else {
|
||||
s = a.toString();
|
||||
}
|
||||
}
|
||||
if (typeof a === "bigfloat" && eval_mode !== "math") {
|
||||
s += "l";
|
||||
} else if (eval_mode !== "std" && s.indexOf(".") < 0 &&
|
||||
((radix == 16 && s.indexOf("p") < 0) ||
|
||||
(radix == 10 && s.indexOf("e") < 0))) {
|
||||
/* add a decimal point so that the floating point type
|
||||
is visible */
|
||||
s += ".0";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
function bigint_to_string(a, radix) {
|
||||
var s;
|
||||
if (radix == 16) {
|
||||
@ -992,27 +924,21 @@ import * as os from "os";
|
||||
s += "n";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
function print(a) {
|
||||
var stack = [];
|
||||
|
||||
function print_rec(a) {
|
||||
var n, i, keys, key, type, s;
|
||||
|
||||
|
||||
type = typeof(a);
|
||||
if (type === "object") {
|
||||
if (a === null) {
|
||||
std.puts(a);
|
||||
} else if (stack.indexOf(a) >= 0) {
|
||||
std.puts("[circular]");
|
||||
} else if (has_jscalc && (a instanceof Fraction ||
|
||||
a instanceof Complex ||
|
||||
a instanceof Mod ||
|
||||
a instanceof Polynomial ||
|
||||
a instanceof PolyMod ||
|
||||
a instanceof RationalFunction ||
|
||||
a instanceof Series)) {
|
||||
std.puts(a.toString());
|
||||
} else if (a instanceof Date) {
|
||||
std.puts("Date " + a.toGMTString().__quote());
|
||||
} else {
|
||||
stack.push(a);
|
||||
if (Array.isArray(a)) {
|
||||
@ -1058,10 +984,6 @@ import * as os from "os";
|
||||
std.puts(number_to_string(a, hex_mode ? 16 : 10));
|
||||
} else if (type === "bigint") {
|
||||
std.puts(bigint_to_string(a, hex_mode ? 16 : 10));
|
||||
} else if (type === "bigfloat") {
|
||||
std.puts(bigfloat_to_string(a, hex_mode ? 16 : 10));
|
||||
} else if (type === "bigdecimal") {
|
||||
std.puts(a.toString() + "m");
|
||||
} else if (type === "symbol") {
|
||||
std.puts(String(a));
|
||||
} else if (type === "function") {
|
||||
@ -1072,7 +994,7 @@ import * as os from "os";
|
||||
}
|
||||
print_rec(a);
|
||||
}
|
||||
|
||||
|
||||
function extract_directive(a) {
|
||||
var pos;
|
||||
if (a[0] !== '\\')
|
||||
@ -1087,7 +1009,7 @@ import * as os from "os";
|
||||
/* return true if the string after cmd can be evaluted as JS */
|
||||
function handle_directive(cmd, expr) {
|
||||
var param, prec1, expBits1;
|
||||
|
||||
|
||||
if (cmd === "h" || cmd === "?" || cmd == "help") {
|
||||
help();
|
||||
} else if (cmd === "load") {
|
||||
@ -1102,75 +1024,10 @@ import * as os from "os";
|
||||
hex_mode = false;
|
||||
} else if (cmd === "t") {
|
||||
show_time = !show_time;
|
||||
} else if (has_bignum && cmd === "p") {
|
||||
param = expr.substring(cmd.length + 1).trim().split(" ");
|
||||
if (param.length === 1 && param[0] === "") {
|
||||
std.puts("BigFloat precision=" + prec + " bits (~" +
|
||||
Math.floor(prec / log2_10) +
|
||||
" digits), exponent size=" + expBits + " bits\n");
|
||||
} else if (param[0] === "f16") {
|
||||
prec = 11;
|
||||
expBits = 5;
|
||||
} else if (param[0] === "f32") {
|
||||
prec = 24;
|
||||
expBits = 8;
|
||||
} else if (param[0] === "f64") {
|
||||
prec = 53;
|
||||
expBits = 11;
|
||||
} else if (param[0] === "f128") {
|
||||
prec = 113;
|
||||
expBits = 15;
|
||||
} else {
|
||||
prec1 = parseInt(param[0]);
|
||||
if (param.length >= 2)
|
||||
expBits1 = parseInt(param[1]);
|
||||
else
|
||||
expBits1 = BigFloatEnv.expBitsMax;
|
||||
if (Number.isNaN(prec1) ||
|
||||
prec1 < BigFloatEnv.precMin ||
|
||||
prec1 > BigFloatEnv.precMax) {
|
||||
std.puts("Invalid precision\n");
|
||||
return false;
|
||||
}
|
||||
if (Number.isNaN(expBits1) ||
|
||||
expBits1 < BigFloatEnv.expBitsMin ||
|
||||
expBits1 > BigFloatEnv.expBitsMax) {
|
||||
std.puts("Invalid exponent bits\n");
|
||||
return false;
|
||||
}
|
||||
prec = prec1;
|
||||
expBits = expBits1;
|
||||
}
|
||||
return false;
|
||||
} else if (has_bignum && cmd === "digits") {
|
||||
param = expr.substring(cmd.length + 1).trim();
|
||||
prec1 = Math.ceil(parseFloat(param) * log2_10);
|
||||
if (prec1 < BigFloatEnv.precMin ||
|
||||
prec1 > BigFloatEnv.precMax) {
|
||||
std.puts("Invalid precision\n");
|
||||
return false;
|
||||
}
|
||||
prec = prec1;
|
||||
expBits = BigFloatEnv.expBitsMax;
|
||||
return false;
|
||||
} else if (has_bignum && cmd === "mode") {
|
||||
param = expr.substring(cmd.length + 1).trim();
|
||||
if (param === "") {
|
||||
std.puts("Running mode=" + eval_mode + "\n");
|
||||
} else if (param === "std" || param === "math") {
|
||||
eval_mode = param;
|
||||
} else {
|
||||
std.puts("Invalid mode\n");
|
||||
}
|
||||
return false;
|
||||
} else if (cmd === "clear") {
|
||||
std.puts("\x1b[H\x1b[J");
|
||||
} else if (cmd === "q") {
|
||||
std.exit(0);
|
||||
} else if (has_jscalc && cmd === "a") {
|
||||
algebraicMode = true;
|
||||
} else if (has_jscalc && cmd === "n") {
|
||||
algebraicMode = false;
|
||||
} else {
|
||||
std.puts("Unknown directive: " + cmd + "\n");
|
||||
return false;
|
||||
@ -1178,26 +1035,6 @@ import * as os from "os";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (config_numcalc) {
|
||||
/* called by the GUI */
|
||||
g.execCmd = function (cmd) {
|
||||
switch(cmd) {
|
||||
case "dec":
|
||||
hex_mode = false;
|
||||
break;
|
||||
case "hex":
|
||||
hex_mode = true;
|
||||
break;
|
||||
case "num":
|
||||
algebraicMode = false;
|
||||
break;
|
||||
case "alg":
|
||||
algebraicMode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function help() {
|
||||
function sel(n) {
|
||||
return n ? "*": " ";
|
||||
@ -1206,40 +1043,12 @@ import * as os from "os";
|
||||
"\\x " + sel(hex_mode) + "hexadecimal number display\n" +
|
||||
"\\d " + sel(!hex_mode) + "decimal number display\n" +
|
||||
"\\t " + sel(show_time) + "toggle timing display\n" +
|
||||
"\\clear clear the terminal\n");
|
||||
if (has_jscalc) {
|
||||
std.puts("\\a " + sel(algebraicMode) + "algebraic mode\n" +
|
||||
"\\n " + sel(!algebraicMode) + "numeric mode\n");
|
||||
}
|
||||
if (has_bignum) {
|
||||
std.puts("\\p [m [e]] set the BigFloat precision to 'm' bits\n" +
|
||||
"\\digits n set the BigFloat precision to 'ceil(n*log2(10))' bits\n");
|
||||
if (!has_jscalc) {
|
||||
std.puts("\\mode [std|math] change the running mode (current = " + eval_mode + ")\n");
|
||||
}
|
||||
}
|
||||
if (!config_numcalc) {
|
||||
std.puts("\\q exit\n");
|
||||
}
|
||||
"\\clear clear the terminal\n" +
|
||||
"\\q exit\n");
|
||||
}
|
||||
|
||||
function cmd_start() {
|
||||
if (!config_numcalc) {
|
||||
if (has_jscalc)
|
||||
std.puts('QJSCalc - Type "\\h" for help\n');
|
||||
else
|
||||
std.puts('QuickJS - Type "\\h" for help\n');
|
||||
}
|
||||
if (has_bignum) {
|
||||
log2_10 = Math.log(10) / Math.log(2);
|
||||
prec = 113;
|
||||
expBits = 15;
|
||||
if (has_jscalc) {
|
||||
eval_mode = "math";
|
||||
/* XXX: numeric mode should always be the default ? */
|
||||
g.algebraicMode = config_numcalc;
|
||||
}
|
||||
}
|
||||
std.puts('QuickJS - Type "\\h" for help\n');
|
||||
|
||||
cmd_readline_start();
|
||||
}
|
||||
@ -1247,7 +1056,7 @@ import * as os from "os";
|
||||
function cmd_readline_start() {
|
||||
readline_start(dupstr(" ", level), readline_handle_cmd);
|
||||
}
|
||||
|
||||
|
||||
function readline_handle_cmd(expr) {
|
||||
if (!handle_cmd(expr)) {
|
||||
cmd_readline_start();
|
||||
@ -1257,7 +1066,7 @@ import * as os from "os";
|
||||
/* return true if async termination */
|
||||
function handle_cmd(expr) {
|
||||
var colorstate, cmd;
|
||||
|
||||
|
||||
if (expr === null) {
|
||||
expr = "";
|
||||
return false;
|
||||
@ -1275,7 +1084,7 @@ import * as os from "os";
|
||||
}
|
||||
if (expr === "")
|
||||
return false;
|
||||
|
||||
|
||||
if (mexpr)
|
||||
expr = mexpr + '\n' + expr;
|
||||
colorstate = colorize_js(expr);
|
||||
@ -1286,38 +1095,28 @@ import * as os from "os";
|
||||
return false;
|
||||
}
|
||||
mexpr = "";
|
||||
|
||||
if (has_bignum) {
|
||||
/* XXX: async is not supported in this case */
|
||||
BigFloatEnv.setPrec(eval_and_print_start.bind(null, expr, false),
|
||||
prec, expBits);
|
||||
} else {
|
||||
eval_and_print_start(expr, true);
|
||||
}
|
||||
|
||||
eval_and_print_start(expr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function eval_and_print_start(expr, is_async) {
|
||||
function eval_and_print_start(expr) {
|
||||
var result;
|
||||
|
||||
|
||||
try {
|
||||
if (eval_mode === "math")
|
||||
expr = '"use math"; void 0;' + expr;
|
||||
eval_start_time = os.now();
|
||||
/* eval as a script */
|
||||
result = std.evalScript(expr, { backtrace_barrier: true, async: is_async });
|
||||
if (is_async) {
|
||||
/* result is a promise */
|
||||
result.then(print_eval_result, print_eval_error);
|
||||
} else {
|
||||
print_eval_result(result);
|
||||
}
|
||||
result = std.evalScript(expr, { backtrace_barrier: true, async: true });
|
||||
/* result is a promise */
|
||||
result.then(print_eval_result, print_eval_error);
|
||||
} catch (error) {
|
||||
print_eval_error(error);
|
||||
}
|
||||
}
|
||||
|
||||
function print_eval_result(result) {
|
||||
result = result.value;
|
||||
eval_time = os.now() - eval_start_time;
|
||||
std.puts(colors[styles.result]);
|
||||
print(result);
|
||||
@ -1341,7 +1140,7 @@ import * as os from "os";
|
||||
console.log(error);
|
||||
}
|
||||
std.puts(colors.none);
|
||||
|
||||
|
||||
handle_cmd_end();
|
||||
}
|
||||
|
||||
@ -1584,7 +1383,7 @@ import * as os from "os";
|
||||
}
|
||||
|
||||
termInit();
|
||||
|
||||
|
||||
cmd_start();
|
||||
|
||||
})(globalThis);
|
||||
|
192
run-test262.c
192
run-test262.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ECMA Test 262 Runner for QuickJS
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2021 Fabrice Bellard
|
||||
* Copyright (c) 2017-2021 Charlie Gordon
|
||||
*
|
||||
@ -63,6 +63,8 @@ enum test_mode_t {
|
||||
TEST_STRICT, /* run tests as strict, skip nostrict tests */
|
||||
TEST_ALL, /* run tests in both strict and nostrict, unless restricted by spec */
|
||||
} test_mode = TEST_DEFAULT_NOSTRICT;
|
||||
int compact;
|
||||
int show_timings;
|
||||
int skip_async;
|
||||
int skip_module;
|
||||
int new_style;
|
||||
@ -321,7 +323,7 @@ void namelist_load(namelist_t *lp, const char *filename)
|
||||
char *p = str_strip(buf);
|
||||
if (*p == '#' || *p == ';' || *p == '\0')
|
||||
continue; /* line comment */
|
||||
|
||||
|
||||
namelist_add(lp, base_name, p);
|
||||
}
|
||||
free(base_name);
|
||||
@ -457,11 +459,11 @@ static void *agent_start(void *arg)
|
||||
JSContext *ctx;
|
||||
JSValue ret_val;
|
||||
int ret;
|
||||
|
||||
|
||||
rt = JS_NewRuntime();
|
||||
if (rt == NULL) {
|
||||
fatal(1, "JS_NewRuntime failure");
|
||||
}
|
||||
}
|
||||
ctx = JS_NewContext(rt);
|
||||
if (ctx == NULL) {
|
||||
JS_FreeRuntime(rt);
|
||||
@ -470,7 +472,7 @@ static void *agent_start(void *arg)
|
||||
JS_SetContextOpaque(ctx, agent);
|
||||
JS_SetRuntimeInfo(rt, "agent");
|
||||
JS_SetCanBlock(rt, TRUE);
|
||||
|
||||
|
||||
add_helpers(ctx);
|
||||
ret_val = JS_Eval(ctx, agent->script, strlen(agent->script),
|
||||
"<evalScript>", JS_EVAL_TYPE_GLOBAL);
|
||||
@ -479,7 +481,7 @@ static void *agent_start(void *arg)
|
||||
if (JS_IsException(ret_val))
|
||||
js_std_dump_error(ctx);
|
||||
JS_FreeValue(ctx, ret_val);
|
||||
|
||||
|
||||
for(;;) {
|
||||
JSContext *ctx1;
|
||||
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
|
||||
@ -491,12 +493,12 @@ static void *agent_start(void *arg)
|
||||
break;
|
||||
} else {
|
||||
JSValue args[2];
|
||||
|
||||
|
||||
pthread_mutex_lock(&agent_mutex);
|
||||
while (!agent->broadcast_pending) {
|
||||
pthread_cond_wait(&agent_cond, &agent_mutex);
|
||||
}
|
||||
|
||||
|
||||
agent->broadcast_pending = FALSE;
|
||||
pthread_cond_signal(&agent_cond);
|
||||
|
||||
@ -530,10 +532,11 @@ static JSValue js_agent_start(JSContext *ctx, JSValue this_val,
|
||||
{
|
||||
const char *script;
|
||||
Test262Agent *agent;
|
||||
pthread_attr_t attr;
|
||||
|
||||
if (JS_GetContextOpaque(ctx) != NULL)
|
||||
return JS_ThrowTypeError(ctx, "cannot be called inside an agent");
|
||||
|
||||
|
||||
script = JS_ToCString(ctx, argv[0]);
|
||||
if (!script)
|
||||
return JS_EXCEPTION;
|
||||
@ -544,7 +547,12 @@ static JSValue js_agent_start(JSContext *ctx, JSValue this_val,
|
||||
agent->script = strdup(script);
|
||||
JS_FreeCString(ctx, script);
|
||||
list_add_tail(&agent->link, &agent_list);
|
||||
pthread_create(&agent->tid, NULL, agent_start, agent);
|
||||
pthread_attr_init(&attr);
|
||||
// musl libc gives threads 80 kb stacks, much smaller than
|
||||
// JS_DEFAULT_STACK_SIZE (256 kb)
|
||||
pthread_attr_setstacksize(&attr, 2 << 20); // 2 MB, glibc default
|
||||
pthread_create(&agent->tid, &attr, agent_start, agent);
|
||||
pthread_attr_destroy(&attr);
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
@ -552,7 +560,7 @@ static void js_agent_free(JSContext *ctx)
|
||||
{
|
||||
struct list_head *el, *el1;
|
||||
Test262Agent *agent;
|
||||
|
||||
|
||||
list_for_each_safe(el, el1, &agent_list) {
|
||||
agent = list_entry(el, Test262Agent, link);
|
||||
pthread_join(agent->tid, NULL);
|
||||
@ -561,7 +569,7 @@ static void js_agent_free(JSContext *ctx)
|
||||
free(agent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static JSValue js_agent_leaving(JSContext *ctx, JSValue this_val,
|
||||
int argc, JSValue *argv)
|
||||
{
|
||||
@ -593,16 +601,16 @@ static JSValue js_agent_broadcast(JSContext *ctx, JSValue this_val,
|
||||
uint8_t *buf;
|
||||
size_t buf_size;
|
||||
int32_t val;
|
||||
|
||||
|
||||
if (JS_GetContextOpaque(ctx) != NULL)
|
||||
return JS_ThrowTypeError(ctx, "cannot be called inside an agent");
|
||||
|
||||
|
||||
buf = JS_GetArrayBuffer(ctx, &buf_size, sab);
|
||||
if (!buf)
|
||||
return JS_EXCEPTION;
|
||||
if (JS_ToInt32(ctx, &val, argv[1]))
|
||||
return JS_EXCEPTION;
|
||||
|
||||
|
||||
/* broadcast the values and wait until all agents have started
|
||||
calling their callbacks */
|
||||
pthread_mutex_lock(&agent_mutex);
|
||||
@ -697,7 +705,7 @@ static JSValue js_agent_report(JSContext *ctx, JSValue this_val,
|
||||
rep = malloc(sizeof(*rep));
|
||||
rep->str = strdup(str);
|
||||
JS_FreeCString(ctx, str);
|
||||
|
||||
|
||||
pthread_mutex_lock(&report_mutex);
|
||||
list_add_tail(&rep->link, &report_list);
|
||||
pthread_mutex_unlock(&report_mutex);
|
||||
@ -717,7 +725,7 @@ static const JSCFunctionListEntry js_agent_funcs[] = {
|
||||
JS_CFUNC_DEF("sleep", 1, js_agent_sleep ),
|
||||
JS_CFUNC_DEF("monotonicNow", 0, js_agent_monotonicNow ),
|
||||
};
|
||||
|
||||
|
||||
static JSValue js_new_agent(JSContext *ctx)
|
||||
{
|
||||
JSValue agent;
|
||||
@ -733,7 +741,7 @@ static JSValue js_createRealm(JSContext *ctx, JSValue this_val,
|
||||
{
|
||||
JSContext *ctx1;
|
||||
JSValue ret;
|
||||
|
||||
|
||||
ctx1 = JS_NewContext(JS_GetRuntime(ctx));
|
||||
if (!ctx1)
|
||||
return JS_ThrowOutOfMemory(ctx);
|
||||
@ -749,11 +757,18 @@ static JSValue js_IsHTMLDDA(JSContext *ctx, JSValue this_val,
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
static JSValue js_gc(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
JS_RunGC(JS_GetRuntime(ctx));
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue add_helpers1(JSContext *ctx)
|
||||
{
|
||||
JSValue global_obj;
|
||||
JSValue obj262, obj;
|
||||
|
||||
|
||||
global_obj = JS_GetGlobalObject(ctx);
|
||||
|
||||
JS_SetPropertyStr(ctx, global_obj, "print",
|
||||
@ -782,9 +797,11 @@ static JSValue add_helpers1(JSContext *ctx)
|
||||
obj = JS_NewCFunction(ctx, js_IsHTMLDDA, "IsHTMLDDA", 0);
|
||||
JS_SetIsHTMLDDA(ctx, obj);
|
||||
JS_SetPropertyStr(ctx, obj262, "IsHTMLDDA", obj);
|
||||
JS_SetPropertyStr(ctx, obj262, "gc",
|
||||
JS_NewCFunction(ctx, js_gc, "gc", 0));
|
||||
|
||||
JS_SetPropertyStr(ctx, global_obj, "$262", JS_DupValue(ctx, obj262));
|
||||
|
||||
|
||||
JS_FreeValue(ctx, global_obj);
|
||||
return obj262;
|
||||
}
|
||||
@ -813,14 +830,27 @@ static JSModuleDef *js_module_loader_test(JSContext *ctx,
|
||||
uint8_t *buf;
|
||||
JSModuleDef *m;
|
||||
JSValue func_val;
|
||||
|
||||
char *filename, *slash, path[1024];
|
||||
|
||||
// interpret import("bar.js") from path/to/foo.js as
|
||||
// import("path/to/bar.js") but leave import("./bar.js") untouched
|
||||
filename = opaque;
|
||||
if (!strchr(module_name, '/')) {
|
||||
slash = strrchr(filename, '/');
|
||||
if (slash) {
|
||||
snprintf(path, sizeof(path), "%.*s/%s",
|
||||
(int)(slash - filename), filename, module_name);
|
||||
module_name = path;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -910,7 +940,7 @@ void update_exclude_dirs(void)
|
||||
lp->count = count;
|
||||
}
|
||||
|
||||
void load_config(const char *filename)
|
||||
void load_config(const char *filename, const char *ignore)
|
||||
{
|
||||
char buf[1024];
|
||||
FILE *f;
|
||||
@ -929,14 +959,14 @@ void load_config(const char *filename)
|
||||
perror_exit(1, filename);
|
||||
}
|
||||
base_name = get_basename(filename);
|
||||
|
||||
|
||||
while (fgets(buf, sizeof(buf), f) != NULL) {
|
||||
char *p, *q;
|
||||
lineno++;
|
||||
p = str_strip(buf);
|
||||
if (*p == '#' || *p == ';' || *p == '\0')
|
||||
continue; /* line comment */
|
||||
|
||||
|
||||
if (*p == "[]"[0]) {
|
||||
/* new section */
|
||||
p++;
|
||||
@ -965,6 +995,10 @@ void load_config(const char *filename)
|
||||
printf("%s:%d: syntax error\n", filename, lineno);
|
||||
continue;
|
||||
}
|
||||
if (strstr(ignore, p)) {
|
||||
printf("%s:%d: ignoring %s=%s\n", filename, lineno, p, q);
|
||||
continue;
|
||||
}
|
||||
if (str_equal(p, "style")) {
|
||||
new_style = str_equal(q, "new");
|
||||
continue;
|
||||
@ -1002,7 +1036,7 @@ void load_config(const char *filename)
|
||||
test_mode = TEST_STRICT;
|
||||
else if (str_equal(q, "all") || str_equal(q, "both"))
|
||||
test_mode = TEST_ALL;
|
||||
else
|
||||
else
|
||||
fatal(2, "unknown test mode: %s", q);
|
||||
continue;
|
||||
}
|
||||
@ -1143,7 +1177,7 @@ int longest_match(const char *str, const char *find, int pos, int *ppos, int lin
|
||||
int len, maxlen;
|
||||
|
||||
maxlen = 0;
|
||||
|
||||
|
||||
if (*find) {
|
||||
const char *p;
|
||||
for (p = str + pos; *p; p++) {
|
||||
@ -1176,7 +1210,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
int ret, error_line, pos, pos_line;
|
||||
BOOL is_error, has_error_line, ret_promise;
|
||||
const char *error_name;
|
||||
|
||||
|
||||
pos = skip_comments(buf, 1, &pos_line);
|
||||
error_line = pos_line;
|
||||
has_error_line = FALSE;
|
||||
@ -1186,7 +1220,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
/* a module evaluation returns a promise */
|
||||
ret_promise = ((eval_flags & JS_EVAL_TYPE_MODULE) != 0);
|
||||
async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */
|
||||
|
||||
|
||||
res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
|
||||
|
||||
if ((is_async || ret_promise) && !JS_IsException(res_val)) {
|
||||
@ -1239,7 +1273,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
if (is_error) {
|
||||
JSValue name, stack;
|
||||
const char *stack_str;
|
||||
|
||||
|
||||
name = JS_GetPropertyStr(ctx, exception_val, "name");
|
||||
error_name = JS_ToCString(ctx, name);
|
||||
stack = JS_GetPropertyStr(ctx, exception_val, "stack");
|
||||
@ -1248,10 +1282,10 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
if (stack_str) {
|
||||
const char *p;
|
||||
int len;
|
||||
|
||||
|
||||
if (outfile)
|
||||
fprintf(outfile, "%s", stack_str);
|
||||
|
||||
|
||||
len = strlen(filename);
|
||||
p = strstr(stack_str, filename);
|
||||
if (p != NULL && p[len] == ':') {
|
||||
@ -1269,7 +1303,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
if (error_type) {
|
||||
char *error_class;
|
||||
const char *msg;
|
||||
|
||||
|
||||
msg = JS_ToCString(ctx, exception_val);
|
||||
error_class = strdup_len(msg, strcspn(msg, ":"));
|
||||
if (!str_equal(error_class, error_type))
|
||||
@ -1393,7 +1427,7 @@ char *extract_desc(const char *buf, char style)
|
||||
const char *p, *desc_start;
|
||||
char *desc;
|
||||
int len;
|
||||
|
||||
|
||||
p = buf;
|
||||
while (*p != '\0') {
|
||||
if (p[0] == '/' && p[1] == '*' && p[2] == style && p[3] != '/') {
|
||||
@ -1525,11 +1559,11 @@ int run_test_buf(const char *filename, const char *harness, namelist_t *ip,
|
||||
JSRuntime *rt;
|
||||
JSContext *ctx;
|
||||
int i, ret;
|
||||
|
||||
|
||||
rt = JS_NewRuntime();
|
||||
if (rt == NULL) {
|
||||
fatal(1, "JS_NewRuntime failure");
|
||||
}
|
||||
}
|
||||
ctx = JS_NewContext(rt);
|
||||
if (ctx == NULL) {
|
||||
JS_FreeRuntime(rt);
|
||||
@ -1538,15 +1572,15 @@ int run_test_buf(const char *filename, const char *harness, namelist_t *ip,
|
||||
JS_SetRuntimeInfo(rt, filename);
|
||||
|
||||
JS_SetCanBlock(rt, can_block);
|
||||
|
||||
|
||||
/* loader for ES6 modules */
|
||||
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, NULL);
|
||||
|
||||
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, (void *)filename);
|
||||
|
||||
add_helpers(ctx);
|
||||
|
||||
for (i = 0; i < ip->count; i++) {
|
||||
if (eval_file(ctx, harness, ip->array[i],
|
||||
JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAG_STRIP)) {
|
||||
JS_EVAL_TYPE_GLOBAL)) {
|
||||
fatal(1, "error including %s for %s", ip->array[i], filename);
|
||||
}
|
||||
}
|
||||
@ -1554,7 +1588,7 @@ int run_test_buf(const char *filename, const char *harness, namelist_t *ip,
|
||||
ret = eval_buf(ctx, buf, buf_len, filename, TRUE, is_negative,
|
||||
error_type, outfile, eval_flags, is_async);
|
||||
ret = (ret != 0);
|
||||
|
||||
|
||||
if (dump_memory) {
|
||||
update_stats(rt, filename);
|
||||
}
|
||||
@ -1587,7 +1621,7 @@ int run_test(const char *filename, int index)
|
||||
BOOL is_negative, is_nostrict, is_onlystrict, is_async, is_module, skip;
|
||||
BOOL can_block;
|
||||
namelist_t include_list = { 0 }, *ip = &include_list;
|
||||
|
||||
|
||||
is_nostrict = is_onlystrict = is_negative = is_async = is_module = skip = FALSE;
|
||||
can_block = TRUE;
|
||||
error_type = NULL;
|
||||
@ -1656,7 +1690,7 @@ int run_test(const char *filename, int index)
|
||||
/* XXX: should extract the phase */
|
||||
char *q = find_tag(p, "type:", &state);
|
||||
if (q) {
|
||||
while (isspace(*q))
|
||||
while (isspace((unsigned char)*q))
|
||||
q++;
|
||||
error_type = strdup_len(q, strcspn(q, " \n"));
|
||||
}
|
||||
@ -1823,13 +1857,13 @@ int run_test262_harness_test(const char *filename, BOOL is_module)
|
||||
int eval_flags, ret_code, ret;
|
||||
JSValue res_val;
|
||||
BOOL can_block;
|
||||
|
||||
|
||||
outfile = stdout; /* for js_print */
|
||||
|
||||
rt = JS_NewRuntime();
|
||||
if (rt == NULL) {
|
||||
fatal(1, "JS_NewRuntime failure");
|
||||
}
|
||||
}
|
||||
ctx = JS_NewContext(rt);
|
||||
if (ctx == NULL) {
|
||||
JS_FreeRuntime(rt);
|
||||
@ -1839,10 +1873,10 @@ int run_test262_harness_test(const char *filename, BOOL is_module)
|
||||
|
||||
can_block = TRUE;
|
||||
JS_SetCanBlock(rt, can_block);
|
||||
|
||||
|
||||
/* loader for ES6 modules */
|
||||
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, NULL);
|
||||
|
||||
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, (void *)filename);
|
||||
|
||||
add_helpers(ctx);
|
||||
|
||||
buf = load_file(filename, &buf_len);
|
||||
@ -1900,9 +1934,27 @@ void show_progress(int force) {
|
||||
clock_t t = clock();
|
||||
if (force || !last_clock || (t - last_clock) > CLOCKS_PER_SEC / 20) {
|
||||
last_clock = t;
|
||||
/* output progress indicator: erase end of line and return to col 0 */
|
||||
fprintf(stderr, "%d/%d/%d\033[K\r",
|
||||
test_failed, test_count, test_skipped);
|
||||
if (compact) {
|
||||
static int last_test_skipped;
|
||||
static int last_test_failed;
|
||||
static int dots;
|
||||
char c = '.';
|
||||
if (test_skipped > last_test_skipped)
|
||||
c = '-';
|
||||
if (test_failed > last_test_failed)
|
||||
c = '!';
|
||||
last_test_skipped = test_skipped;
|
||||
last_test_failed = test_failed;
|
||||
fputc(c, stderr);
|
||||
if (force || ++dots % 60 == 0) {
|
||||
fprintf(stderr, " %d/%d/%d\n",
|
||||
test_failed, test_count, test_skipped);
|
||||
}
|
||||
} else {
|
||||
/* output progress indicator: erase end of line and return to col 0 */
|
||||
fprintf(stderr, "%d/%d/%d\033[K\r",
|
||||
test_failed, test_count, test_skipped);
|
||||
}
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
@ -1953,6 +2005,8 @@ void help(void)
|
||||
"-N run test prepared by test262-harness+eshost\n"
|
||||
"-s run tests in strict mode, skip @nostrict tests\n"
|
||||
"-E only run tests from the error file\n"
|
||||
"-C use compact progress indicator\n"
|
||||
"-t show timings\n"
|
||||
"-u update error file\n"
|
||||
"-v verbose: output error messages\n"
|
||||
"-T duration display tests taking more than 'duration' ms\n"
|
||||
@ -1979,14 +2033,29 @@ int main(int argc, char **argv)
|
||||
BOOL is_dir_list;
|
||||
BOOL only_check_errors = FALSE;
|
||||
const char *filename;
|
||||
const char *ignore = "";
|
||||
BOOL is_test262_harness = FALSE;
|
||||
BOOL is_module = FALSE;
|
||||
clock_t clocks;
|
||||
|
||||
#if !defined(_WIN32)
|
||||
compact = !isatty(STDERR_FILENO);
|
||||
/* Date tests assume California local time */
|
||||
setenv("TZ", "America/Los_Angeles", 1);
|
||||
#endif
|
||||
|
||||
optind = 1;
|
||||
while (optind < argc) {
|
||||
char *arg = argv[optind];
|
||||
if (*arg != '-')
|
||||
break;
|
||||
optind++;
|
||||
if (strstr("-c -d -e -x -f -r -E -T", arg))
|
||||
optind++;
|
||||
if (strstr("-d -f", arg))
|
||||
ignore = "testdir"; // run only the tests from -d or -f
|
||||
}
|
||||
|
||||
/* cannot use getopt because we want to pass the command line to
|
||||
the script */
|
||||
optind = 1;
|
||||
@ -2006,12 +2075,16 @@ int main(int argc, char **argv)
|
||||
test_mode = TEST_STRICT;
|
||||
} else if (str_equal(arg, "-a")) {
|
||||
test_mode = TEST_ALL;
|
||||
} else if (str_equal(arg, "-t")) {
|
||||
show_timings++;
|
||||
} else if (str_equal(arg, "-u")) {
|
||||
update_errors++;
|
||||
} else if (str_equal(arg, "-v")) {
|
||||
verbose++;
|
||||
} else if (str_equal(arg, "-C")) {
|
||||
compact = 1;
|
||||
} else if (str_equal(arg, "-c")) {
|
||||
load_config(get_opt_arg(arg, argv[optind++]));
|
||||
load_config(get_opt_arg(arg, argv[optind++]), ignore);
|
||||
} else if (str_equal(arg, "-d")) {
|
||||
enumerate_tests(get_opt_arg(arg, argv[optind++]));
|
||||
} else if (str_equal(arg, "-e")) {
|
||||
@ -2035,14 +2108,14 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (optind >= argc && !test_list.count)
|
||||
help();
|
||||
|
||||
if (is_test262_harness) {
|
||||
return run_test262_harness_test(argv[optind], is_module);
|
||||
}
|
||||
|
||||
|
||||
error_out = stdout;
|
||||
if (error_filename) {
|
||||
error_file = load_file(error_filename, NULL);
|
||||
@ -2062,8 +2135,10 @@ int main(int argc, char **argv)
|
||||
|
||||
update_exclude_dirs();
|
||||
|
||||
clocks = clock();
|
||||
|
||||
if (is_dir_list) {
|
||||
if (optind < argc && !isdigit(argv[optind][0])) {
|
||||
if (optind < argc && !isdigit((unsigned char)argv[optind][0])) {
|
||||
filename = argv[optind++];
|
||||
namelist_load(&test_list, filename);
|
||||
}
|
||||
@ -2098,6 +2173,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
clocks = clock() - clocks;
|
||||
|
||||
if (dump_memory) {
|
||||
if (dump_memory > 1 && stats_count > 1) {
|
||||
printf("\nMininum memory statistics for %s:\n\n", stats_min_filename);
|
||||
@ -2126,6 +2203,8 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr, ", %d fixed", fixed_errors);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
if (show_timings)
|
||||
fprintf(stderr, "Total time: %.3fs\n", (double)clocks / CLOCKS_PER_SEC);
|
||||
}
|
||||
|
||||
if (error_out && error_out != stdout) {
|
||||
@ -2141,5 +2220,6 @@ int main(int argc, char **argv)
|
||||
free(harness_exclude);
|
||||
free(error_file);
|
||||
|
||||
return 0;
|
||||
/* Signal that the error file is out of date. */
|
||||
return new_errors || changed_errors || fixed_errors;
|
||||
}
|
||||
|
154
test262.conf
154
test262.conf
@ -15,7 +15,7 @@ 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
|
||||
# and expect `print('Test262:AsyncTestComplete')` to be called for
|
||||
# successful termination
|
||||
async=yes
|
||||
|
||||
@ -61,7 +61,6 @@ Array.fromAsync=skip
|
||||
Array.prototype.at
|
||||
Array.prototype.flat
|
||||
Array.prototype.flatMap
|
||||
Array.prototype.flatten
|
||||
Array.prototype.includes
|
||||
Array.prototype.values
|
||||
ArrayBuffer
|
||||
@ -70,9 +69,11 @@ arrow-function
|
||||
async-functions
|
||||
async-iteration
|
||||
Atomics
|
||||
Atomics.pause=skip
|
||||
Atomics.waitAsync=skip
|
||||
BigInt
|
||||
caller
|
||||
canonical-tz=skip
|
||||
change-array-by-copy
|
||||
class
|
||||
class-fields-private
|
||||
@ -83,7 +84,6 @@ class-static-block
|
||||
class-static-fields-private
|
||||
class-static-fields-public
|
||||
class-static-methods-private
|
||||
cleanupSome=skip
|
||||
coalesce-expression
|
||||
computed-property-names
|
||||
const
|
||||
@ -103,11 +103,12 @@ destructuring-assignment
|
||||
destructuring-binding
|
||||
dynamic-import
|
||||
error-cause
|
||||
Error.isError=skip
|
||||
explicit-resource-management=skip
|
||||
exponentiation
|
||||
export-star-as-namespace-from-module
|
||||
FinalizationGroup=skip
|
||||
FinalizationRegistry.prototype.cleanupSome=skip
|
||||
FinalizationRegistry=skip
|
||||
FinalizationRegistry
|
||||
Float16Array=skip
|
||||
Float32Array
|
||||
Float64Array
|
||||
for-in-order
|
||||
@ -118,12 +119,31 @@ hashbang
|
||||
host-gc-required=skip
|
||||
import-assertions=skip
|
||||
import-attributes=skip
|
||||
import-defer=skip
|
||||
import.meta
|
||||
Int16Array
|
||||
Int32Array
|
||||
Int8Array
|
||||
Intl-enumeration=skip
|
||||
intl-normative-optional=skip
|
||||
Intl.DateTimeFormat-datetimestyle=skip
|
||||
Intl.DateTimeFormat-dayPeriod=skip
|
||||
Intl.DateTimeFormat-extend-timezonename=skip
|
||||
Intl.DateTimeFormat-formatRange=skip
|
||||
Intl.DateTimeFormat-fractionalSecondDigits=skip
|
||||
Intl.DisplayNames-v2=skip
|
||||
Intl.DisplayNames=skip
|
||||
Intl.DurationFormat=skip
|
||||
Intl.ListFormat=skip
|
||||
Intl.Locale-info=skip
|
||||
Intl.Locale=skip
|
||||
Intl.NumberFormat-unified=skip
|
||||
Intl.NumberFormat-v3=skip
|
||||
Intl.RelativeTimeFormat=skip
|
||||
Intl.Segmenter=skip
|
||||
IsHTMLDDA
|
||||
iterator-helpers=skip
|
||||
iterator-sequencing=skip
|
||||
json-modules=skip
|
||||
json-parse-with-source=skip
|
||||
json-superset
|
||||
@ -131,6 +151,7 @@ legacy-regexp=skip
|
||||
let
|
||||
logical-assignment-operators
|
||||
Map
|
||||
Math.sumPrecise=skip
|
||||
new.target
|
||||
numeric-separator-literal
|
||||
object-rest
|
||||
@ -141,6 +162,7 @@ Object.is
|
||||
optional-catch-binding
|
||||
optional-chaining
|
||||
Promise
|
||||
promise-try=skip
|
||||
promise-with-resolvers
|
||||
Promise.allSettled
|
||||
Promise.any
|
||||
@ -155,15 +177,19 @@ regexp-dotall
|
||||
regexp-duplicate-named-groups=skip
|
||||
regexp-lookbehind
|
||||
regexp-match-indices
|
||||
regexp-modifiers=skip
|
||||
regexp-named-groups
|
||||
regexp-unicode-property-escapes
|
||||
regexp-v-flag=skip
|
||||
RegExp.escape=skip
|
||||
resizable-arraybuffer=skip
|
||||
rest-parameters
|
||||
Set
|
||||
set-methods=skip
|
||||
ShadowRealm=skip
|
||||
SharedArrayBuffer
|
||||
source-phase-imports-module-source=skip
|
||||
source-phase-imports=skip
|
||||
string-trimming
|
||||
String.fromCodePoint
|
||||
String.prototype.at
|
||||
@ -191,7 +217,7 @@ Symbol.split
|
||||
Symbol.toPrimitive
|
||||
Symbol.toStringTag
|
||||
Symbol.unscopables
|
||||
symbols-as-weakmap-keys=skip
|
||||
symbols-as-weakmap-keys
|
||||
tail-call-optimization=skip
|
||||
template
|
||||
Temporal=skip
|
||||
@ -202,9 +228,10 @@ u180e
|
||||
Uint16Array
|
||||
Uint32Array
|
||||
Uint8Array
|
||||
uint8array-base64=skip
|
||||
Uint8ClampedArray
|
||||
WeakMap
|
||||
WeakRef=skip
|
||||
WeakRef
|
||||
WeakSet
|
||||
well-formed-json-stringify
|
||||
|
||||
@ -223,5 +250,116 @@ test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
|
||||
#test262/test/built-ins/RegExp/CharacterClassEscapes/
|
||||
#test262/test/built-ins/RegExp/property-escapes/
|
||||
|
||||
# feature regexp-v-flag is missing in the tests
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-positive-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-positive-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-positive-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-positive-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-positive-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-positive-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-positive-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-positive-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-positive-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-positive-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-negative-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-positive-cases.js
|
||||
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-positive-cases.js
|
||||
|
||||
# not yet in official specification
|
||||
test262/test/built-ins/String/prototype/match/cstm-matcher-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/match/cstm-matcher-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/match/cstm-matcher-on-boolean-primitive.js
|
||||
test262/test/built-ins/String/prototype/match/cstm-matcher-on-boolean-primitive.js
|
||||
test262/test/built-ins/String/prototype/match/cstm-matcher-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/match/cstm-matcher-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/match/cstm-matcher-on-string-primitive.js
|
||||
test262/test/built-ins/String/prototype/match/cstm-matcher-on-string-primitive.js
|
||||
test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-string-primitive.js
|
||||
test262/test/built-ins/String/prototype/matchAll/cstm-matchall-on-string-primitive.js
|
||||
test262/test/built-ins/String/prototype/replace/cstm-replace-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/replace/cstm-replace-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/replace/cstm-replace-on-boolean-primitive.js
|
||||
test262/test/built-ins/String/prototype/replace/cstm-replace-on-boolean-primitive.js
|
||||
test262/test/built-ins/String/prototype/replace/cstm-replace-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/replace/cstm-replace-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/replace/cstm-replace-on-string-primitive.js
|
||||
test262/test/built-ins/String/prototype/replace/cstm-replace-on-string-primitive.js
|
||||
test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-boolean-primitive.js
|
||||
test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-boolean-primitive.js
|
||||
test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-string-primitive.js
|
||||
test262/test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-string-primitive.js
|
||||
test262/test/built-ins/String/prototype/search/cstm-search-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/search/cstm-search-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/search/cstm-search-on-boolean-primitive.js
|
||||
test262/test/built-ins/String/prototype/search/cstm-search-on-boolean-primitive.js
|
||||
test262/test/built-ins/String/prototype/search/cstm-search-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/search/cstm-search-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/search/cstm-search-on-string-primitive.js
|
||||
test262/test/built-ins/String/prototype/search/cstm-search-on-string-primitive.js
|
||||
test262/test/built-ins/String/prototype/split/cstm-split-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/split/cstm-split-on-bigint-primitive.js
|
||||
test262/test/built-ins/String/prototype/split/cstm-split-on-boolean-primitive.js
|
||||
test262/test/built-ins/String/prototype/split/cstm-split-on-boolean-primitive.js
|
||||
test262/test/built-ins/String/prototype/split/cstm-split-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/split/cstm-split-on-number-primitive.js
|
||||
test262/test/built-ins/String/prototype/split/cstm-split-on-string-primitive.js
|
||||
test262/test/built-ins/String/prototype/split/cstm-split-on-string-primitive.js
|
||||
|
||||
####################################
|
||||
# staging tests
|
||||
|
||||
# sort() does not modify the array and we don't update it (XXX: the
|
||||
# spec updates it in this case)
|
||||
test262/test/staging/sm/Array/frozen-dense-array.js
|
||||
|
||||
# not supported
|
||||
test262/test/staging/sm/Set/difference.js
|
||||
test262/test/staging/sm/Set/intersection.js
|
||||
test262/test/staging/sm/Set/is-disjoint-from.js
|
||||
test262/test/staging/sm/Set/is-subset-of.js
|
||||
test262/test/staging/sm/Set/is-superset-of.js
|
||||
test262/test/staging/sm/Set/symmetric-difference.js
|
||||
test262/test/staging/sm/Set/union.js
|
||||
test262/test/staging/sm/extensions/censor-strict-caller.js
|
||||
test262/test/staging/sm/JSON/parse-with-source.js
|
||||
test262/test/staging/sm/RegExp/flags.js
|
||||
test262/test/staging/sm/RegExp/prototype.js
|
||||
|
||||
# no f16
|
||||
test262/test/staging/sm/Math/f16round.js
|
||||
test262/test/staging/sm/TypedArray/sort_small.js
|
||||
test262/test/staging/sm/extensions/dataview.js
|
||||
test262/test/staging/sm/TypedArray/toString.js
|
||||
|
||||
# not standard
|
||||
test262/test/staging/sm/Function/builtin-no-construct.js
|
||||
test262/test/staging/sm/Function/function-caller-restrictions.js
|
||||
test262/test/staging/sm/Function/function-toString-builtin-name.js
|
||||
test262/test/staging/sm/extensions/arguments-property-access-in-function.js
|
||||
test262/test/staging/sm/extensions/function-caller-skips-eval-frames.js
|
||||
test262/test/staging/sm/extensions/function-properties.js
|
||||
# RegExp toSource not fully compliant
|
||||
test262/test/staging/sm/RegExp/toString.js
|
||||
test262/test/staging/sm/RegExp/source.js
|
||||
|
||||
[tests]
|
||||
# list test files or use config.testdir
|
||||
|
@ -1,8 +1,72 @@
|
||||
test262/test/annexB/language/eval-code/direct/script-decl-lex-collision-in-sloppy-mode.js:13: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
|
||||
test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: Test262Error: Expected a DummyError but got a TypeError
|
||||
test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError
|
||||
test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: Test262Error: Expected a DummyError but got a TypeError
|
||||
test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError
|
||||
test262/test/language/expressions/in/private-field-invalid-assignment-target.js:23: unexpected error type: Test262: This statement should not be evaluated.
|
||||
test262/test/language/expressions/in/private-field-invalid-assignment-target.js:23: strict mode: unexpected error type: Test262: This statement should not be evaluated.
|
||||
test262/test/language/global-code/script-decl-lex-var-declared-via-eval-sloppy.js:13: Test262Error: variable Expected a SyntaxError to be thrown but no exception was thrown at all
|
||||
test262/test/language/module-code/top-level-await/module-graphs-does-not-hang.js:10: TypeError: $DONE() not called
|
||||
test262/test/staging/sm/Date/UTC-convert-all-arguments.js:75: Test262Error: index 1: expected 42, got Error: didn't throw Expected SameValue(«Error: didn't throw», «42») to be true
|
||||
test262/test/staging/sm/Date/constructor-convert-all-arguments.js:75: Test262Error: index undefined: expected 42, got Error: didn't throw Expected SameValue(«Error: didn't throw», «42») to be true
|
||||
test262/test/staging/sm/Date/non-iso.js:76: Test262Error: Expected SameValue(«NaN», «-40071559730000») to be true
|
||||
test262/test/staging/sm/Date/two-digit-years.js:76: Test262Error: Expected SameValue(«915177600000», «NaN») to be true
|
||||
test262/test/staging/sm/Function/arguments-parameter-shadowing.js:15: Test262Error: Expected SameValue(«true», «false») to be true
|
||||
test262/test/staging/sm/Function/constructor-binding.js:12: Test262Error: Expected SameValue(«"function"», «"undefined"») to be true
|
||||
test262/test/staging/sm/Function/function-bind.js:14: Test262Error: Expected SameValue(«false», «true») to be true
|
||||
test262/test/staging/sm/Function/function-name-for.js:12: Test262Error: Expected SameValue(«""», «"forInHead"») to be true
|
||||
test262/test/staging/sm/Function/function-toString-builtin.js:14: Test262Error: Expected match to '/^\s*function\s*(get|set)?\s*(\w+|(?:'[^']*')|(?:"[^"]*")|\d+|(?:\[[^\]]+\]))?\s*\(\s*\)\s*\{\s*\[native code\]\s*\}\s*$/', Actual value 'function bound fn() {
|
||||
[native code]
|
||||
}' Expected SameValue(«null», «null») to be false
|
||||
test262/test/staging/sm/Function/implicit-this-in-parameter-expression.js:13: Test262Error: Expected SameValue(«[object Object]», «undefined») to be true
|
||||
test262/test/staging/sm/Function/invalid-parameter-list.js:35: Error: Assertion failed: expected exception SyntaxError, no exception thrown
|
||||
test262/test/staging/sm/JSON/parse-number-syntax.js:39: Test262Error: parsing string <1.> threw a non-SyntaxError exception: Test262Error: string <1.> shouldn't have parsed as JSON Expected SameValue(«false», «true») to be true Expected SameValue(«true», «false») to be true
|
||||
test262/test/staging/sm/JSON/parse-syntax-errors-02.js:51: Test262Error: parsing string <["Illegal backslash escape: \x15"]> threw a non-SyntaxError exception: Test262Error: string <["Illegal backslash escape: \x15"]> shouldn't have parsed as JSON Expected SameValue(«false», «true») to be true Expected SameValue(«true», «false») to be true
|
||||
test262/test/staging/sm/Math/cbrt-approx.js:26: Error: got 1.39561242508609, expected a number near 1.3956124250860895 (relative error: 2)
|
||||
test262/test/staging/sm/RegExp/constructor-ordering-2.js:15: Test262Error: Expected SameValue(«false», «true») to be true
|
||||
test262/test/staging/sm/RegExp/escape.js:13: Test262Error: Expected SameValue(«"\\\n"», «"\\n"») to be true
|
||||
test262/test/staging/sm/RegExp/match-trace.js:13: Test262Error: Expected SameValue(«"get:flags,get:unicode,set:lastIndex,get:exec,call:exec,get:result[0],get:exec,call:exec,get:result[0],get:exec,call:exec,"», «"get:flags,set:lastIndex,get:exec,call:exec,get:result[0],get:exec,call:exec,get:result[0],get:exec,call:exec,"») to be true
|
||||
test262/test/staging/sm/RegExp/regress-613820-1.js:13: Test262Error: Expected SameValue(«"aaa"», «"aa"») to be true
|
||||
test262/test/staging/sm/RegExp/regress-613820-2.js:13: Test262Error: Expected SameValue(«"f"», «undefined») to be true
|
||||
test262/test/staging/sm/RegExp/regress-613820-3.js:13: Test262Error: Expected SameValue(«"aab"», «"aa"») to be true
|
||||
test262/test/staging/sm/RegExp/replace-trace.js:13: Test262Error: Expected SameValue(«"get:flags,get:unicode,set:lastIndex,get:exec,call:exec,get:result[0],get:exec,call:exec,get:result[length],get:result[0],get:result[index],get:result[groups],"», «"get:flags,set:lastIndex,get:exec,call:exec,get:result[0],get:exec,call:exec,get:result[length],get:result[0],get:result[index],get:result[groups],"») to be true
|
||||
test262/test/staging/sm/RegExp/unicode-ignoreCase-escape.js:22: Test262Error: Actual argument shouldn't be nullish.
|
||||
test262/test/staging/sm/RegExp/unicode-ignoreCase-word-boundary.js:13: Test262Error: Expected SameValue(«false», «true») to be true
|
||||
test262/test/staging/sm/String/match-defines-match-elements.js:52: Test262Error: Expected SameValue(«true», «false») to be true
|
||||
test262/test/staging/sm/TypedArray/constructor-buffer-sequence.js:73: Error: Assertion failed: expected exception ExpectedError, got Error: Poisoned Value
|
||||
test262/test/staging/sm/TypedArray/prototype-constructor-identity.js:17: Test262Error: Expected SameValue(«2», «6») to be true
|
||||
test262/test/staging/sm/TypedArray/set-detached-bigint.js:27: Error: Assertion failed: expected exception SyntaxError, got RangeError: invalid array length
|
||||
test262/test/staging/sm/TypedArray/set-detached.js:112: RangeError: invalid array length
|
||||
test262/test/staging/sm/TypedArray/sort-negative-nan.js:102: TypeError: cannot read property 'name' of undefined
|
||||
test262/test/staging/sm/TypedArray/sort_modifications.js:12: Test262Error: Int8Array at index 0 for size 4 Expected SameValue(«0», «1») to be true
|
||||
test262/test/staging/sm/TypedArray/subarray.js:15: Test262Error: Expected SameValue(«0», «1») to be true
|
||||
test262/test/staging/sm/async-functions/async-contains-unicode-escape.js:45: Error: Assertion failed: expected exception SyntaxError, no exception thrown
|
||||
test262/test/staging/sm/async-functions/await-error.js:12: Test262Error: Expected SameValue(«false», «true») to be true
|
||||
test262/test/staging/sm/async-functions/await-in-arrow-parameters.js:33: Error: Assertion failed: expected exception SyntaxError, no exception thrown - AsyncFunction:(a = (b = await/r/g) => {}) => {}
|
||||
test262/test/staging/sm/class/boundFunctionSubclassing.js:12: Test262Error: Expected SameValue(«false», «true») to be true
|
||||
test262/test/staging/sm/class/compPropNames.js:26: Error: Expected syntax error: ({[1, 2]: 3})
|
||||
test262/test/staging/sm/class/methDefn.js:26: Error: Expected syntax error: b = {a() => 0}
|
||||
test262/test/staging/sm/class/strictExecution.js:32: Error: Assertion failed: expected exception TypeError, no exception thrown
|
||||
test262/test/staging/sm/class/superPropOrdering.js:83: Error: Assertion failed: expected exception TypeError, no exception thrown
|
||||
test262/test/staging/sm/expressions/optional-chain.js:25: Error: Assertion failed: expected exception SyntaxError, no exception thrown
|
||||
test262/test/staging/sm/expressions/short-circuit-compound-assignment-const.js:97: TypeError: 'a' is read-only
|
||||
test262/test/staging/sm/expressions/short-circuit-compound-assignment-tdz.js:23: Error: Assertion failed: expected exception ReferenceError, got TypeError: 'a' is read-only
|
||||
test262/test/staging/sm/extensions/TypedArray-set-object-funky-length-detaches.js:55: RangeError: invalid array length
|
||||
test262/test/staging/sm/extensions/regress-469625-01.js:16: Test262Error: TM: Array prototype and expression closures Expected SameValue(«"TypeError: [].__proto__ is not a function"», «"TypeError: not a function"») to be true
|
||||
test262/test/staging/sm/generators/syntax.js:30: Error: Assertion failed: expected SyntaxError, but no exception thrown - function* g() { (function* yield() {}); }
|
||||
test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-arguments.js:14: Test262Error: Expected SameValue(«"object"», «"function"») to be true
|
||||
test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-eval.js:12: Test262Error: Expected SameValue(«"outer-gouter-geval-gtruefalseq"», «"outer-geval-gwith-gtruefalseq"») to be true
|
||||
test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-if.js:20: TypeError: not a function
|
||||
test262/test/staging/sm/lexical-environment/block-scoped-functions-annex-b-notapplicable.js:15: Test262Error: Expected SameValue(«function x() {2}», «function x() {1}») to be true
|
||||
test262/test/staging/sm/lexical-environment/block-scoped-functions-deprecated-redecl.js:23: Test262Error: Expected SameValue(«3», «4») to be true
|
||||
test262/test/staging/sm/lexical-environment/unscopables-proto.js:15: Test262Error: Expected SameValue(«true», «false») to be true
|
||||
test262/test/staging/sm/lexical-environment/var-in-catch-body-annex-b-eval.js:17: Test262Error: Expected SameValue(«"g"», «"global-x"») to be true
|
||||
test262/test/staging/sm/module/module-export-name-star.js:15: SyntaxError: identifier expected
|
||||
test262/test/staging/sm/object/defineProperties-order.js:14: Test262Error: Expected SameValue(«"ownKeys,getOwnPropertyDescriptor,getOwnPropertyDescriptor,get,get"», «"ownKeys,getOwnPropertyDescriptor,get,getOwnPropertyDescriptor,get"») to be true
|
||||
test262/test/staging/sm/object/defineProperty-proxy.js:32: Test262Error: Expected ["has configurable", "get configurable", "has writable", "get writable", "has enumerable", "get enumerable", "has value", "get value", "has get", "has set"] to be structurally equal to ["has enumerable", "get enumerable", "has configurable", "get configurable", "has value", "get value", "has writable", "get writable", "has get", "has set"].
|
||||
test262/test/staging/sm/regress/regress-577648-1.js:21: Test262Error: 1 Expected SameValue(«true», «false») to be true
|
||||
test262/test/staging/sm/regress/regress-577648-2.js:14: Test262Error: Expected SameValue(«true», «false») to be true
|
||||
test262/test/staging/sm/regress/regress-584355.js:12: Test262Error: Expected SameValue(«"function f () { ff (); }"», «"undefined"») to be true
|
||||
test262/test/staging/sm/regress/regress-586482-1.js:19: Test262Error: ok Expected SameValue(«true», «false») to be true
|
||||
test262/test/staging/sm/regress/regress-586482-2.js:19: Test262Error: ok Expected SameValue(«true», «false») to be true
|
||||
test262/test/staging/sm/regress/regress-586482-3.js:18: Test262Error: ok Expected SameValue(«true», «false») to be true
|
||||
test262/test/staging/sm/regress/regress-586482-4.js:14: Test262Error: ok Expected SameValue(«function() { this.f(); }», «undefined») to be true
|
||||
test262/test/staging/sm/regress/regress-602621.js:14: Test262Error: function sub-statement must override arguments Expected SameValue(«"function"», «"object"») to be true
|
||||
test262/test/staging/sm/regress/regress-699682.js:15: Test262Error: Expected SameValue(«false», «true») to be true
|
||||
test262/test/staging/sm/regress/regress-1383630.js:30: Error: Assertion failed: expected exception TypeError, no exception thrown
|
||||
test262/test/staging/sm/statements/arrow-function-in-for-statement-head.js:15: Test262Error: expected syntax error, got Error: didn't throw Expected SameValue(«false», «true») to be true
|
||||
test262/test/staging/sm/statements/regress-642975.js:14: Test262Error: Expected SameValue(«undefined», «"y"») to be true
|
||||
test262/test/staging/sm/statements/try-completion.js:17: Test262Error: Expected SameValue(«"try"», «undefined») to be true
|
||||
test262/test/staging/sm/syntax/syntax-parsed-arrow-then-directive.js:77: Test262Error: stack should contain 'http://example.com/foo.js': block, semi Expected SameValue(«false», «true») to be true
|
||||
|
@ -406,5 +406,8 @@ 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
|
||||
|
||||
# String.prototype.localeCompare special cases
|
||||
test262o/test/suite/ch15/15.5/15.5.4/15.5.4.9/15.5.4.9_CE.js
|
||||
|
||||
[tests]
|
||||
# list test files or use config.testdir
|
||||
|
49
tests/assert.js
Normal file
49
tests/assert.js
Normal file
@ -0,0 +1,49 @@
|
||||
export function assert(actual, expected, message) {
|
||||
if (arguments.length === 1)
|
||||
expected = true;
|
||||
|
||||
if (typeof actual === typeof expected) {
|
||||
if (actual === expected) {
|
||||
if (actual !== 0 || (1 / actual) === (1 / expected))
|
||||
return;
|
||||
}
|
||||
if (typeof actual === 'number') {
|
||||
if (isNaN(actual) && isNaN(expected))
|
||||
return;
|
||||
}
|
||||
if (typeof actual === 'object') {
|
||||
if (actual !== null && expected !== null
|
||||
&& actual.constructor === expected.constructor
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
export function assertThrows(err, func)
|
||||
{
|
||||
var ex;
|
||||
ex = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
ex = true;
|
||||
assert(e instanceof err);
|
||||
}
|
||||
assert(ex, true, "exception expected");
|
||||
}
|
||||
|
||||
export function assertArrayEquals(a, b)
|
||||
{
|
||||
if (!Array.isArray(a) || !Array.isArray(b))
|
||||
return assert(false);
|
||||
|
||||
assert(a.length, b.length);
|
||||
|
||||
a.forEach((value, idx) => {
|
||||
assert(b[idx], value);
|
||||
});
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
@ -32,7 +32,7 @@ static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
|
||||
JSValue obj;
|
||||
size_t size;
|
||||
int flags;
|
||||
|
||||
|
||||
if (JS_ToIndex(ctx, &pos, argv[1]))
|
||||
return JS_EXCEPTION;
|
||||
if (JS_ToIndex(ctx, &len, argv[2]))
|
||||
@ -56,7 +56,7 @@ static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
|
||||
uint8_t *buf;
|
||||
JSValue array;
|
||||
int flags;
|
||||
|
||||
|
||||
flags = 0;
|
||||
if (JS_ToBool(ctx, argv[1]))
|
||||
flags |= JS_WRITE_OBJ_REFERENCE;
|
||||
|
2
tests/fixture_cyclic_import.js
Normal file
2
tests/fixture_cyclic_import.js
Normal file
@ -0,0 +1,2 @@
|
||||
import * as a from "./test_cyclic_import.js"
|
||||
export function f(x) { return 2 * a.g(x) }
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
diff --git a/harness/atomicsHelper.js b/harness/atomicsHelper.js
|
||||
index 9c1217351e..3c24755558 100644
|
||||
index 9828b15..4a5919d 100644
|
||||
--- a/harness/atomicsHelper.js
|
||||
+++ b/harness/atomicsHelper.js
|
||||
@@ -227,10 +227,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) {
|
||||
@@ -272,10 +272,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) {
|
||||
* }
|
||||
*/
|
||||
$262.agent.timeouts = {
|
||||
@ -22,11 +22,11 @@ index 9c1217351e..3c24755558 100644
|
||||
|
||||
/**
|
||||
diff --git a/harness/regExpUtils.js b/harness/regExpUtils.js
|
||||
index be7039fda0..7b38abf8df 100644
|
||||
index b397be0..c197ddc 100644
|
||||
--- a/harness/regExpUtils.js
|
||||
+++ b/harness/regExpUtils.js
|
||||
@@ -6,24 +6,27 @@ description: |
|
||||
defines: [buildString, testPropertyEscapes, matchValidator]
|
||||
@@ -6,27 +6,30 @@ description: |
|
||||
defines: [buildString, testPropertyEscapes, testPropertyOfStrings, testExtendedCharacterClass, matchValidator]
|
||||
---*/
|
||||
|
||||
+if ($262 && typeof $262.codePointRange === "function") {
|
||||
@ -44,28 +44,62 @@ index be7039fda0..7b38abf8df 100644
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
function buildString({ loneCodePoints, ranges }) {
|
||||
function buildString(args) {
|
||||
// Use member expressions rather than destructuring `args` for improved
|
||||
// compatibility with engines that only implement assignment patterns
|
||||
// partially or not at all.
|
||||
const loneCodePoints = args.loneCodePoints;
|
||||
const ranges = args.ranges;
|
||||
- const CHUNK_SIZE = 10000;
|
||||
- let result = Reflect.apply(String.fromCodePoint, null, loneCodePoints);
|
||||
let result = String.fromCodePoint.apply(null, loneCodePoints);
|
||||
- for (let i = 0; i < ranges.length; i++) {
|
||||
- const range = ranges[i];
|
||||
- const start = range[0];
|
||||
- const end = range[1];
|
||||
- const codePoints = [];
|
||||
- let range = ranges[i];
|
||||
- let start = range[0];
|
||||
- let end = range[1];
|
||||
- let codePoints = [];
|
||||
- for (let length = 0, codePoint = start; codePoint <= end; codePoint++) {
|
||||
- codePoints[length++] = codePoint;
|
||||
- if (length === CHUNK_SIZE) {
|
||||
- result += Reflect.apply(String.fromCodePoint, null, codePoints);
|
||||
- result += String.fromCodePoint.apply(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;
|
||||
- }
|
||||
- result += String.fromCodePoint.apply(null, codePoints);
|
||||
+ for (const [start, end] of ranges) {
|
||||
+ result += codePointRange(start, end + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
diff --git a/harness/sm/non262.js b/harness/sm/non262.js
|
||||
index c1829e3..3a3ee27 100644
|
||||
--- a/harness/sm/non262.js
|
||||
+++ b/harness/sm/non262.js
|
||||
@@ -41,8 +41,6 @@ globalThis.createNewGlobal = function() {
|
||||
return $262.createRealm().global
|
||||
}
|
||||
|
||||
function testPropertyEscapes(regex, string, expression) {
|
||||
-function print(...args) {
|
||||
-}
|
||||
function assertEq(...args) {
|
||||
assert.sameValue(...args)
|
||||
}
|
||||
@@ -71,4 +69,4 @@ if (globalThis.createExternalArrayBuffer === undefined) {
|
||||
if (globalThis.enableGeckoProfilingWithSlowAssertions === undefined) {
|
||||
globalThis.enableGeckoProfilingWithSlowAssertions = globalThis.enableGeckoProfiling =
|
||||
globalThis.disableGeckoProfiling = () => {}
|
||||
-}
|
||||
\ No newline at end of file
|
||||
+}
|
||||
diff --git a/test/staging/sm/misc/new-with-non-constructor.js b/test/staging/sm/misc/new-with-non-constructor.js
|
||||
index 18c2f0c..f9aa209 100644
|
||||
--- a/test/staging/sm/misc/new-with-non-constructor.js
|
||||
+++ b/test/staging/sm/misc/new-with-non-constructor.js
|
||||
@@ -16,7 +16,7 @@ function checkConstruct(thing) {
|
||||
new thing();
|
||||
assert.sameValue(0, 1, "not reached " + thing);
|
||||
} catch (e) {
|
||||
- assert.sameValue(e.message.includes(" is not a constructor") ||
|
||||
+ assert.sameValue(e.message.includes("not a constructor") ||
|
||||
e.message === "Function.prototype.toString called on incompatible object", true);
|
||||
}
|
||||
}
|
||||
|
249
tests/test_bigint.js
Normal file
249
tests/test_bigint.js
Normal file
@ -0,0 +1,249 @@
|
||||
"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_bigint3()
|
||||
{
|
||||
assert(Number(0xffffffffffffffffn), 18446744073709552000);
|
||||
assert(Number(-0xffffffffffffffffn), -18446744073709552000);
|
||||
assert(100000000000000000000n == 1e20, true);
|
||||
assert(100000000000000000001n == 1e20, false);
|
||||
assert((1n << 100n).toString(10), "1267650600228229401496703205376");
|
||||
assert((-1n << 100n).toString(36), "-3ewfdnca0n6ld1ggvfgg");
|
||||
assert((1n << 100n).toString(8), "2000000000000000000000000000000000");
|
||||
|
||||
assert(0x5a4653ca673768565b41f775n << 78n, 8443945299673273647701379149826607537748959488376832n);
|
||||
assert(-0x5a4653ca673768565b41f775n << 78n, -8443945299673273647701379149826607537748959488376832n);
|
||||
assert(0x5a4653ca673768565b41f775n >> 78n, 92441n);
|
||||
assert(-0x5a4653ca673768565b41f775n >> 78n, -92442n);
|
||||
|
||||
assert(~0x5a653ca6n, -1516584103n);
|
||||
assert(0x5a463ca6n | 0x67376856n, 2138537206n);
|
||||
assert(0x5a463ca6n & 0x67376856n, 1107699718n);
|
||||
assert(0x5a463ca6n ^ 0x67376856n, 1030837488n);
|
||||
|
||||
assert(3213213213213213432453243n / 123434343439n, 26031760073331n);
|
||||
assert(-3213213213213213432453243n / 123434343439n, -26031760073331n);
|
||||
assert(-3213213213213213432453243n % -123434343439n, -26953727934n);
|
||||
assert(3213213213213213432453243n % 123434343439n, 26953727934n);
|
||||
|
||||
assert((-2n) ** 127n, -170141183460469231731687303715884105728n);
|
||||
assert((2n) ** 127n, 170141183460469231731687303715884105728n);
|
||||
assert((-256n) ** 11n, -309485009821345068724781056n);
|
||||
assert((7n) ** 20n, 79792266297612001n);
|
||||
}
|
||||
|
||||
/* pi computation */
|
||||
|
||||
/* 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 compute_pi(n_digits) {
|
||||
var r, n_digits, n_bits, out;
|
||||
/* 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();
|
||||
return out[0] + "." + out.slice(1);
|
||||
}
|
||||
|
||||
function test_pi()
|
||||
{
|
||||
assert(compute_pi(2000), "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151557485724245415069595082953311686172785588907509838175463746493931925506040092770167113900984882401285836160356370766010471018194295559619894676783744944825537977472684710404753464620804668425906949129331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992458631503028618297455570674983850549458858692699569092721079750930295532116534498720275596023648066549911988183479775356636980742654252786255181841757467289097777279380008164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179049460165346680498862723279178608578438382796797668145410095388378636095068006422512520511739298489608412848862694560424196528502221066118630674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009");
|
||||
}
|
||||
|
||||
test_bigint1();
|
||||
test_bigint2();
|
||||
test_bigint3();
|
||||
test_pi();
|
@ -1,326 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function assertThrows(err, func)
|
||||
{
|
||||
var ex;
|
||||
ex = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
ex = true;
|
||||
assert(e instanceof err);
|
||||
}
|
||||
assert(ex, true, "exception expected");
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
function bigint_pow(a, n)
|
||||
{
|
||||
var r, i;
|
||||
r = 1n;
|
||||
for(i = 0n; i < n; i++)
|
||||
r *= a;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* a must be < b */
|
||||
function test_less(a, b)
|
||||
{
|
||||
assert(a < b);
|
||||
assert(!(b < a));
|
||||
assert(a <= b);
|
||||
assert(!(b <= a));
|
||||
assert(b > a);
|
||||
assert(!(a > b));
|
||||
assert(b >= a);
|
||||
assert(!(a >= b));
|
||||
assert(a != b);
|
||||
assert(!(a == b));
|
||||
}
|
||||
|
||||
/* a must be numerically equal to b */
|
||||
function test_eq(a, b)
|
||||
{
|
||||
assert(a == b);
|
||||
assert(b == a);
|
||||
assert(!(a != b));
|
||||
assert(!(b != a));
|
||||
assert(a <= b);
|
||||
assert(b <= a);
|
||||
assert(!(a < b));
|
||||
assert(a >= b);
|
||||
assert(b >= a);
|
||||
assert(!(a > b));
|
||||
}
|
||||
|
||||
function test_bigint1()
|
||||
{
|
||||
var a, r;
|
||||
|
||||
test_less(2n, 3n);
|
||||
test_eq(3n, 3n);
|
||||
|
||||
test_less(2, 3n);
|
||||
test_eq(3, 3n);
|
||||
|
||||
test_less(2.1, 3n);
|
||||
test_eq(Math.sqrt(4), 2n);
|
||||
|
||||
a = bigint_pow(3n, 100n);
|
||||
assert((a - 1n) != a);
|
||||
assert(a == 515377520732011331036461129765621272702107522001n);
|
||||
assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1n);
|
||||
|
||||
r = 1n << 31n;
|
||||
assert(r, 2147483648n, "1 << 31n === 2147483648n");
|
||||
|
||||
r = 1n << 32n;
|
||||
assert(r, 4294967296n, "1 << 32n === 4294967296n");
|
||||
}
|
||||
|
||||
function test_bigint2()
|
||||
{
|
||||
assert(BigInt(""), 0n);
|
||||
assert(BigInt(" 123"), 123n);
|
||||
assert(BigInt(" 123 "), 123n);
|
||||
assertThrows(SyntaxError, () => { BigInt("+") } );
|
||||
assertThrows(SyntaxError, () => { BigInt("-") } );
|
||||
assertThrows(SyntaxError, () => { BigInt("\x00a") } );
|
||||
assertThrows(SyntaxError, () => { BigInt(" 123 r") } );
|
||||
}
|
||||
|
||||
function test_divrem(div1, a, b, q)
|
||||
{
|
||||
var div, divrem, t;
|
||||
div = BigInt[div1];
|
||||
divrem = BigInt[div1 + "rem"];
|
||||
assert(div(a, b) == q);
|
||||
t = divrem(a, b);
|
||||
assert(t[0] == q);
|
||||
assert(a == b * q + t[1]);
|
||||
}
|
||||
|
||||
function test_idiv1(div, a, b, r)
|
||||
{
|
||||
test_divrem(div, a, b, r[0]);
|
||||
test_divrem(div, -a, b, r[1]);
|
||||
test_divrem(div, a, -b, r[2]);
|
||||
test_divrem(div, -a, -b, r[3]);
|
||||
}
|
||||
|
||||
/* QuickJS BigInt extensions */
|
||||
function test_bigint_ext()
|
||||
{
|
||||
var r;
|
||||
assert(BigInt.floorLog2(0n) === -1n);
|
||||
assert(BigInt.floorLog2(7n) === 2n);
|
||||
|
||||
assert(BigInt.sqrt(0xffffffc000000000000000n) === 17592185913343n);
|
||||
r = BigInt.sqrtrem(0xffffffc000000000000000n);
|
||||
assert(r[0] === 17592185913343n);
|
||||
assert(r[1] === 35167191957503n);
|
||||
|
||||
test_idiv1("tdiv", 3n, 2n, [1n, -1n, -1n, 1n]);
|
||||
test_idiv1("fdiv", 3n, 2n, [1n, -2n, -2n, 1n]);
|
||||
test_idiv1("cdiv", 3n, 2n, [2n, -1n, -1n, 2n]);
|
||||
test_idiv1("ediv", 3n, 2n, [1n, -2n, -1n, 2n]);
|
||||
}
|
||||
|
||||
function test_bigfloat()
|
||||
{
|
||||
var e, a, b, sqrt2;
|
||||
|
||||
assert(typeof 1n === "bigint");
|
||||
assert(typeof 1l === "bigfloat");
|
||||
assert(1 == 1.0l);
|
||||
assert(1 !== 1.0l);
|
||||
|
||||
test_less(2l, 3l);
|
||||
test_eq(3l, 3l);
|
||||
|
||||
test_less(2, 3l);
|
||||
test_eq(3, 3l);
|
||||
|
||||
test_less(2.1, 3l);
|
||||
test_eq(Math.sqrt(9), 3l);
|
||||
|
||||
test_less(2n, 3l);
|
||||
test_eq(3n, 3l);
|
||||
|
||||
e = new BigFloatEnv(128);
|
||||
assert(e.prec == 128);
|
||||
a = BigFloat.sqrt(2l, e);
|
||||
assert(a === BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));
|
||||
assert(e.inexact === true);
|
||||
assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcc908b2fb1366ea95l);
|
||||
|
||||
b = BigFloatEnv.setPrec(BigFloat.sqrt.bind(null, 2), 128);
|
||||
assert(a === b);
|
||||
|
||||
assert(BigFloat.isNaN(BigFloat(NaN)));
|
||||
assert(BigFloat.isFinite(1l));
|
||||
assert(!BigFloat.isFinite(1l/0l));
|
||||
|
||||
assert(BigFloat.abs(-3l) === 3l);
|
||||
assert(BigFloat.sign(-3l) === -1l);
|
||||
|
||||
assert(BigFloat.exp(0.2l) === 1.2214027581601698339210719946396742l);
|
||||
assert(BigFloat.log(3l) === 1.0986122886681096913952452369225256l);
|
||||
assert(BigFloat.pow(2.1l, 1.6l) === 3.277561666451861947162828744873745l);
|
||||
|
||||
assert(BigFloat.sin(-1l) === -0.841470984807896506652502321630299l);
|
||||
assert(BigFloat.cos(1l) === 0.5403023058681397174009366074429766l);
|
||||
assert(BigFloat.tan(0.1l) === 0.10033467208545054505808004578111154l);
|
||||
|
||||
assert(BigFloat.asin(0.3l) === 0.30469265401539750797200296122752915l);
|
||||
assert(BigFloat.acos(0.4l) === 1.1592794807274085998465837940224159l);
|
||||
assert(BigFloat.atan(0.7l) === 0.610725964389208616543758876490236l);
|
||||
assert(BigFloat.atan2(7.1l, -5.1l) === 2.1937053809751415549388104628759813l);
|
||||
|
||||
assert(BigFloat.floor(2.5l) === 2l);
|
||||
assert(BigFloat.ceil(2.5l) === 3l);
|
||||
assert(BigFloat.trunc(-2.5l) === -2l);
|
||||
assert(BigFloat.round(2.5l) === 3l);
|
||||
|
||||
assert(BigFloat.fmod(3l,2l) === 1l);
|
||||
assert(BigFloat.remainder(3l,2l) === -1l);
|
||||
|
||||
/* string conversion */
|
||||
assert((1234.125l).toString(), "1234.125");
|
||||
assert((1234.125l).toFixed(2), "1234.13");
|
||||
assert((1234.125l).toFixed(2, "down"), "1234.12");
|
||||
assert((1234.125l).toExponential(), "1.234125e+3");
|
||||
assert((1234.125l).toExponential(5), "1.23413e+3");
|
||||
assert((1234.125l).toExponential(5, BigFloatEnv.RNDZ), "1.23412e+3");
|
||||
assert((1234.125l).toPrecision(6), "1234.13");
|
||||
assert((1234.125l).toPrecision(6, BigFloatEnv.RNDZ), "1234.12");
|
||||
|
||||
/* string conversion with binary base */
|
||||
assert((0x123.438l).toString(16), "123.438");
|
||||
assert((0x323.438l).toString(16), "323.438");
|
||||
assert((0x723.438l).toString(16), "723.438");
|
||||
assert((0xf23.438l).toString(16), "f23.438");
|
||||
assert((0x123.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "123.44");
|
||||
assert((0x323.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "323.44");
|
||||
assert((0x723.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "723.44");
|
||||
assert((0xf23.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "f23.44");
|
||||
assert((0x0.0000438l).toFixed(6, BigFloatEnv.RNDNA, 16), "0.000044");
|
||||
assert((0x1230000000l).toFixed(1, BigFloatEnv.RNDNA, 16), "1230000000.0");
|
||||
assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "123.44");
|
||||
assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDZ, 16), "123.43");
|
||||
assert((0x323.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "323.44");
|
||||
assert((0x723.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "723.44");
|
||||
assert((-0xf23.438l).toPrecision(5, BigFloatEnv.RNDD, 16), "-f23.44");
|
||||
assert((0x123.438l).toExponential(4, BigFloatEnv.RNDNA, 16), "1.2344p+8");
|
||||
}
|
||||
|
||||
function test_bigdecimal()
|
||||
{
|
||||
assert(1m === 1m);
|
||||
assert(1m !== 2m);
|
||||
test_less(1m, 2m);
|
||||
test_eq(2m, 2m);
|
||||
|
||||
test_less(1, 2m);
|
||||
test_eq(2, 2m);
|
||||
|
||||
test_less(1.1, 2m);
|
||||
test_eq(Math.sqrt(4), 2m);
|
||||
|
||||
test_less(2n, 3m);
|
||||
test_eq(3n, 3m);
|
||||
|
||||
assert(BigDecimal("1234.1") === 1234.1m);
|
||||
assert(BigDecimal(" 1234.1") === 1234.1m);
|
||||
assert(BigDecimal(" 1234.1 ") === 1234.1m);
|
||||
|
||||
assert(BigDecimal(0.1) === 0.1m);
|
||||
assert(BigDecimal(123) === 123m);
|
||||
assert(BigDecimal(true) === 1m);
|
||||
|
||||
assert(123m + 1m === 124m);
|
||||
assert(123m - 1m === 122m);
|
||||
|
||||
assert(3.2m * 3m === 9.6m);
|
||||
assert(10m / 2m === 5m);
|
||||
assertThrows(RangeError, () => { 10m / 3m } );
|
||||
|
||||
assert(10m % 3m === 1m);
|
||||
assert(-10m % 3m === -1m);
|
||||
|
||||
assert(1234.5m ** 3m === 1881365963.625m);
|
||||
assertThrows(RangeError, () => { 2m ** 3.1m } );
|
||||
assertThrows(RangeError, () => { 2m ** -3m } );
|
||||
|
||||
assert(BigDecimal.sqrt(2m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: 4 }) === 1.414m);
|
||||
assert(BigDecimal.sqrt(101m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 3 }) === 10.050m);
|
||||
assert(BigDecimal.sqrt(0.002m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 3 }) === 0.045m);
|
||||
|
||||
assert(BigDecimal.round(3.14159m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 3 }) === 3.142m);
|
||||
|
||||
assert(BigDecimal.add(3.14159m, 0.31212m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 2 }) === 3.45m);
|
||||
assert(BigDecimal.sub(3.14159m, 0.31212m,
|
||||
{ roundingMode: "down",
|
||||
maximumFractionDigits: 2 }) === 2.82m);
|
||||
assert(BigDecimal.mul(3.14159m, 0.31212m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 3 }) === 0.981m);
|
||||
assert(BigDecimal.mod(3.14159m, 0.31211m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 4 }) === 0.0205m);
|
||||
assert(BigDecimal.div(20m, 3m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: 3 }) === 6.67m);
|
||||
assert(BigDecimal.div(20m, 3m,
|
||||
{ roundingMode: "half-even",
|
||||
maximumFractionDigits: 50 }) ===
|
||||
6.66666666666666666666666666666666666666666666666667m);
|
||||
|
||||
/* string conversion */
|
||||
assert((1234.125m).toString(), "1234.125");
|
||||
assert((1234.125m).toFixed(2), "1234.13");
|
||||
assert((1234.125m).toFixed(2, "down"), "1234.12");
|
||||
assert((1234.125m).toExponential(), "1.234125e+3");
|
||||
assert((1234.125m).toExponential(5), "1.23413e+3");
|
||||
assert((1234.125m).toExponential(5, "down"), "1.23412e+3");
|
||||
assert((1234.125m).toPrecision(6), "1234.13");
|
||||
assert((1234.125m).toPrecision(6, "down"), "1234.12");
|
||||
assert((-1234.125m).toPrecision(6, "floor"), "-1234.13");
|
||||
}
|
||||
|
||||
test_bigint1();
|
||||
test_bigint2();
|
||||
test_bigint_ext();
|
||||
test_bigfloat();
|
||||
test_bigdecimal();
|
@ -34,7 +34,7 @@ function toHex(a)
|
||||
|
||||
function isArrayLike(a)
|
||||
{
|
||||
return Array.isArray(a) ||
|
||||
return Array.isArray(a) ||
|
||||
(a instanceof Uint8ClampedArray) ||
|
||||
(a instanceof Uint8Array) ||
|
||||
(a instanceof Uint16Array) ||
|
||||
@ -87,7 +87,6 @@ function toStr(a)
|
||||
case "string":
|
||||
return a.__quote();
|
||||
case "number":
|
||||
case "bigfloat":
|
||||
if (a == 0 && 1 / a < 0)
|
||||
return "-0";
|
||||
else
|
||||
@ -147,7 +146,7 @@ function bjson_test_reference()
|
||||
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]);
|
||||
@ -155,26 +154,11 @@ function bjson_test_all()
|
||||
bjson_test([BigInt("1"), -BigInt("0x123456789"),
|
||||
BigInt("0x123456789abcdef123456789abcdef")]);
|
||||
}
|
||||
if (typeof BigFloat !== "undefined") {
|
||||
BigFloatEnv.setPrec(function () {
|
||||
bjson_test([BigFloat("0.1"), BigFloat("-1e30"), BigFloat("0"),
|
||||
BigFloat("-0"), BigFloat("Infinity"), BigFloat("-Infinity"),
|
||||
0.0 / BigFloat("0"), BigFloat.MAX_VALUE,
|
||||
BigFloat.MIN_VALUE]);
|
||||
}, 113, 15);
|
||||
}
|
||||
if (typeof BigDecimal !== "undefined") {
|
||||
bjson_test([BigDecimal("0"),
|
||||
BigDecimal("0.8"), BigDecimal("123321312321321e100"),
|
||||
BigDecimal("-1233213123213214332333223332e100"),
|
||||
BigDecimal("1.233e-1000")]);
|
||||
}
|
||||
|
||||
bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]);
|
||||
|
||||
bjson_test(new Int32Array([123123, 222111, -32222]));
|
||||
bjson_test(new Float64Array([123123, 222111.5]));
|
||||
|
||||
|
||||
/* tested with a circular reference */
|
||||
obj = {};
|
||||
obj.x = obj;
|
||||
|
@ -1,19 +1,51 @@
|
||||
"use strict";
|
||||
|
||||
var status = 0;
|
||||
var throw_errors = true;
|
||||
|
||||
function throw_error(msg) {
|
||||
if (throw_errors)
|
||||
throw Error(msg);
|
||||
console.log(msg);
|
||||
status = 1;
|
||||
}
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
function get_full_type(o) {
|
||||
var type = typeof(o);
|
||||
if (type === 'object') {
|
||||
if (o === null)
|
||||
return 'null';
|
||||
if (o.constructor && o.constructor.name)
|
||||
return o.constructor.name;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
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 + "|" +
|
||||
if (typeof actual === typeof expected) {
|
||||
if (actual === expected) {
|
||||
if (actual !== 0 || (1 / actual) === (1 / expected))
|
||||
return;
|
||||
}
|
||||
if (typeof actual === 'number') {
|
||||
if (isNaN(actual) && isNaN(expected))
|
||||
return true;
|
||||
}
|
||||
if (typeof actual === 'object') {
|
||||
if (actual !== null && expected !== null
|
||||
&& actual.constructor === expected.constructor
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Should output the source file and line number and extract
|
||||
// the expression from the assert call
|
||||
throw_error("assertion failed: got " +
|
||||
get_full_type(actual) + ":|" + actual + "|, expected " +
|
||||
get_full_type(expected) + ":|" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
@ -25,11 +57,16 @@ function assert_throws(expected_error, func)
|
||||
} catch(e) {
|
||||
err = true;
|
||||
if (!(e instanceof expected_error)) {
|
||||
throw Error("unexpected exception type");
|
||||
// Should output the source file and line number and extract
|
||||
// the expression from the assert_throws() call
|
||||
throw_error("unexpected exception type");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
throw Error("expected exception");
|
||||
// Should output the source file and line number and extract
|
||||
// the expression from the assert_throws() call
|
||||
throw_error("expected exception");
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,7 +94,7 @@ function test_function()
|
||||
}
|
||||
|
||||
var r, g;
|
||||
|
||||
|
||||
r = my_func.call(null, 1, 2);
|
||||
assert(r, 3, "call");
|
||||
|
||||
@ -70,10 +107,10 @@ function test_function()
|
||||
assert_throws(TypeError, (function() {
|
||||
Reflect.apply((function () { return 1; }), null, undefined);
|
||||
}));
|
||||
|
||||
|
||||
r = new Function("a", "b", "return a + b;");
|
||||
assert(r(2,3), 5, "function");
|
||||
|
||||
|
||||
g = f.bind(1, 2);
|
||||
assert(g.length, 1);
|
||||
assert(g.name, "bound f");
|
||||
@ -103,7 +140,7 @@ function test()
|
||||
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;
|
||||
@ -207,7 +244,7 @@ function test_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);
|
||||
@ -216,7 +253,7 @@ function test_string()
|
||||
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");
|
||||
@ -311,10 +348,14 @@ function test_math()
|
||||
assert(Math.floor(a), 1);
|
||||
assert(Math.ceil(a), 2);
|
||||
assert(Math.imul(0x12345678, 123), -1088058456);
|
||||
assert(Math.imul(0xB505, 0xB504), 2147441940);
|
||||
assert(Math.imul(0xB505, 0xB505), -2147479015);
|
||||
assert(Math.imul((-2)**31, (-2)**31), 0);
|
||||
assert(Math.imul(2**31-1, 2**31-1), 1);
|
||||
assert(Math.fround(0.1), 0.10000000149011612);
|
||||
assert(Math.hypot() == 0);
|
||||
assert(Math.hypot(-2) == 2);
|
||||
assert(Math.hypot(3, 4) == 5);
|
||||
assert(Math.hypot(), 0);
|
||||
assert(Math.hypot(-2), 2);
|
||||
assert(Math.hypot(3, 4), 5);
|
||||
assert(Math.abs(Math.hypot(3, 4, 5) - 7.0710678118654755) <= 1e-15);
|
||||
}
|
||||
|
||||
@ -327,6 +368,10 @@ function test_number()
|
||||
assert(+" 123 ", 123);
|
||||
assert(+"0b111", 7);
|
||||
assert(+"0o123", 83);
|
||||
assert(parseFloat("2147483647"), 2147483647);
|
||||
assert(parseFloat("2147483648"), 2147483648);
|
||||
assert(parseFloat("-2147483647"), -2147483647);
|
||||
assert(parseFloat("-2147483648"), -2147483648);
|
||||
assert(parseFloat("0x1234"), 0);
|
||||
assert(parseFloat("Infinity"), Infinity);
|
||||
assert(parseFloat("-Infinity"), -Infinity);
|
||||
@ -336,12 +381,22 @@ function test_number()
|
||||
assert(Number.isNaN(Number("-")));
|
||||
assert(Number.isNaN(Number("\x00a")));
|
||||
|
||||
assert((1-2**-53).toString(12), "0.bbbbbbbbbbbbbba");
|
||||
assert((1000000000000000128).toString(), "1000000000000000100");
|
||||
assert((1000000000000000128).toFixed(0), "1000000000000000128");
|
||||
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((25).toPrecision(1) === "3e+1");
|
||||
assert((1.125).toFixed(2), "1.13");
|
||||
assert((-1.125).toFixed(2), "-1.13");
|
||||
assert((0.5).toFixed(0), "1");
|
||||
assert((-0.5).toFixed(0), "-1");
|
||||
assert((-1e-10).toFixed(0), "-0");
|
||||
|
||||
assert((1.3).toString(7), "1.2046204620462046205");
|
||||
assert((1.3).toString(35), "1.ahhhhhhhhhm");
|
||||
}
|
||||
|
||||
function test_eval2()
|
||||
@ -379,7 +434,7 @@ function test_eval()
|
||||
assert(eval("if (0) 2; else 3;"), 3);
|
||||
|
||||
assert(f.call(1, "this"), 1);
|
||||
|
||||
|
||||
a = 2;
|
||||
assert(eval("a"), 2);
|
||||
|
||||
@ -424,7 +479,7 @@ function test_typed_array()
|
||||
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);
|
||||
@ -436,7 +491,7 @@ function test_typed_array()
|
||||
|
||||
a = new Float32Array(buffer, 8, 1);
|
||||
a[0] = 1;
|
||||
|
||||
|
||||
a = new Uint8Array(buffer);
|
||||
|
||||
str = a.toString();
|
||||
@ -454,6 +509,66 @@ function test_typed_array()
|
||||
assert(a.toString(), "1,2,10,11");
|
||||
}
|
||||
|
||||
/* return [s, line_num, col_num] where line_num and col_num are the
|
||||
position of the '@' character in 'str'. 's' is str without the '@'
|
||||
character */
|
||||
function get_string_pos(str)
|
||||
{
|
||||
var p, line_num, col_num, s, q, r;
|
||||
p = str.indexOf('@');
|
||||
assert(p >= 0, true);
|
||||
q = 0;
|
||||
line_num = 1;
|
||||
for(;;) {
|
||||
r = str.indexOf('\n', q);
|
||||
if (r < 0 || r >= p)
|
||||
break;
|
||||
q = r + 1;
|
||||
line_num++;
|
||||
}
|
||||
col_num = p - q + 1;
|
||||
s = str.slice(0, p) + str.slice(p + 1);
|
||||
return [s, line_num, col_num];
|
||||
}
|
||||
|
||||
function check_error_pos(e, expected_error, line_num, col_num, level)
|
||||
{
|
||||
var expected_pos, tab, line;
|
||||
level |= 0;
|
||||
expected_pos = ":" + line_num + ":" + col_num;
|
||||
tab = e.stack.split("\n");
|
||||
line = tab[level];
|
||||
if (line.slice(-1) == ')')
|
||||
line = line.slice(0, -1);
|
||||
if (line.indexOf(expected_pos) < 0) {
|
||||
throw_error("unexpected line or column number. error=" + e.message +
|
||||
".got |" + line + "|, expected |" + expected_pos + "|");
|
||||
}
|
||||
}
|
||||
|
||||
function assert_json_error(str, line_num, col_num)
|
||||
{
|
||||
var err = false;
|
||||
var expected_pos, tab;
|
||||
|
||||
tab = get_string_pos(str);
|
||||
|
||||
try {
|
||||
JSON.parse(tab[0]);
|
||||
} catch(e) {
|
||||
err = true;
|
||||
if (!(e instanceof SyntaxError)) {
|
||||
throw_error("unexpected exception type");
|
||||
return;
|
||||
}
|
||||
/* XXX: the way quickjs returns JSON errors is not similar to Node or spiderMonkey */
|
||||
check_error_pos(e, SyntaxError, tab[1], tab[2]);
|
||||
}
|
||||
if (!err) {
|
||||
throw_error("expected exception");
|
||||
}
|
||||
}
|
||||
|
||||
function test_json()
|
||||
{
|
||||
var a, s;
|
||||
@ -477,30 +592,112 @@ function test_json()
|
||||
3
|
||||
]
|
||||
]`);
|
||||
|
||||
assert_json_error('\n" @\\x"');
|
||||
assert_json_error('\n{ "a": @x }"');
|
||||
}
|
||||
|
||||
function test_date()
|
||||
{
|
||||
var d = new Date(1506098258091), a, s;
|
||||
// Date Time String format is YYYY-MM-DDTHH:mm:ss.sssZ
|
||||
// accepted date formats are: YYYY, YYYY-MM and YYYY-MM-DD
|
||||
// accepted time formats are: THH:mm, THH:mm:ss, THH:mm:ss.sss
|
||||
// expanded years are represented with 6 digits prefixed by + or -
|
||||
// -000000 is invalid.
|
||||
// A string containing out-of-bounds or nonconforming elements
|
||||
// is not a valid instance of this format.
|
||||
// Hence the fractional part after . should have 3 digits and how
|
||||
// a different number of digits is handled is implementation defined.
|
||||
assert(Date.parse(""), NaN);
|
||||
assert(Date.parse("2000"), 946684800000);
|
||||
assert(Date.parse("2000-01"), 946684800000);
|
||||
assert(Date.parse("2000-01-01"), 946684800000);
|
||||
//assert(Date.parse("2000-01-01T"), NaN);
|
||||
//assert(Date.parse("2000-01-01T00Z"), NaN);
|
||||
assert(Date.parse("2000-01-01T00:00Z"), 946684800000);
|
||||
assert(Date.parse("2000-01-01T00:00:00Z"), 946684800000);
|
||||
assert(Date.parse("2000-01-01T00:00:00.1Z"), 946684800100);
|
||||
assert(Date.parse("2000-01-01T00:00:00.10Z"), 946684800100);
|
||||
assert(Date.parse("2000-01-01T00:00:00.100Z"), 946684800100);
|
||||
assert(Date.parse("2000-01-01T00:00:00.1000Z"), 946684800100);
|
||||
assert(Date.parse("2000-01-01T00:00:00+00:00"), 946684800000);
|
||||
//assert(Date.parse("2000-01-01T00:00:00+00:30"), 946686600000);
|
||||
var d = new Date("2000T00:00"); // Jan 1st 2000, 0:00:00 local time
|
||||
assert(typeof d === 'object' && d.toString() != 'Invalid Date');
|
||||
assert((new Date('Jan 1 2000')).toISOString(),
|
||||
d.toISOString());
|
||||
assert((new Date('Jan 1 2000 00:00')).toISOString(),
|
||||
d.toISOString());
|
||||
assert((new Date('Jan 1 2000 00:00:00')).toISOString(),
|
||||
d.toISOString());
|
||||
assert((new Date('Jan 1 2000 00:00:00 GMT+0100')).toISOString(),
|
||||
'1999-12-31T23:00:00.000Z');
|
||||
assert((new Date('Jan 1 2000 00:00:00 GMT+0200')).toISOString(),
|
||||
'1999-12-31T22:00:00.000Z');
|
||||
assert((new Date('Sat Jan 1 2000')).toISOString(),
|
||||
d.toISOString());
|
||||
assert((new Date('Sat Jan 1 2000 00:00')).toISOString(),
|
||||
d.toISOString());
|
||||
assert((new Date('Sat Jan 1 2000 00:00:00')).toISOString(),
|
||||
d.toISOString());
|
||||
assert((new Date('Sat Jan 1 2000 00:00:00 GMT+0100')).toISOString(),
|
||||
'1999-12-31T23:00:00.000Z');
|
||||
assert((new Date('Sat Jan 1 2000 00:00:00 GMT+0200')).toISOString(),
|
||||
'1999-12-31T22:00:00.000Z');
|
||||
|
||||
var d = new Date(1506098258091);
|
||||
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());
|
||||
var 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");
|
||||
|
||||
assert((new Date("2020-01-01T01:01:01.123Z")).toISOString(),
|
||||
"2020-01-01T01:01:01.123Z");
|
||||
/* implementation defined behavior */
|
||||
assert((new Date("2020-01-01T01:01:01.1Z")).toISOString(),
|
||||
"2020-01-01T01:01:01.100Z");
|
||||
assert((new Date("2020-01-01T01:01:01.12Z")).toISOString(),
|
||||
"2020-01-01T01:01:01.120Z");
|
||||
assert((new Date("2020-01-01T01:01:01.1234Z")).toISOString(),
|
||||
"2020-01-01T01:01:01.123Z");
|
||||
assert((new Date("2020-01-01T01:01:01.12345Z")).toISOString(),
|
||||
"2020-01-01T01:01:01.123Z");
|
||||
assert((new Date("2020-01-01T01:01:01.1235Z")).toISOString(),
|
||||
"2020-01-01T01:01:01.123Z");
|
||||
assert((new Date("2020-01-01T01:01:01.9999Z")).toISOString(),
|
||||
"2020-01-01T01:01:01.999Z");
|
||||
|
||||
assert(Date.UTC(2017), 1483228800000);
|
||||
assert(Date.UTC(2017, 9), 1506816000000);
|
||||
assert(Date.UTC(2017, 9, 22), 1508630400000);
|
||||
assert(Date.UTC(2017, 9, 22, 18), 1508695200000);
|
||||
assert(Date.UTC(2017, 9, 22, 18, 10), 1508695800000);
|
||||
assert(Date.UTC(2017, 9, 22, 18, 10, 11), 1508695811000);
|
||||
assert(Date.UTC(2017, 9, 22, 18, 10, 11, 91), 1508695811091);
|
||||
|
||||
assert(Date.UTC(NaN), NaN);
|
||||
assert(Date.UTC(2017, NaN), NaN);
|
||||
assert(Date.UTC(2017, 9, NaN), NaN);
|
||||
assert(Date.UTC(2017, 9, 22, NaN), NaN);
|
||||
assert(Date.UTC(2017, 9, 22, 18, NaN), NaN);
|
||||
assert(Date.UTC(2017, 9, 22, 18, 10, NaN), NaN);
|
||||
assert(Date.UTC(2017, 9, 22, 18, 10, 11, NaN), NaN);
|
||||
assert(Date.UTC(2017, 9, 22, 18, 10, 11, 91, NaN), 1508695811091);
|
||||
|
||||
// TODO: Fix rounding errors on Windows/Cygwin.
|
||||
if (!(typeof os !== 'undefined' && ['win32', 'cygwin'].includes(os.platform))) {
|
||||
// from test262/test/built-ins/Date/UTC/fp-evaluation-order.js
|
||||
assert(Date.UTC(1970, 0, 1, 80063993375, 29, 1, -288230376151711740), 29312,
|
||||
'order of operations / precision in MakeTime');
|
||||
assert(Date.UTC(1970, 0, 213503982336, 0, 0, 0, -18446744073709552000), 34447360,
|
||||
'precision in MakeDate');
|
||||
}
|
||||
//assert(Date.UTC(2017 - 1e9, 9 + 12e9), 1506816000000); // node fails this
|
||||
assert(Date.UTC(2017, 9, 22 - 1e10, 18 + 24e10), 1508695200000);
|
||||
assert(Date.UTC(2017, 9, 22, 18 - 1e10, 10 + 60e10), 1508695800000);
|
||||
assert(Date.UTC(2017, 9, 22, 18, 10 - 1e10, 11 + 60e10), 1508695811000);
|
||||
assert(Date.UTC(2017, 9, 22, 18, 10, 11 - 1e12, 91 + 1000e12), 1508695811091);
|
||||
}
|
||||
|
||||
function test_regexp()
|
||||
@ -525,7 +722,7 @@ function test_regexp()
|
||||
|
||||
a = /(\.(?!com|org)|\/)/.exec("ah.com");
|
||||
assert(a, null);
|
||||
|
||||
|
||||
a = /(?=(a+))/.exec("baaabac");
|
||||
assert(a.index === 1 && a[0] === "" && a[1] === "aaa");
|
||||
|
||||
@ -549,6 +746,8 @@ function test_regexp()
|
||||
assert(a, ["a", undefined]);
|
||||
a = /(?:|[\w])+([0-9])/.exec("123a23");
|
||||
assert(a, ["123a23", "3"]);
|
||||
a = /()*?a/.exec(",");
|
||||
assert(a, null);
|
||||
}
|
||||
|
||||
function test_symbol()
|
||||
@ -583,15 +782,26 @@ function test_symbol()
|
||||
assert(b.toString(), "Symbol(aaa)");
|
||||
}
|
||||
|
||||
function test_map()
|
||||
function test_map1(key_type, n)
|
||||
{
|
||||
var a, i, n, tab, o, v;
|
||||
n = 1000;
|
||||
var a, i, tab, o, v;
|
||||
a = new Map();
|
||||
tab = [];
|
||||
for(i = 0; i < n; i++) {
|
||||
v = { };
|
||||
o = { id: i };
|
||||
switch(key_type) {
|
||||
case "small_bigint":
|
||||
o = BigInt(i);
|
||||
break;
|
||||
case "bigint":
|
||||
o = BigInt(i) + (1n << 128n);
|
||||
break;
|
||||
case "object":
|
||||
o = { id: i };
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
tab[i] = [o, v];
|
||||
a.set(o, v);
|
||||
}
|
||||
@ -602,7 +812,7 @@ function test_map()
|
||||
}
|
||||
|
||||
i = 0;
|
||||
a.forEach(function (v, o) {
|
||||
a.forEach(function (v, o) {
|
||||
assert(o, tab[i++][0]);
|
||||
assert(a.has(o));
|
||||
assert(a.delete(o));
|
||||
@ -612,6 +822,29 @@ function test_map()
|
||||
assert(a.size, 0);
|
||||
}
|
||||
|
||||
function test_map()
|
||||
{
|
||||
var a, i, n, tab, o, v;
|
||||
n = 1000;
|
||||
|
||||
a = new Map();
|
||||
for (var i = 0; i < n; i++) {
|
||||
a.set(i, i);
|
||||
}
|
||||
a.set(-2147483648, 1);
|
||||
assert(a.get(-2147483648), 1);
|
||||
assert(a.get(-2147483647 - 1), 1);
|
||||
assert(a.get(-2147483647.5 - 0.5), 1);
|
||||
|
||||
a.set(1n, 1n);
|
||||
assert(a.get(1n), 1n);
|
||||
assert(a.get(2n**1000n - (2n**1000n - 1n)), 1n);
|
||||
|
||||
test_map1("object", n);
|
||||
test_map1("small_bigint", n);
|
||||
test_map1("bigint", n);
|
||||
}
|
||||
|
||||
function test_weak_map()
|
||||
{
|
||||
var a, i, n, tab, o, v, n2;
|
||||
@ -620,22 +853,97 @@ function test_weak_map()
|
||||
tab = [];
|
||||
for(i = 0; i < n; i++) {
|
||||
v = { };
|
||||
o = { id: i };
|
||||
if (i & 1)
|
||||
o = Symbol("x" + i);
|
||||
else
|
||||
o = { id: i };
|
||||
tab[i] = [o, v];
|
||||
a.set(o, v);
|
||||
}
|
||||
o = null;
|
||||
|
||||
n2 = n >> 1;
|
||||
|
||||
n2 = 5;
|
||||
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 */
|
||||
}
|
||||
std.gc();
|
||||
/* the WeakMap should be empty here */
|
||||
}
|
||||
|
||||
function test_weak_map_cycles()
|
||||
{
|
||||
const weak1 = new WeakMap();
|
||||
const weak2 = new WeakMap();
|
||||
function createCyclicKey() {
|
||||
const parent = {};
|
||||
const child = {parent};
|
||||
parent.child = child;
|
||||
return child;
|
||||
}
|
||||
function testWeakMap() {
|
||||
const cyclicKey = createCyclicKey();
|
||||
const valueOfCyclicKey = {};
|
||||
weak1.set(cyclicKey, valueOfCyclicKey);
|
||||
weak2.set(valueOfCyclicKey, 1);
|
||||
}
|
||||
testWeakMap();
|
||||
// Force to free cyclicKey.
|
||||
std.gc();
|
||||
// Here will cause sigsegv because [cyclicKey] and [valueOfCyclicKey] in [weak1] was free,
|
||||
// but weak2's map record was not removed, and it's key refers [valueOfCyclicKey] which is free.
|
||||
weak2.get({});
|
||||
std.gc();
|
||||
}
|
||||
|
||||
function test_weak_ref()
|
||||
{
|
||||
var w1, w2, o, i;
|
||||
|
||||
for(i = 0; i < 2; i++) {
|
||||
if (i == 0)
|
||||
o = { };
|
||||
else
|
||||
o = Symbol("x");
|
||||
w1 = new WeakRef(o);
|
||||
assert(w1.deref(), o);
|
||||
w2 = new WeakRef(o);
|
||||
assert(w2.deref(), o);
|
||||
|
||||
o = null;
|
||||
assert(w1.deref(), undefined);
|
||||
assert(w2.deref(), undefined);
|
||||
std.gc();
|
||||
assert(w1.deref(), undefined);
|
||||
assert(w2.deref(), undefined);
|
||||
}
|
||||
}
|
||||
|
||||
function test_finalization_registry()
|
||||
{
|
||||
{
|
||||
let expected = {};
|
||||
let actual;
|
||||
let finrec = new FinalizationRegistry(v => { actual = v });
|
||||
finrec.register({}, expected);
|
||||
os.setTimeout(() => {
|
||||
assert(actual, expected);
|
||||
}, 0);
|
||||
}
|
||||
{
|
||||
let expected = 42;
|
||||
let actual;
|
||||
let finrec = new FinalizationRegistry(v => { actual = v });
|
||||
finrec.register({}, expected);
|
||||
os.setTimeout(() => {
|
||||
assert(actual, expected);
|
||||
}, 0);
|
||||
}
|
||||
std.gc();
|
||||
}
|
||||
|
||||
function test_generator()
|
||||
{
|
||||
function *f() {
|
||||
@ -695,6 +1003,116 @@ function test_generator()
|
||||
assert(v.value === 6 && v.done === true);
|
||||
}
|
||||
|
||||
function rope_concat(n, dir)
|
||||
{
|
||||
var i, s;
|
||||
s = "";
|
||||
if (dir > 0) {
|
||||
for(i = 0; i < n; i++)
|
||||
s += String.fromCharCode(i & 0xffff);
|
||||
} else {
|
||||
for(i = n - 1; i >= 0; i--)
|
||||
s = String.fromCharCode(i & 0xffff) + s;
|
||||
}
|
||||
|
||||
for(i = 0; i < n; i++) {
|
||||
/* test before the assert to go faster */
|
||||
if (s.charCodeAt(i) != (i & 0xffff)) {
|
||||
assert(s.charCodeAt(i), i & 0xffff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function test_rope()
|
||||
{
|
||||
rope_concat(100000, 1);
|
||||
rope_concat(100000, -1);
|
||||
}
|
||||
|
||||
function eval_error(eval_str, expected_error, level)
|
||||
{
|
||||
var err = false;
|
||||
var expected_pos, tab;
|
||||
|
||||
tab = get_string_pos(eval_str);
|
||||
|
||||
try {
|
||||
eval(tab[0]);
|
||||
} catch(e) {
|
||||
err = true;
|
||||
if (!(e instanceof expected_error)) {
|
||||
throw_error("unexpected exception type");
|
||||
return;
|
||||
}
|
||||
check_error_pos(e, expected_error, tab[1], tab[2], level);
|
||||
}
|
||||
if (!err) {
|
||||
throw_error("expected exception");
|
||||
}
|
||||
}
|
||||
|
||||
var poisoned_number = {
|
||||
valueOf: function() { throw Error("poisoned number") },
|
||||
};
|
||||
|
||||
function test_line_column_numbers()
|
||||
{
|
||||
var f, e, tab;
|
||||
|
||||
/* The '@' character provides the expected position of the
|
||||
error. It is removed before evaluating the string. */
|
||||
|
||||
/* parsing */
|
||||
eval_error("\n 123 @a ", SyntaxError);
|
||||
eval_error("\n @/* ", SyntaxError);
|
||||
eval_error("function f @a", SyntaxError);
|
||||
/* currently regexp syntax errors point to the start of the regexp */
|
||||
eval_error("\n @/aaa]/u", SyntaxError);
|
||||
|
||||
/* function definitions */
|
||||
|
||||
tab = get_string_pos("\n @function f() { }; f;");
|
||||
e = eval(tab[0]);
|
||||
assert(e.lineNumber, tab[1]);
|
||||
assert(e.columnNumber, tab[2]);
|
||||
|
||||
/* errors */
|
||||
tab = get_string_pos('\n Error@("hello");');
|
||||
e = eval(tab[0]);
|
||||
check_error_pos(e, Error, tab[1], tab[2]);
|
||||
|
||||
eval_error('\n throw Error@("hello");', Error);
|
||||
|
||||
/* operators */
|
||||
eval_error('\n 1 + 2 @* poisoned_number;', Error, 1);
|
||||
eval_error('\n 1 + "café" @* poisoned_number;', Error, 1);
|
||||
eval_error('\n 1 + 2 @** poisoned_number;', Error, 1);
|
||||
eval_error('\n 2 * @+ poisoned_number;', Error, 1);
|
||||
eval_error('\n 2 * @- poisoned_number;', Error, 1);
|
||||
eval_error('\n 2 * @~ poisoned_number;', Error, 1);
|
||||
eval_error('\n 2 * @++ poisoned_number;', Error, 1);
|
||||
eval_error('\n 2 * @-- poisoned_number;', Error, 1);
|
||||
eval_error('\n 2 * poisoned_number @++;', Error, 1);
|
||||
eval_error('\n 2 * poisoned_number @--;', Error, 1);
|
||||
|
||||
/* accessors */
|
||||
eval_error('\n 1 + null@[0];', TypeError);
|
||||
eval_error('\n 1 + null @. abcd;', TypeError);
|
||||
eval_error('\n 1 + null @( 1234 );', TypeError);
|
||||
eval_error('var obj = { get a() { throw Error("test"); } }\n 1 + obj @. a;',
|
||||
Error, 1);
|
||||
eval_error('var obj = { set a(b) { throw Error("test"); } }\n obj @. a = 1;',
|
||||
Error, 1);
|
||||
|
||||
/* variables reference */
|
||||
eval_error('\n 1 + @not_def', ReferenceError, 0);
|
||||
|
||||
/* assignments */
|
||||
eval_error('1 + (@not_def = 1)', ReferenceError, 0);
|
||||
eval_error('1 + (@not_def += 2)', ReferenceError, 0);
|
||||
eval_error('var a;\n 1 + (a @+= poisoned_number);', Error, 1);
|
||||
}
|
||||
|
||||
test();
|
||||
test_function();
|
||||
test_enum();
|
||||
@ -710,4 +1128,9 @@ test_regexp();
|
||||
test_symbol();
|
||||
test_map();
|
||||
test_weak_map();
|
||||
test_weak_map_cycles();
|
||||
test_weak_ref();
|
||||
test_finalization_registry();
|
||||
test_generator();
|
||||
test_rope();
|
||||
test_line_column_numbers();
|
||||
|
@ -54,7 +54,7 @@ function test_closure1()
|
||||
function f2()
|
||||
{
|
||||
var val = 1;
|
||||
|
||||
|
||||
function set(a) {
|
||||
val = a;
|
||||
}
|
||||
@ -63,7 +63,7 @@ function test_closure1()
|
||||
}
|
||||
return { "set": set, "get": get };
|
||||
}
|
||||
|
||||
|
||||
var obj = f2();
|
||||
obj.set(10);
|
||||
var r;
|
||||
|
12
tests/test_cyclic_import.js
Normal file
12
tests/test_cyclic_import.js
Normal file
@ -0,0 +1,12 @@
|
||||
/*---
|
||||
negative:
|
||||
phase: resolution
|
||||
type: SyntaxError
|
||||
---*/
|
||||
// FIXME(bnoordhuis) shouldn't throw SyntaxError but that's still better
|
||||
// than segfaulting, see https://github.com/quickjs-ng/quickjs/issues/567
|
||||
import {assert} from "./assert.js"
|
||||
import {f} from "./fixture_cyclic_import.js"
|
||||
export {f}
|
||||
export function g(x) { return x + 1 }
|
||||
assert(f(1), 4)
|
@ -68,10 +68,10 @@ function test_op1()
|
||||
|
||||
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");
|
||||
|
||||
@ -113,7 +113,7 @@ function test_cvt()
|
||||
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);
|
||||
@ -141,7 +141,7 @@ function test_eq()
|
||||
function test_inc_dec()
|
||||
{
|
||||
var a, r;
|
||||
|
||||
|
||||
a = 1;
|
||||
r = a++;
|
||||
assert(r === 1 && a === 2, true, "++");
|
||||
@ -169,19 +169,19 @@ function test_inc_dec()
|
||||
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, "--");
|
||||
@ -213,7 +213,7 @@ function test_op2()
|
||||
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);
|
||||
@ -226,7 +226,7 @@ function test_delete()
|
||||
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);
|
||||
|
||||
@ -311,7 +311,7 @@ function test_class()
|
||||
o = new C();
|
||||
assert(o.f() === 1);
|
||||
assert(o.x === 10);
|
||||
|
||||
|
||||
assert(D.F() === -1);
|
||||
assert(D.G() === -2);
|
||||
assert(D.H() === -1);
|
||||
@ -335,6 +335,13 @@ function test_class()
|
||||
assert(S.x === 42);
|
||||
assert(S.y === 42);
|
||||
assert(S.z === 42);
|
||||
|
||||
class P {
|
||||
get = () => "123";
|
||||
static() { return 42; }
|
||||
}
|
||||
assert(new P().get() === "123");
|
||||
assert(new P().static() === 42);
|
||||
};
|
||||
|
||||
function test_template()
|
||||
@ -362,8 +369,9 @@ function test_template_skip()
|
||||
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 = { get: 2, set: 3, async: 4, get a(){ return this.get} };
|
||||
assert(JSON.stringify(a), '{"get":2,"set":3,"async":4,"a":2}');
|
||||
assert(a.a === 2);
|
||||
|
||||
a = { x, get, set, async };
|
||||
assert(JSON.stringify(a), '{"x":0,"get":1,"set":2,"async":3}');
|
||||
@ -374,7 +382,7 @@ function test_regexp_skip()
|
||||
var a, b;
|
||||
[a, b = /abc\(/] = [1];
|
||||
assert(a === 1);
|
||||
|
||||
|
||||
[a, b =/abc\(/] = [2];
|
||||
assert(a === 2);
|
||||
}
|
||||
@ -390,6 +398,24 @@ function test_labels()
|
||||
while (0) x: { break x; };
|
||||
}
|
||||
|
||||
function test_labels2()
|
||||
{
|
||||
while (1) label: break
|
||||
var i = 0
|
||||
while (i < 3) label: {
|
||||
if (i > 0)
|
||||
break
|
||||
i++
|
||||
}
|
||||
assert(i, 1)
|
||||
for (;;) label: break
|
||||
for (i = 0; i < 3; i++) label: {
|
||||
if (i > 0)
|
||||
break
|
||||
}
|
||||
assert(i, 1)
|
||||
}
|
||||
|
||||
function test_destructuring()
|
||||
{
|
||||
function * g () { return 0; };
|
||||
@ -419,9 +445,13 @@ function test_argument_scope()
|
||||
{
|
||||
var f;
|
||||
var c = "global";
|
||||
|
||||
f = function(a = eval("var arguments")) {};
|
||||
assert_throws(SyntaxError, f);
|
||||
|
||||
(function() {
|
||||
"use strict";
|
||||
// XXX: node only throws in strict mode
|
||||
f = function(a = eval("var arguments")) {};
|
||||
assert_throws(SyntaxError, f);
|
||||
})();
|
||||
|
||||
f = function(a = eval("1"), b = arguments[0]) { return b; };
|
||||
assert(f(12), 12);
|
||||
@ -490,7 +520,7 @@ function test_function_expr_name()
|
||||
|
||||
/* non strict mode test : assignment to the function name silently
|
||||
fails */
|
||||
|
||||
|
||||
f = function myfunc() {
|
||||
myfunc = 1;
|
||||
return myfunc;
|
||||
@ -511,7 +541,7 @@ function test_function_expr_name()
|
||||
return myfunc;
|
||||
};
|
||||
assert(f(), f);
|
||||
|
||||
|
||||
/* strict mode test : assignment to the function name raises a
|
||||
TypeError exception */
|
||||
|
||||
@ -558,6 +588,15 @@ function test_parse_semicolon()
|
||||
}
|
||||
}
|
||||
|
||||
function test_parse_arrow_function()
|
||||
{
|
||||
assert(typeof eval("() => {}\n() => {}"), "function");
|
||||
assert(eval("() => {}\n+1"), 1);
|
||||
assert(typeof eval("x => {}\n() => {}"), "function");
|
||||
assert(typeof eval("async () => {}\n() => {}"), "function");
|
||||
assert(typeof eval("async x => {}\n() => {}"), "function");
|
||||
}
|
||||
|
||||
/* optional chaining tests not present in test262 */
|
||||
function test_optional_chaining()
|
||||
{
|
||||
@ -572,7 +611,7 @@ function test_optional_chaining()
|
||||
assert(delete z?.b["c"], true);
|
||||
assert(delete a?.b["c"], true);
|
||||
assert(JSON.stringify(a), '{"b":{}}');
|
||||
|
||||
|
||||
a = {
|
||||
b() { return this._b; },
|
||||
_b: { c: 42 }
|
||||
@ -583,6 +622,12 @@ function test_optional_chaining()
|
||||
assert((a?.["b"])().c, 42);
|
||||
}
|
||||
|
||||
function test_unicode_ident()
|
||||
{
|
||||
var õ = 3;
|
||||
assert(typeof õ, "undefined");
|
||||
}
|
||||
|
||||
test_op1();
|
||||
test_cvt();
|
||||
test_eq();
|
||||
@ -597,6 +642,7 @@ test_template_skip();
|
||||
test_object_literal();
|
||||
test_regexp_skip();
|
||||
test_labels();
|
||||
test_labels2();
|
||||
test_destructuring();
|
||||
test_spread();
|
||||
test_function_length();
|
||||
@ -604,3 +650,5 @@ test_argument_scope();
|
||||
test_function_expr_name();
|
||||
test_parse_semicolon();
|
||||
test_optional_chaining();
|
||||
test_parse_arrow_function();
|
||||
test_unicode_ident();
|
||||
|
@ -149,7 +149,7 @@ function test_for_in()
|
||||
|
||||
function test_for_in2()
|
||||
{
|
||||
var i;
|
||||
var i, tab;
|
||||
tab = [];
|
||||
for(i in {x:1, y: 2, z:3}) {
|
||||
if (i === "y")
|
||||
@ -356,7 +356,7 @@ function test_try_catch7()
|
||||
function test_try_catch8()
|
||||
{
|
||||
var i, s;
|
||||
|
||||
|
||||
s = "";
|
||||
for(var i in {x:1, y:2}) {
|
||||
try {
|
||||
@ -371,6 +371,16 @@ function test_try_catch8()
|
||||
assert(s === "xafyaf");
|
||||
}
|
||||
|
||||
function test_cyclic_labels()
|
||||
{
|
||||
/* just check that it compiles without a crash */
|
||||
for (;;) {
|
||||
l: break l;
|
||||
l: break l;
|
||||
l: break l;
|
||||
}
|
||||
}
|
||||
|
||||
test_while();
|
||||
test_while_break();
|
||||
test_do_while();
|
||||
|
@ -1,207 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
/* operators overloading with Operators.create() */
|
||||
function test_operators_create() {
|
||||
class Vec2
|
||||
{
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
static mul_scalar(p1, a) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x * a;
|
||||
r.y = p1.y * a;
|
||||
return r;
|
||||
}
|
||||
toString() {
|
||||
return "Vec2(" + this.x + "," + this.y + ")";
|
||||
}
|
||||
}
|
||||
|
||||
Vec2.prototype[Symbol.operatorSet] = Operators.create(
|
||||
{
|
||||
"+"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x + p2.x;
|
||||
r.y = p1.y + p2.y;
|
||||
return r;
|
||||
},
|
||||
"-"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x - p2.x;
|
||||
r.y = p1.y - p2.y;
|
||||
return r;
|
||||
},
|
||||
"=="(a, b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
},
|
||||
"<"(a, b) {
|
||||
var r;
|
||||
/* lexicographic order */
|
||||
if (a.x == b.x)
|
||||
r = (a.y < b.y);
|
||||
else
|
||||
r = (a.x < b.x);
|
||||
return r;
|
||||
},
|
||||
"++"(a) {
|
||||
var r = new Vec2();
|
||||
r.x = a.x + 1;
|
||||
r.y = a.y + 1;
|
||||
return r;
|
||||
}
|
||||
},
|
||||
{
|
||||
left: Number,
|
||||
"*"(a, b) {
|
||||
return Vec2.mul_scalar(b, a);
|
||||
}
|
||||
},
|
||||
{
|
||||
right: Number,
|
||||
"*"(a, b) {
|
||||
return Vec2.mul_scalar(a, b);
|
||||
}
|
||||
});
|
||||
|
||||
var a = new Vec2(1, 2);
|
||||
var b = new Vec2(3, 4);
|
||||
var r;
|
||||
|
||||
r = a * 2 + 3 * b;
|
||||
assert(r.x === 11 && r.y === 16);
|
||||
assert(a == a, true);
|
||||
assert(a == b, false);
|
||||
assert(a != a, false);
|
||||
assert(a < b, true);
|
||||
assert(a <= b, true);
|
||||
assert(b < a, false);
|
||||
assert(b <= a, false);
|
||||
assert(a <= a, true);
|
||||
assert(a >= a, true);
|
||||
a++;
|
||||
assert(a.x === 2 && a.y === 3);
|
||||
r = ++a;
|
||||
assert(a.x === 3 && a.y === 4);
|
||||
assert(r === a);
|
||||
}
|
||||
|
||||
/* operators overloading thru inheritance */
|
||||
function test_operators()
|
||||
{
|
||||
var Vec2;
|
||||
|
||||
function mul_scalar(p1, a) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x * a;
|
||||
r.y = p1.y * a;
|
||||
return r;
|
||||
}
|
||||
|
||||
var vec2_ops = Operators({
|
||||
"+"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x + p2.x;
|
||||
r.y = p1.y + p2.y;
|
||||
return r;
|
||||
},
|
||||
"-"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x - p2.x;
|
||||
r.y = p1.y - p2.y;
|
||||
return r;
|
||||
},
|
||||
"=="(a, b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
},
|
||||
"<"(a, b) {
|
||||
var r;
|
||||
/* lexicographic order */
|
||||
if (a.x == b.x)
|
||||
r = (a.y < b.y);
|
||||
else
|
||||
r = (a.x < b.x);
|
||||
return r;
|
||||
},
|
||||
"++"(a) {
|
||||
var r = new Vec2();
|
||||
r.x = a.x + 1;
|
||||
r.y = a.y + 1;
|
||||
return r;
|
||||
}
|
||||
},
|
||||
{
|
||||
left: Number,
|
||||
"*"(a, b) {
|
||||
return mul_scalar(b, a);
|
||||
}
|
||||
},
|
||||
{
|
||||
right: Number,
|
||||
"*"(a, b) {
|
||||
return mul_scalar(a, b);
|
||||
}
|
||||
});
|
||||
|
||||
Vec2 = class Vec2 extends vec2_ops
|
||||
{
|
||||
constructor(x, y) {
|
||||
super();
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
toString() {
|
||||
return "Vec2(" + this.x + "," + this.y + ")";
|
||||
}
|
||||
}
|
||||
|
||||
var a = new Vec2(1, 2);
|
||||
var b = new Vec2(3, 4);
|
||||
var r;
|
||||
|
||||
r = a * 2 + 3 * b;
|
||||
assert(r.x === 11 && r.y === 16);
|
||||
assert(a == a, true);
|
||||
assert(a == b, false);
|
||||
assert(a != a, false);
|
||||
assert(a < b, true);
|
||||
assert(a <= b, true);
|
||||
assert(b < a, false);
|
||||
assert(b <= a, false);
|
||||
assert(a <= a, true);
|
||||
assert(a >= a, true);
|
||||
a++;
|
||||
assert(a.x === 2 && a.y === 3);
|
||||
r = ++a;
|
||||
assert(a.x === 3 && a.y === 4);
|
||||
assert(r === a);
|
||||
}
|
||||
|
||||
function test_default_op()
|
||||
{
|
||||
assert(Object(1) + 2, 3);
|
||||
assert(Object(1) + true, 2);
|
||||
assert(-Object(1), -1);
|
||||
}
|
||||
|
||||
test_operators_create();
|
||||
test_operators();
|
||||
test_default_op();
|
@ -1,256 +0,0 @@
|
||||
"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");
|
||||
|
||||
assert(typeof 1 === "number");
|
||||
assert(typeof 9007199254740991 === "number");
|
||||
assert(typeof 9007199254740992 === "bigint");
|
||||
}
|
||||
|
||||
function test_float()
|
||||
{
|
||||
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_fraction()
|
||||
{
|
||||
assert((1/3 + 1).toString(), "4/3")
|
||||
assert((2/3)^30, 1073741824/205891132094649);
|
||||
assert(1/3 < 2/3);
|
||||
assert(1/3 < 1);
|
||||
assert(1/3 == 1.0/3);
|
||||
assert(1.0/3 < 2/3);
|
||||
}
|
||||
|
||||
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_fraction();
|
||||
test_mod();
|
||||
test_polynomial();
|
||||
test_poly_mod();
|
||||
test_rfunc();
|
||||
test_series();
|
||||
test_matrix();
|
||||
test_trig();
|
@ -46,7 +46,7 @@ function test_file1()
|
||||
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);
|
||||
@ -81,7 +81,7 @@ function test_file2()
|
||||
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++) {
|
||||
@ -103,7 +103,7 @@ function test_getline()
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
||||
|
||||
function test_popen()
|
||||
{
|
||||
var str, f, fname = "tmp_file.txt";
|
||||
@ -115,7 +115,7 @@ function test_popen()
|
||||
|
||||
/* test loadFile */
|
||||
assert(std.loadFile(fname), content);
|
||||
|
||||
|
||||
/* execute the 'cat' shell command */
|
||||
f = std.popen("cat " + fname, "r");
|
||||
str = f.readAsString();
|
||||
@ -144,23 +144,25 @@ function test_os()
|
||||
{
|
||||
var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
|
||||
|
||||
assert(os.isatty(0));
|
||||
const stdinIsTTY = !os.exec(["/bin/sh", "-c", "test -t 0"], { usePath: false });
|
||||
|
||||
assert(os.isatty(0), stdinIsTTY, `isatty(STDIN)`);
|
||||
|
||||
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;
|
||||
@ -169,16 +171,16 @@ function test_os()
|
||||
assert(os.seek(fd, 0, std.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]);
|
||||
|
||||
|
||||
if (typeof BigInt !== "undefined") {
|
||||
assert(os.seek(fd, BigInt(6), std.SEEK_SET), BigInt(6));
|
||||
assert(os.read(fd, buf2.buffer, 0, 1) === 1);
|
||||
assert(buf[6] == buf2[0]);
|
||||
}
|
||||
|
||||
|
||||
assert(os.close(fd) === 0);
|
||||
|
||||
[files, err] = os.readdir(fdir);
|
||||
@ -189,7 +191,7 @@ function test_os()
|
||||
|
||||
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);
|
||||
@ -197,7 +199,7 @@ function test_os()
|
||||
|
||||
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);
|
||||
@ -205,7 +207,7 @@ function test_os()
|
||||
[buf, err] = os.readlink(link_path);
|
||||
assert(err, 0);
|
||||
assert(buf, fname);
|
||||
|
||||
|
||||
assert(os.remove(link_path) === 0);
|
||||
|
||||
[buf, err] = os.getcwd();
|
||||
@ -215,7 +217,7 @@ function test_os()
|
||||
assert(err, 0);
|
||||
|
||||
assert(buf, buf2);
|
||||
|
||||
|
||||
assert(os.remove(fpath) === 0);
|
||||
|
||||
fd = os.open(fpath, os.O_RDONLY);
|
||||
@ -233,7 +235,7 @@ function test_os_exec()
|
||||
|
||||
ret = os.exec(["/bin/sh", "-c", "exit 1"], { usePath: false });
|
||||
assert(ret, 1);
|
||||
|
||||
|
||||
fds = os.pipe();
|
||||
pid = os.exec(["sh", "-c", "echo $FOO"], {
|
||||
stdout: fds[1],
|
||||
@ -253,10 +255,11 @@ function test_os_exec()
|
||||
|
||||
pid = os.exec(["cat"], { block: false } );
|
||||
assert(pid >= 0);
|
||||
os.kill(pid, os.SIGQUIT);
|
||||
os.kill(pid, os.SIGTERM);
|
||||
[ret, status] = os.waitpid(pid, 0);
|
||||
assert(ret, pid);
|
||||
assert(status & 0x7f, os.SIGQUIT);
|
||||
assert(status !== 0, true, `expect nonzero exit code (got ${status})`);
|
||||
assert(status & 0x7f, os.SIGTERM);
|
||||
}
|
||||
|
||||
function test_timer()
|
||||
@ -277,16 +280,16 @@ function test_async_gc()
|
||||
{
|
||||
(async function run () {
|
||||
let obj = {}
|
||||
|
||||
|
||||
let done = () => {
|
||||
obj
|
||||
std.gc();
|
||||
}
|
||||
|
||||
|
||||
Promise.resolve().then(done)
|
||||
|
||||
|
||||
const p = new Promise(() => {})
|
||||
|
||||
|
||||
await p
|
||||
})();
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ function handle_msg(e) {
|
||||
switch(ev.type) {
|
||||
case "abort":
|
||||
parent.postMessage({ type: "done" });
|
||||
parent.onMessage = null; /* terminate the worker */
|
||||
parent.onmessage = null; /* terminate the worker */
|
||||
break;
|
||||
case "sab":
|
||||
/* modify the SharedArrayBuffer */
|
||||
@ -22,10 +22,10 @@ function handle_msg(e) {
|
||||
|
||||
function worker_main() {
|
||||
var i;
|
||||
|
||||
|
||||
parent.onmessage = handle_msg;
|
||||
for(i = 0; i < 10; i++) {
|
||||
parent.postMessage({ type: "num", num: i });
|
||||
parent.postMessage({ type: "num", num: i });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
url="ftp://ftp.unicode.org/Public/15.0.0/ucd"
|
||||
url="ftp://ftp.unicode.org/Public/16.0.0/ucd"
|
||||
emoji_url="${url}/emoji/emoji-data.txt"
|
||||
|
||||
files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \
|
||||
@ -15,5 +15,5 @@ for f in $files; do
|
||||
g="${url}/${f}"
|
||||
wget $g -O unicode/$f
|
||||
done
|
||||
|
||||
|
||||
wget $emoji_url -O unicode/emoji-data.txt
|
||||
|
338
unicode_gen.c
338
unicode_gen.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Generation of Unicode tables
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
* Copyright (c) 2017-2018 Charlie Gordon
|
||||
*
|
||||
@ -33,6 +33,11 @@
|
||||
|
||||
#include "cutils.h"
|
||||
|
||||
uint32_t total_tables;
|
||||
uint32_t total_table_bytes;
|
||||
uint32_t total_index;
|
||||
uint32_t total_index_bytes;
|
||||
|
||||
/* define it to be able to test unicode.c */
|
||||
//#define USE_TEST
|
||||
/* profile tests */
|
||||
@ -268,7 +273,7 @@ int find_name(const char **tab, int tab_len, const char *name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int get_prop(uint32_t c, int prop_idx)
|
||||
static BOOL get_prop(uint32_t c, int prop_idx)
|
||||
{
|
||||
return (unicode_db[c].prop_bitmap_tab[prop_idx >> 5] >> (prop_idx & 0x1f)) & 1;
|
||||
}
|
||||
@ -291,7 +296,7 @@ void parse_unicode_data(const char *filename)
|
||||
const char *p;
|
||||
int code, lc, uc, last_code;
|
||||
CCInfo *ci, *tab = unicode_db;
|
||||
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
@ -314,7 +319,7 @@ void parse_unicode_data(const char *filename)
|
||||
code = strtoul(p, NULL, 16);
|
||||
lc = 0;
|
||||
uc = 0;
|
||||
|
||||
|
||||
p = get_field(line, 12);
|
||||
if (p && *p != ';') {
|
||||
uc = strtoul(p, NULL, 16);
|
||||
@ -350,7 +355,7 @@ void parse_unicode_data(const char *filename)
|
||||
}
|
||||
ci->general_category = i;
|
||||
}
|
||||
|
||||
|
||||
p = get_field(line, 3);
|
||||
if (p && *p != ';' && *p != '\0') {
|
||||
int cc;
|
||||
@ -402,7 +407,7 @@ void parse_unicode_data(const char *filename)
|
||||
if (p && *p == 'Y') {
|
||||
set_prop(code, PROP_Bidi_Mirrored, 1);
|
||||
}
|
||||
|
||||
|
||||
/* handle ranges */
|
||||
get_field_buf(buf1, sizeof(buf1), line, 1);
|
||||
if (strstr(buf1, " Last>")) {
|
||||
@ -416,7 +421,7 @@ void parse_unicode_data(const char *filename)
|
||||
}
|
||||
last_code = code;
|
||||
}
|
||||
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
@ -427,7 +432,7 @@ void parse_special_casing(CCInfo *tab, const char *filename)
|
||||
const char *p;
|
||||
int code;
|
||||
CCInfo *ci;
|
||||
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
@ -458,8 +463,8 @@ void parse_special_casing(CCInfo *tab, const char *filename)
|
||||
if (*p != '#' && *p != '\0')
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
p = get_field(line, 1);
|
||||
if (p && *p != ';') {
|
||||
ci->l_len = 0;
|
||||
@ -492,7 +497,7 @@ void parse_special_casing(CCInfo *tab, const char *filename)
|
||||
ci->u_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
@ -503,7 +508,7 @@ void parse_case_folding(CCInfo *tab, const char *filename)
|
||||
const char *p;
|
||||
int code, status;
|
||||
CCInfo *ci;
|
||||
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
@ -535,7 +540,7 @@ void parse_case_folding(CCInfo *tab, const char *filename)
|
||||
status = *p;
|
||||
if (status != 'C' && status != 'S' && status != 'F')
|
||||
continue;
|
||||
|
||||
|
||||
p = get_field(line, 2);
|
||||
assert(p != NULL);
|
||||
if (status == 'S') {
|
||||
@ -555,7 +560,7 @@ void parse_case_folding(CCInfo *tab, const char *filename)
|
||||
ci->f_data[ci->f_len++] = strtoul(p, (char **)&p, 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
@ -564,7 +569,7 @@ void parse_composition_exclusions(const char *filename)
|
||||
FILE *f;
|
||||
char line[4096], *p;
|
||||
uint32_t c0;
|
||||
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
@ -592,7 +597,7 @@ void parse_derived_core_properties(const char *filename)
|
||||
char line[4096], *p, buf[256], *q;
|
||||
uint32_t c0, c1, c;
|
||||
int i;
|
||||
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
@ -620,7 +625,7 @@ void parse_derived_core_properties(const char *filename)
|
||||
p++;
|
||||
p += strspn(p, " \t");
|
||||
q = buf;
|
||||
while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') {
|
||||
while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t' && *p != ';') {
|
||||
if ((q - buf) < sizeof(buf) - 1)
|
||||
*q++ = *p;
|
||||
p++;
|
||||
@ -648,7 +653,7 @@ void parse_derived_norm_properties(const char *filename)
|
||||
FILE *f;
|
||||
char line[4096], *p, buf[256], *q;
|
||||
uint32_t c0, c1, c;
|
||||
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
@ -698,7 +703,7 @@ void parse_prop_list(const char *filename)
|
||||
char line[4096], *p, buf[256], *q;
|
||||
uint32_t c0, c1, c;
|
||||
int i;
|
||||
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
@ -752,7 +757,7 @@ void parse_scripts(const char *filename)
|
||||
char line[4096], *p, buf[256], *q;
|
||||
uint32_t c0, c1, c;
|
||||
int i;
|
||||
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
@ -807,7 +812,7 @@ void parse_script_extensions(const char *filename)
|
||||
int i;
|
||||
uint8_t script_ext[255];
|
||||
int script_ext_len;
|
||||
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
@ -972,7 +977,7 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code)
|
||||
ci1 = &tab[code + 1];
|
||||
ci2 = &tab[code + 2];
|
||||
te->code = code;
|
||||
|
||||
|
||||
if (ci->l_len == 1 && ci->l_data[0] == code + 2 &&
|
||||
ci->f_len == 1 && ci->f_data[0] == ci->l_data[0] &&
|
||||
ci->u_len == 0 &&
|
||||
@ -1112,6 +1117,24 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code)
|
||||
te->ext_data[1] = ci->u_data[1];
|
||||
te->ext_data[2] = ci->u_data[2];
|
||||
te->ext_len = 3;
|
||||
} else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_len == 1) {
|
||||
// U+FB05 LATIN SMALL LIGATURE LONG S T
|
||||
assert(code == 0xFB05);
|
||||
te->len = 1;
|
||||
te->type = RUN_TYPE_UF_EXT2;
|
||||
te->ext_data[0] = ci->u_data[0];
|
||||
te->ext_data[1] = ci->u_data[1];
|
||||
te->ext_len = 2;
|
||||
} else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_len == 1) {
|
||||
// U+1FD3 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA or
|
||||
// U+1FE3 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
|
||||
assert(code == 0x1FD3 || code == 0x1FE3);
|
||||
te->len = 1;
|
||||
te->type = RUN_TYPE_UF_EXT3;
|
||||
te->ext_data[0] = ci->u_data[0];
|
||||
te->ext_data[1] = ci->u_data[1];
|
||||
te->ext_data[2] = ci->u_data[2];
|
||||
te->ext_len = 3;
|
||||
} else {
|
||||
printf("unsupported encoding case:\n");
|
||||
dump_cc_info(ci, code);
|
||||
@ -1140,7 +1163,7 @@ void find_run_type(TableEntry *te, CCInfo *tab, int code)
|
||||
te->data = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ci = &tab[code];
|
||||
is_lower = ci->l_len > 0;
|
||||
len = 1;
|
||||
@ -1221,7 +1244,7 @@ void build_conv_table(CCInfo *tab)
|
||||
int code, i, j;
|
||||
CCInfo *ci;
|
||||
TableEntry *te;
|
||||
|
||||
|
||||
te = conv_table;
|
||||
for(code = 0; code <= CHARCODE_MAX; code++) {
|
||||
ci = &tab[code];
|
||||
@ -1245,7 +1268,7 @@ void build_conv_table(CCInfo *tab)
|
||||
for(i = 0; i < conv_table_len; i++) {
|
||||
int data_index;
|
||||
te = &conv_table[i];
|
||||
|
||||
|
||||
switch(te->type) {
|
||||
case RUN_TYPE_U:
|
||||
case RUN_TYPE_L:
|
||||
@ -1328,7 +1351,9 @@ void dump_case_conv_table(FILE *f)
|
||||
uint32_t v;
|
||||
const TableEntry *te;
|
||||
|
||||
fprintf(f, "static const uint32_t case_conv_table1[%u] = {", conv_table_len);
|
||||
total_tables++;
|
||||
total_table_bytes += conv_table_len * sizeof(uint32_t);
|
||||
fprintf(f, "static const uint32_t case_conv_table1[%d] = {", conv_table_len);
|
||||
for(i = 0; i < conv_table_len; i++) {
|
||||
if (i % 4 == 0)
|
||||
fprintf(f, "\n ");
|
||||
@ -1341,7 +1366,9 @@ void dump_case_conv_table(FILE *f)
|
||||
}
|
||||
fprintf(f, "\n};\n\n");
|
||||
|
||||
fprintf(f, "static const uint8_t case_conv_table2[%u] = {", conv_table_len);
|
||||
total_tables++;
|
||||
total_table_bytes += conv_table_len;
|
||||
fprintf(f, "static const uint8_t case_conv_table2[%d] = {", conv_table_len);
|
||||
for(i = 0; i < conv_table_len; i++) {
|
||||
if (i % 8 == 0)
|
||||
fprintf(f, "\n ");
|
||||
@ -1350,7 +1377,9 @@ void dump_case_conv_table(FILE *f)
|
||||
}
|
||||
fprintf(f, "\n};\n\n");
|
||||
|
||||
fprintf(f, "static const uint16_t case_conv_ext[%u] = {", ext_data_len);
|
||||
total_tables++;
|
||||
total_table_bytes += ext_data_len * sizeof(uint16_t);
|
||||
fprintf(f, "static const uint16_t case_conv_ext[%d] = {", ext_data_len);
|
||||
for(i = 0; i < ext_data_len; i++) {
|
||||
if (i % 8 == 0)
|
||||
fprintf(f, "\n ");
|
||||
@ -1374,7 +1403,7 @@ static int sp_cc_cmp(const void *p1, const void *p2)
|
||||
return memcmp(c1->f_data, c2->f_data, sizeof(c1->f_data[0]) * c1->f_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* dump the case special cases (multi character results which are
|
||||
identical and need specific handling in lre_canonicalize() */
|
||||
void dump_case_folding_special_cases(CCInfo *tab)
|
||||
@ -1394,7 +1423,7 @@ void dump_case_folding_special_cases(CCInfo *tab)
|
||||
len = 1;
|
||||
while ((i + len) <= CHARCODE_MAX && !sp_cc_cmp(&perm[i], &perm[i + len]))
|
||||
len++;
|
||||
|
||||
|
||||
if (len > 1) {
|
||||
for(j = i; j < i + len; j++)
|
||||
dump_cc_info(&tab[perm[j]], perm[j]);
|
||||
@ -1405,7 +1434,7 @@ void dump_case_folding_special_cases(CCInfo *tab)
|
||||
free(perm);
|
||||
global_tab = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int tabcmp(const int *tab1, const int *tab2, int n)
|
||||
{
|
||||
@ -1470,6 +1499,9 @@ void compute_internal_props(void)
|
||||
void dump_byte_table(FILE *f, const char *cname, const uint8_t *tab, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
total_tables++;
|
||||
total_table_bytes += len;
|
||||
fprintf(f, "static const uint8_t %s[%d] = {", cname, len);
|
||||
for(i = 0; i < len; i++) {
|
||||
if (i % 8 == 0)
|
||||
@ -1479,9 +1511,26 @@ void dump_byte_table(FILE *f, const char *cname, const uint8_t *tab, int len)
|
||||
fprintf(f, "\n};\n\n");
|
||||
}
|
||||
|
||||
void dump_index_table(FILE *f, const char *cname, const uint8_t *tab, int len)
|
||||
{
|
||||
int i, code, offset;
|
||||
|
||||
total_index++;
|
||||
total_index_bytes += len;
|
||||
fprintf(f, "static const uint8_t %s[%d] = {\n", cname, len);
|
||||
for(i = 0; i < len; i += 3) {
|
||||
code = tab[i] + (tab[i+1] << 8) + ((tab[i+2] & 0x1f) << 16);
|
||||
offset = ((i / 3) + 1) * 32 + (tab[i+2] >> 5);
|
||||
fprintf(f, " 0x%02x, 0x%02x, 0x%02x,", tab[i], tab[i+1], tab[i+2]);
|
||||
fprintf(f, " // %6.5X at %d%s\n", code, offset,
|
||||
i == len - 3 ? " (upper bound)" : "");
|
||||
}
|
||||
fprintf(f, "};\n\n");
|
||||
}
|
||||
|
||||
#define PROP_BLOCK_LEN 32
|
||||
|
||||
void build_prop_table(FILE *f, int prop_index, BOOL add_index)
|
||||
void build_prop_table(FILE *f, const char *name, int prop_index, BOOL add_index)
|
||||
{
|
||||
int i, j, n, v, offset, code;
|
||||
DynBuf dbuf_s, *dbuf = &dbuf_s;
|
||||
@ -1490,7 +1539,7 @@ void build_prop_table(FILE *f, int prop_index, BOOL add_index)
|
||||
const uint32_t *buf;
|
||||
int buf_len, block_end_pos, bit;
|
||||
char cname[128];
|
||||
|
||||
|
||||
dbuf_init(dbuf1);
|
||||
|
||||
for(i = 0; i <= CHARCODE_MAX;) {
|
||||
@ -1506,15 +1555,15 @@ void build_prop_table(FILE *f, int prop_index, BOOL add_index)
|
||||
dbuf_put_u32(dbuf1, n - 1);
|
||||
i += n;
|
||||
}
|
||||
|
||||
|
||||
dbuf_init(dbuf);
|
||||
dbuf_init(dbuf2);
|
||||
buf = (uint32_t *)dbuf1->buf;
|
||||
buf_len = dbuf1->size / sizeof(buf[0]);
|
||||
|
||||
|
||||
/* the first value is assumed to be 0 */
|
||||
assert(get_prop(0, prop_index) == 0);
|
||||
|
||||
|
||||
block_end_pos = PROP_BLOCK_LEN;
|
||||
i = 0;
|
||||
code = 0;
|
||||
@ -1533,6 +1582,14 @@ void build_prop_table(FILE *f, int prop_index, BOOL add_index)
|
||||
block_end_pos += PROP_BLOCK_LEN;
|
||||
}
|
||||
|
||||
/* Compressed byte encoding:
|
||||
00..3F: 2 packed lengths: 3-bit + 3-bit
|
||||
40..5F: 5-bits plus extra byte for length
|
||||
60..7F: 5-bits plus 2 extra bytes for length
|
||||
80..FF: 7-bit length
|
||||
lengths must be incremented to get character count
|
||||
Ranges alternate between false and true return value.
|
||||
*/
|
||||
v = buf[i];
|
||||
code += v + 1;
|
||||
bit ^= 1;
|
||||
@ -1573,9 +1630,9 @@ void build_prop_table(FILE *f, int prop_index, BOOL add_index)
|
||||
dump_byte_table(f, cname, dbuf->buf, dbuf->size);
|
||||
if (add_index) {
|
||||
snprintf(cname, sizeof(cname), "unicode_prop_%s_index", unicode_prop_name[prop_index]);
|
||||
dump_byte_table(f, cname, dbuf2->buf, dbuf2->size);
|
||||
dump_index_table(f, cname, dbuf2->buf, dbuf2->size);
|
||||
}
|
||||
|
||||
|
||||
dbuf_free(dbuf);
|
||||
dbuf_free(dbuf1);
|
||||
dbuf_free(dbuf2);
|
||||
@ -1583,10 +1640,10 @@ void build_prop_table(FILE *f, int prop_index, BOOL add_index)
|
||||
|
||||
void build_flags_tables(FILE *f)
|
||||
{
|
||||
build_prop_table(f, PROP_Cased1, TRUE);
|
||||
build_prop_table(f, PROP_Case_Ignorable, TRUE);
|
||||
build_prop_table(f, PROP_ID_Start, TRUE);
|
||||
build_prop_table(f, PROP_ID_Continue1, TRUE);
|
||||
build_prop_table(f, "Cased1", PROP_Cased1, TRUE);
|
||||
build_prop_table(f, "Case_Ignorable", PROP_Case_Ignorable, TRUE);
|
||||
build_prop_table(f, "ID_Start", PROP_ID_Start, TRUE);
|
||||
build_prop_table(f, "ID_Continue1", PROP_ID_Continue1, TRUE);
|
||||
}
|
||||
|
||||
void dump_name_table(FILE *f, const char *cname, const char **tab_name, int len,
|
||||
@ -1621,7 +1678,9 @@ void build_general_category_table(FILE *f)
|
||||
{
|
||||
int i, v, j, n, n1;
|
||||
DynBuf dbuf_s, *dbuf = &dbuf_s;
|
||||
#ifdef DUMP_TABLE_SIZE
|
||||
int cw_count, cw_len_count[4], cw_start;
|
||||
#endif
|
||||
|
||||
fprintf(f, "typedef enum {\n");
|
||||
for(i = 0; i < GCAT_COUNT; i++)
|
||||
@ -1635,9 +1694,11 @@ void build_general_category_table(FILE *f)
|
||||
|
||||
|
||||
dbuf_init(dbuf);
|
||||
#ifdef DUMP_TABLE_SIZE
|
||||
cw_count = 0;
|
||||
for(i = 0; i < 4; i++)
|
||||
cw_len_count[i] = 0;
|
||||
#endif
|
||||
for(i = 0; i <= CHARCODE_MAX;) {
|
||||
v = unicode_db[i].general_category;
|
||||
j = i + 1;
|
||||
@ -1656,9 +1717,11 @@ void build_general_category_table(FILE *f)
|
||||
}
|
||||
}
|
||||
// printf("%05x %05x %d\n", i, n, v);
|
||||
cw_count++;
|
||||
n--;
|
||||
#ifdef DUMP_TABLE_SIZE
|
||||
cw_count++;
|
||||
cw_start = dbuf->size;
|
||||
#endif
|
||||
if (n < 7) {
|
||||
dbuf_putc(dbuf, (n << 5) | v);
|
||||
} else if (n < 7 + 128) {
|
||||
@ -1680,17 +1743,18 @@ void build_general_category_table(FILE *f)
|
||||
dbuf_putc(dbuf, n1 >> 8);
|
||||
dbuf_putc(dbuf, n1);
|
||||
}
|
||||
#ifdef DUMP_TABLE_SIZE
|
||||
cw_len_count[dbuf->size - cw_start - 1]++;
|
||||
#endif
|
||||
i += n + 1;
|
||||
}
|
||||
#ifdef DUMP_TABLE_SIZE
|
||||
printf("general category: %d entries [",
|
||||
cw_count);
|
||||
printf("general category: %d entries [", cw_count);
|
||||
for(i = 0; i < 4; i++)
|
||||
printf(" %d", cw_len_count[i]);
|
||||
printf(" ], length=%d bytes\n", (int)dbuf->size);
|
||||
#endif
|
||||
|
||||
|
||||
dump_byte_table(f, "unicode_gc_table", dbuf->buf, dbuf->size);
|
||||
|
||||
dbuf_free(dbuf);
|
||||
@ -1700,7 +1764,9 @@ void build_script_table(FILE *f)
|
||||
{
|
||||
int i, v, j, n, n1, type;
|
||||
DynBuf dbuf_s, *dbuf = &dbuf_s;
|
||||
#ifdef DUMP_TABLE_SIZE
|
||||
int cw_count, cw_len_count[4], cw_start;
|
||||
#endif
|
||||
|
||||
fprintf(f, "typedef enum {\n");
|
||||
for(i = 0; i < SCRIPT_COUNT; i++)
|
||||
@ -1714,9 +1780,11 @@ void build_script_table(FILE *f)
|
||||
unicode_script_short_name + i);
|
||||
|
||||
dbuf_init(dbuf);
|
||||
#ifdef DUMP_TABLE_SIZE
|
||||
cw_count = 0;
|
||||
for(i = 0; i < 4; i++)
|
||||
cw_len_count[i] = 0;
|
||||
#endif
|
||||
for(i = 0; i <= CHARCODE_MAX;) {
|
||||
v = unicode_db[i].script;
|
||||
j = i + 1;
|
||||
@ -1726,9 +1794,11 @@ void build_script_table(FILE *f)
|
||||
if (v == 0 && j == (CHARCODE_MAX + 1))
|
||||
break;
|
||||
// printf("%05x %05x %d\n", i, n, v);
|
||||
cw_count++;
|
||||
n--;
|
||||
#ifdef DUMP_TABLE_SIZE
|
||||
cw_count++;
|
||||
cw_start = dbuf->size;
|
||||
#endif
|
||||
if (v == 0)
|
||||
type = 0;
|
||||
else
|
||||
@ -1750,17 +1820,18 @@ void build_script_table(FILE *f)
|
||||
if (type != 0)
|
||||
dbuf_putc(dbuf, v);
|
||||
|
||||
#ifdef DUMP_TABLE_SIZE
|
||||
cw_len_count[dbuf->size - cw_start - 1]++;
|
||||
#endif
|
||||
i += n + 1;
|
||||
}
|
||||
#if defined(DUMP_TABLE_SIZE)
|
||||
printf("script: %d entries [",
|
||||
cw_count);
|
||||
#ifdef DUMP_TABLE_SIZE
|
||||
printf("script: %d entries [", cw_count);
|
||||
for(i = 0; i < 4; i++)
|
||||
printf(" %d", cw_len_count[i]);
|
||||
printf(" ], length=%d bytes\n", (int)dbuf->size);
|
||||
#endif
|
||||
|
||||
|
||||
dump_byte_table(f, "unicode_script_table", dbuf->buf, dbuf->size);
|
||||
|
||||
dbuf_free(dbuf);
|
||||
@ -1770,10 +1841,11 @@ void build_script_ext_table(FILE *f)
|
||||
{
|
||||
int i, j, n, n1, script_ext_len;
|
||||
DynBuf dbuf_s, *dbuf = &dbuf_s;
|
||||
int cw_count;
|
||||
#if defined(DUMP_TABLE_SIZE)
|
||||
int cw_count = 0;
|
||||
#endif
|
||||
|
||||
dbuf_init(dbuf);
|
||||
cw_count = 0;
|
||||
for(i = 0; i <= CHARCODE_MAX;) {
|
||||
script_ext_len = unicode_db[i].script_ext_len;
|
||||
j = i + 1;
|
||||
@ -1784,7 +1856,9 @@ void build_script_ext_table(FILE *f)
|
||||
j++;
|
||||
}
|
||||
n = j - i;
|
||||
#if defined(DUMP_TABLE_SIZE)
|
||||
cw_count++;
|
||||
#endif
|
||||
n--;
|
||||
if (n < 128) {
|
||||
dbuf_putc(dbuf, n);
|
||||
@ -1806,11 +1880,10 @@ void build_script_ext_table(FILE *f)
|
||||
i += n + 1;
|
||||
}
|
||||
#ifdef DUMP_TABLE_SIZE
|
||||
printf("script_ext: %d entries",
|
||||
cw_count);
|
||||
printf("script_ext: %d entries", cw_count);
|
||||
printf(", length=%d bytes\n", (int)dbuf->size);
|
||||
#endif
|
||||
|
||||
|
||||
dump_byte_table(f, "unicode_script_ext_table", dbuf->buf, dbuf->size);
|
||||
|
||||
dbuf_free(dbuf);
|
||||
@ -1822,17 +1895,17 @@ void build_script_ext_table(FILE *f)
|
||||
void build_prop_list_table(FILE *f)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
for(i = 0; i < PROP_TABLE_COUNT; i++) {
|
||||
if (i == PROP_ID_Start ||
|
||||
i == PROP_Case_Ignorable ||
|
||||
i == PROP_ID_Continue1) {
|
||||
/* already generated */
|
||||
} else {
|
||||
build_prop_table(f, i, FALSE);
|
||||
build_prop_table(f, unicode_prop_name[i], i, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fprintf(f, "typedef enum {\n");
|
||||
for(i = 0; i < PROP_COUNT; i++)
|
||||
fprintf(f, " UNICODE_PROP_%s,\n", unicode_prop_name[i]);
|
||||
@ -1870,7 +1943,7 @@ void check_case_conv(void)
|
||||
int l, error;
|
||||
CCInfo ci_s, *ci1, *ci = &ci_s;
|
||||
int code;
|
||||
|
||||
|
||||
for(code = 0; code <= CHARCODE_MAX; code++) {
|
||||
ci1 = &tab[code];
|
||||
*ci = *ci1;
|
||||
@ -1926,7 +1999,7 @@ void check_flags(void)
|
||||
BOOL flag_ref, flag;
|
||||
for(c = 0; c <= CHARCODE_MAX; c++) {
|
||||
flag_ref = get_prop(c, PROP_Cased);
|
||||
flag = lre_is_cased(c);
|
||||
flag = !!lre_is_cased(c);
|
||||
if (flag != flag_ref) {
|
||||
printf("ERROR: c=%05x cased=%d ref=%d\n",
|
||||
c, flag, flag_ref);
|
||||
@ -1934,7 +2007,7 @@ void check_flags(void)
|
||||
}
|
||||
|
||||
flag_ref = get_prop(c, PROP_Case_Ignorable);
|
||||
flag = lre_is_case_ignorable(c);
|
||||
flag = !!lre_is_case_ignorable(c);
|
||||
if (flag != flag_ref) {
|
||||
printf("ERROR: c=%05x case_ignorable=%d ref=%d\n",
|
||||
c, flag, flag_ref);
|
||||
@ -1942,7 +2015,7 @@ void check_flags(void)
|
||||
}
|
||||
|
||||
flag_ref = get_prop(c, PROP_ID_Start);
|
||||
flag = lre_is_id_start(c);
|
||||
flag = !!lre_is_id_start(c);
|
||||
if (flag != flag_ref) {
|
||||
printf("ERROR: c=%05x id_start=%d ref=%d\n",
|
||||
c, flag, flag_ref);
|
||||
@ -1950,7 +2023,7 @@ void check_flags(void)
|
||||
}
|
||||
|
||||
flag_ref = get_prop(c, PROP_ID_Continue);
|
||||
flag = lre_is_id_continue(c);
|
||||
flag = !!lre_is_id_continue(c);
|
||||
if (flag != flag_ref) {
|
||||
printf("ERROR: c=%05x id_cont=%d ref=%d\n",
|
||||
c, flag, flag_ref);
|
||||
@ -1964,7 +2037,7 @@ void check_flags(void)
|
||||
count = 0;
|
||||
for(c = 0x20; c <= 0xffff; c++) {
|
||||
flag_ref = get_prop(c, PROP_ID_Start);
|
||||
flag = lre_is_id_start(c);
|
||||
flag = !!lre_is_id_start(c);
|
||||
assert(flag == flag_ref);
|
||||
count++;
|
||||
}
|
||||
@ -1981,17 +2054,23 @@ void check_flags(void)
|
||||
|
||||
void build_cc_table(FILE *f)
|
||||
{
|
||||
int i, cc, n, cc_table_len, type, n1;
|
||||
// Compress combining class table
|
||||
// see: https://www.unicode.org/reports/tr44/#Canonical_Combining_Class_Values
|
||||
int i, cc, n, type, n1, block_end_pos;
|
||||
DynBuf dbuf_s, *dbuf = &dbuf_s;
|
||||
DynBuf dbuf1_s, *dbuf1 = &dbuf1_s;
|
||||
int cw_len_tab[3], cw_start, block_end_pos;
|
||||
#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)
|
||||
int cw_len_tab[3], cw_start, cc_table_len;
|
||||
#endif
|
||||
uint32_t v;
|
||||
|
||||
|
||||
dbuf_init(dbuf);
|
||||
dbuf_init(dbuf1);
|
||||
#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)
|
||||
cc_table_len = 0;
|
||||
for(i = 0; i < countof(cw_len_tab); i++)
|
||||
cw_len_tab[i] = 0;
|
||||
#endif
|
||||
block_end_pos = CC_BLOCK_LEN;
|
||||
for(i = 0; i <= CHARCODE_MAX;) {
|
||||
cc = unicode_db[i].combining_class;
|
||||
@ -2032,7 +2111,16 @@ void build_cc_table(FILE *f)
|
||||
dbuf_putc(dbuf1, v >> 16);
|
||||
block_end_pos += CC_BLOCK_LEN;
|
||||
}
|
||||
#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)
|
||||
cw_start = dbuf->size;
|
||||
#endif
|
||||
/* Compressed run length encoding:
|
||||
- 2 high order bits are combining class type
|
||||
- 0:0, 1:230, 2:extra byte linear progression, 3:extra byte
|
||||
- 00..2F: range length (add 1)
|
||||
- 30..37: 3-bit range-length + 1 extra byte
|
||||
- 38..3F: 3-bit range-length + 2 extra byte
|
||||
*/
|
||||
if (n1 < 48) {
|
||||
dbuf_putc(dbuf, n1 | (type << 6));
|
||||
} else if (n1 < 48 + (1 << 11)) {
|
||||
@ -2046,10 +2134,12 @@ void build_cc_table(FILE *f)
|
||||
dbuf_putc(dbuf, n1 >> 8);
|
||||
dbuf_putc(dbuf, n1);
|
||||
}
|
||||
#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)
|
||||
cw_len_tab[dbuf->size - cw_start - 1]++;
|
||||
cc_table_len++;
|
||||
#endif
|
||||
if (type == 0 || type == 1)
|
||||
dbuf_putc(dbuf, cc);
|
||||
cc_table_len++;
|
||||
i += n;
|
||||
}
|
||||
|
||||
@ -2058,9 +2148,9 @@ void build_cc_table(FILE *f)
|
||||
dbuf_putc(dbuf1, v);
|
||||
dbuf_putc(dbuf1, v >> 8);
|
||||
dbuf_putc(dbuf1, v >> 16);
|
||||
|
||||
|
||||
dump_byte_table(f, "unicode_cc_table", dbuf->buf, dbuf->size);
|
||||
dump_byte_table(f, "unicode_cc_index", dbuf1->buf, dbuf1->size);
|
||||
dump_index_table(f, "unicode_cc_index", dbuf1->buf, dbuf1->size);
|
||||
|
||||
#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)
|
||||
printf("CC table: size=%d (%d entries) [",
|
||||
@ -2163,7 +2253,7 @@ const int decomp_incr_tab[4][4] = {
|
||||
/*
|
||||
entry size:
|
||||
type bits
|
||||
code 18
|
||||
code 18
|
||||
len 7
|
||||
compat 1
|
||||
type 5
|
||||
@ -2272,7 +2362,7 @@ void find_decomp_run(DecompEntry *tab_de, int i)
|
||||
DecompEntry de_s, *de = &de_s;
|
||||
CCInfo *ci, *ci1, *ci2;
|
||||
int l, j, n, len_max;
|
||||
|
||||
|
||||
ci = &unicode_db[i];
|
||||
l = ci->decomp_len;
|
||||
if (l == 0) {
|
||||
@ -2283,12 +2373,12 @@ void find_decomp_run(DecompEntry *tab_de, int i)
|
||||
/* the offset for the compose table has only 6 bits, so we must
|
||||
limit if it can be used by the compose table */
|
||||
if (!ci->is_compat && !ci->is_excluded && l == 2)
|
||||
len_max = 64;
|
||||
len_max = 64;
|
||||
else
|
||||
len_max = 127;
|
||||
|
||||
|
||||
tab_de[i].cost = 0x7fffffff;
|
||||
|
||||
|
||||
if (!is_16bit(ci->decomp_data, l)) {
|
||||
assert(l <= 2);
|
||||
|
||||
@ -2331,7 +2421,7 @@ void find_decomp_run(DecompEntry *tab_de, int i)
|
||||
if (de->cost < tab_de[i].cost) {
|
||||
tab_de[i] = *de;
|
||||
}
|
||||
|
||||
|
||||
if (!((i + n) <= CHARCODE_MAX && n < len_max))
|
||||
break;
|
||||
ci1 = &unicode_db[i + n];
|
||||
@ -2344,7 +2434,7 @@ void find_decomp_run(DecompEntry *tab_de, int i)
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (l <= 8 || l == 18) {
|
||||
int c_min, c_max, c;
|
||||
c_min = c_max = -1;
|
||||
@ -2415,7 +2505,7 @@ void find_decomp_run(DecompEntry *tab_de, int i)
|
||||
/* check if a single char is increasing */
|
||||
if (l <= 4) {
|
||||
int idx1, idx;
|
||||
|
||||
|
||||
for(idx1 = 1; (idx = decomp_incr_tab[l - 1][idx1]) >= 0; idx1++) {
|
||||
n = 1;
|
||||
for(;;) {
|
||||
@ -2499,7 +2589,7 @@ void find_decomp_run(DecompEntry *tab_de, int i)
|
||||
|
||||
if (l == 2) {
|
||||
BOOL is_16bit;
|
||||
|
||||
|
||||
n = 0;
|
||||
is_16bit = FALSE;
|
||||
for(;;) {
|
||||
@ -2544,7 +2634,7 @@ void add_decomp_data(uint8_t *data_buf, int *pidx, DecompEntry *de)
|
||||
{
|
||||
int i, j, idx, c;
|
||||
CCInfo *ci;
|
||||
|
||||
|
||||
idx = *pidx;
|
||||
de->data_index = idx;
|
||||
if (de->type <= DECOMP_TYPE_C1) {
|
||||
@ -2695,9 +2785,9 @@ void build_decompose_table(FILE *f)
|
||||
int i, array_len, code_max, data_len, count;
|
||||
DecompEntry *tab_de, de_s, *de = &de_s;
|
||||
uint8_t *data_buf;
|
||||
|
||||
|
||||
code_max = CHARCODE_MAX;
|
||||
|
||||
|
||||
tab_de = mallocz((code_max + 2) * sizeof(*tab_de));
|
||||
|
||||
for(i = code_max; i >= 0; i--) {
|
||||
@ -2721,7 +2811,7 @@ void build_decompose_table(FILE *f)
|
||||
/* dump */
|
||||
{
|
||||
int size, size1;
|
||||
|
||||
|
||||
printf("START LEN TYPE L C SIZE\n");
|
||||
size = 0;
|
||||
for(i = 0; i <= code_max; i++) {
|
||||
@ -2735,14 +2825,15 @@ void build_decompose_table(FILE *f)
|
||||
size += size1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
printf("array_len=%d estimated size=%d bytes actual=%d bytes\n",
|
||||
array_len, size, array_len * 6 + data_len);
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(f, "static const uint32_t unicode_decomp_table1[%u] = {",
|
||||
array_len);
|
||||
total_tables++;
|
||||
total_table_bytes += array_len * sizeof(uint32_t);
|
||||
fprintf(f, "static const uint32_t unicode_decomp_table1[%d] = {", array_len);
|
||||
count = 0;
|
||||
for(i = 0; i <= code_max; i++) {
|
||||
de = &tab_de[i];
|
||||
@ -2760,8 +2851,9 @@ void build_decompose_table(FILE *f)
|
||||
}
|
||||
fprintf(f, "\n};\n\n");
|
||||
|
||||
fprintf(f, "static const uint16_t unicode_decomp_table2[%u] = {",
|
||||
array_len);
|
||||
total_tables++;
|
||||
total_table_bytes += array_len * sizeof(uint16_t);
|
||||
fprintf(f, "static const uint16_t unicode_decomp_table2[%d] = {", array_len);
|
||||
count = 0;
|
||||
for(i = 0; i <= code_max; i++) {
|
||||
de = &tab_de[i];
|
||||
@ -2773,9 +2865,10 @@ void build_decompose_table(FILE *f)
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n};\n\n");
|
||||
|
||||
fprintf(f, "static const uint8_t unicode_decomp_data[%u] = {",
|
||||
data_len);
|
||||
|
||||
total_tables++;
|
||||
total_table_bytes += data_len;
|
||||
fprintf(f, "static const uint8_t unicode_decomp_data[%d] = {", data_len);
|
||||
for(i = 0; i < data_len; i++) {
|
||||
if (i % 8 == 0)
|
||||
fprintf(f, "\n ");
|
||||
@ -2786,7 +2879,7 @@ void build_decompose_table(FILE *f)
|
||||
build_compose_table(f, tab_de);
|
||||
|
||||
free(data_buf);
|
||||
|
||||
|
||||
free(tab_de);
|
||||
}
|
||||
|
||||
@ -2817,7 +2910,7 @@ static int get_decomp_pos(const DecompEntry *tab_de, int c)
|
||||
{
|
||||
int i, v, k;
|
||||
const DecompEntry *de;
|
||||
|
||||
|
||||
k = 0;
|
||||
for(i = 0; i <= CHARCODE_MAX; i++) {
|
||||
de = &tab_de[i];
|
||||
@ -2840,14 +2933,14 @@ void build_compose_table(FILE *f, const DecompEntry *tab_de)
|
||||
{
|
||||
int i, v, tab_ce_len;
|
||||
ComposeEntry *ce, *tab_ce;
|
||||
|
||||
|
||||
tab_ce = malloc(sizeof(*tab_ce) * COMPOSE_LEN_MAX);
|
||||
tab_ce_len = 0;
|
||||
for(i = 0; i <= CHARCODE_MAX; i++) {
|
||||
CCInfo *ci = &unicode_db[i];
|
||||
if (ci->decomp_len == 2 && !ci->is_compat &&
|
||||
!ci->is_excluded) {
|
||||
assert(tab_ce_len < COMPOSE_LEN_MAX);
|
||||
assert(tab_ce_len < COMPOSE_LEN_MAX);
|
||||
ce = &tab_ce[tab_ce_len++];
|
||||
ce->c[0] = ci->decomp_data[0];
|
||||
ce->c[1] = ci->decomp_data[1];
|
||||
@ -2865,9 +2958,10 @@ void build_compose_table(FILE *f, const DecompEntry *tab_de)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(f, "static const uint16_t unicode_comp_table[%u] = {",
|
||||
tab_ce_len);
|
||||
|
||||
total_tables++;
|
||||
total_table_bytes += tab_ce_len * sizeof(uint16_t);
|
||||
fprintf(f, "static const uint16_t unicode_comp_table[%u] = {", tab_ce_len);
|
||||
for(i = 0; i < tab_ce_len; i++) {
|
||||
if (i % 8 == 0)
|
||||
fprintf(f, "\n ");
|
||||
@ -2880,7 +2974,7 @@ void build_compose_table(FILE *f, const DecompEntry *tab_de)
|
||||
fprintf(f, " 0x%04x,", v);
|
||||
}
|
||||
fprintf(f, "\n};\n\n");
|
||||
|
||||
|
||||
free(tab_ce);
|
||||
}
|
||||
|
||||
@ -2929,7 +3023,7 @@ void check_compose_table(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -2969,7 +3063,7 @@ void check_cc_table(void)
|
||||
#ifdef PROFILE
|
||||
{
|
||||
int64_t ti, count;
|
||||
|
||||
|
||||
ti = get_time_ns();
|
||||
count = 0;
|
||||
/* only do it on meaningful chars */
|
||||
@ -2992,7 +3086,7 @@ void normalization_test(const char *filename)
|
||||
int *in_str, *nfc_str, *nfd_str, *nfkc_str, *nfkd_str;
|
||||
int in_len, nfc_len, nfd_len, nfkc_len, nfkd_len;
|
||||
int *buf, buf_len, pos;
|
||||
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
@ -3023,7 +3117,7 @@ void normalization_test(const char *filename)
|
||||
buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFKD, NULL, NULL);
|
||||
check_str("nfkd", pos, in_str, in_len, buf, buf_len, nfkd_str, nfkd_len);
|
||||
free(buf);
|
||||
|
||||
|
||||
buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFC, NULL, NULL);
|
||||
check_str("nfc", pos, in_str, in_len, buf, buf_len, nfc_str, nfc_len);
|
||||
free(buf);
|
||||
@ -3042,22 +3136,24 @@ void normalization_test(const char *filename)
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *unicode_db_path, *outfilename;
|
||||
char filename[1024];
|
||||
|
||||
if (argc < 2) {
|
||||
printf("usage: %s unicode_db_path [output_file]\n"
|
||||
"\n"
|
||||
"If no output_file is given, a self test is done using the current unicode library\n",
|
||||
argv[0]);
|
||||
exit(1);
|
||||
int arg = 1;
|
||||
|
||||
if (arg >= argc || (!strcmp(argv[arg], "-h") || !strcmp(argv[arg], "--help"))) {
|
||||
printf("usage: %s PATH [OUTPUT]\n"
|
||||
" PATH path to the Unicode database directory\n"
|
||||
" OUTPUT name of the output file. If omitted, a self test is performed\n"
|
||||
" using the files from the Unicode library\n"
|
||||
, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
unicode_db_path = argv[1];
|
||||
unicode_db_path = argv[arg++];
|
||||
outfilename = NULL;
|
||||
if (argc >= 3)
|
||||
outfilename = argv[2];
|
||||
if (arg < argc)
|
||||
outfilename = argv[arg++];
|
||||
|
||||
unicode_db = mallocz(sizeof(unicode_db[0]) * (CHARCODE_MAX + 1));
|
||||
|
||||
@ -3067,13 +3163,13 @@ int main(int argc, char **argv)
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s/SpecialCasing.txt", unicode_db_path);
|
||||
parse_special_casing(unicode_db, filename);
|
||||
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s/CaseFolding.txt", unicode_db_path);
|
||||
parse_case_folding(unicode_db, filename);
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s/CompositionExclusions.txt", unicode_db_path);
|
||||
parse_composition_exclusions(filename);
|
||||
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s/DerivedCoreProperties.txt", unicode_db_path);
|
||||
parse_derived_core_properties(filename);
|
||||
|
||||
@ -3089,7 +3185,7 @@ int main(int argc, char **argv)
|
||||
snprintf(filename, sizeof(filename), "%s/ScriptExtensions.txt",
|
||||
unicode_db_path);
|
||||
parse_script_extensions(filename);
|
||||
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s/emoji-data.txt",
|
||||
unicode_db_path);
|
||||
parse_prop_list(filename);
|
||||
@ -3098,7 +3194,7 @@ int main(int argc, char **argv)
|
||||
build_conv_table(unicode_db);
|
||||
|
||||
#ifdef DUMP_CASE_FOLDING_SPECIAL_CASES
|
||||
dump_case_folding_special_cases(unicode_db);
|
||||
dump_case_folding_special_cases(unicode_db);
|
||||
#endif
|
||||
|
||||
if (!outfilename) {
|
||||
@ -3117,7 +3213,7 @@ int main(int argc, char **argv)
|
||||
} else
|
||||
{
|
||||
FILE *fo = fopen(outfilename, "wb");
|
||||
|
||||
|
||||
if (!fo) {
|
||||
perror(outfilename);
|
||||
exit(1);
|
||||
@ -3139,6 +3235,8 @@ int main(int argc, char **argv)
|
||||
build_script_ext_table(fo);
|
||||
build_prop_list_table(fo);
|
||||
fprintf(fo, "#endif /* CONFIG_ALL_UNICODE */\n");
|
||||
fprintf(fo, "/* %u tables / %u bytes, %u index / %u bytes */\n",
|
||||
total_tables, total_table_bytes, total_index, total_index_bytes);
|
||||
fclose(fo);
|
||||
}
|
||||
return 0;
|
||||
|
@ -82,6 +82,7 @@ DEF(Egyptian_Hieroglyphs, "Egyp")
|
||||
DEF(Elbasan, "Elba")
|
||||
DEF(Elymaic, "Elym")
|
||||
DEF(Ethiopic, "Ethi")
|
||||
DEF(Garay, "Gara")
|
||||
DEF(Georgian, "Geor")
|
||||
DEF(Glagolitic, "Glag")
|
||||
DEF(Gothic, "Goth")
|
||||
@ -90,6 +91,7 @@ DEF(Greek, "Grek")
|
||||
DEF(Gujarati, "Gujr")
|
||||
DEF(Gunjala_Gondi, "Gong")
|
||||
DEF(Gurmukhi, "Guru")
|
||||
DEF(Gurung_Khema, "Gukh")
|
||||
DEF(Han, "Hani")
|
||||
DEF(Hangul, "Hang")
|
||||
DEF(Hanifi_Rohingya, "Rohg")
|
||||
@ -112,6 +114,7 @@ DEF(Khmer, "Khmr")
|
||||
DEF(Khojki, "Khoj")
|
||||
DEF(Khitan_Small_Script, "Kits")
|
||||
DEF(Khudawadi, "Sind")
|
||||
DEF(Kirat_Rai, "Krai")
|
||||
DEF(Lao, "Laoo")
|
||||
DEF(Latin, "Latn")
|
||||
DEF(Lepcha, "Lepc")
|
||||
@ -149,6 +152,7 @@ DEF(Nushu, "Nshu")
|
||||
DEF(Nyiakeng_Puachue_Hmong, "Hmnp")
|
||||
DEF(Ogham, "Ogam")
|
||||
DEF(Ol_Chiki, "Olck")
|
||||
DEF(Ol_Onal, "Onao")
|
||||
DEF(Old_Hungarian, "Hung")
|
||||
DEF(Old_Italic, "Ital")
|
||||
DEF(Old_North_Arabian, "Narb")
|
||||
@ -180,6 +184,7 @@ DEF(Sogdian, "Sogd")
|
||||
DEF(Sora_Sompeng, "Sora")
|
||||
DEF(Soyombo, "Soyo")
|
||||
DEF(Sundanese, "Sund")
|
||||
DEF(Sunuwar, "Sunu")
|
||||
DEF(Syloti_Nagri, "Sylo")
|
||||
DEF(Syriac, "Syrc")
|
||||
DEF(Tagalog, "Tglg")
|
||||
@ -197,7 +202,9 @@ DEF(Tibetan, "Tibt")
|
||||
DEF(Tifinagh, "Tfng")
|
||||
DEF(Tirhuta, "Tirh")
|
||||
DEF(Tangsa, "Tnsa")
|
||||
DEF(Todhri, "Todr")
|
||||
DEF(Toto, "Toto")
|
||||
DEF(Tulu_Tigalari, "Tutg")
|
||||
DEF(Ugaritic, "Ugar")
|
||||
DEF(Vai, "Vaii")
|
||||
DEF(Vithkuqi, "Vith")
|
||||
@ -236,11 +243,13 @@ DEF(Deprecated, "Dep")
|
||||
DEF(Diacritic, "Dia")
|
||||
DEF(Extender, "Ext")
|
||||
DEF(Hex_Digit, "Hex")
|
||||
DEF(IDS_Unary_Operator, "IDSU")
|
||||
DEF(IDS_Binary_Operator, "IDSB")
|
||||
DEF(IDS_Trinary_Operator, "IDST")
|
||||
DEF(Ideographic, "Ideo")
|
||||
DEF(Join_Control, "Join_C")
|
||||
DEF(Logical_Order_Exception, "LOE")
|
||||
DEF(Modifier_Combining_Mark, "MCM")
|
||||
DEF(Noncharacter_Code_Point, "NChar")
|
||||
DEF(Pattern_Syntax, "Pat_Syn")
|
||||
DEF(Pattern_White_Space, "Pat_WS")
|
||||
@ -279,6 +288,9 @@ DEF(Changes_When_Uppercased, "CWU")
|
||||
DEF(Grapheme_Base, "Gr_Base")
|
||||
DEF(Grapheme_Extend, "Gr_Ext")
|
||||
DEF(ID_Continue, "IDC")
|
||||
DEF(ID_Compat_Math_Start, "")
|
||||
DEF(ID_Compat_Math_Continue, "")
|
||||
DEF(InCB, "")
|
||||
DEF(Lowercase, "Lower")
|
||||
DEF(Math, "")
|
||||
DEF(Uppercase, "Upper")
|
||||
|
Loading…
x
Reference in New Issue
Block a user