revert to previous version
Some checks are pending
ci / Linux (Ubuntu) (push) Waiting to run
ci / linux-asan (push) Waiting to run
ci / linux-msan (push) Waiting to run
ci / linux-ubsan (push) Waiting to run
ci / macOS (push) Waiting to run
ci / macos-asan (push) Waiting to run
ci / macos-ubsan (push) Waiting to run
ci / freebsd (push) Waiting to run
ci / qemu-alpine (arm32v6) (push) Waiting to run
ci / qemu-alpine (arm32v7) (push) Waiting to run
ci / qemu-alpine (arm64v8) (push) Waiting to run
ci / qemu-alpine (i386) (push) Waiting to run
ci / qemu-alpine (s390x) (push) Waiting to run

This commit is contained in:
The Ghost of FOSS' Past 2024-10-24 14:25:35 -05:00
parent 6e2e68fd08
commit 51ec4ed20b
58 changed files with 5011 additions and 4364 deletions

8
.gitignore vendored
View file

@ -1,18 +1,10 @@
*.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
repl.c
run-test262
test262
test262_*.txt

View file

@ -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.sleepAsync(), os.getpid() and os.now()
- added os.getpid() and os.now()
- added cosmopolitan build
- misc bug fixes

View file

@ -1,5 +1,5 @@
QuickJS Javascript Engine
Copyright (c) 2017-2021 Fabrice Bellard
Copyright (c) 2017-2021 Charlie Gordon

161
Makefile
View file

@ -1,6 +1,6 @@
#
# QuickJS Javascript Engine
#
#
# Copyright (c) 2017-2021 Fabrice Bellard
# Copyright (c) 2017-2021 Charlie Gordon
#
@ -25,13 +25,10 @@
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
@ -46,37 +43,16 @@ PREFIX?=/usr/local
#CONFIG_PROFILE=y
# use address sanitizer
#CONFIG_ASAN=y
# use memory sanitizer
#CONFIG_MSAN=y
# use UB sanitizer
#CONFIG_UBSAN=y
# include the code for BigFloat/BigDecimal and math mode
# include the code for BigFloat/BigDecimal, math mode and faster large integers
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
@ -111,7 +87,6 @@ ifdef CONFIG_CLANG
AR=$(CROSS_PREFIX)ar
endif
endif
LIB_FUZZING_ENGINE ?= "-fsanitize=fuzzer"
else ifdef CONFIG_COSMO
CONFIG_LTO=
HOST_CC=gcc
@ -131,7 +106,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
@ -143,11 +118,6 @@ 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
@ -172,14 +142,6 @@ 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
@ -214,21 +176,18 @@ endif
# examples
ifeq ($(CROSS_PREFIX),)
PROGS+=examples/hello
ifndef CONFIG_ASAN
ifndef CONFIG_MSAN
ifndef CONFIG_UBSAN
PROGS+=examples/hello examples/hello_module examples/test_fib
PROGS+=examples/hello_module
endif
ifdef CONFIG_SHARED_LIBS
PROGS+=examples/fib.so examples/point.so
endif
endif
endif
PROGS+=examples/test_fib examples/fib.so examples/point.so
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
@ -254,17 +213,6 @@ 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 \
@ -306,9 +254,6 @@ 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
@ -337,9 +282,6 @@ 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 $@ $<
@ -358,9 +300,6 @@ $(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 $@ $<
@ -372,18 +311,17 @@ 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 fuzz_eval fuzz_compile fuzz_regexp $(PROGS)
rm -f *.a *.o *.d *~ unicode_gen regexp_test $(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$(EXE) qjsc$(EXE)
install -m755 qjs$(EXE) qjsc$(EXE) "$(DESTDIR)$(PREFIX)/bin"
ln -sf qjs$(EXE) "$(DESTDIR)$(PREFIX)/bin/qjscalc$(EXE)"
$(STRIP) qjs qjsc
install -m755 qjs qjsc "$(DESTDIR)$(PREFIX)/bin"
ln -sf qjs "$(DESTDIR)$(PREFIX)/bin/qjscalc"
mkdir -p "$(DESTDIR)$(PREFIX)/lib/quickjs"
install -m644 libquickjs.a "$(DESTDIR)$(PREFIX)/lib/quickjs"
ifdef CONFIG_LTO
@ -437,11 +375,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
@ -466,9 +404,8 @@ endif
test: qjs
./qjs tests/test_closure.js
./qjs tests/test_language.js
./qjs --std tests/test_builtin.js
./qjs 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
@ -481,20 +418,19 @@ endif
endif
ifdef CONFIG_BIGNUM
./qjs --bignum tests/test_op_overloading.js
./qjs --bignum tests/test_bigfloat.js
./qjs --bignum tests/test_bignum.js
./qjs --qjscalc tests/test_qjscalc.js
endif
ifdef CONFIG_M32
./qjs32 tests/test_closure.js
./qjs32 tests/test_language.js
./qjs32 --std tests/test_builtin.js
./qjs32 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_bigfloat.js
./qjs32 --bignum tests/test_bignum.js
./qjs32 --qjscalc tests/test_qjscalc.js
endif
endif
@ -504,46 +440,36 @@ stats: qjs qjs32
./qjs32 -qd
microbench: qjs
./qjs --std tests/microbench.js
./qjs tests/microbench.js
microbench-32: qjs32
./qjs32 --std tests/microbench.js
./qjs32 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 -t -m -c test262o.conf
time ./run-test262 -m -c test262o.conf
test2o-32: run-test262-32
time ./run-test262-32 -t -m -c test262o.conf
time ./run-test262-32 -m -c test262o.conf
test2o-update: run-test262
./run-test262 -t -u -c test262o.conf
endif
./run-test262 -u -c test262o.conf
ifeq ($(wildcard test262/features.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 -t -m -c test262.conf
time ./run-test262 -m -c test262.conf
test2: run-test262
time ./run-test262 -t -m -c test262.conf -a
time ./run-test262 -m -c test262.conf -a
test2-32: run-test262-32
time ./run-test262-32 -t -m -c test262.conf -a
time ./run-test262-32 -m -c test262.conf -a
test2-update: run-test262
./run-test262 -t -u -c test262.conf -a
./run-test262 -u -c test262.conf -a
test2-check: run-test262
time ./run-test262 -t -m -c test262.conf -E -a
endif
time ./run-test262 -m -c test262.conf -E -a
testall: all test microbench test2o test2
@ -551,40 +477,11 @@ 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)

2
TODO
View file

@ -63,5 +63,5 @@ Optimization ideas:
Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
Result: 8/76947 errors, 1497 excluded, 8117 skipped
Result: 10/76947 errors, 1497 excluded, 8117 skipped
Test262 commit: 6cbb6da9473c56d95358d8e679c5a6d2b4574efb

View file

@ -1 +1 @@
2024-02-14
2024-01-13

View file

@ -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_no_ub(s->buf + s->size, data, len);
memcpy(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);

View file

@ -1,6 +1,6 @@
/*
* C utilities
*
*
* Copyright (c) 2017 Fabrice Bellard
* Copyright (c) 2018 Charlie Gordon
*
@ -26,9 +26,11 @@
#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))
@ -46,16 +48,9 @@
#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;
@ -71,12 +66,6 @@ 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)
@ -221,34 +210,28 @@ 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);
@ -298,36 +281,6 @@ 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')

734
doc/jsbignum.html Normal file
View file

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

BIN
doc/jsbignum.pdf Normal file

Binary file not shown.

View file

@ -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 Normal file

File diff suppressed because it is too large Load diff

BIN
doc/quickjs.pdf Normal file

Binary file not shown.

View file

@ -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,9 +379,7 @@ 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. The promise is resolved with an
object whose @code{value} property holds the value returned by the
script.
script and a promise is returned.
@end table
@item loadScript(filename)
@ -489,7 +487,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}
@ -596,7 +594,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
@ -734,7 +732,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.
@ -758,7 +756,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
@ -829,7 +827,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
@ -972,7 +970,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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

542
libbf.c

File diff suppressed because it is too large Load diff

20
libbf.h
View file

@ -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);

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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,15 +25,19 @@
#define LIBREGEXP_H
#include <stddef.h>
#include <stdint.h>
#include "libunicode.h"
#define LRE_BOOL int /* for documentation purposes */
#define LRE_FLAG_GLOBAL (1 << 0)
#define LRE_FLAG_IGNORECASE (1 << 1)
#define LRE_FLAG_MULTILINE (1 << 2)
#define LRE_FLAG_DOTALL (1 << 3)
#define LRE_FLAG_UNICODE (1 << 4)
#define LRE_FLAG_UTF16 (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,
@ -47,9 +51,43 @@ 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, return non zero if overflow */
int lre_check_stack_overflow(void *opaque, size_t alloca_size);
/* must be provided by the user */
LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size);
void *lre_realloc(void *opaque, void *ptr, size_t size);
/* JS identifier test */
extern uint32_t const lre_id_start_table_ascii[4];
extern uint32_t const lre_id_continue_table_ascii[4];
static inline int lre_js_is_ident_first(int c)
{
if ((uint32_t)c < 128) {
return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1;
} else {
#ifdef CONFIG_ALL_UNICODE
return lre_is_id_start(c);
#else
return !lre_is_space(c);
#endif
}
}
static inline int lre_js_is_ident_next(int c)
{
if ((uint32_t)c < 128) {
return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1;
} else {
/* ZWNJ and ZWJ are accepted in identifiers */
#ifdef CONFIG_ALL_UNICODE
return lre_is_id_continue(c) || c == 0x200C || c == 0x200D;
#else
return !lre_is_space(c) || c == 0x200C || c == 0x200D;
#endif
}
}
#undef LRE_BOOL
#endif /* LIBREGEXP_H */

View file

@ -189,13 +189,9 @@ static const uint8_t unicode_prop_Cased1_table[196] = {
};
static const uint8_t unicode_prop_Cased1_index[21] = {
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)
0xb9, 0x02, 0xe0, 0xc0, 0x1d, 0x20, 0xe5, 0x2c,
0x20, 0xb1, 0x07, 0x21, 0xc1, 0xd6, 0x21, 0x4a,
0xf1, 0x01, 0x8a, 0xf1, 0x01,
};
static const uint8_t unicode_prop_Case_Ignorable_table[737] = {
@ -295,29 +291,15 @@ static const uint8_t unicode_prop_Case_Ignorable_table[737] = {
};
static const uint8_t unicode_prop_Case_Ignorable_index[69] = {
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)
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,
};
static const uint8_t unicode_prop_ID_Start_table[1100] = {
@ -462,41 +444,20 @@ static const uint8_t unicode_prop_ID_Start_table[1100] = {
};
static const uint8_t unicode_prop_ID_Start_index[105] = {
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)
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,
};
static const uint8_t unicode_prop_ID_Continue1_table[660] = {
@ -586,27 +547,14 @@ static const uint8_t unicode_prop_ID_Continue1_table[660] = {
};
static const uint8_t unicode_prop_ID_Continue1_index[63] = {
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)
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,
};
#ifdef CONFIG_ALL_UNICODE
@ -728,35 +676,17 @@ static const uint8_t unicode_cc_table[899] = {
};
static const uint8_t unicode_cc_index[87] = {
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)
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,
};
static const uint32_t unicode_decomp_table1[699] = {
@ -4554,4 +4484,3 @@ static const uint16_t unicode_prop_len_table[] = {
};
#endif /* CONFIG_ALL_UNICODE */
/* 62 tables / 32261 bytes, 5 index / 345 bytes */

View file

@ -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,7 +262,11 @@ 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
@ -307,20 +311,12 @@ 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) {
@ -348,7 +344,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) {
@ -407,7 +403,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,
@ -434,7 +430,7 @@ static void cr_compress(CharRange *cr)
{
int i, j, k, len;
uint32_t *pt;
pt = cr->points;
len = cr->len;
i = 0;
@ -464,7 +460,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(;;) {
@ -765,7 +761,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) {
@ -795,7 +791,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) {
@ -831,19 +827,12 @@ 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;
@ -887,7 +876,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) {
@ -926,7 +915,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) {
@ -971,7 +960,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);
@ -999,15 +988,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) {
@ -1044,7 +1033,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);
@ -1077,13 +1066,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) {
@ -1196,15 +1185,6 @@ 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;
@ -1258,14 +1238,6 @@ 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++;
@ -1378,7 +1350,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;
@ -1417,7 +1389,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);
@ -1432,7 +1404,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 */
@ -1516,7 +1488,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(;;) {
@ -1602,7 +1574,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;
@ -1620,7 +1592,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;
@ -1814,97 +1786,3 @@ 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;
}

