forked from cory/tildefriends
Merge branches/quickjs to trunk. This is the way.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3621 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
80
deps/quickjs/Changelog
vendored
80
deps/quickjs/Changelog
vendored
@ -1,3 +1,83 @@
|
||||
2020-11-08:
|
||||
|
||||
- improved function parameter initializers
|
||||
- added std.setenv(), std.unsetenv() and std.getenviron()
|
||||
- added JS_EvalThis()
|
||||
- misc bug fixes
|
||||
|
||||
2020-09-06:
|
||||
|
||||
- added logical assignment operators
|
||||
- added IsHTMLDDA support
|
||||
- faster for-of loops
|
||||
- os.Worker now takes a module filename as parameter
|
||||
- qjsc: added -D option to compile dynamically loaded modules or workers
|
||||
- misc bug fixes
|
||||
|
||||
2020-07-05:
|
||||
|
||||
- modified JS_GetPrototype() to return a live value
|
||||
- REPL: support unicode characters larger than 16 bits
|
||||
- added os.Worker
|
||||
- improved object serialization
|
||||
- added std.parseExtJSON
|
||||
- misc bug fixes
|
||||
|
||||
2020-04-12:
|
||||
|
||||
- added cross realm support
|
||||
- added AggregateError and Promise.any
|
||||
- added env, uid and gid options in os.exec()
|
||||
- misc bug fixes
|
||||
|
||||
2020-03-16:
|
||||
|
||||
- reworked error handling in std and os libraries: suppressed I/O
|
||||
exceptions in std FILE functions and return a positive errno value
|
||||
when it is explicit
|
||||
- output exception messages to stderr
|
||||
- added std.loadFile(), std.strerror(), std.FILE.prototype.tello()
|
||||
- added JS_GetRuntimeOpaque(), JS_SetRuntimeOpaque(), JS_NewUint32()
|
||||
- updated to Unicode 13.0.0
|
||||
- misc bug fixes
|
||||
|
||||
2020-01-19:
|
||||
|
||||
- keep CONFIG_BIGNUM in the makefile
|
||||
- added os.chdir()
|
||||
- qjs: added -I option
|
||||
- more memory checks in the bignum operations
|
||||
- modified operator overloading semantics to be closer to the TC39
|
||||
proposal
|
||||
- suppressed "use bigint" mode. Simplified "use math" mode
|
||||
- BigDecimal: changed suffix from 'd' to 'm'
|
||||
- misc bug fixes
|
||||
|
||||
2020-01-05:
|
||||
|
||||
- always compile the bignum code. Added '--bignum' option to qjs.
|
||||
- added BigDecimal
|
||||
- added String.prototype.replaceAll
|
||||
- misc bug fixes
|
||||
|
||||
2019-12-21:
|
||||
|
||||
- added nullish coalescing operator (ES2020)
|
||||
- added optional chaining (ES2020)
|
||||
- removed recursions in garbage collector
|
||||
- test stack overflow in the parser
|
||||
- improved backtrace logic
|
||||
- added JS_SetHostPromiseRejectionTracker()
|
||||
- allow exotic constructors
|
||||
- improved c++ compatibility
|
||||
- misc bug fixes
|
||||
|
||||
2019-10-27:
|
||||
|
||||
- added example of C class in a module (examples/test_point.js)
|
||||
- added JS_GetTypedArrayBuffer()
|
||||
- misc bug fixes
|
||||
|
||||
2019-09-18:
|
||||
|
||||
- added os.exec and other system calls
|
||||
|
231
deps/quickjs/Makefile
vendored
231
deps/quickjs/Makefile
vendored
@ -1,8 +1,8 @@
|
||||
#
|
||||
# QuickJS Javascript Engine
|
||||
#
|
||||
# Copyright (c) 2017-2019 Fabrice Bellard
|
||||
# Copyright (c) 2017-2019 Charlie Gordon
|
||||
# Copyright (c) 2017-2020 Fabrice Bellard
|
||||
# Copyright (c) 2017-2020 Charlie Gordon
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@ -47,11 +47,17 @@ prefix=/usr/local
|
||||
#CONFIG_PROFILE=y
|
||||
# use address sanitizer
|
||||
#CONFIG_ASAN=y
|
||||
# include the code for BigInt/BigFloat/BigDecimal and math mode
|
||||
CONFIG_BIGNUM=y
|
||||
|
||||
OBJDIR=.obj
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
CROSS_PREFIX=i686-w64-mingw32-
|
||||
ifdef CONFIG_M32
|
||||
CROSS_PREFIX=i686-w64-mingw32-
|
||||
else
|
||||
CROSS_PREFIX=x86_64-w64-mingw32-
|
||||
endif
|
||||
EXE=.exe
|
||||
else
|
||||
CROSS_PREFIX=
|
||||
@ -94,6 +100,13 @@ ifdef CONFIG_WERROR
|
||||
CFLAGS+=-Werror
|
||||
endif
|
||||
DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\"
|
||||
ifdef CONFIG_BIGNUM
|
||||
DEFINES+=-DCONFIG_BIGNUM
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior
|
||||
endif
|
||||
|
||||
CFLAGS+=$(DEFINES)
|
||||
CFLAGS_DEBUG=$(CFLAGS) -O0
|
||||
CFLAGS_SMALL=$(CFLAGS) -Os
|
||||
@ -110,8 +123,8 @@ CFLAGS+=-p
|
||||
LDFLAGS+=-p
|
||||
endif
|
||||
ifdef CONFIG_ASAN
|
||||
CFLAGS+=-fsanitize=address
|
||||
LDFLAGS+=-fsanitize=address
|
||||
CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer
|
||||
endif
|
||||
ifdef CONFIG_WIN32
|
||||
LDEXPORT=
|
||||
@ -119,26 +132,24 @@ else
|
||||
LDEXPORT=-rdynamic
|
||||
endif
|
||||
|
||||
PROGS=qjs$(EXE) qjsbn$(EXE) qjsc$(EXE) qjsbnc$(EXE) run-test262 run-test262-bn
|
||||
PROGS=qjs$(EXE) qjsc$(EXE) run-test262
|
||||
ifneq ($(CROSS_PREFIX),)
|
||||
QJSC_CC=gcc
|
||||
QJSC=./host-qjsc
|
||||
QJSBNC=./host-qjsbnc
|
||||
PROGS+=$(QJSC) $(QJSBNC)
|
||||
PROGS+=$(QJSC)
|
||||
else
|
||||
QJSC_CC=$(CC)
|
||||
QJSC=./qjsc$(EXE)
|
||||
QJSBNC=./qjsbnc$(EXE)
|
||||
endif
|
||||
ifndef CONFIG_WIN32
|
||||
PROGS+=qjscalc
|
||||
endif
|
||||
ifdef CONFIG_M32
|
||||
PROGS+=qjs32 qjs32_s qjsbn32
|
||||
PROGS+=qjs32 qjs32_s
|
||||
endif
|
||||
PROGS+=libquickjs.a libquickjs.bn.a
|
||||
PROGS+=libquickjs.a
|
||||
ifdef CONFIG_LTO
|
||||
PROGS+=libquickjs.lto.a libquickjs.bn.lto.a
|
||||
PROGS+=libquickjs.lto.a
|
||||
endif
|
||||
|
||||
# examples
|
||||
@ -146,7 +157,10 @@ ifeq ($(CROSS_PREFIX),)
|
||||
ifdef CONFIG_ASAN
|
||||
PROGS+=
|
||||
else
|
||||
PROGS+=examples/hello examples/hello_module examples/c_module
|
||||
PROGS+=examples/hello examples/hello_module examples/test_fib
|
||||
ifndef CONFIG_DARWIN
|
||||
PROGS+=examples/fib.so examples/point.so
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -154,19 +168,20 @@ 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
|
||||
|
||||
QJSBN_LIB_OBJS=$(patsubst %.o, %.bn.o, $(QJS_LIB_OBJS)) $(OBJDIR)/libbf.bn.o
|
||||
|
||||
QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS)
|
||||
ifdef CONFIG_BIGNUM
|
||||
QJS_LIB_OBJS+=$(OBJDIR)/libbf.o
|
||||
QJS_OBJS+=$(OBJDIR)/qjscalc.o
|
||||
endif
|
||||
|
||||
QJSBN_OBJS=$(OBJDIR)/qjs.bn.o $(OBJDIR)/repl-bn.bn.o $(OBJDIR)/qjscalc.bn.o $(QJSBN_LIB_OBJS)
|
||||
|
||||
HOST_LIBS=-lm -ldl -lpthread
|
||||
LIBS=-lm
|
||||
ifndef CONFIG_WIN32
|
||||
LIBS+=-ldl
|
||||
LIBS+=-ldl -lpthread
|
||||
endif
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir -p $(OBJDIR)
|
||||
mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests
|
||||
|
||||
qjs$(EXE): $(QJS_OBJS)
|
||||
$(CC) $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
|
||||
@ -177,18 +192,11 @@ qjs-debug$(EXE): $(patsubst %.o, %.debug.o, $(QJS_OBJS))
|
||||
qjsc$(EXE): $(OBJDIR)/qjsc.o $(QJS_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
qjsbnc$(EXE): $(OBJDIR)/qjsc.bn.o $(QJSBN_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
ifneq ($(CROSS_PREFIX),)
|
||||
|
||||
$(QJSC): $(OBJDIR)/qjsc.host.o \
|
||||
$(patsubst %.o, %.host.o, $(QJS_LIB_OBJS))
|
||||
$(HOST_CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
$(QJSBNC): $(OBJDIR)/qjsc.bn.host.o \
|
||||
$(patsubst %.o, %.host.o, $(QJSBN_LIB_OBJS))
|
||||
$(HOST_CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(HOST_CC) $(LDFLAGS) -o $@ $^ $(HOST_LIBS)
|
||||
|
||||
endif #CROSS_PREFIX
|
||||
|
||||
@ -198,8 +206,8 @@ QJSC_DEFINES+=-DCONFIG_LTO
|
||||
endif
|
||||
QJSC_HOST_DEFINES:=-DCONFIG_CC=\"$(HOST_CC)\" -DCONFIG_PREFIX=\"$(prefix)\"
|
||||
|
||||
$(OBJDIR)/qjsc.o $(OBJDIR)/qjsc.bn.o: CFLAGS+=$(QJSC_DEFINES)
|
||||
$(OBJDIR)/qjsc.host.o $(OBJDIR)/qjsc.bn.host.o: CFLAGS+=$(QJSC_HOST_DEFINES)
|
||||
$(OBJDIR)/qjsc.o: CFLAGS+=$(QJSC_DEFINES)
|
||||
$(OBJDIR)/qjsc.host.o: CFLAGS+=$(QJSC_HOST_DEFINES)
|
||||
|
||||
qjs32: $(patsubst %.o, %.m32.o, $(QJS_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
|
||||
@ -208,18 +216,9 @@ qjs32_s: $(patsubst %.o, %.m32s.o, $(QJS_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
@size $@
|
||||
|
||||
qjsbn$(EXE): $(QJSBN_OBJS)
|
||||
$(CC) $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
|
||||
|
||||
qjsbn32: $(patsubst %.o, %.m32.o, $(QJSBN_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)
|
||||
|
||||
qjscalc: qjsbn
|
||||
qjscalc: qjs
|
||||
ln -sf $< $@
|
||||
|
||||
qjsbn-debug$(EXE): $(patsubst %.o, %.debug.o, $(QJSBN_OBJS))
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
ifdef CONFIG_LTO
|
||||
LTOEXT=.lto
|
||||
else
|
||||
@ -229,50 +228,35 @@ endif
|
||||
libquickjs$(LTOEXT).a: $(QJS_LIB_OBJS)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
libquickjs.bn$(LTOEXT).a: $(QJSBN_LIB_OBJS)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
ifdef CONFIG_LTO
|
||||
libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS))
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
libquickjs.bn.a: $(patsubst %.o, %.nolto.o, $(QJSBN_LIB_OBJS))
|
||||
$(AR) rcs $@ $^
|
||||
endif # CONFIG_LTO
|
||||
|
||||
repl.c: $(QJSC) repl.js
|
||||
repl.c: $(QJSC) repl.js
|
||||
$(QJSC) -c -o $@ -m repl.js
|
||||
|
||||
repl-bn.c: $(QJSBNC) repl.js
|
||||
$(QJSBNC) -c -o $@ -m repl.js
|
||||
|
||||
qjscalc.c: $(QJSBNC) qjscalc.js
|
||||
$(QJSBNC) -c -o $@ qjscalc.js
|
||||
qjscalc.c: $(QJSC) qjscalc.js
|
||||
$(QJSC) -fbignum -c -o $@ qjscalc.js
|
||||
|
||||
ifneq ($(wildcard unicode/UnicodeData.txt),)
|
||||
$(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o $(OBJDIR)/libunicode.bn.o $(OBJDIR)/libunicode.bn.m32.o \
|
||||
$(OBJDIR)/libunicode.nolto.o $(OBJDIR)/libunicode.bn.nolto.o: libunicode-table.h
|
||||
$(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o \
|
||||
$(OBJDIR)/libunicode.nolto.o: libunicode-table.h
|
||||
|
||||
libunicode-table.h: unicode_gen
|
||||
./unicode_gen unicode $@
|
||||
endif
|
||||
|
||||
run-test262: $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
|
||||
|
||||
run-test262-bn: $(OBJDIR)/run-test262.bn.o $(QJSBN_LIB_OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
run-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
run-test262-32: $(patsubst %.o, %.m32.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
|
||||
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
run-test262-bn32: $(patsubst %.o, %.m32.o, $(OBJDIR)/run-test262.bn.o $(QJSBN_LIB_OBJS))
|
||||
$(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
|
||||
|
||||
# object suffix order: bn, nolto, [m32|m32s]
|
||||
# object suffix order: nolto, [m32|m32s]
|
||||
|
||||
$(OBJDIR)/%.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_OPT) -c -o $@ $<
|
||||
@ -283,61 +267,44 @@ $(OBJDIR)/%.host.o: %.c | $(OBJDIR)
|
||||
$(OBJDIR)/%.pic.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_OPT) -fPIC -DJS_SHARED_LIBRARY -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.bn.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_OPT) -DCONFIG_BIGNUM -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.bn.host.o: %.c | $(OBJDIR)
|
||||
$(HOST_CC) $(CFLAGS_OPT) -DCONFIG_BIGNUM -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.nolto.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_NOLTO) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.bn.nolto.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_NOLTO) -DCONFIG_BIGNUM -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.m32.o: %.c | $(OBJDIR)
|
||||
$(CC) -m32 $(CFLAGS_OPT) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.m32s.o: %.c | $(OBJDIR)
|
||||
$(CC) -m32 $(CFLAGS_SMALL) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.bn.m32.o: %.c | $(OBJDIR)
|
||||
$(CC) -m32 $(CFLAGS_OPT) -DCONFIG_BIGNUM -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.debug.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_DEBUG) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.bn.debug.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS_DEBUG) -DCONFIG_BIGNUM -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.check.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -DCONFIG_CHECK_JSVALUE -c -o $@ $<
|
||||
|
||||
regexp_test: libregexp.c libunicode.c cutils.c
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -DTEST -o $@ libregexp.c libunicode.c cutils.c $(LIBS)
|
||||
|
||||
jscompress: jscompress.c
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ jscompress.c
|
||||
|
||||
unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c unicode_gen_def.h
|
||||
$(HOST_CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o
|
||||
|
||||
clean:
|
||||
rm -f repl.c repl-bn.c qjscalc.c out.c
|
||||
rm -f *.a *.so *.o *.d *~ jscompress unicode_gen regexp_test $(PROGS)
|
||||
rm -f hello.c hello_module.c c_module.c
|
||||
rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug qjsbn-debug
|
||||
rm -rf run-test262-debug run-test262-32 run-test262-bn32
|
||||
rm -f repl.c qjscalc.c out.c
|
||||
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
|
||||
|
||||
install: all
|
||||
mkdir -p "$(DESTDIR)$(prefix)/bin"
|
||||
$(STRIP) qjs qjsbn qjsc qjsbnc
|
||||
install -m755 qjs qjsbn qjsc qjsbnc "$(DESTDIR)$(prefix)/bin"
|
||||
ln -sf qjsbn "$(DESTDIR)$(prefix)/bin/qjscalc"
|
||||
$(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 libquickjs.bn.a "$(DESTDIR)$(prefix)/lib/quickjs"
|
||||
install -m644 libquickjs.a "$(DESTDIR)$(prefix)/lib/quickjs"
|
||||
ifdef CONFIG_LTO
|
||||
install -m644 libquickjs.lto.a libquickjs.bn.lto.a "$(DESTDIR)$(prefix)/lib/quickjs"
|
||||
install -m644 libquickjs.lto.a "$(DESTDIR)$(prefix)/lib/quickjs"
|
||||
endif
|
||||
mkdir -p "$(DESTDIR)$(prefix)/include/quickjs"
|
||||
install -m644 quickjs.h quickjs-libc.h "$(DESTDIR)$(prefix)/include/quickjs"
|
||||
@ -350,6 +317,9 @@ HELLO_SRCS=examples/hello.js
|
||||
HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \
|
||||
-fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \
|
||||
-fno-date -fno-module-loader
|
||||
ifdef CONFIG_BIGNUM
|
||||
HELLO_OPTS+=-fno-bigint
|
||||
endif
|
||||
|
||||
hello.c: $(QJSC) $(HELLO_SRCS)
|
||||
$(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS)
|
||||
@ -372,14 +342,17 @@ examples/hello_module: $(QJSC) libquickjs$(LTOEXT).a $(HELLO_MODULE_SRCS)
|
||||
|
||||
# use of an external C module (static compilation)
|
||||
|
||||
c_module.c: $(QJSC) examples/c_module.js
|
||||
$(QJSC) -e -M examples/fib.so,fib -m -o $@ examples/c_module.js
|
||||
test_fib.c: $(QJSC) examples/test_fib.js
|
||||
$(QJSC) -e -M examples/fib.so,fib -m -o $@ examples/test_fib.js
|
||||
|
||||
examples/c_module: $(OBJDIR)/c_module.o $(OBJDIR)/fib.o libquickjs$(LTOEXT).a
|
||||
examples/test_fib: $(OBJDIR)/test_fib.o $(OBJDIR)/examples/fib.o libquickjs$(LTOEXT).a
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
$(OBJDIR)/fib.o: examples/fib.c
|
||||
$(CC) $(CFLAGS_OPT) -c -o $@ $<
|
||||
examples/fib.so: $(OBJDIR)/examples/fib.pic.o
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^
|
||||
|
||||
examples/point.so: $(OBJDIR)/examples/point.pic.o
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^
|
||||
|
||||
###############################################################################
|
||||
# documentation
|
||||
@ -404,47 +377,55 @@ doc/%.html: doc/%.html.pre
|
||||
# tests
|
||||
|
||||
ifndef CONFIG_DARWIN
|
||||
test: bjson.so
|
||||
test: tests/bjson.so examples/point.so
|
||||
endif
|
||||
ifdef CONFIG_M32
|
||||
test: qjs32
|
||||
endif
|
||||
|
||||
test: qjs qjsbn
|
||||
test: qjs
|
||||
./qjs tests/test_closure.js
|
||||
./qjs tests/test_op.js
|
||||
./qjs tests/test_language.js
|
||||
./qjs tests/test_builtin.js
|
||||
./qjs tests/test_loop.js
|
||||
./qjs tests/test_std.js
|
||||
./qjs tests/test_worker.js
|
||||
ifndef CONFIG_DARWIN
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs --bignum tests/test_bjson.js
|
||||
else
|
||||
./qjs tests/test_bjson.js
|
||||
endif
|
||||
./qjsbn tests/test_closure.js
|
||||
./qjsbn tests/test_op.js
|
||||
./qjsbn tests/test_builtin.js
|
||||
./qjsbn tests/test_loop.js
|
||||
./qjsbn tests/test_std.js
|
||||
./qjsbn --qjscalc tests/test_bignum.js
|
||||
|
||||
test-32: qjs32 qjsbn32
|
||||
./qjs examples/test_point.js
|
||||
endif
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs --bignum tests/test_op_overloading.js
|
||||
./qjs --bignum tests/test_bignum.js
|
||||
./qjs --qjscalc tests/test_qjscalc.js
|
||||
endif
|
||||
ifdef CONFIG_M32
|
||||
./qjs32 tests/test_closure.js
|
||||
./qjs32 tests/test_op.js
|
||||
./qjs32 tests/test_language.js
|
||||
./qjs32 tests/test_builtin.js
|
||||
./qjs32 tests/test_loop.js
|
||||
./qjs32 tests/test_std.js
|
||||
./qjsbn32 tests/test_closure.js
|
||||
./qjsbn32 tests/test_op.js
|
||||
./qjsbn32 tests/test_builtin.js
|
||||
./qjsbn32 tests/test_loop.js
|
||||
./qjsbn32 tests/test_std.js
|
||||
./qjsbn32 --qjscalc tests/test_bignum.js
|
||||
./qjs32 tests/test_worker.js
|
||||
ifdef CONFIG_BIGNUM
|
||||
./qjs32 --bignum tests/test_op_overloading.js
|
||||
./qjs32 --bignum tests/test_bignum.js
|
||||
./qjs32 --qjscalc tests/test_qjscalc.js
|
||||
endif
|
||||
endif
|
||||
|
||||
stats: qjs qjs32
|
||||
./qjs -qd
|
||||
./qjs32 -qd
|
||||
|
||||
microbench: qjs
|
||||
./qjs --std tests/microbench.js
|
||||
./qjs tests/microbench.js
|
||||
|
||||
microbench-32: qjs32
|
||||
./qjs32 --std tests/microbench.js
|
||||
./qjs32 tests/microbench.js
|
||||
|
||||
# ES5 tests (obsolete)
|
||||
test2o: run-test262
|
||||
@ -472,27 +453,17 @@ test2-update: run-test262
|
||||
test2-check: run-test262
|
||||
time ./run-test262 -m -c test262.conf -E -a
|
||||
|
||||
# Test262 + BigInt tests
|
||||
test2bn-default: run-test262-bn
|
||||
time ./run-test262-bn -m -c test262bn.conf
|
||||
testall: all test microbench test2o test2
|
||||
|
||||
test2bn: run-test262-bn
|
||||
time ./run-test262-bn -m -c test262bn.conf -a
|
||||
|
||||
test2bn-32: run-test262-bn32
|
||||
time ./run-test262-bn32 -m -c test262bn.conf -a
|
||||
|
||||
testall: all test microbench test2o test2 test2bn
|
||||
|
||||
testall-32: all test-32 microbench-32 test2o-32 test2-32 test2bn-32
|
||||
testall-32: all test-32 microbench-32 test2o-32 test2-32
|
||||
|
||||
testall-complete: testall testall-32
|
||||
|
||||
bench-v8: qjs qjs32
|
||||
bench-v8: qjs
|
||||
make -C tests/bench-v8
|
||||
./qjs -d tests/bench-v8/combined.js
|
||||
|
||||
bjson.so: $(OBJDIR)/bjson.pic.o
|
||||
tests/bjson.so: $(OBJDIR)/tests/bjson.pic.o
|
||||
$(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS)
|
||||
|
||||
-include $(wildcard $(OBJDIR)/*.d)
|
||||
|
74
deps/quickjs/TODO
vendored
74
deps/quickjs/TODO
vendored
@ -1,29 +1,48 @@
|
||||
- 64-bit atoms in 64-bit mode?
|
||||
- rename CONFIG_ALL_UNICODE, CONFIG_BIGNUM, CONFIG_ATOMICS, CONFIG_CHECK_JSVALUE ?
|
||||
Bugs:
|
||||
- modules: better error handling with cyclic module references
|
||||
|
||||
Misc ideas:
|
||||
- use custom printf to avoid compatibility issues with floating point numbers
|
||||
- consistent naming for preprocessor defines
|
||||
- unify coding style and naming conventions
|
||||
- use names from the ECMA spec in library implementation
|
||||
- modules: if no ".", use a well known module loading path ?
|
||||
- use JSHoistedDef only for global variables (JSHoistedDef.var_name != JS_ATOM_NULL)
|
||||
- add index in JSVarDef and is_arg flag to merge args and vars in JSFunctionDef
|
||||
- replace most JSVarDef flags with var_type enumeration
|
||||
- use byte code emitters with typed arguments (for clarity)
|
||||
- use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing
|
||||
and use the same wrappers in all phases
|
||||
- use more generic method for line numbers in resolve_variables and resolve_labels
|
||||
- use custom timezone support to avoid C library compatibility issues
|
||||
|
||||
Memory:
|
||||
- use memory pools for objects, etc?
|
||||
- test border cases for max number of atoms, object properties, string length
|
||||
- add emergency malloc mode for out of memory exceptions.
|
||||
- test all DynBuf memory errors
|
||||
- test all js_realloc memory errors
|
||||
- bignum: handle memory errors
|
||||
- use memory pools for objects, etc?
|
||||
- improve JS_ComputeMemoryUsage() with more info
|
||||
|
||||
Optimizations:
|
||||
- use auto-init properties for more global objects
|
||||
Built-in standard library:
|
||||
- BSD sockets
|
||||
- modules: use realpath in module name normalizer and put it in quickjs-libc
|
||||
- modules: if no ".", use a well known module loading path ?
|
||||
- get rid of __loadScript, use more common name
|
||||
|
||||
REPL:
|
||||
- debugger
|
||||
- readline: support MS Windows terminal
|
||||
- readline: handle dynamic terminal resizing
|
||||
- readline: handle double width unicode characters
|
||||
- multiline editing
|
||||
- runtime object and function inspectors
|
||||
- interactive object browser
|
||||
- use more generic approach to display evaluation results
|
||||
- improve directive handling: dispatch, colorize, completion...
|
||||
- save history
|
||||
- close all predefined methods in repl.js and jscalc.js
|
||||
|
||||
Optimization ideas:
|
||||
- 64-bit atoms in 64-bit mode ?
|
||||
- 64-bit small bigint in 64-bit mode ?
|
||||
- reuse stack slots for disjoint scopes, if strip
|
||||
- optimize `for of` iterator for built-in array objects
|
||||
- add heuristic to avoid some cycles in closures
|
||||
- small String (0-2 charcodes) with immediate storage
|
||||
- perform static string concatenation at compile time
|
||||
@ -32,49 +51,20 @@ Optimizations:
|
||||
- optimize `s += a + b`, `s += a.b` and similar simple expressions
|
||||
- ensure string canonical representation and optimise comparisons and hashes?
|
||||
- remove JSObject.first_weak_ref, use bit+context based hashed array for weak references
|
||||
- optimize function storage with length and name accessors?
|
||||
- property access optimization on the global object, functions,
|
||||
prototypes and special non extensible objects.
|
||||
- create object literals with the correct length by backpatching length argument
|
||||
- remove redundant set_loc_uninitialized/check_uninitialized opcodes
|
||||
- peephole optim: push_atom_value, to_propkey -> push_atom_value
|
||||
- peephole optim: put_loc x, get_loc_check x -> set_loc x
|
||||
- comparative performance benchmark
|
||||
- use variable name when throwing uninitialized exception if available
|
||||
- convert slow array to fast array when all properties != length are numeric
|
||||
- optimize destructuring assignments for global and local variables
|
||||
- implement some form of tail-call-optimization
|
||||
- debugger keyword support
|
||||
- optimize OP_apply
|
||||
- optimize f(...b)
|
||||
|
||||
Extensions:
|
||||
- support more features in [features] section
|
||||
- add built-in preprocessor in compiler, get rid of jscompress
|
||||
handle #if, #ifdef, #line, limited support for #define
|
||||
- limited support for web assembly
|
||||
- get rid of __loadScript, use more common name
|
||||
- BSD sockets
|
||||
- Process or thread control
|
||||
- use custom printf to avoid C library compatibility issues
|
||||
- use custom timezone support to avoid C library compatibility issues
|
||||
|
||||
REPL:
|
||||
- strip internal functions from stack trace
|
||||
- readline: support MS Windows terminal
|
||||
- readline: handle dynamic terminal resizing
|
||||
- multiline editing
|
||||
- debugger
|
||||
- runtime object and function inspectors
|
||||
- interactive object browser
|
||||
- use more generic approach to display evaluation results
|
||||
- improve directive handling: dispatch, colorize, completion...
|
||||
- save history
|
||||
- close all predefined methods in repl.js and jscalc.js
|
||||
|
||||
Test262o: 0/11262 errors, 463 excluded
|
||||
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
|
||||
|
||||
Test262: 2/67351 errors, 839 excluded, 1370 skipped
|
||||
Test262bn: 2/69452 errors, 772 excluded, 383 skipped
|
||||
test262 commit: d65b9b35be091147edf31ec527a47cb95a327217
|
||||
Result: 51/75119 errors, 899 excluded, 570 skipped
|
||||
Test262 commit: 1c33fdb0ca60fb9d7392403be769ed0d26209132
|
||||
|
2
deps/quickjs/VERSION
vendored
2
deps/quickjs/VERSION
vendored
@ -1 +1 @@
|
||||
2019-09-18
|
||||
2020-11-08
|
||||
|
21
deps/quickjs/cutils.c
vendored
21
deps/quickjs/cutils.c
vendored
@ -258,19 +258,30 @@ int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
|
||||
return c;
|
||||
}
|
||||
switch(c) {
|
||||
case 0xc0 ... 0xdf:
|
||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
|
||||
case 0xc4: case 0xc5: case 0xc6: case 0xc7:
|
||||
case 0xc8: case 0xc9: case 0xca: case 0xcb:
|
||||
case 0xcc: case 0xcd: case 0xce: case 0xcf:
|
||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
|
||||
case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||
case 0xd8: case 0xd9: case 0xda: case 0xdb:
|
||||
case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||
l = 1;
|
||||
break;
|
||||
case 0xe0 ... 0xef:
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
|
||||
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb:
|
||||
case 0xec: case 0xed: case 0xee: case 0xef:
|
||||
l = 2;
|
||||
break;
|
||||
case 0xf0 ... 0xf7:
|
||||
case 0xf0: case 0xf1: case 0xf2: case 0xf3:
|
||||
case 0xf4: case 0xf5: case 0xf6: case 0xf7:
|
||||
l = 3;
|
||||
break;
|
||||
case 0xf8 ... 0xfb:
|
||||
case 0xf8: case 0xf9: case 0xfa: case 0xfb:
|
||||
l = 4;
|
||||
break;
|
||||
case 0xfc ... 0xfd:
|
||||
case 0xfc: case 0xfd:
|
||||
l = 5;
|
||||
break;
|
||||
default:
|
||||
|
4
deps/quickjs/cutils.h
vendored
4
deps/quickjs/cutils.h
vendored
@ -268,6 +268,10 @@ void dbuf_free(DynBuf *s);
|
||||
static inline BOOL dbuf_error(DynBuf *s) {
|
||||
return s->error;
|
||||
}
|
||||
static inline void dbuf_set_error(DynBuf *s)
|
||||
{
|
||||
s->error = TRUE;
|
||||
}
|
||||
|
||||
#define UTF8_CHAR_LEN_MAX 6
|
||||
|
||||
|
807
deps/quickjs/doc/jsbignum.html
vendored
807
deps/quickjs/doc/jsbignum.html
vendored
File diff suppressed because it is too large
Load Diff
BIN
deps/quickjs/doc/jsbignum.pdf
vendored
BIN
deps/quickjs/doc/jsbignum.pdf
vendored
Binary file not shown.
656
deps/quickjs/doc/jsbignum.texi
vendored
656
deps/quickjs/doc/jsbignum.texi
vendored
@ -10,12 +10,12 @@
|
||||
@sp 7
|
||||
@center @titlefont{Javascript Bignum Extensions}
|
||||
@sp 3
|
||||
@center Version 2018-06-16
|
||||
@center Version 2020-01-11
|
||||
@sp 3
|
||||
@center Author: Fabrice Bellard
|
||||
@end titlepage
|
||||
|
||||
@setfilename spec.info
|
||||
@setfilename jsbignum.info
|
||||
@settitle Javascript Bignum Extensions
|
||||
|
||||
@contents
|
||||
@ -27,347 +27,51 @@ language while being 100% backward compatible:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Overloading of the standard operators
|
||||
to support new types such as complex numbers, fractions or matrixes.
|
||||
|
||||
@item Bigint mode where arbitrarily large integers are available by default (no @code{n} suffix is necessary as in the TC39 BigInt proposal@footnote{@url{https://tc39.github.io/proposal-bigint/}}).
|
||||
@item Operator overloading with a dispatch logic inspired from the proposal available at @url{https://github.com/tc39/proposal-operator-overloading/}.
|
||||
|
||||
@item Arbitrarily large floating point numbers (@code{BigFloat}) in base 2 using the IEEE 754 semantics.
|
||||
|
||||
@item Optional @code{math} mode which modifies the semantics of the division, modulo and power operator. The division and power operator return a fraction with integer operands and the modulo operator is defined as the Euclidian remainder.
|
||||
@item Arbitrarily large floating point numbers (@code{BigDecimal}) in base 10 based on the proposal available at
|
||||
@url{https://github.com/littledan/proposal-bigdecimal}.
|
||||
|
||||
@item @code{math} mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (@code{%}) is defined as the Euclidian
|
||||
remainder. @code{^} is an alias to the power operator
|
||||
(@code{**}). @code{^^} is used as the exclusive or operator.
|
||||
|
||||
@end itemize
|
||||
|
||||
The extensions are independent from each other except the @code{math}
|
||||
mode which relies on the bigint mode and the operator overloading.
|
||||
mode which relies on BigFloat and operator overloading.
|
||||
|
||||
@chapter Operator overloading
|
||||
|
||||
@section Introduction
|
||||
Operator overloading is inspired from the proposal available at
|
||||
@url{https://github.com/tc39/proposal-operator-overloading/}. It
|
||||
implements the same dispatch logic but finds the operator sets by
|
||||
looking at the @code{Symbol.operatorSet} property in the objects. The
|
||||
changes were done in order to simplify the implementation.
|
||||
|
||||
If the operands of an operator have at least one object type, a custom
|
||||
operator method is searched before doing the legacy Javascript
|
||||
@code{ToNumber} conversion.
|
||||
|
||||
For unary operators, the custom function is looked up in the object
|
||||
and has the following name:
|
||||
|
||||
@table @code
|
||||
@item unary +
|
||||
@code{Symbol.operatorPlus}
|
||||
|
||||
@item unary -
|
||||
@code{Symbol.operatorNeg}
|
||||
|
||||
@item ++
|
||||
@code{Symbol.operatorInc}
|
||||
|
||||
@item --
|
||||
@code{Symbol.operatorDec}
|
||||
|
||||
@item ~
|
||||
@code{Symbol.operatorNot}
|
||||
|
||||
@end table
|
||||
|
||||
For binary operators:
|
||||
More precisely, the following modifications were made:
|
||||
|
||||
@itemize
|
||||
|
||||
@item
|
||||
If both operands have the same constructor function, then the operator
|
||||
is looked up in the constructor.
|
||||
@item @code{with operators from} is not supported. Operator overloading is always enabled.
|
||||
|
||||
@item
|
||||
Otherwise, the property @code{Symbol.operatorOrder} is looked up in both
|
||||
constructors and converted to @code{Int32}. The operator is then
|
||||
looked in the constructor with the larger @code{Symbol.operatorOrder}
|
||||
value. A @code{TypeError} is raised if both constructors have the same
|
||||
@code{Symbol.operatorOrder} value.
|
||||
@item The dispatch is not based on a static @code{[[OperatorSet]]} field in all instances. Instead, a dynamic lookup of the @code{Symbol.operatorSet} property is done. This property is typically added in the prototype of each object.
|
||||
|
||||
@item @code{Operators.create(...dictionaries)} is used to create a new OperatorSet object. The @code{Operators} function is supported as an helper to be closer to the TC39 proposal.
|
||||
|
||||
@item @code{[]} cannot be overloaded.
|
||||
|
||||
@item In math mode, the BigInt division and power operators can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
|
||||
|
||||
@end itemize
|
||||
|
||||
The operator is looked up with the following name:
|
||||
@chapter BigInt extensions
|
||||
|
||||
A few properties are added to the BigInt object:
|
||||
|
||||
@table @code
|
||||
@item +
|
||||
@code{Symbol.operatorAdd}
|
||||
|
||||
@item -
|
||||
@code{Symbol.operatorSub}
|
||||
|
||||
@item *
|
||||
@code{Symbol.operatorMul}
|
||||
|
||||
@item /
|
||||
@code{Symbol.operatorDiv}
|
||||
|
||||
@item %
|
||||
@code{Symbol.operatorMod}
|
||||
|
||||
@item % (math mode)
|
||||
@code{Symbol.operatorMathMod}
|
||||
|
||||
@item **
|
||||
@code{Symbol.operatorPow}
|
||||
|
||||
@item |
|
||||
@code{Symbol.operatorOr}
|
||||
|
||||
@item ^
|
||||
@code{Symbol.operatorXor}
|
||||
|
||||
@item &
|
||||
@code{Symbol.operatorAnd}
|
||||
|
||||
@item <<
|
||||
@code{Symbol.operatorShl}
|
||||
|
||||
@item >>
|
||||
@code{Symbol.operatorShr}
|
||||
|
||||
@item <
|
||||
@code{Symbol.operatorCmpLT}
|
||||
|
||||
@item >
|
||||
@code{Symbol.operatorCmpLT}, operands swapped
|
||||
|
||||
@item <=
|
||||
@code{Symbol.operatorCmpLE}
|
||||
|
||||
@item >=
|
||||
@code{Symbol.operatorCmpLE}, operands swapped
|
||||
|
||||
@item ==, !=
|
||||
@code{Symbol.operatorCmpEQ}
|
||||
|
||||
@end table
|
||||
|
||||
The return value of @code{Symbol.operatorCmpLT}, @code{Symbol.operatorCmpLE} and
|
||||
@code{Symbol.operatorCmpEQ} is converted to @code{Boolean}.
|
||||
|
||||
@section Builtin Object changes
|
||||
|
||||
@subsection @code{Symbol} constructor
|
||||
|
||||
The following global symbols are added for the operator overloading:
|
||||
@table @code
|
||||
@item operatorOrder
|
||||
@item operatorAdd
|
||||
@item operatorSub
|
||||
@item operatorMul
|
||||
@item operatorDiv
|
||||
@item operatorMod
|
||||
@item operatorPow
|
||||
@item operatorShl
|
||||
@item operatorShr
|
||||
@item operatorAnd
|
||||
@item operatorOr
|
||||
@item operatorXor
|
||||
@item operatorCmpLT
|
||||
@item operatorCmpLE
|
||||
@item operatorCmpEQ
|
||||
@item operatorPlus
|
||||
@item operatorNeg
|
||||
@item operatorNot
|
||||
@item operatorInc
|
||||
@item operatorDec
|
||||
@end table
|
||||
|
||||
|
||||
@chapter The BigInt Mode
|
||||
|
||||
@section Introduction
|
||||
|
||||
The bigint mode is enabled with the @code{"use bigint"} directive. It
|
||||
propagates the same way as the strict mode. In bigint mode, all
|
||||
integers are considered as @code{bigint} (arbitrarily large integer,
|
||||
similar to the TC39 BigInt
|
||||
proposal@footnote{@url{https://tc39.github.io/proposal-bigint/}})
|
||||
instead of @code{number} (floating point number). In order to be able
|
||||
to exchange data between standard and bigint modes, numbers are
|
||||
internally represented as 3 different types:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Small integer (SmallInt): 32 bit integer@footnote{Could be extended to 53 bits without changing the principle.}.
|
||||
|
||||
@item Big integer (BigInt): arbitrarily large integer.
|
||||
|
||||
@item Floating point number (Float).
|
||||
|
||||
@end itemize
|
||||
|
||||
In standard mode, the semantics of each operation is modified so that
|
||||
when it returns a @code{number}, it is either of SmallInt or
|
||||
Float. But the difference between SmallInt and Float is not observable
|
||||
in standard mode.
|
||||
|
||||
In bigint mode, each operation behaves differently whether its
|
||||
operands are integer or float. The difference between SmallInt and
|
||||
BigInt is not observable (i.e. they are both integers).
|
||||
|
||||
The following table summarizes the observable types:
|
||||
|
||||
@multitable @columnfractions .3 .3 .3
|
||||
@headitem Internal type @tab Observable type@* (standard mode) @tab Observable type@* (bigint mode)
|
||||
@item SmallInt @tab number @tab bigint
|
||||
@item BigInt @tab bigint @tab bigint
|
||||
@item Float @tab number @tab number
|
||||
@end multitable
|
||||
|
||||
@section Changes that introduce incompatibilities with Javascript
|
||||
|
||||
@subsection Standard mode
|
||||
|
||||
There is no incompatibility with Javascript.
|
||||
|
||||
@subsection Bigint mode
|
||||
|
||||
The following changes are visible:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Integer and Float are different types. Constants are typed. For example: @code{typeof 1.0 === "number"} and @code{typeof 1 === "bigint"}. Another consequence is that @code{1.0 === 1} is false.
|
||||
|
||||
@item The range of integers is unlimited. In standard mode: @code{2**53 + 1 === 2**53}. This is no longer true with the bignum extensions.
|
||||
|
||||
@item Binary bitwise operators do not truncate to 32 bits i.e. @code{0x800000000 | 1 === 0x800000001} while it gives @code{1} in standard mode.
|
||||
|
||||
@item Bitwise shift operators do not truncate to 32 bits and do not mask the shift count with @code{0x1f} i.e. @code{1 << 32 === 4294967296} while it gives @code{1} in standard mode. However, the @code{>>>} operator (unsigned right shift) which is useless with bignums keeps its standard mode behavior@footnote{The unsigned right right operator could be removed in bigint mode.}.
|
||||
|
||||
@item Operators with integer operands never return the minus zero floating point value as result. Hence @code{Object.is(0, -0) === true}. Use @code{-0.0} to create a minus zero floating point value.
|
||||
|
||||
@item The @code{ToPrimitive} abstract operation is called with the @code{"integer"} preferred type when an integer is required (e.g. for bitwise binary or shift operations).
|
||||
|
||||
@item The prototype of integers is no longer @code{Number.prototype}. Instead@* @code{Object.getPrototypeOf(1) === BigInt.prototype}. The prototype of floats remains Number.prototype.
|
||||
|
||||
@item If the TC39 BigInt proposal is supported, there is no observable difference between integers and @code{bigint}s.
|
||||
|
||||
@end itemize
|
||||
|
||||
@section Operators
|
||||
|
||||
@subsection Arithmetic operators
|
||||
|
||||
The operands are converted to number values as in normal
|
||||
Javascript. Then the general case is that an Integer is returned if
|
||||
both operands are Integer. Otherwise, a float is returned.
|
||||
|
||||
The @code{+} operator also accepts strings as input and behaves like
|
||||
standard Javascript in this case.
|
||||
|
||||
The binary operator @code{%} returns the truncated remainder of the
|
||||
division. When the result is an Integer type, a dividend of zero yields a
|
||||
RangeError exception.
|
||||
|
||||
The binary operator @code{%} in math mode returns the Euclidian
|
||||
remainder of the division i.e. it is always positive.
|
||||
|
||||
The binary operator @code{/} returns a float.
|
||||
|
||||
The binary operator @code{/} in math mode returns a float if one of
|
||||
the operands is float. Otherwise, @code{BigInt[Symbol.operatorDiv]} is
|
||||
invoked.
|
||||
|
||||
The returned type of @code{a ** b} is Float if @math{a} or @math{b}
|
||||
are Float. If @math{a} and @math{b} are integers:
|
||||
@itemize
|
||||
@item @math{b < 0} returns a Float in bigint mode. In math mode, @code{BigInt[Symbol.operatorPow]} is invoked.
|
||||
|
||||
@item @math{b >= 0} returns an integer.
|
||||
@end itemize
|
||||
|
||||
The unary @code{-} and unary @code{+} return the same type as their
|
||||
operand. They performs no floating point rounding when the result is a
|
||||
float.
|
||||
|
||||
The unary operators @code{++} and @code{--} return the same type as
|
||||
their operand.
|
||||
|
||||
In standard mode:
|
||||
|
||||
If the operator returns an Integer and that the result fits a
|
||||
SmallInt, it is converted to SmallInt. Otherwise, the Integer is
|
||||
converted to a Float.
|
||||
|
||||
In bigint mode:
|
||||
|
||||
If the operator returns an Integer and that the result fits a
|
||||
SmallInt, it is converted to SmallInt. Otherwise it is a BigInt.
|
||||
|
||||
@subsection Logical operators
|
||||
|
||||
In standard mode:
|
||||
|
||||
The operands have their standard behavior. If the result fits a
|
||||
SmallInt it is converted to a SmallInt. Otherwise it is a Float.
|
||||
|
||||
In bigint mode:
|
||||
|
||||
The operands are converted to integer values. The floating point
|
||||
values are converted to integer by rounding them to zero.
|
||||
|
||||
The logical operators are defined assuming the integers are
|
||||
represented in two complement notation.
|
||||
|
||||
For @code{<<} and @code{<<}, the shift can be positive or negative. So
|
||||
@code{a << b} is defined as @math{\lfloor a/2^{-b} \rfloor} and
|
||||
@code{a >> b} is defined as @math{\lfloor a/2^{b} \rfloor}.
|
||||
|
||||
The operator @code{>>>} is supported for backward compatibility and
|
||||
behaves the same way as Javascript i.e. implicit conversion to @code{Uint32}.
|
||||
|
||||
If the result fits a SmallInt it is converted to a SmallInt. Otherwise
|
||||
it is a BigInt.
|
||||
|
||||
@subsection Relational operators
|
||||
|
||||
The relational operators <, <=, >, >=, ==, != work as expected with
|
||||
integers and floating point numbers (e.g. @code{1.0 == 1} is true).
|
||||
|
||||
The strict equality operators === and !== have the usual Javascript
|
||||
semantics. In particular, different types never equal, so @code{1.0
|
||||
=== 1} is false.
|
||||
|
||||
@section Number literals
|
||||
|
||||
Number literals in bigint mode have a slightly different behavior than
|
||||
in standard Javascript:
|
||||
|
||||
@enumerate
|
||||
|
||||
@item
|
||||
A number literal without a decimal point or an exponent is considered
|
||||
as an Integer. Otherwise it is a Float.
|
||||
|
||||
@item
|
||||
Hexadecimal, octal or binary floating point literals are accepted with
|
||||
a decimal point or an exponent. The exponent is specified with the
|
||||
@code{p} letter assuming a base 2. The same convention is used by
|
||||
C99. Example: @code{0x1p3} is the same as @code{8.0}.
|
||||
|
||||
@end enumerate
|
||||
|
||||
@section Builtin Object changes
|
||||
|
||||
@subsection @code{BigInt} function
|
||||
|
||||
The @code{BigInt} function cannot be invoked as a constructor. When
|
||||
invoked as a function, it converts its first parameter to an
|
||||
integer. When a floating point number is given as parameter, it is
|
||||
truncated to an integer with infinite precision.
|
||||
|
||||
@code{BigInt} properties:
|
||||
|
||||
@table @code
|
||||
|
||||
@item asIntN(bits, a)
|
||||
Set @math{b=a \pmod{2^{bits}}}. Return @math{b} if @math{b < 2^{bits-1}}
|
||||
otherwise @math{b-2^{bits}}.
|
||||
|
||||
@item asUintN(bits, a)
|
||||
Return @math{a \pmod{2^{bits}}}.
|
||||
|
||||
@item tdiv(a, b)
|
||||
Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError
|
||||
@ -410,63 +114,12 @@ Return the number of trailing zeros in the two's complement binary representatio
|
||||
|
||||
@end table
|
||||
|
||||
@subsection @code{BigInt.prototype}
|
||||
|
||||
It is a normal object.
|
||||
|
||||
@subsection @code{Number} constructor
|
||||
|
||||
The number constructor returns its argument rounded to a Float using
|
||||
the global floating point environement. In bigint mode, the Number
|
||||
constructor returns a Float. In standard mode, it returns a SmallInt
|
||||
if the value fits it, otherwise a Float.
|
||||
|
||||
@subsection @code{Number.prototype}
|
||||
|
||||
The following properties are modified:
|
||||
|
||||
@table @code
|
||||
@item toString(radix)
|
||||
|
||||
In bigint mode, integers are converted to the specified radix with
|
||||
infinite precision.
|
||||
|
||||
@item toPrecision(p)
|
||||
@item toFixed(p)
|
||||
@item toExponential(p)
|
||||
|
||||
In bigint mode, integers are accepted and converted to string with
|
||||
infinite precision.
|
||||
|
||||
@item parseInt(string, radix)
|
||||
|
||||
In bigint mode, an integer is returned and the conversion is done with
|
||||
infinite precision.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection @code{Math} object
|
||||
|
||||
The following properties are modified:
|
||||
|
||||
@table @code
|
||||
@item abs(x)
|
||||
Absolute value. Return an integer if @code{x} is an Integer. Otherwise
|
||||
return a Float. No rounding is performed.
|
||||
|
||||
@item min(a, b)
|
||||
@item max(a, b)
|
||||
No rounding is performed. The returned type is the same one as the
|
||||
minimum (resp. maximum) value.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter Arbitrarily large floating point numbers
|
||||
@chapter BigFloat
|
||||
|
||||
@section Introduction
|
||||
|
||||
This extension adds the @code{BigFloat} primitive type. The
|
||||
@code{BigFloat} type represents floating point numbers are in base 2
|
||||
@code{BigFloat} type represents floating point numbers in base 2
|
||||
with the IEEE 754 semantics. A floating
|
||||
point number is represented as a sign, mantissa and exponent. The
|
||||
special values @code{NaN}, @code{+/-Infinity}, @code{+0} and @code{-0}
|
||||
@ -490,14 +143,13 @@ explicit.}. The status flags of the global environment cannot be
|
||||
read@footnote{The rationale is to avoid side effects for the built-in
|
||||
operators.}. The precision of the global environment is
|
||||
@code{BigFloatEnv.prec}. The number of exponent bits of the global
|
||||
environment is @code{BigFloatEnv.expBits}. If @code{BigFloatEnv.expBits} is
|
||||
strictly smaller than the maximum allowed number of exponent bits
|
||||
(@code{BigFloatEnv.expBitsMax}), then the global environment subnormal
|
||||
flag is set to @code{true}. Otherwise it is set to @code{false};
|
||||
environment is @code{BigFloatEnv.expBits}. The global environment
|
||||
subnormal flag is set to @code{true}.
|
||||
|
||||
For example, @code{prec = 53} and @code{ expBits = 11} give exactly
|
||||
the same precision as the IEEE 754 64 bit floating point type. It is
|
||||
the default floating point precision.
|
||||
For example, @code{prec = 53} and @code{ expBits = 11} exactly give
|
||||
the same precision as the IEEE 754 64 bit floating point format. The
|
||||
default precision is @code{prec = 113} and @code{ expBits = 15} (IEEE
|
||||
754 128 bit floating point format).
|
||||
|
||||
The global floating point environment can only be modified temporarily
|
||||
when calling a function (see @code{BigFloatEnv.setPrec}). Hence a
|
||||
@ -568,6 +220,12 @@ means radix 10 unless there is a hexadecimal or binary prefix. The
|
||||
result is rounded according to the floating point environment @code{e}
|
||||
or the global environment if @code{e} is undefined.
|
||||
|
||||
@item isFinite(a)
|
||||
Return true if @code{a} is a finite bigfloat.
|
||||
|
||||
@item isNaN(a)
|
||||
Return true if @code{a} is a NaN bigfloat.
|
||||
|
||||
@item add(a, b[, e])
|
||||
@item sub(a, b[, e])
|
||||
@item mul(a, b[, e])
|
||||
@ -577,12 +235,14 @@ point number @code{a} according to the floating point environment
|
||||
@code{e} or the global environment if @code{e} is undefined. If
|
||||
@code{e} is specified, the floating point status flags are updated.
|
||||
|
||||
@item floor(x[, e])
|
||||
@item ceil(x[, e])
|
||||
@item round(x[, e])
|
||||
@item trunc(x[, e])
|
||||
Round to integer. A rounded @code{BigFloat} is returned. @code{e} is an
|
||||
optional floating point environment.
|
||||
@item floor(x)
|
||||
@item ceil(x)
|
||||
@item round(x)
|
||||
@item trunc(x)
|
||||
Round to an integer. No additional rounding is performed.
|
||||
|
||||
@item abs(x)
|
||||
Return the absolute value of x. No additional rounding is performed.
|
||||
|
||||
@item fmod(x, y[, e])
|
||||
@item remainder(x, y[, e])
|
||||
@ -614,6 +274,9 @@ number. @code{e} is an optional floating point environment.
|
||||
The following properties are modified:
|
||||
|
||||
@table @code
|
||||
@item valueOf()
|
||||
Return the bigfloat primitive value corresponding to @code{this}.
|
||||
|
||||
@item toString(radix)
|
||||
|
||||
For floating point numbers:
|
||||
@ -630,13 +293,16 @@ the global precision and round to nearest gives the same number.
|
||||
|
||||
@end itemize
|
||||
|
||||
@item toPrecision(p[, rnd_mode])
|
||||
@item toFixed(p[, rnd_mode])
|
||||
@item toExponential(p[, rnd_mode])
|
||||
The exponent letter is @code{e} for base 10, @code{p} for bases 2, 8,
|
||||
16 with a binary exponent and @code{@@} for the other bases.
|
||||
|
||||
@item toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
|
||||
@item toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
|
||||
@item toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
|
||||
Same semantics as the corresponding @code{Number} functions with
|
||||
BigFloats. There is no limit on the accepted precision @code{p}. The
|
||||
rounding mode can be optionally specified. It is set by default to
|
||||
@code{BigFloatEnv.RNDNA}.
|
||||
rounding mode and radix can be optionally specified. The radix must be
|
||||
between 2 and 36.
|
||||
|
||||
@end table
|
||||
|
||||
@ -673,13 +339,12 @@ subnormal flags is set to @code{false}. If @code{rndMode} is
|
||||
|
||||
@item prec
|
||||
Getter. Return the precision in bits of the global floating point
|
||||
environment. The initial value is @code{53}.
|
||||
environment. The initial value is @code{113}.
|
||||
|
||||
@item expBits
|
||||
Getter. Return the exponent size in bits of the global floating point
|
||||
environment assuming an IEEE 754 representation. If @code{expBits <
|
||||
expBitsMax}, then subnormal numbers are supported. The initial value
|
||||
is @code{11}.
|
||||
environment assuming an IEEE 754 representation. The initial value is
|
||||
@code{15}.
|
||||
|
||||
@item setPrec(f, p[, e])
|
||||
Set the precision of the global floating point environment to @code{p}
|
||||
@ -687,15 +352,13 @@ and the exponent size to @code{e} then call the function
|
||||
@code{f}. Then the Float precision and exponent size are reset to
|
||||
their precious value and the return value of @code{f} is returned (or
|
||||
an exception is raised if @code{f} raised an exception). If @code{e}
|
||||
is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}. @code{p}
|
||||
must be >= 53 and @code{e} must be >= 11 so that the global precision
|
||||
is at least equivalent to the IEEE 754 64 bit doubles.
|
||||
is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}.
|
||||
|
||||
@item precMin
|
||||
Read-only integer. Return the minimum allowed precision. Must be at least 2.
|
||||
|
||||
@item precMax
|
||||
Read-only integer. Return the maximum allowed precision. Must be at least 53.
|
||||
Read-only integer. Return the maximum allowed precision. Must be at least 113.
|
||||
|
||||
@item expBitsMin
|
||||
Read-only integer. Return the minimum allowed exponent size in
|
||||
@ -703,7 +366,7 @@ bits. Must be at least 3.
|
||||
|
||||
@item expBitsMax
|
||||
Read-only integer. Return the maximum allowed exponent size in
|
||||
bits. Must be at least 11.
|
||||
bits. Must be at least 15.
|
||||
|
||||
@item RNDN
|
||||
Read-only integer. Round to nearest, with ties to even rounding mode.
|
||||
@ -720,12 +383,12 @@ Read-only integer. Round to +Infinity rounding mode.
|
||||
@item RNDNA
|
||||
Read-only integer. Round to nearest, with ties away from zero rounding mode.
|
||||
|
||||
@item RNDNU
|
||||
Read-only integer. Round to nearest, with ties to +Infinity rounding mode.
|
||||
@item RNDA
|
||||
Read-only integer. Round away from zero rounding mode.
|
||||
|
||||
@item RNDF@footnote{Could be removed in case a deterministic behvior for floating point operations is required.}
|
||||
@item RNDF@footnote{Could be removed in case a deterministic behavior for floating point operations is required.}
|
||||
Read-only integer. Faithful rounding mode. The result is
|
||||
non-deterministicly rounded to -Infinity or +Infinity. This rounding
|
||||
non-deterministically rounded to -Infinity or +Infinity. This rounding
|
||||
mode usually gives a faster and deterministic running time for the
|
||||
floating point operations.
|
||||
|
||||
@ -761,69 +424,166 @@ Getter and setter (Boolean). Status flags.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection @code{Math} object
|
||||
@chapter BigDecimal
|
||||
|
||||
The following properties are modified:
|
||||
This extension adds the @code{BigDecimal} primitive type. The
|
||||
@code{BigDecimal} type represents floating point numbers in base
|
||||
10. It is inspired from the proposal available at
|
||||
@url{https://github.com/littledan/proposal-bigdecimal}.
|
||||
|
||||
The @code{BigDecimal} floating point numbers are always normalized and
|
||||
finite. There is no concept of @code{-0}, @code{Infinity} or
|
||||
@code{NaN}. By default, all the computations are done with infinite
|
||||
precision.
|
||||
|
||||
@section Operators
|
||||
|
||||
The following builtin operators support BigDecimal:
|
||||
|
||||
@table @code
|
||||
@item abs(x)
|
||||
Absolute value. If @code{x} is a BigFloat, its absolute value is
|
||||
returned as a BigFloat. No rounding is performed.
|
||||
|
||||
@item min(a, b)
|
||||
@item max(a, b)
|
||||
The returned type is the same one as the minimum (resp. maximum)
|
||||
value, so @code{BigFloat} values are accepted. When a @code{BigFloat}
|
||||
is returned, no rounding is performed.
|
||||
@item +
|
||||
@item -
|
||||
@item *
|
||||
Both operands must be BigDecimal. The result is computed with infinite
|
||||
precision.
|
||||
@item %
|
||||
Both operands must be BigDecimal. The result is computed with infinite
|
||||
precision. A range error is throws in case of division by zero.
|
||||
|
||||
@item /
|
||||
Both operands must be BigDecimal. A range error is throws in case of
|
||||
division by zero or if the result cannot be represented with infinite
|
||||
precision (use @code{BigDecimal.div} to specify the rounding).
|
||||
|
||||
@item **
|
||||
Both operands must be BigDecimal. The exponent must be a positive
|
||||
integer. The result is computed with infinite precision.
|
||||
|
||||
@item ===
|
||||
When one of the operand is a BigDecimal, return true if both operands
|
||||
are a BigDecimal and if they are equal.
|
||||
|
||||
@item ==
|
||||
@item !=
|
||||
@item <=
|
||||
@item >=
|
||||
@item <
|
||||
@item >
|
||||
|
||||
Numerical comparison. When one of the operand is not a BigDecimal, it is
|
||||
converted to BigDecimal by using ToString(). Hence comparisons between
|
||||
Number and BigDecimal do not use the exact mathematical value of the
|
||||
Number value.
|
||||
|
||||
@end table
|
||||
|
||||
@section BigDecimal literals
|
||||
|
||||
BigDecimal literals are decimal floating point numbers with a trailing
|
||||
@code{m} suffix.
|
||||
|
||||
@section Builtin Object changes
|
||||
|
||||
@subsection The @code{BigDecimal} function.
|
||||
|
||||
It returns @code{0m} if no parameter is provided. Otherwise the first
|
||||
parameter is converted to a bigdecimal by using ToString(). Hence
|
||||
Number values are not converted to their exact numerical value as
|
||||
BigDecimal.
|
||||
|
||||
@subsection Properties of the @code{BigDecimal} object
|
||||
|
||||
@table @code
|
||||
|
||||
@item add(a, b[, e])
|
||||
@item sub(a, b[, e])
|
||||
@item mul(a, b[, e])
|
||||
@item div(a, b[, e])
|
||||
@item mod(a, b[, e])
|
||||
@item sqrt(a, e)
|
||||
@item round(a, e)
|
||||
Perform the specified floating point operation and round the floating
|
||||
point result according to the rounding object @code{e}. If the
|
||||
rounding object is not present, the operation is executed with
|
||||
infinite precision.
|
||||
|
||||
For @code{div}, a @code{RangeError} exception is thrown in case of
|
||||
division by zero or if the result cannot be represented with infinite
|
||||
precision if no rounding object is present.
|
||||
|
||||
For @code{sqrt}, a range error is thrown if @code{a} is less than
|
||||
zero.
|
||||
|
||||
The rounding object must contain the following properties:
|
||||
@code{roundingMode} is a string specifying the rounding mode
|
||||
(@code{"floor"}, @code{"ceiling"}, @code{"down"}, @code{"up"},
|
||||
@code{"half-even"}, @code{"half-up"}). Either
|
||||
@code{maximumSignificantDigits} or @code{maximumFractionDigits} must
|
||||
be present to specify respectively the number of significant digits
|
||||
(must be >= 1) or the number of digits after the decimal point (must
|
||||
be >= 0).
|
||||
|
||||
@end table
|
||||
|
||||
@subsection Properties of the @code{BigDecimal.prototype} object
|
||||
|
||||
@table @code
|
||||
@item valueOf()
|
||||
Return the bigdecimal primitive value corresponding to @code{this}.
|
||||
|
||||
@item toString()
|
||||
Convert @code{this} to a string with infinite precision in base 10.
|
||||
|
||||
@item toPrecision(p, rnd_mode = "half-up")
|
||||
@item toFixed(p, rnd_mode = "half-up")
|
||||
@item toExponential(p, rnd_mode = "half-up")
|
||||
Convert the BigDecimal @code{this} to string with the specified
|
||||
precision @code{p}. There is no limit on the accepted precision
|
||||
@code{p}. The rounding mode can be optionally
|
||||
specified. @code{toPrecision} outputs either in decimal fixed notation
|
||||
or in decimal exponential notation with a @code{p} digits of
|
||||
precision. @code{toExponential} outputs in decimal exponential
|
||||
notation with @code{p} digits after the decimal point. @code{toFixed}
|
||||
outputs in decimal notation with @code{p} digits after the decimal
|
||||
point.
|
||||
|
||||
@end table
|
||||
|
||||
@chapter Math mode
|
||||
|
||||
@section Introduction
|
||||
|
||||
A new @emph{math mode} is enabled with the @code{"use math"}
|
||||
directive. @code{"use bigint"} is implied in math mode. With this
|
||||
mode, writing mathematical expressions is more intuitive, exact
|
||||
results (e.g. fractions) can be computed for all operators and floating
|
||||
point literals have the @code{BigFloat} type by default.
|
||||
directive. It propagates the same way as the @emph{strict mode}. It is
|
||||
designed so that arbitrarily large integers and floating point numbers
|
||||
are available by default. In order to minimize the number of changes
|
||||
in the Javascript semantics, integers are represented either as Number
|
||||
or BigInt depending on their magnitude. Floating point numbers are
|
||||
always represented as BigFloat.
|
||||
|
||||
It propagates the same way as the @emph{strict mode}. In
|
||||
this mode:
|
||||
The following changes are made to the Javascript semantics:
|
||||
|
||||
@itemize
|
||||
|
||||
@item The @code{^} operator is a similar to the power operator (@code{**}).
|
||||
@item Floating point literals (i.e. number with a decimal point or an exponent) are @code{BigFloat} by default (i.e. a @code{l} suffix is implied). Hence @code{typeof 1.0 === "bigfloat"}.
|
||||
|
||||
@item Integer literals (i.e. numbers without a decimal point or an exponent) with or without the @code{n} suffix are @code{BigInt} if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to @code{2**53-1}. Hence @code{typeof 1 === "number "}, @code{typeof 1n === "number"} but @code{typeof 9007199254740992 === "bigint" }.
|
||||
|
||||
@item All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt.
|
||||
|
||||
@item The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result.
|
||||
|
||||
@item The @code{^} operator is an alias to the power operator (@code{**}).
|
||||
|
||||
@item The power operator (both @code{^} and @code{**}) grammar is modified so that @code{-2^2} is allowed and yields @code{-4}.
|
||||
|
||||
@item The logical xor operator is still available with the @code{^^} operator.
|
||||
|
||||
@item The division operator invokes @code{BigInt[Symbol.operatorDiv]} in case both operands are integers.
|
||||
@item The modulo operator (@code{%}) returns the Euclidian remainder (always positive) instead of the truncated remainder.
|
||||
|
||||
@item The power operator invokes @code{BigInt[Symbol.operatorPow]} in case both operands are integers and the exponent is strictly negative.
|
||||
@item The integer division operator can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
|
||||
|
||||
@item The modulo operator returns the Euclidian remainder (always positive) instead of the truncated remainder.
|
||||
|
||||
@item Floating point literals are @code{BigFloat} by default (i.e. a @code{l} suffix is implied).
|
||||
@item The integer power operator with a non zero negative exponent can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}.
|
||||
|
||||
@end itemize
|
||||
|
||||
@section Builtin Object changes
|
||||
|
||||
@subsection @code{Symbol} constructor
|
||||
|
||||
The following global symbol is added for the operator overloading:
|
||||
@table @code
|
||||
@item operatorMathMod
|
||||
@end table
|
||||
|
||||
@section Remaining issues
|
||||
|
||||
@enumerate
|
||||
|
||||
@item A new floating point literal suffix could be added for @code{Number} literals.
|
||||
|
||||
@end enumerate
|
||||
|
||||
@bye
|
||||
|
435
deps/quickjs/doc/quickjs.html
vendored
435
deps/quickjs/doc/quickjs.html
vendored
@ -1,8 +1,7 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
|
||||
<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>QuickJS Javascript Engine</title>
|
||||
|
||||
<meta name="description" content="QuickJS Javascript Engine">
|
||||
@ -10,6 +9,7 @@
|
||||
<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">
|
||||
<!--
|
||||
@ -72,11 +72,10 @@ ul.no-bullet {list-style: none}
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-Language-support" href="#Language-support">3.1 Language support</a>
|
||||
<ul class="no-bullet">
|
||||
<li><a name="toc-ES2019-support" href="#ES2019-support">3.1.1 ES2019 support</a></li>
|
||||
<li><a name="toc-JSON" href="#JSON">3.1.2 JSON</a></li>
|
||||
<li><a name="toc-ECMA402" href="#ECMA402">3.1.3 ECMA402</a></li>
|
||||
<li><a name="toc-Extensions" href="#Extensions">3.1.4 Extensions</a></li>
|
||||
<li><a name="toc-Mathematical-extensions" href="#Mathematical-extensions">3.1.5 Mathematical extensions</a></li>
|
||||
<li><a name="toc-ES2020-support" href="#ES2020-support">3.1.1 ES2020 support</a></li>
|
||||
<li><a name="toc-ECMA402" href="#ECMA402">3.1.2 ECMA402</a></li>
|
||||
<li><a name="toc-Extensions" href="#Extensions">3.1.3 Extensions</a></li>
|
||||
<li><a name="toc-Mathematical-extensions" href="#Mathematical-extensions">3.1.4 Mathematical extensions</a></li>
|
||||
</ul></li>
|
||||
<li><a name="toc-Modules" href="#Modules">3.2 Modules</a></li>
|
||||
<li><a name="toc-Standard-library" href="#Standard-library">3.3 Standard library</a>
|
||||
@ -118,7 +117,7 @@ ul.no-bullet {list-style: none}
|
||||
</ul></li>
|
||||
<li><a name="toc-RegExp" href="#RegExp">4.4 RegExp</a></li>
|
||||
<li><a name="toc-Unicode" href="#Unicode">4.5 Unicode</a></li>
|
||||
<li><a name="toc-BigInt-and-BigFloat" href="#BigInt-and-BigFloat">4.6 BigInt and BigFloat</a></li>
|
||||
<li><a name="toc-BigInt_002c-BigFloat_002c-BigDecimal" href="#BigInt_002c-BigFloat_002c-BigDecimal">4.6 BigInt, BigFloat, BigDecimal</a></li>
|
||||
</ul></li>
|
||||
<li><a name="toc-License" href="#License">5 License</a></li>
|
||||
|
||||
@ -130,34 +129,34 @@ ul.no-bullet {list-style: none}
|
||||
<h2 class="chapter">1 Introduction</h2>
|
||||
|
||||
<p>QuickJS is a small and embeddable Javascript engine. It supports the
|
||||
ES2019 specification
|
||||
ES2020 specification
|
||||
<a name="DOCF1" href="#FOOT1"><sup>1</sup></a>
|
||||
including modules, asynchronous generators and proxies.
|
||||
including modules, asynchronous generators, proxies and BigInt.
|
||||
</p>
|
||||
<p>It optionally supports mathematical extensions such as big integers
|
||||
(BigInt), big floating point numbers (BigFloat) and operator
|
||||
overloading.
|
||||
<p>It supports mathematical extensions such as big decimal float float
|
||||
numbers (BigDecimal), big binary floating point numbers (BigFloat),
|
||||
and operator overloading.
|
||||
</p>
|
||||
<a name="Main-Features"></a>
|
||||
<h3 class="section">1.1 Main Features</h3>
|
||||
|
||||
<ul>
|
||||
<li> Small and easily embeddable: just a few C files, no external dependency, 180 KiB of x86 code for a simple “hello world” program.
|
||||
<li> Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple “hello world” program.
|
||||
|
||||
</li><li> Fast interpreter with very low startup time: runs the 69000 tests of the ECMAScript Test Suite<a name="DOCF2" href="#FOOT2"><sup>2</sup></a> in about 95 seconds on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds.
|
||||
|
||||
</li><li> Almost complete ES2019 support including modules, asynchronous
|
||||
</li><li> Almost complete ES2020 support including modules, asynchronous
|
||||
generators and full Annex B support (legacy web compatibility). Many
|
||||
features from the upcoming ES2020 specification
|
||||
features from the upcoming ES2021 specification
|
||||
<a name="DOCF3" href="#FOOT3"><sup>3</sup></a> are also supported.
|
||||
|
||||
</li><li> Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2019 features.
|
||||
</li><li> Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2020 features.
|
||||
|
||||
</li><li> Can compile Javascript sources to executables with no external dependency.
|
||||
</li><li> Compile Javascript sources to executables with no external dependency.
|
||||
|
||||
</li><li> Garbage collection using reference counting (to reduce memory usage and have deterministic behavior) with cycle removal.
|
||||
|
||||
</li><li> Mathematical extensions: BigInt, BigFloat, operator overloading, bigint mode, math mode.
|
||||
</li><li> Mathematical extensions: BigDecimal, BigFloat, operator overloading, bigint mode, math mode.
|
||||
|
||||
</li><li> Command line interpreter with contextual colorization and completion implemented in Javascript.
|
||||
|
||||
@ -200,29 +199,13 @@ Javascript files and/or expressions as arguments to execute them:
|
||||
|
||||
<p>generates a <code>hello</code> executable with no external dependency.
|
||||
</p>
|
||||
<p><code>qjsbn</code> and <code>qjscbn</code> are the corresponding interpreter and
|
||||
compiler with the mathematical extensions:
|
||||
</p>
|
||||
<div class="example">
|
||||
<pre class="example">./qjsbn examples/pi.js 1000
|
||||
</pre></div>
|
||||
|
||||
<p>displays 1000 digits of PI.
|
||||
</p>
|
||||
<div class="example">
|
||||
<pre class="example">./qjsbnc -o pi examples/pi.js
|
||||
./pi 1000
|
||||
</pre></div>
|
||||
|
||||
<p>compiles and executes the PI program.
|
||||
</p>
|
||||
<a name="Command-line-options"></a>
|
||||
<h3 class="section">2.3 Command line options</h3>
|
||||
|
||||
<a name="qjs-interpreter"></a>
|
||||
<h4 class="subsection">2.3.1 <code>qjs</code> interpreter</h4>
|
||||
|
||||
<pre class="verbatim">usage: qjs [options] [files]
|
||||
<pre class="verbatim">usage: qjs [options] [file [args]]
|
||||
</pre>
|
||||
<p>Options are:
|
||||
</p><dl compact="compact">
|
||||
@ -243,18 +226,35 @@ compiler with the mathematical extensions:
|
||||
</dd>
|
||||
<dt><code>-m</code></dt>
|
||||
<dt><code>--module</code></dt>
|
||||
<dd><p>Load as ES6 module (default=autodetect).
|
||||
<dd><p>Load as ES6 module (default=autodetect). A module is autodetected if
|
||||
the filename extension is <code>.mjs</code> or if the first keyword of the
|
||||
source is <code>import</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>--script</code></dt>
|
||||
<dd><p>Load as ES6 script (default=autodetect).
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>--bignum</code></dt>
|
||||
<dd><p>Enable the bignum extensions: BigDecimal object, BigFloat object and
|
||||
the <code>"use math"</code> directive.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>-I file</code></dt>
|
||||
<dt><code>--include file</code></dt>
|
||||
<dd><p>Include an additional file.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<p>Advanced options are:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>--std</code></dt>
|
||||
<dd><p>Make the <code>std</code> and <code>os</code> modules available to the loaded
|
||||
script even if it is not a module.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>-d</code></dt>
|
||||
<dt><code>--dump</code></dt>
|
||||
<dd><p>Dump the memory usage stats.
|
||||
@ -293,6 +293,13 @@ executable file.
|
||||
<dd><p>Compile as Javascript module (default=autodetect).
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>-D module_name</code></dt>
|
||||
<dd><p>Compile a dynamically loaded module and its dependencies. This option
|
||||
is needed when your code uses the <code>import</code> keyword or the
|
||||
<code>os.Worker</code> constructor because the compiler cannot statically
|
||||
find the name of the dynamically loaded modules.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>-M module_name[,cname]</code></dt>
|
||||
<dd><p>Add initialization code for an external C module. See the
|
||||
<code>c_module</code> example.
|
||||
@ -308,16 +315,21 @@ executable is smaller and faster. This option is automatically set
|
||||
when the <code>-fno-x</code> options are used.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>-fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise]</code></dt>
|
||||
<dt><code>-fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint]</code></dt>
|
||||
<dd><p>Disable selected language features to produce a smaller executable file.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>-fbignum</code></dt>
|
||||
<dd><p>Enable the bignum extensions: BigDecimal object, BigFloat object and
|
||||
the <code>"use math"</code> directive.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<a name="qjscalc-application"></a>
|
||||
<h3 class="section">2.4 <code>qjscalc</code> application</h3>
|
||||
|
||||
<p>The <code>qjscalc</code> application is a superset of the <code>qjsbn</code>
|
||||
<p>The <code>qjscalc</code> application is a superset of the <code>qjs</code>
|
||||
command line interpreter implementing a Javascript calculator with
|
||||
arbitrarily large integer and floating point numbers, fractions,
|
||||
complex numbers, polynomials and matrices. The source code is in
|
||||
@ -333,13 +345,8 @@ QuickJS archive.
|
||||
<a name="Test262-_0028ECMAScript-Test-Suite_0029"></a>
|
||||
<h3 class="section">2.6 Test262 (ECMAScript Test Suite)</h3>
|
||||
|
||||
<p>A test262 runner is included in the QuickJS archive.
|
||||
</p>
|
||||
<p>For reference, the full test262 tests are provided in the archive
|
||||
<samp>qjs-tests-yyyy-mm-dd.tar.xz</samp>. You just need to untar it into the
|
||||
QuickJS source code directory.
|
||||
</p>
|
||||
<p>Alternatively, the test262 tests can be installed with:
|
||||
<p>A test262 runner is included in the QuickJS archive. The test262 tests
|
||||
can be installed in the QuickJS source directory with:
|
||||
</p>
|
||||
<div class="example">
|
||||
<pre class="example">git clone https://github.com/tc39/test262.git test262
|
||||
@ -358,11 +365,10 @@ slow string initialization function is optimized).
|
||||
<pre class="example">make test2
|
||||
</pre></div>
|
||||
|
||||
<p>The configuration files <code>test262.conf</code> (resp
|
||||
<code>test262bn.conf</code> for the bignum version, <code>test262o.conf</code> for
|
||||
the old ES5.1 tests<a name="DOCF4" href="#FOOT4"><sup>4</sup></a>)) contain the options
|
||||
to run the various tests. Tests can be excluded based on features or
|
||||
filename.
|
||||
<p>The configuration files <code>test262.conf</code>
|
||||
(resp. <code>test262o.conf</code> for the old ES5.1 tests<a name="DOCF4" href="#FOOT4"><sup>4</sup></a>))
|
||||
contain the options to run the various tests. Tests can be excluded
|
||||
based on features or filename.
|
||||
</p>
|
||||
<p>The file <code>test262_errors.txt</code> contains the current list of
|
||||
errors. The runner displays a message when a new error appears or when
|
||||
@ -394,33 +400,26 @@ about 100 seconds).
|
||||
<a name="Language-support"></a>
|
||||
<h3 class="section">3.1 Language support</h3>
|
||||
|
||||
<a name="ES2019-support"></a>
|
||||
<h4 class="subsection">3.1.1 ES2019 support</h4>
|
||||
<a name="ES2020-support"></a>
|
||||
<h4 class="subsection">3.1.1 ES2020 support</h4>
|
||||
|
||||
<p>The ES2019 specification is almost fully supported including the Annex
|
||||
<p>The ES2020 specification is almost fully supported including the Annex
|
||||
B (legacy web compatibility) and the Unicode related features.
|
||||
</p>
|
||||
<p>The following features are not supported yet:
|
||||
</p>
|
||||
<ul>
|
||||
<li> Realms (althougth the C API supports different runtimes and contexts)
|
||||
|
||||
</li><li> Tail calls<a name="DOCF6" href="#FOOT6"><sup>6</sup></a>
|
||||
<li> Tail calls<a name="DOCF6" href="#FOOT6"><sup>6</sup></a>
|
||||
|
||||
</li></ul>
|
||||
|
||||
<a name="JSON"></a>
|
||||
<h4 class="subsection">3.1.2 JSON</h4>
|
||||
|
||||
<p>The JSON parser is currently more tolerant than the specification.
|
||||
</p>
|
||||
<a name="ECMA402"></a>
|
||||
<h4 class="subsection">3.1.3 ECMA402</h4>
|
||||
<h4 class="subsection">3.1.2 ECMA402</h4>
|
||||
|
||||
<p>ECMA402 (Internationalization API) is not supported.
|
||||
</p>
|
||||
<a name="Extensions"></a>
|
||||
<h4 class="subsection">3.1.4 Extensions</h4>
|
||||
<h4 class="subsection">3.1.3 Extensions</h4>
|
||||
|
||||
<ul>
|
||||
<li> The directive <code>"use strip"</code> indicates that the debug information (including the source code of the functions) should not be retained to save memory. As <code>"use strict"</code>, the directive can be global to a script or local to a function.
|
||||
@ -430,14 +429,13 @@ B (legacy web compatibility) and the Unicode related features.
|
||||
</li></ul>
|
||||
|
||||
<a name="Mathematical-extensions"></a>
|
||||
<h4 class="subsection">3.1.5 Mathematical extensions</h4>
|
||||
<h4 class="subsection">3.1.4 Mathematical extensions</h4>
|
||||
|
||||
<p>The mathematical extensions are available in the <code>qjsbn</code> version and are fully
|
||||
backward compatible with standard Javascript. See <code>jsbignum.pdf</code>
|
||||
for more information.
|
||||
<p>The mathematical extensions are fully backward compatible with
|
||||
standard Javascript. See <code>jsbignum.pdf</code> for more information.
|
||||
</p>
|
||||
<ul>
|
||||
<li> The <code>BigInt</code> (big integers) TC39 proposal is supported.
|
||||
<li> <code>BigDecimal</code> support: arbitrary large floating point numbers in base 10.
|
||||
|
||||
</li><li> <code>BigFloat</code> support: arbitrary large floating point numbers in base 2.
|
||||
|
||||
@ -503,58 +501,56 @@ and <samp>stdio.h</samp> and a few other utilities.
|
||||
<dd><p>Exit the process.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>evalScript(str)</code></dt>
|
||||
<dd><p>Evaluate the string <code>str</code> as a script (global eval).
|
||||
<dt><code>evalScript(str, options = undefined)</code></dt>
|
||||
<dd><p>Evaluate the string <code>str</code> as a script (global
|
||||
eval). <code>options</code> is an optional object containing the following
|
||||
optional properties:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>backtrace_barrier</code></dt>
|
||||
<dd><p>Boolean (default = false). If true, error backtraces do not list the
|
||||
stack frames below the evalScript.
|
||||
</p></dd>
|
||||
</dl>
|
||||
|
||||
</dd>
|
||||
<dt><code>loadScript(filename)</code></dt>
|
||||
<dd><p>Evaluate the file <code>filename</code> as a script (global eval).
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>Error(errno)</code></dt>
|
||||
<dd>
|
||||
<p><code>std.Error</code> constructor. Error instances contain the field
|
||||
<code>errno</code> (error code) and <code>message</code> (result of
|
||||
<code>std.Error.strerror(errno)</code>).
|
||||
</p>
|
||||
<p>The constructor contains the following fields:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>EINVAL</code></dt>
|
||||
<dt><code>EIO</code></dt>
|
||||
<dt><code>EACCES</code></dt>
|
||||
<dt><code>EEXIST</code></dt>
|
||||
<dt><code>ENOSPC</code></dt>
|
||||
<dt><code>ENOSYS</code></dt>
|
||||
<dt><code>EBUSY</code></dt>
|
||||
<dt><code>ENOENT</code></dt>
|
||||
<dt><code>EPERM</code></dt>
|
||||
<dt><code>EPIPE</code></dt>
|
||||
<dd><p>Integer value of common errors (additional error codes may be defined).
|
||||
</p></dd>
|
||||
<dt><code>strerror(errno)</code></dt>
|
||||
<dd><p>Return a string that describes the error <code>errno</code>.
|
||||
</p></dd>
|
||||
</dl>
|
||||
|
||||
</dd>
|
||||
<dt><code>open(filename, flags)</code></dt>
|
||||
<dd><p>Open a file (wrapper to the libc <code>fopen()</code>). Throws
|
||||
<code>std.Error</code> in case of I/O error.
|
||||
<dt><code>loadFile(filename)</code></dt>
|
||||
<dd><p>Load the file <code>filename</code> and return it as a string assuming UTF-8
|
||||
encoding. Return <code>null</code> in case of I/O error.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>popen(command, flags)</code></dt>
|
||||
<dd><p>Open a process by creating a pipe (wrapper to the libc <code>popen()</code>). Throws
|
||||
<code>std.Error</code> in case of I/O error.
|
||||
<dt><code>open(filename, flags, errorObj = undefined)</code></dt>
|
||||
<dd><p>Open a file (wrapper to the libc <code>fopen()</code>). Return the FILE
|
||||
object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
|
||||
undefined, set its <code>errno</code> property to the error code or to 0 if
|
||||
no error occured.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>fdopen(fd, flags)</code></dt>
|
||||
<dt><code>popen(command, flags, errorObj = undefined)</code></dt>
|
||||
<dd><p>Open a process by creating a pipe (wrapper to the libc
|
||||
<code>popen()</code>). Return the FILE
|
||||
object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
|
||||
undefined, set its <code>errno</code> property to the error code or to 0 if
|
||||
no error occured.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>fdopen(fd, flags, errorObj = undefined)</code></dt>
|
||||
<dd><p>Open a file from a file handle (wrapper to the libc
|
||||
<code>fdopen()</code>). Throws <code>std.Error</code> in case of I/O error.
|
||||
<code>fdopen()</code>). Return the FILE
|
||||
object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
|
||||
undefined, set its <code>errno</code> property to the error code or to 0 if
|
||||
no error occured.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>tmpfile()</code></dt>
|
||||
<dd><p>Open a temporary file. Throws <code>std.Error</code> in case of I/O error.
|
||||
<dt><code>tmpfile(errorObj = undefined)</code></dt>
|
||||
<dd><p>Open a temporary file. Return the FILE
|
||||
object or <code>null</code> in case of I/O error. If <code>errorObj</code> is not
|
||||
undefined, set its <code>errno</code> property to the error code or to 0 if
|
||||
no error occured.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>puts(str)</code></dt>
|
||||
@ -562,7 +558,7 @@ and <samp>stdio.h</samp> and a few other utilities.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>printf(fmt, ...args)</code></dt>
|
||||
<dd><p>Equivalent to <code>std.out.printf(fmt, ...args)</code>
|
||||
<dd><p>Equivalent to <code>std.out.printf(fmt, ...args)</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>sprintf(fmt, ...args)</code></dt>
|
||||
@ -581,6 +577,29 @@ and <samp>stdio.h</samp> and a few other utilities.
|
||||
<dd><p>Constants for seek().
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>Error</code></dt>
|
||||
<dd>
|
||||
<p>Enumeration object containing the integer value of common errors
|
||||
(additional error codes may be defined):
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>EINVAL</code></dt>
|
||||
<dt><code>EIO</code></dt>
|
||||
<dt><code>EACCES</code></dt>
|
||||
<dt><code>EEXIST</code></dt>
|
||||
<dt><code>ENOSPC</code></dt>
|
||||
<dt><code>ENOSYS</code></dt>
|
||||
<dt><code>EBUSY</code></dt>
|
||||
<dt><code>ENOENT</code></dt>
|
||||
<dt><code>EPERM</code></dt>
|
||||
<dt><code>EPIPE</code></dt>
|
||||
</dl>
|
||||
|
||||
</dd>
|
||||
<dt><code>strerror(errno)</code></dt>
|
||||
<dd><p>Return a string that describes the error <code>errno</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>gc()</code></dt>
|
||||
<dd><p>Manually invoke the cycle removal algorithm. The cycle removal
|
||||
algorithm is automatically started when needed, so this function is
|
||||
@ -592,6 +611,19 @@ useful in case of specific memory constraints or for testing.
|
||||
<code>undefined</code> if it is not defined.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>setenv(name, value)</code></dt>
|
||||
<dd><p>Set the value of the environment variable <code>name</code> to the string
|
||||
<code>value</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>unsetenv(name)</code></dt>
|
||||
<dd><p>Delete the environment variable <code>name</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>getenviron()</code></dt>
|
||||
<dd><p>Return an object containing the environment variables as key-value pairs.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>urlGet(url, options = undefined)</code></dt>
|
||||
<dd>
|
||||
<p>Download <code>url</code> using the <samp>curl</samp> command line
|
||||
@ -606,16 +638,33 @@ optional properties:
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>full</code></dt>
|
||||
<dd><p>Boolean (default = false). If true, return the an object contains
|
||||
<dd>
|
||||
<p>Boolean (default = false). If true, return the an object contains
|
||||
the properties <code>response</code> (response content),
|
||||
<code>responseHeaders</code> (headers separated by CRLF), <code>status</code>
|
||||
(status code). If <code>full</code> is false, only the response is
|
||||
returned if the status is between 200 and 299. Otherwise an
|
||||
<code>std.Error</code> exception is raised.
|
||||
(status code). <code>response</code> is <code>null</code> is case of protocol or
|
||||
network error. If <code>full</code> is false, only the response is
|
||||
returned if the status is between 200 and 299. Otherwise <code>null</code>
|
||||
is returned.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</dd>
|
||||
<dt><code>parseExtJSON(str)</code></dt>
|
||||
<dd>
|
||||
<p>Parse <code>str</code> using a superset of <code>JSON.parse</code>. The
|
||||
following extensions are accepted:
|
||||
</p>
|
||||
<ul>
|
||||
<li> Single line and multiline comments
|
||||
</li><li> unquoted properties (ASCII-only Javascript identifiers)
|
||||
</li><li> trailing comma in array and object definitions
|
||||
</li><li> single quoted strings
|
||||
</li><li> <code>\f</code> and <code>\v</code> are accepted as space characters
|
||||
</li><li> leading plus in numbers
|
||||
</li><li> octal (<code>0o</code> prefix) and hexadecimal (<code>0x</code> prefix) numbers
|
||||
</li></ul>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
@ -623,29 +672,45 @@ optional properties:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>close()</code></dt>
|
||||
<dd><p>Close the file.
|
||||
<dd><p>Close the file. Return 0 if OK or <code>-errno</code> in case of I/O error.
|
||||
</p></dd>
|
||||
<dt><code>puts(str)</code></dt>
|
||||
<dd><p>Outputs the string with the UTF-8 encoding.
|
||||
</p></dd>
|
||||
<dt><code>printf(fmt, ...args)</code></dt>
|
||||
<dd><p>Formatted printf, same formats as the libc printf.
|
||||
</p></dd>
|
||||
<dd><p>Formatted printf.
|
||||
</p>
|
||||
<p>The same formats as the standard C library <code>printf</code> are
|
||||
supported. Integer format types (e.g. <code>%d</code>) truncate the Numbers
|
||||
or BigInts to 32 bits. Use the <code>l</code> modifier (e.g. <code>%ld</code>) to
|
||||
truncate to 64 bits.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>flush()</code></dt>
|
||||
<dd><p>Flush the buffered file.
|
||||
</p></dd>
|
||||
<dt><code>seek(offset, whence)</code></dt>
|
||||
<dd><p>Seek to a give file position (whence is <code>std.SEEK_*</code>). Throws a
|
||||
<code>std.Error</code> in case of I/O error.
|
||||
<dd><p>Seek to a give file position (whence is
|
||||
<code>std.SEEK_*</code>). <code>offset</code> can be a number or a bigint. Return
|
||||
0 if OK or <code>-errno</code> in case of I/O error.
|
||||
</p></dd>
|
||||
<dt><code>tell()</code></dt>
|
||||
<dd><p>Return the current file position.
|
||||
</p></dd>
|
||||
<dt><code>tello()</code></dt>
|
||||
<dd><p>Return the current file position as a bigint.
|
||||
</p></dd>
|
||||
<dt><code>eof()</code></dt>
|
||||
<dd><p>Return true if end of file.
|
||||
</p></dd>
|
||||
<dt><code>fileno()</code></dt>
|
||||
<dd><p>Return the associated OS handle.
|
||||
</p></dd>
|
||||
<dt><code>error()</code></dt>
|
||||
<dd><p>Return true if there was an error.
|
||||
</p></dd>
|
||||
<dt><code>clearerr()</code></dt>
|
||||
<dd><p>Clear the error indication.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>read(buffer, position, length)</code></dt>
|
||||
@ -655,7 +720,7 @@ position <code>position</code> (wrapper to the libc <code>fread</code>).
|
||||
</dd>
|
||||
<dt><code>write(buffer, position, length)</code></dt>
|
||||
<dd><p>Write <code>length</code> bytes to the file from the ArrayBuffer <code>buffer</code> at byte
|
||||
position <code>position</code> (wrapper to the libc <code>fread</code>).
|
||||
position <code>position</code> (wrapper to the libc <code>fwrite</code>).
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>getline()</code></dt>
|
||||
@ -663,8 +728,14 @@ position <code>position</code> (wrapper to the libc <code>fread</code>).
|
||||
the trailing line feed.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>readAsString(max_size = undefined)</code></dt>
|
||||
<dd><p>Read <code>max_size</code> bytes from the file and return them as a string
|
||||
assuming UTF-8 encoding. If <code>max_size</code> is not present, the file
|
||||
is read up its end.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>getByte()</code></dt>
|
||||
<dd><p>Return the next byte from the file.
|
||||
<dd><p>Return the next byte from the file. Return -1 if the end of file is reached.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>putByte(c)</code></dt>
|
||||
@ -682,6 +753,7 @@ the trailing line feed.
|
||||
</li><li> signals
|
||||
</li><li> timers
|
||||
</li><li> asynchronous I/O
|
||||
</li><li> workers (threads)
|
||||
</li></ul>
|
||||
|
||||
<p>The OS functions usually return 0 if OK or an OS specific negative
|
||||
@ -713,7 +785,9 @@ error code.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>seek(fd, offset, whence)</code></dt>
|
||||
<dd><p>Seek in the file. Use <code>std.SEEK_*</code> for <code>whence</code>.
|
||||
<dd><p>Seek in the file. Use <code>std.SEEK_*</code> for
|
||||
<code>whence</code>. <code>offset</code> is either a number or a bigint. If
|
||||
<code>offset</code> is a bigint, a bigint is returned too.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>read(fd, buffer, offset, length)</code></dt>
|
||||
@ -741,11 +815,11 @@ Return the number of written bytes or < 0 if error.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>remove(filename)</code></dt>
|
||||
<dd><p>Remove a file. Return 0 if OK or < 0 if error.
|
||||
<dd><p>Remove a file. Return 0 if OK or <code>-errno</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>rename(oldname, newname)</code></dt>
|
||||
<dd><p>Rename a file. Return 0 if OK or < 0 if error.
|
||||
<dd><p>Rename a file. Return 0 if OK or <code>-errno</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>realpath(path)</code></dt>
|
||||
@ -758,8 +832,12 @@ pathname of <code>path</code> and <code>err</code> the error code.
|
||||
and <code>err</code> the error code.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>chdir(path)</code></dt>
|
||||
<dd><p>Change the current directory. Return 0 if OK or <code>-errno</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>mkdir(path, mode = 0o777)</code></dt>
|
||||
<dd><p>Create a directory at <code>path</code>. Return the error code.
|
||||
<dd><p>Create a directory at <code>path</code>. Return 0 if OK or <code>-errno</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>stat(path)</code></dt>
|
||||
@ -791,11 +869,11 @@ itself.
|
||||
</dd>
|
||||
<dt><code>utimes(path, atime, mtime)</code></dt>
|
||||
<dd><p>Change the access and modification times of the file <code>path</code>. The
|
||||
times are specified in milliseconds since 1970.
|
||||
times are specified in milliseconds since 1970. Return 0 if OK or <code>-errno</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>symlink(target, linkpath)</code></dt>
|
||||
<dd><p>Create a link at <code>linkpath</code> containing the string <code>target</code>.
|
||||
<dd><p>Create a link at <code>linkpath</code> containing the string <code>target</code>. Return 0 if OK or <code>-errno</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>readlink(path)</code></dt>
|
||||
@ -813,21 +891,21 @@ the error code.
|
||||
<dd><p>Add a read handler to the file handle <code>fd</code>. <code>func</code> is called
|
||||
each time there is data pending for <code>fd</code>. A single read handler
|
||||
per file handle is supported. Use <code>func = null</code> to remove the
|
||||
hander.
|
||||
handler.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>setWriteHandler(fd, func)</code></dt>
|
||||
<dd><p>Add a write handler to the file handle <code>fd</code>. <code>func</code> is
|
||||
called each time data can be written to <code>fd</code>. A single write
|
||||
handler per file handle is supported. Use <code>func = null</code> to remove
|
||||
the hander.
|
||||
the handler.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>signal(signal, func)</code></dt>
|
||||
<dd><p>Call the function <code>func</code> when the signal <code>signal</code>
|
||||
happens. Only a single handler per signal number is supported. Use
|
||||
<code>null</code> to set the default handler or <code>undefined</code> to ignore
|
||||
the signal.
|
||||
the signal. Signal handlers can only be defined in the main thread.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>SIGINT</code></dt>
|
||||
@ -850,7 +928,7 @@ object containing optional parameters:
|
||||
<dl compact="compact">
|
||||
<dt><code>block</code></dt>
|
||||
<dd><p>Boolean (default = true). If true, wait until the process is
|
||||
termined. In this case, <code>exec</code> return the exit code if positive
|
||||
terminated. In this case, <code>exec</code> 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.
|
||||
</p>
|
||||
@ -872,13 +950,28 @@ object containing optional parameters:
|
||||
<dt><code>stdout</code></dt>
|
||||
<dt><code>stderr</code></dt>
|
||||
<dd><p>If present, set the handle in the child for stdin, stdout or stderr.
|
||||
</p>
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>env</code></dt>
|
||||
<dd><p>Object. If present, set the process environment from the object
|
||||
key-value pairs. Otherwise use the same environment as the current
|
||||
process.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>uid</code></dt>
|
||||
<dd><p>Integer. If present, the process uid with <code>setuid</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>gid</code></dt>
|
||||
<dd><p>Integer. If present, the process gid with <code>setgid</code>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</dd>
|
||||
<dt><code>waitpid(pid, options)</code></dt>
|
||||
<dd><p><code>waitpid</code> Unix system call. Return the array <code>[ret, status]</code>.
|
||||
<dd><p><code>waitpid</code> Unix system call. Return the array <code>[ret,
|
||||
status]</code>. <code>ret</code> contains <code>-errno</code> in case of error.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>WNOHANG</code></dt>
|
||||
@ -915,6 +1008,50 @@ to the timer.
|
||||
<dd><p>Return a string representing the platform: <code>"linux"</code>, <code>"darwin"</code>,
|
||||
<code>"win32"</code> or <code>"js"</code>.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>Worker(module_filename)</code></dt>
|
||||
<dd><p>Constructor to create a new thread (worker) with an API close to the
|
||||
<code>WebWorkers</code>. <code>module_filename</code> is a string specifying the
|
||||
module filename which is executed in the newly created thread. As for
|
||||
dynamically imported module, it is relative to the current script or
|
||||
module path. Threads normally don’t share any data and communicate
|
||||
between each other with messages. Nested workers are not supported. An
|
||||
example is available in <samp>tests/test_worker.js</samp>.
|
||||
</p>
|
||||
<p>The worker class has the following static properties:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>parent</code></dt>
|
||||
<dd><p>In the created worker, <code>Worker.parent</code> represents the parent
|
||||
worker and is used to send or receive messages.
|
||||
</p></dd>
|
||||
</dl>
|
||||
|
||||
<p>The worker instances have the following properties:
|
||||
</p>
|
||||
<dl compact="compact">
|
||||
<dt><code>postMessage(msg)</code></dt>
|
||||
<dd>
|
||||
<p>Send a message to the corresponding worker. <code>msg</code> is cloned in
|
||||
the destination worker using an algorithm similar to the <code>HTML</code>
|
||||
structured clone algorithm. <code>SharedArrayBuffer</code> are shared
|
||||
between workers.
|
||||
</p>
|
||||
<p>Current limitations: <code>Map</code> and <code>Set</code> are not supported
|
||||
yet.
|
||||
</p>
|
||||
</dd>
|
||||
<dt><code>onmessage</code></dt>
|
||||
<dd>
|
||||
<p>Getter and setter. Set a function which is called each time a
|
||||
message is received. The function is called with a single
|
||||
argument. It is an object with a <code>data</code> property containing the
|
||||
received message. The thread is not terminated if there is at least
|
||||
one non <code>null</code> <code>onmessage</code> handler.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
@ -934,7 +1071,7 @@ supported.
|
||||
</p>
|
||||
<p><code>JSContext</code> represents a Javascript context (or Realm). Each
|
||||
JSContext has its own global objects and system objects. There can be
|
||||
several JSContexts per JSRuntime and they can share objects, similary
|
||||
several JSContexts per JSRuntime and they can share objects, similar
|
||||
to frames of the same origin sharing Javascript objects in a
|
||||
web browser.
|
||||
</p>
|
||||
@ -943,7 +1080,7 @@ web browser.
|
||||
|
||||
<p><code>JSValue</code> represents a Javascript value which can be a primitive
|
||||
type or an object. Reference counting is used, so it is important to
|
||||
explicitely duplicate (<code>JS_DupValue()</code>, increment the reference
|
||||
explicitly duplicate (<code>JS_DupValue()</code>, increment the reference
|
||||
count) or free (<code>JS_FreeValue()</code>, decrement the reference count)
|
||||
JSValues.
|
||||
</p>
|
||||
@ -965,9 +1102,9 @@ general rule, C functions take constant <code>JSValue</code>s as parameters
|
||||
<h4 class="subsection">3.4.4 Exceptions</h4>
|
||||
|
||||
<p>Exceptions: most C functions can return a Javascript exception. It
|
||||
must be explicitely tested and handled by the C code. The specific
|
||||
must be explicitly tested and handled by the C code. The specific
|
||||
<code>JSValue</code> <code>JS_EXCEPTION</code> indicates that an exception
|
||||
occured. The actual exception object is stored in the
|
||||
occurred. The actual exception object is stored in the
|
||||
<code>JSContext</code> and can be retrieved with <code>JS_GetException()</code>.
|
||||
</p>
|
||||
<a name="Script-evaluation"></a>
|
||||
@ -1171,16 +1308,16 @@ stack holds the Javascript parameters and local variables.
|
||||
<a name="RegExp"></a>
|
||||
<h3 class="section">4.4 RegExp</h3>
|
||||
|
||||
<p>A specific regular expression engine was developped. It is both small
|
||||
<p>A specific regular expression engine was developed. It is both small
|
||||
and efficient and supports all the ES2020 features including the
|
||||
Unicode properties. As the Javascript compiler, it directly generates
|
||||
bytecode without a parse tree.
|
||||
</p>
|
||||
<p>Backtracking with an explicit stack is used so that there is no
|
||||
recursion on the system stack. Simple quantizers are specifically
|
||||
recursion on the system stack. Simple quantifiers are specifically
|
||||
optimized to avoid recursions.
|
||||
</p>
|
||||
<p>Infinite recursions coming from quantizers with empty terms are
|
||||
<p>Infinite recursions coming from quantifiers with empty terms are
|
||||
avoided.
|
||||
</p>
|
||||
<p>The full regexp library weights about 15 KiB (x86 code), excluding the
|
||||
@ -1189,9 +1326,9 @@ Unicode library.
|
||||
<a name="Unicode"></a>
|
||||
<h3 class="section">4.5 Unicode</h3>
|
||||
|
||||
<p>A specific Unicode library was developped so that there is no
|
||||
<p>A specific Unicode library was developed so that there is no
|
||||
dependency on an external large Unicode library such as ICU. All the
|
||||
Unicode tables are compressed while keeping a reasonnable access
|
||||
Unicode tables are compressed while keeping a reasonable access
|
||||
speed.
|
||||
</p>
|
||||
<p>The library supports case conversion, Unicode normalization, Unicode
|
||||
@ -1200,11 +1337,11 @@ binary properties.
|
||||
</p>
|
||||
<p>The full Unicode library weights about 45 KiB (x86 code).
|
||||
</p>
|
||||
<a name="BigInt-and-BigFloat"></a>
|
||||
<h3 class="section">4.6 BigInt and BigFloat</h3>
|
||||
<a name="BigInt_002c-BigFloat_002c-BigDecimal"></a>
|
||||
<h3 class="section">4.6 BigInt, BigFloat, BigDecimal</h3>
|
||||
|
||||
<p>BigInt and BigFloat are implemented with the <code>libbf</code>
|
||||
library<a name="DOCF7" href="#FOOT7"><sup>7</sup></a>. It weights about 60
|
||||
<p>BigInt, BigFloat and BigDecimal are implemented with the <code>libbf</code>
|
||||
library<a name="DOCF7" href="#FOOT7"><sup>7</sup></a>. It weights about 90
|
||||
KiB (x86 code) and provides arbitrary precision IEEE 754 floating
|
||||
point operations and transcendental functions with exact rounding.
|
||||
</p>
|
||||
@ -1221,15 +1358,15 @@ Bellard and Charlie Gordon.
|
||||
<h4 class="footnotes-heading">Footnotes</h4>
|
||||
|
||||
<h3><a name="FOOT1" href="#DOCF1">(1)</a></h3>
|
||||
<p><a href="https://www.ecma-international.org/ecma-262/10.0">https://www.ecma-international.org/ecma-262/10.0</a></p>
|
||||
<p><a href="https://tc39.es/ecma262/">https://tc39.es/ecma262/</a></p>
|
||||
<h3><a name="FOOT2" href="#DOCF2">(2)</a></h3>
|
||||
<p><a href="https://github.com/tc39/test262">https://github.com/tc39/test262</a></p>
|
||||
<h3><a name="FOOT3" href="#DOCF3">(3)</a></h3>
|
||||
<p><a href="https://tc39.github.io/ecma262/">https://tc39.github.io/ecma262/</a></p>
|
||||
<h3><a name="FOOT4" href="#DOCF4">(4)</a></h3>
|
||||
<p>The old ES5.1 tests can be extracted with
|
||||
<code>git clone --single-branch --branch es5-tests
|
||||
https://github.com/tc39/test262.git test262o</code></p>
|
||||
<p>The old
|
||||
ES5.1 tests can be extracted with <code>git clone --single-branch
|
||||
--branch es5-tests https://github.com/tc39/test262.git test262o</code></p>
|
||||
<h3><a name="FOOT5" href="#DOCF5">(5)</a></h3>
|
||||
<p><a href="https://github.com/bterlson/test262-harness">https://github.com/bterlson/test262-harness</a></p>
|
||||
<h3><a name="FOOT6" href="#DOCF6">(6)</a></h3>
|
||||
|
BIN
deps/quickjs/doc/quickjs.pdf
vendored
BIN
deps/quickjs/doc/quickjs.pdf
vendored
Binary file not shown.
371
deps/quickjs/doc/quickjs.texi
vendored
371
deps/quickjs/doc/quickjs.texi
vendored
@ -20,34 +20,34 @@
|
||||
@chapter Introduction
|
||||
|
||||
QuickJS is a small and embeddable Javascript engine. It supports the
|
||||
ES2019 specification
|
||||
@footnote{@url{https://www.ecma-international.org/ecma-262/10.0}}
|
||||
including modules, asynchronous generators and proxies.
|
||||
ES2020 specification
|
||||
@footnote{@url{https://tc39.es/ecma262/}}
|
||||
including modules, asynchronous generators, proxies and BigInt.
|
||||
|
||||
It optionally supports mathematical extensions such as big integers
|
||||
(BigInt), big floating point numbers (BigFloat) and operator
|
||||
overloading.
|
||||
It supports mathematical extensions such as big decimal float float
|
||||
numbers (BigDecimal), big binary floating point numbers (BigFloat),
|
||||
and operator overloading.
|
||||
|
||||
@section Main Features
|
||||
|
||||
@itemize
|
||||
|
||||
@item Small and easily embeddable: just a few C files, no external dependency, 180 KiB of x86 code for a simple ``hello world'' program.
|
||||
@item Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple ``hello world'' program.
|
||||
|
||||
@item Fast interpreter with very low startup time: runs the 69000 tests of the ECMAScript Test Suite@footnote{@url{https://github.com/tc39/test262}} in about 95 seconds on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds.
|
||||
|
||||
@item Almost complete ES2019 support including modules, asynchronous
|
||||
@item Almost complete ES2020 support including modules, asynchronous
|
||||
generators and full Annex B support (legacy web compatibility). Many
|
||||
features from the upcoming ES2020 specification
|
||||
features from the upcoming ES2021 specification
|
||||
@footnote{@url{https://tc39.github.io/ecma262/}} are also supported.
|
||||
|
||||
@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2019 features.
|
||||
@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2020 features.
|
||||
|
||||
@item Can compile Javascript sources to executables with no external dependency.
|
||||
@item Compile Javascript sources to executables with no external dependency.
|
||||
|
||||
@item Garbage collection using reference counting (to reduce memory usage and have deterministic behavior) with cycle removal.
|
||||
|
||||
@item Mathematical extensions: BigInt, BigFloat, operator overloading, bigint mode, math mode.
|
||||
@item Mathematical extensions: BigDecimal, BigFloat, operator overloading, bigint mode, math mode.
|
||||
|
||||
@item Command line interpreter with contextual colorization and completion implemented in Javascript.
|
||||
|
||||
@ -87,28 +87,12 @@ Javascript files and/or expressions as arguments to execute them:
|
||||
|
||||
generates a @code{hello} executable with no external dependency.
|
||||
|
||||
@code{qjsbn} and @code{qjscbn} are the corresponding interpreter and
|
||||
compiler with the mathematical extensions:
|
||||
|
||||
@example
|
||||
./qjsbn examples/pi.js 1000
|
||||
@end example
|
||||
|
||||
displays 1000 digits of PI.
|
||||
|
||||
@example
|
||||
./qjsbnc -o pi examples/pi.js
|
||||
./pi 1000
|
||||
@end example
|
||||
|
||||
compiles and executes the PI program.
|
||||
|
||||
@section Command line options
|
||||
|
||||
@subsection @code{qjs} interpreter
|
||||
|
||||
@verbatim
|
||||
usage: qjs [options] [files]
|
||||
usage: qjs [options] [file [args]]
|
||||
@end verbatim
|
||||
|
||||
Options are:
|
||||
@ -127,16 +111,30 @@ Go to interactive mode (it is not the default when files are provided on the com
|
||||
|
||||
@item -m
|
||||
@item --module
|
||||
Load as ES6 module (default=autodetect).
|
||||
Load as ES6 module (default=autodetect). A module is autodetected if
|
||||
the filename extension is @code{.mjs} or if the first keyword of the
|
||||
source is @code{import}.
|
||||
|
||||
@item --script
|
||||
Load as ES6 script (default=autodetect).
|
||||
|
||||
@item --bignum
|
||||
Enable the bignum extensions: BigDecimal object, BigFloat object and
|
||||
the @code{"use math"} directive.
|
||||
|
||||
@item -I file
|
||||
@item --include file
|
||||
Include an additional file.
|
||||
|
||||
@end table
|
||||
|
||||
Advanced options are:
|
||||
|
||||
@table @code
|
||||
@item --std
|
||||
Make the @code{std} and @code{os} modules available to the loaded
|
||||
script even if it is not a module.
|
||||
|
||||
@item -d
|
||||
@item --dump
|
||||
Dump the memory usage stats.
|
||||
@ -169,6 +167,12 @@ Set the C name of the generated data.
|
||||
@item -m
|
||||
Compile as Javascript module (default=autodetect).
|
||||
|
||||
@item -D module_name
|
||||
Compile a dynamically loaded module and its dependencies. This option
|
||||
is needed when your code uses the @code{import} keyword or the
|
||||
@code{os.Worker} constructor because the compiler cannot statically
|
||||
find the name of the dynamically loaded modules.
|
||||
|
||||
@item -M module_name[,cname]
|
||||
Add initialization code for an external C module. See the
|
||||
@code{c_module} example.
|
||||
@ -181,14 +185,18 @@ Use link time optimization. The compilation is slower but the
|
||||
executable is smaller and faster. This option is automatically set
|
||||
when the @code{-fno-x} options are used.
|
||||
|
||||
@item -fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise]
|
||||
@item -fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint]
|
||||
Disable selected language features to produce a smaller executable file.
|
||||
|
||||
@item -fbignum
|
||||
Enable the bignum extensions: BigDecimal object, BigFloat object and
|
||||
the @code{"use math"} directive.
|
||||
|
||||
@end table
|
||||
|
||||
@section @code{qjscalc} application
|
||||
|
||||
The @code{qjscalc} application is a superset of the @code{qjsbn}
|
||||
The @code{qjscalc} application is a superset of the @code{qjs}
|
||||
command line interpreter implementing a Javascript calculator with
|
||||
arbitrarily large integer and floating point numbers, fractions,
|
||||
complex numbers, polynomials and matrices. The source code is in
|
||||
@ -202,13 +210,8 @@ QuickJS archive.
|
||||
|
||||
@section Test262 (ECMAScript Test Suite)
|
||||
|
||||
A test262 runner is included in the QuickJS archive.
|
||||
|
||||
For reference, the full test262 tests are provided in the archive
|
||||
@file{qjs-tests-yyyy-mm-dd.tar.xz}. You just need to untar it into the
|
||||
QuickJS source code directory.
|
||||
|
||||
Alternatively, the test262 tests can be installed with:
|
||||
A test262 runner is included in the QuickJS archive. The test262 tests
|
||||
can be installed in the QuickJS source directory with:
|
||||
|
||||
@example
|
||||
git clone https://github.com/tc39/test262.git test262
|
||||
@ -227,13 +230,12 @@ The tests can be run with
|
||||
make test2
|
||||
@end example
|
||||
|
||||
The configuration files @code{test262.conf} (resp
|
||||
@code{test262bn.conf} for the bignum version, @code{test262o.conf} for
|
||||
the old ES5.1 tests@footnote{The old ES5.1 tests can be extracted with
|
||||
@code{git clone --single-branch --branch es5-tests
|
||||
https://github.com/tc39/test262.git test262o}})) contain the options
|
||||
to run the various tests. Tests can be excluded based on features or
|
||||
filename.
|
||||
The configuration files @code{test262.conf}
|
||||
(resp. @code{test262o.conf} for the old ES5.1 tests@footnote{The old
|
||||
ES5.1 tests can be extracted with @code{git clone --single-branch
|
||||
--branch es5-tests https://github.com/tc39/test262.git test262o}}))
|
||||
contain the options to run the various tests. Tests can be excluded
|
||||
based on features or filename.
|
||||
|
||||
The file @code{test262_errors.txt} contains the current list of
|
||||
errors. The runner displays a message when a new error appears or when
|
||||
@ -263,25 +265,19 @@ about 100 seconds).
|
||||
|
||||
@section Language support
|
||||
|
||||
@subsection ES2019 support
|
||||
@subsection ES2020 support
|
||||
|
||||
The ES2019 specification is almost fully supported including the Annex
|
||||
The ES2020 specification is almost fully supported including the Annex
|
||||
B (legacy web compatibility) and the Unicode related features.
|
||||
|
||||
The following features are not supported yet:
|
||||
|
||||
@itemize
|
||||
|
||||
@item Realms (althougth the C API supports different runtimes and contexts)
|
||||
|
||||
@item Tail calls@footnote{We believe the current specification of tails calls is too complicated and presents limited practical interests.}
|
||||
|
||||
@end itemize
|
||||
|
||||
@subsection JSON
|
||||
|
||||
The JSON parser is currently more tolerant than the specification.
|
||||
|
||||
@subsection ECMA402
|
||||
|
||||
ECMA402 (Internationalization API) is not supported.
|
||||
@ -298,13 +294,12 @@ ECMA402 (Internationalization API) is not supported.
|
||||
|
||||
@subsection Mathematical extensions
|
||||
|
||||
The mathematical extensions are available in the @code{qjsbn} version and are fully
|
||||
backward compatible with standard Javascript. See @code{jsbignum.pdf}
|
||||
for more information.
|
||||
The mathematical extensions are fully backward compatible with
|
||||
standard Javascript. See @code{jsbignum.pdf} for more information.
|
||||
|
||||
@itemize
|
||||
|
||||
@item The @code{BigInt} (big integers) TC39 proposal is supported.
|
||||
@item @code{BigDecimal} support: arbitrary large floating point numbers in base 10.
|
||||
|
||||
@item @code{BigFloat} support: arbitrary large floating point numbers in base 2.
|
||||
|
||||
@ -364,56 +359,55 @@ Available exports:
|
||||
@item exit(n)
|
||||
Exit the process.
|
||||
|
||||
@item evalScript(str)
|
||||
Evaluate the string @code{str} as a script (global eval).
|
||||
@item evalScript(str, options = undefined)
|
||||
Evaluate the string @code{str} as a script (global
|
||||
eval). @code{options} is an optional object containing the following
|
||||
optional properties:
|
||||
|
||||
@table @code
|
||||
@item backtrace_barrier
|
||||
Boolean (default = false). If true, error backtraces do not list the
|
||||
stack frames below the evalScript.
|
||||
@end table
|
||||
|
||||
@item loadScript(filename)
|
||||
Evaluate the file @code{filename} as a script (global eval).
|
||||
|
||||
@item Error(errno)
|
||||
@item loadFile(filename)
|
||||
Load the file @code{filename} and return it as a string assuming UTF-8
|
||||
encoding. Return @code{null} in case of I/O error.
|
||||
|
||||
@code{std.Error} constructor. Error instances contain the field
|
||||
@code{errno} (error code) and @code{message} (result of
|
||||
@code{std.Error.strerror(errno)}).
|
||||
@item open(filename, flags, errorObj = undefined)
|
||||
Open a file (wrapper to the libc @code{fopen()}). Return the FILE
|
||||
object or @code{null} in case of I/O error. If @code{errorObj} is not
|
||||
undefined, set its @code{errno} property to the error code or to 0 if
|
||||
no error occured.
|
||||
|
||||
The constructor contains the following fields:
|
||||
@item popen(command, flags, errorObj = undefined)
|
||||
Open a process by creating a pipe (wrapper to the libc
|
||||
@code{popen()}). Return the FILE
|
||||
object or @code{null} in case of I/O error. If @code{errorObj} is not
|
||||
undefined, set its @code{errno} property to the error code or to 0 if
|
||||
no error occured.
|
||||
|
||||
@table @code
|
||||
@item EINVAL
|
||||
@item EIO
|
||||
@item EACCES
|
||||
@item EEXIST
|
||||
@item ENOSPC
|
||||
@item ENOSYS
|
||||
@item EBUSY
|
||||
@item ENOENT
|
||||
@item EPERM
|
||||
@item EPIPE
|
||||
Integer value of common errors (additional error codes may be defined).
|
||||
@item strerror(errno)
|
||||
Return a string that describes the error @code{errno}.
|
||||
@end table
|
||||
|
||||
@item open(filename, flags)
|
||||
Open a file (wrapper to the libc @code{fopen()}). Throws
|
||||
@code{std.Error} in case of I/O error.
|
||||
|
||||
@item popen(command, flags)
|
||||
Open a process by creating a pipe (wrapper to the libc @code{popen()}). Throws
|
||||
@code{std.Error} in case of I/O error.
|
||||
|
||||
@item fdopen(fd, flags)
|
||||
@item fdopen(fd, flags, errorObj = undefined)
|
||||
Open a file from a file handle (wrapper to the libc
|
||||
@code{fdopen()}). Throws @code{std.Error} in case of I/O error.
|
||||
@code{fdopen()}). Return the FILE
|
||||
object or @code{null} in case of I/O error. If @code{errorObj} is not
|
||||
undefined, set its @code{errno} property to the error code or to 0 if
|
||||
no error occured.
|
||||
|
||||
@item tmpfile()
|
||||
Open a temporary file. Throws @code{std.Error} in case of I/O error.
|
||||
@item tmpfile(errorObj = undefined)
|
||||
Open a temporary file. Return the FILE
|
||||
object or @code{null} in case of I/O error. If @code{errorObj} is not
|
||||
undefined, set its @code{errno} property to the error code or to 0 if
|
||||
no error occured.
|
||||
|
||||
@item puts(str)
|
||||
Equivalent to @code{std.out.puts(str)}.
|
||||
|
||||
@item printf(fmt, ...args)
|
||||
Equivalent to @code{std.out.printf(fmt, ...args)}
|
||||
Equivalent to @code{std.out.printf(fmt, ...args)}.
|
||||
|
||||
@item sprintf(fmt, ...args)
|
||||
Equivalent to the libc sprintf().
|
||||
@ -428,6 +422,27 @@ Wrappers to the libc file @code{stdin}, @code{stdout}, @code{stderr}.
|
||||
@item SEEK_END
|
||||
Constants for seek().
|
||||
|
||||
@item Error
|
||||
|
||||
Enumeration object containing the integer value of common errors
|
||||
(additional error codes may be defined):
|
||||
|
||||
@table @code
|
||||
@item EINVAL
|
||||
@item EIO
|
||||
@item EACCES
|
||||
@item EEXIST
|
||||
@item ENOSPC
|
||||
@item ENOSYS
|
||||
@item EBUSY
|
||||
@item ENOENT
|
||||
@item EPERM
|
||||
@item EPIPE
|
||||
@end table
|
||||
|
||||
@item strerror(errno)
|
||||
Return a string that describes the error @code{errno}.
|
||||
|
||||
@item gc()
|
||||
Manually invoke the cycle removal algorithm. The cycle removal
|
||||
algorithm is automatically started when needed, so this function is
|
||||
@ -437,6 +452,16 @@ useful in case of specific memory constraints or for testing.
|
||||
Return the value of the environment variable @code{name} or
|
||||
@code{undefined} if it is not defined.
|
||||
|
||||
@item setenv(name, value)
|
||||
Set the value of the environment variable @code{name} to the string
|
||||
@code{value}.
|
||||
|
||||
@item unsetenv(name)
|
||||
Delete the environment variable @code{name}.
|
||||
|
||||
@item getenviron()
|
||||
Return an object containing the environment variables as key-value pairs.
|
||||
|
||||
@item urlGet(url, options = undefined)
|
||||
|
||||
Download @code{url} using the @file{curl} command line
|
||||
@ -450,37 +475,66 @@ 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}
|
||||
(status code). If @code{full} is false, only the response is
|
||||
returned if the status is between 200 and 299. Otherwise an
|
||||
@code{std.Error} exception is raised.
|
||||
(status code). @code{response} is @code{null} is case of protocol or
|
||||
network error. If @code{full} is false, only the response is
|
||||
returned if the status is between 200 and 299. Otherwise @code{null}
|
||||
is returned.
|
||||
|
||||
@end table
|
||||
|
||||
@item parseExtJSON(str)
|
||||
|
||||
Parse @code{str} using a superset of @code{JSON.parse}. The
|
||||
following extensions are accepted:
|
||||
|
||||
@itemize
|
||||
@item Single line and multiline comments
|
||||
@item unquoted properties (ASCII-only Javascript identifiers)
|
||||
@item trailing comma in array and object definitions
|
||||
@item single quoted strings
|
||||
@item @code{\f} and @code{\v} are accepted as space characters
|
||||
@item leading plus in numbers
|
||||
@item octal (@code{0o} prefix) and hexadecimal (@code{0x} prefix) numbers
|
||||
@end itemize
|
||||
@end table
|
||||
|
||||
FILE prototype:
|
||||
|
||||
@table @code
|
||||
@item close()
|
||||
Close the file.
|
||||
Close the file. Return 0 if OK or @code{-errno} in case of I/O error.
|
||||
@item puts(str)
|
||||
Outputs the string with the UTF-8 encoding.
|
||||
@item printf(fmt, ...args)
|
||||
Formatted printf, same formats as the libc printf.
|
||||
Formatted printf.
|
||||
|
||||
The same formats as the standard C library @code{printf} are
|
||||
supported. Integer format types (e.g. @code{%d}) truncate the Numbers
|
||||
or BigInts to 32 bits. Use the @code{l} modifier (e.g. @code{%ld}) to
|
||||
truncate to 64 bits.
|
||||
|
||||
@item flush()
|
||||
Flush the buffered file.
|
||||
@item seek(offset, whence)
|
||||
Seek to a give file position (whence is @code{std.SEEK_*}). Throws a
|
||||
@code{std.Error} in case of I/O error.
|
||||
Seek to a give file position (whence is
|
||||
@code{std.SEEK_*}). @code{offset} can be a number or a bigint. Return
|
||||
0 if OK or @code{-errno} in case of I/O error.
|
||||
@item tell()
|
||||
Return the current file position.
|
||||
@item tello()
|
||||
Return the current file position as a bigint.
|
||||
@item eof()
|
||||
Return true if end of file.
|
||||
@item fileno()
|
||||
Return the associated OS handle.
|
||||
@item error()
|
||||
Return true if there was an error.
|
||||
@item clearerr()
|
||||
Clear the error indication.
|
||||
|
||||
@item read(buffer, position, length)
|
||||
Read @code{length} bytes from the file to the ArrayBuffer @code{buffer} at byte
|
||||
@ -488,14 +542,19 @@ position @code{position} (wrapper to the libc @code{fread}).
|
||||
|
||||
@item write(buffer, position, length)
|
||||
Write @code{length} bytes to the file from the ArrayBuffer @code{buffer} at byte
|
||||
position @code{position} (wrapper to the libc @code{fread}).
|
||||
position @code{position} (wrapper to the libc @code{fwrite}).
|
||||
|
||||
@item getline()
|
||||
Return the next line from the file, assuming UTF-8 encoding, excluding
|
||||
the trailing line feed.
|
||||
|
||||
@item readAsString(max_size = undefined)
|
||||
Read @code{max_size} bytes from the file and return them as a string
|
||||
assuming UTF-8 encoding. If @code{max_size} is not present, the file
|
||||
is read up its end.
|
||||
|
||||
@item getByte()
|
||||
Return the next byte from the file.
|
||||
Return the next byte from the file. Return -1 if the end of file is reached.
|
||||
|
||||
@item putByte(c)
|
||||
Write one byte to the file.
|
||||
@ -510,6 +569,7 @@ The @code{os} module provides Operating System specific functions:
|
||||
@item signals
|
||||
@item timers
|
||||
@item asynchronous I/O
|
||||
@item workers (threads)
|
||||
@end itemize
|
||||
|
||||
The OS functions usually return 0 if OK or an OS specific negative
|
||||
@ -537,7 +597,9 @@ POSIX open flags.
|
||||
Close the file handle @code{fd}.
|
||||
|
||||
@item seek(fd, offset, whence)
|
||||
Seek in the file. Use @code{std.SEEK_*} for @code{whence}.
|
||||
Seek in the file. Use @code{std.SEEK_*} for
|
||||
@code{whence}. @code{offset} is either a number or a bigint. If
|
||||
@code{offset} is a bigint, a bigint is returned too.
|
||||
|
||||
@item read(fd, buffer, offset, length)
|
||||
Read @code{length} bytes from the file handle @code{fd} to the
|
||||
@ -559,10 +621,10 @@ Return the TTY size as @code{[width, height]} or @code{null} if not available.
|
||||
Set the TTY in raw mode.
|
||||
|
||||
@item remove(filename)
|
||||
Remove a file. Return 0 if OK or < 0 if error.
|
||||
Remove a file. Return 0 if OK or @code{-errno}.
|
||||
|
||||
@item rename(oldname, newname)
|
||||
Rename a file. Return 0 if OK or < 0 if error.
|
||||
Rename a file. Return 0 if OK or @code{-errno}.
|
||||
|
||||
@item realpath(path)
|
||||
Return @code{[str, err]} where @code{str} is the canonicalized absolute
|
||||
@ -572,8 +634,11 @@ pathname of @code{path} and @code{err} the error code.
|
||||
Return @code{[str, err]} where @code{str} is the current working directory
|
||||
and @code{err} the error code.
|
||||
|
||||
@item chdir(path)
|
||||
Change the current directory. Return 0 if OK or @code{-errno}.
|
||||
|
||||
@item mkdir(path, mode = 0o777)
|
||||
Create a directory at @code{path}. Return the error code.
|
||||
Create a directory at @code{path}. Return 0 if OK or @code{-errno}.
|
||||
|
||||
@item stat(path)
|
||||
@item lstat(path)
|
||||
@ -602,10 +667,10 @@ Constants to interpret the @code{mode} property returned by
|
||||
|
||||
@item utimes(path, atime, mtime)
|
||||
Change the access and modification times of the file @code{path}. The
|
||||
times are specified in milliseconds since 1970.
|
||||
times are specified in milliseconds since 1970. Return 0 if OK or @code{-errno}.
|
||||
|
||||
@item symlink(target, linkpath)
|
||||
Create a link at @code{linkpath} containing the string @code{target}.
|
||||
Create a link at @code{linkpath} containing the string @code{target}. Return 0 if OK or @code{-errno}.
|
||||
|
||||
@item readlink(path)
|
||||
Return @code{[str, err]} where @code{str} is the link target and @code{err}
|
||||
@ -620,19 +685,19 @@ the error code.
|
||||
Add a read handler to the file handle @code{fd}. @code{func} is called
|
||||
each time there is data pending for @code{fd}. A single read handler
|
||||
per file handle is supported. Use @code{func = null} to remove the
|
||||
hander.
|
||||
handler.
|
||||
|
||||
@item setWriteHandler(fd, func)
|
||||
Add a write handler to the file handle @code{fd}. @code{func} is
|
||||
called each time data can be written to @code{fd}. A single write
|
||||
handler per file handle is supported. Use @code{func = null} to remove
|
||||
the hander.
|
||||
the handler.
|
||||
|
||||
@item signal(signal, func)
|
||||
Call the function @code{func} when the signal @code{signal}
|
||||
happens. Only a single handler per signal number is supported. Use
|
||||
@code{null} to set the default handler or @code{undefined} to ignore
|
||||
the signal.
|
||||
the signal. Signal handlers can only be defined in the main thread.
|
||||
|
||||
@item SIGINT
|
||||
@item SIGABRT
|
||||
@ -652,7 +717,7 @@ object containing optional parameters:
|
||||
@table @code
|
||||
@item block
|
||||
Boolean (default = true). If true, wait until the process is
|
||||
termined. In this case, @code{exec} return the exit code if positive
|
||||
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.
|
||||
|
||||
@ -670,11 +735,23 @@ object containing optional parameters:
|
||||
@item stdout
|
||||
@item stderr
|
||||
If present, set the handle in the child for stdin, stdout or stderr.
|
||||
|
||||
|
||||
@item env
|
||||
Object. If present, set the process environment from the object
|
||||
key-value pairs. Otherwise use the same environment as the current
|
||||
process.
|
||||
|
||||
@item uid
|
||||
Integer. If present, the process uid with @code{setuid}.
|
||||
|
||||
@item gid
|
||||
Integer. If present, the process gid with @code{setgid}.
|
||||
|
||||
@end table
|
||||
|
||||
@item waitpid(pid, options)
|
||||
@code{waitpid} Unix system call. Return the array @code{[ret, status]}.
|
||||
@code{waitpid} Unix system call. Return the array @code{[ret,
|
||||
status]}. @code{ret} contains @code{-errno} in case of error.
|
||||
|
||||
@item WNOHANG
|
||||
Constant for the @code{options} argument of @code{waitpid}.
|
||||
@ -703,6 +780,46 @@ Cancel a timer.
|
||||
Return a string representing the platform: @code{"linux"}, @code{"darwin"},
|
||||
@code{"win32"} or @code{"js"}.
|
||||
|
||||
@item Worker(module_filename)
|
||||
Constructor to create a new thread (worker) with an API close to the
|
||||
@code{WebWorkers}. @code{module_filename} is a string specifying the
|
||||
module filename which is executed in the newly created thread. As for
|
||||
dynamically imported module, it is relative to the current script or
|
||||
module path. Threads normally don't share any data and communicate
|
||||
between each other with messages. Nested workers are not supported. An
|
||||
example is available in @file{tests/test_worker.js}.
|
||||
|
||||
The worker class has the following static properties:
|
||||
|
||||
@table @code
|
||||
@item parent
|
||||
In the created worker, @code{Worker.parent} represents the parent
|
||||
worker and is used to send or receive messages.
|
||||
@end table
|
||||
|
||||
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
|
||||
between workers.
|
||||
|
||||
Current limitations: @code{Map} and @code{Set} are not supported
|
||||
yet.
|
||||
|
||||
@item onmessage
|
||||
|
||||
Getter and setter. Set a function which is called each time a
|
||||
message is received. The function is called with a single
|
||||
argument. It is an object with a @code{data} property containing the
|
||||
received message. The thread is not terminated if there is at least
|
||||
one non @code{null} @code{onmessage} handler.
|
||||
|
||||
@end table
|
||||
|
||||
@end table
|
||||
|
||||
@section QuickJS C API
|
||||
@ -719,7 +836,7 @@ supported.
|
||||
|
||||
@code{JSContext} represents a Javascript context (or Realm). Each
|
||||
JSContext has its own global objects and system objects. There can be
|
||||
several JSContexts per JSRuntime and they can share objects, similary
|
||||
several JSContexts per JSRuntime and they can share objects, similar
|
||||
to frames of the same origin sharing Javascript objects in a
|
||||
web browser.
|
||||
|
||||
@ -727,7 +844,7 @@ web browser.
|
||||
|
||||
@code{JSValue} represents a Javascript value which can be a primitive
|
||||
type or an object. Reference counting is used, so it is important to
|
||||
explicitely duplicate (@code{JS_DupValue()}, increment the reference
|
||||
explicitly duplicate (@code{JS_DupValue()}, increment the reference
|
||||
count) or free (@code{JS_FreeValue()}, decrement the reference count)
|
||||
JSValues.
|
||||
|
||||
@ -747,9 +864,9 @@ general rule, C functions take constant @code{JSValue}s as parameters
|
||||
@subsection Exceptions
|
||||
|
||||
Exceptions: most C functions can return a Javascript exception. It
|
||||
must be explicitely tested and handled by the C code. The specific
|
||||
must be explicitly tested and handled by the C code. The specific
|
||||
@code{JSValue} @code{JS_EXCEPTION} indicates that an exception
|
||||
occured. The actual exception object is stored in the
|
||||
occurred. The actual exception object is stored in the
|
||||
@code{JSContext} and can be retrieved with @code{JS_GetException()}.
|
||||
|
||||
@subsection Script evaluation
|
||||
@ -934,16 +1051,16 @@ stack holds the Javascript parameters and local variables.
|
||||
|
||||
@section RegExp
|
||||
|
||||
A specific regular expression engine was developped. It is both small
|
||||
A specific regular expression engine was developed. It is both small
|
||||
and efficient and supports all the ES2020 features including the
|
||||
Unicode properties. As the Javascript compiler, it directly generates
|
||||
bytecode without a parse tree.
|
||||
|
||||
Backtracking with an explicit stack is used so that there is no
|
||||
recursion on the system stack. Simple quantizers are specifically
|
||||
recursion on the system stack. Simple quantifiers are specifically
|
||||
optimized to avoid recursions.
|
||||
|
||||
Infinite recursions coming from quantizers with empty terms are
|
||||
Infinite recursions coming from quantifiers with empty terms are
|
||||
avoided.
|
||||
|
||||
The full regexp library weights about 15 KiB (x86 code), excluding the
|
||||
@ -951,9 +1068,9 @@ Unicode library.
|
||||
|
||||
@section Unicode
|
||||
|
||||
A specific Unicode library was developped so that there is no
|
||||
A specific Unicode library was developed so that there is no
|
||||
dependency on an external large Unicode library such as ICU. All the
|
||||
Unicode tables are compressed while keeping a reasonnable access
|
||||
Unicode tables are compressed while keeping a reasonable access
|
||||
speed.
|
||||
|
||||
The library supports case conversion, Unicode normalization, Unicode
|
||||
@ -962,10 +1079,10 @@ binary properties.
|
||||
|
||||
The full Unicode library weights about 45 KiB (x86 code).
|
||||
|
||||
@section BigInt and BigFloat
|
||||
@section BigInt, BigFloat, BigDecimal
|
||||
|
||||
BigInt and BigFloat are implemented with the @code{libbf}
|
||||
library@footnote{@url{https://bellard.org/libbf}}. It weights about 60
|
||||
BigInt, BigFloat and BigDecimal are implemented with the @code{libbf}
|
||||
library@footnote{@url{https://bellard.org/libbf}}. It weights about 90
|
||||
KiB (x86 code) and provides arbitrary precision IEEE 754 floating
|
||||
point operations and transcendental functions with exact rounding.
|
||||
|
||||
|
68
deps/quickjs/examples/pi_bigdecimal.js
vendored
Normal file
68
deps/quickjs/examples/pi_bigdecimal.js
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* PI computation in Javascript using the QuickJS bigdecimal type
|
||||
* (decimal floating point)
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/* compute PI with a precision of 'prec' digits */
|
||||
function calc_pi(prec) {
|
||||
const CHUD_A = 13591409m;
|
||||
const CHUD_B = 545140134m;
|
||||
const CHUD_C = 640320m;
|
||||
const CHUD_C3 = 10939058860032000m; /* C^3/24 */
|
||||
const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */
|
||||
|
||||
/* return [P, Q, G] */
|
||||
function chud_bs(a, b, need_G) {
|
||||
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1;
|
||||
if (a == (b - 1n)) {
|
||||
b1 = BigDecimal(b);
|
||||
G = (2m * b1 - 1m) * (6m * b1 - 1m) * (6m * b1 - 5m);
|
||||
P = G * (CHUD_B * b1 + CHUD_A);
|
||||
if (b & 1n)
|
||||
P = -P;
|
||||
G = G;
|
||||
Q = b1 * b1 * b1 * CHUD_C3;
|
||||
} else {
|
||||
c = (a + b) >> 1n;
|
||||
[P1, Q1, G1] = chud_bs(a, c, true);
|
||||
[P2, Q2, G2] = chud_bs(c, b, need_G);
|
||||
P = P1 * Q2 + P2 * G1;
|
||||
Q = Q1 * Q2;
|
||||
if (need_G)
|
||||
G = G1 * G2;
|
||||
else
|
||||
G = 0m;
|
||||
}
|
||||
return [P, Q, G];
|
||||
}
|
||||
|
||||
var n, P, Q, G;
|
||||
/* number of serie terms */
|
||||
n = BigInt(Math.ceil(prec / CHUD_DIGITS_PER_TERM)) + 10n;
|
||||
[P, Q, G] = chud_bs(0n, n, false);
|
||||
Q = BigDecimal.div(Q, (P + Q * CHUD_A),
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: prec });
|
||||
G = (CHUD_C / 12m) * BigDecimal.sqrt(CHUD_C,
|
||||
{ roundingMode: "half-even",
|
||||
maximumSignificantDigits: prec });
|
||||
return Q * G;
|
||||
}
|
||||
|
||||
(function() {
|
||||
var r, n_digits, n_bits;
|
||||
if (typeof scriptArgs != "undefined") {
|
||||
if (scriptArgs.length < 2) {
|
||||
print("usage: pi n_digits");
|
||||
return;
|
||||
}
|
||||
n_digits = scriptArgs[1] | 0;
|
||||
} else {
|
||||
n_digits = 1000;
|
||||
}
|
||||
/* we add more digits to reduce the probability of bad rounding for
|
||||
the last digits */
|
||||
r = calc_pi(n_digits + 20);
|
||||
print(r.toFixed(n_digits, "down"));
|
||||
})();
|
@ -1,29 +1,29 @@
|
||||
/*
|
||||
* PI computation in Javascript using the QuickJS bignum extensions
|
||||
* PI computation in Javascript using the QuickJS bigfloat type
|
||||
* (binary floating point)
|
||||
*/
|
||||
"use strict";
|
||||
"use bigint";
|
||||
|
||||
/* compute PI with a precision of 'prec' bits */
|
||||
function calc_pi(prec) {
|
||||
const CHUD_A = 13591409;
|
||||
const CHUD_B = 545140134;
|
||||
const CHUD_C = 640320;
|
||||
const CHUD_C3 = 10939058860032000; /* C^3/24 */
|
||||
function calc_pi() {
|
||||
const CHUD_A = 13591409n;
|
||||
const CHUD_B = 545140134n;
|
||||
const CHUD_C = 640320n;
|
||||
const CHUD_C3 = 10939058860032000n; /* C^3/24 */
|
||||
const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
|
||||
|
||||
/* return [P, Q, G] */
|
||||
function chud_bs(a, b, need_G) {
|
||||
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
|
||||
if (a == (b - 1)) {
|
||||
G = (2 * b - 1) * (6 * b - 1) * (6 * b - 5);
|
||||
if (a == (b - 1n)) {
|
||||
G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
|
||||
P = BigFloat(G * (CHUD_B * b + CHUD_A));
|
||||
if (b & 1)
|
||||
if (b & 1n)
|
||||
P = -P;
|
||||
G = BigFloat(G);
|
||||
Q = BigFloat(b * b * b * CHUD_C3);
|
||||
} else {
|
||||
c = (a + b) >> 1;
|
||||
c = (a + b) >> 1n;
|
||||
[P1, Q1, G1] = chud_bs(a, c, true);
|
||||
[P2, Q2, G2] = chud_bs(c, b, need_G);
|
||||
P = P1 * Q2 + P2 * G1;
|
||||
@ -31,17 +31,17 @@ function calc_pi(prec) {
|
||||
if (need_G)
|
||||
G = G1 * G2;
|
||||
else
|
||||
G = 0;
|
||||
G = 0l;
|
||||
}
|
||||
return [P, Q, G];
|
||||
}
|
||||
|
||||
var n, P, Q, G;
|
||||
/* number of serie terms */
|
||||
n = Math.ceil(BigFloatEnv.prec / CHUD_BITS_PER_TERM) + 10;
|
||||
[P, Q, G] = chud_bs(0, n, false);
|
||||
Q = Q / (P + Q * CHUD_A);
|
||||
G = (CHUD_C / 12) * BigFloat.sqrt(CHUD_C);
|
||||
n = BigInt(Math.ceil(BigFloatEnv.prec / CHUD_BITS_PER_TERM)) + 10n;
|
||||
[P, Q, G] = chud_bs(0n, n, false);
|
||||
Q = Q / (P + Q * BigFloat(CHUD_A));
|
||||
G = BigFloat((CHUD_C / 12n)) * BigFloat.sqrt(BigFloat(CHUD_C));
|
||||
return Q * G;
|
||||
}
|
||||
|
118
deps/quickjs/examples/pi_bigint.js
vendored
Normal file
118
deps/quickjs/examples/pi_bigint.js
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* PI computation in Javascript using the BigInt type
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/* return floor(log2(a)) for a > 0 and 0 for a = 0 */
|
||||
function floor_log2(a)
|
||||
{
|
||||
var k_max, a1, k, i;
|
||||
k_max = 0n;
|
||||
while ((a >> (2n ** k_max)) != 0n) {
|
||||
k_max++;
|
||||
}
|
||||
k = 0n;
|
||||
a1 = a;
|
||||
for(i = k_max - 1n; i >= 0n; i--) {
|
||||
a1 = a >> (2n ** i);
|
||||
if (a1 != 0n) {
|
||||
a = a1;
|
||||
k |= (1n << i);
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
/* return ceil(log2(a)) for a > 0 */
|
||||
function ceil_log2(a)
|
||||
{
|
||||
return floor_log2(a - 1n) + 1n;
|
||||
}
|
||||
|
||||
/* return floor(sqrt(a)) (not efficient but simple) */
|
||||
function int_sqrt(a)
|
||||
{
|
||||
var l, u, s;
|
||||
if (a == 0n)
|
||||
return a;
|
||||
l = ceil_log2(a);
|
||||
u = 1n << ((l + 1n) / 2n);
|
||||
/* u >= floor(sqrt(a)) */
|
||||
for(;;) {
|
||||
s = u;
|
||||
u = ((a / s) + s) / 2n;
|
||||
if (u >= s)
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* return pi * 2**prec */
|
||||
function calc_pi(prec) {
|
||||
const CHUD_A = 13591409n;
|
||||
const CHUD_B = 545140134n;
|
||||
const CHUD_C = 640320n;
|
||||
const CHUD_C3 = 10939058860032000n; /* C^3/24 */
|
||||
const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
|
||||
|
||||
/* return [P, Q, G] */
|
||||
function chud_bs(a, b, need_G) {
|
||||
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
|
||||
if (a == (b - 1n)) {
|
||||
G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
|
||||
P = G * (CHUD_B * b + CHUD_A);
|
||||
if (b & 1n)
|
||||
P = -P;
|
||||
Q = b * b * b * CHUD_C3;
|
||||
} else {
|
||||
c = (a + b) >> 1n;
|
||||
[P1, Q1, G1] = chud_bs(a, c, true);
|
||||
[P2, Q2, G2] = chud_bs(c, b, need_G);
|
||||
P = P1 * Q2 + P2 * G1;
|
||||
Q = Q1 * Q2;
|
||||
if (need_G)
|
||||
G = G1 * G2;
|
||||
else
|
||||
G = 0n;
|
||||
}
|
||||
return [P, Q, G];
|
||||
}
|
||||
|
||||
var n, P, Q, G;
|
||||
/* number of serie terms */
|
||||
n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n;
|
||||
[P, Q, G] = chud_bs(0n, n, false);
|
||||
Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A);
|
||||
G = int_sqrt(CHUD_C << (2n * prec));
|
||||
return (Q * G) >> prec;
|
||||
}
|
||||
|
||||
function main(args) {
|
||||
var r, n_digits, n_bits, out;
|
||||
if (args.length < 1) {
|
||||
print("usage: pi n_digits");
|
||||
return;
|
||||
}
|
||||
n_digits = args[0] | 0;
|
||||
|
||||
/* we add more bits to reduce the probability of bad rounding for
|
||||
the last digits */
|
||||
n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n;
|
||||
r = calc_pi(n_bits);
|
||||
r = ((10n ** BigInt(n_digits)) * r) >> n_bits;
|
||||
out = r.toString();
|
||||
print(out[0] + "." + out.slice(1));
|
||||
}
|
||||
|
||||
var args;
|
||||
if (typeof scriptArgs != "undefined") {
|
||||
args = scriptArgs;
|
||||
args.shift();
|
||||
} else if (typeof arguments != "undefined") {
|
||||
args = arguments;
|
||||
} else {
|
||||
/* default: 1000 digits */
|
||||
args=[1000];
|
||||
}
|
||||
|
||||
main(args);
|
151
deps/quickjs/examples/point.c
vendored
Normal file
151
deps/quickjs/examples/point.c
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* QuickJS: Example of C module with a class
|
||||
*
|
||||
* Copyright (c) 2019 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "../quickjs.h"
|
||||
#include <math.h>
|
||||
|
||||
#define countof(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
/* Point Class */
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
} JSPointData;
|
||||
|
||||
static JSClassID js_point_class_id;
|
||||
|
||||
static void js_point_finalizer(JSRuntime *rt, JSValue val)
|
||||
{
|
||||
JSPointData *s = JS_GetOpaque(val, js_point_class_id);
|
||||
/* Note: 's' can be NULL in case JS_SetOpaque() was not called */
|
||||
js_free_rt(rt, s);
|
||||
}
|
||||
|
||||
static JSValue js_point_ctor(JSContext *ctx,
|
||||
JSValueConst new_target,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
JSPointData *s;
|
||||
JSValue obj = JS_UNDEFINED;
|
||||
JSValue proto;
|
||||
|
||||
s = js_mallocz(ctx, sizeof(*s));
|
||||
if (!s)
|
||||
return JS_EXCEPTION;
|
||||
if (JS_ToInt32(ctx, &s->x, argv[0]))
|
||||
goto fail;
|
||||
if (JS_ToInt32(ctx, &s->y, argv[1]))
|
||||
goto fail;
|
||||
/* using new_target to get the prototype is necessary when the
|
||||
class is extended. */
|
||||
proto = JS_GetPropertyStr(ctx, new_target, "prototype");
|
||||
if (JS_IsException(proto))
|
||||
goto fail;
|
||||
obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id);
|
||||
JS_FreeValue(ctx, proto);
|
||||
if (JS_IsException(obj))
|
||||
goto fail;
|
||||
JS_SetOpaque(obj, s);
|
||||
return obj;
|
||||
fail:
|
||||
js_free(ctx, s);
|
||||
JS_FreeValue(ctx, obj);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic)
|
||||
{
|
||||
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
|
||||
if (!s)
|
||||
return JS_EXCEPTION;
|
||||
if (magic == 0)
|
||||
return JS_NewInt32(ctx, s->x);
|
||||
else
|
||||
return JS_NewInt32(ctx, s->y);
|
||||
}
|
||||
|
||||
static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic)
|
||||
{
|
||||
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
|
||||
int v;
|
||||
if (!s)
|
||||
return JS_EXCEPTION;
|
||||
if (JS_ToInt32(ctx, &v, val))
|
||||
return JS_EXCEPTION;
|
||||
if (magic == 0)
|
||||
s->x = v;
|
||||
else
|
||||
s->y = v;
|
||||
return JS_UNDEFINED;
|
||||
}
|
||||
|
||||
static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
|
||||
if (!s)
|
||||
return JS_EXCEPTION;
|
||||
return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y));
|
||||
}
|
||||
|
||||
static JSClassDef js_point_class = {
|
||||
"Point",
|
||||
.finalizer = js_point_finalizer,
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_point_proto_funcs[] = {
|
||||
JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0),
|
||||
JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1),
|
||||
JS_CFUNC_DEF("norm", 0, js_point_norm),
|
||||
};
|
||||
|
||||
static int js_point_init(JSContext *ctx, JSModuleDef *m)
|
||||
{
|
||||
JSValue point_proto, point_class;
|
||||
|
||||
/* create the Point class */
|
||||
JS_NewClassID(&js_point_class_id);
|
||||
JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class);
|
||||
|
||||
point_proto = JS_NewObject(ctx);
|
||||
JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs));
|
||||
|
||||
point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0);
|
||||
/* set proto.constructor and ctor.prototype */
|
||||
JS_SetConstructor(ctx, point_class, point_proto);
|
||||
JS_SetClassProto(ctx, js_point_class_id, point_proto);
|
||||
|
||||
JS_SetModuleExport(ctx, m, "Point", point_class);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSModuleDef *js_init_module(JSContext *ctx, const char *module_name)
|
||||
{
|
||||
JSModuleDef *m;
|
||||
m = JS_NewCModule(ctx, module_name, js_point_init);
|
||||
if (!m)
|
||||
return NULL;
|
||||
JS_AddModuleExport(ctx, m, "Point");
|
||||
return m;
|
||||
}
|
40
deps/quickjs/examples/test_point.js
vendored
Normal file
40
deps/quickjs/examples/test_point.js
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/* example of JS module importing a C module */
|
||||
import { Point } from "./point.so";
|
||||
|
||||
function assert(b, str)
|
||||
{
|
||||
if (b) {
|
||||
return;
|
||||
} else {
|
||||
throw Error("assertion failed: " + str);
|
||||
}
|
||||
}
|
||||
|
||||
class ColorPoint extends Point {
|
||||
constructor(x, y, color) {
|
||||
super(x, y);
|
||||
this.color = color;
|
||||
}
|
||||
get_color() {
|
||||
return this.color;
|
||||
}
|
||||
};
|
||||
|
||||
function main()
|
||||
{
|
||||
var pt, pt2;
|
||||
|
||||
pt = new Point(2, 3);
|
||||
assert(pt.x === 2);
|
||||
assert(pt.y === 3);
|
||||
pt.x = 4;
|
||||
assert(pt.x === 4);
|
||||
assert(pt.norm() == 5);
|
||||
|
||||
pt2 = new ColorPoint(2, 3, 0xffffff);
|
||||
assert(pt2.x === 2);
|
||||
assert(pt2.color === 0xffffff);
|
||||
assert(pt2.get_color() === 0xffffff);
|
||||
}
|
||||
|
||||
main();
|
918
deps/quickjs/jscompress.c
vendored
918
deps/quickjs/jscompress.c
vendored
@ -1,918 +0,0 @@
|
||||
/*
|
||||
* Javascript Compressor
|
||||
*
|
||||
* Copyright (c) 2008-2018 Fabrice Bellard
|
||||
* Copyright (c) 2017-2018 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cutils.h"
|
||||
|
||||
typedef struct JSToken {
|
||||
int tok;
|
||||
char buf[20];
|
||||
char *str;
|
||||
int len;
|
||||
int size;
|
||||
int line_num; /* line number for start of token */
|
||||
int lines; /* number of embedded linefeeds in token */
|
||||
} JSToken;
|
||||
|
||||
enum {
|
||||
TOK_EOF = 256,
|
||||
TOK_IDENT,
|
||||
TOK_STR1,
|
||||
TOK_STR2,
|
||||
TOK_STR3,
|
||||
TOK_NUM,
|
||||
TOK_COM,
|
||||
TOK_LCOM,
|
||||
};
|
||||
|
||||
void tok_reset(JSToken *tt)
|
||||
{
|
||||
if (tt->str != tt->buf) {
|
||||
free(tt->str);
|
||||
tt->str = tt->buf;
|
||||
tt->size = sizeof(tt->buf);
|
||||
}
|
||||
tt->len = 0;
|
||||
}
|
||||
|
||||
void tok_add_ch(JSToken *tt, int c)
|
||||
{
|
||||
if (tt->len + 1 > tt->size) {
|
||||
tt->size *= 2;
|
||||
if (tt->str == tt->buf) {
|
||||
tt->str = malloc(tt->size);
|
||||
memcpy(tt->str, tt->buf, tt->len);
|
||||
} else {
|
||||
tt->str = realloc(tt->str, tt->size);
|
||||
}
|
||||
}
|
||||
tt->str[tt->len++] = c;
|
||||
}
|
||||
|
||||
FILE *infile;
|
||||
const char *filename;
|
||||
int output_line_num;
|
||||
int line_num;
|
||||
int ch;
|
||||
JSToken tokc;
|
||||
|
||||
int skip_mask;
|
||||
#define DEFINE_MAX 20
|
||||
char *define_tab[DEFINE_MAX];
|
||||
int define_len;
|
||||
|
||||
void error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
if (filename) {
|
||||
fprintf(stderr, "%s:%d: ", filename, line_num);
|
||||
} else {
|
||||
fprintf(stderr, "jscompress: ");
|
||||
}
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void define_symbol(const char *def)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < define_len; i++) {
|
||||
if (!strcmp(tokc.str, define_tab[i]))
|
||||
return;
|
||||
}
|
||||
if (define_len >= DEFINE_MAX)
|
||||
error("too many defines");
|
||||
define_tab[define_len++] = strdup(def);
|
||||
}
|
||||
|
||||
void undefine_symbol(const char *def)
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 0; i < define_len; i++) {
|
||||
if (!strcmp(tokc.str, define_tab[i])) {
|
||||
free(define_tab[i]);
|
||||
} else {
|
||||
define_tab[j++] = define_tab[i];
|
||||
}
|
||||
}
|
||||
define_len = j;
|
||||
}
|
||||
|
||||
const char *find_symbol(const char *def)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < define_len; i++) {
|
||||
if (!strcmp(tokc.str, define_tab[i]))
|
||||
return "1";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void next(void);
|
||||
|
||||
void nextch(void)
|
||||
{
|
||||
ch = fgetc(infile);
|
||||
if (ch == '\n')
|
||||
line_num++;
|
||||
}
|
||||
|
||||
int skip_blanks(void)
|
||||
{
|
||||
for (;;) {
|
||||
next();
|
||||
if (tokc.tok != ' ' && tokc.tok != '\t' &&
|
||||
tokc.tok != TOK_COM && tokc.tok != TOK_LCOM)
|
||||
return tokc.tok;
|
||||
}
|
||||
}
|
||||
|
||||
void parse_directive(void)
|
||||
{
|
||||
int ifdef, mask = skip_mask;
|
||||
/* simplistic preprocessor:
|
||||
#define / #undef / #ifdef / #ifndef / #else / #endif
|
||||
no symbol substitution.
|
||||
*/
|
||||
skip_mask = 0; /* disable skipping to parse preprocessor line */
|
||||
nextch();
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected preprocessing directive after #");
|
||||
|
||||
if (!strcmp(tokc.str, "define")) {
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected identifier after #define");
|
||||
define_symbol(tokc.str);
|
||||
} else if (!strcmp(tokc.str, "undef")) {
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected identifier after #undef");
|
||||
undefine_symbol(tokc.str);
|
||||
} else if ((ifdef = 1, !strcmp(tokc.str, "ifdef")) ||
|
||||
(ifdef = 0, !strcmp(tokc.str, "ifndef"))) {
|
||||
if (skip_blanks() != TOK_IDENT)
|
||||
error("expected identifier after #ifdef/#ifndef");
|
||||
mask = (mask << 2) | 2 | ifdef;
|
||||
if (find_symbol(tokc.str))
|
||||
mask ^= 1;
|
||||
} else if (!strcmp(tokc.str, "else")) {
|
||||
if (!(mask & 2))
|
||||
error("#else without a #if");
|
||||
mask ^= 1;
|
||||
} else if (!strcmp(tokc.str, "endif")) {
|
||||
if (!(mask & 2))
|
||||
error("#endif without a #if");
|
||||
mask >>= 2;
|
||||
} else {
|
||||
error("unsupported preprocessing directive");
|
||||
}
|
||||
if (skip_blanks() != '\n')
|
||||
error("extra characters on preprocessing line");
|
||||
skip_mask = mask;
|
||||
}
|
||||
|
||||
/* return -1 if invalid char */
|
||||
static int hex_to_num(int ch)
|
||||
{
|
||||
if (ch >= 'a' && ch <= 'f')
|
||||
return ch - 'a' + 10;
|
||||
else if (ch >= 'A' && ch <= 'F')
|
||||
return ch - 'A' + 10;
|
||||
else if (ch >= '0' && ch <= '9')
|
||||
return ch - '0';
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
void next(void)
|
||||
{
|
||||
again:
|
||||
tok_reset(&tokc);
|
||||
tokc.line_num = line_num;
|
||||
tokc.lines = 0;
|
||||
switch(ch) {
|
||||
case EOF:
|
||||
tokc.tok = TOK_EOF;
|
||||
if (skip_mask)
|
||||
error("missing #endif");
|
||||
break;
|
||||
case 'a' ... 'z':
|
||||
case 'A' ... 'Z':
|
||||
case '_':
|
||||
case '$':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
while ((ch >= 'a' && ch <= 'z') ||
|
||||
(ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9') ||
|
||||
(ch == '_' || ch == '$')) {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_IDENT;
|
||||
break;
|
||||
case '.':
|
||||
nextch();
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, '.');
|
||||
goto has_dot;
|
||||
}
|
||||
tokc.tok = '.';
|
||||
break;
|
||||
case '0':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
if (ch == 'x' || ch == 'X') {
|
||||
/* hexa */
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
while ((ch >= 'a' && ch <= 'f') ||
|
||||
(ch >= 'A' && ch <= 'F') ||
|
||||
(ch >= '0' && ch <= '9')) {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_NUM;
|
||||
break;
|
||||
}
|
||||
goto has_digit;
|
||||
|
||||
case '1' ... '9':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
has_digit:
|
||||
/* decimal */
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
if (ch == '.') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
has_dot:
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
if (ch == 'e' || ch == 'E') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
if (ch == '+' || ch == '-') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_NUM;
|
||||
break;
|
||||
case '`':
|
||||
{
|
||||
nextch();
|
||||
while (ch != '`' && ch != EOF) {
|
||||
if (ch == '\\') {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
if (ch == EOF) {
|
||||
error("unexpected char after '\\'");
|
||||
}
|
||||
tok_add_ch(&tokc, ch);
|
||||
} else {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
nextch();
|
||||
tok_add_ch(&tokc, 0);
|
||||
tokc.tok = TOK_STR3;
|
||||
}
|
||||
break;
|
||||
case '\"':
|
||||
case '\'':
|
||||
{
|
||||
int n, i, c, hex_digit_count;
|
||||
int quote_ch;
|
||||
quote_ch = ch;
|
||||
nextch();
|
||||
while (ch != quote_ch && ch != EOF) {
|
||||
if (ch == '\\') {
|
||||
nextch();
|
||||
switch(ch) {
|
||||
case 'n':
|
||||
tok_add_ch(&tokc, '\n');
|
||||
nextch();
|
||||
break;
|
||||
case 'r':
|
||||
tok_add_ch(&tokc, '\r');
|
||||
nextch();
|
||||
break;
|
||||
case 't':
|
||||
tok_add_ch(&tokc, '\t');
|
||||
nextch();
|
||||
break;
|
||||
case 'v':
|
||||
tok_add_ch(&tokc, '\v');
|
||||
nextch();
|
||||
break;
|
||||
case '\"':
|
||||
case '\'':
|
||||
case '\\':
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
break;
|
||||
case '0' ... '7':
|
||||
n = 0;
|
||||
while (ch >= '0' && ch <= '7') {
|
||||
n = n * 8 + (ch - '0');
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, n);
|
||||
break;
|
||||
case 'x':
|
||||
case 'u':
|
||||
if (ch == 'x')
|
||||
hex_digit_count = 2;
|
||||
else
|
||||
hex_digit_count = 4;
|
||||
nextch();
|
||||
n = 0;
|
||||
for(i = 0; i < hex_digit_count; i++) {
|
||||
c = hex_to_num(ch);
|
||||
if (c < 0)
|
||||
error("unexpected char after '\\x'");
|
||||
n = n * 16 + c;
|
||||
nextch();
|
||||
}
|
||||
if (n >= 256)
|
||||
error("unicode is currently unsupported");
|
||||
tok_add_ch(&tokc, n);
|
||||
break;
|
||||
|
||||
default:
|
||||
error("unexpected char after '\\'");
|
||||
}
|
||||
} else {
|
||||
/* XXX: should refuse embedded newlines */
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
}
|
||||
nextch();
|
||||
tok_add_ch(&tokc, 0);
|
||||
if (quote_ch == '\'')
|
||||
tokc.tok = TOK_STR1;
|
||||
else
|
||||
tokc.tok = TOK_STR2;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
nextch();
|
||||
if (ch == '/') {
|
||||
tok_add_ch(&tokc, '/');
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
while (ch != '\n' && ch != EOF) {
|
||||
tok_add_ch(&tokc, ch);
|
||||
nextch();
|
||||
}
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_LCOM;
|
||||
} else if (ch == '*') {
|
||||
int last;
|
||||
tok_add_ch(&tokc, '/');
|
||||
tok_add_ch(&tokc, ch);
|
||||
last = 0;
|
||||
for(;;) {
|
||||
nextch();
|
||||
if (ch == EOF)
|
||||
error("unterminated comment");
|
||||
if (ch == '\n')
|
||||
tokc.lines++;
|
||||
tok_add_ch(&tokc, ch);
|
||||
if (last == '*' && ch == '/')
|
||||
break;
|
||||
last = ch;
|
||||
}
|
||||
nextch();
|
||||
tok_add_ch(&tokc, '\0');
|
||||
tokc.tok = TOK_COM;
|
||||
} else {
|
||||
tokc.tok = '/';
|
||||
}
|
||||
break;
|
||||
case '#':
|
||||
parse_directive();
|
||||
goto again;
|
||||
case '\n':
|
||||
/* adjust line number */
|
||||
tokc.line_num--;
|
||||
tokc.lines++;
|
||||
/* fall thru */
|
||||
default:
|
||||
tokc.tok = ch;
|
||||
nextch();
|
||||
break;
|
||||
}
|
||||
if (skip_mask & 1)
|
||||
goto again;
|
||||
}
|
||||
|
||||
void print_tok(FILE *f, JSToken *tt)
|
||||
{
|
||||
/* keep output lines in sync with input lines */
|
||||
while (output_line_num < tt->line_num) {
|
||||
putc('\n', f);
|
||||
output_line_num++;
|
||||
}
|
||||
|
||||
switch(tt->tok) {
|
||||
case TOK_IDENT:
|
||||
case TOK_COM:
|
||||
case TOK_LCOM:
|
||||
fprintf(f, "%s", tt->str);
|
||||
break;
|
||||
case TOK_NUM:
|
||||
{
|
||||
unsigned long a;
|
||||
char *p;
|
||||
a = strtoul(tt->str, &p, 0);
|
||||
if (*p == '\0' && a <= 0x7fffffff) {
|
||||
/* must be an integer */
|
||||
fprintf(f, "%d", (int)a);
|
||||
} else {
|
||||
fprintf(f, "%s", tt->str);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TOK_STR3:
|
||||
fprintf(f, "`%s`", tt->str);
|
||||
break;
|
||||
case TOK_STR1:
|
||||
case TOK_STR2:
|
||||
{
|
||||
int i, c, quote_ch;
|
||||
if (tt->tok == TOK_STR1)
|
||||
quote_ch = '\'';
|
||||
else
|
||||
quote_ch = '\"';
|
||||
fprintf(f, "%c", quote_ch);
|
||||
for(i = 0; i < tt->len - 1; i++) {
|
||||
c = (uint8_t)tt->str[i];
|
||||
switch(c) {
|
||||
case '\r':
|
||||
fprintf(f, "\\r");
|
||||
break;
|
||||
case '\n':
|
||||
fprintf(f, "\\n");
|
||||
break;
|
||||
case '\t':
|
||||
fprintf(f, "\\t");
|
||||
break;
|
||||
case '\v':
|
||||
fprintf(f, "\\v");
|
||||
break;
|
||||
case '\"':
|
||||
case '\'':
|
||||
if (c == quote_ch)
|
||||
fprintf(f, "\\%c", c);
|
||||
else
|
||||
fprintf(f, "%c", c);
|
||||
break;
|
||||
case '\\':
|
||||
fprintf(f, "\\\\");
|
||||
break;
|
||||
default:
|
||||
/* XXX: no utf-8 support! */
|
||||
if (c >= 32 && c <= 255) {
|
||||
fprintf(f, "%c", c);
|
||||
} else if (c <= 255)
|
||||
fprintf(f, "\\x%02x", c);
|
||||
else
|
||||
fprintf(f, "\\u%04x", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(f, "%c", quote_ch);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (tokc.tok >= 256)
|
||||
error("unsupported token in print_tok: %d", tt->tok);
|
||||
fprintf(f, "%c", tt->tok);
|
||||
break;
|
||||
}
|
||||
output_line_num += tt->lines;
|
||||
}
|
||||
|
||||
/* check if token pasting could occur */
|
||||
static BOOL compat_token(int c1, int c2)
|
||||
{
|
||||
if ((c1 == TOK_IDENT || c1 == TOK_NUM) &&
|
||||
(c2 == TOK_IDENT || c2 == TOK_NUM))
|
||||
return FALSE;
|
||||
|
||||
if ((c1 == c2 && strchr("+-<>&|=*/.", c1))
|
||||
|| (c2 == '=' && strchr("+-<>&|!*/^%", c1))
|
||||
|| (c1 == '=' && c2 == '>')
|
||||
|| (c1 == '/' && c2 == '*')
|
||||
|| (c1 == '.' && c2 == TOK_NUM)
|
||||
|| (c1 == TOK_NUM && c2 == '.'))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void js_compress(const char *filename, const char *outfilename,
|
||||
BOOL do_strip, BOOL keep_header)
|
||||
{
|
||||
FILE *outfile;
|
||||
int ltok, seen_space;
|
||||
|
||||
line_num = 1;
|
||||
infile = fopen(filename, "rb");
|
||||
if (!infile) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
output_line_num = 1;
|
||||
outfile = fopen(outfilename, "wb");
|
||||
if (!outfile) {
|
||||
perror(outfilename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
nextch();
|
||||
next();
|
||||
ltok = 0;
|
||||
seen_space = 0;
|
||||
if (do_strip) {
|
||||
if (keep_header) {
|
||||
while (tokc.tok == ' ' ||
|
||||
tokc.tok == '\n' ||
|
||||
tokc.tok == '\t' ||
|
||||
tokc.tok == '\v' ||
|
||||
tokc.tok == '\b' ||
|
||||
tokc.tok == '\f') {
|
||||
seen_space = 1;
|
||||
next();
|
||||
}
|
||||
if (tokc.tok == TOK_COM) {
|
||||
print_tok(outfile, &tokc);
|
||||
//fprintf(outfile, "\n");
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
if (tokc.tok == TOK_EOF)
|
||||
break;
|
||||
if (tokc.tok == ' ' ||
|
||||
tokc.tok == '\r' ||
|
||||
tokc.tok == '\t' ||
|
||||
tokc.tok == '\v' ||
|
||||
tokc.tok == '\b' ||
|
||||
tokc.tok == '\f' ||
|
||||
tokc.tok == TOK_LCOM ||
|
||||
tokc.tok == TOK_COM) {
|
||||
/* don't print spaces or comments */
|
||||
seen_space = 1;
|
||||
} else if (tokc.tok == TOK_STR3) {
|
||||
print_tok(outfile, &tokc);
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
} else if (tokc.tok == TOK_STR1 || tokc.tok == TOK_STR2) {
|
||||
int count, i;
|
||||
/* find the optimal quote char */
|
||||
count = 0;
|
||||
for(i = 0; i < tokc.len; i++) {
|
||||
if (tokc.str[i] == '\'')
|
||||
count++;
|
||||
else if (tokc.str[i] == '\"')
|
||||
count--;
|
||||
}
|
||||
if (count > 0)
|
||||
tokc.tok = TOK_STR2;
|
||||
else if (count < 0)
|
||||
tokc.tok = TOK_STR1;
|
||||
print_tok(outfile, &tokc);
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
} else {
|
||||
if (seen_space && !compat_token(ltok, tokc.tok)) {
|
||||
fprintf(outfile, " ");
|
||||
}
|
||||
print_tok(outfile, &tokc);
|
||||
ltok = tokc.tok;
|
||||
seen_space = 0;
|
||||
}
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
/* just handle preprocessing */
|
||||
while (tokc.tok != TOK_EOF) {
|
||||
print_tok(outfile, &tokc);
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
fclose(outfile);
|
||||
fclose(infile);
|
||||
}
|
||||
|
||||
#define HASH_SIZE 30011
|
||||
#define MATCH_LEN_MIN 3
|
||||
#define MATCH_LEN_MAX (4 + 63)
|
||||
#define DIST_MAX 65535
|
||||
|
||||
static int find_longest_match(int *pdist, const uint8_t *src, int src_len,
|
||||
const int *hash_next, int cur_pos)
|
||||
{
|
||||
int pos, i, match_len, match_pos, pos_min, len_max;
|
||||
|
||||
len_max = min_int(src_len - cur_pos, MATCH_LEN_MAX);
|
||||
match_len = 0;
|
||||
match_pos = 0;
|
||||
pos_min = max_int(cur_pos - DIST_MAX - 1, 0);
|
||||
pos = hash_next[cur_pos];
|
||||
while (pos >= pos_min) {
|
||||
for(i = 0; i < len_max; i++) {
|
||||
if (src[cur_pos + i] != src[pos + i])
|
||||
break;
|
||||
}
|
||||
if (i > match_len) {
|
||||
match_len = i;
|
||||
match_pos = pos;
|
||||
}
|
||||
pos = hash_next[pos];
|
||||
}
|
||||
*pdist = cur_pos - match_pos - 1;
|
||||
return match_len;
|
||||
}
|
||||
|
||||
int lz_compress(uint8_t **pdst, const uint8_t *src, int src_len)
|
||||
{
|
||||
int *hash_table, *hash_next;
|
||||
uint32_t h, v;
|
||||
int i, dist, len, len1, dist1;
|
||||
uint8_t *dst, *q;
|
||||
|
||||
/* build the hash table */
|
||||
|
||||
hash_table = malloc(sizeof(hash_table[0]) * HASH_SIZE);
|
||||
for(i = 0; i < HASH_SIZE; i++)
|
||||
hash_table[i] = -1;
|
||||
hash_next = malloc(sizeof(hash_next[0]) * src_len);
|
||||
for(i = 0; i < src_len; i++)
|
||||
hash_next[i] = -1;
|
||||
|
||||
for(i = 0; i < src_len - MATCH_LEN_MIN + 1; i++) {
|
||||
h = ((src[i] << 16) | (src[i + 1] << 8) | src[i + 2]) % HASH_SIZE;
|
||||
hash_next[i] = hash_table[h];
|
||||
hash_table[h] = i;
|
||||
}
|
||||
for(;i < src_len; i++) {
|
||||
hash_next[i] = -1;
|
||||
}
|
||||
free(hash_table);
|
||||
|
||||
dst = malloc(src_len + 4); /* never larger than the source */
|
||||
q = dst;
|
||||
*q++ = src_len >> 24;
|
||||
*q++ = src_len >> 16;
|
||||
*q++ = src_len >> 8;
|
||||
*q++ = src_len >> 0;
|
||||
/* compress */
|
||||
i = 0;
|
||||
while (i < src_len) {
|
||||
if (src[i] >= 128)
|
||||
return -1;
|
||||
len = find_longest_match(&dist, src, src_len, hash_next, i);
|
||||
if (len >= MATCH_LEN_MIN) {
|
||||
/* heuristic: see if better length just after */
|
||||
len1 = find_longest_match(&dist1, src, src_len, hash_next, i + 1);
|
||||
if (len1 > len)
|
||||
goto no_match;
|
||||
}
|
||||
if (len < MATCH_LEN_MIN) {
|
||||
no_match:
|
||||
*q++ = src[i];
|
||||
i++;
|
||||
} else if (len <= (3 + 15) && dist < (1 << 10)) {
|
||||
v = 0x8000 | ((len - 3) << 10) | dist;
|
||||
*q++ = v >> 8;
|
||||
*q++ = v;
|
||||
i += len;
|
||||
} else if (len >= 4 && len <= (4 + 63) && dist < (1 << 16)) {
|
||||
v = 0xc00000 | ((len - 4) << 16) | dist;
|
||||
*q++ = v >> 16;
|
||||
*q++ = v >> 8;
|
||||
*q++ = v;
|
||||
i += len;
|
||||
} else {
|
||||
goto no_match;
|
||||
}
|
||||
}
|
||||
free(hash_next);
|
||||
*pdst = dst;
|
||||
return q - dst;
|
||||
}
|
||||
|
||||
static int load_file(uint8_t **pbuf, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
uint8_t *buf;
|
||||
int buf_len;
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
buf_len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
buf = malloc(buf_len + 1);
|
||||
fread(buf, 1, buf_len, f);
|
||||
buf[buf_len] = '\0';
|
||||
fclose(f);
|
||||
*pbuf = buf;
|
||||
return buf_len;
|
||||
}
|
||||
|
||||
static void save_file(const char *filename, const uint8_t *buf, int buf_len)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
fwrite(buf, 1, buf_len, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void save_c_source(const char *filename, const uint8_t *buf, int buf_len,
|
||||
const char *var_name)
|
||||
{
|
||||
FILE *f;
|
||||
int i;
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
perror(filename);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(f, "/* This file is automatically generated - do not edit */\n\n");
|
||||
fprintf(f, "const uint8_t %s[] = {\n", var_name);
|
||||
for(i = 0; i < buf_len; i++) {
|
||||
fprintf(f, " 0x%02x,", buf[i]);
|
||||
if ((i % 8) == 7 || (i == buf_len - 1))
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
fprintf(f, "};\n");
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#define DEFAULT_OUTPUT_FILENAME "out.js"
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("jscompress version 1.0 Copyright (c) 2008-2018 Fabrice Bellard\n"
|
||||
"usage: jscompress [options] filename\n"
|
||||
"Javascript compressor\n"
|
||||
"\n"
|
||||
"-h print this help\n"
|
||||
"-n do not compress spaces\n"
|
||||
"-H keep the first comment\n"
|
||||
"-c compress to file\n"
|
||||
"-C name compress to C source ('name' is the variable name)\n"
|
||||
"-D symbol define preprocessor symbol\n"
|
||||
"-U symbol undefine preprocessor symbol\n"
|
||||
"-o outfile set the output filename (default=%s)\n",
|
||||
DEFAULT_OUTPUT_FILENAME);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int c, do_strip, keep_header, compress;
|
||||
const char *out_filename, *c_var, *fname;
|
||||
char tmpfilename[1024];
|
||||
|
||||
do_strip = 1;
|
||||
keep_header = 0;
|
||||
out_filename = DEFAULT_OUTPUT_FILENAME;
|
||||
compress = 0;
|
||||
c_var = NULL;
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "hno:HcC:D:U:");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'h':
|
||||
help();
|
||||
break;
|
||||
case 'n':
|
||||
do_strip = 0;
|
||||
break;
|
||||
case 'o':
|
||||
out_filename = optarg;
|
||||
break;
|
||||
case 'H':
|
||||
keep_header = 1;
|
||||
break;
|
||||
case 'c':
|
||||
compress = 1;
|
||||
break;
|
||||
case 'C':
|
||||
c_var = optarg;
|
||||
compress = 1;
|
||||
break;
|
||||
case 'D':
|
||||
define_symbol(optarg);
|
||||
break;
|
||||
case 'U':
|
||||
undefine_symbol(optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (optind >= argc)
|
||||
help();
|
||||
|
||||
filename = argv[optind++];
|
||||
|
||||
if (compress) {
|
||||
#if defined(__ANDROID__)
|
||||
/* XXX: use another directory ? */
|
||||
snprintf(tmpfilename, sizeof(tmpfilename), "out.%d", getpid());
|
||||
#else
|
||||
snprintf(tmpfilename, sizeof(tmpfilename), "/tmp/out.%d", getpid());
|
||||
#endif
|
||||
fname = tmpfilename;
|
||||
} else {
|
||||
fname = out_filename;
|
||||
}
|
||||
js_compress(filename, fname, do_strip, keep_header);
|
||||
|
||||
if (compress) {
|
||||
uint8_t *buf1, *buf2;
|
||||
int buf1_len, buf2_len;
|
||||
|
||||
buf1_len = load_file(&buf1, fname);
|
||||
unlink(fname);
|
||||
buf2_len = lz_compress(&buf2, buf1, buf1_len);
|
||||
if (buf2_len < 0) {
|
||||
fprintf(stderr, "Could not compress file (UTF8 chars are forbidden)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (c_var) {
|
||||
save_c_source(out_filename, buf2, buf2_len, c_var);
|
||||
} else {
|
||||
save_file(out_filename, buf2, buf2_len);
|
||||
}
|
||||
free(buf1);
|
||||
free(buf2);
|
||||
}
|
||||
return 0;
|
||||
}
|
4777
deps/quickjs/libbf.c
vendored
4777
deps/quickjs/libbf.c
vendored
File diff suppressed because it is too large
Load Diff
343
deps/quickjs/libbf.h
vendored
343
deps/quickjs/libbf.h
vendored
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Tiny arbitrary precision floating point library
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
* Copyright (c) 2017-2020 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -27,7 +27,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#if INTPTR_MAX >= INT64_MAX
|
||||
#define LIMB_LOG2_BITS 6
|
||||
#else
|
||||
#define LIMB_LOG2_BITS 5
|
||||
@ -41,24 +41,37 @@ typedef unsigned __int128 uint128_t;
|
||||
typedef int64_t slimb_t;
|
||||
typedef uint64_t limb_t;
|
||||
typedef uint128_t dlimb_t;
|
||||
#define EXP_MIN INT64_MIN
|
||||
#define EXP_MAX INT64_MAX
|
||||
#define BF_RAW_EXP_MIN INT64_MIN
|
||||
#define BF_RAW_EXP_MAX INT64_MAX
|
||||
|
||||
#define LIMB_DIGITS 19
|
||||
#define BF_DEC_BASE UINT64_C(10000000000000000000)
|
||||
|
||||
#else
|
||||
|
||||
typedef int32_t slimb_t;
|
||||
typedef uint32_t limb_t;
|
||||
typedef uint64_t dlimb_t;
|
||||
#define EXP_MIN INT32_MIN
|
||||
#define EXP_MAX INT32_MAX
|
||||
#define BF_RAW_EXP_MIN INT32_MIN
|
||||
#define BF_RAW_EXP_MAX INT32_MAX
|
||||
|
||||
#define LIMB_DIGITS 9
|
||||
#define BF_DEC_BASE 1000000000U
|
||||
|
||||
#endif
|
||||
|
||||
/* in bits */
|
||||
/* minimum number of bits for the exponent */
|
||||
#define BF_EXP_BITS_MIN 3
|
||||
#define BF_EXP_BITS_MAX (LIMB_BITS - 2)
|
||||
/* maximum number of bits for the exponent */
|
||||
#define BF_EXP_BITS_MAX (LIMB_BITS - 3)
|
||||
/* extended range for exponent, used internally */
|
||||
#define BF_EXT_EXP_BITS_MAX (BF_EXP_BITS_MAX + 1)
|
||||
/* minimum possible precision */
|
||||
#define BF_PREC_MIN 2
|
||||
#define BF_PREC_MAX (((limb_t)1 << BF_EXP_BITS_MAX) - 2)
|
||||
/* minimum possible precision */
|
||||
#define BF_PREC_MAX (((limb_t)1 << (LIMB_BITS - 2)) - 2)
|
||||
/* some operations support infinite precision */
|
||||
#define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */
|
||||
|
||||
#if LIMB_BITS == 64
|
||||
@ -67,9 +80,9 @@ typedef uint64_t dlimb_t;
|
||||
#define BF_CHKSUM_MOD 975620677U
|
||||
#endif
|
||||
|
||||
#define BF_EXP_ZERO EXP_MIN
|
||||
#define BF_EXP_INF (EXP_MAX - 1)
|
||||
#define BF_EXP_NAN EXP_MAX
|
||||
#define BF_EXP_ZERO BF_RAW_EXP_MIN
|
||||
#define BF_EXP_INF (BF_RAW_EXP_MAX - 1)
|
||||
#define BF_EXP_NAN BF_RAW_EXP_MAX
|
||||
|
||||
/* +/-zero is represented with expn = BF_EXP_ZERO and len = 0,
|
||||
+/-infinity is represented with expn = BF_EXP_INF and len = 0,
|
||||
@ -83,25 +96,41 @@ typedef struct {
|
||||
limb_t *tab;
|
||||
} bf_t;
|
||||
|
||||
typedef struct {
|
||||
/* must be kept identical to bf_t */
|
||||
struct bf_context_t *ctx;
|
||||
int sign;
|
||||
slimb_t expn;
|
||||
limb_t len;
|
||||
limb_t *tab;
|
||||
} bfdec_t;
|
||||
|
||||
typedef enum {
|
||||
BF_RNDN, /* round to nearest, ties to even */
|
||||
BF_RNDZ, /* round to zero */
|
||||
BF_RNDD, /* round to -inf */
|
||||
BF_RNDD, /* round to -inf (the code relies on (BF_RNDD xor BF_RNDU) = 1) */
|
||||
BF_RNDU, /* round to +inf */
|
||||
BF_RNDNA, /* round to nearest, ties away from zero */
|
||||
BF_RNDNU, /* round to nearest, ties to +inf */
|
||||
BF_RNDA, /* round away from zero */
|
||||
BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU,
|
||||
inexact flag is always set) */
|
||||
} bf_rnd_t;
|
||||
|
||||
/* allow subnormal numbers (only available if the number of exponent
|
||||
bits is < BF_EXP_BITS_MAX and prec != BF_PREC_INF) */
|
||||
/* allow subnormal numbers. Only available if the number of exponent
|
||||
bits is <= BF_EXP_BITS_USER_MAX and prec != BF_PREC_INF. */
|
||||
#define BF_FLAG_SUBNORMAL (1 << 3)
|
||||
/* 'prec' is the precision after the radix point instead of the whole
|
||||
mantissa. Can only be used with bf_round() and
|
||||
bfdec_[add|sub|mul|div|sqrt|round](). */
|
||||
#define BF_FLAG_RADPNT_PREC (1 << 4)
|
||||
|
||||
#define BF_RND_MASK 0x7
|
||||
#define BF_EXP_BITS_SHIFT 4
|
||||
#define BF_EXP_BITS_SHIFT 5
|
||||
#define BF_EXP_BITS_MASK 0x3f
|
||||
|
||||
/* shortcut for bf_set_exp_bits(BF_EXT_EXP_BITS_MAX) */
|
||||
#define BF_FLAG_EXT_EXP (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)
|
||||
|
||||
/* contains the rounding mode and number of exponents bits */
|
||||
typedef uint32_t bf_flags_t;
|
||||
|
||||
@ -122,12 +151,17 @@ typedef struct bf_context_t {
|
||||
|
||||
static inline int bf_get_exp_bits(bf_flags_t flags)
|
||||
{
|
||||
return BF_EXP_BITS_MAX - ((flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK);
|
||||
int e;
|
||||
e = (flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK;
|
||||
if (e == BF_EXP_BITS_MASK)
|
||||
return BF_EXP_BITS_MAX + 1;
|
||||
else
|
||||
return BF_EXP_BITS_MAX - e;
|
||||
}
|
||||
|
||||
static inline bf_flags_t bf_set_exp_bits(int n)
|
||||
{
|
||||
return (BF_EXP_BITS_MAX - n) << BF_EXP_BITS_SHIFT;
|
||||
return ((BF_EXP_BITS_MAX - n) & BF_EXP_BITS_MASK) << BF_EXP_BITS_SHIFT;
|
||||
}
|
||||
|
||||
/* returned status */
|
||||
@ -136,8 +170,7 @@ static inline bf_flags_t bf_set_exp_bits(int n)
|
||||
#define BF_ST_OVERFLOW (1 << 2)
|
||||
#define BF_ST_UNDERFLOW (1 << 3)
|
||||
#define BF_ST_INEXACT (1 << 4)
|
||||
/* not used yet, indicate that a memory allocation error occured. NaN
|
||||
is returned */
|
||||
/* indicate that a memory allocation error occured. NaN is returned */
|
||||
#define BF_ST_MEM_ERROR (1 << 5)
|
||||
|
||||
#define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */
|
||||
@ -169,13 +202,26 @@ static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size)
|
||||
return s->realloc_func(s->realloc_opaque, ptr, size);
|
||||
}
|
||||
|
||||
/* 'size' must be != 0 */
|
||||
static inline void *bf_malloc(bf_context_t *s, size_t size)
|
||||
{
|
||||
return bf_realloc(s, NULL, size);
|
||||
}
|
||||
|
||||
static inline void bf_free(bf_context_t *s, void *ptr)
|
||||
{
|
||||
/* must test ptr otherwise equivalent to malloc(0) */
|
||||
if (ptr)
|
||||
bf_realloc(s, ptr, 0);
|
||||
}
|
||||
|
||||
void bf_init(bf_context_t *s, bf_t *r);
|
||||
|
||||
static inline void bf_delete(bf_t *r)
|
||||
{
|
||||
bf_context_t *s = r->ctx;
|
||||
/* we accept to delete a zeroed bf_t structure */
|
||||
if (s) {
|
||||
if (s && r->tab) {
|
||||
bf_realloc(s, r->tab, 0);
|
||||
}
|
||||
}
|
||||
@ -200,21 +246,39 @@ static inline int bf_is_zero(const bf_t *a)
|
||||
return (a->expn == BF_EXP_ZERO);
|
||||
}
|
||||
|
||||
void bf_set_ui(bf_t *r, uint64_t a);
|
||||
void bf_set_si(bf_t *r, int64_t a);
|
||||
static inline void bf_memcpy(bf_t *r, const bf_t *a)
|
||||
{
|
||||
*r = *a;
|
||||
}
|
||||
|
||||
int bf_set_ui(bf_t *r, uint64_t a);
|
||||
int bf_set_si(bf_t *r, int64_t a);
|
||||
void bf_set_nan(bf_t *r);
|
||||
void bf_set_zero(bf_t *r, int is_neg);
|
||||
void bf_set_inf(bf_t *r, int is_neg);
|
||||
void bf_set(bf_t *r, const bf_t *a);
|
||||
int bf_set(bf_t *r, const bf_t *a);
|
||||
void bf_move(bf_t *r, bf_t *a);
|
||||
int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode);
|
||||
void bf_set_float64(bf_t *a, double d);
|
||||
int bf_set_float64(bf_t *a, double d);
|
||||
|
||||
int bf_cmpu(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp_full(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp_eq(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp_le(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp_lt(const bf_t *a, const bf_t *b);
|
||||
int bf_cmp(const bf_t *a, const bf_t *b);
|
||||
static inline int bf_cmp_eq(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
static inline int bf_cmp_le(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) <= 0;
|
||||
}
|
||||
|
||||
static inline int bf_cmp_lt(const bf_t *a, const bf_t *b)
|
||||
{
|
||||
return bf_cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags);
|
||||
int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags);
|
||||
@ -227,54 +291,29 @@ int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags)
|
||||
#define BF_DIVREM_EUCLIDIAN BF_RNDF
|
||||
int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b,
|
||||
limb_t prec, bf_flags_t flags, int rnd_mode);
|
||||
int bf_fmod(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bf_remainder(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bf_rem(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bf_pow_ui(bf_t *r, const bf_t *a, limb_t b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bf_pow_ui_ui(bf_t *r, limb_t a1, limb_t b, limb_t prec, bf_flags_t flags);
|
||||
int bf_rint(bf_t *r, limb_t prec, bf_flags_t flags);
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
/* round to integer with infinite precision */
|
||||
int bf_rint(bf_t *r, int rnd_mode);
|
||||
int bf_round(bf_t *r, limb_t prec, bf_flags_t flags);
|
||||
int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a);
|
||||
int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
slimb_t bf_get_exp_min(const bf_t *a);
|
||||
void bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
void bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
void bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
int bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
int bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
int bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b);
|
||||
|
||||
/* additional flags for bf_atof */
|
||||
/* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */
|
||||
#define BF_ATOF_NO_HEX (1 << 16)
|
||||
/* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */
|
||||
#define BF_ATOF_BIN_OCT (1 << 17)
|
||||
/* Only accept integers (no decimal point, no exponent, no infinity nor NaN */
|
||||
#define BF_ATOF_INT_ONLY (1 << 18)
|
||||
/* Do not accept radix prefix after sign */
|
||||
#define BF_ATOF_NO_PREFIX_AFTER_SIGN (1 << 19)
|
||||
/* Do not parse NaN and parse case sensitive 'Infinity' */
|
||||
#define BF_ATOF_JS_QUIRKS (1 << 20)
|
||||
/* Do not round integers to the indicated precision */
|
||||
#define BF_ATOF_INT_PREC_INF (1 << 21)
|
||||
/* Support legacy octal syntax for well formed numbers */
|
||||
#define BF_ATOF_LEGACY_OCTAL (1 << 22)
|
||||
/* accept _ between digits as a digit separator */
|
||||
#define BF_ATOF_UNDERSCORE_SEP (1 << 23)
|
||||
/* if a 'n' suffix is present, force integer parsing (XXX: remove) */
|
||||
#define BF_ATOF_INT_N_SUFFIX (1 << 24)
|
||||
/* if set return NaN if empty number string (instead of 0) */
|
||||
#define BF_ATOF_NAN_IF_EMPTY (1 << 25)
|
||||
/* only accept decimal floating point if radix = 0 */
|
||||
#define BF_ATOF_ONLY_DEC_FLOAT (1 << 26)
|
||||
|
||||
/* additional return flags */
|
||||
/* indicate that the parsed number is an integer (only set when the
|
||||
flags BF_ATOF_INT_PREC_INF or BF_ATOF_INT_N_SUFFIX are used) */
|
||||
#define BF_ATOF_ST_INTEGER (1 << 5)
|
||||
/* integer parsed as legacy octal */
|
||||
#define BF_ATOF_ST_LEGACY_OCTAL (1 << 6)
|
||||
/* Do not parse NaN or Inf */
|
||||
#define BF_ATOF_NO_NAN_INF (1 << 18)
|
||||
/* return the exponent separately */
|
||||
#define BF_ATOF_EXPONENT (1 << 19)
|
||||
|
||||
int bf_atof(bf_t *a, const char *str, const char **pnext, int radix,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
@ -286,25 +325,39 @@ int bf_atof2(bf_t *r, slimb_t *pexponent,
|
||||
int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
|
||||
slimb_t expn, limb_t prec, bf_flags_t flags);
|
||||
|
||||
|
||||
/* Conversion of floating point number to string. Return a null
|
||||
terminated string or NULL if memory error. *plen contains its
|
||||
length if plen != NULL. The exponent letter is "e" for base 10,
|
||||
"p" for bases 2, 8, 16 with a binary exponent and "@" for the other
|
||||
bases. */
|
||||
|
||||
#define BF_FTOA_FORMAT_MASK (3 << 16)
|
||||
|
||||
/* fixed format: prec significant digits rounded with (flags &
|
||||
BF_RND_MASK). Exponential notation is used if too many zeros are
|
||||
needed. */
|
||||
needed.*/
|
||||
#define BF_FTOA_FORMAT_FIXED (0 << 16)
|
||||
/* fractional format: prec digits after the decimal point rounded with
|
||||
(flags & BF_RND_MASK) */
|
||||
#define BF_FTOA_FORMAT_FRAC (1 << 16)
|
||||
/* free format: use as many digits as necessary so that bf_atof()
|
||||
return the same number when using precision 'prec', rounding to
|
||||
nearest and the subnormal+exponent configuration of 'flags'. The
|
||||
result is meaningful only if 'a' is already rounded to the wanted
|
||||
precision.
|
||||
/* free format:
|
||||
|
||||
Infinite precision (BF_PREC_INF) is supported when the radix is a
|
||||
power of two. */
|
||||
For binary radices with bf_ftoa() and for bfdec_ftoa(): use the minimum
|
||||
number of digits to represent 'a'. The precision and the rounding
|
||||
mode are ignored.
|
||||
|
||||
For the non binary radices with bf_ftoa(): use as many digits as
|
||||
necessary so that bf_atof() return the same number when using
|
||||
precision 'prec', rounding to nearest and the subnormal
|
||||
configuration of 'flags'. The result is meaningful only if 'a' is
|
||||
already rounded to 'prec' bits. If the subnormal flag is set, the
|
||||
exponent in 'flags' must also be set to the desired exponent range.
|
||||
*/
|
||||
#define BF_FTOA_FORMAT_FREE (2 << 16)
|
||||
/* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits
|
||||
(takes more computation time). */
|
||||
(takes more computation time). Identical to BF_FTOA_FORMAT_FREE for
|
||||
binary radices with bf_ftoa() and for bfdec_ftoa(). */
|
||||
#define BF_FTOA_FORMAT_FREE_MIN (3 << 16)
|
||||
|
||||
/* force exponential notation for fixed or free format */
|
||||
@ -312,33 +365,44 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
|
||||
/* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for
|
||||
base 2 if non zero value */
|
||||
#define BF_FTOA_ADD_PREFIX (1 << 21)
|
||||
/* return "Infinity" instead of "Inf" and add a "+" for positive
|
||||
exponents */
|
||||
#define BF_FTOA_JS_QUIRKS (1 << 22)
|
||||
|
||||
size_t bf_ftoa(char **pbuf, const bf_t *a, int radix, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
char *bf_ftoa(size_t *plen, const bf_t *a, int radix, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
|
||||
/* modulo 2^n instead of saturation. NaN and infinity return 0 */
|
||||
#define BF_GET_INT_MOD (1 << 0)
|
||||
int bf_get_int32(int *pres, const bf_t *a, int flags);
|
||||
int bf_get_int64(int64_t *pres, const bf_t *a, int flags);
|
||||
int bf_get_uint64(uint64_t *pres, const bf_t *a);
|
||||
|
||||
/* the following functions are exported for testing only. */
|
||||
void mp_print_str(const char *str, const limb_t *tab, limb_t n);
|
||||
void bf_print_str(const char *str, const bf_t *a);
|
||||
void bf_resize(bf_t *r, limb_t len);
|
||||
int bf_resize(bf_t *r, limb_t len);
|
||||
int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len);
|
||||
void bf_recip(bf_t *r, const bf_t *a, limb_t prec);
|
||||
void bf_rsqrt(bf_t *a, const bf_t *x, limb_t prec);
|
||||
int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags);
|
||||
int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k);
|
||||
slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv,
|
||||
int is_ceil1);
|
||||
int mp_mul(bf_context_t *s, limb_t *result,
|
||||
const limb_t *op1, limb_t op1_size,
|
||||
const limb_t *op2, limb_t op2_size);
|
||||
limb_t mp_add(limb_t *res, const limb_t *op1, const limb_t *op2,
|
||||
limb_t n, limb_t carry);
|
||||
limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n);
|
||||
int mp_sqrtrem(bf_context_t *s, limb_t *tabs, limb_t *taba, limb_t n);
|
||||
int mp_recip(bf_context_t *s, limb_t *tabr, const limb_t *taba, limb_t n);
|
||||
limb_t bf_isqrt(limb_t a);
|
||||
|
||||
/* transcendental functions */
|
||||
int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags);
|
||||
int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags);
|
||||
int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
#define BF_POW_JS_QUICKS (1 << 16)
|
||||
#define BF_POW_JS_QUIRKS (1 << 16) /* (+/-1)^(+/-Inf) = NaN, 1^NaN = NaN */
|
||||
int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags);
|
||||
int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
@ -349,4 +413,123 @@ int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x,
|
||||
int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags);
|
||||
|
||||
/* decimal floating point */
|
||||
|
||||
static inline void bfdec_init(bf_context_t *s, bfdec_t *r)
|
||||
{
|
||||
bf_init(s, (bf_t *)r);
|
||||
}
|
||||
static inline void bfdec_delete(bfdec_t *r)
|
||||
{
|
||||
bf_delete((bf_t *)r);
|
||||
}
|
||||
|
||||
static inline void bfdec_neg(bfdec_t *r)
|
||||
{
|
||||
r->sign ^= 1;
|
||||
}
|
||||
|
||||
static inline int bfdec_is_finite(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn < BF_EXP_INF);
|
||||
}
|
||||
|
||||
static inline int bfdec_is_nan(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_NAN);
|
||||
}
|
||||
|
||||
static inline int bfdec_is_zero(const bfdec_t *a)
|
||||
{
|
||||
return (a->expn == BF_EXP_ZERO);
|
||||
}
|
||||
|
||||
static inline void bfdec_memcpy(bfdec_t *r, const bfdec_t *a)
|
||||
{
|
||||
bf_memcpy((bf_t *)r, (const bf_t *)a);
|
||||
}
|
||||
|
||||
int bfdec_set_ui(bfdec_t *r, uint64_t a);
|
||||
int bfdec_set_si(bfdec_t *r, int64_t a);
|
||||
|
||||
static inline void bfdec_set_nan(bfdec_t *r)
|
||||
{
|
||||
bf_set_nan((bf_t *)r);
|
||||
}
|
||||
static inline void bfdec_set_zero(bfdec_t *r, int is_neg)
|
||||
{
|
||||
bf_set_zero((bf_t *)r, is_neg);
|
||||
}
|
||||
static inline void bfdec_set_inf(bfdec_t *r, int is_neg)
|
||||
{
|
||||
bf_set_inf((bf_t *)r, is_neg);
|
||||
}
|
||||
static inline int bfdec_set(bfdec_t *r, const bfdec_t *a)
|
||||
{
|
||||
return bf_set((bf_t *)r, (bf_t *)a);
|
||||
}
|
||||
static inline void bfdec_move(bfdec_t *r, bfdec_t *a)
|
||||
{
|
||||
bf_move((bf_t *)r, (bf_t *)a);
|
||||
}
|
||||
static inline int bfdec_cmpu(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmpu((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp_full(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmp_full((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bf_cmp((const bf_t *)a, (const bf_t *)b);
|
||||
}
|
||||
static inline int bfdec_cmp_eq(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) == 0;
|
||||
}
|
||||
static inline int bfdec_cmp_le(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) <= 0;
|
||||
}
|
||||
static inline int bfdec_cmp_lt(const bfdec_t *a, const bfdec_t *b)
|
||||
{
|
||||
return bfdec_cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
int bfdec_add(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_sub(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_add_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_mul(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_mul_si(bfdec_t *r, const bfdec_t *a, int64_t b1, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_div(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags);
|
||||
int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
|
||||
limb_t prec, bf_flags_t flags, int rnd_mode);
|
||||
int bfdec_rem(bfdec_t *r, const bfdec_t *a, const bfdec_t *b, limb_t prec,
|
||||
bf_flags_t flags, int rnd_mode);
|
||||
int bfdec_rint(bfdec_t *r, int rnd_mode);
|
||||
int bfdec_sqrt(bfdec_t *r, const bfdec_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_round(bfdec_t *r, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_get_int32(int *pres, const bfdec_t *a);
|
||||
int bfdec_pow_ui(bfdec_t *r, const bfdec_t *a, limb_t b);
|
||||
|
||||
char *bfdec_ftoa(size_t *plen, const bfdec_t *a, limb_t prec, bf_flags_t flags);
|
||||
int bfdec_atof(bfdec_t *r, const char *str, const char **pnext,
|
||||
limb_t prec, bf_flags_t flags);
|
||||
|
||||
/* the following functions are exported for testing only. */
|
||||
extern const limb_t mp_pow_dec[LIMB_DIGITS + 1];
|
||||
void bfdec_print_str(const char *str, const bfdec_t *a);
|
||||
static inline int bfdec_resize(bfdec_t *r, limb_t len)
|
||||
{
|
||||
return bf_resize((bf_t *)r, len);
|
||||
}
|
||||
int bfdec_normalize_and_round(bfdec_t *r, limb_t prec1, bf_flags_t flags);
|
||||
|
||||
#endif /* LIBBF_H */
|
||||
|
187
deps/quickjs/libregexp.c
vendored
187
deps/quickjs/libregexp.c
vendored
@ -75,7 +75,7 @@ typedef struct {
|
||||
int capture_count;
|
||||
int total_capture_count; /* -1 = not computed yet */
|
||||
int has_named_captures; /* -1 = don't know, 0 = no, 1 = yes */
|
||||
void *mem_opaque;
|
||||
void *opaque;
|
||||
DynBuf group_names;
|
||||
union {
|
||||
char error_msg[TMP_BUF_SIZE];
|
||||
@ -110,12 +110,14 @@ static inline int is_digit(int c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
/* insert 'len' bytes at position 'pos' */
|
||||
static void dbuf_insert(DynBuf *s, int pos, int len)
|
||||
/* insert 'len' bytes at position 'pos'. Return < 0 if error. */
|
||||
static int dbuf_insert(DynBuf *s, int pos, int len)
|
||||
{
|
||||
dbuf_realloc(s, s->size + len);
|
||||
if (dbuf_realloc(s, s->size + len))
|
||||
return -1;
|
||||
memmove(s->buf + pos + len, s->buf + pos, s->size - pos);
|
||||
s->size += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* canonicalize with the specific JS regexp rules */
|
||||
@ -228,7 +230,7 @@ static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c)
|
||||
invert = c & 1;
|
||||
c_pt = char_range_table[c >> 1];
|
||||
len = *c_pt++;
|
||||
cr_init(cr, s->mem_opaque, lre_realloc);
|
||||
cr_init(cr, s->opaque, lre_realloc);
|
||||
for(i = 0; i < len * 2; i++) {
|
||||
if (cr_add_point(cr, c_pt[i]))
|
||||
goto fail;
|
||||
@ -434,8 +436,14 @@ static int __attribute__((format(printf, 2, 3))) re_parse_error(REParseState *s,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return -1 in case of overflow */
|
||||
static int parse_digits(const uint8_t **pp)
|
||||
static int re_parse_out_of_memory(REParseState *s)
|
||||
{
|
||||
return re_parse_error(s, "out of memory");
|
||||
}
|
||||
|
||||
/* If allow_overflow is false, return -1 in case of
|
||||
overflow. Otherwise return INT32_MAX. */
|
||||
static int parse_digits(const uint8_t **pp, BOOL allow_overflow)
|
||||
{
|
||||
const uint8_t *p;
|
||||
uint64_t v;
|
||||
@ -448,8 +456,12 @@ static int parse_digits(const uint8_t **pp)
|
||||
if (c < '0' || c > '9')
|
||||
break;
|
||||
v = v * 10 + c - '0';
|
||||
if (v >= INT32_MAX)
|
||||
return -1;
|
||||
if (v >= INT32_MAX) {
|
||||
if (allow_overflow)
|
||||
v = INT32_MAX;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
*pp = p;
|
||||
@ -557,7 +569,8 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '0' ... '7':
|
||||
case '0': case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
c -= '0';
|
||||
if (allow_utf16 == 2) {
|
||||
/* only accept \0 not followed by digit */
|
||||
@ -612,7 +625,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
||||
p++;
|
||||
q = name;
|
||||
while (is_unicode_char(*p)) {
|
||||
if ((q - name) > sizeof(name) - 1)
|
||||
if ((q - name) >= sizeof(name) - 1)
|
||||
goto unknown_property_name;
|
||||
*q++ = *p++;
|
||||
}
|
||||
@ -621,7 +634,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
||||
if (*p == '=') {
|
||||
p++;
|
||||
while (is_unicode_char(*p)) {
|
||||
if ((q - value) > sizeof(value) - 1)
|
||||
if ((q - value) >= sizeof(value) - 1)
|
||||
return re_parse_error(s, "unknown unicode property value");
|
||||
*q++ = *p++;
|
||||
}
|
||||
@ -638,7 +651,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
||||
} else if (!strcmp(name, "Script_Extensions") || !strcmp(name, "scx")) {
|
||||
script_ext = TRUE;
|
||||
do_script:
|
||||
cr_init(cr, s->mem_opaque, lre_realloc);
|
||||
cr_init(cr, s->opaque, lre_realloc);
|
||||
ret = unicode_script(cr, value, script_ext);
|
||||
if (ret) {
|
||||
cr_free(cr);
|
||||
@ -648,7 +661,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
||||
goto out_of_memory;
|
||||
}
|
||||
} else if (!strcmp(name, "General_Category") || !strcmp(name, "gc")) {
|
||||
cr_init(cr, s->mem_opaque, lre_realloc);
|
||||
cr_init(cr, s->opaque, lre_realloc);
|
||||
ret = unicode_general_category(cr, value);
|
||||
if (ret) {
|
||||
cr_free(cr);
|
||||
@ -658,7 +671,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
||||
goto out_of_memory;
|
||||
}
|
||||
} else if (value[0] == '\0') {
|
||||
cr_init(cr, s->mem_opaque, lre_realloc);
|
||||
cr_init(cr, s->opaque, lre_realloc);
|
||||
ret = unicode_general_category(cr, name);
|
||||
if (ret == -1) {
|
||||
cr_free(cr);
|
||||
@ -688,7 +701,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
|
||||
*pp = p;
|
||||
return 0;
|
||||
out_of_memory:
|
||||
return re_parse_error(s, "out of memory");
|
||||
return re_parse_out_of_memory(s);
|
||||
}
|
||||
#endif /* CONFIG_ALL_UNICODE */
|
||||
|
||||
@ -851,7 +864,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
|
||||
CharRange cr1_s, *cr1 = &cr1_s;
|
||||
BOOL invert;
|
||||
|
||||
cr_init(cr, s->mem_opaque, lre_realloc);
|
||||
cr_init(cr, s->opaque, lre_realloc);
|
||||
p = *pp;
|
||||
p++; /* skip '[' */
|
||||
invert = FALSE;
|
||||
@ -923,7 +936,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
|
||||
*pp = p;
|
||||
return 0;
|
||||
memory_error:
|
||||
re_parse_error(s, "out of memory");
|
||||
re_parse_out_of_memory(s);
|
||||
fail:
|
||||
cr_free(cr);
|
||||
return -1;
|
||||
@ -1134,9 +1147,13 @@ static int re_parse_captures(REParseState *s, int *phas_named_captures,
|
||||
}
|
||||
}
|
||||
capture_index++;
|
||||
if (capture_index >= CAPTURE_COUNT_MAX)
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
capture_index++;
|
||||
if (capture_index >= CAPTURE_COUNT_MAX)
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
@ -1150,6 +1167,7 @@ static int re_parse_captures(REParseState *s, int *phas_named_captures,
|
||||
break;
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (capture_name)
|
||||
return -1;
|
||||
else
|
||||
@ -1225,14 +1243,27 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
re_emit_op(s, REOP_prev);
|
||||
break;
|
||||
case '{':
|
||||
/* As an extension (see ES6 annex B), we accept '{' not
|
||||
followed by digits as a normal atom */
|
||||
if (!is_digit(p[1])) {
|
||||
if (s->is_utf16)
|
||||
goto invalid_quant_count;
|
||||
if (s->is_utf16) {
|
||||
return re_parse_error(s, "syntax error");
|
||||
} else if (!is_digit(p[1])) {
|
||||
/* Annex B: we accept '{' not followed by digits as a
|
||||
normal atom */
|
||||
goto parse_class_atom;
|
||||
} else {
|
||||
const uint8_t *p1 = p + 1;
|
||||
/* Annex B: error if it is like a repetition count */
|
||||
parse_digits(&p1, TRUE);
|
||||
if (*p1 == ',') {
|
||||
p1++;
|
||||
if (is_digit(*p1)) {
|
||||
parse_digits(&p1, TRUE);
|
||||
}
|
||||
}
|
||||
if (*p1 != '}') {
|
||||
goto parse_class_atom;
|
||||
}
|
||||
}
|
||||
/* fall tru */
|
||||
/* fall thru */
|
||||
case '*':
|
||||
case '+':
|
||||
case '?':
|
||||
@ -1277,6 +1308,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
return -1;
|
||||
re_emit_op(s, REOP_match);
|
||||
/* jump after the 'match' after the lookahead is successful */
|
||||
if (dbuf_error(&s->byte_code))
|
||||
return -1;
|
||||
put_u32(s->byte_code.buf + pos, s->byte_code.size - (pos + 4));
|
||||
} else if (p[2] == '<') {
|
||||
p += 3;
|
||||
@ -1383,11 +1416,13 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
}
|
||||
}
|
||||
goto normal_char;
|
||||
case '1' ... '9':
|
||||
case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8':
|
||||
case '9':
|
||||
{
|
||||
const uint8_t *q = ++p;
|
||||
|
||||
c = parse_digits(&p);
|
||||
c = parse_digits(&p, FALSE);
|
||||
if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) {
|
||||
if (!s->is_utf16) {
|
||||
/* Annex B.1.4: accept legacy octal */
|
||||
@ -1407,7 +1442,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
}
|
||||
goto normal_char;
|
||||
}
|
||||
return re_parse_error(s, "back reference out of range in reguar expression");
|
||||
return re_parse_error(s, "back reference out of range in regular expression");
|
||||
}
|
||||
emit_back_reference:
|
||||
last_atom_start = s->byte_code.size;
|
||||
@ -1484,32 +1519,38 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
quant_max = 1;
|
||||
goto quantifier;
|
||||
case '{':
|
||||
/* As an extension (see ES6 annex B), we accept '{' not
|
||||
followed by digits as a normal atom */
|
||||
if (!is_digit(p[1])) {
|
||||
if (s->is_utf16)
|
||||
goto invalid_quant_count;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
quant_min = parse_digits(&p);
|
||||
if (quant_min < 0) {
|
||||
invalid_quant_count:
|
||||
return re_parse_error(s, "invalid repetition count");
|
||||
}
|
||||
quant_max = quant_min;
|
||||
if (*p == ',') {
|
||||
p++;
|
||||
if (is_digit(*p)) {
|
||||
quant_max = parse_digits(&p);
|
||||
if (quant_max < 0 || quant_max < quant_min)
|
||||
{
|
||||
const uint8_t *p1 = p;
|
||||
/* As an extension (see ES6 annex B), we accept '{' not
|
||||
followed by digits as a normal atom */
|
||||
if (!is_digit(p[1])) {
|
||||
if (s->is_utf16)
|
||||
goto invalid_quant_count;
|
||||
} else {
|
||||
quant_max = INT32_MAX; /* infinity */
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
quant_min = parse_digits(&p, TRUE);
|
||||
quant_max = quant_min;
|
||||
if (*p == ',') {
|
||||
p++;
|
||||
if (is_digit(*p)) {
|
||||
quant_max = parse_digits(&p, TRUE);
|
||||
if (quant_max < quant_min) {
|
||||
invalid_quant_count:
|
||||
return re_parse_error(s, "invalid repetition count");
|
||||
}
|
||||
} else {
|
||||
quant_max = INT32_MAX; /* infinity */
|
||||
}
|
||||
}
|
||||
if (*p != '}' && !s->is_utf16) {
|
||||
/* Annex B: normal atom if invalid '{' syntax */
|
||||
p = p1;
|
||||
break;
|
||||
}
|
||||
if (re_parse_expect(s, &p, '}'))
|
||||
return -1;
|
||||
}
|
||||
if (re_parse_expect(s, &p, '}'))
|
||||
return -1;
|
||||
quantifier:
|
||||
greedy = TRUE;
|
||||
if (*p == '?') {
|
||||
@ -1524,12 +1565,15 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
|
||||
if (quant_max > 0) {
|
||||
/* specific optimization for simple quantifiers */
|
||||
if (dbuf_error(&s->byte_code))
|
||||
goto out_of_memory;
|
||||
len = re_is_simple_quantifier(s->byte_code.buf + last_atom_start,
|
||||
s->byte_code.size - last_atom_start);
|
||||
if (len > 0) {
|
||||
re_emit_op(s, REOP_match);
|
||||
|
||||
dbuf_insert(&s->byte_code, last_atom_start, 17);
|
||||
if (dbuf_insert(&s->byte_code, last_atom_start, 17))
|
||||
goto out_of_memory;
|
||||
pos = last_atom_start;
|
||||
s->byte_code.buf[pos++] = REOP_simple_greedy_quant;
|
||||
put_u32(&s->byte_code.buf[pos],
|
||||
@ -1545,6 +1589,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
}
|
||||
}
|
||||
|
||||
if (dbuf_error(&s->byte_code))
|
||||
goto out_of_memory;
|
||||
add_zero_advance_check = (re_check_advance(s->byte_code.buf + last_atom_start,
|
||||
s->byte_code.size - last_atom_start) == 0);
|
||||
} else {
|
||||
@ -1558,7 +1604,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
/* need to reset the capture in case the atom is
|
||||
not executed */
|
||||
if (last_capture_count != s->capture_count) {
|
||||
dbuf_insert(&s->byte_code, last_atom_start, 3);
|
||||
if (dbuf_insert(&s->byte_code, last_atom_start, 3))
|
||||
goto out_of_memory;
|
||||
s->byte_code.buf[last_atom_start++] = REOP_save_reset;
|
||||
s->byte_code.buf[last_atom_start++] = last_capture_count;
|
||||
s->byte_code.buf[last_atom_start++] = s->capture_count - 1;
|
||||
@ -1566,12 +1613,14 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
if (quant_max == 0) {
|
||||
s->byte_code.size = last_atom_start;
|
||||
} else if (quant_max == 1) {
|
||||
dbuf_insert(&s->byte_code, last_atom_start, 5);
|
||||
if (dbuf_insert(&s->byte_code, last_atom_start, 5))
|
||||
goto out_of_memory;
|
||||
s->byte_code.buf[last_atom_start] = REOP_split_goto_first +
|
||||
greedy;
|
||||
put_u32(s->byte_code.buf + last_atom_start + 1, len);
|
||||
} else if (quant_max == INT32_MAX) {
|
||||
dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check);
|
||||
if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check))
|
||||
goto out_of_memory;
|
||||
s->byte_code.buf[last_atom_start] = REOP_split_goto_first +
|
||||
greedy;
|
||||
put_u32(s->byte_code.buf + last_atom_start + 1,
|
||||
@ -1587,7 +1636,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
re_emit_goto(s, REOP_goto, last_atom_start);
|
||||
}
|
||||
} else {
|
||||
dbuf_insert(&s->byte_code, last_atom_start, 10);
|
||||
if (dbuf_insert(&s->byte_code, last_atom_start, 10))
|
||||
goto out_of_memory;
|
||||
pos = last_atom_start;
|
||||
s->byte_code.buf[pos++] = REOP_push_i32;
|
||||
put_u32(s->byte_code.buf + pos, quant_max);
|
||||
@ -1605,7 +1655,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
if (quant_min == 1) {
|
||||
/* nothing to add */
|
||||
} else {
|
||||
dbuf_insert(&s->byte_code, last_atom_start, 5);
|
||||
if (dbuf_insert(&s->byte_code, last_atom_start, 5))
|
||||
goto out_of_memory;
|
||||
s->byte_code.buf[last_atom_start] = REOP_push_i32;
|
||||
put_u32(s->byte_code.buf + last_atom_start + 1,
|
||||
quant_min);
|
||||
@ -1646,6 +1697,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
|
||||
done:
|
||||
s->buf_ptr = p;
|
||||
return 0;
|
||||
out_of_memory:
|
||||
return re_parse_out_of_memory(s);
|
||||
}
|
||||
|
||||
static int re_parse_alternative(REParseState *s, BOOL is_backward_dir)
|
||||
@ -1686,6 +1739,9 @@ static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir)
|
||||
{
|
||||
int start, len, pos;
|
||||
|
||||
if (lre_check_stack_overflow(s->opaque, 0))
|
||||
return re_parse_error(s, "stack overflow");
|
||||
|
||||
start = s->byte_code.size;
|
||||
if (re_parse_alternative(s, is_backward_dir))
|
||||
return -1;
|
||||
@ -1695,7 +1751,9 @@ static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir)
|
||||
len = s->byte_code.size - start;
|
||||
|
||||
/* insert a split before the first alternative */
|
||||
dbuf_insert(&s->byte_code, start, 5);
|
||||
if (dbuf_insert(&s->byte_code, start, 5)) {
|
||||
return re_parse_out_of_memory(s);
|
||||
}
|
||||
s->byte_code.buf[start] = REOP_split_next_first;
|
||||
put_u32(s->byte_code.buf + start + 1, len + 5);
|
||||
|
||||
@ -1769,7 +1827,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
||||
BOOL is_sticky;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->mem_opaque = opaque;
|
||||
s->opaque = opaque;
|
||||
s->buf_ptr = (const uint8_t *)buf;
|
||||
s->buf_end = s->buf_ptr + buf_len;
|
||||
s->buf_start = s->buf_ptr;
|
||||
@ -1820,7 +1878,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
||||
}
|
||||
|
||||
if (dbuf_error(&s->byte_code)) {
|
||||
re_parse_error(s, "out of memory");
|
||||
re_parse_out_of_memory(s);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -2486,6 +2544,17 @@ int lre_get_flags(const uint8_t *bc_buf)
|
||||
return bc_buf[RE_HEADER_FLAGS];
|
||||
}
|
||||
|
||||
/* Return NULL if no group names. Otherwise, return a pointer to
|
||||
'capture_count - 1' zero terminated UTF-8 strings. */
|
||||
const char *lre_get_groupnames(const uint8_t *bc_buf)
|
||||
{
|
||||
uint32_t re_bytecode_len;
|
||||
if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0)
|
||||
return NULL;
|
||||
re_bytecode_len = get_u32(bc_buf + 3);
|
||||
return (const char *)(bc_buf + 7 + re_bytecode_len);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)
|
||||
|
1
deps/quickjs/libregexp.h
vendored
1
deps/quickjs/libregexp.h
vendored
@ -44,6 +44,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
||||
void *opaque);
|
||||
int lre_get_capture_count(const uint8_t *bc_buf);
|
||||
int lre_get_flags(const uint8_t *bc_buf);
|
||||
const char *lre_get_groupnames(const uint8_t *bc_buf);
|
||||
int lre_exec(uint8_t **capture,
|
||||
const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,
|
||||
int cbuf_type, void *opaque);
|
||||
|
3183
deps/quickjs/libunicode-table.h
vendored
3183
deps/quickjs/libunicode-table.h
vendored
File diff suppressed because it is too large
Load Diff
26
deps/quickjs/libunicode.c
vendored
26
deps/quickjs/libunicode.c
vendored
@ -527,7 +527,13 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
|
||||
} else {
|
||||
d = unicode_decomp_data + unicode_decomp_table2[idx];
|
||||
switch(type) {
|
||||
case DECOMP_TYPE_L1 ... DECOMP_TYPE_L7:
|
||||
case DECOMP_TYPE_L1:
|
||||
case DECOMP_TYPE_L2:
|
||||
case DECOMP_TYPE_L3:
|
||||
case DECOMP_TYPE_L4:
|
||||
case DECOMP_TYPE_L5:
|
||||
case DECOMP_TYPE_L6:
|
||||
case DECOMP_TYPE_L7:
|
||||
l = type - DECOMP_TYPE_L1 + 1;
|
||||
d += (c - code) * l * 2;
|
||||
for(i = 0; i < l; i++) {
|
||||
@ -535,7 +541,8 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
|
||||
return 0;
|
||||
}
|
||||
return l;
|
||||
case DECOMP_TYPE_LL1 ... DECOMP_TYPE_LL2:
|
||||
case DECOMP_TYPE_LL1:
|
||||
case DECOMP_TYPE_LL2:
|
||||
{
|
||||
uint32_t k, p;
|
||||
l = type - DECOMP_TYPE_LL1 + 1;
|
||||
@ -551,7 +558,11 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
|
||||
}
|
||||
}
|
||||
return l;
|
||||
case DECOMP_TYPE_S1 ... DECOMP_TYPE_S5:
|
||||
case DECOMP_TYPE_S1:
|
||||
case DECOMP_TYPE_S2:
|
||||
case DECOMP_TYPE_S3:
|
||||
case DECOMP_TYPE_S4:
|
||||
case DECOMP_TYPE_S5:
|
||||
l = type - DECOMP_TYPE_S1 + 1;
|
||||
d += (c - code) * l;
|
||||
for(i = 0; i < l; i++) {
|
||||
@ -582,7 +593,14 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
|
||||
case DECOMP_TYPE_B18:
|
||||
l = 18;
|
||||
goto decomp_type_b;
|
||||
case DECOMP_TYPE_B1 ... DECOMP_TYPE_B8:
|
||||
case DECOMP_TYPE_B1:
|
||||
case DECOMP_TYPE_B2:
|
||||
case DECOMP_TYPE_B3:
|
||||
case DECOMP_TYPE_B4:
|
||||
case DECOMP_TYPE_B5:
|
||||
case DECOMP_TYPE_B6:
|
||||
case DECOMP_TYPE_B7:
|
||||
case DECOMP_TYPE_B8:
|
||||
l = type - DECOMP_TYPE_B1 + 1;
|
||||
decomp_type_b:
|
||||
{
|
||||
|
107
deps/quickjs/qjs.c
vendored
107
deps/quickjs/qjs.c
vendored
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* QuickJS stand alone interpreter
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
* Copyright (c) 2017-2018 Charlie Gordon
|
||||
* Copyright (c) 2017-2020 Fabrice Bellard
|
||||
* Copyright (c) 2017-2020 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -46,6 +46,7 @@ extern const uint32_t qjsc_repl_size;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
extern const uint8_t qjsc_qjscalc[];
|
||||
extern const uint32_t qjsc_qjscalc_size;
|
||||
static int bignum_ext;
|
||||
#endif
|
||||
|
||||
static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
|
||||
@ -101,6 +102,27 @@ static int eval_file(JSContext *ctx, const char *filename, int module)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* also used to initialize the worker context */
|
||||
static JSContext *JS_NewCustomContext(JSRuntime *rt)
|
||||
{
|
||||
JSContext *ctx;
|
||||
ctx = JS_NewContext(rt);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (bignum_ext) {
|
||||
JS_AddIntrinsicBigFloat(ctx);
|
||||
JS_AddIntrinsicBigDecimal(ctx);
|
||||
JS_AddIntrinsicOperators(ctx);
|
||||
JS_EnableBignumExt(ctx, TRUE);
|
||||
}
|
||||
#endif
|
||||
/* system modules */
|
||||
js_init_module_std(ctx, "std");
|
||||
js_init_module_os(ctx, "os");
|
||||
return ctx;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define MALLOC_OVERHEAD 0
|
||||
#else
|
||||
@ -250,27 +272,28 @@ static const JSMallocFunctions trace_mf = {
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BIGNUM
|
||||
#define PROG_NAME "qjsbn"
|
||||
#else
|
||||
#define PROG_NAME "qjs"
|
||||
#endif
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("QuickJS version " CONFIG_VERSION "\n"
|
||||
"usage: " PROG_NAME " [options] [file]\n"
|
||||
"usage: " PROG_NAME " [options] [file [args]]\n"
|
||||
"-h --help list options\n"
|
||||
"-e --eval EXPR evaluate EXPR\n"
|
||||
"-i --interactive go to interactive mode\n"
|
||||
"-m --module load as ES6 module (default=autodetect)\n"
|
||||
" --script load as ES6 script (default=autodetect)\n"
|
||||
"-I --include file include an additional file\n"
|
||||
" --std make 'std' and 'os' available to the loaded script\n"
|
||||
#ifdef CONFIG_BIGNUM
|
||||
" --bignum enable the bignum extensions (BigFloat, BigDecimal)\n"
|
||||
" --qjscalc load the QJSCalc runtime (default if invoked as qjscalc)\n"
|
||||
#endif
|
||||
"-T --trace trace memory allocation\n"
|
||||
"-d --dump dump the memory usage stats\n"
|
||||
" --memory-limit n limit the memory usage to 'n' bytes\n"
|
||||
" --stack-size n limit the stack size to 'n' bytes\n"
|
||||
" --unhandled-rejection dump unhandled promise rejections\n"
|
||||
"-q --quit just instantiate the interpreter and quit\n");
|
||||
exit(1);
|
||||
}
|
||||
@ -288,10 +311,15 @@ int main(int argc, char **argv)
|
||||
int empty_run = 0;
|
||||
int module = -1;
|
||||
int load_std = 0;
|
||||
int dump_unhandled_promise_rejection = 0;
|
||||
size_t memory_limit = 0;
|
||||
char *include_list[32];
|
||||
int i, include_count = 0;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
int load_jscalc;
|
||||
#endif
|
||||
|
||||
size_t stack_size = 0;
|
||||
|
||||
#ifdef CONFIG_BIGNUM
|
||||
/* load jscalc runtime if invoked as 'qjscalc' */
|
||||
{
|
||||
@ -341,6 +369,18 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr, "qjs: missing expression for -e\n");
|
||||
exit(2);
|
||||
}
|
||||
if (opt == 'I' || !strcmp(longopt, "include")) {
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "expecting filename");
|
||||
exit(1);
|
||||
}
|
||||
if (include_count >= countof(include_list)) {
|
||||
fprintf(stderr, "too many included files");
|
||||
exit(1);
|
||||
}
|
||||
include_list[include_count++] = argv[optind++];
|
||||
continue;
|
||||
}
|
||||
if (opt == 'i' || !strcmp(longopt, "interactive")) {
|
||||
interactive++;
|
||||
continue;
|
||||
@ -365,7 +405,15 @@ int main(int argc, char **argv)
|
||||
load_std = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "unhandled-rejection")) {
|
||||
dump_unhandled_promise_rejection = 1;
|
||||
continue;
|
||||
}
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (!strcmp(longopt, "bignum")) {
|
||||
bignum_ext = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "qjscalc")) {
|
||||
load_jscalc = 1;
|
||||
continue;
|
||||
@ -375,6 +423,22 @@ int main(int argc, char **argv)
|
||||
empty_run++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "memory-limit")) {
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "expecting memory limit");
|
||||
exit(1);
|
||||
}
|
||||
memory_limit = (size_t)strtod(argv[optind++], NULL);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(longopt, "stack-size")) {
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "expecting stack size");
|
||||
exit(1);
|
||||
}
|
||||
stack_size = (size_t)strtod(argv[optind++], NULL);
|
||||
continue;
|
||||
}
|
||||
if (opt) {
|
||||
fprintf(stderr, "qjs: unknown option '-%c'\n", opt);
|
||||
} else {
|
||||
@ -384,6 +448,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (load_jscalc)
|
||||
bignum_ext = 1;
|
||||
|
||||
if (trace_memory) {
|
||||
js_trace_malloc_init(&trace_data);
|
||||
rt = JS_NewRuntime2(&trace_mf, &trace_data);
|
||||
@ -394,7 +461,13 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr, "qjs: cannot allocate JS runtime\n");
|
||||
exit(2);
|
||||
}
|
||||
ctx = JS_NewContext(rt);
|
||||
if (memory_limit != 0)
|
||||
JS_SetMemoryLimit(rt, memory_limit);
|
||||
if (stack_size != 0)
|
||||
JS_SetMaxStackSize(rt, stack_size);
|
||||
js_std_set_worker_new_context_func(JS_NewCustomContext);
|
||||
js_std_init_handlers(rt);
|
||||
ctx = JS_NewCustomContext(rt);
|
||||
if (!ctx) {
|
||||
fprintf(stderr, "qjs: cannot allocate JS context\n");
|
||||
exit(2);
|
||||
@ -402,7 +475,12 @@ int main(int argc, char **argv)
|
||||
|
||||
/* loader for ES6 modules */
|
||||
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
|
||||
|
||||
|
||||
if (dump_unhandled_promise_rejection) {
|
||||
JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!empty_run) {
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (load_jscalc) {
|
||||
@ -411,10 +489,6 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
js_std_add_helpers(ctx, argc - optind, argv + optind);
|
||||
|
||||
/* system modules */
|
||||
js_init_module_std(ctx, "std");
|
||||
js_init_module_os(ctx, "os");
|
||||
|
||||
/* make 'std' and 'os' visible to non module code */
|
||||
if (load_std) {
|
||||
const char *str = "import * as std from 'std';\n"
|
||||
@ -424,6 +498,11 @@ int main(int argc, char **argv)
|
||||
eval_buf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE);
|
||||
}
|
||||
|
||||
for(i = 0; i < include_count; i++) {
|
||||
if (eval_file(ctx, include_list[i], module))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (expr) {
|
||||
if (eval_buf(ctx, expr, strlen(expr), "<cmdline>", 0))
|
||||
goto fail;
|
||||
|
128
deps/quickjs/qjsc.c
vendored
128
deps/quickjs/qjsc.c
vendored
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* QuickJS command line compiler
|
||||
*
|
||||
* Copyright (c) 2018-2019 Fabrice Bellard
|
||||
* Copyright (c) 2018-2020 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -76,6 +76,9 @@ static const FeatureEntry feature_list[] = {
|
||||
{ "promise", "Promise" },
|
||||
#define FE_MODULE_LOADER 9
|
||||
{ "module-loader", NULL },
|
||||
#ifdef CONFIG_BIGNUM
|
||||
{ "bigint", "BigInt" },
|
||||
#endif
|
||||
};
|
||||
|
||||
void namelist_add(namelist_t *lp, const char *name, const char *short_name,
|
||||
@ -323,6 +326,8 @@ static const char main_c_template1[] =
|
||||
" JSRuntime *rt;\n"
|
||||
" JSContext *ctx;\n"
|
||||
" rt = JS_NewRuntime();\n"
|
||||
" js_std_set_worker_new_context_func(JS_NewCustomContext);\n"
|
||||
" js_std_init_handlers(rt);\n"
|
||||
;
|
||||
|
||||
static const char main_c_template2[] =
|
||||
@ -332,11 +337,7 @@ static const char main_c_template2[] =
|
||||
" return 0;\n"
|
||||
"}\n";
|
||||
|
||||
#ifdef CONFIG_BIGNUM
|
||||
#define PROG_NAME "qjscbn"
|
||||
#else
|
||||
#define PROG_NAME "qjsc"
|
||||
#endif
|
||||
|
||||
void help(void)
|
||||
{
|
||||
@ -349,14 +350,17 @@ void help(void)
|
||||
"-o output set the output filename\n"
|
||||
"-N cname set the C name of the generated data\n"
|
||||
"-m compile as Javascript module (default=autodetect)\n"
|
||||
"-D module_name compile a dynamically loaded module or worker\n"
|
||||
"-M module_name[,cname] add initialization code for an external C module\n"
|
||||
"-x byte swapped output\n"
|
||||
"-p prefix set the prefix of the generated C names\n"
|
||||
);
|
||||
"-S n set the maximum stack size to 'n' bytes (default=%d)\n",
|
||||
JS_DEFAULT_STACK_SIZE);
|
||||
#ifdef CONFIG_LTO
|
||||
{
|
||||
int i;
|
||||
printf("-flto use link time optimization\n");
|
||||
printf("-fbignum enable bignum extensions\n");
|
||||
printf("-fno-[");
|
||||
for(i = 0; i < countof(feature_list); i++) {
|
||||
if (i != 0)
|
||||
@ -420,11 +424,7 @@ static int output_executable(const char *out_filename, const char *cfilename,
|
||||
}
|
||||
|
||||
lto_suffix = "";
|
||||
#ifdef CONFIG_BIGNUM
|
||||
bn_suffix = ".bn";
|
||||
#else
|
||||
bn_suffix = "";
|
||||
#endif
|
||||
|
||||
arg = argv;
|
||||
*arg++ = CONFIG_CC;
|
||||
@ -451,6 +451,7 @@ static int output_executable(const char *out_filename, const char *cfilename,
|
||||
*arg++ = libjsname;
|
||||
*arg++ = "-lm";
|
||||
*arg++ = "-ldl";
|
||||
*arg++ = "-lpthread";
|
||||
*arg = NULL;
|
||||
|
||||
if (verbose) {
|
||||
@ -491,6 +492,11 @@ int main(int argc, char **argv)
|
||||
BOOL use_lto;
|
||||
int module;
|
||||
OutputTypeEnum output_type;
|
||||
size_t stack_size;
|
||||
#ifdef CONFIG_BIGNUM
|
||||
BOOL bignum_ext = FALSE;
|
||||
#endif
|
||||
namelist_t dynamic_module_list;
|
||||
|
||||
out_filename = NULL;
|
||||
output_type = OUTPUT_EXECUTABLE;
|
||||
@ -500,13 +506,15 @@ int main(int argc, char **argv)
|
||||
byte_swap = FALSE;
|
||||
verbose = 0;
|
||||
use_lto = FALSE;
|
||||
|
||||
stack_size = 0;
|
||||
memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));
|
||||
|
||||
/* add system modules */
|
||||
namelist_add(&cmodule_list, "std", "std", 0);
|
||||
namelist_add(&cmodule_list, "os", "os", 0);
|
||||
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "ho:cN:f:mxevM:p:");
|
||||
c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
@ -540,7 +548,13 @@ int main(int argc, char **argv)
|
||||
}
|
||||
if (i == countof(feature_list))
|
||||
goto bad_feature;
|
||||
} else {
|
||||
} else
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (!strcmp(optarg, "bignum")) {
|
||||
bignum_ext = TRUE;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
bad_feature:
|
||||
fprintf(stderr, "unsupported feature: %s\n", optarg);
|
||||
exit(1);
|
||||
@ -566,6 +580,9 @@ int main(int argc, char **argv)
|
||||
namelist_add(&cmodule_list, path, cname, 0);
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
namelist_add(&dynamic_module_list, optarg, NULL, 0);
|
||||
break;
|
||||
case 'x':
|
||||
byte_swap = TRUE;
|
||||
break;
|
||||
@ -575,6 +592,9 @@ int main(int argc, char **argv)
|
||||
case 'p':
|
||||
c_ident_prefix = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
stack_size = (size_t)strtod(optarg, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -610,9 +630,15 @@ int main(int argc, char **argv)
|
||||
outfile = fo;
|
||||
|
||||
rt = JS_NewRuntime();
|
||||
ctx = JS_NewContextRaw(rt);
|
||||
JS_AddIntrinsicEval(ctx);
|
||||
JS_AddIntrinsicRegExpCompiler(ctx);
|
||||
ctx = JS_NewContext(rt);
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (bignum_ext) {
|
||||
JS_AddIntrinsicBigFloat(ctx);
|
||||
JS_AddIntrinsicBigDecimal(ctx);
|
||||
JS_AddIntrinsicOperators(ctx);
|
||||
JS_EnableBignumExt(ctx, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* loader for ES6 modules */
|
||||
JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL);
|
||||
@ -637,17 +663,22 @@ int main(int argc, char **argv)
|
||||
cname = NULL;
|
||||
}
|
||||
|
||||
if (output_type != OUTPUT_C) {
|
||||
fputs(main_c_template1, fo);
|
||||
fprintf(fo, " ctx = JS_NewContextRaw(rt);\n");
|
||||
|
||||
/* add the module loader if necessary */
|
||||
if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
|
||||
fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
|
||||
for(i = 0; i < dynamic_module_list.count; i++) {
|
||||
if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) {
|
||||
fprintf(stderr, "Could not load dynamic module '%s'\n",
|
||||
dynamic_module_list.array[i].name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (output_type != OUTPUT_C) {
|
||||
fprintf(fo,
|
||||
"static JSContext *JS_NewCustomContext(JSRuntime *rt)\n"
|
||||
"{\n"
|
||||
" JSContext *ctx = JS_NewContextRaw(rt);\n"
|
||||
" if (!ctx)\n"
|
||||
" return NULL;\n");
|
||||
/* add the basic objects */
|
||||
|
||||
fprintf(fo, " JS_AddIntrinsicBaseObjects(ctx);\n");
|
||||
for(i = 0; i < countof(feature_list); i++) {
|
||||
if ((feature_bitmap & ((uint64_t)1 << i)) &&
|
||||
@ -656,9 +687,17 @@ int main(int argc, char **argv)
|
||||
feature_list[i].init_name);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fo, " js_std_add_helpers(ctx, argc, argv);\n");
|
||||
|
||||
#ifdef CONFIG_BIGNUM
|
||||
if (bignum_ext) {
|
||||
fprintf(fo,
|
||||
" JS_AddIntrinsicBigFloat(ctx);\n"
|
||||
" JS_AddIntrinsicBigDecimal(ctx);\n"
|
||||
" JS_AddIntrinsicOperators(ctx);\n"
|
||||
" JS_EnableBignumExt(ctx, 1);\n");
|
||||
}
|
||||
#endif
|
||||
/* add the precompiled modules (XXX: could modify the module
|
||||
loader instead) */
|
||||
for(i = 0; i < init_module_list.count; i++) {
|
||||
namelist_entry_t *e = &init_module_list.array[i];
|
||||
/* initialize the static C modules */
|
||||
@ -670,12 +709,39 @@ int main(int argc, char **argv)
|
||||
" }\n",
|
||||
e->short_name, e->short_name, e->name);
|
||||
}
|
||||
for(i = 0; i < cname_list.count; i++) {
|
||||
namelist_entry_t *e = &cname_list.array[i];
|
||||
if (e->flags) {
|
||||
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n",
|
||||
e->name, e->name);
|
||||
}
|
||||
}
|
||||
fprintf(fo,
|
||||
" return ctx;\n"
|
||||
"}\n\n");
|
||||
|
||||
fputs(main_c_template1, fo);
|
||||
|
||||
if (stack_size != 0) {
|
||||
fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n",
|
||||
(unsigned int)stack_size);
|
||||
}
|
||||
|
||||
/* add the module loader if necessary */
|
||||
if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
|
||||
fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
|
||||
}
|
||||
|
||||
fprintf(fo,
|
||||
" ctx = JS_NewCustomContext(rt);\n"
|
||||
" js_std_add_helpers(ctx, argc, argv);\n");
|
||||
|
||||
for(i = 0; i < cname_list.count; i++) {
|
||||
namelist_entry_t *e = &cname_list.array[i];
|
||||
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, %s);\n",
|
||||
e->name, e->name,
|
||||
e->flags ? "1" : "0");
|
||||
if (!e->flags) {
|
||||
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n",
|
||||
e->name, e->name);
|
||||
}
|
||||
}
|
||||
fputs(main_c_template2, fo);
|
||||
}
|
||||
|
1454
deps/quickjs/qjscalc.js
vendored
1454
deps/quickjs/qjscalc.js
vendored
File diff suppressed because it is too large
Load Diff
33
deps/quickjs/quickjs-atom.h
vendored
33
deps/quickjs/quickjs-atom.h
vendored
@ -82,6 +82,7 @@ DEF(length, "length")
|
||||
DEF(fileName, "fileName")
|
||||
DEF(lineNumber, "lineNumber")
|
||||
DEF(message, "message")
|
||||
DEF(errors, "errors")
|
||||
DEF(stack, "stack")
|
||||
DEF(name, "name")
|
||||
DEF(toString, "toString")
|
||||
@ -112,6 +113,7 @@ DEF(caller, "caller")
|
||||
DEF(_eval_, "<eval>")
|
||||
DEF(_ret_, "<ret>")
|
||||
DEF(_var_, "<var>")
|
||||
DEF(_arg_var_, "<arg_var>")
|
||||
DEF(_with_, "<with>")
|
||||
DEF(lastIndex, "lastIndex")
|
||||
DEF(target, "target")
|
||||
@ -170,6 +172,10 @@ DEF(globalThis, "globalThis")
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF(bigint, "bigint")
|
||||
DEF(bigfloat, "bigfloat")
|
||||
DEF(bigdecimal, "bigdecimal")
|
||||
DEF(roundingMode, "roundingMode")
|
||||
DEF(maximumSignificantDigits, "maximumSignificantDigits")
|
||||
DEF(maximumFractionDigits, "maximumFractionDigits")
|
||||
#endif
|
||||
#ifdef CONFIG_ATOMICS
|
||||
DEF(not_equal, "not-equal")
|
||||
@ -214,6 +220,9 @@ DEF(DataView, "DataView")
|
||||
DEF(BigInt, "BigInt")
|
||||
DEF(BigFloat, "BigFloat")
|
||||
DEF(BigFloatEnv, "BigFloatEnv")
|
||||
DEF(BigDecimal, "BigDecimal")
|
||||
DEF(OperatorSet, "OperatorSet")
|
||||
DEF(Operators, "Operators")
|
||||
#endif
|
||||
DEF(Map, "Map")
|
||||
DEF(Set, "Set") /* Map + 1 */
|
||||
@ -258,27 +267,7 @@ DEF(Symbol_species, "Symbol.species")
|
||||
DEF(Symbol_unscopables, "Symbol.unscopables")
|
||||
DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF(Symbol_operatorOrder, "Symbol.operatorOrder")
|
||||
DEF(Symbol_operatorAdd, "Symbol.operatorAdd")
|
||||
DEF(Symbol_operatorSub, "Symbol.operatorSub")
|
||||
DEF(Symbol_operatorMul, "Symbol.operatorMul")
|
||||
DEF(Symbol_operatorDiv, "Symbol.operatorDiv")
|
||||
DEF(Symbol_operatorMod, "Symbol.operatorMod")
|
||||
DEF(Symbol_operatorPow, "Symbol.operatorPow")
|
||||
DEF(Symbol_operatorShl, "Symbol.operatorShl")
|
||||
DEF(Symbol_operatorShr, "Symbol.operatorShr")
|
||||
DEF(Symbol_operatorAnd, "Symbol.operatorAnd")
|
||||
DEF(Symbol_operatorOr, "Symbol.operatorOr")
|
||||
DEF(Symbol_operatorXor, "Symbol.operatorXor")
|
||||
DEF(Symbol_operatorCmpLT, "Symbol.operatorCmpLT")
|
||||
DEF(Symbol_operatorCmpLE, "Symbol.operatorCmpLE")
|
||||
DEF(Symbol_operatorCmpEQ, "Symbol.operatorCmpEQ")
|
||||
DEF(Symbol_operatorPlus, "Symbol.operatorPlus")
|
||||
DEF(Symbol_operatorNeg, "Symbol.operatorNeg")
|
||||
DEF(Symbol_operatorNot, "Symbol.operatorNot")
|
||||
DEF(Symbol_operatorInc, "Symbol.operatorInc")
|
||||
DEF(Symbol_operatorDec, "Symbol.operatorDec")
|
||||
DEF(Symbol_operatorMathMod, "Symbol.operatorMathMod")
|
||||
DEF(Symbol_operatorSet, "Symbol.operatorSet")
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* DEF */
|
||||
|
2024
deps/quickjs/quickjs-libc.c
vendored
2024
deps/quickjs/quickjs-libc.c
vendored
File diff suppressed because it is too large
Load Diff
13
deps/quickjs/quickjs-libc.h
vendored
13
deps/quickjs/quickjs-libc.h
vendored
@ -29,10 +29,15 @@
|
||||
|
||||
#include "quickjs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
|
||||
JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
|
||||
void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
|
||||
void js_std_loop(JSContext *ctx);
|
||||
void js_std_init_handlers(JSRuntime *rt);
|
||||
void js_std_free_handlers(JSRuntime *rt);
|
||||
void js_std_dump_error(JSContext *ctx);
|
||||
uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
|
||||
@ -42,5 +47,13 @@ JSModuleDef *js_module_loader(JSContext *ctx,
|
||||
const char *module_name, void *opaque);
|
||||
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
||||
int flags);
|
||||
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
|
||||
JSValueConst reason,
|
||||
JS_BOOL is_handled, void *opaque);
|
||||
void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" { */
|
||||
#endif
|
||||
|
||||
#endif /* QUICKJS_LIBC_H */
|
||||
|
21
deps/quickjs/quickjs-opcode.h
vendored
21
deps/quickjs/quickjs-opcode.h
vendored
@ -114,12 +114,11 @@ DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
|
||||
DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
|
||||
DEF( return_async, 1, 1, 0, none)
|
||||
DEF( throw, 1, 1, 0, none)
|
||||
DEF( throw_var, 6, 0, 0, atom_u8)
|
||||
DEF( throw_error, 6, 0, 0, atom_u8)
|
||||
DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
|
||||
DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
|
||||
DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
|
||||
bytecode string */
|
||||
DEF( get_super_ctor, 1, 1, 1, none)
|
||||
DEF( get_super, 1, 1, 1, none)
|
||||
DEF( import, 1, 1, 1, none) /* dynamic module import */
|
||||
|
||||
@ -206,16 +205,15 @@ DEF( for_of_start, 1, 1, 3, none)
|
||||
DEF(for_await_of_start, 1, 1, 3, none)
|
||||
DEF( for_in_next, 1, 1, 3, none)
|
||||
DEF( for_of_next, 2, 3, 5, u8)
|
||||
DEF(for_await_of_next, 1, 3, 4, none)
|
||||
DEF(iterator_check_object, 1, 1, 1, none)
|
||||
DEF(iterator_get_value_done, 1, 1, 2, none)
|
||||
DEF( iterator_close, 1, 3, 0, none)
|
||||
DEF(iterator_close_return, 1, 4, 4, none)
|
||||
DEF(async_iterator_close, 1, 3, 2, none)
|
||||
DEF(async_iterator_next, 1, 4, 4, none)
|
||||
DEF(async_iterator_get, 2, 4, 5, u8)
|
||||
DEF( iterator_next, 1, 4, 4, none)
|
||||
DEF( iterator_call, 2, 4, 5, u8)
|
||||
DEF( initial_yield, 1, 0, 0, none)
|
||||
DEF( yield, 1, 1, 2, none)
|
||||
DEF( yield_star, 1, 2, 2, none)
|
||||
DEF( yield_star, 1, 1, 2, none)
|
||||
DEF(async_yield_star, 1, 1, 2, none)
|
||||
DEF( await, 1, 1, 1, none)
|
||||
|
||||
@ -257,20 +255,16 @@ DEF( strict_neq, 1, 2, 1, none)
|
||||
DEF( and, 1, 2, 1, none)
|
||||
DEF( xor, 1, 2, 1, none)
|
||||
DEF( or, 1, 2, 1, none)
|
||||
DEF(is_undefined_or_null, 1, 1, 1, none)
|
||||
#ifdef CONFIG_BIGNUM
|
||||
DEF( mul_pow10, 1, 2, 1, none)
|
||||
DEF( math_div, 1, 2, 1, none)
|
||||
DEF( math_mod, 1, 2, 1, none)
|
||||
DEF( math_pow, 1, 2, 1, none)
|
||||
#endif
|
||||
/* must be the last non short and non temporary opcode */
|
||||
DEF( nop, 1, 0, 0, none)
|
||||
|
||||
/* temporary opcodes: never emitted in the final bytecode */
|
||||
|
||||
def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */
|
||||
|
||||
def(close_var_object, 1, 0, 0, none) /* emitted in phase 1, removed in phase 2 */
|
||||
def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
|
||||
def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
|
||||
|
||||
@ -362,7 +356,8 @@ DEF( call3, 1, 1, 1, npopx)
|
||||
|
||||
DEF( is_undefined, 1, 1, 1, none)
|
||||
DEF( is_null, 1, 1, 1, none)
|
||||
DEF( is_function, 1, 1, 1, none)
|
||||
DEF(typeof_is_undefined, 1, 1, 1, none)
|
||||
DEF( typeof_is_function, 1, 1, 1, none)
|
||||
#endif
|
||||
|
||||
#undef DEF
|
||||
|
15419
deps/quickjs/quickjs.c
vendored
15419
deps/quickjs/quickjs.c
vendored
File diff suppressed because it is too large
Load Diff
211
deps/quickjs/quickjs.h
vendored
211
deps/quickjs/quickjs.h
vendored
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* QuickJS Javascript Engine
|
||||
*
|
||||
* Copyright (c) 2017-2019 Fabrice Bellard
|
||||
* Copyright (c) 2017-2019 Charlie Gordon
|
||||
* Copyright (c) 2017-2020 Fabrice Bellard
|
||||
* Copyright (c) 2017-2020 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -53,7 +53,7 @@ typedef struct JSClass JSClass;
|
||||
typedef uint32_t JSClassID;
|
||||
typedef uint32_t JSAtom;
|
||||
|
||||
#if defined(__x86_64__) || defined(__aarch64__)
|
||||
#if INTPTR_MAX >= INT64_MAX
|
||||
#define JS_PTR64
|
||||
#define JS_PTR64_DEF(a) a
|
||||
#else
|
||||
@ -66,14 +66,12 @@ typedef uint32_t JSAtom;
|
||||
|
||||
enum {
|
||||
/* all tags with a reference count are negative */
|
||||
JS_TAG_FIRST = -10, /* first negative tag */
|
||||
JS_TAG_FIRST = -11, /* first negative tag */
|
||||
JS_TAG_BIG_DECIMAL = -11,
|
||||
JS_TAG_BIG_INT = -10,
|
||||
JS_TAG_BIG_FLOAT = -9,
|
||||
JS_TAG_SYMBOL = -8,
|
||||
JS_TAG_STRING = -7,
|
||||
JS_TAG_SHAPE = -6, /* used internally during GC */
|
||||
JS_TAG_ASYNC_FUNCTION = -5, /* used internally during GC */
|
||||
JS_TAG_VAR_REF = -4, /* used internally during GC */
|
||||
JS_TAG_MODULE = -3, /* used internally */
|
||||
JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */
|
||||
JS_TAG_OBJECT = -1,
|
||||
@ -124,6 +122,11 @@ static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
|
||||
return JS_MKVAL(JS_TAG_FLOAT64, (int)d);
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(JS_NAN_BOXING)
|
||||
|
||||
typedef uint64_t JSValue;
|
||||
@ -182,6 +185,13 @@ static inline int JS_VALUE_GET_NORM_TAG(JSValue v)
|
||||
return tag;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
{
|
||||
uint32_t tag;
|
||||
tag = JS_VALUE_GET_TAG(v);
|
||||
return tag == (JS_NAN >> 32);
|
||||
}
|
||||
|
||||
#else /* !JS_NAN_BOXING */
|
||||
|
||||
typedef union JSValueUnion {
|
||||
@ -220,6 +230,18 @@ static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u;
|
||||
if (v.tag != JS_TAG_FLOAT64)
|
||||
return 0;
|
||||
u.d = v.u.float64;
|
||||
return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000;
|
||||
}
|
||||
|
||||
#endif /* !JS_NAN_BOXING */
|
||||
|
||||
#define JS_VALUE_IS_BOTH_INT(v1, v2) ((JS_VALUE_GET_TAG(v1) | JS_VALUE_GET_TAG(v2)) == 0)
|
||||
@ -283,6 +305,8 @@ static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
|
||||
JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed
|
||||
with JS_EvalFunction(). */
|
||||
#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5)
|
||||
/* don't include the stack frames before this eval in the Error() backtraces */
|
||||
#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)
|
||||
|
||||
typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
|
||||
typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
|
||||
@ -302,25 +326,29 @@ typedef struct JSMallocFunctions {
|
||||
size_t (*js_malloc_usable_size)(const void *ptr);
|
||||
} JSMallocFunctions;
|
||||
|
||||
typedef struct JSGCObjectHeader JSGCObjectHeader;
|
||||
|
||||
JSRuntime *JS_NewRuntime(void);
|
||||
/* info lifetime must exceed that of rt */
|
||||
void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
|
||||
void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
|
||||
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
|
||||
void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size);
|
||||
JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque);
|
||||
void JS_FreeRuntime(JSRuntime *rt);
|
||||
typedef void JS_MarkFunc(JSRuntime *rt, JSValueConst val);
|
||||
void *JS_GetRuntimeOpaque(JSRuntime *rt);
|
||||
void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque);
|
||||
typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp);
|
||||
void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
|
||||
void JS_RunGC(JSRuntime *rt);
|
||||
JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj);
|
||||
JS_BOOL JS_IsInGCSweep(JSRuntime *rt);
|
||||
|
||||
JSContext *JS_NewContext(JSRuntime *rt);
|
||||
void JS_FreeContext(JSContext *s);
|
||||
JSContext *JS_DupContext(JSContext *ctx);
|
||||
void *JS_GetContextOpaque(JSContext *ctx);
|
||||
void JS_SetContextOpaque(JSContext *ctx, void *opaque);
|
||||
JSRuntime *JS_GetRuntime(JSContext *ctx);
|
||||
void JS_SetMaxStackSize(JSContext *ctx, size_t stack_size);
|
||||
void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj);
|
||||
JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id);
|
||||
|
||||
@ -338,6 +366,14 @@ void JS_AddIntrinsicProxy(JSContext *ctx);
|
||||
void JS_AddIntrinsicMapSet(JSContext *ctx);
|
||||
void JS_AddIntrinsicTypedArrays(JSContext *ctx);
|
||||
void JS_AddIntrinsicPromise(JSContext *ctx);
|
||||
void JS_AddIntrinsicBigInt(JSContext *ctx);
|
||||
void JS_AddIntrinsicBigFloat(JSContext *ctx);
|
||||
void JS_AddIntrinsicBigDecimal(JSContext *ctx);
|
||||
/* enable operator overloading */
|
||||
void JS_AddIntrinsicOperators(JSContext *ctx);
|
||||
/* enable "use math" */
|
||||
void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable);
|
||||
|
||||
JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv);
|
||||
|
||||
@ -376,6 +412,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s);
|
||||
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt);
|
||||
|
||||
/* atom support */
|
||||
#define JS_ATOM_NULL 0
|
||||
|
||||
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len);
|
||||
JSAtom JS_NewAtom(JSContext *ctx, const char *str);
|
||||
JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n);
|
||||
@ -434,13 +472,20 @@ typedef struct JSClassExoticMethods {
|
||||
typedef void JSClassFinalizer(JSRuntime *rt, JSValue val);
|
||||
typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val,
|
||||
JS_MarkFunc *mark_func);
|
||||
#define JS_CALL_FLAG_CONSTRUCTOR (1 << 0)
|
||||
typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj,
|
||||
JSValueConst this_val, int argc, JSValueConst *argv);
|
||||
JSValueConst this_val, int argc, JSValueConst *argv,
|
||||
int flags);
|
||||
|
||||
typedef struct JSClassDef {
|
||||
const char *class_name;
|
||||
JSClassFinalizer *finalizer;
|
||||
JSClassGCMark *gc_mark;
|
||||
/* if call != NULL, the object is a function. If (flags &
|
||||
JS_CALL_FLAG_CONSTRUCTOR) != 0, the function is called as a
|
||||
constructor. In this case, 'this_val' is new.target. A
|
||||
constructor call only happens if the object constructor bit is
|
||||
set (see JS_SetConstructorBit()). */
|
||||
JSClassCall *call;
|
||||
/* XXX: suppress this indirection ? It is here only to save memory
|
||||
because only a few classes need these methods */
|
||||
@ -455,7 +500,7 @@ int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);
|
||||
|
||||
static js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val)
|
||||
{
|
||||
return JS_MKVAL(JS_TAG_BOOL, val);
|
||||
return JS_MKVAL(JS_TAG_BOOL, (val != 0));
|
||||
}
|
||||
|
||||
static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val)
|
||||
@ -468,7 +513,28 @@ static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val)
|
||||
return JS_MKVAL(JS_TAG_CATCH_OFFSET, val);
|
||||
}
|
||||
|
||||
JSValue JS_NewInt64(JSContext *ctx, int64_t v);
|
||||
static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val)
|
||||
{
|
||||
JSValue v;
|
||||
if (val == (int32_t)val) {
|
||||
v = JS_NewInt32(ctx, val);
|
||||
} else {
|
||||
v = __JS_NewFloat64(ctx, val);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
|
||||
{
|
||||
JSValue v;
|
||||
if (val <= 0x7fffffff) {
|
||||
v = JS_NewInt32(ctx, val);
|
||||
} else {
|
||||
v = __JS_NewFloat64(ctx, val);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v);
|
||||
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);
|
||||
|
||||
@ -493,12 +559,16 @@ static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d)
|
||||
return v;
|
||||
}
|
||||
|
||||
JS_BOOL JS_IsNumber(JSValueConst v);
|
||||
|
||||
static inline JS_BOOL JS_IsInteger(JSValueConst v)
|
||||
static inline JS_BOOL JS_IsNumber(JSValueConst v)
|
||||
{
|
||||
int tag = JS_VALUE_GET_TAG(v);
|
||||
return tag == JS_TAG_INT || tag == JS_TAG_BIG_INT;
|
||||
return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)
|
||||
{
|
||||
int tag = JS_VALUE_GET_TAG(v);
|
||||
return tag == JS_TAG_BIG_INT;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsBigFloat(JSValueConst v)
|
||||
@ -507,6 +577,12 @@ static inline JS_BOOL JS_IsBigFloat(JSValueConst v)
|
||||
return tag == JS_TAG_BIG_FLOAT;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsBigDecimal(JSValueConst v)
|
||||
{
|
||||
int tag = JS_VALUE_GET_TAG(v);
|
||||
return tag == JS_TAG_BIG_DECIMAL;
|
||||
}
|
||||
|
||||
static inline JS_BOOL JS_IsBool(JSValueConst v)
|
||||
{
|
||||
return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL;
|
||||
@ -550,7 +626,6 @@ static inline JS_BOOL JS_IsObject(JSValueConst v)
|
||||
JSValue JS_Throw(JSContext *ctx, JSValue obj);
|
||||
JSValue JS_GetException(JSContext *ctx);
|
||||
JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val);
|
||||
void JS_EnableIsErrorProperty(JSContext *ctx, JS_BOOL enable);
|
||||
void JS_ResetUncatchableError(JSContext *ctx);
|
||||
JSValue JS_NewError(JSContext *ctx);
|
||||
JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...);
|
||||
@ -601,14 +676,17 @@ static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
|
||||
|
||||
int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */
|
||||
int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val);
|
||||
static int inline JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
|
||||
static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
|
||||
{
|
||||
return JS_ToInt32(ctx, (int32_t*)pres, val);
|
||||
}
|
||||
int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
|
||||
int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val);
|
||||
int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val);
|
||||
/* return an exception if 'val' is a Number */
|
||||
int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
|
||||
/* same as JS_ToInt64() but allow BigInt */
|
||||
int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val);
|
||||
|
||||
JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1);
|
||||
JSValue JS_NewString(JSContext *ctx, const char *str);
|
||||
@ -633,6 +711,7 @@ JSValue JS_NewObject(JSContext *ctx);
|
||||
|
||||
JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val);
|
||||
JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val);
|
||||
JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val);
|
||||
|
||||
JSValue JS_NewArray(JSContext *ctx);
|
||||
int JS_IsArray(JSContext *ctx, JSValueConst val);
|
||||
@ -669,7 +748,7 @@ int JS_IsExtensible(JSContext *ctx, JSValueConst obj);
|
||||
int JS_PreventExtensions(JSContext *ctx, JSValueConst obj);
|
||||
int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags);
|
||||
int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val);
|
||||
JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val);
|
||||
JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val);
|
||||
|
||||
#define JS_GPN_STRING_MASK (1 << 0)
|
||||
#define JS_GPN_SYMBOL_MASK (1 << 1)
|
||||
@ -684,8 +763,6 @@ int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
|
||||
int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
|
||||
JSValueConst obj, JSAtom prop);
|
||||
|
||||
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
const char *filename);
|
||||
JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
|
||||
int argc, JSValueConst *argv);
|
||||
JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,
|
||||
@ -696,9 +773,13 @@ JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
|
||||
JSValueConst new_target,
|
||||
int argc, JSValueConst *argv);
|
||||
JS_BOOL JS_DetectModule(const char *input, size_t input_len);
|
||||
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
|
||||
JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
|
||||
const char *filename, int eval_flags);
|
||||
JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj);
|
||||
/* same as JS_Eval() but with an explicit 'this_obj' parameter */
|
||||
JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
|
||||
const char *input, size_t input_len,
|
||||
const char *filename, int eval_flags);
|
||||
JSValue JS_GetGlobalObject(JSContext *ctx);
|
||||
int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj);
|
||||
int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
|
||||
@ -717,6 +798,15 @@ void JS_SetOpaque(JSValue obj, void *opaque);
|
||||
void *JS_GetOpaque(JSValueConst obj, JSClassID class_id);
|
||||
void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id);
|
||||
|
||||
/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
|
||||
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
const char *filename);
|
||||
#define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */
|
||||
JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
const char *filename, int flags);
|
||||
JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
|
||||
JSValueConst replacer, JSValueConst space0);
|
||||
|
||||
typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr);
|
||||
JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
|
||||
JSFreeArrayBufferDataFunc *free_func, void *opaque,
|
||||
@ -724,14 +814,34 @@ 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);
|
||||
JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
|
||||
size_t *pbyte_offset,
|
||||
size_t *pbyte_length,
|
||||
size_t *pbytes_per_element);
|
||||
typedef struct {
|
||||
void *(*sab_alloc)(void *opaque, size_t size);
|
||||
void (*sab_free)(void *opaque, void *ptr);
|
||||
void (*sab_dup)(void *opaque, void *ptr);
|
||||
void *sab_opaque;
|
||||
} JSSharedArrayBufferFunctions;
|
||||
void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
|
||||
const JSSharedArrayBufferFunctions *sf);
|
||||
|
||||
JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
|
||||
|
||||
/* is_handled = TRUE means that the rejection is handled */
|
||||
typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise,
|
||||
JSValueConst reason,
|
||||
JS_BOOL is_handled, void *opaque);
|
||||
void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque);
|
||||
|
||||
/* return != 0 if the JS code needs to be interrupted */
|
||||
typedef int JSInterruptHandler(JSRuntime *rt, void *opaque);
|
||||
void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque);
|
||||
/* if can_block is TRUE, Atomics.wait() can be used */
|
||||
void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block);
|
||||
/* set the [IsHTMLDDA] internal slot */
|
||||
void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj);
|
||||
|
||||
typedef struct JSModuleDef JSModuleDef;
|
||||
|
||||
@ -761,18 +871,36 @@ JS_BOOL JS_IsJobPending(JSRuntime *rt);
|
||||
int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);
|
||||
|
||||
/* Object Writer/Reader (currently only used to handle precompiled code) */
|
||||
#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
|
||||
#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */
|
||||
#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
|
||||
#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */
|
||||
#define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
|
||||
#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to
|
||||
encode arbitrary object
|
||||
graph */
|
||||
uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
|
||||
int flags);
|
||||
uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
|
||||
int flags, uint8_t ***psab_tab, size_t *psab_tab_len);
|
||||
|
||||
#define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */
|
||||
#define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */
|
||||
#define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
|
||||
#define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */
|
||||
JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
||||
int flags);
|
||||
/* instantiate and evaluate a bytecode function. Only used when
|
||||
reading a script or module with JS_ReadObject() */
|
||||
JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj);
|
||||
/* load the dependencies of the module 'obj'. Useful when JS_ReadObject()
|
||||
returns a module. */
|
||||
int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
|
||||
|
||||
/* only exported for os.Worker() */
|
||||
JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
|
||||
/* only exported for os.Worker() */
|
||||
JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
|
||||
const char *filename);
|
||||
|
||||
/* C function definition */
|
||||
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
|
||||
JS_CFUNC_generic,
|
||||
@ -825,6 +953,8 @@ 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,
|
||||
JSValueConst proto);
|
||||
|
||||
/* C property definition */
|
||||
|
||||
@ -865,24 +995,25 @@ typedef struct JSCFunctionListEntry {
|
||||
#define JS_DEF_PROP_INT32 4
|
||||
#define JS_DEF_PROP_INT64 5
|
||||
#define JS_DEF_PROP_DOUBLE 6
|
||||
#define JS_DEF_PROP_UNDEFINED 7
|
||||
#define JS_DEF_PROP_UNDEFINED 7
|
||||
#define JS_DEF_OBJECT 8
|
||||
#define JS_DEF_ALIAS 9
|
||||
|
||||
#define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u.func = { length, JS_CFUNC_generic, { .generic = func1 } } }
|
||||
#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u.func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } }
|
||||
#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u.func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } }
|
||||
#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u.func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } }
|
||||
#define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u.getset.get.getter = fgetter, .u.getset.set.setter = fsetter }
|
||||
#define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u.getset.get.getter_magic = fgetter, .u.getset.set.setter_magic = fsetter }
|
||||
#define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u.str = cstr }
|
||||
#define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u.i32 = val }
|
||||
#define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u.i64 = val }
|
||||
#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u.f64 = val }
|
||||
#define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u.i32 = 0 }
|
||||
#define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u.prop_list = { tab, len } }
|
||||
#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u.alias = { from, -1 } }
|
||||
#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u.alias = { from, base } }
|
||||
/* Note: c++ does not like nested designators */
|
||||
#define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } }
|
||||
#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } }
|
||||
#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } }
|
||||
#define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } }
|
||||
#define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u = { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } }
|
||||
#define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u = { .str = cstr } }
|
||||
#define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } }
|
||||
#define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u = { .i64 = val } }
|
||||
#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = { .f64 = val } }
|
||||
#define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } }
|
||||
#define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u = { .prop_list = { tab, len } } }
|
||||
#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } }
|
||||
#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } }
|
||||
|
||||
void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
|
||||
const JSCFunctionListEntry *tab,
|
||||
|
136
deps/quickjs/release.sh
vendored
136
deps/quickjs/release.sh
vendored
@ -6,62 +6,32 @@ set -e
|
||||
version=`cat VERSION`
|
||||
|
||||
if [ "$1" = "-h" ] ; then
|
||||
echo "release.sh [all]"
|
||||
echo "release.sh [release_list]"
|
||||
echo ""
|
||||
echo "all: build all the archives. Otherwise only build the quickjs source archive."
|
||||
echo "release_list: extras binary win_binary quickjs"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
unicode="no"
|
||||
tests="no"
|
||||
binary="no"
|
||||
quickjs="no"
|
||||
release_list="extras binary win_binary quickjs"
|
||||
|
||||
if [ "$1" = "all" ] ; then
|
||||
unicode="yes"
|
||||
tests="yes"
|
||||
binary="yes"
|
||||
quickjs="yes"
|
||||
elif [ "$1" = "binary" ] ; then
|
||||
binary="yes"
|
||||
else
|
||||
quickjs="yes"
|
||||
if [ "$1" != "" ] ; then
|
||||
release_list="$1"
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# unicode data
|
||||
# extras
|
||||
|
||||
if [ "$unicode" = "yes" ] ; then
|
||||
if echo $release_list | grep -w -q extras ; then
|
||||
|
||||
d="quickjs-${version}"
|
||||
name="quickjs-unicode-data-${version}"
|
||||
name="quickjs-extras-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir $outdir/unicode
|
||||
mkdir -p $outdir $outdir/unicode $outdir/tests
|
||||
|
||||
cp unicode/* $outdir/unicode
|
||||
|
||||
( cd /tmp && tar Jcvf /tmp/${name}.tar.xz ${d} )
|
||||
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# all tests
|
||||
|
||||
if [ "$tests" = "yes" ] ; then
|
||||
|
||||
d="quickjs-${version}"
|
||||
name="quickjs-tests-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir $outdir/test262o $outdir/test262 $outdir/tests
|
||||
|
||||
cp -a test262o/test $outdir/test262o
|
||||
|
||||
cp -a test262/test test262/harness $outdir/test262
|
||||
|
||||
cp -a tests/bench-v8 $outdir/tests
|
||||
|
||||
( cd /tmp && tar Jcvf /tmp/${name}.tar.xz ${d} )
|
||||
@ -69,32 +39,89 @@ cp -a tests/bench-v8 $outdir/tests
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# binary release
|
||||
# Windows binary release
|
||||
|
||||
if [ "$binary" = "yes" ] ; then
|
||||
if echo $release_list | grep -w -q win_binary ; then
|
||||
|
||||
d="quickjs-linux-x86_64-${version}"
|
||||
name="quickjs-linux-x86_64-${version}"
|
||||
# win64
|
||||
|
||||
dlldir=/usr/x86_64-w64-mingw32/sys-root/mingw/bin
|
||||
cross_prefix="x86_64-w64-mingw32-"
|
||||
d="quickjs-win-x86_64-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
files="qjs qjsbn run-test262 run-test262-bn"
|
||||
make CONFIG_WIN32=y qjs.exe
|
||||
cp qjs.exe $outdir
|
||||
${cross_prefix}strip $outdir/qjs.exe
|
||||
cp $dlldir/libwinpthread-1.dll $outdir
|
||||
|
||||
make -j4 $files
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
strip $files
|
||||
cp $files $outdir
|
||||
make CONFIG_WIN32=y clean
|
||||
|
||||
( cd /tmp/$d && rm -f ../${name}.zip && zip -r ../${name}.zip . )
|
||||
# win32
|
||||
|
||||
dlldir=/usr/i686-w64-mingw32/sys-root/mingw/bin
|
||||
cross_prefix="i686-w64-mingw32-"
|
||||
d="quickjs-win-i686-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
make clean
|
||||
make CONFIG_WIN32=y clean
|
||||
|
||||
make CONFIG_WIN32=y CONFIG_M32=y qjs.exe
|
||||
cp qjs.exe $outdir
|
||||
${cross_prefix}strip $outdir/qjs.exe
|
||||
cp $dlldir/libwinpthread-1.dll $outdir
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# Linux binary release
|
||||
|
||||
if echo $release_list | grep -w -q binary ; then
|
||||
|
||||
make clean
|
||||
make CONFIG_WIN32=y clean
|
||||
make -j4 qjs run-test262
|
||||
make -j4 CONFIG_M32=y qjs32 run-test262-32
|
||||
strip qjs run-test262 qjs32 run-test262-32
|
||||
|
||||
d="quickjs-linux-x86_64-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
cp qjs run-test262 $outdir
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
d="quickjs-linux-i686-${version}"
|
||||
outdir="/tmp/${d}"
|
||||
|
||||
rm -rf $outdir
|
||||
mkdir -p $outdir
|
||||
|
||||
cp qjs32 $outdir/qjs
|
||||
cp run-test262-32 $outdir/run-test262
|
||||
|
||||
( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )
|
||||
|
||||
fi
|
||||
|
||||
#################################################"
|
||||
# quickjs
|
||||
|
||||
if [ "$quickjs" = "yes" ] ; then
|
||||
if echo $release_list | grep -w -q quickjs ; then
|
||||
|
||||
make build_doc
|
||||
|
||||
@ -112,13 +139,12 @@ cp Makefile VERSION TODO Changelog readme.txt release.sh unicode_download.sh \
|
||||
libregexp.c libregexp.h libregexp-opcode.h \
|
||||
libunicode.c libunicode.h libunicode-table.h \
|
||||
libbf.c libbf.h \
|
||||
jscompress.c unicode_gen.c unicode_gen_def.h \
|
||||
bjson.c \
|
||||
run-test262.c test262o.conf test262.conf test262bn.conf \
|
||||
test262o_errors.txt test262_errors.txt test262bn_errors.txt \
|
||||
unicode_gen.c unicode_gen_def.h \
|
||||
run-test262.c test262o.conf test262.conf \
|
||||
test262o_errors.txt test262_errors.txt \
|
||||
$outdir
|
||||
|
||||
cp tests/*.js tests/*.patch $outdir/tests
|
||||
cp tests/*.js tests/*.patch tests/bjson.c $outdir/tests
|
||||
|
||||
cp examples/*.js examples/*.c $outdir/examples
|
||||
|
||||
|
145
deps/quickjs/repl.js
vendored
145
deps/quickjs/repl.js
vendored
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* QuickJS Read Eval Print Loop
|
||||
*
|
||||
* Copyright (c) 2017-2019 Fabrice Bellard
|
||||
* Copyright (c) 2017-2019 Charlie Gordon
|
||||
* Copyright (c) 2017-2020 Fabrice Bellard
|
||||
* Copyright (c) 2017-2020 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -209,6 +209,29 @@ import * as os from "os";
|
||||
(is_alpha(c) || is_digit(c) || c == '_' || c == '$');
|
||||
}
|
||||
|
||||
function ucs_length(str) {
|
||||
var len, c, i, str_len = str.length;
|
||||
len = 0;
|
||||
/* we never count the trailing surrogate to have the
|
||||
following property: ucs_length(str) =
|
||||
ucs_length(str.substring(0, a)) + ucs_length(str.substring(a,
|
||||
str.length)) for 0 <= a <= str.length */
|
||||
for(i = 0; i < str_len; i++) {
|
||||
c = str.charCodeAt(i);
|
||||
if (c < 0xdc00 || c >= 0xe000)
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
function is_trailing_surrogate(c) {
|
||||
var d;
|
||||
if (typeof c !== "string")
|
||||
return false;
|
||||
d = c.codePointAt(0); /* can be NaN if empty string */
|
||||
return d >= 0xdc00 && d < 0xe000;
|
||||
}
|
||||
|
||||
function is_balanced(a, b) {
|
||||
switch (a + b) {
|
||||
case "()":
|
||||
@ -235,6 +258,7 @@ import * as os from "os";
|
||||
std.puts("\x1b[" + ((n != 1) ? n : "") + code);
|
||||
}
|
||||
|
||||
/* XXX: handle double-width characters */
|
||||
function move_cursor(delta) {
|
||||
var i, l;
|
||||
if (delta > 0) {
|
||||
@ -269,15 +293,16 @@ import * as os from "os";
|
||||
}
|
||||
|
||||
function update() {
|
||||
var i;
|
||||
|
||||
var i, cmd_len;
|
||||
/* cursor_pos is the position in 16 bit characters inside the
|
||||
UTF-16 string 'cmd' */
|
||||
if (cmd != last_cmd) {
|
||||
if (!show_colors && last_cmd.substring(0, last_cursor_pos) == cmd.substring(0, last_cursor_pos)) {
|
||||
/* optimize common case */
|
||||
std.puts(cmd.substring(last_cursor_pos));
|
||||
} else {
|
||||
/* goto the start of the line */
|
||||
move_cursor(-last_cursor_pos);
|
||||
move_cursor(-ucs_length(last_cmd.substring(0, last_cursor_pos)));
|
||||
if (show_colors) {
|
||||
var str = mexpr ? mexpr + '\n' + cmd : cmd;
|
||||
var start = str.length - cmd.length;
|
||||
@ -287,8 +312,7 @@ import * as os from "os";
|
||||
std.puts(cmd);
|
||||
}
|
||||
}
|
||||
/* Note: assuming no surrogate pairs */
|
||||
term_cursor_x = (term_cursor_x + cmd.length) % term_width;
|
||||
term_cursor_x = (term_cursor_x + ucs_length(cmd)) % term_width;
|
||||
if (term_cursor_x == 0) {
|
||||
/* show the cursor on the next line */
|
||||
std.puts(" \x08");
|
||||
@ -298,7 +322,11 @@ import * as os from "os";
|
||||
last_cmd = cmd;
|
||||
last_cursor_pos = cmd.length;
|
||||
}
|
||||
move_cursor(cursor_pos - last_cursor_pos);
|
||||
if (cursor_pos > last_cursor_pos) {
|
||||
move_cursor(ucs_length(cmd.substring(last_cursor_pos, cursor_pos)));
|
||||
} else if (cursor_pos < last_cursor_pos) {
|
||||
move_cursor(-ucs_length(cmd.substring(cursor_pos, last_cursor_pos)));
|
||||
}
|
||||
last_cursor_pos = cursor_pos;
|
||||
std.out.flush();
|
||||
}
|
||||
@ -333,13 +361,19 @@ import * as os from "os";
|
||||
}
|
||||
|
||||
function forward_char() {
|
||||
if (cursor_pos < cmd.length)
|
||||
if (cursor_pos < cmd.length) {
|
||||
cursor_pos++;
|
||||
while (is_trailing_surrogate(cmd.charAt(cursor_pos)))
|
||||
cursor_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
function backward_char() {
|
||||
if (cursor_pos > 0)
|
||||
if (cursor_pos > 0) {
|
||||
cursor_pos--;
|
||||
while (is_trailing_surrogate(cmd.charAt(cursor_pos)))
|
||||
cursor_pos--;
|
||||
}
|
||||
}
|
||||
|
||||
function skip_word_forward(pos) {
|
||||
@ -419,8 +453,18 @@ import * as os from "os";
|
||||
}
|
||||
|
||||
function delete_char_dir(dir) {
|
||||
var start = cursor_pos - (dir < 0);
|
||||
var end = start + 1;
|
||||
var start, end;
|
||||
|
||||
start = cursor_pos;
|
||||
if (dir < 0) {
|
||||
start--;
|
||||
while (is_trailing_surrogate(cmd.charAt(start)))
|
||||
start--;
|
||||
}
|
||||
end = start + 1;
|
||||
while (is_trailing_surrogate(cmd.charAt(end)))
|
||||
end++;
|
||||
|
||||
if (start >= 0 && start < cmd.length) {
|
||||
if (last_fun === kill_region) {
|
||||
kill_region(start, end, dir);
|
||||
@ -752,7 +796,7 @@ import * as os from "os";
|
||||
function readline_print_prompt()
|
||||
{
|
||||
std.puts(prompt);
|
||||
term_cursor_x = prompt.length % term_width;
|
||||
term_cursor_x = ucs_length(prompt) % term_width;
|
||||
last_cmd = "";
|
||||
last_cursor_pos = 0;
|
||||
}
|
||||
@ -785,7 +829,7 @@ import * as os from "os";
|
||||
|
||||
function handle_char(c1) {
|
||||
var c;
|
||||
c = String.fromCharCode(c1);
|
||||
c = String.fromCodePoint(c1);
|
||||
switch(readline_state) {
|
||||
case 0:
|
||||
if (c == '\x1b') { /* '^[' - ESC */
|
||||
@ -825,7 +869,7 @@ import * as os from "os";
|
||||
var fun;
|
||||
|
||||
if (quote_flag) {
|
||||
if (keys.length === 1)
|
||||
if (ucs_length(keys) === 1)
|
||||
insert(keys);
|
||||
quote_flag = false;
|
||||
} else if (fun = commands[keys]) {
|
||||
@ -845,7 +889,7 @@ import * as os from "os";
|
||||
return;
|
||||
}
|
||||
last_fun = this_fun;
|
||||
} else if (keys.length === 1 && keys >= ' ') {
|
||||
} else if (ucs_length(keys) === 1 && keys >= ' ') {
|
||||
insert(keys);
|
||||
last_fun = insert;
|
||||
} else {
|
||||
@ -860,23 +904,40 @@ import * as os from "os";
|
||||
var hex_mode = false;
|
||||
var eval_mode = "std";
|
||||
|
||||
function bignum_typeof(a) {
|
||||
"use bigint";
|
||||
return typeof a;
|
||||
}
|
||||
|
||||
function eval_mode_typeof(a) {
|
||||
if (eval_mode === "std")
|
||||
return typeof a;
|
||||
else
|
||||
return bignum_typeof(a);
|
||||
}
|
||||
|
||||
function number_to_string(a, radix) {
|
||||
var s;
|
||||
if (!isFinite(a)) {
|
||||
/* NaN, Infinite */
|
||||
if (typeof a === "bigfloat" && eval_mode !== "math") {
|
||||
return a.toString();
|
||||
} else {
|
||||
if (a == 0) {
|
||||
if (1 / a < 0)
|
||||
s = "-0";
|
||||
else
|
||||
s = "0";
|
||||
} else {
|
||||
if (radix == 16 && a === Math.floor(a)) {
|
||||
var s;
|
||||
if (a < 0) {
|
||||
a = -a;
|
||||
s = "-";
|
||||
} else {
|
||||
s = "";
|
||||
}
|
||||
s += "0x" + a.toString(16);
|
||||
} else {
|
||||
s = a.toString();
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
function bigfloat_to_string(a, radix) {
|
||||
var s;
|
||||
if (!BigFloat.isFinite(a)) {
|
||||
/* NaN, Infinite */
|
||||
if (eval_mode !== "math") {
|
||||
return "BigFloat(" + a.toString() + ")";
|
||||
} else {
|
||||
return a.toString();
|
||||
@ -939,7 +1000,7 @@ import * as os from "os";
|
||||
function print_rec(a) {
|
||||
var n, i, keys, key, type, s;
|
||||
|
||||
type = eval_mode_typeof(a);
|
||||
type = typeof(a);
|
||||
if (type === "object") {
|
||||
if (a === null) {
|
||||
std.puts(a);
|
||||
@ -994,10 +1055,14 @@ import * as os from "os";
|
||||
if (s.length > 79)
|
||||
s = s.substring(0, 75) + "...\"";
|
||||
std.puts(s);
|
||||
} else if (type === "number" || type === "bigfloat") {
|
||||
} else if (type === "number") {
|
||||
std.puts(number_to_string(a, hex_mode ? 16 : 10));
|
||||
} else if (type === "bigint") {
|
||||
std.puts(bigint_to_string(a, hex_mode ? 16 : 10));
|
||||
} else if (type === "bigfloat") {
|
||||
std.puts(bigfloat_to_string(a, hex_mode ? 16 : 10));
|
||||
} else if (type === "bigdecimal") {
|
||||
std.puts(a.toString() + "m");
|
||||
} else if (type === "symbol") {
|
||||
std.puts(String(a));
|
||||
} else if (type === "function") {
|
||||
@ -1093,8 +1158,7 @@ import * as os from "os";
|
||||
param = expr.substring(cmd.length + 1).trim();
|
||||
if (param === "") {
|
||||
std.puts("Running mode=" + eval_mode + "\n");
|
||||
} else if (param === "std" || param === "math" ||
|
||||
param === "bigint") {
|
||||
} else if (param === "std" || param === "math") {
|
||||
eval_mode = param;
|
||||
} else {
|
||||
std.puts("Invalid mode\n");
|
||||
@ -1145,14 +1209,14 @@ import * as os from "os";
|
||||
"\\t " + sel(show_time) + "toggle timing display\n" +
|
||||
"\\clear clear the terminal\n");
|
||||
if (has_jscalc) {
|
||||
std.puts("\\a " + sel(algebraicMode) + "algegraic mode\n" +
|
||||
std.puts("\\a " + sel(algebraicMode) + "algebraic mode\n" +
|
||||
"\\n " + sel(!algebraicMode) + "numeric mode\n");
|
||||
}
|
||||
if (has_bignum) {
|
||||
std.puts("\\p [m [e]] set the BigFloat precision to 'm' bits\n" +
|
||||
"\\digits n set the BigFloat precision to 'ceil(n*log2(10))' bits\n");
|
||||
if (!has_jscalc) {
|
||||
std.puts("\\mode [std|bigint|math] change the running mode (current = " + eval_mode + ")\n");
|
||||
std.puts("\\mode [std|math] change the running mode (current = " + eval_mode + ")\n");
|
||||
}
|
||||
}
|
||||
if (!config_numcalc) {
|
||||
@ -1166,11 +1230,9 @@ import * as os from "os";
|
||||
try {
|
||||
if (eval_mode === "math")
|
||||
expr = '"use math"; void 0;' + expr;
|
||||
else if (eval_mode === "bigint")
|
||||
expr = '"use bigint"; void 0;' + expr;
|
||||
var now = (new Date).getTime();
|
||||
/* eval as a script */
|
||||
result = std.evalScript(expr);
|
||||
result = std.evalScript(expr, { backtrace_barrier: true });
|
||||
eval_time = (new Date).getTime() - now;
|
||||
std.puts(colors[styles.result]);
|
||||
print(result);
|
||||
@ -1202,15 +1264,12 @@ import * as os from "os";
|
||||
}
|
||||
if (has_bignum) {
|
||||
log2_10 = Math.log(10) / Math.log(2);
|
||||
prec = 113;
|
||||
expBits = 15;
|
||||
if (has_jscalc) {
|
||||
prec = 113;
|
||||
expBits = 15;
|
||||
eval_mode = "math";
|
||||
/* XXX: numeric mode should always be the default ? */
|
||||
g.algebraicMode = config_numcalc;
|
||||
} else {
|
||||
prec = 53;
|
||||
expBits = 11;
|
||||
}
|
||||
}
|
||||
|
||||
|
44
deps/quickjs/run-test262.c
vendored
44
deps/quickjs/run-test262.c
vendored
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* ECMA Test 262 Runner for QuickJS
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
* Copyright (c) 2017-2018 Charlie Gordon
|
||||
* Copyright (c) 2017-2020 Fabrice Bellard
|
||||
* Copyright (c) 2017-2020 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -41,8 +41,6 @@
|
||||
|
||||
/* enable test262 thread support to test SharedArrayBuffer and Atomics */
|
||||
#define CONFIG_AGENT
|
||||
/* cross-realm tests (not supported yet) */
|
||||
//#define CONFIG_REALM
|
||||
|
||||
#define CMD_NAME "run-test262"
|
||||
|
||||
@ -385,8 +383,11 @@ static JSValue js_print(JSContext *ctx, JSValueConst this_val,
|
||||
str = JS_ToCString(ctx, argv[i]);
|
||||
if (!str)
|
||||
return JS_EXCEPTION;
|
||||
if (!strcmp(str, "Test262:AsyncTestComplete"))
|
||||
if (!strcmp(str, "Test262:AsyncTestComplete")) {
|
||||
async_done++;
|
||||
} else if (strstart(str, "Test262:AsyncTestFailure", NULL)) {
|
||||
async_done = 2; /* force an error */
|
||||
}
|
||||
fputs(str, outfile);
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
@ -727,23 +728,31 @@ static JSValue js_new_agent(JSContext *ctx)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_REALM
|
||||
static JSValue js_createRealm(JSContext *ctx, JSValue this_val,
|
||||
int argc, JSValue *argv)
|
||||
{
|
||||
JSContext *ctx1;
|
||||
/* XXX: the context is not freed, need a refcount */
|
||||
JSValue ret;
|
||||
|
||||
ctx1 = JS_NewContext(JS_GetRuntime(ctx));
|
||||
if (!ctx1)
|
||||
return JS_ThrowOutOfMemory(ctx);
|
||||
return add_helpers1(ctx1);
|
||||
ret = add_helpers1(ctx1);
|
||||
/* ctx1 has a refcount so it stays alive */
|
||||
JS_FreeContext(ctx1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static JSValue js_IsHTMLDDA(JSContext *ctx, JSValue this_val,
|
||||
int argc, JSValue *argv)
|
||||
{
|
||||
return JS_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static JSValue add_helpers1(JSContext *ctx)
|
||||
{
|
||||
JSValue global_obj;
|
||||
JSValue obj262;
|
||||
JSValue obj262, obj;
|
||||
|
||||
global_obj = JS_GetGlobalObject(ctx);
|
||||
|
||||
@ -767,12 +776,12 @@ static JSValue add_helpers1(JSContext *ctx)
|
||||
|
||||
JS_SetPropertyStr(ctx, obj262, "global",
|
||||
JS_DupValue(ctx, global_obj));
|
||||
|
||||
#ifdef CONFIG_REALM
|
||||
JS_SetPropertyStr(ctx, obj262, "createRealm",
|
||||
JS_NewCFunction(ctx, js_createRealm,
|
||||
"createRealm", 0));
|
||||
#endif
|
||||
obj = JS_NewCFunction(ctx, js_IsHTMLDDA, "IsHTMLDDA", 0);
|
||||
JS_SetIsHTMLDDA(ctx, obj);
|
||||
JS_SetPropertyStr(ctx, obj262, "IsHTMLDDA", obj);
|
||||
|
||||
JS_SetPropertyStr(ctx, global_obj, "$262", JS_DupValue(ctx, obj262));
|
||||
|
||||
@ -1516,10 +1525,6 @@ int run_test_buf(const char *filename, char *harness, namelist_t *ip,
|
||||
|
||||
add_helpers(ctx);
|
||||
|
||||
/* add backtrace if the isError property is present in a thrown
|
||||
object */
|
||||
JS_EnableIsErrorProperty(ctx, TRUE);
|
||||
|
||||
for (i = 0; i < ip->count; i++) {
|
||||
if (eval_file(ctx, harness, ip->array[i],
|
||||
JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAG_STRIP)) {
|
||||
@ -1817,10 +1822,6 @@ int run_test262_harness_test(const char *filename, BOOL is_module)
|
||||
|
||||
add_helpers(ctx);
|
||||
|
||||
/* add backtrace if the isError property is present in a thrown
|
||||
object */
|
||||
JS_EnableIsErrorProperty(ctx, TRUE);
|
||||
|
||||
buf = load_file(filename, &buf_len);
|
||||
|
||||
if (is_module) {
|
||||
@ -1913,6 +1914,7 @@ void help(void)
|
||||
"-n use new style harness\n"
|
||||
"-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"
|
||||
"-u update error file\n"
|
||||
"-v verbose: output error messages\n"
|
||||
"-T duration display tests taking more than 'duration' ms\n"
|
||||
|
36
deps/quickjs/test262.conf
vendored
36
deps/quickjs/test262.conf
vendored
@ -48,16 +48,21 @@ testdir=test262/test
|
||||
# list the features that are included
|
||||
# skipped features are tagged as such to avoid warnings
|
||||
|
||||
AggregateError
|
||||
align-detached-buffer-semantics-with-web-reality
|
||||
arbitrary-module-namespace-names=skip
|
||||
Array.prototype.flat
|
||||
Array.prototype.flatMap
|
||||
Array.prototype.flatten
|
||||
Array.prototype.item=skip
|
||||
Array.prototype.values
|
||||
ArrayBuffer
|
||||
arrow-function
|
||||
async-functions
|
||||
async-iteration
|
||||
Atomics
|
||||
BigInt=skip
|
||||
Atomics.waitAsync=skip
|
||||
BigInt
|
||||
caller
|
||||
class
|
||||
class-fields-private
|
||||
@ -66,9 +71,11 @@ class-methods-private
|
||||
class-static-fields-public
|
||||
class-static-fields-private
|
||||
class-static-methods-private
|
||||
cleanupSome=skip
|
||||
coalesce-expression
|
||||
computed-property-names
|
||||
const
|
||||
cross-realm=skip
|
||||
cross-realm
|
||||
DataView
|
||||
DataView.prototype.getFloat32
|
||||
DataView.prototype.getFloat64
|
||||
@ -78,26 +85,31 @@ DataView.prototype.getInt8
|
||||
DataView.prototype.getUint16
|
||||
DataView.prototype.getUint32
|
||||
DataView.prototype.setUint8
|
||||
default-arg
|
||||
default-parameters
|
||||
destructuring-assignment
|
||||
destructuring-binding
|
||||
dynamic-import
|
||||
export-star-as-namespace-from-module
|
||||
FinalizationGroup=skip
|
||||
FinalizationRegistry=skip
|
||||
FinalizationRegistry.prototype.cleanupSome=skip
|
||||
Float32Array
|
||||
Float64Array
|
||||
for-in-order
|
||||
for-of
|
||||
generators
|
||||
globalThis
|
||||
hashbang
|
||||
host-gc-required=skip
|
||||
import.meta
|
||||
Int16Array
|
||||
Int32Array
|
||||
Int8Array
|
||||
IsHTMLDDA=skip
|
||||
IsHTMLDDA
|
||||
json-superset
|
||||
legacy-regexp=skip
|
||||
let
|
||||
logical-assignment-operators
|
||||
Map
|
||||
new.target
|
||||
numeric-separator-literal
|
||||
@ -106,8 +118,10 @@ object-spread
|
||||
Object.fromEntries
|
||||
Object.is
|
||||
optional-catch-binding
|
||||
optional-chaining=skip
|
||||
optional-chaining
|
||||
Promise
|
||||
Promise.allSettled
|
||||
Promise.any
|
||||
Promise.prototype.finally
|
||||
Proxy
|
||||
proxy-missing-checks
|
||||
@ -117,6 +131,7 @@ Reflect.set
|
||||
Reflect.setPrototypeOf
|
||||
regexp-dotall
|
||||
regexp-lookbehind
|
||||
regexp-match-indices=skip
|
||||
regexp-named-groups
|
||||
regexp-unicode-property-escapes
|
||||
rest-parameters
|
||||
@ -126,7 +141,9 @@ string-trimming
|
||||
String.fromCodePoint
|
||||
String.prototype.endsWith
|
||||
String.prototype.includes
|
||||
String.prototype.item=skip
|
||||
String.prototype.matchAll
|
||||
String.prototype.replaceAll
|
||||
String.prototype.trimEnd
|
||||
String.prototype.trimStart
|
||||
super
|
||||
@ -149,14 +166,19 @@ tail-call-optimization=skip
|
||||
template
|
||||
top-level-await=skip
|
||||
TypedArray
|
||||
TypedArray.prototype.item=skip
|
||||
u180e
|
||||
Uint16Array
|
||||
Uint32Array
|
||||
Uint8Array
|
||||
Uint8ClampedArray
|
||||
WeakMap
|
||||
WeakRef=skip
|
||||
WeakSet
|
||||
well-formed-json-stringify
|
||||
__getter__
|
||||
__proto__
|
||||
__setter__
|
||||
|
||||
[exclude]
|
||||
# list excluded tests and directories here
|
||||
@ -164,11 +186,9 @@ well-formed-json-stringify
|
||||
# intl not supported
|
||||
test262/test/intl402/
|
||||
|
||||
# these builtins are not supported:
|
||||
test262/test/built-ins/BigInt/
|
||||
|
||||
# incompatible with the "caller" feature
|
||||
test262/test/built-ins/Function/prototype/restricted-property-caller.js
|
||||
test262/test/built-ins/Function/prototype/restricted-property-arguments.js
|
||||
test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
|
||||
|
||||
# slow tests
|
||||
|
49
deps/quickjs/test262_errors.txt
vendored
49
deps/quickjs/test262_errors.txt
vendored
@ -1,2 +1,51 @@
|
||||
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: Test262Error: Expected a ReferenceError but got a ReferenceError
|
||||
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError
|
||||
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name
|
||||
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name
|
||||
test262/test/built-ins/TypedArray/prototype/every/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/every/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/every/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/every/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/filter/BigInt/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/filter/BigInt/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/filter/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/filter/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/findIndex/BigInt/predicate-may-detach-buffer.js:36: Test262Error: throws a TypeError getting a value from the detached buffer Expected a TypeError to be thrown but no exception was thrown at all (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/findIndex/BigInt/predicate-may-detach-buffer.js:36: strict mode: Test262Error: throws a TypeError getting a value from the detached buffer Expected a TypeError to be thrown but no exception was thrown at all (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/forEach/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/forEach/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/forEach/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/forEach/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/map/BigInt/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/map/BigInt/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/map/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/map/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduce/BigInt/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduce/BigInt/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduce/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduce/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduceRight/BigInt/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduceRight/BigInt/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduceRight/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/reduceRight/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/some/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/some/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/some/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArray/prototype/some/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:37: Test262Error: (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:37: strict mode: Test262Error: (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:38: Test262Error: (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:38: strict mode: Test262Error: (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/BigInt/index-prop-desc.js:21: Test262Error: Expected SameValue(«43», «42») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/BigInt/index-prop-desc.js:21: strict mode: Test262Error: Expected SameValue(«43», «42») to be true (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/index-prop-desc.js:22: Test262Error: Expected SameValue(«43», «42») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/index-prop-desc.js:22: strict mode: Test262Error: Expected SameValue(«43», «42») to be true (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:36: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:34: TypeError: cannot convert bigint to number (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:36: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
|
||||
test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
|
||||
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
|
||||
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
|
||||
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined
|
||||
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined
|
||||
|
177
deps/quickjs/test262bn.conf
vendored
177
deps/quickjs/test262bn.conf
vendored
@ -1,177 +0,0 @@
|
||||
[config]
|
||||
# general settings for test262 ES6 bignum version
|
||||
|
||||
# framework style: old, new
|
||||
style=new
|
||||
|
||||
# handle tests tagged as [noStrict]: yes, no, skip
|
||||
nostrict=yes
|
||||
|
||||
# handle tests tagged as [strictOnly]: yes, no, skip
|
||||
strict=yes
|
||||
|
||||
# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all
|
||||
mode=default
|
||||
|
||||
# handle tests flagged as [async]: yes, no, skip
|
||||
# for these, load 'harness/doneprintHandle.js' prior to test
|
||||
# and expect `print('Test262:AsyncTestComplete')` to be called for
|
||||
# successful termination
|
||||
async=yes
|
||||
|
||||
# handle tests flagged as [module]: yes, no, skip
|
||||
module=yes
|
||||
|
||||
# output error messages: yes, no
|
||||
verbose=yes
|
||||
|
||||
# load harness files from this directory
|
||||
harnessdir=test262/harness
|
||||
|
||||
# names of harness include files to skip
|
||||
# bignum version does not support Atomics
|
||||
harnessexclude=testAtomics.js
|
||||
|
||||
# name of the error file for known errors
|
||||
errorfile=test262bn_errors.txt
|
||||
|
||||
# exclude tests enumerated in this file (see also [exclude] section)
|
||||
#excludefile=test262bn_exclude.txt
|
||||
|
||||
# report test results to this file
|
||||
reportfile=test262bn_report.txt
|
||||
|
||||
# enumerate tests from this directory
|
||||
testdir=test262/test
|
||||
|
||||
[features]
|
||||
# Standard language features and proposed extensions
|
||||
# list the features that are included
|
||||
# skipped features are tagged as such to avoid warnings
|
||||
|
||||
Array.prototype.flat
|
||||
Array.prototype.flatMap
|
||||
Array.prototype.flatten
|
||||
Array.prototype.values
|
||||
ArrayBuffer
|
||||
arrow-function
|
||||
async-functions
|
||||
async-iteration
|
||||
Atomics
|
||||
BigInt
|
||||
caller
|
||||
class
|
||||
class-fields-private
|
||||
class-fields-public
|
||||
class-methods-private
|
||||
class-static-fields-public
|
||||
class-static-fields-private
|
||||
class-static-methods-private
|
||||
computed-property-names
|
||||
const
|
||||
cross-realm=skip
|
||||
DataView
|
||||
DataView.prototype.getFloat32
|
||||
DataView.prototype.getFloat64
|
||||
DataView.prototype.getInt16
|
||||
DataView.prototype.getInt32
|
||||
DataView.prototype.getInt8
|
||||
DataView.prototype.getUint16
|
||||
DataView.prototype.getUint32
|
||||
DataView.prototype.setUint8
|
||||
default-arg
|
||||
default-parameters
|
||||
destructuring-assignment
|
||||
destructuring-binding
|
||||
dynamic-import
|
||||
export-star-as-namespace-from-module
|
||||
FinalizationGroup=skip
|
||||
Float32Array
|
||||
Float64Array
|
||||
for-of
|
||||
generators
|
||||
globalThis=skip
|
||||
hashbang
|
||||
host-gc-required=skip
|
||||
import.meta
|
||||
Int32Array
|
||||
Int8Array
|
||||
IsHTMLDDA=skip
|
||||
json-superset
|
||||
let
|
||||
Map
|
||||
new.target
|
||||
numeric-separator-literal
|
||||
object-rest
|
||||
object-spread
|
||||
Object.fromEntries
|
||||
Object.is
|
||||
optional-catch-binding
|
||||
optional-chaining=skip
|
||||
Promise.allSettled
|
||||
Promise.prototype.finally
|
||||
Proxy
|
||||
proxy-missing-checks
|
||||
Reflect
|
||||
Reflect.construct
|
||||
Reflect.set
|
||||
Reflect.setPrototypeOf
|
||||
regexp-dotall
|
||||
regexp-lookbehind
|
||||
regexp-named-groups
|
||||
regexp-unicode-property-escapes
|
||||
rest-parameters
|
||||
Set
|
||||
SharedArrayBuffer
|
||||
string-trimming
|
||||
String.fromCodePoint
|
||||
String.prototype.endsWith
|
||||
String.prototype.includes
|
||||
String.prototype.matchAll
|
||||
String.prototype.trimEnd
|
||||
String.prototype.trimStart
|
||||
super
|
||||
Symbol
|
||||
Symbol.asyncIterator
|
||||
Symbol.hasInstance
|
||||
Symbol.isConcatSpreadable
|
||||
Symbol.iterator
|
||||
Symbol.match
|
||||
Symbol.matchAll
|
||||
Symbol.prototype.description
|
||||
Symbol.replace
|
||||
Symbol.search
|
||||
Symbol.species
|
||||
Symbol.split
|
||||
Symbol.toPrimitive
|
||||
Symbol.toStringTag
|
||||
Symbol.unscopables
|
||||
tail-call-optimization=skip
|
||||
template
|
||||
top-level-await=skip
|
||||
TypedArray
|
||||
u180e
|
||||
Uint16Array
|
||||
Uint8Array
|
||||
Uint8ClampedArray
|
||||
WeakMap
|
||||
WeakRef=skip
|
||||
WeakSet
|
||||
well-formed-json-stringify
|
||||
|
||||
[exclude]
|
||||
# list excluded tests and directories here
|
||||
|
||||
# intl not supported
|
||||
test262/test/intl402/
|
||||
|
||||
# incompatible with the "caller" feature
|
||||
test262/test/built-ins/Function/prototype/restricted-property-caller.js
|
||||
test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
|
||||
|
||||
# slow tests
|
||||
#test262/test/built-ins/RegExp/CharacterClassEscapes/
|
||||
#test262/test/built-ins/RegExp/property-escapes/
|
||||
|
||||
[tests]
|
||||
# list test files or use config.testdir
|
2
deps/quickjs/test262bn_errors.txt
vendored
2
deps/quickjs/test262bn_errors.txt
vendored
@ -1,2 +0,0 @@
|
||||
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
|
||||
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
|
@ -21,8 +21,8 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "quickjs-libc.h"
|
||||
#include "cutils.h"
|
||||
#include "../quickjs-libc.h"
|
||||
#include "../cutils.h"
|
||||
|
||||
static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
@ -31,6 +31,7 @@ static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
|
||||
uint64_t pos, len;
|
||||
JSValue obj;
|
||||
size_t size;
|
||||
int flags;
|
||||
|
||||
if (JS_ToIndex(ctx, &pos, argv[1]))
|
||||
return JS_EXCEPTION;
|
||||
@ -41,7 +42,10 @@ static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
|
||||
return JS_EXCEPTION;
|
||||
if (pos + len > size)
|
||||
return JS_ThrowRangeError(ctx, "array buffer overflow");
|
||||
obj = JS_ReadObject(ctx, buf + pos, len, 0);
|
||||
flags = 0;
|
||||
if (JS_ToBool(ctx, argv[3]))
|
||||
flags |= JS_READ_OBJ_REFERENCE;
|
||||
obj = JS_ReadObject(ctx, buf + pos, len, flags);
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -51,8 +55,12 @@ static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
|
||||
size_t len;
|
||||
uint8_t *buf;
|
||||
JSValue array;
|
||||
int flags;
|
||||
|
||||
buf = JS_WriteObject(ctx, &len, argv[0], 0);
|
||||
flags = 0;
|
||||
if (JS_ToBool(ctx, argv[1]))
|
||||
flags |= JS_WRITE_OBJ_REFERENCE;
|
||||
buf = JS_WriteObject(ctx, &len, argv[0], flags);
|
||||
if (!buf)
|
||||
return JS_EXCEPTION;
|
||||
array = JS_NewArrayBufferCopy(ctx, buf, len);
|
||||
@ -61,8 +69,8 @@ static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
|
||||
}
|
||||
|
||||
static const JSCFunctionListEntry js_bjson_funcs[] = {
|
||||
JS_CFUNC_DEF("read", 3, js_bjson_read ),
|
||||
JS_CFUNC_DEF("write", 1, js_bjson_write ),
|
||||
JS_CFUNC_DEF("read", 4, js_bjson_read ),
|
||||
JS_CFUNC_DEF("write", 2, js_bjson_write ),
|
||||
};
|
||||
|
||||
static int js_bjson_init(JSContext *ctx, JSModuleDef *m)
|
93
deps/quickjs/tests/microbench.js
vendored
93
deps/quickjs/tests/microbench.js
vendored
@ -22,8 +22,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
import * as std from "std";
|
||||
|
||||
function pad(str, n) {
|
||||
str += "";
|
||||
@ -98,13 +97,16 @@ var clocks_per_sec = 1000000;
|
||||
var max_iterations = 100;
|
||||
var clock_threshold = 2000; /* favoring short measuring spans */
|
||||
var min_n_argument = 1;
|
||||
var __date_clock;
|
||||
var get_clock;
|
||||
|
||||
if (typeof __date_clock != "function") {
|
||||
if (typeof globalThis.__date_clock != "function") {
|
||||
console.log("using fallback millisecond clock");
|
||||
clocks_per_sec = 1000;
|
||||
max_iterations = 10;
|
||||
clock_threshold = 100;
|
||||
get_clock = Date.now;
|
||||
} else {
|
||||
get_clock = globalThis.__date_clock;
|
||||
}
|
||||
|
||||
function log_one(text, n, ti) {
|
||||
@ -136,21 +138,18 @@ function bench(f, text)
|
||||
if (f.bench) {
|
||||
ti_n = f(text);
|
||||
} else {
|
||||
var clock = __date_clock;
|
||||
if (typeof clock != "function")
|
||||
clock = Date.now;
|
||||
ti_n = 1000000000;
|
||||
min_ti = clock_threshold / 10;
|
||||
for(i = 0; i < 30; i++) {
|
||||
ti = 1000000000;
|
||||
for (j = 0; j < max_iterations; j++) {
|
||||
t = clock();
|
||||
while ((t1 = clock()) == t)
|
||||
t = get_clock();
|
||||
while ((t1 = get_clock()) == t)
|
||||
continue;
|
||||
nb_its = f(n);
|
||||
if (nb_its < 0)
|
||||
return; // test failure
|
||||
t1 = clock() - t1;
|
||||
t1 = get_clock() - t1;
|
||||
if (ti > t1)
|
||||
ti = t1;
|
||||
}
|
||||
@ -229,6 +228,19 @@ function prop_create(n)
|
||||
return n * 4;
|
||||
}
|
||||
|
||||
function prop_delete(n)
|
||||
{
|
||||
var obj, j;
|
||||
obj = {};
|
||||
for(j = 0; j < n; j++) {
|
||||
obj[j] = 1;
|
||||
}
|
||||
for(j = 0; j < n; j++) {
|
||||
delete obj[j];
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
function array_read(n)
|
||||
{
|
||||
var tab, len, sum, i, j;
|
||||
@ -827,9 +839,9 @@ function sort_bench(text) {
|
||||
for (j = 0; j < 100; j++) {
|
||||
arr = new array_type(n);
|
||||
f(arr, n, def);
|
||||
var t1 = __date_clock();
|
||||
var t1 = get_clock();
|
||||
arr.sort();
|
||||
t1 = __date_clock() - t1;
|
||||
t1 = get_clock() - t1;
|
||||
tx += t1;
|
||||
if (!ti || ti > t1)
|
||||
ti = t1;
|
||||
@ -867,16 +879,60 @@ function sort_bench(text) {
|
||||
sort_bench.bench = true;
|
||||
sort_bench.verbose = false;
|
||||
|
||||
function int_to_string(n)
|
||||
{
|
||||
var s, r, j;
|
||||
r = 0;
|
||||
for(j = 0; j < n; j++) {
|
||||
s = (j + 1).toString();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
function float_to_string(n)
|
||||
{
|
||||
var s, r, j;
|
||||
r = 0;
|
||||
for(j = 0; j < n; j++) {
|
||||
s = (j + 0.1).toString();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
function string_to_int(n)
|
||||
{
|
||||
var s, r, j;
|
||||
r = 0;
|
||||
s = "12345";
|
||||
r = 0;
|
||||
for(j = 0; j < n; j++) {
|
||||
r += (s | 0);
|
||||
}
|
||||
global_res = r;
|
||||
return n;
|
||||
}
|
||||
|
||||
function string_to_float(n)
|
||||
{
|
||||
var s, r, j;
|
||||
r = 0;
|
||||
s = "12345.6";
|
||||
r = 0;
|
||||
for(j = 0; j < n; j++) {
|
||||
r -= s;
|
||||
}
|
||||
global_res = r;
|
||||
return n;
|
||||
}
|
||||
|
||||
function load_result(filename)
|
||||
{
|
||||
var f, str, res;
|
||||
if (typeof std === "undefined")
|
||||
return null;
|
||||
try {
|
||||
f = std.open(filename, "r");
|
||||
} catch(e) {
|
||||
f = std.open(filename, "r");
|
||||
if (!f)
|
||||
return null;
|
||||
}
|
||||
str = f.readAsString();
|
||||
res = JSON.parse(str);
|
||||
f.close();
|
||||
@ -902,6 +958,7 @@ function main(argc, argv, g)
|
||||
prop_read,
|
||||
prop_write,
|
||||
prop_create,
|
||||
prop_delete,
|
||||
array_read,
|
||||
array_write,
|
||||
array_prop_create,
|
||||
@ -931,6 +988,10 @@ function main(argc, argv, g)
|
||||
//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;
|
||||
|
10
deps/quickjs/tests/test262.patch
vendored
10
deps/quickjs/tests/test262.patch
vendored
@ -1,8 +1,8 @@
|
||||
diff --git a/harness/atomicsHelper.js b/harness/atomicsHelper.js
|
||||
index 135c16e..b19f2ef 100644
|
||||
index 9c1217351e..3c24755558 100644
|
||||
--- a/harness/atomicsHelper.js
|
||||
+++ b/harness/atomicsHelper.js
|
||||
@@ -222,10 +222,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 135c16e..b19f2ef 100644
|
||||
|
||||
/**
|
||||
diff --git a/harness/regExpUtils.js b/harness/regExpUtils.js
|
||||
index 2abfee3..e7c07b1 100644
|
||||
index be7039fda0..7b38abf8df 100644
|
||||
--- a/harness/regExpUtils.js
|
||||
+++ b/harness/regExpUtils.js
|
||||
@@ -5,24 +5,27 @@ description: |
|
||||
Collection of functions used to assert the correctness of RegExp objects.
|
||||
@@ -6,24 +6,27 @@ description: |
|
||||
defines: [buildString, testPropertyEscapes, matchValidator]
|
||||
---*/
|
||||
|
||||
+if ($262 && typeof $262.codePointRange === "function") {
|
||||
|
435
deps/quickjs/tests/test_bignum.js
vendored
435
deps/quickjs/tests/test_bignum.js
vendored
@ -1,4 +1,3 @@
|
||||
"use math";
|
||||
"use strict";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
@ -18,48 +17,104 @@ function assert(actual, expected, message) {
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function assertThrows(err, func)
|
||||
{
|
||||
var ex;
|
||||
ex = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
ex = true;
|
||||
assert(e instanceof err);
|
||||
}
|
||||
assert(ex, true, "exception expected");
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
function pow(a, n)
|
||||
function bigint_pow(a, n)
|
||||
{
|
||||
var r, i;
|
||||
r = 1;
|
||||
for(i = 0; i < n; i++)
|
||||
r = 1n;
|
||||
for(i = 0n; i < n; i++)
|
||||
r *= a;
|
||||
return r;
|
||||
}
|
||||
|
||||
function test_integer()
|
||||
/* a must be < b */
|
||||
function test_less(a, b)
|
||||
{
|
||||
assert(a < b);
|
||||
assert(!(b < a));
|
||||
assert(a <= b);
|
||||
assert(!(b <= a));
|
||||
assert(b > a);
|
||||
assert(!(a > b));
|
||||
assert(b >= a);
|
||||
assert(!(a >= b));
|
||||
assert(a != b);
|
||||
assert(!(a == b));
|
||||
}
|
||||
|
||||
/* a must be numerically equal to b */
|
||||
function test_eq(a, b)
|
||||
{
|
||||
assert(a == b);
|
||||
assert(b == a);
|
||||
assert(!(a != b));
|
||||
assert(!(b != a));
|
||||
assert(a <= b);
|
||||
assert(b <= a);
|
||||
assert(!(a < b));
|
||||
assert(a >= b);
|
||||
assert(b >= a);
|
||||
assert(!(a > b));
|
||||
}
|
||||
|
||||
function test_bigint1()
|
||||
{
|
||||
var a, r;
|
||||
a = pow(3, 100);
|
||||
assert((a - 1) != a);
|
||||
assert(a == 515377520732011331036461129765621272702107522001);
|
||||
assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1);
|
||||
assert(Integer.isInteger(1) === true);
|
||||
assert(Integer.isInteger(1.0) === false);
|
||||
|
||||
assert(Integer.floorLog2(0) === -1);
|
||||
assert(Integer.floorLog2(7) === 2);
|
||||
test_less(2n, 3n);
|
||||
test_eq(3n, 3n);
|
||||
|
||||
r = 1 << 31;
|
||||
assert(r, 2147483648, "1 << 31 === 2147483648");
|
||||
test_less(2, 3n);
|
||||
test_eq(3, 3n);
|
||||
|
||||
test_less(2.1, 3n);
|
||||
test_eq(Math.sqrt(4), 2n);
|
||||
|
||||
a = bigint_pow(3n, 100n);
|
||||
assert((a - 1n) != a);
|
||||
assert(a == 515377520732011331036461129765621272702107522001n);
|
||||
assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1n);
|
||||
|
||||
r = 1n << 31n;
|
||||
assert(r, 2147483648n, "1 << 31n === 2147483648n");
|
||||
|
||||
r = 1 << 32;
|
||||
assert(r, 4294967296, "1 << 32 === 4294967296");
|
||||
|
||||
r = (1 << 31) < 0;
|
||||
assert(r, false, "(1 << 31) < 0 === false");
|
||||
r = 1n << 32n;
|
||||
assert(r, 4294967296n, "1 << 32n === 4294967296n");
|
||||
}
|
||||
|
||||
function test_bigint2()
|
||||
{
|
||||
assert(BigInt(""), 0n);
|
||||
assert(BigInt(" 123"), 123n);
|
||||
assert(BigInt(" 123 "), 123n);
|
||||
assertThrows(SyntaxError, () => { BigInt("+") } );
|
||||
assertThrows(SyntaxError, () => { BigInt("-") } );
|
||||
assertThrows(SyntaxError, () => { BigInt("\x00a") } );
|
||||
assertThrows(SyntaxError, () => { BigInt(" 123 r") } );
|
||||
}
|
||||
|
||||
function test_divrem(div1, a, b, q)
|
||||
{
|
||||
var div, divrem, t;
|
||||
div = Integer[div1];
|
||||
divrem = Integer[div1 + "rem"];
|
||||
div = BigInt[div1];
|
||||
divrem = BigInt[div1 + "rem"];
|
||||
assert(div(a, b) == q);
|
||||
t = divrem(a, b);
|
||||
assert(t[0] == q);
|
||||
@ -74,196 +129,198 @@ function test_idiv1(div, a, b, r)
|
||||
test_divrem(div, -a, -b, r[3]);
|
||||
}
|
||||
|
||||
function test_idiv()
|
||||
/* QuickJS BigInt extensions */
|
||||
function test_bigint_ext()
|
||||
{
|
||||
test_idiv1("tdiv", 3, 2, [1, -1, -1, 1]);
|
||||
test_idiv1("fdiv", 3, 2, [1, -2, -2, 1]);
|
||||
test_idiv1("cdiv", 3, 2, [2, -1, -1, 2]);
|
||||
test_idiv1("ediv", 3, 2, [1, -2, -1, 2]);
|
||||
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_float()
|
||||
function test_bigfloat()
|
||||
{
|
||||
var e, a, b, sqrt2;
|
||||
|
||||
assert(typeof 1 === "bigint");
|
||||
assert(typeof 1.0 === "bigfloat");
|
||||
assert(1 == 1.0);
|
||||
assert(1 !== 1.0);
|
||||
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(2, e);
|
||||
assert(a == BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));
|
||||
a = BigFloat.sqrt(2l, e);
|
||||
assert(a === BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e));
|
||||
assert(e.inexact === true);
|
||||
assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcd);
|
||||
assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcc908b2fb1366ea95l);
|
||||
|
||||
b = BigFloatEnv.setPrec(BigFloat.sqrt.bind(null, 2), 128);
|
||||
assert(a == b);
|
||||
}
|
||||
assert(a === b);
|
||||
|
||||
/* jscalc tests */
|
||||
assert(BigFloat.isNaN(BigFloat(NaN)));
|
||||
assert(BigFloat.isFinite(1l));
|
||||
assert(!BigFloat.isFinite(1l/0l));
|
||||
|
||||
function test_modulo()
|
||||
{
|
||||
var i, p, a, b;
|
||||
assert(BigFloat.abs(-3l) === 3l);
|
||||
assert(BigFloat.sign(-3l) === -1l);
|
||||
|
||||
/* Euclidian modulo operator */
|
||||
assert((-3) % 2 == 1);
|
||||
assert(3 % (-2) == 1);
|
||||
|
||||
p = 101;
|
||||
for(i = 1; i < p; i++) {
|
||||
a = Integer.invmod(i, p);
|
||||
assert(a >= 0 && a < p);
|
||||
assert((i * a) % p == 1);
|
||||
}
|
||||
|
||||
assert(Integer.isPrime(2^107-1));
|
||||
assert(!Integer.isPrime((2^107-1) * (2^89-1)));
|
||||
a = Integer.factor((2^89-1)*2^3*11*13^2*1009);
|
||||
assert(a == [ 2,2,2,11,13,13,1009,618970019642690137449562111 ]);
|
||||
}
|
||||
|
||||
function test_mod()
|
||||
{
|
||||
var a, b, p;
|
||||
assert(BigFloat.exp(0.2l) === 1.2214027581601698339210719946396742l);
|
||||
assert(BigFloat.log(3l) === 1.0986122886681096913952452369225256l);
|
||||
assert(BigFloat.pow(2.1l, 1.6l) === 3.277561666451861947162828744873745l);
|
||||
|
||||
a = Mod(3, 101);
|
||||
b = Mod(-1, 101);
|
||||
assert((a + b) == Mod(2, 101));
|
||||
assert(a ^ 100 == Mod(1, 101));
|
||||
assert(BigFloat.sin(-1l) === -0.841470984807896506652502321630299l);
|
||||
assert(BigFloat.cos(1l) === 0.5403023058681397174009366074429766l);
|
||||
assert(BigFloat.tan(0.1l) === 0.10033467208545054505808004578111154l);
|
||||
|
||||
p = 2 ^ 607 - 1; /* mersenne prime */
|
||||
a = Mod(3, p) ^ (p - 1);
|
||||
assert(a == Mod(1, p));
|
||||
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_polynomial()
|
||||
function test_bigdecimal()
|
||||
{
|
||||
var a, b, q, r, t, i;
|
||||
a = (1 + X) ^ 4;
|
||||
assert(a == X^4+4*X^3+6*X^2+4*X+1);
|
||||
assert(1m === 1m);
|
||||
assert(1m !== 2m);
|
||||
test_less(1m, 2m);
|
||||
test_eq(2m, 2m);
|
||||
|
||||
r = (1 + X);
|
||||
q = (1+X+X^2);
|
||||
b = (1 - X^2);
|
||||
a = q * b + r;
|
||||
t = Polynomial.divrem(a, b);
|
||||
assert(t[0] == q);
|
||||
assert(t[1] == r);
|
||||
test_less(1, 2m);
|
||||
test_eq(2, 2m);
|
||||
|
||||
a = 1 + 2*X + 3*X^2;
|
||||
assert(a.apply(0.1) == 1.23);
|
||||
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);
|
||||
|
||||
a = 1-2*X^2+2*X^3;
|
||||
assert(deriv(a) == (6*X^2-4*X));
|
||||
assert(deriv(integ(a)) == a);
|
||||
assert(BigDecimal(0.1) === 0.1m);
|
||||
assert(BigDecimal(123) === 123m);
|
||||
assert(BigDecimal(true) === 1m);
|
||||
|
||||
a = (X-1)*(X-2)*(X-3)*(X-4)*(X-0.1);
|
||||
r = polroots(a);
|
||||
for(i = 0; i < r.length; i++) {
|
||||
b = abs(a.apply(r[i]));
|
||||
assert(b <= 1e-13);
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
function test_poly_mod()
|
||||
{
|
||||
var a, p;
|
||||
|
||||
/* modulo using polynomials */
|
||||
p = X^2 + X + 1;
|
||||
a = PolyMod(3+X, p) ^ 10;
|
||||
assert(a == PolyMod(-3725*X-18357, p));
|
||||
|
||||
a = PolyMod(1/X, 1+X^2);
|
||||
assert(a == PolyMod(-X, X^2+1));
|
||||
}
|
||||
|
||||
function test_rfunc()
|
||||
{
|
||||
var a;
|
||||
a = (X+1)/((X+1)*(X-1));
|
||||
assert(a == 1/(X-1));
|
||||
a = (X + 2) / (X - 2);
|
||||
assert(a.apply(1/3) == -7/5);
|
||||
|
||||
assert(deriv((X^2-X+1)/(X-1)) == (X^2-2*X)/(X^2-2*X+1));
|
||||
}
|
||||
|
||||
function test_series()
|
||||
{
|
||||
var a, b;
|
||||
a = 1+X+O(X^5);
|
||||
b = a.inverse();
|
||||
assert(b == 1-X+X^2-X^3+X^4+O(X^5));
|
||||
assert(deriv(b) == -1+2*X-3*X^2+4*X^3+O(X^4));
|
||||
assert(deriv(integ(b)) == b);
|
||||
|
||||
a = Series(1/(1-X), 5);
|
||||
assert(a == 1+X+X^2+X^3+X^4+O(X^5));
|
||||
b = a.apply(0.1);
|
||||
assert(b == 1.1111);
|
||||
|
||||
assert(exp(3*X^2+O(X^10)) == 1+3*X^2+9/2*X^4+9/2*X^6+27/8*X^8+O(X^10));
|
||||
assert(sin(X+O(X^6)) == X-1/6*X^3+1/120*X^5+O(X^6));
|
||||
assert(cos(X+O(X^6)) == 1-1/2*X^2+1/24*X^4+O(X^6));
|
||||
assert(tan(X+O(X^8)) == X+1/3*X^3+2/15*X^5+17/315*X^7+O(X^8));
|
||||
assert((1+X+O(X^6))^(2+X) == 1+2*X+2*X^2+3/2*X^3+5/6*X^4+5/12*X^5+O(X^6));
|
||||
}
|
||||
|
||||
function test_matrix()
|
||||
{
|
||||
var a, b, r;
|
||||
a = [[1, 2],[3, 4]];
|
||||
b = [3, 4];
|
||||
r = a * b;
|
||||
assert(r == [11, 25]);
|
||||
r = (a^-1) * 2;
|
||||
assert(r == [[-4, 2],[3, -1]]);
|
||||
|
||||
assert(norm2([1,2,3]) == 14);
|
||||
|
||||
assert(diag([1,2,3]) == [ [ 1, 0, 0 ], [ 0, 2, 0 ], [ 0, 0, 3 ] ]);
|
||||
assert(trans(a) == [ [ 1, 3 ], [ 2, 4 ] ]);
|
||||
assert(trans([1,2,3]) == [[1,2,3]]);
|
||||
assert(trace(a) == 5);
|
||||
|
||||
assert(charpoly(Matrix.hilbert(4)) == X^4-176/105*X^3+3341/12600*X^2-41/23625*X+1/6048000);
|
||||
assert(det(Matrix.hilbert(4)) == 1/6048000);
|
||||
|
||||
a = [[1,2,1],[-2,-3,1],[3,5,0]];
|
||||
assert(rank(a) == 2);
|
||||
assert(ker(a) == [ [ 5 ], [ -3 ], [ 1 ] ]);
|
||||
|
||||
assert(dp([1, 2, 3], [3, -4, -7]) === -26);
|
||||
assert(cp([1, 2, 3], [3, -4, -7]) == [ -2, 16, -10 ]);
|
||||
}
|
||||
|
||||
function assert_eq(a, ref)
|
||||
{
|
||||
assert(abs(a / ref - 1.0) <= 1e-15);
|
||||
}
|
||||
|
||||
function test_trig()
|
||||
{
|
||||
assert_eq(sin(1/2), 0.479425538604203);
|
||||
assert_eq(sin(2+3*I), 9.154499146911428-4.168906959966565*I);
|
||||
assert_eq(cos(2+3*I), -4.189625690968807-9.109227893755337*I);
|
||||
assert_eq((2+0.5*I)^(1.1-0.5*I), 2.494363021357619-0.23076804554558092*I);
|
||||
assert_eq(sqrt(2*I), 1 + I);
|
||||
}
|
||||
|
||||
test_integer();
|
||||
test_idiv();
|
||||
test_float();
|
||||
|
||||
test_modulo();
|
||||
test_mod();
|
||||
test_polynomial();
|
||||
test_poly_mod();
|
||||
test_rfunc();
|
||||
test_series();
|
||||
test_matrix();
|
||||
test_trig();
|
||||
test_bigint1();
|
||||
test_bigint2();
|
||||
test_bigint_ext();
|
||||
test_bigfloat();
|
||||
test_bigdecimal();
|
||||
|
88
deps/quickjs/tests/test_bjson.js
vendored
88
deps/quickjs/tests/test_bjson.js
vendored
@ -1,12 +1,20 @@
|
||||
import * as bjson from "../bjson.so";
|
||||
import * as bjson from "./bjson.so";
|
||||
|
||||
function assert(b, str)
|
||||
{
|
||||
if (b) {
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
} else {
|
||||
throw Error("assertion failed: " + str);
|
||||
}
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function toHex(a)
|
||||
@ -24,6 +32,20 @@ function toHex(a)
|
||||
return s;
|
||||
}
|
||||
|
||||
function isArrayLike(a)
|
||||
{
|
||||
return Array.isArray(a) ||
|
||||
(a instanceof Uint8ClampedArray) ||
|
||||
(a instanceof Uint8Array) ||
|
||||
(a instanceof Uint16Array) ||
|
||||
(a instanceof Uint32Array) ||
|
||||
(a instanceof Int8Array) ||
|
||||
(a instanceof Int16Array) ||
|
||||
(a instanceof Int32Array) ||
|
||||
(a instanceof Float32Array) ||
|
||||
(a instanceof Float64Array);
|
||||
}
|
||||
|
||||
function toStr(a)
|
||||
{
|
||||
var s, i, props, prop;
|
||||
@ -32,7 +54,15 @@ function toStr(a)
|
||||
case "object":
|
||||
if (a === null)
|
||||
return "null";
|
||||
if (Array.isArray(a)) {
|
||||
if (a instanceof Date) {
|
||||
s = "Date(" + toStr(a.valueOf()) + ")";
|
||||
} else if (a instanceof Number) {
|
||||
s = "Number(" + toStr(a.valueOf()) + ")";
|
||||
} else if (a instanceof String) {
|
||||
s = "String(" + toStr(a.valueOf()) + ")";
|
||||
} else if (a instanceof Boolean) {
|
||||
s = "Boolean(" + toStr(a.valueOf()) + ")";
|
||||
} else if (isArrayLike(a)) {
|
||||
s = "[";
|
||||
for(i = 0; i < a.length; i++) {
|
||||
if (i != 0)
|
||||
@ -85,6 +115,35 @@ function bjson_test(a)
|
||||
}
|
||||
}
|
||||
|
||||
/* test multiple references to an object including circular
|
||||
references */
|
||||
function bjson_test_reference()
|
||||
{
|
||||
var array, buf, i, n, array_buffer;
|
||||
n = 16;
|
||||
array = [];
|
||||
for(i = 0; i < n; i++)
|
||||
array[i] = {};
|
||||
array_buffer = new ArrayBuffer(n);
|
||||
for(i = 0; i < n; i++) {
|
||||
array[i].next = array[(i + 1) % n];
|
||||
array[i].idx = i;
|
||||
array[i].typed_array = new Uint8Array(array_buffer, i, 1);
|
||||
}
|
||||
buf = bjson.write(array, true);
|
||||
|
||||
array = bjson.read(buf, 0, buf.byteLength, true);
|
||||
|
||||
/* check the result */
|
||||
for(i = 0; i < n; i++) {
|
||||
assert(array[i].next, array[(i + 1) % n]);
|
||||
assert(array[i].idx, i);
|
||||
assert(array[i].typed_array.buffer, array_buffer);
|
||||
assert(array[i].typed_array.length, 1);
|
||||
assert(array[i].typed_array.byteOffset, i);
|
||||
}
|
||||
}
|
||||
|
||||
function bjson_test_all()
|
||||
{
|
||||
var obj;
|
||||
@ -104,7 +163,18 @@ function bjson_test_all()
|
||||
BigFloat.MIN_VALUE]);
|
||||
}, 113, 15);
|
||||
}
|
||||
if (typeof BigDecimal !== "undefined") {
|
||||
bjson_test([BigDecimal("0"),
|
||||
BigDecimal("0.8"), BigDecimal("123321312321321e100"),
|
||||
BigDecimal("-1233213123213214332333223332e100"),
|
||||
BigDecimal("1.233e-1000")]);
|
||||
}
|
||||
|
||||
bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]);
|
||||
|
||||
bjson_test(new Int32Array([123123, 222111, -32222]));
|
||||
bjson_test(new Float64Array([123123, 222111.5]));
|
||||
|
||||
/* tested with a circular reference */
|
||||
obj = {};
|
||||
obj.x = obj;
|
||||
@ -114,6 +184,8 @@ function bjson_test_all()
|
||||
} catch(e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
|
||||
bjson_test_reference();
|
||||
}
|
||||
|
||||
bjson_test_all();
|
||||
|
38
deps/quickjs/tests/test_builtin.js
vendored
38
deps/quickjs/tests/test_builtin.js
vendored
@ -17,6 +17,22 @@ function assert(actual, expected, message) {
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function assert_throws(expected_error, func)
|
||||
{
|
||||
var err = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
err = true;
|
||||
if (!(e instanceof expected_error)) {
|
||||
throw Error("unexpected exception type");
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
throw Error("expected exception");
|
||||
}
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
@ -39,7 +55,7 @@ function test_function()
|
||||
function constructor1(a) {
|
||||
this.x = a;
|
||||
}
|
||||
|
||||
|
||||
var r, g;
|
||||
|
||||
r = my_func.call(null, 1, 2);
|
||||
@ -48,6 +64,13 @@ function test_function()
|
||||
r = my_func.apply(null, [1, 2]);
|
||||
assert(r, 3, "apply");
|
||||
|
||||
r = (function () { return 1; }).apply(null, undefined);
|
||||
assert(r, 1);
|
||||
|
||||
assert_throws(TypeError, (function() {
|
||||
Reflect.apply((function () { return 1; }), null, undefined);
|
||||
}));
|
||||
|
||||
r = new Function("a", "b", "return a + b;");
|
||||
assert(r(2,3), 5, "function");
|
||||
|
||||
@ -277,6 +300,8 @@ function test_string()
|
||||
assert("aaaa".split("aaaaa", 1), [ "aaaa" ]);
|
||||
|
||||
assert(eval('"\0"'), "\0");
|
||||
|
||||
assert("abc".padStart(Infinity, ""), "abc");
|
||||
}
|
||||
|
||||
function test_math()
|
||||
@ -287,6 +312,10 @@ function test_math()
|
||||
assert(Math.ceil(a), 2);
|
||||
assert(Math.imul(0x12345678, 123), -1088058456);
|
||||
assert(Math.fround(0.1), 0.10000000149011612);
|
||||
assert(Math.hypot() == 0);
|
||||
assert(Math.hypot(-2) == 2);
|
||||
assert(Math.hypot(3, 4) == 5);
|
||||
assert(Math.abs(Math.hypot(3, 4, 5) - 7.0710678118654755) <= 1e-15);
|
||||
}
|
||||
|
||||
function test_number()
|
||||
@ -303,6 +332,9 @@ function test_number()
|
||||
assert(parseFloat("-Infinity"), -Infinity);
|
||||
assert(parseFloat("123.2"), 123.2);
|
||||
assert(parseFloat("123.2e3"), 123200);
|
||||
assert(Number.isNaN(Number("+")));
|
||||
assert(Number.isNaN(Number("-")));
|
||||
assert(Number.isNaN(Number("\x00a")));
|
||||
|
||||
assert((25).toExponential(0), "3e+1");
|
||||
assert((-25).toExponential(0), "-3e+1");
|
||||
@ -498,6 +530,10 @@ function test_regexp()
|
||||
a = eval("/\0a/");
|
||||
assert(a.toString(), "/\0a/");
|
||||
assert(a.exec("\0a")[0], "\0a");
|
||||
|
||||
assert(/{1a}/.toString(), "/{1a}/");
|
||||
a = /a{1+/.exec("a{11");
|
||||
assert(a, ["a{11"] );
|
||||
}
|
||||
|
||||
function test_symbol()
|
||||
|
@ -15,6 +15,22 @@ function assert(actual, expected, message) {
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function assert_throws(expected_error, func)
|
||||
{
|
||||
var err = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
err = true;
|
||||
if (!(e instanceof expected_error)) {
|
||||
throw Error("unexpected exception type");
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
throw Error("expected exception");
|
||||
}
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
@ -233,8 +249,13 @@ function test_delete()
|
||||
|
||||
function test_prototype()
|
||||
{
|
||||
function f() { }
|
||||
var f = function f() { };
|
||||
assert(f.prototype.constructor, f, "prototype");
|
||||
|
||||
var g = function g() { };
|
||||
/* QuickJS bug */
|
||||
Object.defineProperty(g, "prototype", { writable: false });
|
||||
assert(g.prototype.constructor, g, "prototype");
|
||||
}
|
||||
|
||||
function test_arguments()
|
||||
@ -311,10 +332,21 @@ function test_template()
|
||||
var a, b;
|
||||
b = 123;
|
||||
a = `abc${b}d`;
|
||||
assert(a === "abc123d");
|
||||
assert(a, "abc123d");
|
||||
|
||||
a = String.raw `abc${b}d`;
|
||||
assert(a === "abc123d");
|
||||
assert(a, "abc123d");
|
||||
|
||||
a = "aaa";
|
||||
b = "bbb";
|
||||
assert(`aaa${a, b}ccc`, "aaabbbccc");
|
||||
}
|
||||
|
||||
function test_template_skip()
|
||||
{
|
||||
var a = "Bar";
|
||||
var { b = `${a + `a${a}` }baz` } = {};
|
||||
assert(b, "BaraBarbaz");
|
||||
}
|
||||
|
||||
function test_object_literal()
|
||||
@ -337,6 +369,163 @@ function test_regexp_skip()
|
||||
assert(a === 2);
|
||||
}
|
||||
|
||||
function test_labels()
|
||||
{
|
||||
do x: { break x; } while(0);
|
||||
if (1)
|
||||
x: { break x; }
|
||||
else
|
||||
x: { break x; }
|
||||
with ({}) x: { break x; };
|
||||
while (0) x: { break x; };
|
||||
}
|
||||
|
||||
function test_destructuring()
|
||||
{
|
||||
function * g () { return 0; };
|
||||
var [x] = g();
|
||||
assert(x, void 0);
|
||||
}
|
||||
|
||||
function test_spread()
|
||||
{
|
||||
var x;
|
||||
x = [1, 2, ...[3, 4]];
|
||||
assert(x.toString(), "1,2,3,4");
|
||||
|
||||
x = [ ...[ , ] ];
|
||||
assert(Object.getOwnPropertyNames(x).toString(), "0,length");
|
||||
}
|
||||
|
||||
function test_function_length()
|
||||
{
|
||||
assert( ((a, b = 1, c) => {}).length, 1);
|
||||
assert( (([a,b]) => {}).length, 1);
|
||||
assert( (({a,b}) => {}).length, 1);
|
||||
assert( ((c, [a,b] = 1, d) => {}).length, 1);
|
||||
}
|
||||
|
||||
function test_argument_scope()
|
||||
{
|
||||
var f;
|
||||
var c = "global";
|
||||
|
||||
f = function(a = eval("var arguments")) {};
|
||||
assert_throws(SyntaxError, f);
|
||||
|
||||
f = function(a = eval("1"), b = arguments[0]) { return b; };
|
||||
assert(f(12), 12);
|
||||
|
||||
f = function(a, b = arguments[0]) { return b; };
|
||||
assert(f(12), 12);
|
||||
|
||||
f = function(a, b = () => arguments) { return b; };
|
||||
assert(f(12)()[0], 12);
|
||||
|
||||
f = function(a = eval("1"), b = () => arguments) { return b; };
|
||||
assert(f(12)()[0], 12);
|
||||
|
||||
(function() {
|
||||
"use strict";
|
||||
f = function(a = this) { return a; };
|
||||
assert(f.call(123), 123);
|
||||
|
||||
f = function f(a = f) { return a; };
|
||||
assert(f(), f);
|
||||
|
||||
f = function f(a = eval("f")) { return a; };
|
||||
assert(f(), f);
|
||||
})();
|
||||
|
||||
f = (a = eval("var c = 1"), probe = () => c) => {
|
||||
var c = 2;
|
||||
assert(c, 2);
|
||||
assert(probe(), 1);
|
||||
}
|
||||
f();
|
||||
|
||||
f = (a = eval("var arguments = 1"), probe = () => arguments) => {
|
||||
var arguments = 2;
|
||||
assert(arguments, 2);
|
||||
assert(probe(), 1);
|
||||
}
|
||||
f();
|
||||
|
||||
f = function f(a = eval("var c = 1"), b = c, probe = () => c) {
|
||||
assert(b, 1);
|
||||
assert(c, 1);
|
||||
assert(probe(), 1)
|
||||
}
|
||||
f();
|
||||
|
||||
assert(c, "global");
|
||||
f = function f(a, b = c, probe = () => c) {
|
||||
eval("var c = 1");
|
||||
assert(c, 1);
|
||||
assert(b, "global");
|
||||
assert(probe(), "global")
|
||||
}
|
||||
f();
|
||||
assert(c, "global");
|
||||
|
||||
f = function f(a = eval("var c = 1"), probe = (d = eval("c")) => d) {
|
||||
assert(probe(), 1)
|
||||
}
|
||||
f();
|
||||
}
|
||||
|
||||
function test_function_expr_name()
|
||||
{
|
||||
var f;
|
||||
|
||||
/* non strict mode test : assignment to the function name silently
|
||||
fails */
|
||||
|
||||
f = function myfunc() {
|
||||
myfunc = 1;
|
||||
return myfunc;
|
||||
};
|
||||
assert(f(), f);
|
||||
|
||||
f = function myfunc() {
|
||||
myfunc = 1;
|
||||
(() => {
|
||||
myfunc = 1;
|
||||
})();
|
||||
return myfunc;
|
||||
};
|
||||
assert(f(), f);
|
||||
|
||||
f = function myfunc() {
|
||||
eval("myfunc = 1");
|
||||
return myfunc;
|
||||
};
|
||||
assert(f(), f);
|
||||
|
||||
/* strict mode test : assignment to the function name raises a
|
||||
TypeError exception */
|
||||
|
||||
f = function myfunc() {
|
||||
"use strict";
|
||||
myfunc = 1;
|
||||
};
|
||||
assert_throws(TypeError, f);
|
||||
|
||||
f = function myfunc() {
|
||||
"use strict";
|
||||
(() => {
|
||||
myfunc = 1;
|
||||
})();
|
||||
};
|
||||
assert_throws(TypeError, f);
|
||||
|
||||
f = function myfunc() {
|
||||
"use strict";
|
||||
eval("myfunc = 1");
|
||||
};
|
||||
assert_throws(TypeError, f);
|
||||
}
|
||||
|
||||
test_op1();
|
||||
test_cvt();
|
||||
test_eq();
|
||||
@ -347,6 +536,12 @@ test_prototype();
|
||||
test_arguments();
|
||||
test_class();
|
||||
test_template();
|
||||
test_template_skip();
|
||||
test_object_literal();
|
||||
test_regexp_skip();
|
||||
|
||||
test_labels();
|
||||
test_destructuring();
|
||||
test_spread();
|
||||
test_function_length();
|
||||
test_argument_scope();
|
||||
test_function_expr_name();
|
207
deps/quickjs/tests/test_op_overloading.js
vendored
Normal file
207
deps/quickjs/tests/test_op_overloading.js
vendored
Normal file
@ -0,0 +1,207 @@
|
||||
"use strict";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
/* operators overloading with Operators.create() */
|
||||
function test_operators_create() {
|
||||
class Vec2
|
||||
{
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
static mul_scalar(p1, a) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x * a;
|
||||
r.y = p1.y * a;
|
||||
return r;
|
||||
}
|
||||
toString() {
|
||||
return "Vec2(" + this.x + "," + this.y + ")";
|
||||
}
|
||||
}
|
||||
|
||||
Vec2.prototype[Symbol.operatorSet] = Operators.create(
|
||||
{
|
||||
"+"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x + p2.x;
|
||||
r.y = p1.y + p2.y;
|
||||
return r;
|
||||
},
|
||||
"-"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x - p2.x;
|
||||
r.y = p1.y - p2.y;
|
||||
return r;
|
||||
},
|
||||
"=="(a, b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
},
|
||||
"<"(a, b) {
|
||||
var r;
|
||||
/* lexicographic order */
|
||||
if (a.x == b.x)
|
||||
r = (a.y < b.y);
|
||||
else
|
||||
r = (a.x < b.x);
|
||||
return r;
|
||||
},
|
||||
"++"(a) {
|
||||
var r = new Vec2();
|
||||
r.x = a.x + 1;
|
||||
r.y = a.y + 1;
|
||||
return r;
|
||||
}
|
||||
},
|
||||
{
|
||||
left: Number,
|
||||
"*"(a, b) {
|
||||
return Vec2.mul_scalar(b, a);
|
||||
}
|
||||
},
|
||||
{
|
||||
right: Number,
|
||||
"*"(a, b) {
|
||||
return Vec2.mul_scalar(a, b);
|
||||
}
|
||||
});
|
||||
|
||||
var a = new Vec2(1, 2);
|
||||
var b = new Vec2(3, 4);
|
||||
var r;
|
||||
|
||||
r = a * 2 + 3 * b;
|
||||
assert(r.x === 11 && r.y === 16);
|
||||
assert(a == a, true);
|
||||
assert(a == b, false);
|
||||
assert(a != a, false);
|
||||
assert(a < b, true);
|
||||
assert(a <= b, true);
|
||||
assert(b < a, false);
|
||||
assert(b <= a, false);
|
||||
assert(a <= a, true);
|
||||
assert(a >= a, true);
|
||||
a++;
|
||||
assert(a.x === 2 && a.y === 3);
|
||||
r = ++a;
|
||||
assert(a.x === 3 && a.y === 4);
|
||||
assert(r === a);
|
||||
}
|
||||
|
||||
/* operators overloading thru inheritance */
|
||||
function test_operators()
|
||||
{
|
||||
var Vec2;
|
||||
|
||||
function mul_scalar(p1, a) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x * a;
|
||||
r.y = p1.y * a;
|
||||
return r;
|
||||
}
|
||||
|
||||
var vec2_ops = Operators({
|
||||
"+"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x + p2.x;
|
||||
r.y = p1.y + p2.y;
|
||||
return r;
|
||||
},
|
||||
"-"(p1, p2) {
|
||||
var r = new Vec2();
|
||||
r.x = p1.x - p2.x;
|
||||
r.y = p1.y - p2.y;
|
||||
return r;
|
||||
},
|
||||
"=="(a, b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
},
|
||||
"<"(a, b) {
|
||||
var r;
|
||||
/* lexicographic order */
|
||||
if (a.x == b.x)
|
||||
r = (a.y < b.y);
|
||||
else
|
||||
r = (a.x < b.x);
|
||||
return r;
|
||||
},
|
||||
"++"(a) {
|
||||
var r = new Vec2();
|
||||
r.x = a.x + 1;
|
||||
r.y = a.y + 1;
|
||||
return r;
|
||||
}
|
||||
},
|
||||
{
|
||||
left: Number,
|
||||
"*"(a, b) {
|
||||
return mul_scalar(b, a);
|
||||
}
|
||||
},
|
||||
{
|
||||
right: Number,
|
||||
"*"(a, b) {
|
||||
return mul_scalar(a, b);
|
||||
}
|
||||
});
|
||||
|
||||
Vec2 = class Vec2 extends vec2_ops
|
||||
{
|
||||
constructor(x, y) {
|
||||
super();
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
toString() {
|
||||
return "Vec2(" + this.x + "," + this.y + ")";
|
||||
}
|
||||
}
|
||||
|
||||
var a = new Vec2(1, 2);
|
||||
var b = new Vec2(3, 4);
|
||||
var r;
|
||||
|
||||
r = a * 2 + 3 * b;
|
||||
assert(r.x === 11 && r.y === 16);
|
||||
assert(a == a, true);
|
||||
assert(a == b, false);
|
||||
assert(a != a, false);
|
||||
assert(a < b, true);
|
||||
assert(a <= b, true);
|
||||
assert(b < a, false);
|
||||
assert(b <= a, false);
|
||||
assert(a <= a, true);
|
||||
assert(a >= a, true);
|
||||
a++;
|
||||
assert(a.x === 2 && a.y === 3);
|
||||
r = ++a;
|
||||
assert(a.x === 3 && a.y === 4);
|
||||
assert(r === a);
|
||||
}
|
||||
|
||||
function test_default_op()
|
||||
{
|
||||
assert(Object(1) + 2, 3);
|
||||
assert(Object(1) + true, 2);
|
||||
assert(-Object(1), -1);
|
||||
}
|
||||
|
||||
test_operators_create();
|
||||
test_operators();
|
||||
test_default_op();
|
256
deps/quickjs/tests/test_qjscalc.js
vendored
Normal file
256
deps/quickjs/tests/test_qjscalc.js
vendored
Normal file
@ -0,0 +1,256 @@
|
||||
"use math";
|
||||
"use strict";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
function assertThrows(err, func)
|
||||
{
|
||||
var ex;
|
||||
ex = false;
|
||||
try {
|
||||
func();
|
||||
} catch(e) {
|
||||
ex = true;
|
||||
assert(e instanceof err);
|
||||
}
|
||||
assert(ex, true, "exception expected");
|
||||
}
|
||||
|
||||
// load more elaborate version of assert if available
|
||||
try { __loadScript("test_assert.js"); } catch(e) {}
|
||||
|
||||
/*----------------*/
|
||||
|
||||
function pow(a, n)
|
||||
{
|
||||
var r, i;
|
||||
r = 1;
|
||||
for(i = 0; i < n; i++)
|
||||
r *= a;
|
||||
return r;
|
||||
}
|
||||
|
||||
function test_integer()
|
||||
{
|
||||
var a, r;
|
||||
a = pow(3, 100);
|
||||
assert((a - 1) != a);
|
||||
assert(a == 515377520732011331036461129765621272702107522001);
|
||||
assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1);
|
||||
assert(Integer.isInteger(1) === true);
|
||||
assert(Integer.isInteger(1.0) === false);
|
||||
|
||||
assert(Integer.floorLog2(0) === -1);
|
||||
assert(Integer.floorLog2(7) === 2);
|
||||
|
||||
r = 1 << 31;
|
||||
assert(r, 2147483648, "1 << 31 === 2147483648");
|
||||
|
||||
r = 1 << 32;
|
||||
assert(r, 4294967296, "1 << 32 === 4294967296");
|
||||
|
||||
r = (1 << 31) < 0;
|
||||
assert(r, false, "(1 << 31) < 0 === false");
|
||||
|
||||
assert(typeof 1 === "number");
|
||||
assert(typeof 9007199254740991 === "number");
|
||||
assert(typeof 9007199254740992 === "bigint");
|
||||
}
|
||||
|
||||
function test_float()
|
||||
{
|
||||
assert(typeof 1.0 === "bigfloat");
|
||||
assert(1 == 1.0);
|
||||
assert(1 !== 1.0);
|
||||
}
|
||||
|
||||
/* jscalc tests */
|
||||
|
||||
function test_modulo()
|
||||
{
|
||||
var i, p, a, b;
|
||||
|
||||
/* Euclidian modulo operator */
|
||||
assert((-3) % 2 == 1);
|
||||
assert(3 % (-2) == 1);
|
||||
|
||||
p = 101;
|
||||
for(i = 1; i < p; i++) {
|
||||
a = Integer.invmod(i, p);
|
||||
assert(a >= 0 && a < p);
|
||||
assert((i * a) % p == 1);
|
||||
}
|
||||
|
||||
assert(Integer.isPrime(2^107-1));
|
||||
assert(!Integer.isPrime((2^107-1) * (2^89-1)));
|
||||
a = Integer.factor((2^89-1)*2^3*11*13^2*1009);
|
||||
assert(a == [ 2,2,2,11,13,13,1009,618970019642690137449562111 ]);
|
||||
}
|
||||
|
||||
function test_fraction()
|
||||
{
|
||||
assert((1/3 + 1).toString(), "4/3")
|
||||
assert((2/3)^30, 1073741824/205891132094649);
|
||||
assert(1/3 < 2/3);
|
||||
assert(1/3 < 1);
|
||||
assert(1/3 == 1.0/3);
|
||||
assert(1.0/3 < 2/3);
|
||||
}
|
||||
|
||||
function test_mod()
|
||||
{
|
||||
var a, b, p;
|
||||
|
||||
a = Mod(3, 101);
|
||||
b = Mod(-1, 101);
|
||||
assert((a + b) == Mod(2, 101));
|
||||
assert(a ^ 100 == Mod(1, 101));
|
||||
|
||||
p = 2 ^ 607 - 1; /* mersenne prime */
|
||||
a = Mod(3, p) ^ (p - 1);
|
||||
assert(a == Mod(1, p));
|
||||
}
|
||||
|
||||
function test_polynomial()
|
||||
{
|
||||
var a, b, q, r, t, i;
|
||||
a = (1 + X) ^ 4;
|
||||
assert(a == X^4+4*X^3+6*X^2+4*X+1);
|
||||
|
||||
r = (1 + X);
|
||||
q = (1+X+X^2);
|
||||
b = (1 - X^2);
|
||||
a = q * b + r;
|
||||
t = Polynomial.divrem(a, b);
|
||||
assert(t[0] == q);
|
||||
assert(t[1] == r);
|
||||
|
||||
a = 1 + 2*X + 3*X^2;
|
||||
assert(a.apply(0.1) == 1.23);
|
||||
|
||||
a = 1-2*X^2+2*X^3;
|
||||
assert(deriv(a) == (6*X^2-4*X));
|
||||
assert(deriv(integ(a)) == a);
|
||||
|
||||
a = (X-1)*(X-2)*(X-3)*(X-4)*(X-0.1);
|
||||
r = polroots(a);
|
||||
for(i = 0; i < r.length; i++) {
|
||||
b = abs(a.apply(r[i]));
|
||||
assert(b <= 1e-13);
|
||||
}
|
||||
}
|
||||
|
||||
function test_poly_mod()
|
||||
{
|
||||
var a, p;
|
||||
|
||||
/* modulo using polynomials */
|
||||
p = X^2 + X + 1;
|
||||
a = PolyMod(3+X, p) ^ 10;
|
||||
assert(a == PolyMod(-3725*X-18357, p));
|
||||
|
||||
a = PolyMod(1/X, 1+X^2);
|
||||
assert(a == PolyMod(-X, X^2+1));
|
||||
}
|
||||
|
||||
function test_rfunc()
|
||||
{
|
||||
var a;
|
||||
a = (X+1)/((X+1)*(X-1));
|
||||
assert(a == 1/(X-1));
|
||||
a = (X + 2) / (X - 2);
|
||||
assert(a.apply(1/3) == -7/5);
|
||||
|
||||
assert(deriv((X^2-X+1)/(X-1)) == (X^2-2*X)/(X^2-2*X+1));
|
||||
}
|
||||
|
||||
function test_series()
|
||||
{
|
||||
var a, b;
|
||||
a = 1+X+O(X^5);
|
||||
b = a.inverse();
|
||||
assert(b == 1-X+X^2-X^3+X^4+O(X^5));
|
||||
assert(deriv(b) == -1+2*X-3*X^2+4*X^3+O(X^4));
|
||||
assert(deriv(integ(b)) == b);
|
||||
|
||||
a = Series(1/(1-X), 5);
|
||||
assert(a == 1+X+X^2+X^3+X^4+O(X^5));
|
||||
b = a.apply(0.1);
|
||||
assert(b == 1.1111);
|
||||
|
||||
assert(exp(3*X^2+O(X^10)) == 1+3*X^2+9/2*X^4+9/2*X^6+27/8*X^8+O(X^10));
|
||||
assert(sin(X+O(X^6)) == X-1/6*X^3+1/120*X^5+O(X^6));
|
||||
assert(cos(X+O(X^6)) == 1-1/2*X^2+1/24*X^4+O(X^6));
|
||||
assert(tan(X+O(X^8)) == X+1/3*X^3+2/15*X^5+17/315*X^7+O(X^8));
|
||||
assert((1+X+O(X^6))^(2+X) == 1+2*X+2*X^2+3/2*X^3+5/6*X^4+5/12*X^5+O(X^6));
|
||||
}
|
||||
|
||||
function test_matrix()
|
||||
{
|
||||
var a, b, r;
|
||||
a = [[1, 2],[3, 4]];
|
||||
b = [3, 4];
|
||||
r = a * b;
|
||||
assert(r == [11, 25]);
|
||||
r = (a^-1) * 2;
|
||||
assert(r == [[-4, 2],[3, -1]]);
|
||||
|
||||
assert(norm2([1,2,3]) == 14);
|
||||
|
||||
assert(diag([1,2,3]) == [ [ 1, 0, 0 ], [ 0, 2, 0 ], [ 0, 0, 3 ] ]);
|
||||
assert(trans(a) == [ [ 1, 3 ], [ 2, 4 ] ]);
|
||||
assert(trans([1,2,3]) == [[1,2,3]]);
|
||||
assert(trace(a) == 5);
|
||||
|
||||
assert(charpoly(Matrix.hilbert(4)) == X^4-176/105*X^3+3341/12600*X^2-41/23625*X+1/6048000);
|
||||
assert(det(Matrix.hilbert(4)) == 1/6048000);
|
||||
|
||||
a = [[1,2,1],[-2,-3,1],[3,5,0]];
|
||||
assert(rank(a) == 2);
|
||||
assert(ker(a) == [ [ 5 ], [ -3 ], [ 1 ] ]);
|
||||
|
||||
assert(dp([1, 2, 3], [3, -4, -7]) === -26);
|
||||
assert(cp([1, 2, 3], [3, -4, -7]) == [ -2, 16, -10 ]);
|
||||
}
|
||||
|
||||
function assert_eq(a, ref)
|
||||
{
|
||||
assert(abs(a / ref - 1.0) <= 1e-15);
|
||||
}
|
||||
|
||||
function test_trig()
|
||||
{
|
||||
assert_eq(sin(1/2), 0.479425538604203);
|
||||
assert_eq(sin(2+3*I), 9.154499146911428-4.168906959966565*I);
|
||||
assert_eq(cos(2+3*I), -4.189625690968807-9.109227893755337*I);
|
||||
assert_eq((2+0.5*I)^(1.1-0.5*I), 2.494363021357619-0.23076804554558092*I);
|
||||
assert_eq(sqrt(2*I), 1 + I);
|
||||
}
|
||||
|
||||
test_integer();
|
||||
test_float();
|
||||
|
||||
test_modulo();
|
||||
test_fraction();
|
||||
test_mod();
|
||||
test_polynomial();
|
||||
test_poly_mod();
|
||||
test_rfunc();
|
||||
test_series();
|
||||
test_matrix();
|
||||
test_trig();
|
38
deps/quickjs/tests/test_std.js
vendored
38
deps/quickjs/tests/test_std.js
vendored
@ -26,6 +26,12 @@ try { std.loadScript("test_assert.js"); } catch(e) {}
|
||||
function test_printf()
|
||||
{
|
||||
assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc");
|
||||
assert(std.sprintf("%010d", 123), "0000000123");
|
||||
assert(std.sprintf("%x", -2), "fffffffe");
|
||||
assert(std.sprintf("%lx", -2), "fffffffffffffffe");
|
||||
assert(std.sprintf("%10.1f", 2.1), " 2.1");
|
||||
assert(std.sprintf("%*.*f", 10, 2, -2.13), " -2.13");
|
||||
assert(std.sprintf("%#lx", 0x7fffffffffffffffn), "0x7fffffffffffffff");
|
||||
}
|
||||
|
||||
function test_file1()
|
||||
@ -106,6 +112,9 @@ function test_popen()
|
||||
f.puts(content);
|
||||
f.close();
|
||||
|
||||
/* test loadFile */
|
||||
assert(std.loadFile(fname), content);
|
||||
|
||||
/* execute the 'cat' shell command */
|
||||
f = std.popen("cat " + fname, "r");
|
||||
str = f.readAsString();
|
||||
@ -116,6 +125,20 @@ function test_popen()
|
||||
os.remove(fname);
|
||||
}
|
||||
|
||||
function test_ext_json()
|
||||
{
|
||||
var expected, input, obj;
|
||||
expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"s":"str"}';
|
||||
input = `{ "x":false, /*comments are allowed */
|
||||
"y":true, // also a comment
|
||||
z2:null, // unquoted property names
|
||||
"a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal
|
||||
"s":"str",} // trailing comma in objects and arrays
|
||||
`;
|
||||
obj = std.parseExtJSON(input);
|
||||
assert(JSON.stringify(obj), expected);
|
||||
}
|
||||
|
||||
function test_os()
|
||||
{
|
||||
var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
|
||||
@ -142,13 +165,19 @@ function test_os()
|
||||
buf[i] = i;
|
||||
assert(os.write(fd, buf.buffer, 0, buf.length) === buf.length);
|
||||
|
||||
assert(os.seek(fd, 0, os.SEEK_SET) === 0);
|
||||
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);
|
||||
@ -205,7 +234,11 @@ function test_os_exec()
|
||||
assert(ret, 1);
|
||||
|
||||
fds = os.pipe();
|
||||
pid = os.exec(["echo", "hello"], { stdout: fds[1], block: false } );
|
||||
pid = os.exec(["sh", "-c", "echo $FOO"], {
|
||||
stdout: fds[1],
|
||||
block: false,
|
||||
env: { FOO: "hello" },
|
||||
} );
|
||||
assert(pid >= 0);
|
||||
os.close(fds[1]); /* close the write end (as it is only in the child) */
|
||||
f = std.fdopen(fds[0], "r");
|
||||
@ -245,3 +278,4 @@ test_popen();
|
||||
test_os();
|
||||
test_os_exec();
|
||||
test_timer();
|
||||
test_ext_json();
|
||||
|
62
deps/quickjs/tests/test_worker.js
vendored
Normal file
62
deps/quickjs/tests/test_worker.js
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
/* os.Worker API test */
|
||||
import * as std from "std";
|
||||
import * as os from "os";
|
||||
|
||||
function assert(actual, expected, message) {
|
||||
if (arguments.length == 1)
|
||||
expected = true;
|
||||
|
||||
if (actual === expected)
|
||||
return;
|
||||
|
||||
if (actual !== null && expected !== null
|
||||
&& typeof actual == 'object' && typeof expected == 'object'
|
||||
&& actual.toString() === expected.toString())
|
||||
return;
|
||||
|
||||
throw Error("assertion failed: got |" + actual + "|" +
|
||||
", expected |" + expected + "|" +
|
||||
(message ? " (" + message + ")" : ""));
|
||||
}
|
||||
|
||||
var worker;
|
||||
|
||||
function test_worker()
|
||||
{
|
||||
var counter;
|
||||
|
||||
worker = new os.Worker("./test_worker_module.js");
|
||||
|
||||
counter = 0;
|
||||
worker.onmessage = function (e) {
|
||||
var ev = e.data;
|
||||
// print("recv", JSON.stringify(ev));
|
||||
switch(ev.type) {
|
||||
case "num":
|
||||
assert(ev.num, counter);
|
||||
counter++;
|
||||
if (counter == 10) {
|
||||
/* test SharedArrayBuffer modification */
|
||||
let sab = new SharedArrayBuffer(10);
|
||||
let buf = new Uint8Array(sab);
|
||||
worker.postMessage({ type: "sab", buf: buf });
|
||||
}
|
||||
break;
|
||||
case "sab_done":
|
||||
{
|
||||
let buf = ev.buf;
|
||||
/* check that the SharedArrayBuffer was modified */
|
||||
assert(buf[2], 10);
|
||||
worker.postMessage({ type: "abort" });
|
||||
}
|
||||
break;
|
||||
case "done":
|
||||
/* terminate */
|
||||
worker.onmessage = null;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
test_worker();
|
31
deps/quickjs/tests/test_worker_module.js
vendored
Normal file
31
deps/quickjs/tests/test_worker_module.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
/* Worker code for test_worker.js */
|
||||
import * as std from "std";
|
||||
import * as os from "os";
|
||||
|
||||
var parent = os.Worker.parent;
|
||||
|
||||
function handle_msg(e) {
|
||||
var ev = e.data;
|
||||
// print("child_recv", JSON.stringify(ev));
|
||||
switch(ev.type) {
|
||||
case "abort":
|
||||
parent.postMessage({ type: "done" });
|
||||
break;
|
||||
case "sab":
|
||||
/* modify the SharedArrayBuffer */
|
||||
ev.buf[2] = 10;
|
||||
parent.postMessage({ type: "sab_done", buf: ev.buf });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function worker_main() {
|
||||
var i;
|
||||
|
||||
parent.onmessage = handle_msg;
|
||||
for(i = 0; i < 10; i++) {
|
||||
parent.postMessage({ type: "num", num: i });
|
||||
}
|
||||
}
|
||||
|
||||
worker_main();
|
12
deps/quickjs/unicode_download.sh
vendored
12
deps/quickjs/unicode_download.sh
vendored
@ -1,8 +1,8 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
url="ftp://ftp.unicode.org/Public/12.1.0/ucd"
|
||||
emoji_url="ftp://ftp.unicode.org/Public/emoji/12.0/emoji-data.txt"
|
||||
url="ftp://ftp.unicode.org/Public/13.0.0/ucd"
|
||||
emoji_url="${url}/emoji/emoji-data.txt"
|
||||
|
||||
files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \
|
||||
SpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \
|
||||
@ -11,9 +11,9 @@ PropertyValueAliases.txt"
|
||||
|
||||
mkdir -p unicode
|
||||
|
||||
for f in $files; do
|
||||
g="${url}/${f}"
|
||||
wget $g -O unicode/$f
|
||||
done
|
||||
#for f in $files; do
|
||||
# g="${url}/${f}"
|
||||
# wget $g -O unicode/$f
|
||||
#done
|
||||
|
||||
wget $emoji_url -O unicode/emoji-data.txt
|
||||
|
1
deps/quickjs/unicode_gen.c
vendored
1
deps/quickjs/unicode_gen.c
vendored
@ -296,6 +296,7 @@ void parse_unicode_data(const char *filename)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
last_code = 0;
|
||||
for(;;) {
|
||||
if (!get_line(line, sizeof(line), f))
|
||||
break;
|
||||
|
14
deps/quickjs/unicode_gen_def.h
vendored
14
deps/quickjs/unicode_gen_def.h
vendored
@ -66,6 +66,7 @@ DEF(Caucasian_Albanian, "Aghb")
|
||||
DEF(Chakma, "Cakm")
|
||||
DEF(Cham, "Cham")
|
||||
DEF(Cherokee, "Cher")
|
||||
DEF(Chorasmian, "Chrs")
|
||||
DEF(Common, "Zyyy")
|
||||
DEF(Coptic, "Copt,Qaac")
|
||||
DEF(Cuneiform, "Xsux")
|
||||
@ -73,6 +74,7 @@ DEF(Cypriot, "Cprt")
|
||||
DEF(Cyrillic, "Cyrl")
|
||||
DEF(Deseret, "Dsrt")
|
||||
DEF(Devanagari, "Deva")
|
||||
DEF(Dives_Akuru, "Diak")
|
||||
DEF(Dogra, "Dogr")
|
||||
DEF(Duployan, "Dupl")
|
||||
DEF(Egyptian_Hieroglyphs, "Egyp")
|
||||
@ -106,6 +108,7 @@ DEF(Kayah_Li, "Kali")
|
||||
DEF(Kharoshthi, "Khar")
|
||||
DEF(Khmer, "Khmr")
|
||||
DEF(Khojki, "Khoj")
|
||||
DEF(Khitan_Small_Script, "Kits")
|
||||
DEF(Khudawadi, "Sind")
|
||||
DEF(Lao, "Laoo")
|
||||
DEF(Latin, "Latn")
|
||||
@ -193,6 +196,7 @@ DEF(Ugaritic, "Ugar")
|
||||
DEF(Vai, "Vaii")
|
||||
DEF(Wancho, "Wcho")
|
||||
DEF(Warang_Citi, "Wara")
|
||||
DEF(Yezidi, "Yezi")
|
||||
DEF(Yi, "Yiii")
|
||||
DEF(Zanabazar_Square, "Zanb")
|
||||
#endif
|
||||
@ -244,11 +248,11 @@ DEF(Variation_Selector, "VS")
|
||||
DEF(White_Space, "space")
|
||||
DEF(Bidi_Mirrored, "Bidi_M")
|
||||
DEF(Emoji, "")
|
||||
DEF(Emoji_Component, "")
|
||||
DEF(Emoji_Modifier, "")
|
||||
DEF(Emoji_Modifier_Base, "")
|
||||
DEF(Emoji_Presentation, "")
|
||||
DEF(Extended_Pictographic, "")
|
||||
DEF(Emoji_Component, "EComp")
|
||||
DEF(Emoji_Modifier, "EMod")
|
||||
DEF(Emoji_Modifier_Base, "EBase")
|
||||
DEF(Emoji_Presentation, "EPres")
|
||||
DEF(Extended_Pictographic, "ExtPict")
|
||||
DEF(Default_Ignorable_Code_Point, "DI")
|
||||
DEF(ID_Start, "IDS")
|
||||
DEF(Case_Ignorable, "CI")
|
||||
|
Reference in New Issue
Block a user