Compare commits
1 commit
master
...
revert-265
Author | SHA1 | Date | |
---|---|---|---|
|
e02472dabc |
63 changed files with 4330 additions and 5085 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,15 +1,17 @@
|
|||
*.a
|
||||
.obj/
|
||||
tests/bjson.so
|
||||
examples/test_fib
|
||||
test_fib.c
|
||||
examples/*.so
|
||||
examples/hello
|
||||
examples/hello_module
|
||||
hello.c
|
||||
microbench*.txt
|
||||
qjs
|
||||
qjsc
|
||||
qjscalc
|
||||
qjscalc.c
|
||||
hello.c
|
||||
hello
|
||||
hello_module
|
||||
repl.c
|
||||
run-test262
|
||||
test262
|
||||
|
|
|
@ -13,7 +13,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
|
||||
|
||||
|
|
3
LICENSE
3
LICENSE
|
@ -1,6 +1,5 @@
|
|||
QuickJS Javascript Engine (DoneJS Edition)
|
||||
QuickJS Javascript Engine
|
||||
|
||||
Copyright (c) 2024 Sneed Group
|
||||
Copyright (c) 2017-2021 Fabrice Bellard
|
||||
Copyright (c) 2017-2021 Charlie Gordon
|
||||
|
||||
|
|
161
Makefile
161
Makefile
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
# QuickJS Javascript Engine
|
||||
#
|
||||
#
|
||||
# Copyright (c) 2017-2021 Fabrice Bellard
|
||||
# Copyright (c) 2017-2021 Charlie Gordon
|
||||
#
|
||||
|
@ -25,10 +25,13 @@
|
|||
ifeq ($(shell uname -s),Darwin)
|
||||
CONFIG_DARWIN=y
|
||||
endif
|
||||
ifeq ($(shell uname -s),FreeBSD)
|
||||
CONFIG_FREEBSD=y
|
||||
endif
|
||||
# Windows cross compilation from Linux
|
||||
#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
|
||||
|
@ -43,16 +46,37 @@ PREFIX?=/usr/local
|
|||
#CONFIG_PROFILE=y
|
||||
# use address sanitizer
|
||||
#CONFIG_ASAN=y
|
||||
# include the code for BigFloat/BigDecimal, math mode and faster large integers
|
||||
# use memory sanitizer
|
||||
#CONFIG_MSAN=y
|
||||
# use UB sanitizer
|
||||
#CONFIG_UBSAN=y
|
||||
|
||||
# include the code for BigFloat/BigDecimal and math mode
|
||||
CONFIG_BIGNUM=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
|
||||
|
@ -87,6 +111,7 @@ ifdef CONFIG_CLANG
|
|||
AR=$(CROSS_PREFIX)ar
|
||||
endif
|
||||
endif
|
||||
LIB_FUZZING_ENGINE ?= "-fsanitize=fuzzer"
|
||||
else ifdef CONFIG_COSMO
|
||||
CONFIG_LTO=
|
||||
HOST_CC=gcc
|
||||
|
@ -106,7 +131,7 @@ else
|
|||
AR=$(CROSS_PREFIX)ar
|
||||
endif
|
||||
endif
|
||||
STRIP=$(CROSS_PREFIX)strip
|
||||
STRIP?=$(CROSS_PREFIX)strip
|
||||
CFLAGS+=-fwrapv # ensure that signed overflows behave as expected
|
||||
ifdef CONFIG_WERROR
|
||||
CFLAGS+=-Werror
|
||||
|
@ -118,6 +143,11 @@ 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 +172,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
|
||||
|
@ -176,18 +214,21 @@ endif
|
|||
|
||||
# examples
|
||||
ifeq ($(CROSS_PREFIX),)
|
||||
PROGS+=examples/hello
|
||||
ifndef CONFIG_ASAN
|
||||
PROGS+=examples/hello_module
|
||||
endif
|
||||
ifndef CONFIG_MSAN
|
||||
ifndef CONFIG_UBSAN
|
||||
PROGS+=examples/hello examples/hello_module examples/test_fib
|
||||
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)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o $(OBJDIR)/libbf.o
|
||||
|
||||
QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS)
|
||||
ifdef CONFIG_BIGNUM
|
||||
|
@ -213,6 +254,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 \
|
||||
|
@ -254,6 +306,9 @@ libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS))
|
|||
$(AR) rcs $@ $^
|
||||
endif # CONFIG_LTO
|
||||
|
||||
libquickjs.fuzz.a: $(patsubst %.o, %.fuzz.o, $(QJS_LIB_OBJS))
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
repl.c: $(QJSC) repl.js
|
||||
$(QJSC) -c -o $@ -m repl.js
|
||||
|
||||
|
@ -282,6 +337,9 @@ run-test262-32: $(patsubst %.o, %.m32.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)
|
|||
$(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 $@ $<
|
||||
|
||||
|
@ -300,6 +358,9 @@ $(OBJDIR)/%.m32s.o: %.c | $(OBJDIR)
|
|||
$(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 $@ $<
|
||||
|
||||
|
@ -311,17 +372,18 @@ unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c u
|
|||
|
||||
clean:
|
||||
rm -f repl.c qjscalc.c out.c
|
||||
rm -f *.a *.o *.d *~ unicode_gen regexp_test $(PROGS)
|
||||
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 -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"
|
||||
ln -sf qjs$(EXE) "$(DESTDIR)$(PREFIX)/bin/qjscalc$(EXE)"
|
||||
mkdir -p "$(DESTDIR)$(PREFIX)/lib/quickjs"
|
||||
install -m644 libquickjs.a "$(DESTDIR)$(PREFIX)/lib/quickjs"
|
||||
ifdef CONFIG_LTO
|
||||
|
@ -375,11 +437,11 @@ 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 doc/jsbignum.pdf doc/jsbignum.html
|
||||
|
||||
build_doc: $(DOCS)
|
||||
|
||||
clean_doc:
|
||||
clean_doc:
|
||||
rm -f $(DOCS)
|
||||
|
||||
doc/%.pdf: doc/%.texi
|
||||
|
@ -404,8 +466,9 @@ endif
|
|||
test: qjs
|
||||
./qjs tests/test_closure.js
|
||||
./qjs tests/test_language.js
|
||||
./qjs tests/test_builtin.js
|
||||
./qjs --std tests/test_builtin.js
|
||||
./qjs tests/test_loop.js
|
||||
./qjs tests/test_bignum.js
|
||||
./qjs tests/test_std.js
|
||||
./qjs tests/test_worker.js
|
||||
ifdef CONFIG_SHARED_LIBS
|
||||
|
@ -418,19 +481,20 @@ endif
|
|||
endif
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs --bignum tests/test_op_overloading.js
|
||||
./qjs --bignum tests/test_bignum.js
|
||||
./qjs --bignum tests/test_bigfloat.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 --std tests/test_builtin.js
|
||||
./qjs32 tests/test_loop.js
|
||||
./qjs32 tests/test_bignum.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 --bignum tests/test_bigfloat.js
|
||||
./qjs32 --qjscalc tests/test_qjscalc.js
|
||||
endif
|
||||
endif
|
||||
|
@ -440,36 +504,46 @@ stats: qjs qjs32
|
|||
./qjs32 -qd
|
||||
|
||||
microbench: qjs
|
||||
./qjs tests/microbench.js
|
||||
./qjs --std tests/microbench.js
|
||||
|
||||
microbench-32: qjs32
|
||||
./qjs32 tests/microbench.js
|
||||
./qjs32 --std tests/microbench.js
|
||||
|
||||
ifeq ($(wildcard test262o/tests.txt),)
|
||||
test2o test2o-32 test2o-update:
|
||||
@echo test262o tests not installed
|
||||
else
|
||||
# ES5 tests (obsolete)
|
||||
test2o: run-test262
|
||||
time ./run-test262 -m -c test262o.conf
|
||||
time ./run-test262 -t -m -c test262o.conf
|
||||
|
||||
test2o-32: run-test262-32
|
||||
time ./run-test262-32 -m -c test262o.conf
|
||||
time ./run-test262-32 -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 test262o/tests.txt),)
|
||||
test2 test2-32 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
|
||||
time ./run-test262 -t -m -c test262.conf -a
|
||||
|
||||
test2-32: run-test262-32
|
||||
time ./run-test262-32 -m -c test262.conf -a
|
||||
time ./run-test262-32 -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
|
||||
|
||||
|
@ -477,11 +551,40 @@ testall-32: all test-32 microbench-32 test2o-32 test2-32
|
|||
|
||||
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_bignum.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
README.md
14
README.md
|
@ -1,14 +0,0 @@
|
|||
# QuickJS (DoneJS edition)
|
||||
|
||||
An *unofficial* fork of QuickJS that contains polyfills and modifications to the source code to make it more like something such as NodeJS or De*no*.
|
||||
|
||||
# FAQ
|
||||
|
||||
## Documentation Location
|
||||
|
||||
The main documentation is in "doc/quickjs.pdf" for the PDF version or "doc/quickjs.html" for the HTML one.
|
||||
|
||||
|
||||
## Location of Polyfills
|
||||
|
||||
The polyfills are located in the "qjs.c" file.
|
2
TODO
2
TODO
|
@ -63,5 +63,5 @@ Optimization ideas:
|
|||
Test262o: 0/11262 errors, 463 excluded
|
||||
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
|
||||
|
||||
Result: 10/76947 errors, 1497 excluded, 8117 skipped
|
||||
Result: 8/76947 errors, 1497 excluded, 8117 skipped
|
||||
Test262 commit: 6cbb6da9473c56d95358d8e679c5a6d2b4574efb
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
2024-01-13
|
||||
2024-02-14
|
||||
|
|
6
cutils.c
6
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,7 +172,7 @@ 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);
|
||||
|
|
71
cutils.h
71
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')
|
||||
|
|
|
@ -1,734 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
|
||||
<head>
|
||||
<title>Javascript Bignum Extensions</title>
|
||||
|
||||
<meta name="description" content="Javascript Bignum Extensions">
|
||||
<meta name="keywords" content="Javascript Bignum Extensions">
|
||||
<meta name="resource-type" content="document">
|
||||
<meta name="distribution" content="global">
|
||||
<meta name="Generator" content="makeinfo">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
|
||||
<style type="text/css">
|
||||
<!--
|
||||
a.summary-letter {text-decoration: none}
|
||||
blockquote.indentedblock {margin-right: 0em}
|
||||
blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
|
||||
blockquote.smallquotation {font-size: smaller}
|
||||
div.display {margin-left: 3.2em}
|
||||
div.example {margin-left: 3.2em}
|
||||
div.lisp {margin-left: 3.2em}
|
||||
div.smalldisplay {margin-left: 3.2em}
|
||||
div.smallexample {margin-left: 3.2em}
|
||||
div.smalllisp {margin-left: 3.2em}
|
||||
kbd {font-style: oblique}
|
||||
pre.display {font-family: inherit}
|
||||
pre.format {font-family: inherit}
|
||||
pre.menu-comment {font-family: serif}
|
||||
pre.menu-preformatted {font-family: serif}
|
||||
pre.smalldisplay {font-family: inherit; font-size: smaller}
|
||||
pre.smallexample {font-size: smaller}
|
||||
pre.smallformat {font-family: inherit; font-size: smaller}
|
||||
pre.smalllisp {font-size: smaller}
|
||||
span.nolinebreak {white-space: nowrap}
|
||||
span.roman {font-family: initial; font-weight: normal}
|
||||
span.sansserif {font-family: sans-serif; font-weight: normal}
|
||||
ul.no-bullet {list-style: none}
|
||||
-->
|
||||
</style>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body lang="en">
|
||||
<h1 class="settitle" align="center">Javascript Bignum Extensions</h1>
|
||||
|
||||
<a name="SEC_Contents"></a>
|
||||
<h2 class="contents-heading">Table of Contents</h2>
|
||||
|
||||
<div class="contents">
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-Introduction" href="#Introduction">1 Introduction</a></li>
|
||||
<li><a name="toc-Operator-overloading" href="#Operator-overloading">2 Operator overloading</a></li>
|
||||
<li><a name="toc-BigInt-extensions" href="#BigInt-extensions">3 BigInt extensions</a></li>
|
||||
<li><a name="toc-BigFloat" href="#BigFloat">4 BigFloat</a>
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-Introduction-1" href="#Introduction-1">4.1 Introduction</a></li>
|
||||
<li><a name="toc-Floating-point-rounding" href="#Floating-point-rounding">4.2 Floating point rounding</a></li>
|
||||
<li><a name="toc-Operators" href="#Operators">4.3 Operators</a></li>
|
||||
<li><a name="toc-BigFloat-literals" href="#BigFloat-literals">4.4 BigFloat literals</a></li>
|
||||
<li><a name="toc-Builtin-Object-changes" href="#Builtin-Object-changes">4.5 Builtin Object changes</a>
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-BigFloat-function" href="#BigFloat-function">4.5.1 <code>BigFloat</code> function</a></li>
|
||||
<li><a name="toc-BigFloat_002eprototype" href="#BigFloat_002eprototype">4.5.2 <code>BigFloat.prototype</code></a></li>
|
||||
<li><a name="toc-BigFloatEnv-constructor" href="#BigFloatEnv-constructor">4.5.3 <code>BigFloatEnv</code> constructor</a></li>
|
||||
</ul></li>
|
||||
</ul></li>
|
||||
<li><a name="toc-BigDecimal" href="#BigDecimal">5 BigDecimal</a>
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-Operators-1" href="#Operators-1">5.1 Operators</a></li>
|
||||
<li><a name="toc-BigDecimal-literals" href="#BigDecimal-literals">5.2 BigDecimal literals</a></li>
|
||||
<li><a name="toc-Builtin-Object-changes-1" href="#Builtin-Object-changes-1">5.3 Builtin Object changes</a>
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-The-BigDecimal-function_002e" href="#The-BigDecimal-function_002e">5.3.1 The <code>BigDecimal</code> function.</a></li>
|
||||
<li><a name="toc-Properties-of-the-BigDecimal-object" href="#Properties-of-the-BigDecimal-object">5.3.2 Properties of the <code>BigDecimal</code> object</a></li>
|
||||
<li><a name="toc-Properties-of-the-BigDecimal_002eprototype-object" href="#Properties-of-the-BigDecimal_002eprototype-object">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</a></li>
|
||||
</ul></li>
|
||||
</ul></li>
|
||||
<li><a name="toc-Math-mode" href="#Math-mode">6 Math mode</a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<a name="Introduction"></a>
|
||||
<h2 class="chapter">1 Introduction</h2>
|
||||
|
||||
<p>The Bignum extensions add the following features to the Javascript
|
||||
language while being 100% backward compatible:
|
||||
</p>
|
||||
<ul>
|
||||
<li> Operator overloading with a dispatch logic inspired from the proposal available at <a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>.
|
||||
|
||||
</li><li> Arbitrarily large floating point numbers (<code>BigFloat</code>) in base 2 using the IEEE 754 semantics.
|
||||
|
||||
</li><li> Arbitrarily large floating point numbers (<code>BigDecimal</code>) in base 10 based on the proposal available at
|
||||
<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
|
||||
|
||||
</li><li> <code>math</code> mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (<code>%</code>) is defined as the Euclidian
|
||||
remainder. <code>^</code> is an alias to the power operator
|
||||
(<code>**</code>). <code>^^</code> is used as the exclusive or operator.
|
||||
|
||||
</li></ul>
|
||||
|
||||
<p>The extensions are independent from each other except the <code>math</code>
|
||||
mode which relies on BigFloat and operator overloading.
|
||||
</p>
|
||||
<a name="Operator-overloading"></a>
|
||||
<h2 class="chapter">2 Operator overloading</h2>
|
||||
|
||||
<p>Operator overloading is inspired from the proposal available at
|
||||
<a href="https://github.com/tc39/proposal-operator-overloading/">https://github.com/tc39/proposal-operator-overloading/</a>. It
|
||||
implements the same dispatch logic but finds the operator sets by
|
||||
looking at the <code>Symbol.operatorSet</code> property in the objects. The
|
||||
changes were done in order to simplify the implementation.
|
||||
</p>
|
||||
<p>More precisely, the following modifications were made:
|
||||
</p>
|
||||
<ul>
|
||||
<li> <code>with operators from</code> is not supported. Operator overloading is always enabled.
|
||||
|
||||
</li><li> The dispatch is not based on a static <code>[[OperatorSet]]</code> field in all instances. Instead, a dynamic lookup of the <code>Symbol.operatorSet</code> property is done. This property is typically added in the prototype of each object.
|
||||
|
||||
</li><li> <code>Operators.create(...dictionaries)</code> is used to create a new OperatorSet object. The <code>Operators</code> function is supported as an helper to be closer to the TC39 proposal.
|
||||
|
||||
</li><li> <code>[]</code> cannot be overloaded.
|
||||
|
||||
</li><li> In math mode, the BigInt division and power operators can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
|
||||
|
||||
</li></ul>
|
||||
|
||||
<a name="BigInt-extensions"></a>
|
||||
<h2 class="chapter">3 BigInt extensions</h2>
|
||||
|
||||
<p>A few properties are added to the BigInt object:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>tdiv(a, b)</code></dt>
|
||||
<dd><p>Return <em>trunc(a/b)</em>. <code>b = 0</code> raises a RangeError
|
||||
exception.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>fdiv(a, b)</code></dt>
|
||||
<dd><p>Return <em>\lfloor a/b \rfloor</em>. <code>b = 0</code> raises a RangeError
|
||||
exception.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>cdiv(a, b)</code></dt>
|
||||
<dd><p>Return <em>\lceil a/b \rceil</em>. <code>b = 0</code> raises a RangeError
|
||||
exception.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>ediv(a, b)</code></dt>
|
||||
<dd><p>Return <em>sgn(b) \lfloor a/{|b|} \rfloor</em> (Euclidian
|
||||
division). <code>b = 0</code> raises a RangeError exception.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>tdivrem(a, b)</code></dt>
|
||||
<dt><code>fdivrem(a, b)</code></dt>
|
||||
<dt><code>cdivrem(a, b)</code></dt>
|
||||
<dt><code>edivrem(a, b)</code></dt>
|
||||
<dd><p>Return an array of two elements. The first element is the quotient,
|
||||
the second is the remainder. The same rounding is done as the
|
||||
corresponding division operation.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>sqrt(a)</code></dt>
|
||||
<dd><p>Return <em>\lfloor \sqrt(a) \rfloor</em>. A RangeError exception is
|
||||
raised if <em>a < 0</em>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>sqrtrem(a)</code></dt>
|
||||
<dd><p>Return an array of two elements. The first element is <em>\lfloor
|
||||
\sqrt{a} \rfloor</em>. The second element is <em>a-\lfloor \sqrt{a}
|
||||
\rfloor^2</em>. A RangeError exception is raised if <em>a < 0</em>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>floorLog2(a)</code></dt>
|
||||
<dd><p>Return -1 if <em>a \leq 0</em> otherwise return <em>\lfloor \log2(a) \rfloor</em>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>ctz(a)</code></dt>
|
||||
<dd><p>Return the number of trailing zeros in the two’s complement binary representation of a. Return -1 if <em>a=0</em>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="BigFloat"></a>
|
||||
<h2 class="chapter">4 BigFloat</h2>
|
||||
|
||||
<a name="Introduction-1"></a>
|
||||
<h3 class="section">4.1 Introduction</h3>
|
||||
|
||||
<p>This extension adds the <code>BigFloat</code> primitive type. The
|
||||
<code>BigFloat</code> type represents floating point numbers in base 2
|
||||
with the IEEE 754 semantics. A floating
|
||||
point number is represented as a sign, mantissa and exponent. The
|
||||
special values <code>NaN</code>, <code>+/-Infinity</code>, <code>+0</code> and <code>-0</code>
|
||||
are supported. The mantissa and exponent can have any bit length with
|
||||
an implementation specific minimum and maximum.
|
||||
</p>
|
||||
<a name="Floating-point-rounding"></a>
|
||||
<h3 class="section">4.2 Floating point rounding</h3>
|
||||
|
||||
<p>Each floating point operation operates with infinite precision and
|
||||
then rounds the result according to the specified floating point
|
||||
environment (<code>BigFloatEnv</code> object). The status flags of the
|
||||
environment are also set according to the result of the operation.
|
||||
</p>
|
||||
<p>If no floating point environment is provided, the global floating
|
||||
point environment is used.
|
||||
</p>
|
||||
<p>The rounding mode of the global floating point environment is always
|
||||
<code>RNDN</code> (“round to nearest with ties to even”)<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>. The status flags of the global environment cannot be
|
||||
read<a name="DOCF2" href="#FOOT2"><sup>2</sup></a>. The precision of the global environment is
|
||||
<code>BigFloatEnv.prec</code>. The number of exponent bits of the global
|
||||
environment is <code>BigFloatEnv.expBits</code>. The global environment
|
||||
subnormal flag is set to <code>true</code>.
|
||||
</p>
|
||||
<p>For example, <code>prec = 53</code> and <code> expBits = 11</code> exactly give
|
||||
the same precision as the IEEE 754 64 bit floating point format. The
|
||||
default precision is <code>prec = 113</code> and <code> expBits = 15</code> (IEEE
|
||||
754 128 bit floating point format).
|
||||
</p>
|
||||
<p>The global floating point environment can only be modified temporarily
|
||||
when calling a function (see <code>BigFloatEnv.setPrec</code>). Hence a
|
||||
function can change the global floating point environment for its
|
||||
callees but not for its caller.
|
||||
</p>
|
||||
<a name="Operators"></a>
|
||||
<h3 class="section">4.3 Operators</h3>
|
||||
|
||||
<p>The builtin operators are extended so that a BigFloat is returned if
|
||||
at least one operand is a BigFloat. The computations are always done
|
||||
with infinite precision and rounded according to the global floating
|
||||
point environment.
|
||||
</p>
|
||||
<p><code>typeof</code> applied on a <code>BigFloat</code> returns <code>bigfloat</code>.
|
||||
</p>
|
||||
<p>BigFloat can be compared with all the other numeric types and the
|
||||
result follows the expected mathematical relations.
|
||||
</p>
|
||||
<p>However, since BigFloat and Number are different types they are never
|
||||
equal when using the strict comparison operators (e.g. <code>0.0 ===
|
||||
0.0l</code> is false).
|
||||
</p>
|
||||
<a name="BigFloat-literals"></a>
|
||||
<h3 class="section">4.4 BigFloat literals</h3>
|
||||
|
||||
<p>BigFloat literals are floating point numbers with a trailing <code>l</code>
|
||||
suffix. BigFloat literals have an infinite precision. They are rounded
|
||||
according to the global floating point environment when they are
|
||||
evaluated.<a name="DOCF3" href="#FOOT3"><sup>3</sup></a>
|
||||
</p>
|
||||
<a name="Builtin-Object-changes"></a>
|
||||
<h3 class="section">4.5 Builtin Object changes</h3>
|
||||
|
||||
<a name="BigFloat-function"></a>
|
||||
<h4 class="subsection">4.5.1 <code>BigFloat</code> function</h4>
|
||||
|
||||
<p>The <code>BigFloat</code> function cannot be invoked as a constructor. When
|
||||
invoked as a function: the parameter is converted to a primitive
|
||||
type. If the result is a numeric type, it is converted to BigFloat
|
||||
without rounding. If the result is a string, it is converted to
|
||||
BigFloat using the precision of the global floating point environment.
|
||||
</p>
|
||||
<p><code>BigFloat</code> properties:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>LN2</code></dt>
|
||||
<dt><code>PI</code></dt>
|
||||
<dd><p>Getter. Return the value of the corresponding mathematical constant
|
||||
rounded to nearest, ties to even with the current global
|
||||
precision. The constant values are cached for small precisions.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>MIN_VALUE</code></dt>
|
||||
<dt><code>MAX_VALUE</code></dt>
|
||||
<dt><code>EPSILON</code></dt>
|
||||
<dd><p>Getter. Return the minimum, maximum and epsilon <code>BigFloat</code> values
|
||||
(same definition as the corresponding <code>Number</code> constants).
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>fpRound(a[, e])</code></dt>
|
||||
<dd><p>Round the floating point number <code>a</code> according to the floating
|
||||
point environment <code>e</code> or the global environment if <code>e</code> is
|
||||
undefined.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>parseFloat(a[, radix[, e]])</code></dt>
|
||||
<dd><p>Parse the string <code>a</code> as a floating point number in radix
|
||||
<code>radix</code>. The radix is 0 (default) or from 2 to 36. The radix 0
|
||||
means radix 10 unless there is a hexadecimal or binary prefix. The
|
||||
result is rounded according to the floating point environment <code>e</code>
|
||||
or the global environment if <code>e</code> is undefined.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>isFinite(a)</code></dt>
|
||||
<dd><p>Return true if <code>a</code> is a finite bigfloat.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>isNaN(a)</code></dt>
|
||||
<dd><p>Return true if <code>a</code> is a NaN bigfloat.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>add(a, b[, e])</code></dt>
|
||||
<dt><code>sub(a, b[, e])</code></dt>
|
||||
<dt><code>mul(a, b[, e])</code></dt>
|
||||
<dt><code>div(a, b[, e])</code></dt>
|
||||
<dd><p>Perform the specified floating point operation and round the floating
|
||||
point number <code>a</code> according to the floating point environment
|
||||
<code>e</code> or the global environment if <code>e</code> is undefined. If
|
||||
<code>e</code> is specified, the floating point status flags are updated.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>floor(x)</code></dt>
|
||||
<dt><code>ceil(x)</code></dt>
|
||||
<dt><code>round(x)</code></dt>
|
||||
<dt><code>trunc(x)</code></dt>
|
||||
<dd><p>Round to an integer. No additional rounding is performed.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>abs(x)</code></dt>
|
||||
<dd><p>Return the absolute value of x. No additional rounding is performed.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>fmod(x, y[, e])</code></dt>
|
||||
<dt><code>remainder(x, y[, e])</code></dt>
|
||||
<dd><p>Floating point remainder. The quotient is truncated to zero (fmod) or
|
||||
to the nearest integer with ties to even (remainder). <code>e</code> is an
|
||||
optional floating point environment.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>sqrt(x[, e])</code></dt>
|
||||
<dd><p>Square root. Return a rounded floating point number. <code>e</code> is an
|
||||
optional floating point environment.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>sin(x[, e])</code></dt>
|
||||
<dt><code>cos(x[, e])</code></dt>
|
||||
<dt><code>tan(x[, e])</code></dt>
|
||||
<dt><code>asin(x[, e])</code></dt>
|
||||
<dt><code>acos(x[, e])</code></dt>
|
||||
<dt><code>atan(x[, e])</code></dt>
|
||||
<dt><code>atan2(x, y[, e])</code></dt>
|
||||
<dt><code>exp(x[, e])</code></dt>
|
||||
<dt><code>log(x[, e])</code></dt>
|
||||
<dt><code>pow(x, y[, e])</code></dt>
|
||||
<dd><p>Transcendental operations. Return a rounded floating point
|
||||
number. <code>e</code> is an optional floating point environment.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="BigFloat_002eprototype"></a>
|
||||
<h4 class="subsection">4.5.2 <code>BigFloat.prototype</code></h4>
|
||||
|
||||
<p>The following properties are modified:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>valueOf()</code></dt>
|
||||
<dd><p>Return the bigfloat primitive value corresponding to <code>this</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>toString(radix)</code></dt>
|
||||
<dd>
|
||||
<p>For floating point numbers:
|
||||
</p>
|
||||
<ul>
|
||||
<li> If the radix is a power of two, the conversion is done with infinite
|
||||
precision.
|
||||
</li><li> Otherwise, the number is rounded to nearest with ties to even using
|
||||
the global precision. It is then converted to string using the minimum
|
||||
number of digits so that its conversion back to a floating point using
|
||||
the global precision and round to nearest gives the same number.
|
||||
|
||||
</li></ul>
|
||||
|
||||
<p>The exponent letter is <code>e</code> for base 10, <code>p</code> for bases 2, 8,
|
||||
16 with a binary exponent and <code>@</code> for the other bases.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
|
||||
<dt><code>toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
|
||||
<dt><code>toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)</code></dt>
|
||||
<dd><p>Same semantics as the corresponding <code>Number</code> functions with
|
||||
BigFloats. There is no limit on the accepted precision <code>p</code>. The
|
||||
rounding mode and radix can be optionally specified. The radix must be
|
||||
between 2 and 36.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="BigFloatEnv-constructor"></a>
|
||||
<h4 class="subsection">4.5.3 <code>BigFloatEnv</code> constructor</h4>
|
||||
|
||||
<p>The <code>BigFloatEnv([p, [,rndMode]]</code> constructor cannot be invoked as a
|
||||
function. The floating point environment contains:
|
||||
</p>
|
||||
<ul>
|
||||
<li> the mantissa precision in bits
|
||||
|
||||
</li><li> the exponent size in bits assuming an IEEE 754 representation;
|
||||
|
||||
</li><li> the subnormal flag (if true, subnormal floating point numbers can
|
||||
be generated by the floating point operations).
|
||||
|
||||
</li><li> the rounding mode
|
||||
|
||||
</li><li> the floating point status. The status flags can only be set by the floating point operations. They can be reset with <code>BigFloatEnv.prototype.clearStatus()</code> or with the various status flag setters.
|
||||
|
||||
</li></ul>
|
||||
|
||||
<p><code>new BigFloatEnv([p, [,rndMode]]</code> creates a new floating point
|
||||
environment. The status flags are reset. If no parameter is given the
|
||||
precision, exponent bits and subnormal flags are copied from the
|
||||
global floating point environment. Otherwise, the precision is set to
|
||||
<code>p</code>, the number of exponent bits is set to <code>expBitsMax</code> and the
|
||||
subnormal flags is set to <code>false</code>. If <code>rndMode</code> is
|
||||
<code>undefined</code>, the rounding mode is set to <code>RNDN</code>.
|
||||
</p>
|
||||
<p><code>BigFloatEnv</code> properties:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>prec</code></dt>
|
||||
<dd><p>Getter. Return the precision in bits of the global floating point
|
||||
environment. The initial value is <code>113</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>expBits</code></dt>
|
||||
<dd><p>Getter. Return the exponent size in bits of the global floating point
|
||||
environment assuming an IEEE 754 representation. The initial value is
|
||||
<code>15</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>setPrec(f, p[, e])</code></dt>
|
||||
<dd><p>Set the precision of the global floating point environment to <code>p</code>
|
||||
and the exponent size to <code>e</code> then call the function
|
||||
<code>f</code>. Then the Float precision and exponent size are reset to
|
||||
their precious value and the return value of <code>f</code> is returned (or
|
||||
an exception is raised if <code>f</code> raised an exception). If <code>e</code>
|
||||
is <code>undefined</code> it is set to <code>BigFloatEnv.expBitsMax</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>precMin</code></dt>
|
||||
<dd><p>Read-only integer. Return the minimum allowed precision. Must be at least 2.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>precMax</code></dt>
|
||||
<dd><p>Read-only integer. Return the maximum allowed precision. Must be at least 113.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>expBitsMin</code></dt>
|
||||
<dd><p>Read-only integer. Return the minimum allowed exponent size in
|
||||
bits. Must be at least 3.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>expBitsMax</code></dt>
|
||||
<dd><p>Read-only integer. Return the maximum allowed exponent size in
|
||||
bits. Must be at least 15.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDN</code></dt>
|
||||
<dd><p>Read-only integer. Round to nearest, with ties to even rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDZ</code></dt>
|
||||
<dd><p>Read-only integer. Round to zero rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDD</code></dt>
|
||||
<dd><p>Read-only integer. Round to -Infinity rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDU</code></dt>
|
||||
<dd><p>Read-only integer. Round to +Infinity rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDNA</code></dt>
|
||||
<dd><p>Read-only integer. Round to nearest, with ties away from zero rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDA</code></dt>
|
||||
<dd><p>Read-only integer. Round away from zero rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>RNDF<a name="DOCF4" href="#FOOT4"><sup>4</sup></a></code></dt>
|
||||
<dd><p>Read-only integer. Faithful rounding mode. The result is
|
||||
non-deterministically rounded to -Infinity or +Infinity. This rounding
|
||||
mode usually gives a faster and deterministic running time for the
|
||||
floating point operations.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<p><code>BigFloatEnv.prototype</code> properties:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>prec</code></dt>
|
||||
<dd><p>Getter and setter (Integer). Return or set the precision in bits.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>expBits</code></dt>
|
||||
<dd><p>Getter and setter (Integer). Return or set the exponent size in bits
|
||||
assuming an IEEE 754 representation.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>rndMode</code></dt>
|
||||
<dd><p>Getter and setter (Integer). Return or set the rounding mode.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>subnormal</code></dt>
|
||||
<dd><p>Getter and setter (Boolean). subnormal flag. It is false when
|
||||
<code>expBits = expBitsMax</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>clearStatus()</code></dt>
|
||||
<dd><p>Clear the status flags.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>invalidOperation</code></dt>
|
||||
<dt><code>divideByZero</code></dt>
|
||||
<dt><code>overflow</code></dt>
|
||||
<dt><code>underflow</code></dt>
|
||||
<dt><code>inexact</code></dt>
|
||||
<dd><p>Getter and setter (Boolean). Status flags.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="BigDecimal"></a>
|
||||
<h2 class="chapter">5 BigDecimal</h2>
|
||||
|
||||
<p>This extension adds the <code>BigDecimal</code> primitive type. The
|
||||
<code>BigDecimal</code> type represents floating point numbers in base
|
||||
10. It is inspired from the proposal available at
|
||||
<a href="https://github.com/littledan/proposal-bigdecimal">https://github.com/littledan/proposal-bigdecimal</a>.
|
||||
</p>
|
||||
<p>The <code>BigDecimal</code> floating point numbers are always normalized and
|
||||
finite. There is no concept of <code>-0</code>, <code>Infinity</code> or
|
||||
<code>NaN</code>. By default, all the computations are done with infinite
|
||||
precision.
|
||||
</p>
|
||||
<a name="Operators-1"></a>
|
||||
<h3 class="section">5.1 Operators</h3>
|
||||
|
||||
<p>The following builtin operators support BigDecimal:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>+</code></dt>
|
||||
<dt><code>-</code></dt>
|
||||
<dt><code>*</code></dt>
|
||||
<dd><p>Both operands must be BigDecimal. The result is computed with infinite
|
||||
precision.
|
||||
</p></dd>
|
||||
<dt><code>%</code></dt>
|
||||
<dd><p>Both operands must be BigDecimal. The result is computed with infinite
|
||||
precision. A range error is throws in case of division by zero.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>/</code></dt>
|
||||
<dd><p>Both operands must be BigDecimal. A range error is throws in case of
|
||||
division by zero or if the result cannot be represented with infinite
|
||||
precision (use <code>BigDecimal.div</code> to specify the rounding).
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>**</code></dt>
|
||||
<dd><p>Both operands must be BigDecimal. The exponent must be a positive
|
||||
integer. The result is computed with infinite precision.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>===</code></dt>
|
||||
<dd><p>When one of the operand is a BigDecimal, return true if both operands
|
||||
are a BigDecimal and if they are equal.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>==</code></dt>
|
||||
<dt><code>!=</code></dt>
|
||||
<dt><code><=</code></dt>
|
||||
<dt><code>>=</code></dt>
|
||||
<dt><code><</code></dt>
|
||||
<dt><code>></code></dt>
|
||||
<dd>
|
||||
<p>Numerical comparison. When one of the operand is not a BigDecimal, it is
|
||||
converted to BigDecimal by using ToString(). Hence comparisons between
|
||||
Number and BigDecimal do not use the exact mathematical value of the
|
||||
Number value.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="BigDecimal-literals"></a>
|
||||
<h3 class="section">5.2 BigDecimal literals</h3>
|
||||
|
||||
<p>BigDecimal literals are decimal floating point numbers with a trailing
|
||||
<code>m</code> suffix.
|
||||
</p>
|
||||
<a name="Builtin-Object-changes-1"></a>
|
||||
<h3 class="section">5.3 Builtin Object changes</h3>
|
||||
|
||||
<a name="The-BigDecimal-function_002e"></a>
|
||||
<h4 class="subsection">5.3.1 The <code>BigDecimal</code> function.</h4>
|
||||
|
||||
<p>It returns <code>0m</code> if no parameter is provided. Otherwise the first
|
||||
parameter is converted to a bigdecimal by using ToString(). Hence
|
||||
Number values are not converted to their exact numerical value as
|
||||
BigDecimal.
|
||||
</p>
|
||||
<a name="Properties-of-the-BigDecimal-object"></a>
|
||||
<h4 class="subsection">5.3.2 Properties of the <code>BigDecimal</code> object</h4>
|
||||
|
||||
<dl compact="compact">
|
||||
<dt><code>add(a, b[, e])</code></dt>
|
||||
<dt><code>sub(a, b[, e])</code></dt>
|
||||
<dt><code>mul(a, b[, e])</code></dt>
|
||||
<dt><code>div(a, b[, e])</code></dt>
|
||||
<dt><code>mod(a, b[, e])</code></dt>
|
||||
<dt><code>sqrt(a, e)</code></dt>
|
||||
<dt><code>round(a, e)</code></dt>
|
||||
<dd><p>Perform the specified floating point operation and round the floating
|
||||
point result according to the rounding object <code>e</code>. If the
|
||||
rounding object is not present, the operation is executed with
|
||||
infinite precision.
|
||||
</p>
|
||||
<p>For <code>div</code>, a <code>RangeError</code> exception is thrown in case of
|
||||
division by zero or if the result cannot be represented with infinite
|
||||
precision if no rounding object is present.
|
||||
</p>
|
||||
<p>For <code>sqrt</code>, a range error is thrown if <code>a</code> is less than
|
||||
zero.
|
||||
</p>
|
||||
<p>The rounding object must contain the following properties:
|
||||
<code>roundingMode</code> is a string specifying the rounding mode
|
||||
(<code>"floor"</code>, <code>"ceiling"</code>, <code>"down"</code>, <code>"up"</code>,
|
||||
<code>"half-even"</code>, <code>"half-up"</code>). Either
|
||||
<code>maximumSignificantDigits</code> or <code>maximumFractionDigits</code> must
|
||||
be present to specify respectively the number of significant digits
|
||||
(must be >= 1) or the number of digits after the decimal point (must
|
||||
be >= 0).
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="Properties-of-the-BigDecimal_002eprototype-object"></a>
|
||||
<h4 class="subsection">5.3.3 Properties of the <code>BigDecimal.prototype</code> object</h4>
|
||||
|
||||
<dl compact="compact">
|
||||
<dt><code>valueOf()</code></dt>
|
||||
<dd><p>Return the bigdecimal primitive value corresponding to <code>this</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>toString()</code></dt>
|
||||
<dd><p>Convert <code>this</code> to a string with infinite precision in base 10.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>toPrecision(p, rnd_mode = "half-up")</code></dt>
|
||||
<dt><code>toFixed(p, rnd_mode = "half-up")</code></dt>
|
||||
<dt><code>toExponential(p, rnd_mode = "half-up")</code></dt>
|
||||
<dd><p>Convert the BigDecimal <code>this</code> to string with the specified
|
||||
precision <code>p</code>. There is no limit on the accepted precision
|
||||
<code>p</code>. The rounding mode can be optionally
|
||||
specified. <code>toPrecision</code> outputs either in decimal fixed notation
|
||||
or in decimal exponential notation with a <code>p</code> digits of
|
||||
precision. <code>toExponential</code> outputs in decimal exponential
|
||||
notation with <code>p</code> digits after the decimal point. <code>toFixed</code>
|
||||
outputs in decimal notation with <code>p</code> digits after the decimal
|
||||
point.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="Math-mode"></a>
|
||||
<h2 class="chapter">6 Math mode</h2>
|
||||
|
||||
<p>A new <em>math mode</em> is enabled with the <code>"use math"</code>
|
||||
directive. It propagates the same way as the <em>strict mode</em>. It is
|
||||
designed so that arbitrarily large integers and floating point numbers
|
||||
are available by default. In order to minimize the number of changes
|
||||
in the Javascript semantics, integers are represented either as Number
|
||||
or BigInt depending on their magnitude. Floating point numbers are
|
||||
always represented as BigFloat.
|
||||
</p>
|
||||
<p>The following changes are made to the Javascript semantics:
|
||||
</p>
|
||||
<ul>
|
||||
<li> Floating point literals (i.e. number with a decimal point or an exponent) are <code>BigFloat</code> by default (i.e. a <code>l</code> suffix is implied). Hence <code>typeof 1.0 === "bigfloat"</code>.
|
||||
|
||||
</li><li> Integer literals (i.e. numbers without a decimal point or an exponent) with or without the <code>n</code> suffix are <code>BigInt</code> if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to <code>2**53-1</code>. Hence <code>typeof 1 === "number "</code>, <code>typeof 1n === "number"</code> but <code>typeof 9007199254740992 === "bigint" </code>.
|
||||
|
||||
</li><li> All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt.
|
||||
|
||||
</li><li> The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result.
|
||||
|
||||
</li><li> The <code>^</code> operator is an alias to the power operator (<code>**</code>).
|
||||
|
||||
</li><li> The power operator (both <code>^</code> and <code>**</code>) grammar is modified so that <code>-2^2</code> is allowed and yields <code>-4</code>.
|
||||
|
||||
</li><li> The logical xor operator is still available with the <code>^^</code> operator.
|
||||
|
||||
</li><li> The modulo operator (<code>%</code>) returns the Euclidian remainder (always positive) instead of the truncated remainder.
|
||||
|
||||
</li><li> The integer division operator can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
|
||||
|
||||
</li><li> The integer power operator with a non zero negative exponent can be overloaded with <code>Operators.updateBigIntOperators(dictionary)</code>.
|
||||
|
||||
</li></ul>
|
||||
|
||||
<div class="footnote">
|
||||
<hr>
|
||||
<h4 class="footnotes-heading">Footnotes</h4>
|
||||
|
||||
<h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>
|
||||
<p>The
|
||||
rationale is that the rounding mode changes must always be
|
||||
explicit.</p>
|
||||
<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
|
||||
<p>The rationale is to avoid side effects for the built-in
|
||||
operators.</p>
|
||||
<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
|
||||
<p>Base 10 floating point literals cannot usually be
|
||||
exactly represented as base 2 floating point number. In order to
|
||||
ensure that the literal is represented accurately with the current
|
||||
precision, it must be evaluated at runtime.</p>
|
||||
<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
|
||||
<p>Could be removed in case a deterministic behavior for floating point operations is required.</p>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
BIN
doc/jsbignum.pdf
BIN
doc/jsbignum.pdf
Binary file not shown.
|
@ -289,7 +289,7 @@ precision.
|
|||
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.
|
||||
the global precision and round to nearest gives the same number.
|
||||
|
||||
@end itemize
|
||||
|
||||
|
|
1410
doc/quickjs.html
1410
doc/quickjs.html
File diff suppressed because it is too large
Load diff
BIN
doc/quickjs.pdf
BIN
doc/quickjs.pdf
Binary file not shown.
|
@ -160,7 +160,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
|
||||
|
@ -379,7 +379,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 +489,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 +596,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 +734,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 +758,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 +829,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 +972,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
|
||||
|
|
|
@ -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,9 +0,0 @@
|
|||
function fib(n)
|
||||
{
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
else if (n == 1)
|
||||
return 1;
|
||||
else
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
/* example of JS module */
|
||||
|
||||
const fibModule = require("./fib_require.js");
|
||||
|
||||
console.log("Hello World");
|
||||
console.log("fib(10)=", fib(10));
|
|
@ -11,7 +11,7 @@ function calc_pi(prec) {
|
|||
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;
|
||||
|
|
|
@ -11,7 +11,7 @@ function calc_pi() {
|
|||
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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
20
libbf.h
20
libbf.h
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
|
@ -171,7 +171,7 @@ static inline bf_flags_t bf_set_exp_bits(int n)
|
|||
#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_ST_MEM_ERROR (1 << 5)
|
||||
|
||||
#define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */
|
||||
|
||||
|
@ -284,7 +284,7 @@ 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,
|
||||
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);
|
||||
|
@ -341,12 +341,12 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
|
|||
/* fractional format: prec digits after the decimal point rounded with
|
||||
(flags & BF_RND_MASK) */
|
||||
#define BF_FTOA_FORMAT_FRAC (1 << 16)
|
||||
/* free format:
|
||||
|
||||
/* 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
|
||||
|
@ -373,7 +373,7 @@ 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)
|
||||
#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);
|
||||
|
@ -387,10 +387,10 @@ 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,
|
||||
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 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);
|
||||
|
|
|
@ -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
|
||||
|
|
396
libregexp.c
396
libregexp.c
|
@ -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
|
||||
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "cutils.h"
|
||||
#include "libregexp.h"
|
||||
#include "libunicode.h"
|
||||
|
||||
/*
|
||||
TODO:
|
||||
|
@ -66,7 +67,7 @@ typedef struct {
|
|||
const uint8_t *buf_end;
|
||||
const uint8_t *buf_start;
|
||||
int re_flags;
|
||||
BOOL is_utf16;
|
||||
BOOL is_unicode;
|
||||
BOOL ignore_case;
|
||||
BOOL dotall;
|
||||
int capture_count;
|
||||
|
@ -100,6 +101,7 @@ static const REOpCode reopcode_info[REOP_COUNT] = {
|
|||
#define RE_HEADER_FLAGS 0
|
||||
#define RE_HEADER_CAPTURE_COUNT 1
|
||||
#define RE_HEADER_STACK_SIZE 2
|
||||
#define RE_HEADER_BYTECODE_LEN 3
|
||||
|
||||
#define RE_HEADER_LEN 7
|
||||
|
||||
|
@ -140,32 +142,6 @@ static const uint16_t char_range_s[] = {
|
|||
0xFEFF, 0xFEFF + 1,
|
||||
};
|
||||
|
||||
BOOL lre_is_space(int c)
|
||||
{
|
||||
int i, n, low, high;
|
||||
n = (countof(char_range_s) - 1) / 2;
|
||||
for(i = 0; i < n; i++) {
|
||||
low = char_range_s[2 * i + 1];
|
||||
if (c < low)
|
||||
return FALSE;
|
||||
high = char_range_s[2 * i + 2];
|
||||
if (c < high)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uint32_t const lre_id_start_table_ascii[4] = {
|
||||
/* $ A-Z _ a-z */
|
||||
0x00000000, 0x00000010, 0x87FFFFFE, 0x07FFFFFE
|
||||
};
|
||||
|
||||
uint32_t const lre_id_continue_table_ascii[4] = {
|
||||
/* $ 0-9 A-Z _ a-z */
|
||||
0x00000000, 0x03FF0010, 0x87FFFFFE, 0x07FFFFFE
|
||||
};
|
||||
|
||||
|
||||
static const uint16_t char_range_w[] = {
|
||||
4,
|
||||
0x0030, 0x0039 + 1,
|
||||
|
@ -185,7 +161,7 @@ typedef enum {
|
|||
CHAR_RANGE_W,
|
||||
} CharRangeEnum;
|
||||
|
||||
static const uint16_t *char_range_table[] = {
|
||||
static const uint16_t * const char_range_table[] = {
|
||||
char_range_d,
|
||||
char_range_s,
|
||||
char_range_w,
|
||||
|
@ -196,7 +172,7 @@ static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c)
|
|||
BOOL invert;
|
||||
const uint16_t *c_pt;
|
||||
int len, i;
|
||||
|
||||
|
||||
invert = c & 1;
|
||||
c_pt = char_range_table[c >> 1];
|
||||
len = *c_pt++;
|
||||
|
@ -221,19 +197,19 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
|
|||
{
|
||||
int pos, len, opcode, bc_len, re_flags, i;
|
||||
uint32_t val;
|
||||
|
||||
|
||||
assert(buf_len >= RE_HEADER_LEN);
|
||||
|
||||
re_flags= buf[0];
|
||||
bc_len = get_u32(buf + 3);
|
||||
re_flags = lre_get_flags(buf);
|
||||
bc_len = get_u32(buf + RE_HEADER_BYTECODE_LEN);
|
||||
assert(bc_len + RE_HEADER_LEN <= buf_len);
|
||||
printf("flags: 0x%x capture_count=%d stack_size=%d\n",
|
||||
re_flags, buf[1], buf[2]);
|
||||
re_flags, buf[RE_HEADER_CAPTURE_COUNT], buf[RE_HEADER_STACK_SIZE]);
|
||||
if (re_flags & LRE_FLAG_NAMED_GROUPS) {
|
||||
const char *p;
|
||||
p = (char *)buf + RE_HEADER_LEN + bc_len;
|
||||
printf("named groups: ");
|
||||
for(i = 1; i < buf[1]; i++) {
|
||||
for(i = 1; i < buf[RE_HEADER_CAPTURE_COUNT]; i++) {
|
||||
if (i != 1)
|
||||
printf(",");
|
||||
printf("<%s>", p);
|
||||
|
@ -392,7 +368,7 @@ static int parse_digits(const uint8_t **pp, BOOL allow_overflow)
|
|||
const uint8_t *p;
|
||||
uint64_t v;
|
||||
int c;
|
||||
|
||||
|
||||
p = *pp;
|
||||
v = 0;
|
||||
for(;;) {
|
||||
|
@ -464,7 +440,7 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
|
|||
{
|
||||
int h, n, i;
|
||||
uint32_t c1;
|
||||
|
||||
|
||||
if (*p == '{' && allow_utf16) {
|
||||
p++;
|
||||
c = 0;
|
||||
|
@ -494,7 +470,7 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
|
|||
}
|
||||
c = (c << 4) | h;
|
||||
}
|
||||
if (c >= 0xd800 && c < 0xdc00 &&
|
||||
if (is_hi_surrogate(c) &&
|
||||
allow_utf16 == 2 && p[0] == '\\' && p[1] == 'u') {
|
||||
/* convert an escaped surrogate pair into a
|
||||
unicode char */
|
||||
|
@ -505,9 +481,9 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
|
|||
break;
|
||||
c1 = (c1 << 4) | h;
|
||||
}
|
||||
if (i == 4 && c1 >= 0xdc00 && c1 < 0xe000) {
|
||||
if (i == 4 && is_lo_surrogate(c1)) {
|
||||
p += 6;
|
||||
c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
|
||||
c = from_surrogate(c, c1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -658,7 +634,7 @@ static int get_class_atom(REParseState *s, CharRange *cr,
|
|||
const uint8_t *p;
|
||||
uint32_t c;
|
||||
int ret;
|
||||
|
||||
|
||||
p = *pp;
|
||||
|
||||
c = *p;
|
||||
|
@ -696,10 +672,10 @@ static int get_class_atom(REParseState *s, CharRange *cr,
|
|||
if ((c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(((c >= '0' && c <= '9') || c == '_') &&
|
||||
inclass && !s->is_utf16)) { /* Annex B.1.4 */
|
||||
inclass && !s->is_unicode)) { /* Annex B.1.4 */
|
||||
c &= 0x1f;
|
||||
p++;
|
||||
} else if (s->is_utf16) {
|
||||
} else if (s->is_unicode) {
|
||||
goto invalid_escape;
|
||||
} else {
|
||||
/* otherwise return '\' and 'c' */
|
||||
|
@ -710,7 +686,7 @@ static int get_class_atom(REParseState *s, CharRange *cr,
|
|||
#ifdef CONFIG_ALL_UNICODE
|
||||
case 'p':
|
||||
case 'P':
|
||||
if (s->is_utf16) {
|
||||
if (s->is_unicode) {
|
||||
if (parse_unicode_property(s, cr, &p, (c == 'P')))
|
||||
return -1;
|
||||
c = CLASS_RANGE_BASE;
|
||||
|
@ -720,14 +696,14 @@ static int get_class_atom(REParseState *s, CharRange *cr,
|
|||
#endif
|
||||
default:
|
||||
p--;
|
||||
ret = lre_parse_escape(&p, s->is_utf16 * 2);
|
||||
ret = lre_parse_escape(&p, s->is_unicode * 2);
|
||||
if (ret >= 0) {
|
||||
c = ret;
|
||||
} else {
|
||||
if (ret == -2 && *p != '\0' && strchr("^$\\.*+?()[]{}|/", *p)) {
|
||||
/* always valid to escape these characters */
|
||||
goto normal_char;
|
||||
} else if (s->is_utf16) {
|
||||
} else if (s->is_unicode) {
|
||||
invalid_escape:
|
||||
return re_parse_error(s, "invalid escape sequence in regular expression");
|
||||
} else {
|
||||
|
@ -749,7 +725,7 @@ static int get_class_atom(REParseState *s, CharRange *cr,
|
|||
/* normal char */
|
||||
if (c >= 128) {
|
||||
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
|
||||
if ((unsigned)c > 0xffff && !s->is_utf16) {
|
||||
if ((unsigned)c > 0xffff && !s->is_unicode) {
|
||||
/* XXX: should handle non BMP-1 code points */
|
||||
return re_parse_error(s, "malformed unicode char");
|
||||
}
|
||||
|
@ -766,7 +742,7 @@ static int re_emit_range(REParseState *s, const CharRange *cr)
|
|||
{
|
||||
int len, i;
|
||||
uint32_t high;
|
||||
|
||||
|
||||
len = (unsigned)cr->len / 2;
|
||||
if (len >= 65535)
|
||||
return re_parse_error(s, "too many ranges");
|
||||
|
@ -807,15 +783,17 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
|
|||
CharRange cr_s, *cr = &cr_s;
|
||||
CharRange cr1_s, *cr1 = &cr1_s;
|
||||
BOOL invert;
|
||||
|
||||
|
||||
cr_init(cr, s->opaque, lre_realloc);
|
||||
p = *pp;
|
||||
p++; /* skip '[' */
|
||||
|
||||
invert = FALSE;
|
||||
if (*p == '^') {
|
||||
p++;
|
||||
invert = TRUE;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
if (*p == ']')
|
||||
break;
|
||||
|
@ -825,7 +803,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
|
|||
if (*p == '-' && p[1] != ']') {
|
||||
const uint8_t *p0 = p + 1;
|
||||
if (c1 >= CLASS_RANGE_BASE) {
|
||||
if (s->is_utf16) {
|
||||
if (s->is_unicode) {
|
||||
cr_free(cr1);
|
||||
goto invalid_class_range;
|
||||
}
|
||||
|
@ -837,7 +815,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
|
|||
goto fail;
|
||||
if (c2 >= CLASS_RANGE_BASE) {
|
||||
cr_free(cr1);
|
||||
if (s->is_utf16) {
|
||||
if (s->is_unicode) {
|
||||
goto invalid_class_range;
|
||||
}
|
||||
/* Annex B: match '-' character */
|
||||
|
@ -866,7 +844,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
|
|||
}
|
||||
}
|
||||
if (s->ignore_case) {
|
||||
if (cr_regexp_canonicalize(cr, s->is_utf16))
|
||||
if (cr_regexp_canonicalize(cr, s->is_unicode))
|
||||
goto memory_error;
|
||||
}
|
||||
if (invert) {
|
||||
|
@ -895,7 +873,7 @@ static BOOL re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len)
|
|||
int pos, opcode, len;
|
||||
uint32_t val;
|
||||
BOOL ret;
|
||||
|
||||
|
||||
ret = TRUE;
|
||||
pos = 0;
|
||||
while (pos < bc_buf_len) {
|
||||
|
@ -934,7 +912,7 @@ static BOOL re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len)
|
|||
case REOP_backward_back_reference:
|
||||
break;
|
||||
default:
|
||||
/* safe behvior: we cannot predict the outcome */
|
||||
/* safe behavior: we cannot predict the outcome */
|
||||
return TRUE;
|
||||
}
|
||||
pos += len;
|
||||
|
@ -948,7 +926,7 @@ static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len)
|
|||
{
|
||||
int pos, opcode, len, count;
|
||||
uint32_t val;
|
||||
|
||||
|
||||
count = 0;
|
||||
pos = 0;
|
||||
while (pos < bc_buf_len) {
|
||||
|
@ -1003,10 +981,10 @@ static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp)
|
|||
break;
|
||||
} else if (c >= 128) {
|
||||
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
|
||||
if (c >= 0xD800 && c <= 0xDBFF) {
|
||||
if (is_hi_surrogate(c)) {
|
||||
d = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
|
||||
if (d >= 0xDC00 && d <= 0xDFFF) {
|
||||
c = 0x10000 + 0x400 * (c - 0xD800) + (d - 0xDC00);
|
||||
if (is_lo_surrogate(d)) {
|
||||
c = from_surrogate(c, d);
|
||||
p = p1;
|
||||
}
|
||||
}
|
||||
|
@ -1113,10 +1091,11 @@ static int find_group_name(REParseState *s, const char *name)
|
|||
const char *p, *buf_end;
|
||||
size_t len, name_len;
|
||||
int capture_index;
|
||||
|
||||
name_len = strlen(name);
|
||||
|
||||
p = (char *)s->group_names.buf;
|
||||
if (!p) return -1;
|
||||
buf_end = (char *)s->group_names.buf + s->group_names.size;
|
||||
name_len = strlen(name);
|
||||
capture_index = 1;
|
||||
while (p < buf_end) {
|
||||
len = strlen(p);
|
||||
|
@ -1136,7 +1115,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
int c, last_atom_start, quant_min, quant_max, last_capture_count;
|
||||
BOOL greedy, add_zero_advance_check, is_neg, is_backward_lookahead;
|
||||
CharRange cr_s, *cr = &cr_s;
|
||||
|
||||
|
||||
last_atom_start = -1;
|
||||
last_capture_count = 0;
|
||||
p = s->buf_ptr;
|
||||
|
@ -1161,7 +1140,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
re_emit_op(s, REOP_prev);
|
||||
break;
|
||||
case '{':
|
||||
if (s->is_utf16) {
|
||||
if (s->is_unicode) {
|
||||
return re_parse_error(s, "syntax error");
|
||||
} else if (!is_digit(p[1])) {
|
||||
/* Annex B: we accept '{' not followed by digits as a
|
||||
|
@ -1213,7 +1192,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
lookahead:
|
||||
/* Annex B allows lookahead to be used as an atom for
|
||||
the quantifiers */
|
||||
if (!s->is_utf16 && !is_backward_lookahead) {
|
||||
if (!s->is_unicode && !is_backward_lookahead) {
|
||||
last_atom_start = s->byte_code.size;
|
||||
last_capture_count = s->capture_count;
|
||||
}
|
||||
|
@ -1259,15 +1238,15 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
capture_index = s->capture_count++;
|
||||
re_emit_op_u8(s, REOP_save_start + is_backward_dir,
|
||||
capture_index);
|
||||
|
||||
|
||||
s->buf_ptr = p;
|
||||
if (re_parse_disjunction(s, is_backward_dir))
|
||||
return -1;
|
||||
p = s->buf_ptr;
|
||||
|
||||
|
||||
re_emit_op_u8(s, REOP_save_start + 1 - is_backward_dir,
|
||||
capture_index);
|
||||
|
||||
|
||||
if (re_parse_expect(s, &p, ')'))
|
||||
return -1;
|
||||
}
|
||||
|
@ -1283,13 +1262,13 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
{
|
||||
const uint8_t *p1;
|
||||
int dummy_res;
|
||||
|
||||
|
||||
p1 = p;
|
||||
if (p1[2] != '<') {
|
||||
/* annex B: we tolerate invalid group names in non
|
||||
unicode mode if there is no named capture
|
||||
definition */
|
||||
if (s->is_utf16 || re_has_named_captures(s))
|
||||
if (s->is_unicode || re_has_named_captures(s))
|
||||
return re_parse_error(s, "expecting group name");
|
||||
else
|
||||
goto parse_class_atom;
|
||||
|
@ -1297,7 +1276,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
p1 += 3;
|
||||
if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf),
|
||||
&p1)) {
|
||||
if (s->is_utf16 || re_has_named_captures(s))
|
||||
if (s->is_unicode || re_has_named_captures(s))
|
||||
return re_parse_error(s, "invalid group name");
|
||||
else
|
||||
goto parse_class_atom;
|
||||
|
@ -1308,7 +1287,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
after (inefficient, but hopefully not common */
|
||||
c = re_parse_captures(s, &dummy_res, s->u.tmp_buf);
|
||||
if (c < 0) {
|
||||
if (s->is_utf16 || re_has_named_captures(s))
|
||||
if (s->is_unicode || re_has_named_captures(s))
|
||||
return re_parse_error(s, "group name not defined");
|
||||
else
|
||||
goto parse_class_atom;
|
||||
|
@ -1320,7 +1299,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
case '0':
|
||||
p += 2;
|
||||
c = 0;
|
||||
if (s->is_utf16) {
|
||||
if (s->is_unicode) {
|
||||
if (is_digit(*p)) {
|
||||
return re_parse_error(s, "invalid decimal escape in regular expression");
|
||||
}
|
||||
|
@ -1336,13 +1315,13 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
goto normal_char;
|
||||
case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8':
|
||||
case '9':
|
||||
case '9':
|
||||
{
|
||||
const uint8_t *q = ++p;
|
||||
|
||||
|
||||
c = parse_digits(&p, FALSE);
|
||||
if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) {
|
||||
if (!s->is_utf16) {
|
||||
if (!s->is_unicode) {
|
||||
/* Annex B.1.4: accept legacy octal */
|
||||
p = q;
|
||||
if (*p <= '7') {
|
||||
|
@ -1384,7 +1363,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
break;
|
||||
case ']':
|
||||
case '}':
|
||||
if (s->is_utf16)
|
||||
if (s->is_unicode)
|
||||
return re_parse_error(s, "syntax error");
|
||||
goto parse_class_atom;
|
||||
default:
|
||||
|
@ -1406,7 +1385,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
return -1;
|
||||
} else {
|
||||
if (s->ignore_case)
|
||||
c = lre_canonicalize(c, s->is_utf16);
|
||||
c = lre_canonicalize(c, s->is_unicode);
|
||||
if (c <= 0xffff)
|
||||
re_emit_op_u16(s, REOP_char, c);
|
||||
else
|
||||
|
@ -1442,7 +1421,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
/* As an extension (see ES6 annex B), we accept '{' not
|
||||
followed by digits as a normal atom */
|
||||
if (!is_digit(p[1])) {
|
||||
if (s->is_utf16)
|
||||
if (s->is_unicode)
|
||||
goto invalid_quant_count;
|
||||
break;
|
||||
}
|
||||
|
@ -1461,7 +1440,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
quant_max = INT32_MAX; /* infinity */
|
||||
}
|
||||
}
|
||||
if (*p != '}' && !s->is_utf16) {
|
||||
if (*p != '}' && !s->is_unicode) {
|
||||
/* Annex B: normal atom if invalid '{' syntax */
|
||||
p = p1;
|
||||
break;
|
||||
|
@ -1480,7 +1459,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
}
|
||||
if (greedy) {
|
||||
int len, pos;
|
||||
|
||||
|
||||
if (quant_max > 0) {
|
||||
/* specific optimization for simple quantifiers */
|
||||
if (dbuf_error(&s->byte_code))
|
||||
|
@ -1489,7 +1468,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
s->byte_code.size - last_atom_start);
|
||||
if (len > 0) {
|
||||
re_emit_op(s, REOP_match);
|
||||
|
||||
|
||||
if (dbuf_insert(&s->byte_code, last_atom_start, 17))
|
||||
goto out_of_memory;
|
||||
pos = last_atom_start;
|
||||
|
@ -1506,7 +1485,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (dbuf_error(&s->byte_code))
|
||||
goto out_of_memory;
|
||||
/* the spec tells that if there is no advance when
|
||||
|
@ -1518,7 +1497,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
} else {
|
||||
add_zero_advance_check = FALSE;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
int len, pos;
|
||||
len = s->byte_code.size - last_atom_start;
|
||||
|
@ -1544,7 +1523,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
len + 5 * has_goto + add_zero_advance_check * 2);
|
||||
if (add_zero_advance_check) {
|
||||
s->byte_code.buf[last_atom_start + 1 + 4] = REOP_push_char_pos;
|
||||
re_emit_op(s, REOP_check_advance);
|
||||
re_emit_op(s, REOP_check_advance);
|
||||
}
|
||||
if (has_goto)
|
||||
re_emit_goto(s, REOP_goto, last_atom_start);
|
||||
|
@ -1560,7 +1539,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
|||
pos += 4;
|
||||
if (add_zero_advance_check) {
|
||||
s->byte_code.buf[pos++] = REOP_push_char_pos;
|
||||
re_emit_op(s, REOP_check_advance);
|
||||
re_emit_op(s, REOP_check_advance);
|
||||
}
|
||||
re_emit_goto(s, REOP_loop, last_atom_start + 5);
|
||||
re_emit_op(s, REOP_drop);
|
||||
|
@ -1655,14 +1634,14 @@ static int re_parse_alternative(REParseState *s, BOOL is_backward_dir)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir)
|
||||
{
|
||||
int start, len, pos;
|
||||
|
||||
if (lre_check_stack_overflow(s->opaque, 0))
|
||||
return re_parse_error(s, "stack overflow");
|
||||
|
||||
|
||||
start = s->byte_code.size;
|
||||
if (re_parse_alternative(s, is_backward_dir))
|
||||
return -1;
|
||||
|
@ -1682,7 +1661,7 @@ static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir)
|
|||
|
||||
if (re_parse_alternative(s, is_backward_dir))
|
||||
return -1;
|
||||
|
||||
|
||||
/* patch the goto */
|
||||
len = s->byte_code.size - (pos + 4);
|
||||
put_u32(s->byte_code.buf + pos, len);
|
||||
|
@ -1695,7 +1674,7 @@ static int compute_stack_size(const uint8_t *bc_buf, int bc_buf_len)
|
|||
{
|
||||
int stack_size, stack_size_max, pos, opcode, len;
|
||||
uint32_t val;
|
||||
|
||||
|
||||
stack_size = 0;
|
||||
stack_size_max = 0;
|
||||
bc_buf += RE_HEADER_LEN;
|
||||
|
@ -1746,21 +1725,21 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
|||
REParseState s_s, *s = &s_s;
|
||||
int stack_size;
|
||||
BOOL is_sticky;
|
||||
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->opaque = opaque;
|
||||
s->buf_ptr = (const uint8_t *)buf;
|
||||
s->buf_end = s->buf_ptr + buf_len;
|
||||
s->buf_start = s->buf_ptr;
|
||||
s->re_flags = re_flags;
|
||||
s->is_utf16 = ((re_flags & LRE_FLAG_UTF16) != 0);
|
||||
s->is_unicode = ((re_flags & LRE_FLAG_UNICODE) != 0);
|
||||
is_sticky = ((re_flags & LRE_FLAG_STICKY) != 0);
|
||||
s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0);
|
||||
s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 0);
|
||||
s->capture_count = 1;
|
||||
s->total_capture_count = -1;
|
||||
s->has_named_captures = -1;
|
||||
|
||||
|
||||
dbuf_init2(&s->byte_code, opaque, lre_realloc);
|
||||
dbuf_init2(&s->group_names, opaque, lre_realloc);
|
||||
|
||||
|
@ -1768,7 +1747,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
|||
dbuf_putc(&s->byte_code, 0); /* second element is the number of captures */
|
||||
dbuf_putc(&s->byte_code, 0); /* stack size */
|
||||
dbuf_put_u32(&s->byte_code, 0); /* bytecode length */
|
||||
|
||||
|
||||
if (!is_sticky) {
|
||||
/* iterate thru all positions (about the same as .*?( ... ) )
|
||||
. We do it without an explicit loop so that lock step
|
||||
|
@ -1790,7 +1769,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
|||
}
|
||||
|
||||
re_emit_op_u8(s, REOP_save_end, 0);
|
||||
|
||||
|
||||
re_emit_op(s, REOP_match);
|
||||
|
||||
if (*s->buf_ptr != '\0') {
|
||||
|
@ -1802,16 +1781,17 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
|||
re_parse_out_of_memory(s);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
stack_size = compute_stack_size(s->byte_code.buf, s->byte_code.size);
|
||||
if (stack_size < 0) {
|
||||
re_parse_error(s, "too many imbricated quantifiers");
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
s->byte_code.buf[RE_HEADER_CAPTURE_COUNT] = s->capture_count;
|
||||
s->byte_code.buf[RE_HEADER_STACK_SIZE] = stack_size;
|
||||
put_u32(s->byte_code.buf + 3, s->byte_code.size - RE_HEADER_LEN);
|
||||
put_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN,
|
||||
s->byte_code.size - RE_HEADER_LEN);
|
||||
|
||||
/* add the named groups if needed */
|
||||
if (s->group_names.size > (s->capture_count - 1)) {
|
||||
|
@ -1819,11 +1799,11 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
|||
s->byte_code.buf[RE_HEADER_FLAGS] |= LRE_FLAG_NAMED_GROUPS;
|
||||
}
|
||||
dbuf_free(&s->group_names);
|
||||
|
||||
|
||||
#ifdef DUMP_REOP
|
||||
lre_dump_bytecode(s->byte_code.buf, s->byte_code.size);
|
||||
#endif
|
||||
|
||||
|
||||
error_msg[0] = '\0';
|
||||
*plen = s->byte_code.size;
|
||||
return s->byte_code.buf;
|
||||
|
@ -1842,93 +1822,86 @@ static BOOL is_word_char(uint32_t c)
|
|||
(c == '_'));
|
||||
}
|
||||
|
||||
#define GET_CHAR(c, cptr, cbuf_end) \
|
||||
#define GET_CHAR(c, cptr, cbuf_end, cbuf_type) \
|
||||
do { \
|
||||
if (cbuf_type == 0) { \
|
||||
c = *cptr++; \
|
||||
} else { \
|
||||
uint32_t __c1; \
|
||||
c = *(uint16_t *)cptr; \
|
||||
cptr += 2; \
|
||||
if (c >= 0xd800 && c < 0xdc00 && \
|
||||
cbuf_type == 2 && cptr < cbuf_end) { \
|
||||
__c1 = *(uint16_t *)cptr; \
|
||||
if (__c1 >= 0xdc00 && __c1 < 0xe000) { \
|
||||
c = (((c & 0x3ff) << 10) | (__c1 & 0x3ff)) + 0x10000; \
|
||||
cptr += 2; \
|
||||
const uint16_t *_p = (const uint16_t *)cptr; \
|
||||
const uint16_t *_end = (const uint16_t *)cbuf_end; \
|
||||
c = *_p++; \
|
||||
if (is_hi_surrogate(c) && cbuf_type == 2) { \
|
||||
if (_p < _end && is_lo_surrogate(*_p)) { \
|
||||
c = from_surrogate(c, *_p++); \
|
||||
} \
|
||||
} \
|
||||
cptr = (const void *)_p; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PEEK_CHAR(c, cptr, cbuf_end, cbuf_type) \
|
||||
do { \
|
||||
if (cbuf_type == 0) { \
|
||||
c = cptr[0]; \
|
||||
} else { \
|
||||
const uint16_t *_p = (const uint16_t *)cptr; \
|
||||
const uint16_t *_end = (const uint16_t *)cbuf_end; \
|
||||
c = *_p++; \
|
||||
if (is_hi_surrogate(c) && cbuf_type == 2) { \
|
||||
if (_p < _end && is_lo_surrogate(*_p)) { \
|
||||
c = from_surrogate(c, *_p); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PEEK_CHAR(c, cptr, cbuf_end) \
|
||||
do { \
|
||||
if (cbuf_type == 0) { \
|
||||
c = cptr[0]; \
|
||||
} else { \
|
||||
uint32_t __c1; \
|
||||
c = ((uint16_t *)cptr)[0]; \
|
||||
if (c >= 0xd800 && c < 0xdc00 && \
|
||||
cbuf_type == 2 && (cptr + 2) < cbuf_end) { \
|
||||
__c1 = ((uint16_t *)cptr)[1]; \
|
||||
if (__c1 >= 0xdc00 && __c1 < 0xe000) { \
|
||||
c = (((c & 0x3ff) << 10) | (__c1 & 0x3ff)) + 0x10000; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PEEK_PREV_CHAR(c, cptr, cbuf_start) \
|
||||
do { \
|
||||
if (cbuf_type == 0) { \
|
||||
c = cptr[-1]; \
|
||||
} else { \
|
||||
uint32_t __c1; \
|
||||
c = ((uint16_t *)cptr)[-1]; \
|
||||
if (c >= 0xdc00 && c < 0xe000 && \
|
||||
cbuf_type == 2 && (cptr - 4) >= cbuf_start) { \
|
||||
__c1 = ((uint16_t *)cptr)[-2]; \
|
||||
if (__c1 >= 0xd800 && __c1 < 0xdc00 ) { \
|
||||
c = (((__c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000; \
|
||||
#define PEEK_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \
|
||||
do { \
|
||||
if (cbuf_type == 0) { \
|
||||
c = cptr[-1]; \
|
||||
} else { \
|
||||
const uint16_t *_p = (const uint16_t *)cptr - 1; \
|
||||
const uint16_t *_start = (const uint16_t *)cbuf_start; \
|
||||
c = *_p; \
|
||||
if (is_lo_surrogate(c) && cbuf_type == 2) { \
|
||||
if (_p > _start && is_hi_surrogate(_p[-1])) { \
|
||||
c = from_surrogate(*--_p, c); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define GET_PREV_CHAR(c, cptr, cbuf_start) \
|
||||
do { \
|
||||
if (cbuf_type == 0) { \
|
||||
cptr--; \
|
||||
c = cptr[0]; \
|
||||
} else { \
|
||||
uint32_t __c1; \
|
||||
cptr -= 2; \
|
||||
c = ((uint16_t *)cptr)[0]; \
|
||||
if (c >= 0xdc00 && c < 0xe000 && \
|
||||
cbuf_type == 2 && cptr > cbuf_start) { \
|
||||
__c1 = ((uint16_t *)cptr)[-1]; \
|
||||
if (__c1 >= 0xd800 && __c1 < 0xdc00 ) { \
|
||||
cptr -= 2; \
|
||||
c = (((__c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000; \
|
||||
#define GET_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \
|
||||
do { \
|
||||
if (cbuf_type == 0) { \
|
||||
cptr--; \
|
||||
c = cptr[0]; \
|
||||
} else { \
|
||||
const uint16_t *_p = (const uint16_t *)cptr - 1; \
|
||||
const uint16_t *_start = (const uint16_t *)cbuf_start; \
|
||||
c = *_p; \
|
||||
if (is_lo_surrogate(c) && cbuf_type == 2) { \
|
||||
if (_p > _start && is_hi_surrogate(_p[-1])) { \
|
||||
c = from_surrogate(*--_p, c); \
|
||||
} \
|
||||
} \
|
||||
cptr = (const void *)_p; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PREV_CHAR(cptr, cbuf_start) \
|
||||
do { \
|
||||
if (cbuf_type == 0) { \
|
||||
cptr--; \
|
||||
} else { \
|
||||
cptr -= 2; \
|
||||
if (cbuf_type == 2) { \
|
||||
c = ((uint16_t *)cptr)[0]; \
|
||||
if (c >= 0xdc00 && c < 0xe000 && cptr > cbuf_start) { \
|
||||
c = ((uint16_t *)cptr)[-1]; \
|
||||
if (c >= 0xd800 && c < 0xdc00) \
|
||||
cptr -= 2; \
|
||||
#define PREV_CHAR(cptr, cbuf_start, cbuf_type) \
|
||||
do { \
|
||||
if (cbuf_type == 0) { \
|
||||
cptr--; \
|
||||
} else { \
|
||||
const uint16_t *_p = (const uint16_t *)cptr - 1; \
|
||||
const uint16_t *_start = (const uint16_t *)cbuf_start; \
|
||||
if (is_lo_surrogate(*_p) && cbuf_type == 2) { \
|
||||
if (_p > _start && is_hi_surrogate(_p[-1])) { \
|
||||
--_p; \
|
||||
} \
|
||||
} \
|
||||
cptr = (const void *)_p; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
@ -1954,12 +1927,12 @@ typedef struct {
|
|||
const uint8_t *cbuf;
|
||||
const uint8_t *cbuf_end;
|
||||
/* 0 = 8 bit chars, 1 = 16 bit chars, 2 = 16 bit chars, UTF-16 */
|
||||
int cbuf_type;
|
||||
int cbuf_type;
|
||||
int capture_count;
|
||||
int stack_size_max;
|
||||
BOOL multi_line;
|
||||
BOOL ignore_case;
|
||||
BOOL is_utf16;
|
||||
BOOL is_unicode;
|
||||
void *opaque; /* used for stack overflow check */
|
||||
|
||||
size_t state_size;
|
||||
|
@ -2016,7 +1989,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
int cbuf_type;
|
||||
uint32_t val, c;
|
||||
const uint8_t *cbuf_end;
|
||||
|
||||
|
||||
cbuf_type = s->cbuf_type;
|
||||
cbuf_end = s->cbuf_end;
|
||||
|
||||
|
@ -2068,7 +2041,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
/* go backward */
|
||||
char_count = get_u32(pc + 12);
|
||||
for(i = 0; i < char_count; i++) {
|
||||
PREV_CHAR(cptr, s->cbuf);
|
||||
PREV_CHAR(cptr, s->cbuf, cbuf_type);
|
||||
}
|
||||
pc = (pc + 16) + (int)get_u32(pc);
|
||||
rs->cptr = cptr;
|
||||
|
@ -2103,9 +2076,9 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
test_char:
|
||||
if (cptr >= cbuf_end)
|
||||
goto no_match;
|
||||
GET_CHAR(c, cptr, cbuf_end);
|
||||
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
||||
if (s->ignore_case) {
|
||||
c = lre_canonicalize(c, s->is_utf16);
|
||||
c = lre_canonicalize(c, s->is_unicode);
|
||||
}
|
||||
if (val != c)
|
||||
goto no_match;
|
||||
|
@ -2114,7 +2087,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
case REOP_split_next_first:
|
||||
{
|
||||
const uint8_t *pc1;
|
||||
|
||||
|
||||
val = get_u32(pc);
|
||||
pc += 4;
|
||||
if (opcode == REOP_split_next_first) {
|
||||
|
@ -2140,7 +2113,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
if (ret < 0)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
|
||||
case REOP_goto:
|
||||
val = get_u32(pc);
|
||||
pc += 4 + (int)val;
|
||||
|
@ -2150,7 +2123,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
break;
|
||||
if (!s->multi_line)
|
||||
goto no_match;
|
||||
PEEK_PREV_CHAR(c, cptr, s->cbuf);
|
||||
PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
|
||||
if (!is_line_terminator(c))
|
||||
goto no_match;
|
||||
break;
|
||||
|
@ -2159,21 +2132,21 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
break;
|
||||
if (!s->multi_line)
|
||||
goto no_match;
|
||||
PEEK_CHAR(c, cptr, cbuf_end);
|
||||
PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
|
||||
if (!is_line_terminator(c))
|
||||
goto no_match;
|
||||
break;
|
||||
case REOP_dot:
|
||||
if (cptr == cbuf_end)
|
||||
goto no_match;
|
||||
GET_CHAR(c, cptr, cbuf_end);
|
||||
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
||||
if (is_line_terminator(c))
|
||||
goto no_match;
|
||||
break;
|
||||
case REOP_any:
|
||||
if (cptr == cbuf_end)
|
||||
goto no_match;
|
||||
GET_CHAR(c, cptr, cbuf_end);
|
||||
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
||||
break;
|
||||
case REOP_save_start:
|
||||
case REOP_save_end:
|
||||
|
@ -2225,14 +2198,14 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
if (cptr == s->cbuf) {
|
||||
v1 = FALSE;
|
||||
} else {
|
||||
PEEK_PREV_CHAR(c, cptr, s->cbuf);
|
||||
PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
|
||||
v1 = is_word_char(c);
|
||||
}
|
||||
/* current char */
|
||||
if (cptr >= cbuf_end) {
|
||||
v2 = FALSE;
|
||||
} else {
|
||||
PEEK_CHAR(c, cptr, cbuf_end);
|
||||
PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
|
||||
v2 = is_word_char(c);
|
||||
}
|
||||
if (v1 ^ v2 ^ (REOP_not_word_boundary - opcode))
|
||||
|
@ -2244,7 +2217,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
{
|
||||
const uint8_t *cptr1, *cptr1_end, *cptr1_start;
|
||||
uint32_t c1, c2;
|
||||
|
||||
|
||||
val = *pc++;
|
||||
if (val >= s->capture_count)
|
||||
goto no_match;
|
||||
|
@ -2257,11 +2230,11 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
while (cptr1 < cptr1_end) {
|
||||
if (cptr >= cbuf_end)
|
||||
goto no_match;
|
||||
GET_CHAR(c1, cptr1, cptr1_end);
|
||||
GET_CHAR(c2, cptr, cbuf_end);
|
||||
GET_CHAR(c1, cptr1, cptr1_end, cbuf_type);
|
||||
GET_CHAR(c2, cptr, cbuf_end, cbuf_type);
|
||||
if (s->ignore_case) {
|
||||
c1 = lre_canonicalize(c1, s->is_utf16);
|
||||
c2 = lre_canonicalize(c2, s->is_utf16);
|
||||
c1 = lre_canonicalize(c1, s->is_unicode);
|
||||
c2 = lre_canonicalize(c2, s->is_unicode);
|
||||
}
|
||||
if (c1 != c2)
|
||||
goto no_match;
|
||||
|
@ -2271,11 +2244,11 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
while (cptr1 > cptr1_start) {
|
||||
if (cptr == s->cbuf)
|
||||
goto no_match;
|
||||
GET_PREV_CHAR(c1, cptr1, cptr1_start);
|
||||
GET_PREV_CHAR(c2, cptr, s->cbuf);
|
||||
GET_PREV_CHAR(c1, cptr1, cptr1_start, cbuf_type);
|
||||
GET_PREV_CHAR(c2, cptr, s->cbuf, cbuf_type);
|
||||
if (s->ignore_case) {
|
||||
c1 = lre_canonicalize(c1, s->is_utf16);
|
||||
c2 = lre_canonicalize(c2, s->is_utf16);
|
||||
c1 = lre_canonicalize(c1, s->is_unicode);
|
||||
c2 = lre_canonicalize(c2, s->is_unicode);
|
||||
}
|
||||
if (c1 != c2)
|
||||
goto no_match;
|
||||
|
@ -2287,14 +2260,14 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
{
|
||||
int n;
|
||||
uint32_t low, high, idx_min, idx_max, idx;
|
||||
|
||||
|
||||
n = get_u16(pc); /* n must be >= 1 */
|
||||
pc += 2;
|
||||
if (cptr >= cbuf_end)
|
||||
goto no_match;
|
||||
GET_CHAR(c, cptr, cbuf_end);
|
||||
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
||||
if (s->ignore_case) {
|
||||
c = lre_canonicalize(c, s->is_utf16);
|
||||
c = lre_canonicalize(c, s->is_unicode);
|
||||
}
|
||||
idx_min = 0;
|
||||
low = get_u16(pc + 0 * 4);
|
||||
|
@ -2327,14 +2300,14 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
{
|
||||
int n;
|
||||
uint32_t low, high, idx_min, idx_max, idx;
|
||||
|
||||
|
||||
n = get_u16(pc); /* n must be >= 1 */
|
||||
pc += 2;
|
||||
if (cptr >= cbuf_end)
|
||||
goto no_match;
|
||||
GET_CHAR(c, cptr, cbuf_end);
|
||||
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
||||
if (s->ignore_case) {
|
||||
c = lre_canonicalize(c, s->is_utf16);
|
||||
c = lre_canonicalize(c, s->is_unicode);
|
||||
}
|
||||
idx_min = 0;
|
||||
low = get_u32(pc + 0 * 8);
|
||||
|
@ -2364,7 +2337,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
/* go to the previous char */
|
||||
if (cptr == s->cbuf)
|
||||
goto no_match;
|
||||
PREV_CHAR(cptr, s->cbuf);
|
||||
PREV_CHAR(cptr, s->cbuf, cbuf_type);
|
||||
break;
|
||||
case REOP_simple_greedy_quant:
|
||||
{
|
||||
|
@ -2372,14 +2345,14 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
|
|||
size_t q;
|
||||
intptr_t res;
|
||||
const uint8_t *pc1;
|
||||
|
||||
|
||||
next_pos = get_u32(pc);
|
||||
quant_min = get_u32(pc + 4);
|
||||
quant_max = get_u32(pc + 8);
|
||||
pc += 16;
|
||||
pc1 = pc;
|
||||
pc += (int)next_pos;
|
||||
|
||||
|
||||
q = 0;
|
||||
for(;;) {
|
||||
res = lre_exec_backtrack(s, capture, stack, stack_len,
|
||||
|
@ -2422,17 +2395,17 @@ int lre_exec(uint8_t **capture,
|
|||
REExecContext s_s, *s = &s_s;
|
||||
int re_flags, i, alloca_size, ret;
|
||||
StackInt *stack_buf;
|
||||
|
||||
re_flags = bc_buf[RE_HEADER_FLAGS];
|
||||
|
||||
re_flags = lre_get_flags(bc_buf);
|
||||
s->multi_line = (re_flags & LRE_FLAG_MULTILINE) != 0;
|
||||
s->ignore_case = (re_flags & LRE_FLAG_IGNORECASE) != 0;
|
||||
s->is_utf16 = (re_flags & LRE_FLAG_UTF16) != 0;
|
||||
s->is_unicode = (re_flags & LRE_FLAG_UNICODE) != 0;
|
||||
s->capture_count = bc_buf[RE_HEADER_CAPTURE_COUNT];
|
||||
s->stack_size_max = bc_buf[RE_HEADER_STACK_SIZE];
|
||||
s->cbuf = cbuf;
|
||||
s->cbuf_end = cbuf + (clen << cbuf_type);
|
||||
s->cbuf_type = cbuf_type;
|
||||
if (s->cbuf_type == 1 && s->is_utf16)
|
||||
if (s->cbuf_type == 1 && s->is_unicode)
|
||||
s->cbuf_type = 2;
|
||||
s->opaque = opaque;
|
||||
|
||||
|
@ -2442,7 +2415,7 @@ int lre_exec(uint8_t **capture,
|
|||
s->state_stack = NULL;
|
||||
s->state_stack_len = 0;
|
||||
s->state_stack_size = 0;
|
||||
|
||||
|
||||
for(i = 0; i < s->capture_count * 2; i++)
|
||||
capture[i] = NULL;
|
||||
alloca_size = s->stack_size_max * sizeof(stack_buf[0]);
|
||||
|
@ -2470,8 +2443,8 @@ const char *lre_get_groupnames(const uint8_t *bc_buf)
|
|||
uint32_t re_bytecode_len;
|
||||
if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0)
|
||||
return NULL;
|
||||
re_bytecode_len = get_u32(bc_buf + 3);
|
||||
return (const char *)(bc_buf + 7 + re_bytecode_len);
|
||||
re_bytecode_len = get_u32(bc_buf + RE_HEADER_BYTECODE_LEN);
|
||||
return (const char *)(bc_buf + RE_HEADER_LEN + re_bytecode_len);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
@ -2488,27 +2461,28 @@ void *lre_realloc(void *opaque, void *ptr, size_t size)
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int len, ret, i;
|
||||
int len, flags, ret, i;
|
||||
uint8_t *bc;
|
||||
char error_msg[64];
|
||||
uint8_t *capture[CAPTURE_COUNT_MAX * 2];
|
||||
const char *input;
|
||||
int input_len, capture_count;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("usage: %s regexp input\n", argv[0]);
|
||||
exit(1);
|
||||
|
||||
if (argc < 4) {
|
||||
printf("usage: %s regexp flags input\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
flags = atoi(argv[2]);
|
||||
bc = lre_compile(&len, error_msg, sizeof(error_msg), argv[1],
|
||||
strlen(argv[1]), 0, NULL);
|
||||
strlen(argv[1]), flags, NULL);
|
||||
if (!bc) {
|
||||
fprintf(stderr, "error: %s\n", error_msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
input = argv[2];
|
||||
input = argv[3];
|
||||
input_len = strlen(input);
|
||||
|
||||
|
||||
ret = lre_exec(capture, bc, (uint8_t *)input, 0, input_len, 0, NULL);
|
||||
printf("ret=%d\n", ret);
|
||||
if (ret == 1) {
|
||||
|
|
48
libregexp.h
48
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,19 +25,15 @@
|
|||
#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 */
|
||||
|
||||
uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
||||
|
@ -51,43 +47,9 @@ 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);
|
||||
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 */
|
||||
|
|
|
@ -189,9 +189,13 @@ static const uint8_t unicode_prop_Cased1_table[196] = {
|
|||
};
|
||||
|
||||
static const uint8_t unicode_prop_Cased1_index[21] = {
|
||||
0xb9, 0x02, 0xe0, 0xc0, 0x1d, 0x20, 0xe5, 0x2c,
|
||||
0x20, 0xb1, 0x07, 0x21, 0xc1, 0xd6, 0x21, 0x4a,
|
||||
0xf1, 0x01, 0x8a, 0xf1, 0x01,
|
||||
0xb9, 0x02, 0xe0, // 002B9 at 39
|
||||
0xc0, 0x1d, 0x20, // 01DC0 at 65
|
||||
0xe5, 0x2c, 0x20, // 02CE5 at 97
|
||||
0xb1, 0x07, 0x21, // 107B1 at 129
|
||||
0xc1, 0xd6, 0x21, // 1D6C1 at 161
|
||||
0x4a, 0xf1, 0x01, // 1F14A at 192
|
||||
0x8a, 0xf1, 0x01, // 1F18A at 224 (upper bound)
|
||||
};
|
||||
|
||||
static const uint8_t unicode_prop_Case_Ignorable_table[737] = {
|
||||
|
@ -291,15 +295,29 @@ static const uint8_t unicode_prop_Case_Ignorable_table[737] = {
|
|||
};
|
||||
|
||||
static const uint8_t unicode_prop_Case_Ignorable_index[69] = {
|
||||
0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a,
|
||||
0xa0, 0xc1, 0x0b, 0x00, 0x82, 0x0d, 0x00, 0x3f,
|
||||
0x10, 0x80, 0xd4, 0x17, 0x40, 0xcf, 0x1a, 0x20,
|
||||
0xf5, 0x1c, 0x00, 0x80, 0x20, 0x00, 0x16, 0xa0,
|
||||
0x00, 0xc6, 0xa8, 0x00, 0xc2, 0xaa, 0x60, 0x56,
|
||||
0xfe, 0x20, 0xb1, 0x07, 0x01, 0x75, 0x10, 0x01,
|
||||
0xeb, 0x12, 0x21, 0x41, 0x16, 0x01, 0x5c, 0x1a,
|
||||
0x01, 0x43, 0x1f, 0x01, 0x2e, 0xcf, 0x41, 0x25,
|
||||
0xe0, 0x01, 0xf0, 0x01, 0x0e,
|
||||
0xbe, 0x05, 0x00, // 005BE at 32
|
||||
0xfe, 0x07, 0x00, // 007FE at 64
|
||||
0x52, 0x0a, 0xa0, // 00A52 at 101
|
||||
0xc1, 0x0b, 0x00, // 00BC1 at 128
|
||||
0x82, 0x0d, 0x00, // 00D82 at 160
|
||||
0x3f, 0x10, 0x80, // 0103F at 196
|
||||
0xd4, 0x17, 0x40, // 017D4 at 226
|
||||
0xcf, 0x1a, 0x20, // 01ACF at 257
|
||||
0xf5, 0x1c, 0x00, // 01CF5 at 288
|
||||
0x80, 0x20, 0x00, // 02080 at 320
|
||||
0x16, 0xa0, 0x00, // 0A016 at 352
|
||||
0xc6, 0xa8, 0x00, // 0A8C6 at 384
|
||||
0xc2, 0xaa, 0x60, // 0AAC2 at 419
|
||||
0x56, 0xfe, 0x20, // 0FE56 at 449
|
||||
0xb1, 0x07, 0x01, // 107B1 at 480
|
||||
0x75, 0x10, 0x01, // 11075 at 512
|
||||
0xeb, 0x12, 0x21, // 112EB at 545
|
||||
0x41, 0x16, 0x01, // 11641 at 576
|
||||
0x5c, 0x1a, 0x01, // 11A5C at 608
|
||||
0x43, 0x1f, 0x01, // 11F43 at 640
|
||||
0x2e, 0xcf, 0x41, // 1CF2E at 674
|
||||
0x25, 0xe0, 0x01, // 1E025 at 704
|
||||
0xf0, 0x01, 0x0e, // E01F0 at 736 (upper bound)
|
||||
};
|
||||
|
||||
static const uint8_t unicode_prop_ID_Start_table[1100] = {
|
||||
|
@ -444,20 +462,41 @@ static const uint8_t unicode_prop_ID_Start_table[1100] = {
|
|||
};
|
||||
|
||||
static const uint8_t unicode_prop_ID_Start_index[105] = {
|
||||
0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09,
|
||||
0x20, 0xb1, 0x0a, 0x00, 0xba, 0x0b, 0x20, 0x3b,
|
||||
0x0d, 0x20, 0xc7, 0x0e, 0x20, 0x49, 0x12, 0x00,
|
||||
0x9b, 0x16, 0x00, 0xac, 0x19, 0x00, 0xc0, 0x1d,
|
||||
0x80, 0x80, 0x20, 0x20, 0x70, 0x2d, 0x00, 0x00,
|
||||
0x32, 0x00, 0xda, 0xa7, 0x00, 0x4c, 0xaa, 0x20,
|
||||
0xc7, 0xd7, 0x20, 0xfc, 0xfd, 0x20, 0x9d, 0x02,
|
||||
0x21, 0x96, 0x05, 0x01, 0xf3, 0x08, 0x01, 0xb3,
|
||||
0x0c, 0x21, 0x73, 0x11, 0x61, 0x34, 0x13, 0x01,
|
||||
0x1b, 0x17, 0x21, 0x8a, 0x1a, 0x01, 0x34, 0x1f,
|
||||
0x21, 0xbf, 0x6a, 0x01, 0x23, 0xb1, 0xa1, 0xad,
|
||||
0xd4, 0x01, 0x6f, 0xd7, 0x01, 0xff, 0xe7, 0x61,
|
||||
0x5e, 0xee, 0x01, 0xe1, 0xeb, 0x22, 0xb0, 0x23,
|
||||
0x03,
|
||||
0xf6, 0x03, 0x20, // 003F6 at 33
|
||||
0xa6, 0x07, 0x00, // 007A6 at 64
|
||||
0xa9, 0x09, 0x20, // 009A9 at 97
|
||||
0xb1, 0x0a, 0x00, // 00AB1 at 128
|
||||
0xba, 0x0b, 0x20, // 00BBA at 161
|
||||
0x3b, 0x0d, 0x20, // 00D3B at 193
|
||||
0xc7, 0x0e, 0x20, // 00EC7 at 225
|
||||
0x49, 0x12, 0x00, // 01249 at 256
|
||||
0x9b, 0x16, 0x00, // 0169B at 288
|
||||
0xac, 0x19, 0x00, // 019AC at 320
|
||||
0xc0, 0x1d, 0x80, // 01DC0 at 356
|
||||
0x80, 0x20, 0x20, // 02080 at 385
|
||||
0x70, 0x2d, 0x00, // 02D70 at 416
|
||||
0x00, 0x32, 0x00, // 03200 at 448
|
||||
0xda, 0xa7, 0x00, // 0A7DA at 480
|
||||
0x4c, 0xaa, 0x20, // 0AA4C at 513
|
||||
0xc7, 0xd7, 0x20, // 0D7C7 at 545
|
||||
0xfc, 0xfd, 0x20, // 0FDFC at 577
|
||||
0x9d, 0x02, 0x21, // 1029D at 609
|
||||
0x96, 0x05, 0x01, // 10596 at 640
|
||||
0xf3, 0x08, 0x01, // 108F3 at 672
|
||||
0xb3, 0x0c, 0x21, // 10CB3 at 705
|
||||
0x73, 0x11, 0x61, // 11173 at 739
|
||||
0x34, 0x13, 0x01, // 11334 at 768
|
||||
0x1b, 0x17, 0x21, // 1171B at 801
|
||||
0x8a, 0x1a, 0x01, // 11A8A at 832
|
||||
0x34, 0x1f, 0x21, // 11F34 at 865
|
||||
0xbf, 0x6a, 0x01, // 16ABF at 896
|
||||
0x23, 0xb1, 0xa1, // 1B123 at 933
|
||||
0xad, 0xd4, 0x01, // 1D4AD at 960
|
||||
0x6f, 0xd7, 0x01, // 1D76F at 992
|
||||
0xff, 0xe7, 0x61, // 1E7FF at 1027
|
||||
0x5e, 0xee, 0x01, // 1EE5E at 1056
|
||||
0xe1, 0xeb, 0x22, // 2EBE1 at 1089
|
||||
0xb0, 0x23, 0x03, // 323B0 at 1120 (upper bound)
|
||||
};
|
||||
|
||||
static const uint8_t unicode_prop_ID_Continue1_table[660] = {
|
||||
|
@ -547,14 +586,27 @@ static const uint8_t unicode_prop_ID_Continue1_table[660] = {
|
|||
};
|
||||
|
||||
static const uint8_t unicode_prop_ID_Continue1_index[63] = {
|
||||
0xfa, 0x06, 0x00, 0x70, 0x09, 0x00, 0xf0, 0x0a,
|
||||
0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x60, 0xc7,
|
||||
0x0f, 0x20, 0xea, 0x17, 0x40, 0x05, 0x1b, 0x00,
|
||||
0x41, 0x20, 0x00, 0x0c, 0xa8, 0x80, 0x37, 0xaa,
|
||||
0x20, 0x50, 0xfe, 0x20, 0x3a, 0x0d, 0x21, 0x74,
|
||||
0x11, 0x01, 0x5a, 0x14, 0x21, 0x44, 0x19, 0x81,
|
||||
0x5a, 0x1d, 0xa1, 0xf5, 0x6a, 0x21, 0x45, 0xd2,
|
||||
0x41, 0xaf, 0xe2, 0x21, 0xf0, 0x01, 0x0e,
|
||||
0xfa, 0x06, 0x00, // 006FA at 32
|
||||
0x70, 0x09, 0x00, // 00970 at 64
|
||||
0xf0, 0x0a, 0x40, // 00AF0 at 98
|
||||
0x57, 0x0c, 0x00, // 00C57 at 128
|
||||
0xf0, 0x0d, 0x60, // 00DF0 at 163
|
||||
0xc7, 0x0f, 0x20, // 00FC7 at 193
|
||||
0xea, 0x17, 0x40, // 017EA at 226
|
||||
0x05, 0x1b, 0x00, // 01B05 at 256
|
||||
0x41, 0x20, 0x00, // 02041 at 288
|
||||
0x0c, 0xa8, 0x80, // 0A80C at 324
|
||||
0x37, 0xaa, 0x20, // 0AA37 at 353
|
||||
0x50, 0xfe, 0x20, // 0FE50 at 385
|
||||
0x3a, 0x0d, 0x21, // 10D3A at 417
|
||||
0x74, 0x11, 0x01, // 11174 at 448
|
||||
0x5a, 0x14, 0x21, // 1145A at 481
|
||||
0x44, 0x19, 0x81, // 11944 at 516
|
||||
0x5a, 0x1d, 0xa1, // 11D5A at 549
|
||||
0xf5, 0x6a, 0x21, // 16AF5 at 577
|
||||
0x45, 0xd2, 0x41, // 1D245 at 610
|
||||
0xaf, 0xe2, 0x21, // 1E2AF at 641
|
||||
0xf0, 0x01, 0x0e, // E01F0 at 672 (upper bound)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ALL_UNICODE
|
||||
|
@ -676,17 +728,35 @@ static const uint8_t unicode_cc_table[899] = {
|
|||
};
|
||||
|
||||
static const uint8_t unicode_cc_index[87] = {
|
||||
0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05,
|
||||
0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0x9c,
|
||||
0x08, 0x00, 0x4d, 0x09, 0x00, 0x3c, 0x0b, 0x00,
|
||||
0x3d, 0x0d, 0x00, 0x36, 0x0f, 0x00, 0x38, 0x10,
|
||||
0x20, 0x3a, 0x19, 0x00, 0xcb, 0x1a, 0x20, 0xd3,
|
||||
0x1c, 0x00, 0xcf, 0x1d, 0x00, 0xe2, 0x20, 0x00,
|
||||
0x2e, 0x30, 0x20, 0x2b, 0xa9, 0x20, 0xed, 0xab,
|
||||
0x00, 0x39, 0x0a, 0x01, 0x51, 0x0f, 0x01, 0x73,
|
||||
0x11, 0x01, 0x75, 0x13, 0x01, 0x2b, 0x17, 0x21,
|
||||
0x3f, 0x1c, 0x21, 0x9e, 0xbc, 0x21, 0x08, 0xe0,
|
||||
0x01, 0x44, 0xe9, 0x01, 0x4b, 0xe9, 0x01,
|
||||
0x4d, 0x03, 0x00, // 0034D at 32
|
||||
0x97, 0x05, 0x20, // 00597 at 65
|
||||
0xc6, 0x05, 0x00, // 005C6 at 96
|
||||
0xe7, 0x06, 0x00, // 006E7 at 128
|
||||
0x45, 0x07, 0x00, // 00745 at 160
|
||||
0x9c, 0x08, 0x00, // 0089C at 192
|
||||
0x4d, 0x09, 0x00, // 0094D at 224
|
||||
0x3c, 0x0b, 0x00, // 00B3C at 256
|
||||
0x3d, 0x0d, 0x00, // 00D3D at 288
|
||||
0x36, 0x0f, 0x00, // 00F36 at 320
|
||||
0x38, 0x10, 0x20, // 01038 at 353
|
||||
0x3a, 0x19, 0x00, // 0193A at 384
|
||||
0xcb, 0x1a, 0x20, // 01ACB at 417
|
||||
0xd3, 0x1c, 0x00, // 01CD3 at 448
|
||||
0xcf, 0x1d, 0x00, // 01DCF at 480
|
||||
0xe2, 0x20, 0x00, // 020E2 at 512
|
||||
0x2e, 0x30, 0x20, // 0302E at 545
|
||||
0x2b, 0xa9, 0x20, // 0A92B at 577
|
||||
0xed, 0xab, 0x00, // 0ABED at 608
|
||||
0x39, 0x0a, 0x01, // 10A39 at 640
|
||||
0x51, 0x0f, 0x01, // 10F51 at 672
|
||||
0x73, 0x11, 0x01, // 11173 at 704
|
||||
0x75, 0x13, 0x01, // 11375 at 736
|
||||
0x2b, 0x17, 0x21, // 1172B at 769
|
||||
0x3f, 0x1c, 0x21, // 11C3F at 801
|
||||
0x9e, 0xbc, 0x21, // 1BC9E at 833
|
||||
0x08, 0xe0, 0x01, // 1E008 at 864
|
||||
0x44, 0xe9, 0x01, // 1E944 at 896
|
||||
0x4b, 0xe9, 0x01, // 1E94B at 928 (upper bound)
|
||||
};
|
||||
|
||||
static const uint32_t unicode_decomp_table1[699] = {
|
||||
|
@ -4484,3 +4554,4 @@ static const uint16_t unicode_prop_len_table[] = {
|
|||
};
|
||||
|
||||
#endif /* CONFIG_ALL_UNICODE */
|
||||
/* 62 tables / 32261 bytes, 5 index / 345 bytes */
|
||||
|
|
186
libunicode.c
186
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(;;) {
|
||||
|
@ -761,7 +765,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 +795,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 +831,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 +887,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 +926,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 +971,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 +999,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 +1044,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 +1077,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 +1196,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 +1258,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++;
|
||||
|
@ -1350,7 +1378,7 @@ static int point_cmp(const void *p1, const void *p2, void *arg)
|
|||
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;
|
||||
|
@ -1389,7 +1417,7 @@ 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);
|
||||
|
@ -1404,7 +1432,7 @@ int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode)
|
|||
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 */
|
||||
|
||||
|
@ -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;
|
||||
|
|
90
qjs.c
90
qjs.c
|
@ -1,7 +1,6 @@
|
|||
/*
|
||||
* QuickJS stand alone interpreter
|
||||
*
|
||||
* Copyright (c) 2024 Sneed Group
|
||||
*
|
||||
* Copyright (c) 2017-2021 Fabrice Bellard
|
||||
* Copyright (c) 2017-2021 Charlie Gordon
|
||||
*
|
||||
|
@ -37,6 +36,8 @@
|
|||
#include <malloc/malloc.h>
|
||||
#elif defined(__linux__)
|
||||
#include <malloc.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <malloc_np.h>
|
||||
#endif
|
||||
|
||||
#include "cutils.h"
|
||||
|
@ -65,6 +66,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);
|
||||
}
|
||||
|
@ -83,7 +85,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);
|
||||
|
@ -98,34 +100,6 @@ static int eval_file(JSContext *ctx, const char *filename, int module)
|
|||
eval_flags = JS_EVAL_TYPE_MODULE;
|
||||
else
|
||||
eval_flags = JS_EVAL_TYPE_GLOBAL;
|
||||
|
||||
//POLYFILLS FOR QJS FILES BEGIN
|
||||
const char *pf = "globalThis.global = globalThis;\n"
|
||||
"global.console.error = console.log\n"
|
||||
"global.console.warn = console.log\n"
|
||||
"globalThis.breakFunction = () => { throw new Error('Function Break'); };\n"
|
||||
"\n"
|
||||
"if (typeof os !== 'undefined') {\n"
|
||||
" globalThis.sleep = os.sleep;\n"
|
||||
" async function setTimeout2(func, ms) {globalThis.clearTimeout = false; await sleep(ms); if (!clearTimeout) { func(); } }\n"
|
||||
" globalThis.setTimeout = setTimeout2\n"
|
||||
"} else {\n"
|
||||
" console.error('os is not defined.');\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"if (typeof std !== 'undefined') {\n"
|
||||
" globalThis.urlGet = std.urlGet;\n"
|
||||
" globalThis.loadFile = std.loadFile;\n"
|
||||
" globalThis.printf = console.log;\n"
|
||||
" globalThis.evalFile = std.loadScript;\n"
|
||||
" globalThis.require = std.loadScript;\n"
|
||||
" globalThis.getURL = std.urlGet;\n"
|
||||
"} else {\n"
|
||||
" console.error('std is not defined.');\n"
|
||||
"}\n";
|
||||
|
||||
|
||||
eval_buf(ctx, pf, strlen(pf), "<input>", JS_EVAL_TYPE_MODULE);
|
||||
ret = eval_buf(ctx, buf, buf_len, filename, eval_flags);
|
||||
js_free(ctx, buf);
|
||||
return ret;
|
||||
|
@ -334,7 +308,7 @@ int main(int argc, char **argv)
|
|||
int trace_memory = 0;
|
||||
int empty_run = 0;
|
||||
int module = -1;
|
||||
//int load_std = 0; //we don't need this anymore, we ignore this and always load std libs
|
||||
int load_std = 0;
|
||||
int dump_unhandled_promise_rejection = 0;
|
||||
size_t memory_limit = 0;
|
||||
char *include_list[32];
|
||||
|
@ -343,7 +317,7 @@ int main(int argc, char **argv)
|
|||
int load_jscalc;
|
||||
#endif
|
||||
size_t stack_size = 0;
|
||||
|
||||
|
||||
#ifdef CONFIG_BIGNUM
|
||||
/* load jscalc runtime if invoked as 'qjscalc' */
|
||||
{
|
||||
|
@ -355,7 +329,7 @@ int main(int argc, char **argv)
|
|||
load_jscalc = !strcmp(exename, "qjscalc");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* cannot use getopt because we want to pass the command line to
|
||||
the script */
|
||||
optind = 1;
|
||||
|
@ -425,10 +399,10 @@ int main(int argc, char **argv)
|
|||
trace_memory++;
|
||||
continue;
|
||||
}
|
||||
//if (!strcmp(longopt, "std")) {
|
||||
//load_std = 1;
|
||||
//continue;
|
||||
//}
|
||||
if (!strcmp(longopt, "std")) {
|
||||
load_std = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "unhandled-rejection")) {
|
||||
dump_unhandled_promise_rejection = 1;
|
||||
continue;
|
||||
|
@ -506,7 +480,7 @@ int main(int argc, char **argv)
|
|||
JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
if (!empty_run) {
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (load_jscalc) {
|
||||
|
@ -515,15 +489,14 @@ int main(int argc, char **argv)
|
|||
#endif
|
||||
js_std_add_helpers(ctx, argc - optind, argv + optind);
|
||||
|
||||
/* make 'std' and 'os' visible to all code */
|
||||
//if (load_std) {
|
||||
/* make 'std' and 'os' visible to non module code */
|
||||
if (load_std) {
|
||||
const char *str = "import * as std from 'std';\n"
|
||||
"import * as os from 'os';\n"
|
||||
"globalThis.std = std;\n"
|
||||
"globalThis.os = os;\n";
|
||||
eval_buf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE);
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
for(i = 0; i < include_count; i++) {
|
||||
if (eval_file(ctx, include_list[i], module))
|
||||
|
@ -546,38 +519,9 @@ int main(int argc, char **argv)
|
|||
if (interactive) {
|
||||
js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0);
|
||||
}
|
||||
|
||||
//POLYFILLS FOR QJS REPL BEGIN
|
||||
const char *pf = "globalThis.global = globalThis;\n"
|
||||
"global.console.error = console.log\n"
|
||||
"global.console.warn = console.log\n"
|
||||
"globalThis.breakFunction = () => { throw new Error('Function Break'); };\n"
|
||||
"\n"
|
||||
"if (typeof os !== 'undefined') {\n"
|
||||
" globalThis.sleep = os.sleep;\n"
|
||||
" async function setTimeout2(func, ms) {globalThis.clearTimeout = false; await sleep(ms); if (!clearTimeout) { func(); } }\n"
|
||||
" globalThis.setTimeout = setTimeout2\n"
|
||||
"} else {\n"
|
||||
" console.error('os is not defined.');\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"if (typeof std !== 'undefined') {\n"
|
||||
" globalThis.urlGet = std.urlGet;\n"
|
||||
" globalThis.loadFile = std.loadFile;\n"
|
||||
" globalThis.printf = console.log;\n"
|
||||
" globalThis.evalFile = std.loadScript;\n"
|
||||
" globalThis.require = std.loadScript;\n"
|
||||
" globalThis.getURL = std.urlGet;\n"
|
||||
"} else {\n"
|
||||
" console.error('std is not defined.');\n"
|
||||
"}\n";
|
||||
|
||||
|
||||
eval_buf(ctx, pf, strlen(pf), "<input>", JS_EVAL_TYPE_MODULE);
|
||||
|
||||
js_std_loop(ctx);
|
||||
}
|
||||
|
||||
|
||||
if (dump_memory) {
|
||||
JSMemoryUsage stats;
|
||||
JS_ComputeMemoryUsage(rt, &stats);
|
||||
|
|
52
qjsc.c
52
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
|
||||
|
@ -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);
|
||||
|
@ -383,7 +383,7 @@ int exec_cmd(char **argv)
|
|||
if (pid == 0) {
|
||||
execvp(argv[0], argv);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
ret = waitpid(pid, &status, 0);
|
||||
|
@ -401,7 +401,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 +421,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 +452,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;
|
||||
|
@ -496,7 +496,7 @@ int main(int argc, char **argv)
|
|||
BOOL bignum_ext = FALSE;
|
||||
#endif
|
||||
namelist_t dynamic_module_list;
|
||||
|
||||
|
||||
out_filename = NULL;
|
||||
output_type = OUTPUT_EXECUTABLE;
|
||||
cname = NULL;
|
||||
|
@ -507,7 +507,7 @@ int main(int argc, char **argv)
|
|||
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);
|
||||
|
@ -620,14 +620,14 @@ 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
|
||||
|
@ -638,14 +638,14 @@ int main(int argc, char **argv)
|
|||
JS_EnableBignumExt(ctx, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* loader for ES6 modules */
|
||||
JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL);
|
||||
|
||||
fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n"
|
||||
"\n"
|
||||
);
|
||||
|
||||
|
||||
if (output_type != OUTPUT_C) {
|
||||
fprintf(fo, "#include \"quickjs-libc.h\"\n"
|
||||
"\n"
|
||||
|
@ -669,7 +669,7 @@ int main(int argc, char **argv)
|
|||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (output_type != OUTPUT_C) {
|
||||
fprintf(fo,
|
||||
"static JSContext *JS_NewCustomContext(JSRuntime *rt)\n"
|
||||
|
@ -700,7 +700,7 @@ int main(int argc, char **argv)
|
|||
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 +718,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 +744,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
fputs(main_c_template2, fo);
|
||||
}
|
||||
|
||||
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
|
||||
|
|
76
qjscalc.js
76
qjscalc.js
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* QuickJS Javascript Calculator
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2020 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
@ -30,7 +30,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
global.Integer = global.BigInt;
|
||||
global.Float = global.BigFloat;
|
||||
global.algebraicMode = true;
|
||||
|
||||
|
||||
/* add non enumerable properties */
|
||||
function add_props(obj, props) {
|
||||
var i, val, prop, tab, desc;
|
||||
|
@ -85,9 +85,9 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
}
|
||||
}
|
||||
proto[Symbol.operatorSet] =
|
||||
Operators.create.call(null, ...new_op_list);
|
||||
Operators.create.call(null, ...new_op_list);
|
||||
}
|
||||
|
||||
|
||||
/* Integer */
|
||||
|
||||
function generic_pow(a, b) {
|
||||
|
@ -121,7 +121,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
var small_primes = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499 ];
|
||||
|
||||
function miller_rabin_test(n, t) {
|
||||
|
@ -184,7 +184,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
add_props(Integer, {
|
||||
isInteger(a) {
|
||||
/* integers are represented either as bigint or as number */
|
||||
|
@ -305,7 +305,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
r.push(-1);
|
||||
n = -n;
|
||||
}
|
||||
|
||||
|
||||
while ((n % 2) == 0) {
|
||||
n >>= 1;
|
||||
r.push(2);
|
||||
|
@ -394,7 +394,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
a = Integer.tdiv(a, d);
|
||||
b = Integer.tdiv(b, d);
|
||||
}
|
||||
|
||||
|
||||
/* the fractions are normalized with den > 0 */
|
||||
if (b < 0) {
|
||||
a = -a;
|
||||
|
@ -476,7 +476,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
else
|
||||
return a < b;
|
||||
}
|
||||
|
||||
|
||||
operators_set(Fraction.prototype,
|
||||
{
|
||||
"+": fraction_add,
|
||||
|
@ -518,7 +518,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
"==": float_eq,
|
||||
"<": float_lt,
|
||||
});
|
||||
|
||||
|
||||
add_props(Fraction, {
|
||||
/* (internal use) simplify 'a' to an integer when possible */
|
||||
toFraction(a, b) {
|
||||
|
@ -602,11 +602,11 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/* Float */
|
||||
|
||||
var const_tab = [];
|
||||
|
||||
|
||||
/* we cache the constants for small precisions */
|
||||
function get_const(n) {
|
||||
var t, c, p;
|
||||
|
@ -631,7 +631,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
add_props(Float, {
|
||||
isFloat(a) {
|
||||
return typeof a === "number" || typeof a === "bigfloat";
|
||||
|
@ -700,9 +700,9 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/* Complex */
|
||||
|
||||
|
||||
Complex = function Complex(re, im)
|
||||
{
|
||||
var obj;
|
||||
|
@ -719,7 +719,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
return obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function complex_add(a, b) {
|
||||
a = Complex(a);
|
||||
b = Complex(b);
|
||||
|
@ -746,7 +746,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
b = Complex(b);
|
||||
return a.re == b.re && a.im == b.im;
|
||||
}
|
||||
|
||||
|
||||
operators_set(Complex.prototype,
|
||||
{
|
||||
"+": complex_add,
|
||||
|
@ -772,7 +772,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
"**": generic_pow,
|
||||
"==": complex_eq,
|
||||
});
|
||||
|
||||
|
||||
add_props(Complex, {
|
||||
/* simplify to real number when possible */
|
||||
toComplex(re, im) {
|
||||
|
@ -851,7 +851,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
obj.mod = m;
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
function mod_add(a, b) {
|
||||
if (!(a instanceof Mod)) {
|
||||
return Mod(a + b.res, b.mod);
|
||||
|
@ -947,7 +947,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Polynomial = function Polynomial(a)
|
||||
{
|
||||
if (new.target)
|
||||
|
@ -1017,7 +1017,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
/* trivial zero */
|
||||
if (p[0] == 0)
|
||||
return 0.0;
|
||||
|
||||
|
||||
p1 = p.deriv();
|
||||
p2 = p1.deriv();
|
||||
el = 0.0;
|
||||
|
@ -1041,7 +1041,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
}
|
||||
el = e;
|
||||
zl = z;
|
||||
|
||||
|
||||
z1 = p1.apply(z);
|
||||
z2 = p2.apply(z);
|
||||
t0 = (d - 1) * z1;
|
||||
|
@ -1052,7 +1052,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
d2 = z1 - t0;
|
||||
if (norm2(d2) > norm2(d1))
|
||||
d1 = d2;
|
||||
if (d1 == 0)
|
||||
if (d1 == 0)
|
||||
return null;
|
||||
z = z - d * z0 / d1;
|
||||
}
|
||||
|
@ -1274,7 +1274,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
"/": polynomial_div_scalar,
|
||||
"**": generic_pow, /* XXX: only for integer */
|
||||
});
|
||||
|
||||
|
||||
add_props(Polynomial, {
|
||||
divrem(a, b) {
|
||||
var n1, n2, i, j, q, r, n, c;
|
||||
|
@ -1437,7 +1437,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
});
|
||||
|
||||
/* Rational function */
|
||||
|
||||
|
||||
RationalFunction = function RationalFunction(a, b)
|
||||
{
|
||||
var t, r, d, obj;
|
||||
|
@ -1538,7 +1538,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
"/": ratfunc_div,
|
||||
"**": generic_pow, /* should only be used with integers */
|
||||
});
|
||||
|
||||
|
||||
add_props(RationalFunction, {
|
||||
/* This function always return a RationalFunction object even
|
||||
if it could simplified to a polynomial, so it is not
|
||||
|
@ -1555,7 +1555,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/* Power series */
|
||||
|
||||
/* 'a' is an array */
|
||||
|
@ -1574,11 +1574,11 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
return polynomial_is_scalar(a) ||
|
||||
(a instanceof Polynomial);
|
||||
}
|
||||
|
||||
|
||||
/* n is the maximum number of terms if 'a' is not a serie */
|
||||
Series = function Series(a, n) {
|
||||
var emin, r, i;
|
||||
|
||||
|
||||
if (a instanceof Series) {
|
||||
return a;
|
||||
} else if (series_is_scalar_or_polynomial(a)) {
|
||||
|
@ -1897,7 +1897,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
return Series.zero(0, n);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/* Array (Matrix) */
|
||||
|
||||
Matrix = function Matrix(h, w) {
|
||||
|
@ -2002,7 +2002,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
},
|
||||
det(a) {
|
||||
var n, i, j, k, s, src, v, c;
|
||||
|
||||
|
||||
n = Matrix.check_square(a);
|
||||
s = 1;
|
||||
src = a.dup();
|
||||
|
@ -2061,7 +2061,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
src[i][k] *= c;
|
||||
dst[i][k] *= c;
|
||||
}
|
||||
|
||||
|
||||
for(j = 0; j < n; j++) {
|
||||
if (j != i) {
|
||||
c = src[j][i];
|
||||
|
@ -2078,7 +2078,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
},
|
||||
rank(a) {
|
||||
var src, i, j, k, w, h, l, c;
|
||||
|
||||
|
||||
if (!Array.isArray(a) ||
|
||||
!Array.isArray(a[0]))
|
||||
throw TypeError("matrix expected");
|
||||
|
@ -2101,12 +2101,12 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
src[l][k] = v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
c = src[l][i].inverse();
|
||||
for(k = 0; k < w; k++) {
|
||||
src[l][k] *= c;
|
||||
}
|
||||
|
||||
|
||||
for(j = l + 1; j < h; j++) {
|
||||
c = src[j][i];
|
||||
for(k = i; k < w; k++) {
|
||||
|
@ -2119,7 +2119,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
},
|
||||
ker(a) {
|
||||
var src, i, j, k, w, h, l, m, r, im_cols, ker_dim, c;
|
||||
|
||||
|
||||
if (!Array.isArray(a) ||
|
||||
!Array.isArray(a[0]))
|
||||
throw TypeError("matrix expected");
|
||||
|
@ -2145,12 +2145,12 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
|
|||
src[l][k] = v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
c = src[l][i].inverse();
|
||||
for(k = 0; k < w; k++) {
|
||||
src[l][k] *= c;
|
||||
}
|
||||
|
||||
|
||||
for(j = 0; j < h; j++) {
|
||||
if (j != l) {
|
||||
c = src[j][i];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* QuickJS atom definitions
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
* Copyright (c) 2017-2018 Charlie Gordon
|
||||
*
|
||||
|
@ -204,7 +204,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")
|
||||
|
@ -269,5 +269,5 @@ DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
|
|||
#ifdef CONFIG_BIGNUM
|
||||
DEF(Symbol_operatorSet, "Symbol.operatorSet")
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* DEF */
|
||||
|
|
449
quickjs-libc.c
449
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
|
||||
*
|
||||
|
@ -165,7 +165,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 +173,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)
|
||||
|
@ -263,7 +263,7 @@ DEF( mul_pow10, 1, 2, 1, none)
|
|||
DEF( math_mod, 1, 2, 1, none)
|
||||
#endif
|
||||
/* must be the last non short and non temporary opcode */
|
||||
DEF( nop, 1, 0, 0, none)
|
||||
DEF( nop, 1, 0, 0, none)
|
||||
|
||||
/* temporary opcodes: never emitted in the final bytecode */
|
||||
|
||||
|
@ -289,7 +289,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
|
||||
|
|
56
quickjs.h
56
quickjs.h
|
@ -126,7 +126,7 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(JS_NAN_BOXING)
|
||||
|
||||
typedef uint64_t JSValue;
|
||||
|
@ -191,7 +191,7 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
|||
tag = JS_VALUE_GET_TAG(v);
|
||||
return tag == (JS_NAN >> 32);
|
||||
}
|
||||
|
||||
|
||||
#else /* !JS_NAN_BOXING */
|
||||
|
||||
typedef union JSValueUnion {
|
||||
|
@ -309,7 +309,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);
|
||||
|
@ -499,7 +499,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 +550,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)
|
||||
|
@ -633,6 +634,7 @@ static inline JS_BOOL JS_IsObject(JSValueConst v)
|
|||
JSValue JS_Throw(JSContext *ctx, JSValue obj);
|
||||
JSValue JS_GetException(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 +683,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)
|
||||
|
@ -723,6 +729,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);
|
||||
|
@ -821,6 +829,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,
|
||||
|
@ -876,6 +901,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 +994,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 */
|
||||
|
|
1
readme.txt
Normal file
1
readme.txt
Normal file
|
@ -0,0 +1 @@
|
|||
The main documentation is in doc/quickjs.pdf or doc/quickjs.html.
|
32
release.sh
32
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 cosmo_binary quickjs"
|
||||
|
||||
echo "release_list: extras binary win_binary quickjs"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
release_list="extras binary win_binary cosmo_binary quickjs"
|
||||
release_list="extras binary win_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
|
||||
|
@ -82,28 +82,6 @@ cp $dlldir/libwinpthread-1.dll $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 . )
|
||||
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
|
@ -173,7 +151,7 @@ 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} )
|
||||
|
||||
|
|
146
repl.js
146
repl.js
|
@ -1,7 +1,6 @@
|
|||
/*
|
||||
* QuickJS Read Eval Print Loop
|
||||
*
|
||||
* Copyright (c) 2024 Sneed Group
|
||||
*
|
||||
* Copyright (c) 2017-2020 Fabrice Bellard
|
||||
* Copyright (c) 2017-2020 Charlie Gordon
|
||||
*
|
||||
|
@ -32,7 +31,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;
|
||||
|
@ -46,7 +45,7 @@ import * as os from "os";
|
|||
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",
|
||||
|
@ -68,60 +67,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 = "donejs > ";
|
||||
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 = "";
|
||||
|
@ -139,12 +116,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)) {
|
||||
|
@ -171,14 +148,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);
|
||||
|
@ -196,12 +173,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');
|
||||
}
|
||||
|
@ -233,7 +210,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 "()":
|
||||
|
@ -272,7 +249,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;
|
||||
}
|
||||
}
|
||||
|
@ -400,7 +377,7 @@ import * as os from "os";
|
|||
|
||||
function backward_word() {
|
||||
cursor_pos = skip_word_backward(cursor_pos);
|
||||
}
|
||||
}
|
||||
|
||||
function accept_line() {
|
||||
std.puts("\n");
|
||||
|
@ -578,7 +555,7 @@ import * as os from "os";
|
|||
readline_print_prompt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function reset() {
|
||||
cmd = "";
|
||||
cursor_pos = 0;
|
||||
|
@ -614,6 +591,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;
|
||||
|
@ -732,7 +712,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 */
|
||||
|
@ -808,9 +788,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;
|
||||
|
@ -895,7 +875,7 @@ import * as os from "os";
|
|||
} else {
|
||||
alert(); /* beep! */
|
||||
}
|
||||
|
||||
|
||||
cursor_pos = (cursor_pos < 0) ? 0 :
|
||||
(cursor_pos > cmd.length) ? cmd.length : cursor_pos;
|
||||
update();
|
||||
|
@ -993,19 +973,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 (a instanceof Date) {
|
||||
std.puts("Date " + a.toGMTString().__quote());
|
||||
} else if (has_jscalc && (a instanceof Fraction ||
|
||||
a instanceof Complex ||
|
||||
a instanceof Mod ||
|
||||
|
@ -1073,7 +1055,7 @@ import * as os from "os";
|
|||
}
|
||||
print_rec(a);
|
||||
}
|
||||
|
||||
|
||||
function extract_directive(a) {
|
||||
var pos;
|
||||
if (a[0] !== '\\')
|
||||
|
@ -1088,7 +1070,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") {
|
||||
|
@ -1180,6 +1162,23 @@ import * as os from "os";
|
|||
}
|
||||
|
||||
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',
|
||||
};
|
||||
|
||||
ps1 = "> ";
|
||||
|
||||
/* called by the GUI */
|
||||
g.execCmd = function (cmd) {
|
||||
switch(cmd) {
|
||||
|
@ -1198,7 +1197,7 @@ import * as os from "os";
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function help() {
|
||||
function sel(n) {
|
||||
return n ? "*": " ";
|
||||
|
@ -1227,9 +1226,9 @@ import * as os from "os";
|
|||
function cmd_start() {
|
||||
if (!config_numcalc) {
|
||||
if (has_jscalc)
|
||||
std.puts('QJSCalc (DoneJS Edition) - Type "\\h" for help\n');
|
||||
std.puts('QJSCalc - Type "\\h" for help\n');
|
||||
else
|
||||
std.puts('QuickJS (DoneJS Edition) - Type "\\h" for help\n');
|
||||
std.puts('QuickJS - Type "\\h" for help\n');
|
||||
}
|
||||
if (has_bignum) {
|
||||
log2_10 = Math.log(10) / Math.log(2);
|
||||
|
@ -1248,7 +1247,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();
|
||||
|
@ -1258,7 +1257,7 @@ import * as os from "os";
|
|||
/* return true if async termination */
|
||||
function handle_cmd(expr) {
|
||||
var colorstate, cmd;
|
||||
|
||||
|
||||
if (expr === null) {
|
||||
expr = "";
|
||||
return false;
|
||||
|
@ -1276,7 +1275,7 @@ import * as os from "os";
|
|||
}
|
||||
if (expr === "")
|
||||
return false;
|
||||
|
||||
|
||||
if (mexpr)
|
||||
expr = mexpr + '\n' + expr;
|
||||
colorstate = colorize_js(expr);
|
||||
|
@ -1287,7 +1286,7 @@ 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),
|
||||
|
@ -1300,7 +1299,7 @@ import * as os from "os";
|
|||
|
||||
function eval_and_print_start(expr, is_async) {
|
||||
var result;
|
||||
|
||||
|
||||
try {
|
||||
if (eval_mode === "math")
|
||||
expr = '"use math"; void 0;' + expr;
|
||||
|
@ -1311,7 +1310,7 @@ import * as os from "os";
|
|||
/* result is a promise */
|
||||
result.then(print_eval_result, print_eval_error);
|
||||
} else {
|
||||
print_eval_result(result);
|
||||
print_eval_result({ value: result });
|
||||
}
|
||||
} catch (error) {
|
||||
print_eval_error(error);
|
||||
|
@ -1319,6 +1318,7 @@ import * as os from "os";
|
|||
}
|
||||
|
||||
function print_eval_result(result) {
|
||||
result = result.value;
|
||||
eval_time = os.now() - eval_start_time;
|
||||
std.puts(colors[styles.result]);
|
||||
print(result);
|
||||
|
@ -1342,7 +1342,7 @@ import * as os from "os";
|
|||
console.log(error);
|
||||
}
|
||||
std.puts(colors.none);
|
||||
|
||||
|
||||
handle_cmd_end();
|
||||
}
|
||||
|
||||
|
@ -1585,7 +1585,7 @@ import * as os from "os";
|
|||
}
|
||||
|
||||
termInit();
|
||||
|
||||
|
||||
cmd_start();
|
||||
|
||||
})(globalThis);
|
||||
|
|
181
run-test262.c
181
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);
|
||||
|
@ -753,7 +761,7 @@ static JSValue add_helpers1(JSContext *ctx)
|
|||
{
|
||||
JSValue global_obj;
|
||||
JSValue obj262, obj;
|
||||
|
||||
|
||||
global_obj = JS_GetGlobalObject(ctx);
|
||||
|
||||
JS_SetPropertyStr(ctx, global_obj, "print",
|
||||
|
@ -784,7 +792,7 @@ static JSValue add_helpers1(JSContext *ctx)
|
|||
JS_SetPropertyStr(ctx, obj262, "IsHTMLDDA", obj);
|
||||
|
||||
JS_SetPropertyStr(ctx, global_obj, "$262", JS_DupValue(ctx, obj262));
|
||||
|
||||
|
||||
JS_FreeValue(ctx, global_obj);
|
||||
return obj262;
|
||||
}
|
||||
|
@ -813,14 +821,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 +931,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 +950,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 +986,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 +1027,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 +1168,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 +1201,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 +1211,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 +1264,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 +1273,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 +1294,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 +1418,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 +1550,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,10 +1563,10 @@ 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++) {
|
||||
|
@ -1554,7 +1579,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 +1612,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 +1681,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 +1848,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 +1864,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 +1925,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 +1996,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 +2024,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 +2066,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 +2099,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 +2126,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 +2164,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 +2194,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 +2211,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;
|
||||
}
|
||||
|
|
5
test.js
5
test.js
|
@ -1,5 +0,0 @@
|
|||
function test() {
|
||||
breakFunction();
|
||||
console.warn("lol it works!");
|
||||
}
|
||||
test()
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
import * as std from "std";
|
||||
import * as os from "os";
|
||||
|
||||
if (typeof require !== 'undefined') {
|
||||
var fs = require('fs');
|
||||
}
|
||||
|
||||
function pad(str, n) {
|
||||
str += "";
|
||||
|
@ -61,21 +63,17 @@ function toPrec(n, prec) {
|
|||
s = s.substring(0, i) + "." + s.substring(i);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
var ref_data;
|
||||
var log_data;
|
||||
|
||||
var heads = [ "TEST", "N", "TIME (ns)", "REF (ns)", "SCORE (%)" ];
|
||||
var heads = [ "TEST", "N", "TIME (ns)", "REF (ns)", "SCORE (1000)" ];
|
||||
var widths = [ 22, 10, 9, 9, 9 ];
|
||||
var precs = [ 0, 0, 2, 2, 2 ];
|
||||
var precs = [ 0, 0, 2, 2, 0 ];
|
||||
var total = [ 0, 0, 0, 0, 0 ];
|
||||
var total_score = 0;
|
||||
var total_scale = 0;
|
||||
|
||||
if (typeof console == "undefined") {
|
||||
var console = { log: print };
|
||||
}
|
||||
|
||||
function log_line() {
|
||||
var i, n, s, a;
|
||||
s = "";
|
||||
|
@ -83,7 +81,7 @@ function log_line() {
|
|||
if (i > 0)
|
||||
s += " ";
|
||||
a = arguments[i];
|
||||
if (typeof a == "number") {
|
||||
if (typeof a === "number") {
|
||||
total[i] += a;
|
||||
a = toPrec(a, precs[i]);
|
||||
s += pad_left(a, widths[i]);
|
||||
|
@ -95,11 +93,28 @@ function log_line() {
|
|||
}
|
||||
|
||||
var clocks_per_sec = 1000;
|
||||
var max_iterations = 10;
|
||||
var clock_threshold = 100; /* favoring short measuring spans */
|
||||
var max_iterations = 100;
|
||||
var clock_threshold = 2; /* favoring short measuring spans */
|
||||
var min_n_argument = 1;
|
||||
//var get_clock = Date.now;
|
||||
var get_clock = os.now;
|
||||
var get_clock;
|
||||
if (typeof performance !== "undefined") {
|
||||
// use more precise clock on NodeJS
|
||||
// need a method call on performance object
|
||||
get_clock = () => performance.now();
|
||||
} else
|
||||
if (typeof os !== "undefined") {
|
||||
// use more precise clock on QuickJS
|
||||
get_clock = os.now;
|
||||
} else {
|
||||
// use Date.now and round up to the next millisecond
|
||||
get_clock = () => {
|
||||
var t0 = Date.now();
|
||||
var t;
|
||||
while ((t = Date.now()) == t0)
|
||||
continue;
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
function log_one(text, n, ti) {
|
||||
var ref;
|
||||
|
@ -112,7 +127,7 @@ function log_one(text, n, ti) {
|
|||
ti = Math.round(ti * 100) / 100;
|
||||
log_data[text] = ti;
|
||||
if (typeof ref === "number") {
|
||||
log_line(text, n, ti, ref, ti * 100 / ref);
|
||||
log_line(text, n, ti, ref, Math.round(ref * 1000 / ti));
|
||||
total_score += ti * 100 / ref;
|
||||
total_scale += 100;
|
||||
} else {
|
||||
|
@ -124,28 +139,27 @@ function log_one(text, n, ti) {
|
|||
|
||||
function bench(f, text)
|
||||
{
|
||||
var i, j, n, t, t1, ti, nb_its, ref, ti_n, ti_n1, min_ti;
|
||||
var i, j, n, t, ti, nb_its, ref, ti_n, ti_n1;
|
||||
|
||||
nb_its = n = 1;
|
||||
if (f.bench) {
|
||||
ti_n = f(text);
|
||||
} else {
|
||||
// measure ti_n: the shortest time for an individual operation
|
||||
ti_n = 1000000000;
|
||||
min_ti = clock_threshold / 10;
|
||||
for(i = 0; i < 30; i++) {
|
||||
// measure ti: the shortest time for max_iterations iterations
|
||||
ti = 1000000000;
|
||||
for (j = 0; j < max_iterations; j++) {
|
||||
t = get_clock();
|
||||
while ((t1 = get_clock()) == t)
|
||||
continue;
|
||||
nb_its = f(n);
|
||||
t = get_clock() - t;
|
||||
if (nb_its < 0)
|
||||
return; // test failure
|
||||
t1 = get_clock() - t1;
|
||||
if (ti > t1)
|
||||
ti = t1;
|
||||
if (ti > t)
|
||||
ti = t;
|
||||
}
|
||||
if (ti >= min_ti) {
|
||||
if (ti >= clock_threshold / 10) {
|
||||
ti_n1 = ti / nb_its;
|
||||
if (ti_n > ti_n1)
|
||||
ti_n = ti_n1;
|
||||
|
@ -171,6 +185,26 @@ function empty_loop(n) {
|
|||
return n;
|
||||
}
|
||||
|
||||
function empty_down_loop(n) {
|
||||
var j;
|
||||
for(j = n; j > 0; j--) {
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
function empty_down_loop2(n) {
|
||||
var j;
|
||||
for(j = n; j --> 0;) {
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
function empty_do_loop(n) {
|
||||
var j = n;
|
||||
do { } while (--j > 0);
|
||||
return n;
|
||||
}
|
||||
|
||||
function date_now(n) {
|
||||
var j;
|
||||
for(j = 0; j < n; j++) {
|
||||
|
@ -179,6 +213,32 @@ function date_now(n) {
|
|||
return n;
|
||||
}
|
||||
|
||||
function date_parse(n) {
|
||||
var x0 = 0, dx = 0;
|
||||
var j;
|
||||
for(j = 0; j < n; j++) {
|
||||
var x1 = x0 - x0 % 1000;
|
||||
var x2 = -x0;
|
||||
var x3 = -x1;
|
||||
var d0 = new Date(x0);
|
||||
var d1 = new Date(x1);
|
||||
var d2 = new Date(x2);
|
||||
var d3 = new Date(x3);
|
||||
if (Date.parse(d0.toISOString()) != x0
|
||||
|| Date.parse(d1.toGMTString()) != x1
|
||||
|| Date.parse(d1.toString()) != x1
|
||||
|| Date.parse(d2.toISOString()) != x2
|
||||
|| Date.parse(d3.toGMTString()) != x3
|
||||
|| Date.parse(d3.toString()) != x3) {
|
||||
console.log("Date.parse error for " + x0);
|
||||
return -1;
|
||||
}
|
||||
dx = (dx * 1.1 + 1) >> 0;
|
||||
x0 = (x0 + dx) % 8.64e15;
|
||||
}
|
||||
return n * 6;
|
||||
}
|
||||
|
||||
function prop_read(n)
|
||||
{
|
||||
var obj, sum, j;
|
||||
|
@ -207,30 +267,78 @@ function prop_write(n)
|
|||
return n * 4;
|
||||
}
|
||||
|
||||
function prop_create(n)
|
||||
function prop_update(n)
|
||||
{
|
||||
var obj, j;
|
||||
obj = {a: 1, b: 2, c:3, d:4 };
|
||||
for(j = 0; j < n; j++) {
|
||||
obj = new Object();
|
||||
obj.a = 1;
|
||||
obj.b = 2;
|
||||
obj.c = 3;
|
||||
obj.d = 4;
|
||||
obj.a += j;
|
||||
obj.b += j;
|
||||
obj.c += j;
|
||||
obj.d += j;
|
||||
}
|
||||
return n * 4;
|
||||
}
|
||||
|
||||
function prop_create(n)
|
||||
{
|
||||
var obj, i, j;
|
||||
for(j = 0; j < n; j++) {
|
||||
obj = {};
|
||||
obj.a = 1;
|
||||
obj.b = 2;
|
||||
obj.c = 3;
|
||||
obj.d = 4;
|
||||
obj.e = 5;
|
||||
obj.f = 6;
|
||||
obj.g = 7;
|
||||
obj.h = 8;
|
||||
obj.i = 9;
|
||||
obj.j = 10;
|
||||
for(i = 0; i < 10; i++) {
|
||||
obj[i] = i;
|
||||
}
|
||||
}
|
||||
return n * 20;
|
||||
}
|
||||
|
||||
function prop_clone(n)
|
||||
{
|
||||
var ref, obj, j, k;
|
||||
ref = { a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10 };
|
||||
for(k = 0; k < 10; k++) {
|
||||
ref[k] = k;
|
||||
}
|
||||
for (j = 0; j < n; j++) {
|
||||
global_res = { ...ref };
|
||||
}
|
||||
return n * 20;
|
||||
}
|
||||
|
||||
function prop_delete(n)
|
||||
{
|
||||
var obj, j;
|
||||
obj = {};
|
||||
for(j = 0; j < n; j++) {
|
||||
obj[j] = 1;
|
||||
var ref, obj, j, k;
|
||||
ref = { a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10 };
|
||||
for(k = 0; k < 10; k++) {
|
||||
ref[k] = k;
|
||||
}
|
||||
for(j = 0; j < n; j++) {
|
||||
delete obj[j];
|
||||
for (j = 0; j < n; j++) {
|
||||
obj = { ...ref };
|
||||
delete obj.a;
|
||||
delete obj.b;
|
||||
delete obj.c;
|
||||
delete obj.d;
|
||||
delete obj.e;
|
||||
delete obj.f;
|
||||
delete obj.g;
|
||||
delete obj.h;
|
||||
delete obj.i;
|
||||
delete obj.j;
|
||||
for(k = 0; k < 10; k++) {
|
||||
delete obj[k];
|
||||
}
|
||||
}
|
||||
return n;
|
||||
return n * 20;
|
||||
}
|
||||
|
||||
function array_read(n)
|
||||
|
@ -291,15 +399,32 @@ function array_prop_create(n)
|
|||
return len * n;
|
||||
}
|
||||
|
||||
function array_slice(n)
|
||||
{
|
||||
var ref, a, i, j, len;
|
||||
len = 1000;
|
||||
ref = [];
|
||||
for(i = 0; i < len; i++)
|
||||
ref[i] = i;
|
||||
for(j = 0; j < n; j++) {
|
||||
ref[0] = j;
|
||||
a = ref.slice();
|
||||
a[0] = 0;
|
||||
global_res = a;
|
||||
}
|
||||
return len * n;
|
||||
}
|
||||
|
||||
function array_length_decr(n)
|
||||
{
|
||||
var tab, i, j, len;
|
||||
var tab, ref, i, j, len;
|
||||
len = 1000;
|
||||
tab = [];
|
||||
ref = [];
|
||||
for(i = 0; i < len; i++)
|
||||
tab[i] = i;
|
||||
ref[i] = i;
|
||||
for(j = 0; j < n; j++) {
|
||||
for(i = len - 1; i >= 0; i--)
|
||||
tab = ref.slice();
|
||||
for(i = len; i --> 0;)
|
||||
tab.length = i;
|
||||
}
|
||||
return len * n;
|
||||
|
@ -307,15 +432,16 @@ function array_length_decr(n)
|
|||
|
||||
function array_hole_length_decr(n)
|
||||
{
|
||||
var tab, i, j, len;
|
||||
var tab, ref, i, j, len;
|
||||
len = 1000;
|
||||
tab = [];
|
||||
ref = [];
|
||||
for(i = 0; i < len; i++) {
|
||||
if (i != 3)
|
||||
tab[i] = i;
|
||||
if (i % 10 == 9)
|
||||
ref[i] = i;
|
||||
}
|
||||
for(j = 0; j < n; j++) {
|
||||
for(i = len - 1; i >= 0; i--)
|
||||
tab = ref.slice();
|
||||
for(i = len; i --> 0;)
|
||||
tab.length = i;
|
||||
}
|
||||
return len * n;
|
||||
|
@ -335,12 +461,13 @@ function array_push(n)
|
|||
|
||||
function array_pop(n)
|
||||
{
|
||||
var tab, i, j, len, sum;
|
||||
var tab, ref, i, j, len, sum;
|
||||
len = 500;
|
||||
ref = [];
|
||||
for(i = 0; i < len; i++)
|
||||
ref[i] = i;
|
||||
for(j = 0; j < n; j++) {
|
||||
tab = [];
|
||||
for(i = 0; i < len; i++)
|
||||
tab[i] = i;
|
||||
tab = ref.slice();
|
||||
sum = 0;
|
||||
for(i = 0; i < len; i++)
|
||||
sum += tab.pop();
|
||||
|
@ -412,6 +539,7 @@ function global_read(n)
|
|||
return n * 4;
|
||||
}
|
||||
|
||||
// non strict version
|
||||
var global_write =
|
||||
(1, eval)(`(function global_write(n)
|
||||
{
|
||||
|
@ -454,6 +582,7 @@ function local_destruct(n)
|
|||
var global_v1, global_v2, global_v3, global_v4;
|
||||
var global_a, global_b, global_c, global_d;
|
||||
|
||||
// non strict version
|
||||
var global_destruct =
|
||||
(1, eval)(`(function global_destruct(n)
|
||||
{
|
||||
|
@ -481,6 +610,25 @@ function global_destruct_strict(n)
|
|||
return n * 8;
|
||||
}
|
||||
|
||||
function g(a)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
function global_func_call(n)
|
||||
{
|
||||
var j, sum;
|
||||
sum = 0;
|
||||
for(j = 0; j < n; j++) {
|
||||
sum += g(j);
|
||||
sum += g(j);
|
||||
sum += g(j);
|
||||
sum += g(j);
|
||||
}
|
||||
global_res = sum;
|
||||
return n * 4;
|
||||
}
|
||||
|
||||
function func_call(n)
|
||||
{
|
||||
function f(a)
|
||||
|
@ -500,7 +648,7 @@ function func_call(n)
|
|||
return n * 4;
|
||||
}
|
||||
|
||||
function closure_var(n)
|
||||
function func_closure_call(n)
|
||||
{
|
||||
function f(a)
|
||||
{
|
||||
|
@ -605,8 +753,8 @@ function bigint256_arith(n)
|
|||
function set_collection_add(n)
|
||||
{
|
||||
var s, i, j, len = 100;
|
||||
s = new Set();
|
||||
for(j = 0; j < n; j++) {
|
||||
s = new Set();
|
||||
for(i = 0; i < len; i++) {
|
||||
s.add(String(i), i);
|
||||
}
|
||||
|
@ -620,25 +768,25 @@ function set_collection_add(n)
|
|||
|
||||
function array_for(n)
|
||||
{
|
||||
var r, i, j, sum;
|
||||
var r, i, j, sum, len = 100;
|
||||
r = [];
|
||||
for(i = 0; i < 100; i++)
|
||||
for(i = 0; i < len; i++)
|
||||
r[i] = i;
|
||||
for(j = 0; j < n; j++) {
|
||||
sum = 0;
|
||||
for(i = 0; i < 100; i++) {
|
||||
for(i = 0; i < len; i++) {
|
||||
sum += r[i];
|
||||
}
|
||||
global_res = sum;
|
||||
}
|
||||
return n * 100;
|
||||
return n * len;
|
||||
}
|
||||
|
||||
function array_for_in(n)
|
||||
{
|
||||
var r, i, j, sum;
|
||||
var r, i, j, sum, len = 100;
|
||||
r = [];
|
||||
for(i = 0; i < 100; i++)
|
||||
for(i = 0; i < len; i++)
|
||||
r[i] = i;
|
||||
for(j = 0; j < n; j++) {
|
||||
sum = 0;
|
||||
|
@ -647,14 +795,14 @@ function array_for_in(n)
|
|||
}
|
||||
global_res = sum;
|
||||
}
|
||||
return n * 100;
|
||||
return n * len;
|
||||
}
|
||||
|
||||
function array_for_of(n)
|
||||
{
|
||||
var r, i, j, sum;
|
||||
var r, i, j, sum, len = 100;
|
||||
r = [];
|
||||
for(i = 0; i < 100; i++)
|
||||
for(i = 0; i < len; i++)
|
||||
r[i] = i;
|
||||
for(j = 0; j < n; j++) {
|
||||
sum = 0;
|
||||
|
@ -663,7 +811,7 @@ function array_for_of(n)
|
|||
}
|
||||
global_res = sum;
|
||||
}
|
||||
return n * 100;
|
||||
return n * len;
|
||||
}
|
||||
|
||||
function math_min(n)
|
||||
|
@ -678,58 +826,108 @@ function math_min(n)
|
|||
return n * 1000;
|
||||
}
|
||||
|
||||
function regexp_ascii(n)
|
||||
{
|
||||
var i, j, r, s;
|
||||
s = "the quick brown fox jumped over the lazy dog"
|
||||
for(j = 0; j < n; j++) {
|
||||
for(i = 0; i < 1000; i++)
|
||||
r = /the quick brown fox/.exec(s)
|
||||
global_res = r;
|
||||
}
|
||||
return n * 1000;
|
||||
}
|
||||
|
||||
function regexp_utf16(n)
|
||||
{
|
||||
var i, j, r, s;
|
||||
s = "the quick brown ᶠᵒˣ jumped over the lazy ᵈᵒᵍ"
|
||||
for(j = 0; j < n; j++) {
|
||||
for(i = 0; i < 1000; i++)
|
||||
r = /the quick brown ᶠᵒˣ/.exec(s)
|
||||
global_res = r;
|
||||
}
|
||||
return n * 1000;
|
||||
}
|
||||
|
||||
/* incremental string contruction as local var */
|
||||
function string_build1(n)
|
||||
{
|
||||
var i, j, r;
|
||||
r = "";
|
||||
for(j = 0; j < n; j++) {
|
||||
for(i = 0; i < 100; i++)
|
||||
r = "";
|
||||
for(i = 0; i < 1000; i++)
|
||||
r += "x";
|
||||
global_res = r;
|
||||
}
|
||||
return n * 100;
|
||||
return n * 1000;
|
||||
}
|
||||
|
||||
/* incremental string contruction using + */
|
||||
function string_build1x(n)
|
||||
{
|
||||
var i, j, r;
|
||||
for(j = 0; j < n; j++) {
|
||||
r = "";
|
||||
for(i = 0; i < 1000; i++)
|
||||
r = r + "x";
|
||||
global_res = r;
|
||||
}
|
||||
return n * 1000;
|
||||
}
|
||||
|
||||
/* incremental string contruction using +2c */
|
||||
function string_build2c(n)
|
||||
{
|
||||
var i, j;
|
||||
for(j = 0; j < n; j++) {
|
||||
var r = "";
|
||||
for(i = 0; i < 1000; i++)
|
||||
r += "xy";
|
||||
global_res = r;
|
||||
}
|
||||
return n * 1000;
|
||||
}
|
||||
|
||||
/* incremental string contruction as arg */
|
||||
function string_build2(n, r)
|
||||
{
|
||||
var i, j;
|
||||
r = "";
|
||||
for(j = 0; j < n; j++) {
|
||||
for(i = 0; i < 100; i++)
|
||||
r = "";
|
||||
for(i = 0; i < 1000; i++)
|
||||
r += "x";
|
||||
global_res = r;
|
||||
}
|
||||
return n * 100;
|
||||
return n * 1000;
|
||||
}
|
||||
|
||||
/* incremental string contruction by prepending */
|
||||
function string_build3(n, r)
|
||||
function string_build3(n)
|
||||
{
|
||||
var i, j;
|
||||
r = "";
|
||||
var i, j, r;
|
||||
for(j = 0; j < n; j++) {
|
||||
for(i = 0; i < 100; i++)
|
||||
r = "";
|
||||
for(i = 0; i < 1000; i++)
|
||||
r = "x" + r;
|
||||
global_res = r;
|
||||
}
|
||||
return n * 100;
|
||||
return n * 1000;
|
||||
}
|
||||
|
||||
/* incremental string contruction with multiple reference */
|
||||
function string_build4(n)
|
||||
{
|
||||
var i, j, r, s;
|
||||
r = "";
|
||||
for(j = 0; j < n; j++) {
|
||||
for(i = 0; i < 100; i++) {
|
||||
r = "";
|
||||
for(i = 0; i < 1000; i++) {
|
||||
s = r;
|
||||
r += "x";
|
||||
}
|
||||
global_res = r;
|
||||
}
|
||||
return n * 100;
|
||||
return n * 1000;
|
||||
}
|
||||
|
||||
/* sort bench */
|
||||
|
@ -862,32 +1060,33 @@ function sort_bench(text) {
|
|||
": " + arr[i - 1] + " > " + arr[i]);
|
||||
}
|
||||
if (sort_bench.verbose)
|
||||
log_one("sort_" + f.name, n, ti, n * 100);
|
||||
log_one("sort_" + f.name, 1, ti / 100);
|
||||
}
|
||||
total_score = save_total_score;
|
||||
total_scale = save_total_scale;
|
||||
return total / n / 1000;
|
||||
return total / n / 100;
|
||||
}
|
||||
sort_bench.bench = true;
|
||||
sort_bench.verbose = false;
|
||||
|
||||
function int_to_string(n)
|
||||
{
|
||||
var s, r, j;
|
||||
r = 0;
|
||||
var s, j;
|
||||
for(j = 0; j < n; j++) {
|
||||
s = (j + 1).toString();
|
||||
s = (j % 1000).toString();
|
||||
s = (1234000 + j % 1000).toString();
|
||||
}
|
||||
return n;
|
||||
global_res = s;
|
||||
return n * 2;
|
||||
}
|
||||
|
||||
function float_to_string(n)
|
||||
{
|
||||
var s, r, j;
|
||||
r = 0;
|
||||
var s, j;
|
||||
for(j = 0; j < n; j++) {
|
||||
s = (j + 0.1).toString();
|
||||
}
|
||||
global_res = s;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -896,7 +1095,6 @@ function string_to_int(n)
|
|||
var s, r, j;
|
||||
r = 0;
|
||||
s = "12345";
|
||||
r = 0;
|
||||
for(j = 0; j < n; j++) {
|
||||
r += (s | 0);
|
||||
}
|
||||
|
@ -909,7 +1107,6 @@ function string_to_float(n)
|
|||
var s, r, j;
|
||||
r = 0;
|
||||
s = "12345.6";
|
||||
r = 0;
|
||||
for(j = 0; j < n; j++) {
|
||||
r -= s;
|
||||
}
|
||||
|
@ -919,41 +1116,92 @@ function string_to_float(n)
|
|||
|
||||
function load_result(filename)
|
||||
{
|
||||
var f, str, res;
|
||||
if (typeof std === "undefined")
|
||||
var has_filename = filename;
|
||||
var has_error = false;
|
||||
var str, res;
|
||||
|
||||
if (!filename)
|
||||
filename = "microbench.txt";
|
||||
|
||||
if (typeof fs !== "undefined") {
|
||||
// read the file in Node.js
|
||||
try {
|
||||
str = fs.readFileSync(filename, { encoding: "utf8" });
|
||||
} catch {
|
||||
has_error = true;
|
||||
}
|
||||
} else
|
||||
if (typeof std !== "undefined") {
|
||||
// read the file in QuickJS
|
||||
var f = std.open(filename, "r");
|
||||
if (f) {
|
||||
str = f.readAsString();
|
||||
f.close();
|
||||
} else {
|
||||
has_error = true;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
f = std.open(filename, "r");
|
||||
if (!f)
|
||||
}
|
||||
if (has_error) {
|
||||
if (has_filename) {
|
||||
// Should throw exception?
|
||||
console.log("cannot load " + filename);
|
||||
}
|
||||
return null;
|
||||
str = f.readAsString();
|
||||
}
|
||||
res = JSON.parse(str);
|
||||
f.close();
|
||||
return res;
|
||||
}
|
||||
|
||||
function save_result(filename, obj)
|
||||
{
|
||||
var f;
|
||||
if (typeof std === "undefined")
|
||||
var str = JSON.stringify(obj, null, 2) + "\n";
|
||||
var has_error = false;
|
||||
|
||||
if (typeof fs !== "undefined") {
|
||||
// save the file in Node.js
|
||||
try {
|
||||
str = fs.writeFileSync(filename, str, { encoding: "utf8" });
|
||||
} catch {
|
||||
has_error = true;
|
||||
}
|
||||
} else
|
||||
if (typeof std !== "undefined") {
|
||||
// save the file in QuickJS
|
||||
var f = std.open(filename, "w");
|
||||
if (f) {
|
||||
f.puts(str);
|
||||
f.close();
|
||||
} else {
|
||||
has_error = 'true';
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
f = std.open(filename, "w");
|
||||
f.puts(JSON.stringify(obj, null, 2));
|
||||
f.puts("\n");
|
||||
f.close();
|
||||
}
|
||||
if (has_error)
|
||||
console.log("cannot save " + filename);
|
||||
}
|
||||
|
||||
function main(argc, argv, g)
|
||||
{
|
||||
var test_list = [
|
||||
empty_loop,
|
||||
empty_down_loop,
|
||||
empty_down_loop2,
|
||||
empty_do_loop,
|
||||
date_now,
|
||||
date_parse,
|
||||
prop_read,
|
||||
prop_write,
|
||||
prop_update,
|
||||
prop_create,
|
||||
prop_clone,
|
||||
prop_delete,
|
||||
array_read,
|
||||
array_write,
|
||||
array_prop_create,
|
||||
array_slice,
|
||||
array_length_decr,
|
||||
array_hole_length_decr,
|
||||
array_push,
|
||||
|
@ -966,8 +1214,9 @@ function main(argc, argv, g)
|
|||
local_destruct,
|
||||
global_destruct,
|
||||
global_destruct_strict,
|
||||
global_func_call,
|
||||
func_call,
|
||||
closure_var,
|
||||
func_closure_call,
|
||||
int_arith,
|
||||
float_arith,
|
||||
set_collection_add,
|
||||
|
@ -975,29 +1224,34 @@ function main(argc, argv, g)
|
|||
array_for_in,
|
||||
array_for_of,
|
||||
math_min,
|
||||
regexp_ascii,
|
||||
regexp_utf16,
|
||||
string_build1,
|
||||
string_build1x,
|
||||
string_build2c,
|
||||
string_build2,
|
||||
//string_build3,
|
||||
//string_build4,
|
||||
sort_bench,
|
||||
string_build3,
|
||||
string_build4,
|
||||
int_to_string,
|
||||
float_to_string,
|
||||
string_to_int,
|
||||
string_to_float,
|
||||
];
|
||||
var tests = [];
|
||||
var i, j, n, f, name;
|
||||
|
||||
if (typeof BigInt == "function") {
|
||||
var i, j, n, f, name, found;
|
||||
var ref_file, new_ref_file = "microbench-new.txt";
|
||||
|
||||
if (typeof BigInt === "function") {
|
||||
/* BigInt test */
|
||||
test_list.push(bigint64_arith);
|
||||
test_list.push(bigint256_arith);
|
||||
}
|
||||
if (typeof BigFloat == "function") {
|
||||
if (typeof BigFloat === "function") {
|
||||
/* BigFloat test */
|
||||
test_list.push(float256_arith);
|
||||
}
|
||||
|
||||
test_list.push(sort_bench);
|
||||
|
||||
for (i = 1; i < argc;) {
|
||||
name = argv[i++];
|
||||
if (name == "-a") {
|
||||
|
@ -1007,7 +1261,7 @@ function main(argc, argv, g)
|
|||
if (name == "-t") {
|
||||
name = argv[i++];
|
||||
sort_bench.array_type = g[name];
|
||||
if (typeof sort_bench.array_type != "function") {
|
||||
if (typeof sort_bench.array_type !== "function") {
|
||||
console.log("unknown array type: " + name);
|
||||
return 1;
|
||||
}
|
||||
|
@ -1017,14 +1271,22 @@ function main(argc, argv, g)
|
|||
sort_bench.array_size = +argv[i++];
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < test_list.length; j++) {
|
||||
if (name == "-r") {
|
||||
ref_file = argv[i++];
|
||||
continue;
|
||||
}
|
||||
if (name == "-s") {
|
||||
new_ref_file = argv[i++];
|
||||
continue;
|
||||
}
|
||||
for (j = 0, found = false; j < test_list.length; j++) {
|
||||
f = test_list[j];
|
||||
if (name === f.name) {
|
||||
if (f.name.startsWith(name)) {
|
||||
tests.push(f);
|
||||
break;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (j == test_list.length) {
|
||||
if (!found) {
|
||||
console.log("unknown benchmark: " + name);
|
||||
return 1;
|
||||
}
|
||||
|
@ -1032,7 +1294,7 @@ function main(argc, argv, g)
|
|||
if (tests.length == 0)
|
||||
tests = test_list;
|
||||
|
||||
ref_data = load_result("microbench.txt");
|
||||
ref_data = load_result(ref_file);
|
||||
log_data = {};
|
||||
log_line.apply(null, heads);
|
||||
n = 0;
|
||||
|
@ -1044,14 +1306,17 @@ function main(argc, argv, g)
|
|||
n++;
|
||||
}
|
||||
if (ref_data)
|
||||
log_line("total", "", total[2], total[3], total_score * 100 / total_scale);
|
||||
log_line("total", "", total[2], total[3], Math.round(total_scale * 1000 / total_score));
|
||||
else
|
||||
log_line("total", "", total[2]);
|
||||
|
||||
if (tests == test_list)
|
||||
save_result("microbench-new.txt", log_data);
|
||||
|
||||
if (tests == test_list && new_ref_file)
|
||||
save_result(new_ref_file, log_data);
|
||||
}
|
||||
|
||||
if (!scriptArgs)
|
||||
if (typeof scriptArgs === "undefined") {
|
||||
scriptArgs = [];
|
||||
if (typeof process.argv === "object")
|
||||
scriptArgs = process.argv.slice(1);
|
||||
}
|
||||
main(scriptArgs.length, scriptArgs, this);
|
||||
|
|
|
@ -28,7 +28,7 @@ index be7039fda0..7b38abf8df 100644
|
|||
@@ -6,24 +6,27 @@ description: |
|
||||
defines: [buildString, testPropertyEscapes, matchValidator]
|
||||
---*/
|
||||
|
||||
|
||||
+if ($262 && typeof $262.codePointRange === "function") {
|
||||
+ /* use C function to build the codePointRange (much faster with
|
||||
+ slow JS engines) */
|
||||
|
@ -67,5 +67,5 @@ index be7039fda0..7b38abf8df 100644
|
|||
- return result;
|
||||
+ return result;
|
||||
}
|
||||
|
||||
|
||||
function testPropertyEscapes(regex, string, expression) {
|
||||
|
|
279
tests/test_bigfloat.js
Normal file
279
tests/test_bigfloat.js
Normal file
|
@ -0,0 +1,279 @@
|
|||
"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) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
/* 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_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_bigint_ext();
|
||||
test_bigfloat();
|
||||
test_bigdecimal();
|
|
@ -94,7 +94,7 @@ function test_bigint1()
|
|||
|
||||
r = 1n << 31n;
|
||||
assert(r, 2147483648n, "1 << 31n === 2147483648n");
|
||||
|
||||
|
||||
r = 1n << 32n;
|
||||
assert(r, 4294967296n, "1 << 32n === 4294967296n");
|
||||
}
|
||||
|
@ -110,217 +110,5 @@ function test_bigint2()
|
|||
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) ||
|
||||
|
@ -147,7 +147,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]);
|
||||
|
@ -174,7 +174,7 @@ function bjson_test_all()
|
|||
|
||||
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,6 +381,11 @@ function test_number()
|
|||
assert(Number.isNaN(Number("-")));
|
||||
assert(Number.isNaN(Number("\x00a")));
|
||||
|
||||
// TODO: Fix rounding errors on Windows/Cygwin.
|
||||
if (typeof os !== 'undefined' && ['win32', 'cygwin'].includes(os.platform)) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert((25).toExponential(0), "3e+1");
|
||||
assert((-25).toExponential(0), "-3e+1");
|
||||
assert((2.5).toPrecision(1), "3");
|
||||
|
@ -379,7 +429,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 +474,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 +486,7 @@ function test_typed_array()
|
|||
|
||||
a = new Float32Array(buffer, 8, 1);
|
||||
a[0] = 1;
|
||||
|
||||
|
||||
a = new Uint8Array(buffer);
|
||||
|
||||
str = a.toString();
|
||||
|
@ -481,26 +531,105 @@ function test_json()
|
|||
|
||||
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 +654,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");
|
||||
|
||||
|
@ -587,6 +716,20 @@ 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);
|
||||
|
||||
a = new Map();
|
||||
tab = [];
|
||||
for(i = 0; i < n; i++) {
|
||||
|
@ -602,7 +745,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));
|
||||
|
@ -625,7 +768,7 @@ function test_weak_map()
|
|||
a.set(o, v);
|
||||
}
|
||||
o = null;
|
||||
|
||||
|
||||
n2 = n >> 1;
|
||||
for(i = 0; i < n2; i++) {
|
||||
a.delete(tab[i][0]);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -419,9 +427,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 +502,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 +523,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 +570,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 +593,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 }
|
||||
|
@ -604,3 +625,4 @@ test_argument_scope();
|
|||
test_function_expr_name();
|
||||
test_parse_semicolon();
|
||||
test_optional_chaining();
|
||||
test_parse_arrow_function();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -35,7 +35,7 @@ function test_operators_create() {
|
|||
return "Vec2(" + this.x + "," + this.y + ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vec2.prototype[Symbol.operatorSet] = Operators.create(
|
||||
{
|
||||
"+"(p1, p2) {
|
||||
|
@ -172,7 +172,7 @@ function test_operators()
|
|||
return "Vec2(" + this.x + "," + this.y + ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var a = new Vec2(1, 2);
|
||||
var b = new Vec2(3, 4);
|
||||
var r;
|
||||
|
|
|
@ -60,10 +60,10 @@ function test_integer()
|
|||
|
||||
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");
|
||||
|
||||
|
@ -115,7 +115,7 @@ function test_fraction()
|
|||
function test_mod()
|
||||
{
|
||||
var a, b, p;
|
||||
|
||||
|
||||
a = Mod(3, 101);
|
||||
b = Mod(-1, 101);
|
||||
assert((a + b) == Mod(2, 101));
|
||||
|
@ -131,7 +131,7 @@ 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);
|
||||
|
|
|
@ -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
|
||||
})();
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
318
unicode_gen.c
318
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);
|
||||
|
@ -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 &&
|
||||
|
@ -1140,7 +1145,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 +1226,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 +1250,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 +1333,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 +1348,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 +1359,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 +1385,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 +1405,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 +1416,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 +1481,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 +1493,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 +1521,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 +1537,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 +1564,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 +1612,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 +1622,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 +1660,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 +1676,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 +1699,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 +1725,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 +1746,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 +1762,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 +1776,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 +1802,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 +1823,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 +1838,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 +1862,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 +1877,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 +1925,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 +1981,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 +1989,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 +1997,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 +2005,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 +2019,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 +2036,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 +2093,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 +2116,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 +2130,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 +2235,7 @@ const int decomp_incr_tab[4][4] = {
|
|||
/*
|
||||
entry size:
|
||||
type bits
|
||||
code 18
|
||||
code 18
|
||||
len 7
|
||||
compat 1
|
||||
type 5
|
||||
|
@ -2272,7 +2344,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 +2355,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 +2403,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 +2416,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 +2487,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 +2571,7 @@ void find_decomp_run(DecompEntry *tab_de, int i)
|
|||
|
||||
if (l == 2) {
|
||||
BOOL is_16bit;
|
||||
|
||||
|
||||
n = 0;
|
||||
is_16bit = FALSE;
|
||||
for(;;) {
|
||||
|
@ -2544,7 +2616,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 +2767,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 +2793,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 +2807,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 +2833,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 +2847,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 +2861,7 @@ void build_decompose_table(FILE *f)
|
|||
build_compose_table(f, tab_de);
|
||||
|
||||
free(data_buf);
|
||||
|
||||
|
||||
free(tab_de);
|
||||
}
|
||||
|
||||
|
@ -2817,7 +2892,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 +2915,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 +2940,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 +2956,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 +3005,7 @@ void check_compose_table(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -2969,7 +3045,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 +3068,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 +3099,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 +3118,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 +3145,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 +3167,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 +3176,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 +3195,7 @@ int main(int argc, char **argv)
|
|||
} else
|
||||
{
|
||||
FILE *fo = fopen(outfilename, "wb");
|
||||
|
||||
|
||||
if (!fo) {
|
||||
perror(outfilename);
|
||||
exit(1);
|
||||
|
@ -3139,6 +3217,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;
|
||||
|
|
Loading…
Reference in a new issue