View file

@ -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,13 +24,27 @@
#ifndef LIBUNICODE_H
#define LIBUNICODE_H
#include <stdint.h>
#include <inttypes.h>
#define LRE_BOOL int /* for documentation purposes */
/* define it to include all the unicode tables (40KB larger) */
#define CONFIG_ALL_UNICODE
#define LRE_CC_RES_LEN_MAX 3
typedef enum {
UNICODE_NFC,
UNICODE_NFD,
UNICODE_NFKC,
UNICODE_NFKD,
} UnicodeNormalizationEnum;
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
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 {
@ -88,14 +102,12 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
int cr_invert(CharRange *cr);
int cr_regexp_canonicalize(CharRange *cr, int is_unicode);
int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode);
typedef enum {
UNICODE_NFC,
UNICODE_NFD,
UNICODE_NFKC,
UNICODE_NFKD,
} UnicodeNormalizationEnum;
#ifdef CONFIG_ALL_UNICODE
LRE_BOOL lre_is_id_start(uint32_t c);
LRE_BOOL lre_is_id_continue(uint32_t c);
int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
UnicodeNormalizationEnum n_type,
@ -103,80 +115,13 @@ 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, int is_ext);
int unicode_script(CharRange *cr,
const char *script_name, LRE_BOOL is_ext);
int unicode_general_category(CharRange *cr, const char *gc_name);
int unicode_prop(CharRange *cr, const char *prop_name);
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
int lre_canonicalize(uint32_t c, int is_unicode);
#endif /* CONFIG_ALL_UNICODE */
/* 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
}
}
#undef LRE_BOOL
#endif /* LIBUNICODE_H */

4
list.h
View file

@ -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;

25
qjs.c
View file

@ -1,6 +1,6 @@
/*
* QuickJS stand alone interpreter
*
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
@ -34,10 +34,8 @@
#include <time.h>
#if defined(__APPLE__)
#include <malloc/malloc.h>
#elif defined(__linux__) || defined(__GLIBC__)
#elif defined(__linux__)
#include <malloc.h>
#elif defined(__FreeBSD__)
#include <malloc_np.h>
#endif
#include "cutils.h"
@ -66,7 +64,6 @@ 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);
}
@ -85,7 +82,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);
@ -151,7 +148,7 @@ static size_t js_trace_malloc_usable_size(const void *ptr)
return _msize((void *)ptr);
#elif defined(EMSCRIPTEN)
return 0;
#elif defined(__linux__) || defined(__GLIBC__)
#elif defined(__linux__)
return malloc_usable_size((void *)ptr);
#else
/* change this to `return 0;` if compilation fails */
@ -317,7 +314,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' */
{
@ -329,7 +326,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;
@ -480,7 +477,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) {
@ -497,6 +494,12 @@ int main(int argc, char **argv)
"globalThis.os = os;\n";
eval_buf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE);
}
//POLYFILLS BEGIN
const char *reqPF = "function require(x) { \n"
" import { y } from `String(x)` \n"
" return y \n"
"}";
eval_buf(ctx, reqPF, strlen(reqPF), "<input>", JS_EVAL_TYPE_MODULE);
for(i = 0; i < include_count; i++) {
if (eval_file(ctx, include_list[i], module))
@ -521,7 +524,7 @@ int main(int argc, char **argv)
}
js_std_loop(ctx);
}
if (dump_memory) {
JSMemoryUsage stats;
JS_ComputeMemoryUsage(rt, &stats);

52
qjsc.c
View file

@ -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);

View file

@ -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];

View file

@ -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 */

File diff suppressed because it is too large Load diff

View file

@ -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,7 +37,6 @@ 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);
@ -52,7 +51,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

View file

@ -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

2696
quickjs.c

File diff suppressed because it is too large Load diff

View file

@ -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,10 +499,7 @@ 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);
@ -550,21 +547,23 @@ 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;
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);
u.d = d;
val = (int32_t)d;
t.d = val;
/* -0 cannot be represented as integer, so we compare the bit
representation */
if (u.u == t.u) {
v = JS_MKVAL(JS_TAG_INT, val);
} else {
v = __JS_NewFloat64(ctx, d);
}
return __JS_NewFloat64(ctx, d);
return v;
}
static inline JS_BOOL JS_IsNumber(JSValueConst v)
@ -633,9 +632,7 @@ static inline JS_BOOL JS_IsObject(JSValueConst v)
JSValue JS_Throw(JSContext *ctx, JSValue obj);
JSValue JS_GetException(JSContext *ctx);
JS_BOOL JS_HasException(JSContext *ctx);
JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val);
void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, JS_BOOL flag);
void JS_ResetUncatchableError(JSContext *ctx);
JSValue JS_NewError(JSContext *ctx);
JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...);
@ -684,10 +681,6 @@ 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)
@ -730,8 +723,6 @@ 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);
@ -830,23 +821,6 @@ 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,
@ -902,7 +876,6 @@ 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 */
@ -995,7 +968,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 */

View file

@ -8,12 +8,12 @@ version=`cat VERSION`
if [ "$1" = "-h" ] ; then
echo "release.sh [release_list]"
echo ""
echo "release_list: extras binary win_binary quickjs"
echo "release_list: extras binary win_binary cosmo_binary quickjs"
exit 1
fi
release_list="extras binary win_binary quickjs"
release_list="extras binary win_binary cosmo_binary quickjs"
if [ "$1" != "" ] ; then
release_list="$1"
@ -29,7 +29,7 @@ name="quickjs-extras-${version}"
outdir="/tmp/${d}"
rm -rf $outdir
mkdir -p $outdir $outdir/unicode $outdir/tests
mkdir -p $outdir $outdir/unicode $outdir/tests
cp unicode/* $outdir/unicode
cp -a tests/bench-v8 $outdir/tests
@ -82,6 +82,28 @@ 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
#################################################"
@ -151,7 +173,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} )

141
repl.js
View file

@ -1,6 +1,6 @@
/*
* QuickJS Read Eval Print Loop
*
*
* Copyright (c) 2017-2020 Fabrice Bellard
* Copyright (c) 2017-2020 Charlie Gordon
*
@ -31,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;
@ -45,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",
@ -67,38 +67,60 @@ import * as os from "os";
bright_white: "\x1b[37;1m",
};
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 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 history = [];
var clip_board = "";
var prec;
var expBits;
var log2_10;
var pstate = "";
var prompt = "";
var plen = 0;
var ps1 = "qjs > ";
var ps1;
if (config_numcalc)
ps1 = "> ";
else
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 = "";
@ -116,12 +138,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)) {
@ -148,14 +170,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);
@ -173,12 +195,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');
}
@ -210,7 +232,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 "()":
@ -249,7 +271,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;
}
}
@ -377,7 +399,7 @@ import * as os from "os";
function backward_word() {
cursor_pos = skip_word_backward(cursor_pos);
}
}
function accept_line() {
std.puts("\n");
@ -555,7 +577,7 @@ import * as os from "os";
readline_print_prompt();
}
}
function reset() {
cmd = "";
cursor_pos = 0;
@ -591,9 +613,6 @@ 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;
@ -712,7 +731,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 */
@ -788,9 +807,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;
@ -875,7 +894,7 @@ import * as os from "os";
} else {
alert(); /* beep! */
}
cursor_pos = (cursor_pos < 0) ? 0 :
(cursor_pos > cmd.length) ? cmd.length : cursor_pos;
update();
@ -973,21 +992,19 @@ 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 ||
@ -1055,7 +1072,7 @@ import * as os from "os";
}
print_rec(a);
}
function extract_directive(a) {
var pos;
if (a[0] !== '\\')
@ -1070,7 +1087,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") {
@ -1162,23 +1179,6 @@ 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) {
@ -1197,7 +1197,7 @@ import * as os from "os";
}
}
}
function help() {
function sel(n) {
return n ? "*": " ";
@ -1247,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();
@ -1257,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;
@ -1275,7 +1275,7 @@ import * as os from "os";
}
if (expr === "")
return false;
if (mexpr)
expr = mexpr + '\n' + expr;
colorstate = colorize_js(expr);
@ -1286,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),
@ -1299,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;
@ -1310,7 +1310,7 @@ import * as os from "os";
/* result is a promise */
result.then(print_eval_result, print_eval_error);
} else {
print_eval_result({ value: result });
print_eval_result(result);
}
} catch (error) {
print_eval_error(error);
@ -1318,7 +1318,6 @@ 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 +1341,7 @@ import * as os from "os";
console.log(error);
}
std.puts(colors.none);
handle_cmd_end();
}
@ -1585,7 +1584,7 @@ import * as os from "os";
}
termInit();
cmd_start();
})(globalThis);

View file

@ -1,6 +1,6 @@
/*
* ECMA Test 262 Runner for QuickJS
*
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
@ -63,8 +63,6 @@ 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;
@ -323,7 +321,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);
@ -459,11 +457,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);
@ -472,7 +470,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);
@ -481,7 +479,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);
@ -493,12 +491,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);
@ -532,11 +530,10 @@ 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;
@ -547,12 +544,7 @@ 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_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);
pthread_create(&agent->tid, NULL, agent_start, agent);
return JS_UNDEFINED;
}
@ -560,7 +552,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);
@ -569,7 +561,7 @@ static void js_agent_free(JSContext *ctx)
free(agent);
}
}
static JSValue js_agent_leaving(JSContext *ctx, JSValue this_val,
int argc, JSValue *argv)
{
@ -601,16 +593,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);
@ -705,7 +697,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);
@ -725,7 +717,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;
@ -741,7 +733,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);
@ -761,7 +753,7 @@ static JSValue add_helpers1(JSContext *ctx)
{
JSValue global_obj;
JSValue obj262, obj;
global_obj = JS_GetGlobalObject(ctx);
JS_SetPropertyStr(ctx, global_obj, "print",
@ -792,7 +784,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;
}
@ -821,27 +813,14 @@ 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);
@ -931,7 +910,7 @@ void update_exclude_dirs(void)
lp->count = count;
}
void load_config(const char *filename, const char *ignore)
void load_config(const char *filename)
{
char buf[1024];
FILE *f;
@ -950,14 +929,14 @@ void load_config(const char *filename, const char *ignore)
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++;
@ -986,10 +965,6 @@ void load_config(const char *filename, const char *ignore)
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;
@ -1027,7 +1002,7 @@ void load_config(const char *filename, const char *ignore)
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;
}
@ -1168,7 +1143,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++) {
@ -1201,7 +1176,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;
@ -1211,7 +1186,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)) {
@ -1264,7 +1239,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");
@ -1273,10 +1248,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] == ':') {
@ -1294,7 +1269,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))
@ -1418,7 +1393,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] != '/') {
@ -1550,11 +1525,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);
@ -1563,10 +1538,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, (void *)filename);
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, NULL);
add_helpers(ctx);
for (i = 0; i < ip->count; i++) {
@ -1579,7 +1554,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);
}
@ -1612,7 +1587,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;
@ -1681,7 +1656,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((unsigned char)*q))
while (isspace(*q))
q++;
error_type = strdup_len(q, strcspn(q, " \n"));
}
@ -1848,13 +1823,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);
@ -1864,10 +1839,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, (void *)filename);
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, NULL);
add_helpers(ctx);
buf = load_file(filename, &buf_len);
@ -1925,27 +1900,9 @@ void show_progress(int force) {
clock_t t = clock();
if (force || !last_clock || (t - last_clock) > CLOCKS_PER_SEC / 20) {
last_clock = t;
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);
}
/* 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);
}
}
@ -1996,8 +1953,6 @@ 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"
@ -2024,29 +1979,14 @@ 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;
@ -2066,16 +2006,12 @@ 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++]), ignore);
load_config(get_opt_arg(arg, argv[optind++]));
} else if (str_equal(arg, "-d")) {
enumerate_tests(get_opt_arg(arg, argv[optind++]));
} else if (str_equal(arg, "-e")) {
@ -2099,14 +2035,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);
@ -2126,10 +2062,8 @@ int main(int argc, char **argv)
update_exclude_dirs();
clocks = clock();
if (is_dir_list) {
if (optind < argc && !isdigit((unsigned char)argv[optind][0])) {
if (optind < argc && !isdigit(argv[optind][0])) {
filename = argv[optind++];
namelist_load(&test_list, filename);
}
@ -2164,8 +2098,6 @@ 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);
@ -2194,8 +2126,6 @@ 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) {
@ -2211,6 +2141,5 @@ int main(int argc, char **argv)
free(harness_exclude);
free(error_file);
/* Signal that the error file is out of date. */
return new_errors || changed_errors || fixed_errors;
return 0;
}

View file

@ -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

View file

@ -406,8 +406,5 @@ 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

View file

@ -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;

View file

@ -22,10 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
if (typeof require !== 'undefined') {
var fs = require('fs');
}
import * as std from "std";
import * as os from "os";
function pad(str, n) {
str += "";
@ -63,17 +61,21 @@ 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 (1000)" ];
var heads = [ "TEST", "N", "TIME (ns)", "REF (ns)", "SCORE (%)" ];
var widths = [ 22, 10, 9, 9, 9 ];
var precs = [ 0, 0, 2, 2, 0 ];
var precs = [ 0, 0, 2, 2, 2 ];
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 = "";
@ -81,7 +83,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]);
@ -93,28 +95,11 @@ function log_line() {
}
var clocks_per_sec = 1000;
var max_iterations = 100;
var clock_threshold = 2; /* favoring short measuring spans */
var max_iterations = 10;
var clock_threshold = 100; /* favoring short measuring spans */
var min_n_argument = 1;
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;
}
}
//var get_clock = Date.now;
var get_clock = os.now;
function log_one(text, n, ti) {
var ref;
@ -127,7 +112,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, Math.round(ref * 1000 / ti));
log_line(text, n, ti, ref, ti * 100 / ref);
total_score += ti * 100 / ref;
total_scale += 100;
} else {
@ -139,27 +124,28 @@ function log_one(text, n, ti) {
function bench(f, text)
{
var i, j, n, t, ti, nb_its, ref, ti_n, ti_n1;
var i, j, n, t, t1, ti, nb_its, ref, ti_n, ti_n1, min_ti;
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
if (ti > t)
ti = t;
t1 = get_clock() - t1;
if (ti > t1)
ti = t1;
}
if (ti >= clock_threshold / 10) {
if (ti >= min_ti) {
ti_n1 = ti / nb_its;
if (ti_n > ti_n1)
ti_n = ti_n1;
@ -185,26 +171,6 @@ 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++) {
@ -213,32 +179,6 @@ 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;
@ -267,78 +207,30 @@ function prop_write(n)
return n * 4;
}
function prop_update(n)
{
var obj, j;
obj = {a: 1, b: 2, c:3, d:4 };
for(j = 0; j < n; j++) {
obj.a += j;
obj.b += j;
obj.c += j;
obj.d += j;
}
return n * 4;
}
function prop_create(n)
{
var obj, i, j;
var obj, j;
for(j = 0; j < n; j++) {
obj = {};
obj = new Object();
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;
return n * 4;
}
function prop_delete(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;
var obj, j;
obj = {};
for(j = 0; j < n; j++) {
obj[j] = 1;
}
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];
}
for(j = 0; j < n; j++) {
delete obj[j];
}
return n * 20;
return n;
}
function array_read(n)
@ -399,32 +291,15 @@ 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, ref, i, j, len;
var tab, i, j, len;
len = 1000;
ref = [];
tab = [];
for(i = 0; i < len; i++)
ref[i] = i;
tab[i] = i;
for(j = 0; j < n; j++) {
tab = ref.slice();
for(i = len; i --> 0;)
for(i = len - 1; i >= 0; i--)
tab.length = i;
}
return len * n;
@ -432,16 +307,15 @@ function array_length_decr(n)
function array_hole_length_decr(n)
{
var tab, ref, i, j, len;
var tab, i, j, len;
len = 1000;
ref = [];
tab = [];
for(i = 0; i < len; i++) {
if (i % 10 == 9)
ref[i] = i;
if (i != 3)
tab[i] = i;
}
for(j = 0; j < n; j++) {
tab = ref.slice();
for(i = len; i --> 0;)
for(i = len - 1; i >= 0; i--)
tab.length = i;
}
return len * n;
@ -461,13 +335,12 @@ function array_push(n)
function array_pop(n)
{
var tab, ref, i, j, len, sum;
var tab, i, j, len, sum;
len = 500;
ref = [];
for(i = 0; i < len; i++)
ref[i] = i;
for(j = 0; j < n; j++) {
tab = ref.slice();
tab = [];
for(i = 0; i < len; i++)
tab[i] = i;
sum = 0;
for(i = 0; i < len; i++)
sum += tab.pop();
@ -539,7 +412,6 @@ function global_read(n)
return n * 4;
}
// non strict version
var global_write =
(1, eval)(`(function global_write(n)
{
@ -582,7 +454,6 @@ 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)
{
@ -610,25 +481,6 @@ 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)
@ -648,7 +500,7 @@ function func_call(n)
return n * 4;
}
function func_closure_call(n)
function closure_var(n)
{
function f(a)
{
@ -753,8 +605,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);
}
@ -768,25 +620,25 @@ function set_collection_add(n)
function array_for(n)
{
var r, i, j, sum, len = 100;
var r, i, j, sum;
r = [];
for(i = 0; i < len; i++)
for(i = 0; i < 100; i++)
r[i] = i;
for(j = 0; j < n; j++) {
sum = 0;
for(i = 0; i < len; i++) {
for(i = 0; i < 100; i++) {
sum += r[i];
}
global_res = sum;
}
return n * len;
return n * 100;
}
function array_for_in(n)
{
var r, i, j, sum, len = 100;
var r, i, j, sum;
r = [];
for(i = 0; i < len; i++)
for(i = 0; i < 100; i++)
r[i] = i;
for(j = 0; j < n; j++) {
sum = 0;
@ -795,14 +647,14 @@ function array_for_in(n)
}
global_res = sum;
}
return n * len;
return n * 100;
}
function array_for_of(n)
{
var r, i, j, sum, len = 100;
var r, i, j, sum;
r = [];
for(i = 0; i < len; i++)
for(i = 0; i < 100; i++)
r[i] = i;
for(j = 0; j < n; j++) {
sum = 0;
@ -811,7 +663,7 @@ function array_for_of(n)
}
global_res = sum;
}
return n * len;
return n * 100;
}
function math_min(n)
@ -826,108 +678,58 @@ 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++) {
r = "";
for(i = 0; i < 1000; i++)
for(i = 0; i < 100; i++)
r += "x";
global_res = r;
}
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;
return n * 100;
}
/* incremental string contruction as arg */
function string_build2(n, r)
{
var i, j;
r = "";
for(j = 0; j < n; j++) {
r = "";
for(i = 0; i < 1000; i++)
for(i = 0; i < 100; i++)
r += "x";
global_res = r;
}
return n * 1000;
return n * 100;
}
/* incremental string contruction by prepending */
function string_build3(n)
function string_build3(n, r)
{
var i, j, r;
var i, j;
r = "";
for(j = 0; j < n; j++) {
r = "";
for(i = 0; i < 1000; i++)
for(i = 0; i < 100; i++)
r = "x" + r;
global_res = r;
}
return n * 1000;
return n * 100;
}
/* incremental string contruction with multiple reference */
function string_build4(n)
{
var i, j, r, s;
r = "";
for(j = 0; j < n; j++) {
r = "";
for(i = 0; i < 1000; i++) {
for(i = 0; i < 100; i++) {
s = r;
r += "x";
}
global_res = r;
}
return n * 1000;
return n * 100;
}
/* sort bench */
@ -1060,33 +862,32 @@ function sort_bench(text) {
": " + arr[i - 1] + " > " + arr[i]);
}
if (sort_bench.verbose)
log_one("sort_" + f.name, 1, ti / 100);
log_one("sort_" + f.name, n, ti, n * 100);
}
total_score = save_total_score;
total_scale = save_total_scale;
return total / n / 100;
return total / n / 1000;
}
sort_bench.bench = true;
sort_bench.verbose = false;
function int_to_string(n)
{
var s, j;
var s, r, j;
r = 0;
for(j = 0; j < n; j++) {
s = (j % 1000).toString();
s = (1234000 + j % 1000).toString();
s = (j + 1).toString();
}
global_res = s;
return n * 2;
return n;
}
function float_to_string(n)
{
var s, j;
var s, r, j;
r = 0;
for(j = 0; j < n; j++) {
s = (j + 0.1).toString();
}
global_res = s;
return n;
}
@ -1095,6 +896,7 @@ function string_to_int(n)
var s, r, j;
r = 0;
s = "12345";
r = 0;
for(j = 0; j < n; j++) {
r += (s | 0);
}
@ -1107,6 +909,7 @@ function string_to_float(n)
var s, r, j;
r = 0;
s = "12345.6";
r = 0;
for(j = 0; j < n; j++) {
r -= s;
}
@ -1116,92 +919,41 @@ function string_to_float(n)
function load_result(filename)
{
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 {
var f, str, res;
if (typeof std === "undefined")
return null;
}
if (has_error) {
if (has_filename) {
// Should throw exception?
console.log("cannot load " + filename);
}
f = std.open(filename, "r");
if (!f)
return null;
}
str = f.readAsString();
res = JSON.parse(str);
f.close();
return res;
}
function save_result(filename, obj)
{
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 {
var f;
if (typeof std === "undefined")
return;
}
if (has_error)
console.log("cannot save " + filename);
f = std.open(filename, "w");
f.puts(JSON.stringify(obj, null, 2));
f.puts("\n");
f.close();
}
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,
@ -1214,9 +966,8 @@ function main(argc, argv, g)
local_destruct,
global_destruct,
global_destruct_strict,
global_func_call,
func_call,
func_closure_call,
closure_var,
int_arith,
float_arith,
set_collection_add,
@ -1224,34 +975,29 @@ 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,
//string_build3,
//string_build4,
sort_bench,
int_to_string,
float_to_string,
string_to_int,
string_to_float,
];
var tests = [];
var i, j, n, f, name, found;
var ref_file, new_ref_file = "microbench-new.txt";
if (typeof BigInt === "function") {
var i, j, n, f, name;
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") {
@ -1261,7 +1007,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;
}
@ -1271,22 +1017,14 @@ function main(argc, argv, g)
sort_bench.array_size = +argv[i++];
continue;
}
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++) {
for (j = 0; j < test_list.length; j++) {
f = test_list[j];
if (f.name.startsWith(name)) {
if (name === f.name) {
tests.push(f);
found = true;
break;
}
}
if (!found) {
if (j == test_list.length) {
console.log("unknown benchmark: " + name);
return 1;
}
@ -1294,7 +1032,7 @@ function main(argc, argv, g)
if (tests.length == 0)
tests = test_list;
ref_data = load_result(ref_file);
ref_data = load_result("microbench.txt");
log_data = {};
log_line.apply(null, heads);
n = 0;
@ -1306,17 +1044,14 @@ function main(argc, argv, g)
n++;
}
if (ref_data)
log_line("total", "", total[2], total[3], Math.round(total_scale * 1000 / total_score));
log_line("total", "", total[2], total[3], total_score * 100 / total_scale);
else
log_line("total", "", total[2]);
if (tests == test_list && new_ref_file)
save_result(new_ref_file, log_data);
if (tests == test_list)
save_result("microbench-new.txt", log_data);
}
if (typeof scriptArgs === "undefined") {
if (!scriptArgs)
scriptArgs = [];
if (typeof process.argv === "object")
scriptArgs = process.argv.slice(1);
}
main(scriptArgs.length, scriptArgs, this);

View file

@ -1,8 +1,8 @@
diff --git a/harness/atomicsHelper.js b/harness/atomicsHelper.js
index 9828b15..4a5919d 100644
index 9c1217351e..3c24755558 100644
--- a/harness/atomicsHelper.js
+++ b/harness/atomicsHelper.js
@@ -272,10 +272,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) {
@@ -227,10 +227,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) {
* }
*/
$262.agent.timeouts = {
@ -22,11 +22,11 @@ index 9828b15..4a5919d 100644
/**
diff --git a/harness/regExpUtils.js b/harness/regExpUtils.js
index b55f3c6..396bad4 100644
index be7039fda0..7b38abf8df 100644
--- a/harness/regExpUtils.js
+++ b/harness/regExpUtils.js
@@ -6,27 +6,30 @@ description: |
defines: [buildString, testPropertyEscapes, testPropertyOfStrings, testExtendedCharacterClass, matchValidator]
@@ -6,24 +6,27 @@ description: |
defines: [buildString, testPropertyEscapes, matchValidator]
---*/
+if ($262 && typeof $262.codePointRange === "function") {
@ -44,12 +44,7 @@ index b55f3c6..396bad4 100644
+ }
+}
+
function buildString(args) {
// Use member expressions rather than destructuring `args` for improved
// compatibility with engines that only implement assignment patterns
// partially or not at all.
const loneCodePoints = args.loneCodePoints;
const ranges = args.ranges;
function buildString({ loneCodePoints, ranges }) {
- const CHUNK_SIZE = 10000;
- let result = Reflect.apply(String.fromCodePoint, null, loneCodePoints);
- for (let i = 0; i < ranges.length; i++) {
@ -63,11 +58,14 @@ index b55f3c6..396bad4 100644
- result += Reflect.apply(String.fromCodePoint, null, codePoints);
- codePoints.length = length = 0;
- }
- }
+ let result = String.fromCodePoint.apply(null, loneCodePoints);
+ for (const [start, end] of ranges) {
+ result += codePointRange(start, end + 1);
}
- result += Reflect.apply(String.fromCodePoint, null, codePoints);
+ let result = String.fromCodePoint.apply(null, loneCodePoints);
+ for (const [start, end] of ranges) {
+ result += codePointRange(start, end + 1);
}
return result;
- }
- return result;
+ return result;
}
function testPropertyEscapes(regex, string, expression) {

View file

@ -1,279 +0,0 @@
"use strict";
function assert(actual, expected, message) {
if (arguments.length == 1)
expected = true;
if (actual === expected)
return;
if (actual !== null && expected !== null
&& typeof actual == 'object' && typeof expected == 'object'
&& actual.toString() === expected.toString())
return;
throw Error("assertion failed: got |" + actual + "|" +
", expected |" + expected + "|" +
(message ? " (" + message + ")" : ""));
}
function assertThrows(err, func)
{
var ex;
ex = false;
try {
func();
} catch(e) {
ex = true;
assert(e instanceof err);
}
assert(ex, true, "exception expected");
}
// load more elaborate version of assert if available
try { __loadScript("test_assert.js"); } catch(e) {}
/*----------------*/
/* 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();

View file

@ -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,5 +110,217 @@ 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();

View file

@ -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;

View file

@ -1,51 +1,19 @@
"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 (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 + "|" +
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 + ")" : ""));
}
@ -57,16 +25,11 @@ function assert_throws(expected_error, func)
} catch(e) {
err = true;
if (!(e instanceof expected_error)) {
// Should output the source file and line number and extract
// the expression from the assert_throws() call
throw_error("unexpected exception type");
return;
throw Error("unexpected exception type");
}
}
if (!err) {
// Should output the source file and line number and extract
// the expression from the assert_throws() call
throw_error("expected exception");
throw Error("expected exception");
}
}
@ -94,7 +57,7 @@ function test_function()
}
var r, g;
r = my_func.call(null, 1, 2);
assert(r, 3, "call");
@ -107,10 +70,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");
@ -140,7 +103,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;
@ -244,7 +207,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);
@ -253,7 +216,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");
@ -348,14 +311,10 @@ 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);
}
@ -368,10 +327,6 @@ 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);
@ -381,11 +336,6 @@ 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");
@ -429,7 +379,7 @@ function test_eval()
assert(eval("if (0) 2; else 3;"), 3);
assert(f.call(1, "this"), 1);
a = 2;
assert(eval("a"), 2);
@ -474,7 +424,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);
@ -486,7 +436,7 @@ function test_typed_array()
a = new Float32Array(buffer, 8, 1);
a[0] = 1;
a = new Uint8Array(buffer);
str = a.toString();
@ -531,105 +481,26 @@ function test_json()
function test_date()
{
// 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);
var d = new Date(1506098258091), a, s;
assert(d.toISOString(), "2017-09-22T16:37:38.091Z");
d.setUTCHours(18, 10, 11);
assert(d.toISOString(), "2017-09-22T18:10:11.091Z");
var a = Date.parse(d.toISOString());
a = Date.parse(d.toISOString());
assert((new Date(a)).toISOString(), d.toISOString());
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);
s = new Date("2020-01-01T01:01:01.1Z").toISOString();
assert(s == "2020-01-01T01:01:01.100Z");
s = new Date("2020-01-01T01:01:01.12Z").toISOString();
assert(s == "2020-01-01T01:01:01.120Z");
s = new Date("2020-01-01T01:01:01.123Z").toISOString();
assert(s == "2020-01-01T01:01:01.123Z");
s = new Date("2020-01-01T01:01:01.1234Z").toISOString();
assert(s == "2020-01-01T01:01:01.123Z");
s = new Date("2020-01-01T01:01:01.12345Z").toISOString();
assert(s == "2020-01-01T01:01:01.123Z");
s = new Date("2020-01-01T01:01:01.1235Z").toISOString();
assert(s == "2020-01-01T01:01:01.124Z");
s = new Date("2020-01-01T01:01:01.9999Z").toISOString();
assert(s == "2020-01-01T01:01:02.000Z");
}
function test_regexp()
@ -654,7 +525,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");
@ -678,8 +549,6 @@ function test_regexp()
assert(a, ["a", undefined]);
a = /(?:|[\w])+([0-9])/.exec("123a23");
assert(a, ["123a23", "3"]);
a = /()*?a/.exec(",");
assert(a, null);
}
function test_symbol()
@ -718,20 +587,6 @@ 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++) {
@ -747,7 +602,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));
@ -770,7 +625,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]);

View file

@ -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;

View file

@ -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,13 +335,6 @@ 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()
@ -369,9 +362,8 @@ function test_template_skip()
function test_object_literal()
{
var x = 0, get = 1, set = 2; async = 3;
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 = { get: 2, set: 3, async: 4 };
assert(JSON.stringify(a), '{"get":2,"set":3,"async":4}');
a = { x, get, set, async };
assert(JSON.stringify(a), '{"x":0,"get":1,"set":2,"async":3}');
@ -382,7 +374,7 @@ function test_regexp_skip()
var a, b;
[a, b = /abc\(/] = [1];
assert(a === 1);
[a, b =/abc\(/] = [2];
assert(a === 2);
}
@ -427,13 +419,9 @@ function test_argument_scope()
{
var f;
var c = "global";
(function() {
"use strict";
// XXX: node only throws in strict mode
f = function(a = eval("var arguments")) {};
assert_throws(SyntaxError, f);
})();
f = function(a = eval("var arguments")) {};
assert_throws(SyntaxError, f);
f = function(a = eval("1"), b = arguments[0]) { return b; };
assert(f(12), 12);
@ -502,7 +490,7 @@ function test_function_expr_name()
/* non strict mode test : assignment to the function name silently
fails */
f = function myfunc() {
myfunc = 1;
return myfunc;
@ -523,7 +511,7 @@ function test_function_expr_name()
return myfunc;
};
assert(f(), f);
/* strict mode test : assignment to the function name raises a
TypeError exception */
@ -570,15 +558,6 @@ 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()
{
@ -593,7 +572,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 }
@ -625,4 +604,3 @@ test_argument_scope();
test_function_expr_name();
test_parse_semicolon();
test_optional_chaining();
test_parse_arrow_function();

View file

@ -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 {

View file

@ -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;

View file

@ -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);

View file

@ -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,25 +144,23 @@ function test_os()
{
var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
const stdinIsTTY = !os.exec(["/bin/sh", "-c", "test -t 0"], { usePath: false });
assert(os.isatty(0), stdinIsTTY, `isatty(STDIN)`);
assert(os.isatty(0));
fdir = "test_tmp_dir";
fname = "tmp_file.txt";
fpath = fdir + "/" + fname;
link_path = fdir + "/test_link";
os.remove(link_path);
os.remove(fpath);
os.remove(fdir);
err = os.mkdir(fdir, 0o755);
assert(err === 0);
fd = os.open(fpath, os.O_RDWR | os.O_CREAT | os.O_TRUNC);
assert(fd >= 0);
buf = new Uint8Array(10);
for(i = 0; i < buf.length; i++)
buf[i] = i;
@ -171,16 +169,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);
@ -191,7 +189,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);
@ -199,7 +197,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);
@ -207,7 +205,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();
@ -217,7 +215,7 @@ function test_os()
assert(err, 0);
assert(buf, buf2);
assert(os.remove(fpath) === 0);
fd = os.open(fpath, os.O_RDONLY);
@ -235,7 +233,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],
@ -255,11 +253,10 @@ function test_os_exec()
pid = os.exec(["cat"], { block: false } );
assert(pid >= 0);
os.kill(pid, os.SIGTERM);
os.kill(pid, os.SIGQUIT);
[ret, status] = os.waitpid(pid, 0);
assert(ret, pid);
assert(status !== 0, true, `expect nonzero exit code (got ${status})`);
assert(status & 0x7f, os.SIGTERM);
assert(status & 0x7f, os.SIGQUIT);
}
function test_timer()
@ -280,16 +277,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
})();
}

View file

@ -10,7 +10,7 @@ function handle_msg(e) {
switch(ev.type) {
case "abort":
parent.postMessage({ type: "done" });
parent.onmessage = null; /* terminate the worker */
parent.onMessage = null; /* terminate the worker */
break;
case "sab":
/* modify the SharedArrayBuffer */
@ -22,10 +22,10 @@ function handle_msg(e) {
function worker_main() {
var i;
parent.onmessage = handle_msg;
for(i = 0; i < 10; i++) {
parent.postMessage({ type: "num", num: i });
parent.postMessage({ type: "num", num: i });
}
}

View file

@ -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

View file

@ -1,6 +1,6 @@
/*
* Generation of Unicode tables
*
*
* Copyright (c) 2017-2018 Fabrice Bellard
* Copyright (c) 2017-2018 Charlie Gordon
*
@ -33,11 +33,6 @@
#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 */
@ -273,7 +268,7 @@ int find_name(const char **tab, int tab_len, const char *name)
return -1;
}
static BOOL get_prop(uint32_t c, int prop_idx)
static int get_prop(uint32_t c, int prop_idx)
{
return (unicode_db[c].prop_bitmap_tab[prop_idx >> 5] >> (prop_idx & 0x1f)) & 1;
}
@ -296,7 +291,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);
@ -319,7 +314,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);
@ -355,7 +350,7 @@ void parse_unicode_data(const char *filename)
}
ci->general_category = i;
}
p = get_field(line, 3);
if (p && *p != ';' && *p != '\0') {
int cc;
@ -407,7 +402,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>")) {
@ -421,7 +416,7 @@ void parse_unicode_data(const char *filename)
}
last_code = code;
}
fclose(f);
}
@ -432,7 +427,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);
@ -463,8 +458,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;
@ -497,7 +492,7 @@ void parse_special_casing(CCInfo *tab, const char *filename)
ci->u_len = 0;
}
}
fclose(f);
}
@ -508,7 +503,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);
@ -540,7 +535,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') {
@ -560,7 +555,7 @@ void parse_case_folding(CCInfo *tab, const char *filename)
ci->f_data[ci->f_len++] = strtoul(p, (char **)&p, 16);
}
}
fclose(f);
}
@ -569,7 +564,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);
@ -597,7 +592,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);
@ -653,7 +648,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);
@ -703,7 +698,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);
@ -757,7 +752,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);
@ -812,7 +807,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);
@ -977,7 +972,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 &&
@ -1145,7 +1140,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;
@ -1226,7 +1221,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];
@ -1250,7 +1245,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:
@ -1333,9 +1328,7 @@ void dump_case_conv_table(FILE *f)
uint32_t v;
const TableEntry *te;
total_tables++;
total_table_bytes += conv_table_len * sizeof(uint32_t);
fprintf(f, "static const uint32_t case_conv_table1[%d] = {", conv_table_len);
fprintf(f, "static const uint32_t case_conv_table1[%u] = {", conv_table_len);
for(i = 0; i < conv_table_len; i++) {
if (i % 4 == 0)
fprintf(f, "\n ");
@ -1348,9 +1341,7 @@ void dump_case_conv_table(FILE *f)
}
fprintf(f, "\n};\n\n");
total_tables++;
total_table_bytes += conv_table_len;
fprintf(f, "static const uint8_t case_conv_table2[%d] = {", conv_table_len);
fprintf(f, "static const uint8_t case_conv_table2[%u] = {", conv_table_len);
for(i = 0; i < conv_table_len; i++) {
if (i % 8 == 0)
fprintf(f, "\n ");
@ -1359,9 +1350,7 @@ void dump_case_conv_table(FILE *f)
}
fprintf(f, "\n};\n\n");
total_tables++;
total_table_bytes += ext_data_len * sizeof(uint16_t);
fprintf(f, "static const uint16_t case_conv_ext[%d] = {", ext_data_len);
fprintf(f, "static const uint16_t case_conv_ext[%u] = {", ext_data_len);
for(i = 0; i < ext_data_len; i++) {
if (i % 8 == 0)
fprintf(f, "\n ");
@ -1385,7 +1374,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)
@ -1405,7 +1394,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]);
@ -1416,7 +1405,7 @@ void dump_case_folding_special_cases(CCInfo *tab)
free(perm);
global_tab = NULL;
}
int tabcmp(const int *tab1, const int *tab2, int n)
{
@ -1481,9 +1470,6 @@ 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)
@ -1493,26 +1479,9 @@ 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, const char *name, int prop_index, BOOL add_index)
void build_prop_table(FILE *f, int prop_index, BOOL add_index)
{
int i, j, n, v, offset, code;
DynBuf dbuf_s, *dbuf = &dbuf_s;
@ -1521,7 +1490,7 @@ void build_prop_table(FILE *f, const char *name, 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;) {
@ -1537,15 +1506,15 @@ void build_prop_table(FILE *f, const char *name, 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;
@ -1564,14 +1533,6 @@ void build_prop_table(FILE *f, const char *name, 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;
@ -1612,9 +1573,9 @@ void build_prop_table(FILE *f, const char *name, 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_index_table(f, cname, dbuf2->buf, dbuf2->size);
dump_byte_table(f, cname, dbuf2->buf, dbuf2->size);
}
dbuf_free(dbuf);
dbuf_free(dbuf1);
dbuf_free(dbuf2);
@ -1622,10 +1583,10 @@ void build_prop_table(FILE *f, const char *name, int prop_index, BOOL add_index)
void build_flags_tables(FILE *f)
{
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);
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);
}
void dump_name_table(FILE *f, const char *cname, const char **tab_name, int len,
@ -1660,9 +1621,7 @@ 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++)
@ -1676,11 +1635,9 @@ 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;
@ -1699,11 +1656,9 @@ void build_general_category_table(FILE *f)
}
}
// printf("%05x %05x %d\n", i, n, v);
n--;
#ifdef DUMP_TABLE_SIZE
cw_count++;
n--;
cw_start = dbuf->size;
#endif
if (n < 7) {
dbuf_putc(dbuf, (n << 5) | v);
} else if (n < 7 + 128) {
@ -1725,18 +1680,17 @@ 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);
@ -1746,9 +1700,7 @@ 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++)
@ -1762,11 +1714,9 @@ 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;
@ -1776,11 +1726,9 @@ void build_script_table(FILE *f)
if (v == 0 && j == (CHARCODE_MAX + 1))
break;
// printf("%05x %05x %d\n", i, n, v);
n--;
#ifdef DUMP_TABLE_SIZE
cw_count++;
n--;
cw_start = dbuf->size;
#endif
if (v == 0)
type = 0;
else
@ -1802,18 +1750,17 @@ 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;
}
#ifdef DUMP_TABLE_SIZE
printf("script: %d entries [", cw_count);
#if defined(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);
@ -1823,11 +1770,10 @@ void build_script_ext_table(FILE *f)
{
int i, j, n, n1, script_ext_len;
DynBuf dbuf_s, *dbuf = &dbuf_s;
#if defined(DUMP_TABLE_SIZE)
int cw_count = 0;
#endif
int cw_count;
dbuf_init(dbuf);
cw_count = 0;
for(i = 0; i <= CHARCODE_MAX;) {
script_ext_len = unicode_db[i].script_ext_len;
j = i + 1;
@ -1838,9 +1784,7 @@ 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);
@ -1862,10 +1806,11 @@ 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);
@ -1877,17 +1822,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, unicode_prop_name[i], i, FALSE);
build_prop_table(f, i, FALSE);
}
}
fprintf(f, "typedef enum {\n");
for(i = 0; i < PROP_COUNT; i++)
fprintf(f, " UNICODE_PROP_%s,\n", unicode_prop_name[i]);
@ -1925,7 +1870,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;
@ -1981,7 +1926,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);
@ -1989,7 +1934,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);
@ -1997,7 +1942,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);
@ -2005,7 +1950,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);
@ -2019,7 +1964,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++;
}
@ -2036,23 +1981,17 @@ void check_flags(void)
void build_cc_table(FILE *f)
{
// Compress combining class table
// see: https://www.unicode.org/reports/tr44/#Canonical_Combining_Class_Values
int i, cc, n, type, n1, block_end_pos;
int i, cc, n, cc_table_len, type, n1;
DynBuf dbuf_s, *dbuf = &dbuf_s;
DynBuf dbuf1_s, *dbuf1 = &dbuf1_s;
#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)
int cw_len_tab[3], cw_start, cc_table_len;
#endif
int cw_len_tab[3], cw_start, block_end_pos;
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;
@ -2093,16 +2032,7 @@ 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)) {
@ -2116,12 +2046,10 @@ 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;
}
@ -2130,9 +2058,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_index_table(f, "unicode_cc_index", dbuf1->buf, dbuf1->size);
dump_byte_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) [",
@ -2235,7 +2163,7 @@ const int decomp_incr_tab[4][4] = {
/*
entry size:
type bits
code 18
code 18
len 7
compat 1
type 5
@ -2344,7 +2272,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) {
@ -2355,12 +2283,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);
@ -2403,7 +2331,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];
@ -2416,7 +2344,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;
@ -2487,7 +2415,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(;;) {
@ -2571,7 +2499,7 @@ void find_decomp_run(DecompEntry *tab_de, int i)
if (l == 2) {
BOOL is_16bit;
n = 0;
is_16bit = FALSE;
for(;;) {
@ -2616,7 +2544,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) {
@ -2767,9 +2695,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--) {
@ -2793,7 +2721,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++) {
@ -2807,15 +2735,14 @@ 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
total_tables++;
total_table_bytes += array_len * sizeof(uint32_t);
fprintf(f, "static const uint32_t unicode_decomp_table1[%d] = {", array_len);
fprintf(f, "static const uint32_t unicode_decomp_table1[%u] = {",
array_len);
count = 0;
for(i = 0; i <= code_max; i++) {
de = &tab_de[i];
@ -2833,9 +2760,8 @@ void build_decompose_table(FILE *f)
}
fprintf(f, "\n};\n\n");
total_tables++;
total_table_bytes += array_len * sizeof(uint16_t);
fprintf(f, "static const uint16_t unicode_decomp_table2[%d] = {", array_len);
fprintf(f, "static const uint16_t unicode_decomp_table2[%u] = {",
array_len);
count = 0;
for(i = 0; i <= code_max; i++) {
de = &tab_de[i];
@ -2847,10 +2773,9 @@ void build_decompose_table(FILE *f)
}
}
fprintf(f, "\n};\n\n");
total_tables++;
total_table_bytes += data_len;
fprintf(f, "static const uint8_t unicode_decomp_data[%d] = {", data_len);
fprintf(f, "static const uint8_t unicode_decomp_data[%u] = {",
data_len);
for(i = 0; i < data_len; i++) {
if (i % 8 == 0)
fprintf(f, "\n ");
@ -2861,7 +2786,7 @@ void build_decompose_table(FILE *f)
build_compose_table(f, tab_de);
free(data_buf);
free(tab_de);
}
@ -2892,7 +2817,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];
@ -2915,14 +2840,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];
@ -2940,10 +2865,9 @@ void build_compose_table(FILE *f, const DecompEntry *tab_de)
}
}
#endif
total_tables++;
total_table_bytes += tab_ce_len * sizeof(uint16_t);
fprintf(f, "static const uint16_t unicode_comp_table[%u] = {", tab_ce_len);
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 ");
@ -2956,7 +2880,7 @@ void build_compose_table(FILE *f, const DecompEntry *tab_de)
fprintf(f, " 0x%04x,", v);
}
fprintf(f, "\n};\n\n");
free(tab_ce);
}
@ -3005,7 +2929,7 @@ void check_compose_table(void)
}
}
}
}
@ -3045,7 +2969,7 @@ void check_cc_table(void)
#ifdef PROFILE
{
int64_t ti, count;
ti = get_time_ns();
count = 0;
/* only do it on meaningful chars */
@ -3068,7 +2992,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);
@ -3099,7 +3023,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);
@ -3118,24 +3042,22 @@ 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];
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;
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);
}
unicode_db_path = argv[arg++];
unicode_db_path = argv[1];
outfilename = NULL;
if (arg < argc)
outfilename = argv[arg++];
if (argc >= 3)
outfilename = argv[2];
unicode_db = mallocz(sizeof(unicode_db[0]) * (CHARCODE_MAX + 1));
@ -3145,13 +3067,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);
@ -3167,7 +3089,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);
@ -3176,7 +3098,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) {
@ -3195,7 +3117,7 @@ int main(int argc, char *argv[])
} else
{
FILE *fo = fopen(outfilename, "wb");
if (!fo) {
perror(outfilename);
exit(1);
@ -3217,8 +3139,6 @@ 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;